From c4e99dbdb20225b9c08db40cb5ad3653ce92b1fa Mon Sep 17 00:00:00 2001 From: Nekotekina Date: Thu, 14 Apr 2016 02:09:41 +0300 Subject: [PATCH] Partial commit: Cell --- rpcs3/Emu/Cell/Common.h | 13 - rpcs3/Emu/{SysCalls => Cell}/ErrorCodes.h | 151 +- .../Callback.cpp => Cell/PPUCallback.cpp} | 20 +- .../CB_FUNC.h => Cell/PPUCallback.h} | 97 +- rpcs3/Emu/Cell/PPUDisAsm.cpp | 2160 +++++++ rpcs3/Emu/Cell/PPUDisAsm.h | 2232 ++----- rpcs3/Emu/Cell/PPUFunction.cpp | 2379 ++++++++ .../SC_FUNC.h => Cell/PPUFunction.h} | 117 +- rpcs3/Emu/Cell/PPUInterpreter.cpp | 3334 ++++++----- rpcs3/Emu/Cell/PPUInterpreter.h | 5110 ++--------------- rpcs3/Emu/Cell/PPUInterpreter2.h | 870 --- rpcs3/Emu/Cell/PPUModule.cpp | 1152 ++++ rpcs3/Emu/Cell/PPUModule.h | 255 + rpcs3/Emu/Cell/PPUOpcodes.h | 1499 ++--- rpcs3/Emu/Cell/PPUThread.cpp | 411 +- rpcs3/Emu/Cell/PPUThread.h | 1026 +--- rpcs3/Emu/Cell/RawSPUThread.cpp | 45 +- rpcs3/Emu/Cell/RawSPUThread.h | 43 +- rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp | 38 +- rpcs3/Emu/Cell/SPUASMJITRecompiler.h | 6 +- rpcs3/Emu/Cell/SPUAnalyser.cpp | 40 +- rpcs3/Emu/Cell/SPUAnalyser.h | 430 +- rpcs3/Emu/Cell/SPUContext.h | 5 - rpcs3/Emu/Cell/SPUDisAsm.cpp | 11 + rpcs3/Emu/Cell/SPUDisAsm.h | 14 +- rpcs3/Emu/Cell/SPUInterpreter.cpp | 127 +- rpcs3/Emu/Cell/SPUInterpreter.h | 486 +- rpcs3/Emu/Cell/SPUOpcodes.h | 489 +- rpcs3/Emu/Cell/SPURecompiler.cpp | 39 +- rpcs3/Emu/Cell/SPURecompiler.h | 29 +- rpcs3/Emu/Cell/SPUThread.cpp | 396 +- rpcs3/Emu/Cell/SPUThread.h | 188 +- 32 files changed, 10685 insertions(+), 12527 deletions(-) rename rpcs3/Emu/{SysCalls => Cell}/ErrorCodes.h (53%) rename rpcs3/Emu/{SysCalls/Callback.cpp => Cell/PPUCallback.cpp} (80%) rename rpcs3/Emu/{SysCalls/CB_FUNC.h => Cell/PPUCallback.h} (61%) create mode 100644 rpcs3/Emu/Cell/PPUDisAsm.cpp create mode 100644 rpcs3/Emu/Cell/PPUFunction.cpp rename rpcs3/Emu/{SysCalls/SC_FUNC.h => Cell/PPUFunction.h} (68%) delete mode 100644 rpcs3/Emu/Cell/PPUInterpreter2.h create mode 100644 rpcs3/Emu/Cell/PPUModule.cpp create mode 100644 rpcs3/Emu/Cell/PPUModule.h delete mode 100644 rpcs3/Emu/Cell/SPUContext.h create mode 100644 rpcs3/Emu/Cell/SPUDisAsm.cpp diff --git a/rpcs3/Emu/Cell/Common.h b/rpcs3/Emu/Cell/Common.h index b24396f854..214af66bce 100644 --- a/rpcs3/Emu/Cell/Common.h +++ b/rpcs3/Emu/Cell/Common.h @@ -8,16 +8,3 @@ enum FPSCR_RN FPSCR_RN_PINF = 2, FPSCR_RN_MINF = 3, }; - -using ppu_inter_func_t = void(*)(class PPUThread& CPU, union ppu_opcode_t opcode); - -struct ppu_decoder_cache_t -{ - ppu_inter_func_t* const pointer; - - ppu_decoder_cache_t(); - - ~ppu_decoder_cache_t(); - - void initialize(u32 addr, u32 size); -}; diff --git a/rpcs3/Emu/SysCalls/ErrorCodes.h b/rpcs3/Emu/Cell/ErrorCodes.h similarity index 53% rename from rpcs3/Emu/SysCalls/ErrorCodes.h rename to rpcs3/Emu/Cell/ErrorCodes.h index 373c806539..05445a6aa0 100644 --- a/rpcs3/Emu/SysCalls/ErrorCodes.h +++ b/rpcs3/Emu/Cell/ErrorCodes.h @@ -2,10 +2,13 @@ #define ERROR_CODE(code) static_cast(code) -enum : s32 +enum CellOk : s32 { - CELL_OK = 0, + CELL_OK = 0, +}; +enum CellError : s32 +{ CELL_EAGAIN = ERROR_CODE(0x80010001), // The resource is temporarily unavailable CELL_EINVAL = ERROR_CODE(0x80010002), // An invalid argument value is specified CELL_ENOSYS = ERROR_CODE(0x80010003), // The feature is not yet implemented @@ -64,6 +67,146 @@ enum : s32 CELL_EOVERFLOW = ERROR_CODE(0x80010039), CELL_ENOTMOUNTED = ERROR_CODE(0x8001003A), CELL_ENOTSDATA = ERROR_CODE(0x8001003B), - - CELL_UNKNOWN_ERROR = -1, }; + +// Special return type signaling on errors +struct ppu_error_code +{ + s32 value; + + // Print error message, error code is returned + static s32 report(s32 error, const char* text); + + // Must be specialized for specific tag type T + template + static const char* print(T code) + { + return nullptr; + } + + template + s32 error_check(T code) + { + if (const auto text = print(code)) + { + return report(code, text); + } + + return code; + } + + ppu_error_code() = default; + + // General error check + template::value>> + ppu_error_code(T value) + : value(error_check(value)) + { + } + + // Force error reporting with a message specified + ppu_error_code(s32 value, const char* text) + : value(report(value, text)) + { + } + + // Silence any error + constexpr ppu_error_code(s32 value, const std::nothrow_t&) + : value(value) + { + } + + // Conversion + constexpr operator s32() const + { + return value; + } +}; + +// Helper macro for silencing possible error checks on returning ppu_error_code values +#define NOT_AN_ERROR(value) { static_cast(value), std::nothrow } + +template +struct ppu_gpr_cast_impl; + +template<> +struct ppu_gpr_cast_impl +{ + static inline u64 to(const ppu_error_code& code) + { + return code; + } + + static inline ppu_error_code from(const u64 reg) + { + return NOT_AN_ERROR(reg); + } +}; + +template<> +inline const char* ppu_error_code::print(CellError error) +{ + switch (error) + { + STR_CASE(CELL_EAGAIN); + STR_CASE(CELL_EINVAL); + STR_CASE(CELL_ENOSYS); + STR_CASE(CELL_ENOMEM); + STR_CASE(CELL_ESRCH); + STR_CASE(CELL_ENOENT); + STR_CASE(CELL_ENOEXEC); + STR_CASE(CELL_EDEADLK); + STR_CASE(CELL_EPERM); + STR_CASE(CELL_EBUSY); + STR_CASE(CELL_ETIMEDOUT); + STR_CASE(CELL_EABORT); + STR_CASE(CELL_EFAULT); + STR_CASE(CELL_ESTAT); + STR_CASE(CELL_EALIGN); + STR_CASE(CELL_EKRESOURCE); + STR_CASE(CELL_EISDIR); + STR_CASE(CELL_ECANCELED); + STR_CASE(CELL_EEXIST); + STR_CASE(CELL_EISCONN); + STR_CASE(CELL_ENOTCONN); + STR_CASE(CELL_EAUTHFAIL); + STR_CASE(CELL_ENOTMSELF); + STR_CASE(CELL_ESYSVER); + STR_CASE(CELL_EAUTHFATAL); + STR_CASE(CELL_EDOM); + STR_CASE(CELL_ERANGE); + STR_CASE(CELL_EILSEQ); + STR_CASE(CELL_EFPOS); + STR_CASE(CELL_EINTR); + STR_CASE(CELL_EFBIG); + STR_CASE(CELL_EMLINK); + STR_CASE(CELL_ENFILE); + STR_CASE(CELL_ENOSPC); + STR_CASE(CELL_ENOTTY); + STR_CASE(CELL_EPIPE); + STR_CASE(CELL_EROFS); + STR_CASE(CELL_ESPIPE); + STR_CASE(CELL_E2BIG); + STR_CASE(CELL_EACCES); + STR_CASE(CELL_EBADF); + STR_CASE(CELL_EIO); + STR_CASE(CELL_EMFILE); + STR_CASE(CELL_ENODEV); + STR_CASE(CELL_ENOTDIR); + STR_CASE(CELL_ENXIO); + STR_CASE(CELL_EXDEV); + STR_CASE(CELL_EBADMSG); + STR_CASE(CELL_EINPROGRESS); + STR_CASE(CELL_EMSGSIZE); + STR_CASE(CELL_ENAMETOOLONG); + STR_CASE(CELL_ENOLCK); + STR_CASE(CELL_ENOTEMPTY); + STR_CASE(CELL_ENOTSUP); + STR_CASE(CELL_EFSSPECIFIC); + STR_CASE(CELL_EOVERFLOW); + STR_CASE(CELL_ENOTMOUNTED); + STR_CASE(CELL_ENOTSDATA); + } + + return nullptr; +} diff --git a/rpcs3/Emu/SysCalls/Callback.cpp b/rpcs3/Emu/Cell/PPUCallback.cpp similarity index 80% rename from rpcs3/Emu/SysCalls/Callback.cpp rename to rpcs3/Emu/Cell/PPUCallback.cpp index d2146c161f..8ca6a675e0 100644 --- a/rpcs3/Emu/SysCalls/Callback.cpp +++ b/rpcs3/Emu/Cell/PPUCallback.cpp @@ -3,9 +3,8 @@ #include "Emu/System.h" #include "Emu/IdManager.h" -#include "Emu/Cell/PPUThread.h" -#include "Emu/ARMv7/ARMv7Thread.h" -#include "Callback.h" +#include "PPUThread.h" +#include "PPUCallback.h" void CallbackManager::Register(check_cb_t func) { @@ -79,17 +78,14 @@ void CallbackManager::Init() } }; - if (vm::get(vm::main)->addr == 0x10000) - { - auto thread = idm::make_ptr("Callback Thread"); + auto thread = idm::make_ptr("Callback Thread"); - thread->prio = 1001; - thread->stack_size = 0x10000; - thread->custom_task = task; - thread->run(); + thread->prio = 1001; + thread->stack_size = 0x10000; + thread->custom_task = task; + thread->cpu_init(); - m_cb_thread = thread; - } + m_cb_thread = thread; } void CallbackManager::Clear() diff --git a/rpcs3/Emu/SysCalls/CB_FUNC.h b/rpcs3/Emu/Cell/PPUCallback.h similarity index 61% rename from rpcs3/Emu/SysCalls/CB_FUNC.h rename to rpcs3/Emu/Cell/PPUCallback.h index 2d621439f2..66b3ce2449 100644 --- a/rpcs3/Emu/SysCalls/CB_FUNC.h +++ b/rpcs3/Emu/Cell/PPUCallback.h @@ -2,7 +2,7 @@ #include "Emu/Cell/PPUThread.h" -namespace cb_detail +namespace ppu_cb_detail { enum _func_arg_type { @@ -10,7 +10,7 @@ namespace cb_detail ARG_FLOAT, ARG_VECTOR, ARG_STACK, - ARG_CONTEXT, // for compatibility with SC_FUNC and CALL_FUNC + ARG_CONTEXT, ARG_UNKNOWN, }; @@ -19,7 +19,7 @@ namespace cb_detail // It's possible to calculate suitable stack frame size in template, but too complicated. static const auto FIXED_STACK_FRAME_SIZE = 0x90; - template + template struct _func_arg { static_assert(type == ARG_GENERAL, "Unknown callback argument type"); @@ -27,50 +27,48 @@ namespace cb_detail static_assert(!std::is_reference::value, "Invalid callback argument type (reference)"); static_assert(sizeof(T) <= 8, "Invalid callback argument type for ARG_GENERAL"); - force_inline static void set_value(PPUThread& CPU, const T& arg) + static inline void set_value(PPUThread& CPU, const T& arg) { - CPU.GPR[g_count + 2] = cast_to_ppu_gpr(arg); + CPU.GPR[g_count + 2] = ppu_gpr_cast(arg); } }; - template + template struct _func_arg { static_assert(sizeof(T) <= 8, "Invalid callback argument type for ARG_FLOAT"); - force_inline static void set_value(PPUThread& CPU, const T& arg) + static inline void set_value(PPUThread& CPU, const T& arg) { CPU.FPR[f_count] = static_cast(arg); } }; - template + template struct _func_arg { - static_assert(std::is_same, v128>::value, "Invalid callback argument type for ARG_VECTOR"); + static_assert(std::is_same::value, "Invalid callback argument type for ARG_VECTOR"); - force_inline static void set_value(PPUThread& CPU, const T& arg) + static inline void set_value(PPUThread& CPU, const T& arg) { - CPU.VPR[v_count + 1] = arg; + CPU.VR[v_count + 1] = arg; } }; - template + template struct _func_arg { - static_assert(f_count <= 13, "TODO: Unsupported stack argument type (float)"); - static_assert(v_count <= 12, "TODO: Unsupported stack argument type (vector)"); - static_assert(sizeof(T) <= 8, "Invalid callback argument type for ARG_STACK"); + static_assert(alignof(T) <= 16, "Unsupported callback argument type alignment for ARG_STACK"); - force_inline static void set_value(PPUThread& CPU, const T& arg) + static inline void set_value(PPUThread& CPU, const T& arg) { - const int stack_pos = (g_count - 9) * 8 - FIXED_STACK_FRAME_SIZE; - static_assert(stack_pos < 0, "TODO: Increase fixed stack frame size (arg count limit broken)"); - vm::ps3::write64(CPU.GPR[1] + stack_pos, cast_to_ppu_gpr(arg)); + const s64 stack_pos = (g_count - 1) * 0x8 + 0x30 - FIXED_STACK_FRAME_SIZE; + static_assert(stack_pos < 0, "TODO: Increase FIXED_STACK_FRAME_SIZE (arg count limit broken)"); + vm::ps3::write64(CPU.GPR[1] + stack_pos, ppu_gpr_cast(arg)); // TODO } }; - template + template struct _func_arg { static_assert(std::is_same::value, "Invalid callback argument type for ARG_CONTEXT"); @@ -80,18 +78,18 @@ namespace cb_detail } }; - template + template force_inline static bool _bind_func_args(PPUThread& CPU) { // terminator return false; } - template + template force_inline static bool _bind_func_args(PPUThread& CPU, T1 arg1, T... args) { const bool is_float = std::is_floating_point::value; - const bool is_vector = std::is_same, v128>::value; + const bool is_vector = std::is_same::value; const bool is_context = std::is_same::value; const bool is_general = !is_float && !is_vector && !is_context; @@ -102,9 +100,9 @@ namespace cb_detail is_context ? ARG_CONTEXT : ARG_UNKNOWN; - const int g = g_count + is_general; - const int f = f_count + is_float; - const int v = v_count + is_vector; + const u32 g = g_count + (is_general || is_float ? 1 : is_vector ? ::align(g_count, 2) + 2 : 0); + const u32 f = f_count + is_float; + const u32 v = v_count + is_vector; _func_arg::set_value(CPU, arg1); @@ -120,7 +118,7 @@ namespace cb_detail force_inline static T get_value(const PPUThread& CPU) { - return cast_from_ppu_gpr(CPU.GPR[3]); + return ppu_gpr_cast(CPU.GPR[3]); } }; @@ -138,11 +136,11 @@ namespace cb_detail template struct _func_res { - static_assert(std::is_same, v128>::value, "Invalid callback result type for ARG_VECTOR"); + static_assert(std::is_same::value, "Invalid callback result type for ARG_VECTOR"); force_inline static T get_value(const PPUThread& CPU) { - return CPU.VPR[2]; + return CPU.VR[2]; } }; @@ -169,11 +167,9 @@ namespace cb_detail force_inline static void call(PPUThread& CPU, u32 pc, u32 rtoc, T... args) { const bool stack = _bind_func_args<0, 0, 0, T...>(CPU, args...); - if (stack) CPU.GPR[1] -= FIXED_STACK_FRAME_SIZE; - CPU.GPR[1] -= 0x70; // create reserved area + CPU.GPR[1] -= stack ? FIXED_STACK_FRAME_SIZE : 0x30; // create reserved area CPU.fast_call(pc, rtoc); - CPU.GPR[1] += 0x70; - if (stack) CPU.GPR[1] += FIXED_STACK_FRAME_SIZE; + CPU.GPR[1] += stack ? FIXED_STACK_FRAME_SIZE : 0x30; } }; } @@ -183,15 +179,44 @@ namespace vm template force_inline RT _ptr_base::operator()(PPUThread& CPU, T... args) const { - const auto data = vm::ps3::_ptr(VM_CAST(m_addr)); + const auto data = vm::ps3::_ptr(vm::cast(m_addr, HERE)); const u32 pc = data[0]; const u32 rtoc = data[1]; - return cb_detail::_func_caller::call(CPU, pc, rtoc, args...); + return ppu_cb_detail::_func_caller::call(CPU, pc, rtoc, args...); } } template inline RT cb_call(PPUThread& CPU, u32 pc, u32 rtoc, T... args) { - return cb_detail::_func_caller::call(CPU, pc, rtoc, args...); + return ppu_cb_detail::_func_caller::call(CPU, pc, rtoc, args...); } + +#include + +class CallbackManager +{ + using check_cb_t = std::function; + using async_cb_t = std::function; + + std::mutex m_mutex; + + std::queue m_check_cb; + std::queue m_async_cb; + + std::shared_ptr m_cb_thread; + +public: + // Register checked callback + void Register(check_cb_t func); + + // Register async callback, called in callback thread + void Async(async_cb_t func); + + // Get one registered callback + check_cb_t Check(); + + void Init(); + + void Clear(); +}; diff --git a/rpcs3/Emu/Cell/PPUDisAsm.cpp b/rpcs3/Emu/Cell/PPUDisAsm.cpp new file mode 100644 index 0000000000..31a1cfa48d --- /dev/null +++ b/rpcs3/Emu/Cell/PPUDisAsm.cpp @@ -0,0 +1,2160 @@ +#include "stdafx.h" +#include "PPUDisAsm.h" + +const ppu_decoder s_ppu_disasm; + +u32 PPUDisAsm::disasm(u32 pc) +{ + const u32 op = *(be_t*)(offset + pc); + (this->*(s_ppu_disasm.decode(op)))({ op }); + return 4; +} + +void PPUDisAsm::TDI(ppu_opcode_t op) +{ + DisAsm_INT1_R1_IMM("tdi", op.bo, op.ra, op.simm16); +} + +void PPUDisAsm::TWI(ppu_opcode_t op) +{ + DisAsm_INT1_R1_IMM("twi", op.bo, op.ra, op.simm16); +} + +void PPUDisAsm::MFVSCR(ppu_opcode_t op) +{ + DisAsm_V1("mfvscr", op.vd); +} + +void PPUDisAsm::MTVSCR(ppu_opcode_t op) +{ + DisAsm_V1("mtvscr", op.vb); +} + +void PPUDisAsm::VADDCUW(ppu_opcode_t op) +{ + DisAsm_V3("vaddcuw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VADDFP(ppu_opcode_t op) +{ + DisAsm_V3("vaddfp", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VADDSBS(ppu_opcode_t op) +{ + DisAsm_V3("vaddsbs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VADDSHS(ppu_opcode_t op) +{ + DisAsm_V3("vaddshs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VADDSWS(ppu_opcode_t op) +{ + DisAsm_V3("vaddsws", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VADDUBM(ppu_opcode_t op) +{ + DisAsm_V3("vaddubm", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VADDUBS(ppu_opcode_t op) +{ + DisAsm_V3("vaddubs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VADDUHM(ppu_opcode_t op) +{ + DisAsm_V3("vadduhm", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VADDUHS(ppu_opcode_t op) +{ + DisAsm_V3("vadduhs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VADDUWM(ppu_opcode_t op) +{ + DisAsm_V3("vadduwm", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VADDUWS(ppu_opcode_t op) +{ + DisAsm_V3("vadduws", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VAND(ppu_opcode_t op) +{ + DisAsm_V3("vand", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VANDC(ppu_opcode_t op) +{ + DisAsm_V3("vandc", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VAVGSB(ppu_opcode_t op) +{ + DisAsm_V3("vavgsb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VAVGSH(ppu_opcode_t op) +{ + DisAsm_V3("vavgsh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VAVGSW(ppu_opcode_t op) +{ + DisAsm_V3("vavgsw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VAVGUB(ppu_opcode_t op) +{ + DisAsm_V3("vavgub", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VAVGUH(ppu_opcode_t op) +{ + DisAsm_V3("vavguh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VAVGUW(ppu_opcode_t op) +{ + DisAsm_V3("vavguw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCFSX(ppu_opcode_t op) +{ + DisAsm_V2_UIMM("vcfsx", op.vd, op.vb, op.vuimm); +} + +void PPUDisAsm::VCFUX(ppu_opcode_t op) +{ + DisAsm_V2_UIMM("vcfux", op.vd, op.vb, op.vuimm); +} + +void PPUDisAsm::VCMPBFP(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpbfp." : "vcmpbfp", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPEQFP(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpeqfp." : "vcmpeqfp", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPEQUB(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpequb." : "vcmpequb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPEQUH(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpequh." : "vcmpequh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPEQUW(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpequw." : "vcmpequw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPGEFP(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpgefp." : "vcmpgefp", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPGTFP(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpgtfp." : "vcmpgtfp", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPGTSB(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpgtsb." : "vcmpgtsb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPGTSH(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpgtsh." : "vcmpgtsh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPGTSW(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpgtsw." : "vcmpgtsw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPGTUB(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpgtub." : "vcmpgtub", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPGTUH(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpgtuh." : "vcmpgtuh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCMPGTUW(ppu_opcode_t op) +{ + DisAsm_V3(op.oe ? "vcmpgtuw." : "vcmpgtuw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VCTSXS(ppu_opcode_t op) +{ + DisAsm_V2_UIMM("vctsxs", op.vd, op.vb, op.vuimm); +} + +void PPUDisAsm::VCTUXS(ppu_opcode_t op) +{ + DisAsm_V2_UIMM("vctuxs", op.vd, op.vb, op.vuimm); +} + +void PPUDisAsm::VEXPTEFP(ppu_opcode_t op) +{ + DisAsm_V2("vexptefp", op.vd, op.vb); +} + +void PPUDisAsm::VLOGEFP(ppu_opcode_t op) +{ + DisAsm_V2("vlogefp", op.vd, op.vb); +} + +void PPUDisAsm::VMADDFP(ppu_opcode_t op) +{ + DisAsm_V4("vmaddfp", op.vd, op.va, op.vc, op.vb); +} + +void PPUDisAsm::VMAXFP(ppu_opcode_t op) +{ + DisAsm_V3("vmaxfp", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMAXSB(ppu_opcode_t op) +{ + DisAsm_V3("vmaxsb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMAXSH(ppu_opcode_t op) +{ + DisAsm_V3("vmaxsh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMAXSW(ppu_opcode_t op) +{ + DisAsm_V3("vmaxsw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMAXUB(ppu_opcode_t op) +{ + DisAsm_V3("vmaxub", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMAXUH(ppu_opcode_t op) +{ + DisAsm_V3("vmaxuh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMAXUW(ppu_opcode_t op) +{ + DisAsm_V3("vmaxuw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMHADDSHS(ppu_opcode_t op) +{ + DisAsm_V4("vmhaddshs", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VMHRADDSHS(ppu_opcode_t op) +{ + DisAsm_V4("vmhraddshs", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VMINFP(ppu_opcode_t op) +{ + DisAsm_V3("vminfp", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMINSB(ppu_opcode_t op) +{ + DisAsm_V3("vminsb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMINSH(ppu_opcode_t op) +{ + DisAsm_V3("vminsh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMINSW(ppu_opcode_t op) +{ + DisAsm_V3("vminsw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMINUB(ppu_opcode_t op) +{ + DisAsm_V3("vminub", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMINUH(ppu_opcode_t op) +{ + DisAsm_V3("vminuh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMINUW(ppu_opcode_t op) +{ + DisAsm_V3("vminuw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMLADDUHM(ppu_opcode_t op) +{ + DisAsm_V4("vmladduhm", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VMRGHB(ppu_opcode_t op) +{ + DisAsm_V3("vmrghb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMRGHH(ppu_opcode_t op) +{ + DisAsm_V3("vmrghh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMRGHW(ppu_opcode_t op) +{ + DisAsm_V3("vmrghw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMRGLB(ppu_opcode_t op) +{ + DisAsm_V3("vmrglb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMRGLH(ppu_opcode_t op) +{ + DisAsm_V3("vmrglh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMRGLW(ppu_opcode_t op) +{ + DisAsm_V3("vmrglw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMSUMMBM(ppu_opcode_t op) +{ + DisAsm_V4("vmsummbm", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VMSUMSHM(ppu_opcode_t op) +{ + DisAsm_V4("vmsumshm", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VMSUMSHS(ppu_opcode_t op) +{ + DisAsm_V4("vmsumshs", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VMSUMUBM(ppu_opcode_t op) +{ + DisAsm_V4("vmsumubm", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VMSUMUHM(ppu_opcode_t op) +{ + DisAsm_V4("vmsumuhm", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VMSUMUHS(ppu_opcode_t op) +{ + DisAsm_V4("vmsumuhs", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VMULESB(ppu_opcode_t op) +{ + DisAsm_V3("vmulesb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMULESH(ppu_opcode_t op) +{ + DisAsm_V3("vmulesh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMULEUB(ppu_opcode_t op) +{ + DisAsm_V3("vmuleub", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMULEUH(ppu_opcode_t op) +{ + DisAsm_V3("vmuleuh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMULOSB(ppu_opcode_t op) +{ + DisAsm_V3("vmulosb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMULOSH(ppu_opcode_t op) +{ + DisAsm_V3("vmulosh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMULOUB(ppu_opcode_t op) +{ + DisAsm_V3("vmuloub", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VMULOUH(ppu_opcode_t op) +{ + DisAsm_V3("vmulouh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VNMSUBFP(ppu_opcode_t op) +{ + DisAsm_V4("vnmsubfp", op.vd, op.va, op.vc, op.vb); +} + +void PPUDisAsm::VNOR(ppu_opcode_t op) +{ + DisAsm_V3("vnor", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VOR(ppu_opcode_t op) +{ + DisAsm_V3("vor", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VPERM(ppu_opcode_t op) +{ + DisAsm_V4("vperm", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VPKPX(ppu_opcode_t op) +{ + DisAsm_V3("vpkpx", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VPKSHSS(ppu_opcode_t op) +{ + DisAsm_V3("vpkshss", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VPKSHUS(ppu_opcode_t op) +{ + DisAsm_V3("vpkshus", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VPKSWSS(ppu_opcode_t op) +{ + DisAsm_V3("vpkswss", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VPKSWUS(ppu_opcode_t op) +{ + DisAsm_V3("vpkswus", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VPKUHUM(ppu_opcode_t op) +{ + DisAsm_V3("vpkuhum", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VPKUHUS(ppu_opcode_t op) +{ + DisAsm_V3("vpkuhus", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VPKUWUM(ppu_opcode_t op) +{ + DisAsm_V3("vpkuwum", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VPKUWUS(ppu_opcode_t op) +{ + DisAsm_V3("vpkuwus", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VREFP(ppu_opcode_t op) +{ + DisAsm_V2("vrefp", op.vd, op.vb); +} + +void PPUDisAsm::VRFIM(ppu_opcode_t op) +{ + DisAsm_V2("vrfim", op.vd, op.vb); +} + +void PPUDisAsm::VRFIN(ppu_opcode_t op) +{ + DisAsm_V2("vrfin", op.vd, op.vb); +} + +void PPUDisAsm::VRFIP(ppu_opcode_t op) +{ + DisAsm_V2("vrfip", op.vd, op.vb); +} + +void PPUDisAsm::VRFIZ(ppu_opcode_t op) +{ + DisAsm_V2("vrfiz", op.vd, op.vb); +} + +void PPUDisAsm::VRLB(ppu_opcode_t op) +{ + DisAsm_V3("vrlb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VRLH(ppu_opcode_t op) +{ + DisAsm_V3("vrlh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VRLW(ppu_opcode_t op) +{ + DisAsm_V3("vrlw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VRSQRTEFP(ppu_opcode_t op) +{ + DisAsm_V2("vrsqrtefp", op.vd, op.vb); +} + +void PPUDisAsm::VSEL(ppu_opcode_t op) +{ + DisAsm_V4("vsel", op.vd, op.va, op.vb, op.vc); +} + +void PPUDisAsm::VSL(ppu_opcode_t op) +{ + DisAsm_V3("vsl", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSLB(ppu_opcode_t op) +{ + DisAsm_V3("vslb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSLDOI(ppu_opcode_t op) +{ + DisAsm_V3_UIMM("vsldoi", op.vd, op.va, op.vb, op.vsh); +} + +void PPUDisAsm::VSLH(ppu_opcode_t op) +{ + DisAsm_V3("vslh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSLO(ppu_opcode_t op) +{ + DisAsm_V3("vslo", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSLW(ppu_opcode_t op) +{ + DisAsm_V3("vslw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSPLTB(ppu_opcode_t op) +{ + DisAsm_V2_UIMM("vspltb", op.vd, op.vb, op.vuimm & 0xf); +} + +void PPUDisAsm::VSPLTH(ppu_opcode_t op) +{ + DisAsm_V2_UIMM("vsplth", op.vd, op.vb, op.vuimm & 0x7); +} + +void PPUDisAsm::VSPLTISB(ppu_opcode_t op) +{ + DisAsm_V1_SIMM("vspltisb", op.vd, op.vsimm); +} + +void PPUDisAsm::VSPLTISH(ppu_opcode_t op) +{ + DisAsm_V1_SIMM("vspltish", op.vd, op.vsimm); +} + +void PPUDisAsm::VSPLTISW(ppu_opcode_t op) +{ + DisAsm_V1_SIMM("vspltisw", op.vd, op.vsimm); +} + +void PPUDisAsm::VSPLTW(ppu_opcode_t op) +{ + DisAsm_V2_UIMM("vspltw", op.vd, op.vb, op.vuimm & 0x3); +} + +void PPUDisAsm::VSR(ppu_opcode_t op) +{ + DisAsm_V3("vsr", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSRAB(ppu_opcode_t op) +{ + DisAsm_V3("vsrab", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSRAH(ppu_opcode_t op) +{ + DisAsm_V3("vsrah", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSRAW(ppu_opcode_t op) +{ + DisAsm_V3("vsraw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSRB(ppu_opcode_t op) +{ + DisAsm_V3("vsrb", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSRH(ppu_opcode_t op) +{ + DisAsm_V3("vsrh", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSRO(ppu_opcode_t op) +{ + DisAsm_V3("vsro", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSRW(ppu_opcode_t op) +{ + DisAsm_V3("vsrw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBCUW(ppu_opcode_t op) +{ + DisAsm_V3("vsubcuw", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBFP(ppu_opcode_t op) +{ + DisAsm_V3("vsubfp", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBSBS(ppu_opcode_t op) +{ + DisAsm_V3("vsubsbs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBSHS(ppu_opcode_t op) +{ + DisAsm_V3("vsubshs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBSWS(ppu_opcode_t op) +{ + DisAsm_V3("vsubsws", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBUBM(ppu_opcode_t op) +{ + DisAsm_V3("vsububm", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBUBS(ppu_opcode_t op) +{ + DisAsm_V3("vsububs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBUHM(ppu_opcode_t op) +{ + DisAsm_V3("vsubuhm", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBUHS(ppu_opcode_t op) +{ + DisAsm_V3("vsubuhs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBUWM(ppu_opcode_t op) +{ + DisAsm_V3("vsubuwm", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUBUWS(ppu_opcode_t op) +{ + DisAsm_V3("vsubuws", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUMSWS(ppu_opcode_t op) +{ + DisAsm_V3("vsumsws", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUM2SWS(ppu_opcode_t op) +{ + DisAsm_V3("vsum2sws", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUM4SBS(ppu_opcode_t op) +{ + DisAsm_V3("vsum4sbs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUM4SHS(ppu_opcode_t op) +{ + DisAsm_V3("vsum4shs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VSUM4UBS(ppu_opcode_t op) +{ + DisAsm_V3("vsum4ubs", op.vd, op.va, op.vb); +} + +void PPUDisAsm::VUPKHPX(ppu_opcode_t op) +{ + DisAsm_V2("vupkhpx", op.vd, op.vb); +} + +void PPUDisAsm::VUPKHSB(ppu_opcode_t op) +{ + DisAsm_V2("vupkhsb", op.vd, op.vb); +} + +void PPUDisAsm::VUPKHSH(ppu_opcode_t op) +{ + DisAsm_V2("vupkhsh", op.vd, op.vb); +} + +void PPUDisAsm::VUPKLPX(ppu_opcode_t op) +{ + DisAsm_V2("vupklpx", op.vd, op.vb); +} + +void PPUDisAsm::VUPKLSB(ppu_opcode_t op) +{ + DisAsm_V2("vupklsb", op.vd, op.vb); +} + +void PPUDisAsm::VUPKLSH(ppu_opcode_t op) +{ + DisAsm_V2("vupklsh", op.vd, op.vb); +} + +void PPUDisAsm::VXOR(ppu_opcode_t op) +{ + DisAsm_V3("vxor", op.vd, op.va, op.vb); +} + +void PPUDisAsm::MULLI(ppu_opcode_t op) +{ + DisAsm_R2_IMM("mulli", op.rd, op.ra, op.simm16); +} + +void PPUDisAsm::SUBFIC(ppu_opcode_t op) +{ + DisAsm_R2_IMM("subfic", op.rd, op.ra, op.simm16); +} + +void PPUDisAsm::CMPLI(ppu_opcode_t op) +{ + DisAsm_CR1_R1_IMM(op.l10 ? "cmpdi" : "cmpwi", op.crfd, op.ra, op.uimm16); +} + +void PPUDisAsm::CMPI(ppu_opcode_t op) +{ + DisAsm_CR1_R1_IMM(op.l10 ? "cmpdi" : "cmpwi", op.crfd, op.ra, op.simm16); +} + +void PPUDisAsm::ADDIC(ppu_opcode_t op) +{ + DisAsm_R2_IMM(op.main & 1 ? "addic." : "addic", op.rd, op.ra, op.simm16); +} + +void PPUDisAsm::ADDI(ppu_opcode_t op) +{ + if (op.ra == 0) + { + DisAsm_R1_IMM("li", op.rd, op.simm16); + } + else + { + DisAsm_R2_IMM("addi", op.rd, op.ra, op.simm16); + } +} + +void PPUDisAsm::ADDIS(ppu_opcode_t op) +{ + if (op.ra == 0) + { + DisAsm_R1_IMM("lis", op.rd, op.simm16); + } + else + { + DisAsm_R2_IMM("addis", op.rd, op.ra, op.simm16); + } +} + +void PPUDisAsm::BC(ppu_opcode_t op) +{ + const u32 bo = op.bo; + const u32 bi = op.bi; + const s32 bd = op.ds * 4; + const u32 aa = op.aa; + const u32 lk = op.lk; + + if (m_mode == CPUDisAsm_CompilerElfMode) + { + Write(fmt::format("bc 0x%x, 0x%x, 0x%x, %d, %d", bo, bi, bd, aa, lk)); + return; + } + + //TODO: aa lk + const u8 bo0 = (bo & 0x10) ? 1 : 0; + const u8 bo1 = (bo & 0x08) ? 1 : 0; + const u8 bo2 = (bo & 0x04) ? 1 : 0; + const u8 bo3 = (bo & 0x02) ? 1 : 0; + const u8 bo4 = (bo & 0x01) ? 1 : 0; + + if (bo0 && !bo1 && !bo2 && bo3 && !bo4) + { + DisAsm_CR_BRANCH("bdz", bi / 4, bd); return; + } + else if (bo0 && bo1 && !bo2 && bo3 && !bo4) + { + DisAsm_CR_BRANCH("bdz-", bi / 4, bd); return; + } + else if (bo0 && bo1 && !bo2 && bo3 && bo4) + { + DisAsm_CR_BRANCH("bdz+", bi / 4, bd); return; + } + else if (bo0 && !bo1 && !bo2 && !bo3 && !bo4) + { + DisAsm_CR_BRANCH("bdnz", bi / 4, bd); return; + } + else if (bo0 && bo1 && !bo2 && !bo3 && !bo4) + { + DisAsm_CR_BRANCH("bdnz-", bi / 4, bd); return; + } + else if (bo0 && bo1 && !bo2 && !bo3 && bo4) + { + DisAsm_CR_BRANCH("bdnz+", bi / 4, bd); return; + } + else if (!bo0 && !bo1 && bo2 && !bo3 && !bo4) + { + switch (bi % 4) + { + case 0x0: DisAsm_CR_BRANCH("bge", bi / 4, bd); return; + case 0x1: DisAsm_CR_BRANCH("ble", bi / 4, bd); return; + case 0x2: DisAsm_CR_BRANCH("bne", bi / 4, bd); return; + } + } + else if (!bo0 && !bo1 && bo2 && bo3 && !bo4) + { + switch (bi % 4) + { + case 0x0: DisAsm_CR_BRANCH("bge-", bi / 4, bd); return; + case 0x1: DisAsm_CR_BRANCH("ble-", bi / 4, bd); return; + case 0x2: DisAsm_CR_BRANCH("bne-", bi / 4, bd); return; + } + } + else if (!bo0 && !bo1 && bo2 && bo3 && bo4) + { + switch (bi % 4) + { + case 0x0: DisAsm_CR_BRANCH("bge+", bi / 4, bd); return; + case 0x1: DisAsm_CR_BRANCH("ble+", bi / 4, bd); return; + case 0x2: DisAsm_CR_BRANCH("bne+", bi / 4, bd); return; + } + } + else if (!bo0 && bo1 && bo2 && !bo3 && !bo4) + { + switch (bi % 4) + { + case 0x0: DisAsm_CR_BRANCH("blt", bi / 4, bd); return; + case 0x1: DisAsm_CR_BRANCH("bgt", bi / 4, bd); return; + case 0x2: DisAsm_CR_BRANCH("beq", bi / 4, bd); return; + } + } + else if (!bo0 && bo1 && bo2 && bo3 && !bo4) + { + switch (bi % 4) + { + case 0x0: DisAsm_CR_BRANCH("blt-", bi / 4, bd); return; + case 0x1: DisAsm_CR_BRANCH("bgt-", bi / 4, bd); return; + case 0x2: DisAsm_CR_BRANCH("beq-", bi / 4, bd); return; + } + } + else if (!bo0 && bo1 && bo2 && bo3 && bo4) + { + switch (bi % 4) + { + case 0x0: DisAsm_CR_BRANCH("blt+", bi / 4, bd); return; + case 0x1: DisAsm_CR_BRANCH("bgt+", bi / 4, bd); return; + case 0x2: DisAsm_CR_BRANCH("beq+", bi / 4, bd); return; + } + } + + Write(fmt::format("bc [%x:%x:%x:%x:%x], cr%d[%x], 0x%x, %d, %d", bo0, bo1, bo2, bo3, bo4, bi / 4, bi % 4, bd, aa, lk)); +} + +void PPUDisAsm::HACK(ppu_opcode_t op) +{ + Write(fmt::format("hack %d", op.opcode & 0x3ffffff)); +} + +void PPUDisAsm::SC(ppu_opcode_t op) +{ + switch (op.lev) + { + case 0x0: Write("sc"); break; + case 0x1: Write("HyperCall LV1"); break; + case 0x3: Write("fast_stop()"); break; // hack + default: Write(fmt::format("Unknown sc: 0x%x", op.lev)); + } +} + +void PPUDisAsm::B(ppu_opcode_t op) +{ + const u32 ll = op.ll; + const u32 aa = op.aa; + const u32 lk = op.lk; + + if (m_mode == CPUDisAsm_CompilerElfMode) + { + Write(fmt::format("b 0x%x, %d, %d", ll, aa, lk)); + return; + } + + switch (lk) + { + case 0: + switch (aa) + { + case 0: DisAsm_BRANCH("b", ll); break; + case 1: DisAsm_BRANCH_A("ba", ll); break; + } + break; + + case 1: + switch (aa) + { + case 0: DisAsm_BRANCH("bl", ll); break; + case 1: DisAsm_BRANCH_A("bla", ll); break; + } + break; + } +} + +void PPUDisAsm::MCRF(ppu_opcode_t op) +{ + DisAsm_CR2("mcrf", op.crfd, op.crfs); +} + +void PPUDisAsm::BCLR(ppu_opcode_t op) +{ + const u32 bo = op.bo; + const u32 bi = op.bi; + + const u8 bo0 = (bo & 0x10) ? 1 : 0; + const u8 bo1 = (bo & 0x08) ? 1 : 0; + const u8 bo2 = (bo & 0x04) ? 1 : 0; + const u8 bo3 = (bo & 0x02) ? 1 : 0; + + if (bo0 && !bo1 && bo2 && !bo3) { Write("blr"); return; } + Write(fmt::format("bclr [%x:%x:%x:%x], cr%d[%x], %d, %d", bo0, bo1, bo2, bo3, bi / 4, bi % 4, op.bh, op.lk)); +} + +void PPUDisAsm::CRNOR(ppu_opcode_t op) +{ + DisAsm_INT3("crnor", op.crbd, op.crba, op.crbb); +} + +void PPUDisAsm::CRANDC(ppu_opcode_t op) +{ + DisAsm_INT3("crandc", op.crbd, op.crba, op.crbb); +} + +void PPUDisAsm::ISYNC(ppu_opcode_t op) +{ + Write("isync"); +} + +void PPUDisAsm::CRXOR(ppu_opcode_t op) +{ + DisAsm_INT3("crxor", op.crbd, op.crba, op.crbb); +} + +void PPUDisAsm::CRNAND(ppu_opcode_t op) +{ + DisAsm_INT3("crnand", op.crbd, op.crba, op.crbb); +} + +void PPUDisAsm::CRAND(ppu_opcode_t op) +{ + DisAsm_INT3("crand", op.crbd, op.crba, op.crbb); +} + +void PPUDisAsm::CREQV(ppu_opcode_t op) +{ + DisAsm_INT3("creqv", op.crbd, op.crba, op.crbb); +} + +void PPUDisAsm::CRORC(ppu_opcode_t op) +{ + DisAsm_INT3("crorc", op.crbd, op.crba, op.crbb); +} + +void PPUDisAsm::CROR(ppu_opcode_t op) +{ + DisAsm_INT3("cror", op.crbd, op.crba, op.crbb); +} + +void PPUDisAsm::BCCTR(ppu_opcode_t op) +{ + const u32 bo = op.bo; + const u32 bi = op.bi; + const u32 bh = op.bh; + + switch (op.lk) + { + case 0: DisAsm_INT3("bcctr", bo, bi, bh); break; + case 1: DisAsm_INT3("bcctrl", bo, bi, bh); break; + } +} + +void PPUDisAsm::RLWIMI(ppu_opcode_t op) +{ + DisAsm_R2_INT3_RC("rlwimi", op.ra, op.rs, op.sh32, op.mb32, op.me32, op.rc); +} + +void PPUDisAsm::RLWINM(ppu_opcode_t op) +{ + DisAsm_R2_INT3_RC("rlwinm", op.ra, op.rs, op.sh32, op.mb32, op.me32, op.rc); +} + +void PPUDisAsm::RLWNM(ppu_opcode_t op) +{ + DisAsm_R3_INT2_RC("rlwnm", op.ra, op.rs, op.rb, op.mb32, op.me32, op.rc); +} + +void PPUDisAsm::ORI(ppu_opcode_t op) +{ + if (op.rs == 0 && op.ra == 0 && op.uimm16 == 0) return Write("nop"); + DisAsm_R2_IMM("ori", op.rs, op.ra, op.uimm16); +} + +void PPUDisAsm::ORIS(ppu_opcode_t op) +{ + if (op.rs == 0 && op.ra == 0 && op.uimm16 == 0) return Write("nop"); + DisAsm_R2_IMM("oris", op.rs, op.ra, op.uimm16); +} + +void PPUDisAsm::XORI(ppu_opcode_t op) +{ + DisAsm_R2_IMM("xori", op.ra, op.rs, op.uimm16); +} + +void PPUDisAsm::XORIS(ppu_opcode_t op) +{ + DisAsm_R2_IMM("xoris", op.ra, op.rs, op.uimm16); +} + +void PPUDisAsm::ANDI(ppu_opcode_t op) +{ + DisAsm_R2_IMM("andi.", op.ra, op.rs, op.uimm16); +} + +void PPUDisAsm::ANDIS(ppu_opcode_t op) +{ + DisAsm_R2_IMM("andis.", op.ra, op.rs, op.uimm16); +} + +void PPUDisAsm::RLDICL(ppu_opcode_t op) +{ + const u32 sh = op.sh64; + const u32 mb = op.mbe64; + + if (sh == 0) + { + DisAsm_R2_INT1_RC("clrldi", op.ra, op.rs, mb, op.rc); + } + else if (mb == 0) + { + DisAsm_R2_INT1_RC("rotldi", op.ra, op.rs, sh, op.rc); + } + else if (mb == 64 - sh) + { + DisAsm_R2_INT1_RC("srdi", op.ra, op.rs, mb, op.rc); + } + else + { + DisAsm_R2_INT2_RC("rldicl", op.ra, op.rs, sh, mb, op.rc); + } +} + +void PPUDisAsm::RLDICR(ppu_opcode_t op) +{ + const u32 sh = op.sh64; + const u32 me = op.mbe64; + + DisAsm_R2_INT2_RC("rldicr", op.ra, op.rs, sh, me, op.rc); +} + +void PPUDisAsm::RLDIC(ppu_opcode_t op) +{ + const u32 sh = op.sh64; + const u32 mb = op.mbe64; + + DisAsm_R2_INT2_RC("rldic", op.ra, op.rs, sh, mb, op.rc); +} + +void PPUDisAsm::RLDIMI(ppu_opcode_t op) +{ + const u32 sh = op.sh64; + const u32 mb = op.mbe64; + + DisAsm_R2_INT2_RC("rldimi", op.ra, op.rs, sh, mb, op.rc); +} + +void PPUDisAsm::RLDCL(ppu_opcode_t op) +{ + const u32 mb = op.mbe64; + + DisAsm_R3_INT2_RC("rldcl", op.ra, op.rs, op.rb, mb, 0, op.rc); +} + +void PPUDisAsm::RLDCR(ppu_opcode_t op) +{ + const u32 me = op.mbe64; + + DisAsm_R3_INT2_RC("rldcr", op.ra, op.rs, op.rb, me, 0, op.rc); +} + +void PPUDisAsm::CMP(ppu_opcode_t op) +{ + DisAsm_CR1_R2(op.l10 ? "cmpd" : "cmpw", op.crfd, op.ra, op.rb); +} + +void PPUDisAsm::TW(ppu_opcode_t op) +{ + DisAsm_INT1_R2("tw", op.bo, op.ra, op.rb); +} + +void PPUDisAsm::LVSL(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvsl", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::LVEBX(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvebx", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::SUBFC(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("subfc", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::ADDC(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("addc", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::MULHDU(ppu_opcode_t op) +{ + DisAsm_R3_RC("mulhdu", op.rd, op.ra, op.rb, op.rc); +} + +void PPUDisAsm::MULHWU(ppu_opcode_t op) +{ + DisAsm_R3_RC("mulhwu", op.rd, op.ra, op.rb, op.rc); +} + +void PPUDisAsm::MFOCRF(ppu_opcode_t op) +{ + if (op.l11) + { + DisAsm_R1_IMM("mfocrf", op.rd, op.crm); + } + else + { + DisAsm_R1("mfcr", op.rd); + } +} + +void PPUDisAsm::LWARX(ppu_opcode_t op) +{ + DisAsm_R3("lwarx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::LDX(ppu_opcode_t op) +{ + DisAsm_R3("ldx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::LWZX(ppu_opcode_t op) +{ + DisAsm_R3("lwzx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::SLW(ppu_opcode_t op) +{ + DisAsm_R3_RC("slw", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::CNTLZW(ppu_opcode_t op) +{ + DisAsm_R2_RC("cntlzw", op.ra, op.rs, op.rc); +} + +void PPUDisAsm::SLD(ppu_opcode_t op) +{ + DisAsm_R3_RC("sld", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::AND(ppu_opcode_t op) +{ + DisAsm_R3_RC("and", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::CMPL(ppu_opcode_t op) +{ + DisAsm_CR1_R2(op.l10 ? "cmpld" : "cmplw", op.crfd, op.ra, op.rb); +} + +void PPUDisAsm::LVSR(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvsr", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::LVEHX(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvehx", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::SUBF(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("subf", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::LDUX(ppu_opcode_t op) +{ + DisAsm_R3("ldux", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::DCBST(ppu_opcode_t op) +{ + DisAsm_R2("dcbst", op.ra, op.rb); +} + +void PPUDisAsm::LWZUX(ppu_opcode_t op) +{ + DisAsm_R3("lwzux", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::CNTLZD(ppu_opcode_t op) +{ + DisAsm_R2_RC("cntlzd", op.ra, op.rs, op.rc); +} + +void PPUDisAsm::ANDC(ppu_opcode_t op) +{ + DisAsm_R3_RC("andc", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::TD(ppu_opcode_t op) +{ + DisAsm_INT1_R2("td", op.bo, op.ra, op.rb); +} + +void PPUDisAsm::LVEWX(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvewx", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::MULHD(ppu_opcode_t op) +{ + DisAsm_R3_RC("mulhd", op.rd, op.ra, op.rb, op.rc); +} + +void PPUDisAsm::MULHW(ppu_opcode_t op) +{ + DisAsm_R3_RC("mulhw", op.rd, op.ra, op.rb, op.rc); +} + +void PPUDisAsm::LDARX(ppu_opcode_t op) +{ + DisAsm_R3("ldarx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::DCBF(ppu_opcode_t op) +{ + DisAsm_R2("dcbf", op.ra, op.rb); +} + +void PPUDisAsm::LBZX(ppu_opcode_t op) +{ + DisAsm_R3("lbzx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::LVX(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvx", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::NEG(ppu_opcode_t op) +{ + DisAsm_R2_OE_RC("neg", op.rd, op.ra, op.oe, op.rc); +} + +void PPUDisAsm::LBZUX(ppu_opcode_t op) +{ + DisAsm_R3("lbzux", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::NOR(ppu_opcode_t op) +{ + if (op.rs == op.rb) + { + DisAsm_R2_RC("not", op.ra, op.rs, op.rc); + } + else + { + DisAsm_R3_RC("nor", op.ra, op.rs, op.rb, op.rc); + } +} + +void PPUDisAsm::STVEBX(ppu_opcode_t op) +{ + DisAsm_V1_R2("stvebx", op.vs, op.ra, op.rb); +} + +void PPUDisAsm::SUBFE(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("subfe", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::ADDE(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("adde", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::MTOCRF(ppu_opcode_t op) +{ + if (op.l11) + { + DisAsm_INT1_R1("mtocrf", op.crm, op.rs); + } + else + { + DisAsm_INT1_R1("mtcrf", op.crm, op.rs); + } +} + +void PPUDisAsm::STDX(ppu_opcode_t op) +{ + DisAsm_R3("stdx.", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STWCX(ppu_opcode_t op) +{ + DisAsm_R3("stwcx.", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STWX(ppu_opcode_t op) +{ + DisAsm_R3("stwx", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STVEHX(ppu_opcode_t op) +{ + DisAsm_V1_R2("stvehx", op.vs, op.ra, op.rb); +} + +void PPUDisAsm::STDUX(ppu_opcode_t op) +{ + DisAsm_R3("stdux", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STWUX(ppu_opcode_t op) +{ + DisAsm_R3("stwux", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STVEWX(ppu_opcode_t op) +{ + DisAsm_V1_R2("stvewx", op.vs, op.ra, op.rb); +} + +void PPUDisAsm::SUBFZE(ppu_opcode_t op) +{ + DisAsm_R2_OE_RC("subfze", op.rd, op.ra, op.oe, op.rc); +} + +void PPUDisAsm::ADDZE(ppu_opcode_t op) +{ + DisAsm_R2_OE_RC("addze", op.rd, op.ra, op.oe, op.rc); +} + +void PPUDisAsm::STDCX(ppu_opcode_t op) +{ + DisAsm_R3("stdcx.", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STBX(ppu_opcode_t op) +{ + DisAsm_R3("stbx", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STVX(ppu_opcode_t op) +{ + DisAsm_V1_R2("stvx", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::SUBFME(ppu_opcode_t op) +{ + DisAsm_R2_OE_RC("subfme", op.rd, op.ra, op.oe, op.rc); +} + +void PPUDisAsm::MULLD(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("mulld", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::ADDME(ppu_opcode_t op) +{ + DisAsm_R2_OE_RC("addme", op.rd, op.ra, op.oe, op.rc); +} + +void PPUDisAsm::MULLW(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("mullw", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::DCBTST(ppu_opcode_t op) +{ + DisAsm_R3("dcbtst", op.ra, op.rb, op.bo); +} + +void PPUDisAsm::STBUX(ppu_opcode_t op) +{ + DisAsm_R3("stbux", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::ADD(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("add", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::DCBT(ppu_opcode_t op) +{ + DisAsm_R2("dcbt", op.ra, op.rb); +} + +void PPUDisAsm::LHZX(ppu_opcode_t op) +{ + DisAsm_R3("lhzx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::EQV(ppu_opcode_t op) +{ + DisAsm_R3_RC("eqv", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::ECIWX(ppu_opcode_t op) +{ + DisAsm_R3("eciwx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::LHZUX(ppu_opcode_t op) +{ + DisAsm_R3("lhzux", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::XOR(ppu_opcode_t op) +{ + DisAsm_R3_RC("xor", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::MFSPR(ppu_opcode_t op) +{ + const u32 n = (op.spr >> 5) | ((op.spr & 0x1f) << 5); + switch (n) + { + case 0x001: DisAsm_R1("mfxer", op.rd); break; + case 0x008: DisAsm_R1("mflr", op.rd); break; + case 0x009: DisAsm_R1("mfctr", op.rd); break; + default: DisAsm_R1_IMM("mfspr", op.rd, op.spr); break; + } +} + +void PPUDisAsm::LWAX(ppu_opcode_t op) +{ + DisAsm_R3("lwax", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::DST(ppu_opcode_t op) +{ + DisAsm_R2("dst(t)", op.ra, op.rb); +} + +void PPUDisAsm::LHAX(ppu_opcode_t op) +{ + DisAsm_R3("lhax", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::LVXL(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvxl", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::MFTB(ppu_opcode_t op) +{ + const u32 n = (op.spr >> 5) | ((op.spr & 0x1f) << 5); + switch (n) + { + case 268: DisAsm_R1("mftb", op.rd); break; + case 269: DisAsm_R1("mftbu", op.rd); break; + default: DisAsm_R1_IMM("mftb", op.rd, op.spr); break; + } +} + +void PPUDisAsm::LWAUX(ppu_opcode_t op) +{ + DisAsm_R3("lwaux", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::DSTST(ppu_opcode_t op) +{ + DisAsm_R2("dstst(t)", op.ra, op.rb); +} + +void PPUDisAsm::LHAUX(ppu_opcode_t op) +{ + DisAsm_R3("lhaux", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::STHX(ppu_opcode_t op) +{ + DisAsm_R3("sthx", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::ORC(ppu_opcode_t op) +{ + DisAsm_R3_RC("orc", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::ECOWX(ppu_opcode_t op) +{ + DisAsm_R3("ecowx", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STHUX(ppu_opcode_t op) +{ + DisAsm_R3("sthux", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::OR(ppu_opcode_t op) +{ + if (op.rs == op.rb) + { + DisAsm_R2_RC("mr", op.ra, op.rb, op.rc); + } + else + { + DisAsm_R3_RC("or", op.ra, op.rs, op.rb, op.rc); + } +} + +void PPUDisAsm::DIVDU(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("divdu", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::DIVWU(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("divwu", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::MTSPR(ppu_opcode_t op) +{ + const u32 n = (op.spr & 0x1f) + ((op.spr >> 5) & 0x1f); + + switch (n) + { + case 0x001: DisAsm_R1("mtxer", op.rs); break; + case 0x008: DisAsm_R1("mtlr", op.rs); break; + case 0x009: DisAsm_R1("mtctr", op.rs); break; + default: DisAsm_IMM_R1("mtspr", op.spr, op.rs); break; + } +} + +void PPUDisAsm::DCBI(ppu_opcode_t op) +{ + DisAsm_R2("dcbi", op.ra, op.rb); +} + +void PPUDisAsm::NAND(ppu_opcode_t op) +{ + DisAsm_R3_RC("nand", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::STVXL(ppu_opcode_t op) +{ + DisAsm_V1_R2("stvxl", op.vs, op.ra, op.rb); +} + +void PPUDisAsm::DIVD(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("divd", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::DIVW(ppu_opcode_t op) +{ + DisAsm_R3_OE_RC("divw", op.rd, op.ra, op.rb, op.oe, op.rc); +} + +void PPUDisAsm::LVLX(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvlx", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::LDBRX(ppu_opcode_t op) +{ + DisAsm_R3("ldbrx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::LSWX(ppu_opcode_t op) +{ + DisAsm_R3("lswx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::LWBRX(ppu_opcode_t op) +{ + DisAsm_R3("lwbrx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::LFSX(ppu_opcode_t op) +{ + DisAsm_F1_R2("lfsx", op.frd, op.ra, op.rb); +} + +void PPUDisAsm::SRW(ppu_opcode_t op) +{ + DisAsm_R3_RC("srw", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::SRD(ppu_opcode_t op) +{ + DisAsm_R3_RC("srd", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::LVRX(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvrx", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::LSWI(ppu_opcode_t op) +{ + DisAsm_R2_INT1("lswi", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::LFSUX(ppu_opcode_t op) +{ + DisAsm_F1_R2("lfsux", op.frd, op.ra, op.rb); +} + +void PPUDisAsm::SYNC(ppu_opcode_t op) +{ + Write("sync"); +} + +void PPUDisAsm::LFDX(ppu_opcode_t op) +{ + DisAsm_F1_R2("lfdx", op.frd, op.ra, op.rb); +} + +void PPUDisAsm::LFDUX(ppu_opcode_t op) +{ + DisAsm_F1_R2("lfdux", op.frd, op.ra, op.rb); +} + +void PPUDisAsm::STVLX(ppu_opcode_t op) +{ + DisAsm_V1_R2("stvlx", op.vs, op.ra, op.rb); +} + +void PPUDisAsm::STDBRX(ppu_opcode_t op) +{ + DisAsm_R3("stdbrx", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STSWX(ppu_opcode_t op) +{ + DisAsm_R3("swswx", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STWBRX(ppu_opcode_t op) +{ + DisAsm_R3("stwbrx", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::STFSX(ppu_opcode_t op) +{ + DisAsm_F1_R2("stfsx", op.frs, op.ra, op.rb); +} + +void PPUDisAsm::STVRX(ppu_opcode_t op) +{ + DisAsm_V1_R2("stvrx", op.vs, op.ra, op.rb); +} + +void PPUDisAsm::STFSUX(ppu_opcode_t op) +{ + DisAsm_F1_R2("stfsux", op.frs, op.ra, op.rb); +} + +void PPUDisAsm::STSWI(ppu_opcode_t op) +{ + DisAsm_R2_INT1("stswi", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::STFDX(ppu_opcode_t op) +{ + DisAsm_F1_R2("stfdx", op.frs, op.ra, op.rb); +} + +void PPUDisAsm::STFDUX(ppu_opcode_t op) +{ + DisAsm_F1_R2("stfdux", op.frs, op.ra, op.rb); +} + +void PPUDisAsm::LVLXL(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvlxl", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::LHBRX(ppu_opcode_t op) +{ + DisAsm_R3("lhbrx", op.rd, op.ra, op.rb); +} + +void PPUDisAsm::SRAW(ppu_opcode_t op) +{ + DisAsm_R3_RC("sraw", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::SRAD(ppu_opcode_t op) +{ + DisAsm_R3_RC("srad", op.ra, op.rs, op.rb, op.rc); +} + +void PPUDisAsm::LVRXL(ppu_opcode_t op) +{ + DisAsm_V1_R2("lvrxl", op.vd, op.ra, op.rb); +} + +void PPUDisAsm::DSS(ppu_opcode_t op) +{ + Write("dss()"); +} + +void PPUDisAsm::SRAWI(ppu_opcode_t op) +{ + DisAsm_R2_INT1_RC("srawi", op.ra, op.rs, op.sh32, op.rc); +} + +void PPUDisAsm::SRADI(ppu_opcode_t op) +{ + DisAsm_R2_INT1_RC("sradi", op.ra, op.rs, op.sh64, op.rc); +} + +void PPUDisAsm::EIEIO(ppu_opcode_t op) +{ + Write("eieio"); +} + +void PPUDisAsm::STVLXL(ppu_opcode_t op) +{ + DisAsm_V1_R2("stvlxl", op.vs, op.ra, op.rb); +} + +void PPUDisAsm::STHBRX(ppu_opcode_t op) +{ + DisAsm_R3("sthbrx", op.rs, op.ra, op.rb); +} + +void PPUDisAsm::EXTSH(ppu_opcode_t op) +{ + DisAsm_R2_RC("extsh", op.ra, op.rs, op.rc); +} + +void PPUDisAsm::STVRXL(ppu_opcode_t op) +{ + DisAsm_V1_R2("stvrxl", op.vs, op.ra, op.rb); +} + +void PPUDisAsm::EXTSB(ppu_opcode_t op) +{ + DisAsm_R2_RC("extsb", op.ra, op.rs, op.rc); +} + +void PPUDisAsm::STFIWX(ppu_opcode_t op) +{ + DisAsm_F1_R2("stfiwx", op.frs, op.ra, op.rb); +} + +void PPUDisAsm::EXTSW(ppu_opcode_t op) +{ + DisAsm_R2_RC("extsw", op.ra, op.rs, op.rc); +} + +void PPUDisAsm::ICBI(ppu_opcode_t op) +{ + DisAsm_R2("icbi", op.ra, op.rb); +} + +void PPUDisAsm::DCBZ(ppu_opcode_t op) +{ + DisAsm_R2("dcbz", op.ra, op.rb); +} + +void PPUDisAsm::LWZ(ppu_opcode_t op) +{ + DisAsm_R2_IMM("lwz", op.rd, op.ra, op.simm16); +} + +void PPUDisAsm::LWZU(ppu_opcode_t op) +{ + DisAsm_R2_IMM("lwzu", op.rd, op.ra, op.simm16); +} + +void PPUDisAsm::LBZ(ppu_opcode_t op) +{ + DisAsm_R2_IMM("lbz", op.rd, op.ra, op.simm16); +} + +void PPUDisAsm::LBZU(ppu_opcode_t op) +{ + DisAsm_R2_IMM("lbzu", op.rd, op.ra, op.simm16); +} + +void PPUDisAsm::STW(ppu_opcode_t op) +{ + DisAsm_R2_IMM("stw", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::STWU(ppu_opcode_t op) +{ + DisAsm_R2_IMM("stwu", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::STB(ppu_opcode_t op) +{ + DisAsm_R2_IMM("stb", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::STBU(ppu_opcode_t op) +{ + DisAsm_R2_IMM("stbu", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::LHZ(ppu_opcode_t op) +{ + DisAsm_R2_IMM("lhz", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::LHZU(ppu_opcode_t op) +{ + DisAsm_R2_IMM("lhzu", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::LHA(ppu_opcode_t op) +{ + DisAsm_R2_IMM("lha", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::LHAU(ppu_opcode_t op) +{ + DisAsm_R2_IMM("lhau", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::STH(ppu_opcode_t op) +{ + DisAsm_R2_IMM("sth", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::STHU(ppu_opcode_t op) +{ + DisAsm_R2_IMM("sthu", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::LMW(ppu_opcode_t op) +{ + DisAsm_R2_IMM("lmw", op.rd, op.ra, op.simm16); +} + +void PPUDisAsm::STMW(ppu_opcode_t op) +{ + DisAsm_R2_IMM("stmw", op.rs, op.ra, op.simm16); +} + +void PPUDisAsm::LFS(ppu_opcode_t op) +{ + DisAsm_F1_IMM_R1("lfs", op.frd, op.simm16, op.ra); +} + +void PPUDisAsm::LFSU(ppu_opcode_t op) +{ + DisAsm_F1_IMM_R1("lfsu", op.frd, op.simm16, op.ra); +} + +void PPUDisAsm::LFD(ppu_opcode_t op) +{ + DisAsm_F1_IMM_R1("lfd", op.frd, op.simm16, op.ra); +} + +void PPUDisAsm::LFDU(ppu_opcode_t op) +{ + DisAsm_F1_IMM_R1("lfdu", op.frd, op.simm16, op.ra); +} + +void PPUDisAsm::STFS(ppu_opcode_t op) +{ + DisAsm_F1_IMM_R1("stfs", op.frs, op.simm16, op.ra); +} + +void PPUDisAsm::STFSU(ppu_opcode_t op) +{ + DisAsm_F1_IMM_R1("stfsu", op.frs, op.simm16, op.ra); +} + +void PPUDisAsm::STFD(ppu_opcode_t op) +{ + DisAsm_F1_IMM_R1("stfd", op.frs, op.simm16, op.ra); +} + +void PPUDisAsm::STFDU(ppu_opcode_t op) +{ + DisAsm_F1_IMM_R1("stfdu", op.frs, op.simm16, op.ra); +} + +void PPUDisAsm::LD(ppu_opcode_t op) +{ + DisAsm_R2_IMM("ld", op.rd, op.ra, op.ds * 4); +} + +void PPUDisAsm::LDU(ppu_opcode_t op) +{ + DisAsm_R2_IMM("ldu", op.rd, op.ra, op.ds * 4); +} + +void PPUDisAsm::LWA(ppu_opcode_t op) +{ + DisAsm_R2_IMM("lwa", op.rd, op.ra, op.ds * 4); +} + +void PPUDisAsm::FDIVS(ppu_opcode_t op) +{ + DisAsm_F3_RC("fdivs", op.frd, op.fra, op.frb, op.rc); +} + +void PPUDisAsm::FSUBS(ppu_opcode_t op) +{ + DisAsm_F3_RC("fsubs", op.frd, op.fra, op.frb, op.rc); +} + +void PPUDisAsm::FADDS(ppu_opcode_t op) +{ + DisAsm_F3_RC("fadds", op.frd, op.fra, op.frb, op.rc); +} + +void PPUDisAsm::FSQRTS(ppu_opcode_t op) +{ + DisAsm_F2_RC("fsqrts", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FRES(ppu_opcode_t op) +{ + DisAsm_F2_RC("fres", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FMULS(ppu_opcode_t op) +{ + DisAsm_F3_RC("fmuls", op.frd, op.fra, op.frc, op.rc); +} + +void PPUDisAsm::FMADDS(ppu_opcode_t op) +{ + DisAsm_F4_RC("fmadds", op.frd, op.fra, op.frc, op.frb, op.rc); +} + +void PPUDisAsm::FMSUBS(ppu_opcode_t op) +{ + DisAsm_F4_RC("fmsubs", op.frd, op.fra, op.frc, op.frb, op.rc); +} + +void PPUDisAsm::FNMSUBS(ppu_opcode_t op) +{ + DisAsm_F4_RC("fnmsubs", op.frd, op.fra, op.frc, op.frb, op.rc); +} + +void PPUDisAsm::FNMADDS(ppu_opcode_t op) +{ + DisAsm_F4_RC("fnmadds", op.frd, op.fra, op.frc, op.frb, op.rc); +} + +void PPUDisAsm::STD(ppu_opcode_t op) +{ + DisAsm_R2_IMM("std", op.rs, op.ra, op.ds * 4); +} + +void PPUDisAsm::STDU(ppu_opcode_t op) +{ + DisAsm_R2_IMM("stdu", op.rs, op.ra, op.ds * 4); +} + +void PPUDisAsm::MTFSB1(ppu_opcode_t op) +{ + Write(fmt::format("mtfsb1%s %d", op.rc ? "." : "", op.crbd)); +} + +void PPUDisAsm::MCRFS(ppu_opcode_t op) +{ + DisAsm_CR2("mcrfs", op.crfd, op.crfs); +} + +void PPUDisAsm::MTFSB0(ppu_opcode_t op) +{ + Write(fmt::format("mtfsb0%s %d", op.rc ? "." : "", op.crbd)); +} + +void PPUDisAsm::MTFSFI(ppu_opcode_t op) +{ + Write(fmt::format("mtfsfi%s cr%d,%d,%d", op.rc ? "." : "", op.crfd, op.i, op.l15)); +} + +void PPUDisAsm::MFFS(ppu_opcode_t op) +{ + DisAsm_F1_RC("mffs", op.frd, op.rc); +} + +void PPUDisAsm::MTFSF(ppu_opcode_t op) +{ + Write(fmt::format("mtfsf%s %d,f%d,%d,%d", op.rc ? "." : "", op.rc, op.flm, op.frb, op.l6, op.l15)); +} + +void PPUDisAsm::FCMPU(ppu_opcode_t op) +{ + DisAsm_CR1_F2("fcmpu", op.crfd, op.fra, op.frb); +} + +void PPUDisAsm::FRSP(ppu_opcode_t op) +{ + DisAsm_F2_RC("frsp", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FCTIW(ppu_opcode_t op) +{ + DisAsm_F2_RC("fctiw", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FCTIWZ(ppu_opcode_t op) +{ + DisAsm_F2_RC("fctiwz", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FDIV(ppu_opcode_t op) +{ + DisAsm_F3_RC("fdiv", op.frd, op.fra, op.frb, op.rc); +} + +void PPUDisAsm::FSUB(ppu_opcode_t op) +{ + DisAsm_F3_RC("fsub", op.frd, op.fra, op.frb, op.rc); +} + +void PPUDisAsm::FADD(ppu_opcode_t op) +{ + DisAsm_F3_RC("fadd", op.frd, op.fra, op.frb, op.rc); +} + +void PPUDisAsm::FSQRT(ppu_opcode_t op) +{ + DisAsm_F2_RC("fsqrt", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FSEL(ppu_opcode_t op) +{ + DisAsm_F4_RC("fsel", op.frd, op.fra, op.frc, op.frb, op.rc); +} + +void PPUDisAsm::FMUL(ppu_opcode_t op) +{ + DisAsm_F3_RC("fmul", op.frd, op.fra, op.frc, op.rc); +} + +void PPUDisAsm::FRSQRTE(ppu_opcode_t op) +{ + DisAsm_F2_RC("frsqrte", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FMSUB(ppu_opcode_t op) +{ + DisAsm_F4_RC("fmsub", op.frd, op.fra, op.frc, op.frb, op.rc); +} + +void PPUDisAsm::FMADD(ppu_opcode_t op) +{ + DisAsm_F4_RC("fmadd", op.frd, op.fra, op.frc, op.frb, op.rc); +} + +void PPUDisAsm::FNMSUB(ppu_opcode_t op) +{ + DisAsm_F4_RC("fnmsub", op.frd, op.fra, op.frc, op.frb, op.rc); +} + +void PPUDisAsm::FNMADD(ppu_opcode_t op) +{ + DisAsm_F4_RC("fnmadd", op.frd, op.fra, op.frc, op.frb, op.rc); +} + +void PPUDisAsm::FCMPO(ppu_opcode_t op) +{ + DisAsm_F3("fcmpo", op.crfd, op.fra, op.frb); +} + +void PPUDisAsm::FNEG(ppu_opcode_t op) +{ + DisAsm_F2_RC("fneg", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FMR(ppu_opcode_t op) +{ + DisAsm_F2_RC("fmr", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FNABS(ppu_opcode_t op) +{ + DisAsm_F2_RC("fnabs", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FABS(ppu_opcode_t op) +{ + DisAsm_F2_RC("fabs", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FCTID(ppu_opcode_t op) +{ + DisAsm_F2_RC("fctid", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FCTIDZ(ppu_opcode_t op) +{ + DisAsm_F2_RC("fctidz", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::FCFID(ppu_opcode_t op) +{ + DisAsm_F2_RC("fcfid", op.frd, op.frb, op.rc); +} + +void PPUDisAsm::UNK(ppu_opcode_t op) +{ + Write(fmt::format("Unknown/Illegal opcode! (0x%08x)", op.opcode)); +} diff --git a/rpcs3/Emu/Cell/PPUDisAsm.h b/rpcs3/Emu/Cell/PPUDisAsm.h index 53478560ac..7138bfe519 100644 --- a/rpcs3/Emu/Cell/PPUDisAsm.h +++ b/rpcs3/Emu/Cell/PPUDisAsm.h @@ -3,9 +3,7 @@ #include "Emu/Cell/PPCDisAsm.h" #include "Emu/Cell/PPUOpcodes.h" -class PPUDisAsm - : public PPUOpcodes - , public PPCDisAsm +class PPUDisAsm final : public PPCDisAsm { public: PPUDisAsm(CPUDisAsmMode mode) : PPCDisAsm(mode) @@ -15,7 +13,7 @@ public: private: u32 DisAsmBranchTarget(const s32 imm) { - return branchTarget(dump_pc, imm); + return ppu_branch_target(dump_pc, imm); } private: @@ -131,9 +129,9 @@ private: { DisAsm_R1_RC(op, r0, false); } - void DisAsm_R2_OE_RC(const std::string& op, u32 r0, u32 r1, u32 oe, u32 rc) + void DisAsm_R2_OE_RC(const std::string& op, u32 r0, u32 r1, u32 _oe, u32 rc) { - Write(fmt::format("%s%s%s r%d,r%d", FixOp(op).c_str(), (oe ? "o" : ""), (rc ? "." : ""), r0, r1)); + Write(fmt::format("%s%s%s r%d,r%d", FixOp(op).c_str(), (_oe ? "o" : ""), (rc ? "." : ""), r0, r1)); } void DisAsm_R2_RC(const std::string& op, u32 r0, u32 r1, u32 rc) { @@ -143,9 +141,9 @@ private: { DisAsm_R2_RC(op, r0, r1, false); } - void DisAsm_R3_OE_RC(const std::string& op, u32 r0, u32 r1, u32 r2, u32 oe, u32 rc) + void DisAsm_R3_OE_RC(const std::string& op, u32 r0, u32 r1, u32 r2, u32 _oe, u32 rc) { - Write(fmt::format("%s%s%s r%d,r%d,r%d", FixOp(op).c_str(), (oe ? "o" : ""), (rc ? "." : ""), r0, r1, r2)); + Write(fmt::format("%s%s%s r%d,r%d,r%d", FixOp(op).c_str(), (_oe ? "o" : ""), (rc ? "." : ""), r0, r1, r2)); } void DisAsm_R3_INT2_RC(const std::string& op, u32 r0, u32 r1, u32 r2, s32 i0, s32 i1, u32 rc) { @@ -242,1841 +240,389 @@ private: Write(fmt::format("%s cr%d,0x%x ", FixOp(op).c_str(), cr, DisAsmBranchTarget(pc))); } -private: - void NULL_OP() - { - Write( "null" ); - } +public: + u32 disasm(u32 pc) override; - void NOP() - { - Write( "nop" ); - } + void TDI(ppu_opcode_t op); + void TWI(ppu_opcode_t op); + void MFVSCR(ppu_opcode_t op); + void MTVSCR(ppu_opcode_t op); + void VADDCUW(ppu_opcode_t op); + void VADDFP(ppu_opcode_t op); + void VADDSBS(ppu_opcode_t op); + void VADDSHS(ppu_opcode_t op); + void VADDSWS(ppu_opcode_t op); + void VADDUBM(ppu_opcode_t op); + void VADDUBS(ppu_opcode_t op); + void VADDUHM(ppu_opcode_t op); + void VADDUHS(ppu_opcode_t op); + void VADDUWM(ppu_opcode_t op); + void VADDUWS(ppu_opcode_t op); + void VAND(ppu_opcode_t op); + void VANDC(ppu_opcode_t op); + void VAVGSB(ppu_opcode_t op); + void VAVGSH(ppu_opcode_t op); + void VAVGSW(ppu_opcode_t op); + void VAVGUB(ppu_opcode_t op); + void VAVGUH(ppu_opcode_t op); + void VAVGUW(ppu_opcode_t op); + void VCFSX(ppu_opcode_t op); + void VCFUX(ppu_opcode_t op); + void VCMPBFP(ppu_opcode_t op); + void VCMPEQFP(ppu_opcode_t op); + void VCMPEQUB(ppu_opcode_t op); + void VCMPEQUH(ppu_opcode_t op); + void VCMPEQUW(ppu_opcode_t op); + void VCMPGEFP(ppu_opcode_t op); + void VCMPGTFP(ppu_opcode_t op); + void VCMPGTSB(ppu_opcode_t op); + void VCMPGTSH(ppu_opcode_t op); + void VCMPGTSW(ppu_opcode_t op); + void VCMPGTUB(ppu_opcode_t op); + void VCMPGTUH(ppu_opcode_t op); + void VCMPGTUW(ppu_opcode_t op); + void VCTSXS(ppu_opcode_t op); + void VCTUXS(ppu_opcode_t op); + void VEXPTEFP(ppu_opcode_t op); + void VLOGEFP(ppu_opcode_t op); + void VMADDFP(ppu_opcode_t op); + void VMAXFP(ppu_opcode_t op); + void VMAXSB(ppu_opcode_t op); + void VMAXSH(ppu_opcode_t op); + void VMAXSW(ppu_opcode_t op); + void VMAXUB(ppu_opcode_t op); + void VMAXUH(ppu_opcode_t op); + void VMAXUW(ppu_opcode_t op); + void VMHADDSHS(ppu_opcode_t op); + void VMHRADDSHS(ppu_opcode_t op); + void VMINFP(ppu_opcode_t op); + void VMINSB(ppu_opcode_t op); + void VMINSH(ppu_opcode_t op); + void VMINSW(ppu_opcode_t op); + void VMINUB(ppu_opcode_t op); + void VMINUH(ppu_opcode_t op); + void VMINUW(ppu_opcode_t op); + void VMLADDUHM(ppu_opcode_t op); + void VMRGHB(ppu_opcode_t op); + void VMRGHH(ppu_opcode_t op); + void VMRGHW(ppu_opcode_t op); + void VMRGLB(ppu_opcode_t op); + void VMRGLH(ppu_opcode_t op); + void VMRGLW(ppu_opcode_t op); + void VMSUMMBM(ppu_opcode_t op); + void VMSUMSHM(ppu_opcode_t op); + void VMSUMSHS(ppu_opcode_t op); + void VMSUMUBM(ppu_opcode_t op); + void VMSUMUHM(ppu_opcode_t op); + void VMSUMUHS(ppu_opcode_t op); + void VMULESB(ppu_opcode_t op); + void VMULESH(ppu_opcode_t op); + void VMULEUB(ppu_opcode_t op); + void VMULEUH(ppu_opcode_t op); + void VMULOSB(ppu_opcode_t op); + void VMULOSH(ppu_opcode_t op); + void VMULOUB(ppu_opcode_t op); + void VMULOUH(ppu_opcode_t op); + void VNMSUBFP(ppu_opcode_t op); + void VNOR(ppu_opcode_t op); + void VOR(ppu_opcode_t op); + void VPERM(ppu_opcode_t op); + void VPKPX(ppu_opcode_t op); + void VPKSHSS(ppu_opcode_t op); + void VPKSHUS(ppu_opcode_t op); + void VPKSWSS(ppu_opcode_t op); + void VPKSWUS(ppu_opcode_t op); + void VPKUHUM(ppu_opcode_t op); + void VPKUHUS(ppu_opcode_t op); + void VPKUWUM(ppu_opcode_t op); + void VPKUWUS(ppu_opcode_t op); + void VREFP(ppu_opcode_t op); + void VRFIM(ppu_opcode_t op); + void VRFIN(ppu_opcode_t op); + void VRFIP(ppu_opcode_t op); + void VRFIZ(ppu_opcode_t op); + void VRLB(ppu_opcode_t op); + void VRLH(ppu_opcode_t op); + void VRLW(ppu_opcode_t op); + void VRSQRTEFP(ppu_opcode_t op); + void VSEL(ppu_opcode_t op); + void VSL(ppu_opcode_t op); + void VSLB(ppu_opcode_t op); + void VSLDOI(ppu_opcode_t op); + void VSLH(ppu_opcode_t op); + void VSLO(ppu_opcode_t op); + void VSLW(ppu_opcode_t op); + void VSPLTB(ppu_opcode_t op); + void VSPLTH(ppu_opcode_t op); + void VSPLTISB(ppu_opcode_t op); + void VSPLTISH(ppu_opcode_t op); + void VSPLTISW(ppu_opcode_t op); + void VSPLTW(ppu_opcode_t op); + void VSR(ppu_opcode_t op); + void VSRAB(ppu_opcode_t op); + void VSRAH(ppu_opcode_t op); + void VSRAW(ppu_opcode_t op); + void VSRB(ppu_opcode_t op); + void VSRH(ppu_opcode_t op); + void VSRO(ppu_opcode_t op); + void VSRW(ppu_opcode_t op); + void VSUBCUW(ppu_opcode_t op); + void VSUBFP(ppu_opcode_t op); + void VSUBSBS(ppu_opcode_t op); + void VSUBSHS(ppu_opcode_t op); + void VSUBSWS(ppu_opcode_t op); + void VSUBUBM(ppu_opcode_t op); + void VSUBUBS(ppu_opcode_t op); + void VSUBUHM(ppu_opcode_t op); + void VSUBUHS(ppu_opcode_t op); + void VSUBUWM(ppu_opcode_t op); + void VSUBUWS(ppu_opcode_t op); + void VSUMSWS(ppu_opcode_t op); + void VSUM2SWS(ppu_opcode_t op); + void VSUM4SBS(ppu_opcode_t op); + void VSUM4SHS(ppu_opcode_t op); + void VSUM4UBS(ppu_opcode_t op); + void VUPKHPX(ppu_opcode_t op); + void VUPKHSB(ppu_opcode_t op); + void VUPKHSH(ppu_opcode_t op); + void VUPKLPX(ppu_opcode_t op); + void VUPKLSB(ppu_opcode_t op); + void VUPKLSH(ppu_opcode_t op); + void VXOR(ppu_opcode_t op); + void MULLI(ppu_opcode_t op); + void SUBFIC(ppu_opcode_t op); + void CMPLI(ppu_opcode_t op); + void CMPI(ppu_opcode_t op); + void ADDIC(ppu_opcode_t op); + void ADDI(ppu_opcode_t op); + void ADDIS(ppu_opcode_t op); + void BC(ppu_opcode_t op); + void HACK(ppu_opcode_t op); + void SC(ppu_opcode_t op); + void B(ppu_opcode_t op); + void MCRF(ppu_opcode_t op); + void BCLR(ppu_opcode_t op); + void CRNOR(ppu_opcode_t op); + void CRANDC(ppu_opcode_t op); + void ISYNC(ppu_opcode_t op); + void CRXOR(ppu_opcode_t op); + void CRNAND(ppu_opcode_t op); + void CRAND(ppu_opcode_t op); + void CREQV(ppu_opcode_t op); + void CRORC(ppu_opcode_t op); + void CROR(ppu_opcode_t op); + void BCCTR(ppu_opcode_t op); + void RLWIMI(ppu_opcode_t op); + void RLWINM(ppu_opcode_t op); + void RLWNM(ppu_opcode_t op); + void ORI(ppu_opcode_t op); + void ORIS(ppu_opcode_t op); + void XORI(ppu_opcode_t op); + void XORIS(ppu_opcode_t op); + void ANDI(ppu_opcode_t op); + void ANDIS(ppu_opcode_t op); + void RLDICL(ppu_opcode_t op); + void RLDICR(ppu_opcode_t op); + void RLDIC(ppu_opcode_t op); + void RLDIMI(ppu_opcode_t op); + void RLDCL(ppu_opcode_t op); + void RLDCR(ppu_opcode_t op); + void CMP(ppu_opcode_t op); + void TW(ppu_opcode_t op); + void LVSL(ppu_opcode_t op); + void LVEBX(ppu_opcode_t op); + void SUBFC(ppu_opcode_t op); + void ADDC(ppu_opcode_t op); + void MULHDU(ppu_opcode_t op); + void MULHWU(ppu_opcode_t op); + void MFOCRF(ppu_opcode_t op); + void LWARX(ppu_opcode_t op); + void LDX(ppu_opcode_t op); + void LWZX(ppu_opcode_t op); + void SLW(ppu_opcode_t op); + void CNTLZW(ppu_opcode_t op); + void SLD(ppu_opcode_t op); + void AND(ppu_opcode_t op); + void CMPL(ppu_opcode_t op); + void LVSR(ppu_opcode_t op); + void LVEHX(ppu_opcode_t op); + void SUBF(ppu_opcode_t op); + void LDUX(ppu_opcode_t op); + void DCBST(ppu_opcode_t op); + void LWZUX(ppu_opcode_t op); + void CNTLZD(ppu_opcode_t op); + void ANDC(ppu_opcode_t op); + void TD(ppu_opcode_t op); + void LVEWX(ppu_opcode_t op); + void MULHD(ppu_opcode_t op); + void MULHW(ppu_opcode_t op); + void LDARX(ppu_opcode_t op); + void DCBF(ppu_opcode_t op); + void LBZX(ppu_opcode_t op); + void LVX(ppu_opcode_t op); + void NEG(ppu_opcode_t op); + void LBZUX(ppu_opcode_t op); + void NOR(ppu_opcode_t op); + void STVEBX(ppu_opcode_t op); + void SUBFE(ppu_opcode_t op); + void ADDE(ppu_opcode_t op); + void MTOCRF(ppu_opcode_t op); + void STDX(ppu_opcode_t op); + void STWCX(ppu_opcode_t op); + void STWX(ppu_opcode_t op); + void STVEHX(ppu_opcode_t op); + void STDUX(ppu_opcode_t op); + void STWUX(ppu_opcode_t op); + void STVEWX(ppu_opcode_t op); + void SUBFZE(ppu_opcode_t op); + void ADDZE(ppu_opcode_t op); + void STDCX(ppu_opcode_t op); + void STBX(ppu_opcode_t op); + void STVX(ppu_opcode_t op); + void SUBFME(ppu_opcode_t op); + void MULLD(ppu_opcode_t op); + void ADDME(ppu_opcode_t op); + void MULLW(ppu_opcode_t op); + void DCBTST(ppu_opcode_t op); + void STBUX(ppu_opcode_t op); + void ADD(ppu_opcode_t op); + void DCBT(ppu_opcode_t op); + void LHZX(ppu_opcode_t op); + void EQV(ppu_opcode_t op); + void ECIWX(ppu_opcode_t op); + void LHZUX(ppu_opcode_t op); + void XOR(ppu_opcode_t op); + void MFSPR(ppu_opcode_t op); + void LWAX(ppu_opcode_t op); + void DST(ppu_opcode_t op); + void LHAX(ppu_opcode_t op); + void LVXL(ppu_opcode_t op); + void MFTB(ppu_opcode_t op); + void LWAUX(ppu_opcode_t op); + void DSTST(ppu_opcode_t op); + void LHAUX(ppu_opcode_t op); + void STHX(ppu_opcode_t op); + void ORC(ppu_opcode_t op); + void ECOWX(ppu_opcode_t op); + void STHUX(ppu_opcode_t op); + void OR(ppu_opcode_t op); + void DIVDU(ppu_opcode_t op); + void DIVWU(ppu_opcode_t op); + void MTSPR(ppu_opcode_t op); + void DCBI(ppu_opcode_t op); + void NAND(ppu_opcode_t op); + void STVXL(ppu_opcode_t op); + void DIVD(ppu_opcode_t op); + void DIVW(ppu_opcode_t op); + void LVLX(ppu_opcode_t op); + void LDBRX(ppu_opcode_t op); + void LSWX(ppu_opcode_t op); + void LWBRX(ppu_opcode_t op); + void LFSX(ppu_opcode_t op); + void SRW(ppu_opcode_t op); + void SRD(ppu_opcode_t op); + void LVRX(ppu_opcode_t op); + void LSWI(ppu_opcode_t op); + void LFSUX(ppu_opcode_t op); + void SYNC(ppu_opcode_t op); + void LFDX(ppu_opcode_t op); + void LFDUX(ppu_opcode_t op); + void STVLX(ppu_opcode_t op); + void STDBRX(ppu_opcode_t op); + void STSWX(ppu_opcode_t op); + void STWBRX(ppu_opcode_t op); + void STFSX(ppu_opcode_t op); + void STVRX(ppu_opcode_t op); + void STFSUX(ppu_opcode_t op); + void STSWI(ppu_opcode_t op); + void STFDX(ppu_opcode_t op); + void STFDUX(ppu_opcode_t op); + void LVLXL(ppu_opcode_t op); + void LHBRX(ppu_opcode_t op); + void SRAW(ppu_opcode_t op); + void SRAD(ppu_opcode_t op); + void LVRXL(ppu_opcode_t op); + void DSS(ppu_opcode_t op); + void SRAWI(ppu_opcode_t op); + void SRADI(ppu_opcode_t op); + void EIEIO(ppu_opcode_t op); + void STVLXL(ppu_opcode_t op); + void STHBRX(ppu_opcode_t op); + void EXTSH(ppu_opcode_t op); + void STVRXL(ppu_opcode_t op); + void EXTSB(ppu_opcode_t op); + void STFIWX(ppu_opcode_t op); + void EXTSW(ppu_opcode_t op); + void ICBI(ppu_opcode_t op); + void DCBZ(ppu_opcode_t op); + void LWZ(ppu_opcode_t op); + void LWZU(ppu_opcode_t op); + void LBZ(ppu_opcode_t op); + void LBZU(ppu_opcode_t op); + void STW(ppu_opcode_t op); + void STWU(ppu_opcode_t op); + void STB(ppu_opcode_t op); + void STBU(ppu_opcode_t op); + void LHZ(ppu_opcode_t op); + void LHZU(ppu_opcode_t op); + void LHA(ppu_opcode_t op); + void LHAU(ppu_opcode_t op); + void STH(ppu_opcode_t op); + void STHU(ppu_opcode_t op); + void LMW(ppu_opcode_t op); + void STMW(ppu_opcode_t op); + void LFS(ppu_opcode_t op); + void LFSU(ppu_opcode_t op); + void LFD(ppu_opcode_t op); + void LFDU(ppu_opcode_t op); + void STFS(ppu_opcode_t op); + void STFSU(ppu_opcode_t op); + void STFD(ppu_opcode_t op); + void STFDU(ppu_opcode_t op); + void LD(ppu_opcode_t op); + void LDU(ppu_opcode_t op); + void LWA(ppu_opcode_t op); + void FDIVS(ppu_opcode_t op); + void FSUBS(ppu_opcode_t op); + void FADDS(ppu_opcode_t op); + void FSQRTS(ppu_opcode_t op); + void FRES(ppu_opcode_t op); + void FMULS(ppu_opcode_t op); + void FMADDS(ppu_opcode_t op); + void FMSUBS(ppu_opcode_t op); + void FNMSUBS(ppu_opcode_t op); + void FNMADDS(ppu_opcode_t op); + void STD(ppu_opcode_t op); + void STDU(ppu_opcode_t op); + void MTFSB1(ppu_opcode_t op); + void MCRFS(ppu_opcode_t op); + void MTFSB0(ppu_opcode_t op); + void MTFSFI(ppu_opcode_t op); + void MFFS(ppu_opcode_t op); + void MTFSF(ppu_opcode_t op); + void FCMPU(ppu_opcode_t op); + void FRSP(ppu_opcode_t op); + void FCTIW(ppu_opcode_t op); + void FCTIWZ(ppu_opcode_t op); + void FDIV(ppu_opcode_t op); + void FSUB(ppu_opcode_t op); + void FADD(ppu_opcode_t op); + void FSQRT(ppu_opcode_t op); + void FSEL(ppu_opcode_t op); + void FMUL(ppu_opcode_t op); + void FRSQRTE(ppu_opcode_t op); + void FMSUB(ppu_opcode_t op); + void FMADD(ppu_opcode_t op); + void FNMSUB(ppu_opcode_t op); + void FNMADD(ppu_opcode_t op); + void FCMPO(ppu_opcode_t op); + void FNEG(ppu_opcode_t op); + void FMR(ppu_opcode_t op); + void FNABS(ppu_opcode_t op); + void FABS(ppu_opcode_t op); + void FCTID(ppu_opcode_t op); + void FCTIDZ(ppu_opcode_t op); + void FCFID(ppu_opcode_t op); - void TDI(u32 to, u32 ra, s32 simm16) - { - DisAsm_INT1_R1_IMM("tdi", to, ra, simm16); - } - void TWI(u32 to, u32 ra, s32 simm16) - { - DisAsm_INT1_R1_IMM("twi", to, ra, simm16); - } - void MFVSCR(u32 vd) - { - DisAsm_V1("mfvscr", vd); - } - void MTVSCR(u32 vb) - { - DisAsm_V1("mtvscr", vb); - } - void VADDCUW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vaddcuw", vd, va, vb); - } - void VADDFP(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vaddfp", vd, va, vb); - } - void VADDSBS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vaddsbs", vd, va, vb); - } - void VADDSHS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vaddshs", vd, va, vb); - } - void VADDSWS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vaddsws", vd, va, vb); - } - void VADDUBM(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vaddubm", vd, va, vb); - } - void VADDUBS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vaddubs", vd, va, vb); - } - void VADDUHM(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vadduhm", vd, va, vb); - } - void VADDUHS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vadduhs", vd, va, vb); - } - void VADDUWM(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vadduwm", vd, va, vb); - } - void VADDUWS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vadduws", vd, va, vb); - } - void VAND(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vand", vd, va, vb); - } - void VANDC(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vandc", vd, va, vb); - } - void VAVGSB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vavgsb", vd, va, vb); - } - void VAVGSH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vavgsh", vd, va, vb); - } - void VAVGSW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vavgsw", vd, va, vb); - } - void VAVGUB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vavgub", vd, va, vb); - } - void VAVGUH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vavguh", vd, va, vb); - } - void VAVGUW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vavguw", vd, va, vb); - } - void VCFSX(u32 vd, u32 uimm5, u32 vb) - { - DisAsm_V2_UIMM("vcfsx", vd, vb, uimm5); - } - void VCFUX(u32 vd, u32 uimm5, u32 vb) - { - DisAsm_V2_UIMM("vcfux", vd, vb, uimm5); - } - void VCMPBFP(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpbfp", vd, va, vb); - } - void VCMPBFP_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpbfp.", vd, va, vb); - } - void VCMPEQFP(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpeqfp", vd, va, vb); - } - void VCMPEQFP_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpeqfp.", vd, va, vb); - } - void VCMPEQUB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpequb", vd, va, vb); - } - void VCMPEQUB_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpequb.", vd, va, vb); - } - void VCMPEQUH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpequh", vd, va, vb); - } - void VCMPEQUH_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpequh.", vd, va, vb); - } - void VCMPEQUW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpequw", vd, va, vb); - } - void VCMPEQUW_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpequw.", vd, va, vb); - } - void VCMPGEFP(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgefp", vd, va, vb); - } - void VCMPGEFP_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgefp.", vd, va, vb); - } - void VCMPGTFP(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtfp", vd, va, vb); - } - void VCMPGTFP_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtfp.", vd, va, vb); - } - void VCMPGTSB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtsb", vd, va, vb); - } - void VCMPGTSB_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtsb.", vd, va, vb); - } - void VCMPGTSH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtsh", vd, va, vb); - } - void VCMPGTSH_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtsh.", vd, va, vb); - } - void VCMPGTSW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtsw", vd, va, vb); - } - void VCMPGTSW_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtsw.", vd, va, vb); - } - void VCMPGTUB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtub", vd, va, vb); - } - void VCMPGTUB_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtub.", vd, va, vb); - } - void VCMPGTUH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtuh", vd, va, vb); - } - void VCMPGTUH_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtuh.", vd, va, vb); - } - void VCMPGTUW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtuw", vd, va, vb); - } - void VCMPGTUW_(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vcmpgtuw.", vd, va, vb); - } - void VCTSXS(u32 vd, u32 uimm5, u32 vb) - { - DisAsm_V2_UIMM("vctsxs", vd, vb, uimm5); - } - void VCTUXS(u32 vd, u32 uimm5, u32 vb) - { - DisAsm_V2_UIMM("vctuxs", vd, vb, uimm5); - } - void VEXPTEFP(u32 vd, u32 vb) - { - DisAsm_V2("vexptefp", vd, vb); - } - void VLOGEFP(u32 vd, u32 vb) - { - DisAsm_V2("vlogefp", vd, vb); - } - void VMADDFP(u32 vd, u32 va, u32 vc, u32 vb) - { - DisAsm_V4("vmaddfp", vd, va, vc, vb); - } - void VMAXFP(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmaxfp", vd, va, vb); - } - void VMAXSB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmaxsb", vd, va, vb); - } - void VMAXSH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmaxsh", vd, va, vb); - } - void VMAXSW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmaxsw", vd, va, vb); - } - void VMAXUB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmaxub", vd, va, vb); - } - void VMAXUH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmaxuh", vd, va, vb); - } - void VMAXUW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmaxuw", vd, va, vb); - } - void VMHADDSHS(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vmhaddshs", vd, va, vb, vc); - } - void VMHRADDSHS(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vmhraddshs", vd, va, vb, vc); - } - void VMINFP(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vminfp", vd, va, vb); - } - void VMINSB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vminsb", vd, va, vb); - } - void VMINSH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vminsh", vd, va, vb); - } - void VMINSW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vminsw", vd, va, vb); - } - void VMINUB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vminub", vd, va, vb); - } - void VMINUH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vminuh", vd, va, vb); - } - void VMINUW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vminuw", vd, va, vb); - } - void VMLADDUHM(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vmladduhm", vd, va, vb, vc); - } - void VMRGHB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmrghb", vd, va, vb); - } - void VMRGHH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmrghh", vd, va, vb); - } - void VMRGHW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmrghw", vd, va, vb); - } - void VMRGLB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmrglb", vd, va, vb); - } - void VMRGLH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmrglh", vd, va, vb); - } - void VMRGLW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmrglw", vd, va, vb); - } - void VMSUMMBM(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vmsummbm", vd, va, vb, vc); - } - void VMSUMSHM(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vmsumshm", vd, va, vb, vc); - } - void VMSUMSHS(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vmsumshs", vd, va, vb, vc); - } - void VMSUMUBM(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vmsumubm", vd, va, vb, vc); - } - void VMSUMUHM(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vmsumuhm", vd, va, vb, vc); - } - void VMSUMUHS(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vmsumuhs", vd, va, vb, vc); - } - void VMULESB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmulesb", vd, va, vb); - } - void VMULESH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmulesh", vd, va, vb); - } - void VMULEUB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmuleub", vd, va, vb); - } - void VMULEUH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmuleuh", vd, va, vb); - } - void VMULOSB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmulosb", vd, va, vb); - } - void VMULOSH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmulosh", vd, va, vb); - } - void VMULOUB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmuloub", vd, va, vb); - } - void VMULOUH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vmulouh", vd, va, vb); - } - void VNMSUBFP(u32 vd, u32 va, u32 vc, u32 vb) - { - DisAsm_V4("vnmsubfp", vd, va, vc, vb); - } - void VNOR(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vnor", vd, va, vb); - } - void VOR(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vor", vd, va, vb); - } - void VPERM(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vperm", vd, va, vb, vc); - } - void VPKPX(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vpkpx", vd, va, vb); - } - void VPKSHSS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vpkshss", vd, va, vb); - } - void VPKSHUS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vpkshus", vd, va, vb); - } - void VPKSWSS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vpkswss", vd, va, vb); - } - void VPKSWUS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vpkswus", vd, va, vb); - } - void VPKUHUM(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vpkuhum", vd, va, vb); - } - void VPKUHUS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vpkuhus", vd, va, vb); - } - void VPKUWUM(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vpkuwum", vd, va, vb); - } - void VPKUWUS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vpkuwus", vd, va, vb); - } - void VREFP(u32 vd, u32 vb) - { - DisAsm_V2("vrefp", vd, vb); - } - void VRFIM(u32 vd, u32 vb) - { - DisAsm_V2("vrfim", vd, vb); - } - void VRFIN(u32 vd, u32 vb) - { - DisAsm_V2("vrfin", vd, vb); - } - void VRFIP(u32 vd, u32 vb) - { - DisAsm_V2("vrfip", vd, vb); - } - void VRFIZ(u32 vd, u32 vb) - { - DisAsm_V2("vrfiz", vd, vb); - } - void VRLB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vrlb", vd, va, vb); - } - void VRLH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vrlh", vd, va, vb); - } - void VRLW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vrlw", vd, va, vb); - } - void VRSQRTEFP(u32 vd, u32 vb) - { - DisAsm_V2("vrsqrtefp", vd, vb); - } - void VSEL(u32 vd, u32 va, u32 vb, u32 vc) - { - DisAsm_V4("vsel", vd, va, vb, vc); - } - void VSL(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsl", vd, va, vb); - } - void VSLB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vslb", vd, va, vb); - } - void VSLDOI(u32 vd, u32 va, u32 vb, u32 sh) - { - DisAsm_V3_UIMM("vsldoi", vd, va, vb, sh); - } - void VSLH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vslh", vd, va, vb); - } - void VSLO(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vslo", vd, va, vb); - } - void VSLW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vslw", vd, va, vb); - } - void VSPLTB(u32 vd, u32 uimm5, u32 vb) - { - DisAsm_V2_UIMM("vspltb", vd, vb, uimm5); - } - void VSPLTH(u32 vd, u32 uimm5, u32 vb) - { - DisAsm_V2_UIMM("vsplth", vd, vb, uimm5); - } - void VSPLTISB(u32 vd, s32 simm5) - { - DisAsm_V1_SIMM("vspltisb", vd, simm5); - } - void VSPLTISH(u32 vd, s32 simm5) - { - DisAsm_V1_SIMM("vspltish", vd, simm5); - } - void VSPLTISW(u32 vd, s32 simm5) - { - DisAsm_V1_SIMM("vspltisw", vd, simm5); - } - void VSPLTW(u32 vd, u32 uimm5, u32 vb) - { - DisAsm_V2_UIMM("vspltw", vd, vb, uimm5); - } - void VSR(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsr", vd, va, vb); - } - void VSRAB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsrab", vd, va, vb); - } - void VSRAH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsrah", vd, va, vb); - } - void VSRAW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsraw", vd, va, vb); - } - void VSRB(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsrb", vd, va, vb); - } - void VSRH(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsrh", vd, va, vb); - } - void VSRO(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsro", vd, va, vb); - } - void VSRW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsrw", vd, va, vb); - } - void VSUBCUW(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsubcuw", vd, va, vb); - } - void VSUBFP(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsubfp", vd, va, vb); - } - void VSUBSBS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsubsbs", vd, va, vb); - } - void VSUBSHS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsubshs", vd, va, vb); - } - void VSUBSWS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsubsws", vd, va, vb); - } - void VSUBUBM(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsububm", vd, va, vb); - } - void VSUBUBS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsububs", vd, va, vb); - } - void VSUBUHM(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsubuhm", vd, va, vb); - } - void VSUBUHS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsubuhs", vd, va, vb); - } - void VSUBUWM(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsubuwm", vd, va, vb); - } - void VSUBUWS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsubuws", vd, va, vb); - } - void VSUMSWS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsumsws", vd, va, vb); - } - void VSUM2SWS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsum2sws", vd, va, vb); - } - void VSUM4SBS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsum4sbs", vd, va, vb); - } - void VSUM4SHS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsum4shs", vd, va, vb); - } - void VSUM4UBS(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vsum4ubs", vd, va, vb); - } - void VUPKHPX(u32 vd, u32 vb) - { - DisAsm_V2("vupkhpx", vd, vb); - } - void VUPKHSB(u32 vd, u32 vb) - { - DisAsm_V2("vupkhsb", vd, vb); - } - void VUPKHSH(u32 vd, u32 vb) - { - DisAsm_V2("vupkhsh", vd, vb); - } - void VUPKLPX(u32 vd, u32 vb) - { - DisAsm_V2("vupklpx", vd, vb); - } - void VUPKLSB(u32 vd, u32 vb) - { - DisAsm_V2("vupklsb", vd, vb); - } - void VUPKLSH(u32 vd, u32 vb) - { - DisAsm_V2("vupklsh", vd, vb); - } - void VXOR(u32 vd, u32 va, u32 vb) - { - DisAsm_V3("vxor", vd, va, vb); - } - void MULLI(u32 rd, u32 ra, s32 simm16) - { - DisAsm_R2_IMM("mulli", rd, ra, simm16); - } - void SUBFIC(u32 rd, u32 ra, s32 simm16) - { - DisAsm_R2_IMM("subfic", rd, ra, simm16); - } - void CMPLI(u32 crfd, u32 l, u32 ra, u32 uimm16) - { - DisAsm_CR1_R1_IMM(fmt::format("cmpl%si", (l ? "d" : "w")), crfd, ra, uimm16); - } - void CMPI(u32 crfd, u32 l, u32 ra, s32 simm16) - { - DisAsm_CR1_R1_IMM(fmt::format("cmp%si", (l ? "d" : "w")), crfd, ra, simm16); - } - void ADDIC(u32 rd, u32 ra, s32 simm16) - { - DisAsm_R2_IMM("addic", rd, ra, simm16); - } - void ADDIC_(u32 rd, u32 ra, s32 simm16) - { - DisAsm_R2_IMM("addic.", rd, ra, simm16); - } - void ADDI(u32 rd, u32 ra, s32 simm16) - { - if(ra == 0) - { - DisAsm_R1_IMM("li", rd, simm16); - } - else - { - DisAsm_R2_IMM("addi", rd, ra, simm16); - } - } - void ADDIS(u32 rd, u32 ra, s32 simm16) - { - if(ra == 0) - { - DisAsm_R1_IMM("lis", rd, simm16); - } - else - { - DisAsm_R2_IMM("addis", rd, ra, simm16); - } - } - void BC(u32 bo, u32 bi, s32 bd, u32 aa, u32 lk) - { - if(m_mode == CPUDisAsm_CompilerElfMode) - { - Write(fmt::format("bc 0x%x, 0x%x, 0x%x, %d, %d", bo, bi, bd, aa, lk)); - return; - } - - //TODO: aa lk - const u8 bo0 = (bo & 0x10) ? 1 : 0; - const u8 bo1 = (bo & 0x08) ? 1 : 0; - const u8 bo2 = (bo & 0x04) ? 1 : 0; - const u8 bo3 = (bo & 0x02) ? 1 : 0; - const u8 bo4 = (bo & 0x01) ? 1 : 0; - - if(bo0 && !bo1 && !bo2 && bo3 && !bo4) - { - DisAsm_CR_BRANCH("bdz", bi/4, bd); return; - } - else if(bo0 && bo1 && !bo2 && bo3 && !bo4) - { - DisAsm_CR_BRANCH("bdz-", bi/4, bd); return; - } - else if(bo0 && bo1 && !bo2 && bo3 && bo4) - { - DisAsm_CR_BRANCH("bdz+", bi/4, bd); return; - } - else if(bo0 && !bo1 && !bo2 && !bo3 && !bo4) - { - DisAsm_CR_BRANCH("bdnz", bi/4, bd); return; - } - else if(bo0 && bo1 && !bo2 && !bo3 && !bo4) - { - DisAsm_CR_BRANCH("bdnz-", bi/4, bd); return; - } - else if(bo0 && bo1 && !bo2 && !bo3 && bo4) - { - DisAsm_CR_BRANCH("bdnz+", bi/4, bd); return; - } - else if(!bo0 && !bo1 && bo2 && !bo3 && !bo4) - { - switch(bi % 4) - { - case 0x0: DisAsm_CR_BRANCH("bge", bi/4, bd); return; - case 0x1: DisAsm_CR_BRANCH("ble", bi/4, bd); return; - case 0x2: DisAsm_CR_BRANCH("bne", bi/4, bd); return; - } - } - else if(!bo0 && !bo1 && bo2 && bo3 && !bo4) - { - switch(bi % 4) - { - case 0x0: DisAsm_CR_BRANCH("bge-", bi/4, bd); return; - case 0x1: DisAsm_CR_BRANCH("ble-", bi/4, bd); return; - case 0x2: DisAsm_CR_BRANCH("bne-", bi/4, bd); return; - } - } - else if(!bo0 && !bo1 && bo2 && bo3 && bo4) - { - switch(bi % 4) - { - case 0x0: DisAsm_CR_BRANCH("bge+", bi/4, bd); return; - case 0x1: DisAsm_CR_BRANCH("ble+", bi/4, bd); return; - case 0x2: DisAsm_CR_BRANCH("bne+", bi/4, bd); return; - } - } - else if(!bo0 && bo1 && bo2 && !bo3 && !bo4) - { - switch(bi % 4) - { - case 0x0: DisAsm_CR_BRANCH("blt", bi/4, bd); return; - case 0x1: DisAsm_CR_BRANCH("bgt", bi/4, bd); return; - case 0x2: DisAsm_CR_BRANCH("beq", bi/4, bd); return; - } - } - else if(!bo0 && bo1 && bo2 && bo3 && !bo4) - { - switch(bi % 4) - { - case 0x0: DisAsm_CR_BRANCH("blt-", bi/4, bd); return; - case 0x1: DisAsm_CR_BRANCH("bgt-", bi/4, bd); return; - case 0x2: DisAsm_CR_BRANCH("beq-", bi/4, bd); return; - } - } - else if(!bo0 && bo1 && bo2 && bo3 && bo4) - { - switch(bi % 4) - { - case 0x0: DisAsm_CR_BRANCH("blt+", bi/4, bd); return; - case 0x1: DisAsm_CR_BRANCH("bgt+", bi/4, bd); return; - case 0x2: DisAsm_CR_BRANCH("beq+", bi/4, bd); return; - } - } - - Write(fmt::format("bc [%x:%x:%x:%x:%x], cr%d[%x], 0x%x, %d, %d", bo0, bo1, bo2, bo3, bo4, bi/4, bi%4, bd, aa, lk)); - } - void HACK(u32 index) - { - Write(fmt::format("hack %d", index)); - } - void SC(u32 lev) - { - switch (lev) - { - case 0x0: Write("sc"); break; - case 0x1: Write("HyperCall LV1"); break; - default: Write(fmt::format("Unknown sc: 0x%x", lev)); - } - } - void B(s32 ll, u32 aa, u32 lk) - { - if(m_mode == CPUDisAsm_CompilerElfMode) - { - Write(fmt::format("b 0x%x, %d, %d", ll, aa, lk)); - return; - } - - switch(lk) - { - case 0: - switch(aa) - { - case 0: DisAsm_BRANCH("b", ll); break; - case 1: DisAsm_BRANCH_A("ba", ll); break; - } - break; - - case 1: - switch(aa) - { - case 0: DisAsm_BRANCH("bl", ll); break; - case 1: DisAsm_BRANCH_A("bla", ll); break; - } - break; - } - } - void MCRF(u32 crfd, u32 crfs) - { - DisAsm_CR2("mcrf", crfd, crfs); - } - void BCLR(u32 bo, u32 bi, u32 bh, u32 lk) - { - const u8 bo0 = (bo & 0x10) ? 1 : 0; - const u8 bo1 = (bo & 0x08) ? 1 : 0; - const u8 bo2 = (bo & 0x04) ? 1 : 0; - const u8 bo3 = (bo & 0x02) ? 1 : 0; - - if(bo0 && !bo1 && bo2 && !bo3) {Write("blr"); return;} - Write(fmt::format("bclr [%x:%x:%x:%x], cr%d[%x], %d, %d", bo0, bo1, bo2, bo3, bi/4, bi%4, bh, lk)); - } - void CRNOR(u32 bt, u32 ba, u32 bb) - { - DisAsm_INT3("crnor", bt, ba, bb); - } - void CRANDC(u32 bt, u32 ba, u32 bb) - { - DisAsm_INT3("crandc", bt, ba, bb); - } - void ISYNC() - { - Write("isync"); - } - void CRXOR(u32 bt, u32 ba, u32 bb) - { - DisAsm_INT3("crxor", bt, ba, bb); - } - void CRNAND(u32 bt, u32 ba, u32 bb) - { - DisAsm_INT3("crnand", bt, ba, bb); - } - void CRAND(u32 bt, u32 ba, u32 bb) - { - DisAsm_INT3("crand", bt, ba, bb); - } - void CREQV(u32 bt, u32 ba, u32 bb) - { - DisAsm_INT3("creqv", bt, ba, bb); - } - void CRORC(u32 bt, u32 ba, u32 bb) - { - DisAsm_INT3("crorc", bt, ba, bb); - } - void CROR(u32 bt, u32 ba, u32 bb) - { - DisAsm_INT3("cror", bt, ba, bb); - } - void BCCTR(u32 bo, u32 bi, u32 bh, u32 lk) - { - switch(lk) - { - case 0: DisAsm_INT3("bcctr", bo, bi, bh); break; - case 1: DisAsm_INT3("bcctrl", bo, bi, bh); break; - } - } - void RLWIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) - { - DisAsm_R2_INT3_RC("rlwimi", ra, rs, sh, mb, me, rc); - } - void RLWINM(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) - { - DisAsm_R2_INT3_RC("rlwinm", ra, rs, sh, mb, me, rc); - } - void RLWNM(u32 ra, u32 rs, u32 rb, u32 MB, u32 ME, u32 rc) - { - DisAsm_R3_INT2_RC("rlwnm", ra, rs, rb, MB, ME, rc); - } - void ORI(u32 rs, u32 ra, u32 uimm16) - { - if(rs == 0 && ra == 0 && uimm16 == 0) - { - NOP(); - return; - } - DisAsm_R2_IMM("ori", rs, ra, uimm16); - } - void ORIS(u32 rs, u32 ra, u32 uimm16) - { - if(rs == 0 && ra == 0 && uimm16 == 0) - { - NOP(); - return; - } - DisAsm_R2_IMM("oris", rs, ra, uimm16); - } - void XORI(u32 ra, u32 rs, u32 uimm16) - { - DisAsm_R2_IMM("xori", ra, rs, uimm16); - } - void XORIS(u32 ra, u32 rs, u32 uimm16) - { - DisAsm_R2_IMM("xoris", ra, rs, uimm16); - } - void ANDI_(u32 ra, u32 rs, u32 uimm16) - { - DisAsm_R2_IMM("andi.", ra, rs, uimm16); - } - void ANDIS_(u32 ra, u32 rs, u32 uimm16) - { - DisAsm_R2_IMM("andis.", ra, rs, uimm16); - } - void RLDICL(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) - { - if(sh == 0) - { - DisAsm_R2_INT1_RC("clrldi", ra, rs, mb, rc); - } - else if(mb == 0) - { - DisAsm_R2_INT1_RC("rotldi", ra, rs, sh, rc); - } - else if(mb == 64 - sh) - { - DisAsm_R2_INT1_RC("srdi", ra, rs, mb, rc); - } - else - { - DisAsm_R2_INT2_RC("rldicl", ra, rs, sh, mb, rc); - } - } - void RLDICR(u32 ra, u32 rs, u32 sh, u32 me, u32 rc) - { - DisAsm_R2_INT2_RC("rldicr", ra, rs, sh, me, rc); - } - void RLDIC(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) - { - DisAsm_R2_INT2_RC("rldic", ra, rs, sh, mb, rc); - } - void RLDIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) - { - DisAsm_R2_INT2_RC("rldimi", ra, rs, sh, mb, rc); - } - void RLDC_LR(u32 ra, u32 rs, u32 rb, u32 m_eb, u32 is_r, u32 rc) - { - if (is_r) - DisAsm_R3_INT2_RC("rldcr", ra, rs, rb, m_eb, 0, rc); - else - DisAsm_R3_INT2_RC("rldcl", ra, rs, rb, m_eb, 0, rc); - } - void CMP(u32 crfd, u32 l, u32 ra, u32 rb) - { - DisAsm_CR1_R2(fmt::format("cmp%s", (l ? "d" : "w")), crfd, ra, rb); - } - void TW(u32 to, u32 ra, u32 rb) - { - DisAsm_INT1_R2("tw", to, ra, rb); - } - void LVSL(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvsl", vd, ra, rb); - } - void LVEBX(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvebx", vd, ra, rb); - } - void SUBFC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("subfc", rd, ra, rb, oe, rc); - } - void ADDC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("addc", rd, ra, rb, oe, rc); - } - void MULHDU(u32 rd, u32 ra, u32 rb, u32 rc) - { - DisAsm_R3_RC("mulhdu", rd, ra, rb, rc); - } - void MULHWU(u32 rd, u32 ra, u32 rb, u32 rc) - { - DisAsm_R3_RC("mulhwu", rd, ra, rb, rc); - } - void MFOCRF(u32 a, u32 rd, u32 crm) - { - if(a) - { - DisAsm_R1_IMM("mfocrf", rd, crm); - } - else - { - DisAsm_R1("mfcr", rd); - } - } - void LWARX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lwarx", rd, ra, rb); - } - void LDX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("ldx", rd, ra, rb); - } - void LWZX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lwzx", rd, ra, rb); - } - void SLW(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("slw", ra, rs, rb, rc); - } - void CNTLZW(u32 ra, u32 rs, u32 rc) - { - DisAsm_R2_RC("cntlzw", ra, rs, rc); - } - void SLD(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("sld", ra, rs, rb, rc); - } - void AND(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("and", ra, rs, rb, rc); - } - void CMPL(u32 crfd, u32 l, u32 ra, u32 rb) - { - DisAsm_CR1_R2(fmt::format("cmpl%s", (l ? "d" : "w")), crfd, ra, rb); - } - void LVSR(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvsr", vd, ra, rb); - } - void LVEHX(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvehx", vd, ra, rb); - } - void SUBF(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("subf", rd, ra, rb, oe, rc); - } - void LDUX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("ldux", rd, ra, rb); - } - void DCBST(u32 ra, u32 rb) - { - DisAsm_R2("dcbst", ra, rb); - } - void LWZUX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lwzux", rd, ra, rb); - } - void CNTLZD(u32 ra, u32 rs, u32 rc) - { - DisAsm_R2_RC("cntlzd", ra, rs, rc); - } - void ANDC(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("andc", ra, rs, rb, rc); - } - void TD(u32 to, u32 ra, u32 rb) - { - DisAsm_INT1_R2("td", to, ra, rb); - } - void LVEWX(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvewx", vd, ra, rb); - } - void MULHD(u32 rd, u32 ra, u32 rb, u32 rc) - { - DisAsm_R3_RC("mulhd", rd, ra, rb, rc); - } - void MULHW(u32 rd, u32 ra, u32 rb, u32 rc) - { - DisAsm_R3_RC("mulhw", rd, ra, rb, rc); - } - void LDARX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("ldarx", rd, ra, rb); - } - void DCBF(u32 ra, u32 rb) - { - DisAsm_R2("dcbf", ra, rb); - } - void LBZX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lbzx", rd, ra, rb); - } - void LVX(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvx", vd, ra, rb); - } - void NEG(u32 rd, u32 ra, u32 oe, u32 rc) - { - DisAsm_R2_OE_RC("neg", rd, ra, oe, rc); - } - void LBZUX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lbzux", rd, ra, rb); - } - void NOR(u32 ra, u32 rs, u32 rb, u32 rc) - { - if(rs == rb) - { - DisAsm_R2_RC("not", ra, rs, rc); - } - else - { - DisAsm_R3_RC("nor", ra, rs, rb, rc); - } - } - void STVEBX(u32 vs, u32 ra, u32 rb) - { - DisAsm_V1_R2("stvebx", vs, ra, rb); - } - void SUBFE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("subfe", rd, ra, rb, oe, rc); - } - void ADDE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("adde", rd, ra, rb, oe, rc); - } - void MTOCRF(u32 l, u32 crm, u32 rs) - { - if(l) - { - DisAsm_INT1_R1("mtocrf", crm, rs); - } - else - { - DisAsm_INT1_R1("mtcrf", crm, rs); - } - } - void STDX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("stdx.", rs, ra, rb); - } - void STWCX_(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("stwcx.", rs, ra, rb); - } - void STWX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("stwx", rs, ra, rb); - } - void STVEHX(u32 vs, u32 ra, u32 rb) - { - DisAsm_V1_R2("stvehx", vs, ra, rb); - } - void STDUX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("stdux", rs, ra, rb); - } - void STWUX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("stwux", rs, ra, rb); - } - void STVEWX(u32 vs, u32 ra, u32 rb) - { - DisAsm_V1_R2("stvewx", vs, ra, rb); - } - void SUBFZE(u32 rd, u32 ra, u32 oe, u32 rc) - { - DisAsm_R2_OE_RC("subfze", rd, ra, oe, rc); - } - void ADDZE(u32 rd, u32 ra, u32 oe, u32 rc) - { - DisAsm_R2_OE_RC("addze", rd, ra, oe, rc); - } - void STDCX_(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("stdcx.", rs, ra, rb); - } - void STBX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("stbx", rs, ra, rb); - } - void STVX(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("stvx", vd, ra, rb); - } - void SUBFME(u32 rd, u32 ra, u32 oe, u32 rc) - { - DisAsm_R2_OE_RC("subfme", rd, ra, oe, rc); - } - void MULLD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("mulld", rd, ra, rb, oe, rc); - } - void ADDME(u32 rd, u32 ra, u32 oe, u32 rc) - { - DisAsm_R2_OE_RC("addme", rd, ra, oe, rc); - } - void MULLW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("mullw", rd, ra, rb, oe, rc); - } - void DCBTST(u32 ra, u32 rb, u32 th) - { - DisAsm_R3("dcbtst", ra, rb, th); - } - void STBUX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("stbux", rs, ra, rb); - } - void ADD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("add", rd, ra, rb, oe, rc); - } - void DCBT(u32 ra, u32 rb, u32 th) - { - DisAsm_R2("dcbt", ra, rb); - } - void LHZX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lhzx", rd, ra, rb); - } - void EQV(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("eqv", ra, rs, rb, rc); - } - void ECIWX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("eciwx", rd, ra, rb); - } - void LHZUX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lhzux", rd, ra, rb); - } - void XOR(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("xor", ra, rs, rb, rc); - } - void MFSPR(u32 rd, u32 spr) - { - const u32 n = (spr >> 5) | ((spr & 0x1f) << 5); - switch(n) - { - case 0x001: DisAsm_R1("mfxer", rd); break; - case 0x008: DisAsm_R1("mflr", rd); break; - case 0x009: DisAsm_R1("mfctr", rd); break; - default: DisAsm_R1_IMM("mfspr", rd, spr); break; - } - } - void LWAX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lwax", rd, ra, rb); - } - void DST(u32 ra, u32 rb, u32 strm, u32 t) - { - if(t) - { - DisAsm_R2_INT1("dstt", ra, rb, strm); - } - else - { - DisAsm_R2_INT1("dst", ra, rb, strm); - } - } - void LHAX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lhax", rd, ra, rb); - } - void LVXL(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvxl", vd, ra, rb); - } - void MFTB(u32 rd, u32 spr) - { - const u32 n = (spr >> 5) | ((spr & 0x1f) << 5); - switch(n) - { - case 268: DisAsm_R1("mftb", rd); break; - case 269: DisAsm_R1("mftbu", rd); break; - default: DisAsm_R1_IMM("mftb", rd, spr); break; - } - } - void LWAUX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lwaux", rd, ra, rb); - } - void DSTST(u32 ra, u32 rb, u32 strm, u32 t) - { - if(t) - { - DisAsm_R2_INT1("dststt", ra, rb, strm); - } - else - { - DisAsm_R2_INT1("dstst", ra, rb, strm); - } - } - void LHAUX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lhaux", rd, ra, rb); - } - void STHX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("sthx", rs, ra, rb); - } - void ORC(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("orc", ra, rs, rb, rc); - } - void ECOWX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("ecowx", rs, ra, rb); - } - void STHUX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("sthux", rs, ra, rb); - } - void OR(u32 ra, u32 rs, u32 rb, u32 rc) - { - if(rs==rb) - { - DisAsm_R2_RC("mr", ra, rb, rc); - } - else - { - DisAsm_R3_RC("or", ra, rs, rb, rc); - } - } - void DIVDU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("divdu", rd, ra, rb, oe, rc); - } - void DIVWU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("divwu", rd, ra, rb, oe, rc); - } - void MTSPR(u32 spr, u32 rs) - { - const u32 n = (spr & 0x1f) + ((spr >> 5) & 0x1f); - - switch(n) - { - case 0x001: DisAsm_R1("mtxer", rs); break; - case 0x008: DisAsm_R1("mtlr", rs); break; - case 0x009: DisAsm_R1("mtctr", rs); break; - default: DisAsm_IMM_R1("mtspr", spr, rs); break; - } - } - void DCBI(u32 ra, u32 rb) - { - DisAsm_R2("dcbi", ra, rb); - } - void NAND(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("nand", ra, rs, rb, rc); - } - void STVXL(u32 vs, u32 ra, u32 rb) - { - DisAsm_V1_R2("stvxl", vs, ra, rb); - } - void DIVD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("divd", rd, ra, rb, oe, rc); - } - void DIVW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - DisAsm_R3_OE_RC("divw", rd, ra, rb, oe, rc); - } - void LVLX(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvlx", vd, ra, rb); - } - void LDBRX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("ldbrx", rd, ra, rb); - } - void LSWX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lswx", rd, ra, rb); - } - void LWBRX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lwbrx", rd, ra, rb); - } - void LFSX(u32 frd, u32 ra, u32 rb) - { - DisAsm_F1_R2("lfsx", frd, ra, rb); - } - void SRW(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("srw", ra, rs, rb, rc); - } - void SRD(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("srd", ra, rs, rb, rc); - } - void LVRX(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvrx", vd, ra, rb); - } - void LSWI(u32 rd, u32 ra, u32 nb) - { - DisAsm_R2_INT1("lswi", rd, ra, nb); - } - void LFSUX(u32 frd, u32 ra, u32 rb) - { - DisAsm_F1_R2("lfsux", frd, ra, rb); - } - void SYNC(u32 l) - { - DisAsm_INT1("sync", l); - } - void LFDX(u32 frd, u32 ra, u32 rb) - { - DisAsm_F1_R2("lfdx", frd, ra, rb); - } - void LFDUX(u32 frd, u32 ra, u32 rb) - { - DisAsm_F1_R2("lfdux", frd, ra, rb); - } - void STVLX(u32 vs, u32 ra, u32 rb) - { - DisAsm_V1_R2("stvlx", vs, ra, rb); - } - void STDBRX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("stdbrx", rs, ra, rb); - } - void STSWX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("swswx", rs, ra, rb); - } - void STWBRX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("stwbrx", rs, ra, rb); - } - void STFSX(u32 frs, u32 ra, u32 rb) - { - DisAsm_F1_R2("stfsx", frs, ra, rb); - } - void STVRX(u32 sd, u32 ra, u32 rb) - { - DisAsm_V1_R2("stvrx", sd, ra, rb); - } - void STFSUX(u32 frs, u32 ra, u32 rb) - { - DisAsm_F1_R2("stfsux", frs, ra, rb); - } - void STSWI(u32 rd, u32 ra, u32 nb) - { - DisAsm_R2_INT1("stswi", rd, ra, nb); - } - void STFDX(u32 frs, u32 ra, u32 rb) - { - DisAsm_F1_R2("stfdx", frs, ra, rb); - } - void STFDUX(u32 frs, u32 ra, u32 rb) - { - DisAsm_F1_R2("stfdux", frs, ra, rb); - } - void LVLXL(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvlxl", vd, ra, rb); - } - void LHBRX(u32 rd, u32 ra, u32 rb) - { - DisAsm_R3("lhbrx", rd, ra, rb); - } - void SRAW(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("sraw", ra, rs, rb, rc); - } - void SRAD(u32 ra, u32 rs, u32 rb, u32 rc) - { - DisAsm_R3_RC("srad", ra, rs, rb, rc); - } - void LVRXL(u32 vd, u32 ra, u32 rb) - { - DisAsm_V1_R2("lvrxl", vd, ra, rb); - } - void DSS(u32 strm, u32 a) - { - if(a) - { - Write("dssall"); - } - else - { - DisAsm_INT1("dss", strm); - } - } - void SRAWI(u32 ra, u32 rs, u32 sh, u32 rc) - { - DisAsm_R2_INT1_RC("srawi", ra, rs, sh, rc); - } - void SRADI1(u32 ra, u32 rs, u32 sh, u32 rc) - { - DisAsm_R2_INT1_RC("sradi", ra, rs, sh, rc); - } - void SRADI2(u32 ra, u32 rs, u32 sh, u32 rc) - { - DisAsm_R2_INT1_RC("sradi", ra, rs, sh, rc); - } - void EIEIO() - { - Write("eieio"); - } - void STVLXL(u32 vs, u32 ra, u32 rb) - { - DisAsm_V1_R2("stvlxl", vs, ra, rb); - } - void STHBRX(u32 rs, u32 ra, u32 rb) - { - DisAsm_R3("sthbrx", rs, ra, rb); - } - void EXTSH(u32 ra, u32 rs, u32 rc) - { - DisAsm_R2_RC("extsh", ra, rs, rc); - } - void STVRXL(u32 sd, u32 ra, u32 rb) - { - DisAsm_V1_R2("stvrxl", sd, ra, rb); - } - void EXTSB(u32 ra, u32 rs, u32 rc) - { - DisAsm_R2_RC("extsb", ra, rs, rc); - } - void STFIWX(u32 frs, u32 ra, u32 rb) - { - DisAsm_F1_R2("stfiwx", frs, ra, rb); - } - void EXTSW(u32 ra, u32 rs, u32 rc) - { - DisAsm_R2_RC("extsw", ra, rs, rc); - } - void ICBI(u32 ra, u32 rb) - { - DisAsm_R2("icbi", ra, rb); - } - void DCBZ(u32 ra, u32 rb) - { - DisAsm_R2("dcbz", ra, rb); - } - void LWZ(u32 rd, u32 ra, s32 d) - { - DisAsm_R2_IMM("lwz", rd, ra, d); - } - void LWZU(u32 rd, u32 ra, s32 d) - { - DisAsm_R2_IMM("lwzu", rd, ra, d); - } - void LBZ(u32 rd, u32 ra, s32 d) - { - DisAsm_R2_IMM("lbz", rd, ra, d); - } - void LBZU(u32 rd, u32 ra, s32 d) - { - DisAsm_R2_IMM("lbzu", rd, ra, d); - } - void STW(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("stw", rs, ra, d); - } - void STWU(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("stwu", rs, ra, d); - } - void STB(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("stb", rs, ra, d); - } - void STBU(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("stbu", rs, ra, d); - } - void LHZ(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("lhz", rs, ra, d); - } - void LHZU(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("lhzu", rs, ra, d); - } - void LHA(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("lha", rs, ra, d); - } - void LHAU(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("lhau", rs, ra, d); - } - void STH(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("sth", rs, ra, d); - } - void STHU(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("sthu", rs, ra, d); - } - void LMW(u32 rd, u32 ra, s32 d) - { - DisAsm_R2_IMM("lmw", rd, ra, d); - } - void STMW(u32 rs, u32 ra, s32 d) - { - DisAsm_R2_IMM("stmw", rs, ra, d); - } - void LFS(u32 frd, u32 ra, s32 d) - { - DisAsm_F1_IMM_R1("lfs", frd, d, ra); - } - void LFSU(u32 frd, u32 ra, s32 ds) - { - DisAsm_F1_IMM_R1("lfsu", frd, ds, ra); - } - void LFD(u32 frd, u32 ra, s32 d) - { - DisAsm_F1_IMM_R1("lfd", frd, d, ra); - } - void LFDU(u32 frd, u32 ra, s32 ds) - { - DisAsm_F1_IMM_R1("lfdu", frd, ds, ra); - } - void STFS(u32 frs, u32 ra, s32 d) - { - DisAsm_F1_IMM_R1("stfs", frs, d, ra); - } - void STFSU(u32 frs, u32 ra, s32 d) - { - DisAsm_F1_IMM_R1("stfsu", frs, d, ra); - } - void STFD(u32 frs, u32 ra, s32 d) - { - DisAsm_F1_IMM_R1("stfd", frs, d, ra); - } - void STFDU(u32 frs, u32 ra, s32 d) - { - DisAsm_F1_IMM_R1("stfdu", frs, d, ra); - } - void LD(u32 rd, u32 ra, s32 ds) - { - DisAsm_R2_IMM("ld", rd, ra, ds); - } - void LDU(u32 rd, u32 ra, s32 ds) - { - DisAsm_R2_IMM("ldu", rd, ra, ds); - } - void LWA(u32 rd, u32 ra, s32 ds) - { - DisAsm_R2_IMM("lwa", rd, ra, ds); - } - void FDIVS(u32 frd, u32 fra, u32 frb, u32 rc) - { - DisAsm_F3_RC("fdivs", frd, fra, frb, rc); - } - void FSUBS(u32 frd, u32 fra, u32 frb, u32 rc) - { - DisAsm_F3_RC("fsubs", frd, fra, frb, rc); - } - void FADDS(u32 frd, u32 fra, u32 frb, u32 rc) - { - DisAsm_F3_RC("fadds", frd, fra, frb, rc); - } - void FSQRTS(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fsqrts", frd, frb, rc); - } - void FRES(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fres", frd, frb, rc); - } - void FMULS(u32 frd, u32 fra, u32 frc, u32 rc) - { - DisAsm_F3_RC("fmuls", frd, fra, frc, rc); - } - void FMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) - { - DisAsm_F4_RC("fmadds", frd, fra, frc, frb, rc); - } - void FMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) - { - DisAsm_F4_RC("fmsubs", frd, fra, frc, frb, rc); - } - void FNMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) - { - DisAsm_F4_RC("fnmsubs", frd, fra, frc, frb, rc); - } - void FNMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) - { - DisAsm_F4_RC("fnmadds", frd, fra, frc, frb, rc); - } - void STD(u32 rs, u32 ra, s32 ds) - { - DisAsm_R2_IMM("std", rs, ra, ds); - } - void STDU(u32 rs, u32 ra, s32 ds) - { - DisAsm_R2_IMM("stdu", rs, ra, ds); - } - void MTFSB1(u32 bt, u32 rc) - { - DisAsm_F1_RC("mtfsb1", bt, rc); - } - void MCRFS(u32 bf, u32 bfa) - { - DisAsm_F2("mcrfs", bf, bfa); - } - void MTFSB0(u32 bt, u32 rc) - { - DisAsm_F1_RC("mtfsb0", bt, rc); - } - void MTFSFI(u32 crfd, u32 i, u32 rc) - { - DisAsm_F2_RC("mtfsfi", crfd, i, rc); - } - void MFFS(u32 frd, u32 rc) - { - DisAsm_F1_RC("mffs", frd, rc); - } - void MTFSF(u32 flm, u32 frb, u32 rc) - { - DisAsm_F2_RC("mtfsf", flm, frb, rc); - } - void FCMPU(u32 crfd, u32 fra, u32 frb) - { - DisAsm_CR1_F2("fcmpu", crfd, fra, frb); - } - void FRSP(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("frsp", frd, frb, rc); - } - void FCTIW(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fctiw", frd, frb, rc); - } - void FCTIWZ(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fctiwz", frd, frb, rc); - } - void FDIV(u32 frd, u32 fra, u32 frb, u32 rc) - { - DisAsm_F3_RC("fdiv", frd, fra, frb, rc); - } - void FSUB(u32 frd, u32 fra, u32 frb, u32 rc) - { - DisAsm_F3_RC("fsub", frd, fra, frb, rc); - } - void FADD(u32 frd, u32 fra, u32 frb, u32 rc) - { - DisAsm_F3_RC("fadd", frd, fra, frb, rc); - } - void FSQRT(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fsqrt", frd, frb, rc); - } - void FSEL(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) - { - DisAsm_F4_RC("fsel", frd, fra, frc, frb, rc); - } - void FMUL(u32 frd, u32 fra, u32 frc, u32 rc) - { - DisAsm_F3_RC("fmul", frd, fra, frc, rc); - } - void FRSQRTE(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("frsqrte", frd, frb, rc); - } - void FMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) - { - DisAsm_F4_RC("fmsub", frd, fra, frc, frb, rc); - } - void FMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) - { - DisAsm_F4_RC("fmadd", frd, fra, frc, frb, rc); - } - void FNMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) - { - DisAsm_F4_RC("fnmsub", frd, fra, frc, frb, rc); - } - void FNMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) - { - DisAsm_F4_RC("fnmadd", frd, fra, frc, frb, rc); - } - void FCMPO(u32 crfd, u32 fra, u32 frb) - { - DisAsm_F3("fcmpo", crfd, fra, frb); - } - void FNEG(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fneg", frd, frb, rc); - } - void FMR(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fmr", frd, frb, rc); - } - void FNABS(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fnabs", frd, frb, rc); - } - void FABS(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fabs", frd, frb, rc); - } - void FCTID(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fctid", frd, frb, rc); - } - void FCTIDZ(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fctidz", frd, frb, rc); - } - void FCFID(u32 frd, u32 frb, u32 rc) - { - DisAsm_F2_RC("fcfid", frd, frb, rc); - } - - void UNK(const u32 code, const u32 opcode, const u32 gcode) - { - Write(fmt::format("Unknown/Illegal opcode! (0x%08x : 0x%x : 0x%x)", code, opcode, gcode)); - } + void UNK(ppu_opcode_t op); }; - -#undef START_OPCODES_GROUP -#undef END_OPCODES_GROUP diff --git a/rpcs3/Emu/Cell/PPUFunction.cpp b/rpcs3/Emu/Cell/PPUFunction.cpp new file mode 100644 index 0000000000..8ad14ff3db --- /dev/null +++ b/rpcs3/Emu/Cell/PPUFunction.cpp @@ -0,0 +1,2379 @@ +#include "stdafx.h" +#include "PPUModule.h" + +extern std::string ppu_get_syscall_name(u64 code) +{ + switch (code) + { + case 1: return "sys_process_getpid"; + case 2: return "sys_process_wait_for_child"; + case 3: return "sys_process_exit"; + case 4: return "sys_process_get_status"; + case 5: return "sys_process_detach_child"; + case 12: return "sys_process_get_number_of_object"; + case 13: return "sys_process_get_id"; + case 14: return "sys_process_is_spu_lock_line_reservation_address"; + case 18: return "sys_process_getppid"; + case 19: return "sys_process_kill"; + case 21: return "_sys_process_spawn"; + case 22: return "sys_process_exit"; + case 23: return "sys_process_wait_for_child2"; + case 25: return "sys_process_get_sdk_version"; + case 26: return "_sys_process_exit"; + case 28: return "_sys_process_get_number_of_object"; + case 29: return "sys_process_get_id"; + case 30: return "_sys_process_get_paramsfo"; + case 31: return "sys_process_get_ppu_guid"; + case 41: return "_sys_ppu_thread_exit"; + case 43: return "sys_ppu_thread_yield"; + case 44: return "sys_ppu_thread_join"; + case 45: return "sys_ppu_thread_detach"; + case 46: return "sys_ppu_thread_get_join_state"; + case 47: return "sys_ppu_thread_set_priority"; + case 48: return "sys_ppu_thread_get_priority"; + case 49: return "sys_ppu_thread_get_stack_information"; + case 50: return "sys_ppu_thread_stop"; + case 51: return "sys_ppu_thread_restart"; + case 52: return "_sys_ppu_thread_create"; + case 53: return "sys_ppu_thread_start"; + case 56: return "sys_ppu_thread_rename"; + case 57: return "sys_ppu_thread_recover_page_fault"; + case 58: return "sys_ppu_thread_get_page_fault_context"; + case 60: return "sys_trace_create"; + case 61: return "sys_trace_start"; + case 62: return "sys_trace_stop"; + case 63: return "sys_trace_update_top_index"; + case 64: return "sys_trace_destroy"; + case 65: return "sys_trace_drain"; + case 66: return "sys_trace_attach_process"; + case 67: return "sys_trace_allocate_buffer"; + case 68: return "sys_trace_free_buffer"; + case 69: return "sys_trace_create2"; + case 70: return "sys_timer_create"; + case 71: return "sys_timer_destroy"; + case 72: return "sys_timer_get_information"; + case 73: return "_sys_timer_start"; + case 74: return "sys_timer_stop"; + case 75: return "sys_timer_connect_event_queue"; + case 76: return "sys_timer_disconnect_event_queue"; + case 77: return "sys_trace_create2_in_cbepm"; + case 80: return "sys_interrupt_tag_create"; + case 81: return "sys_interrupt_tag_destroy"; + case 82: return "sys_event_flag_create"; + case 83: return "sys_event_flag_destroy"; + case 84: return "_sys_interrupt_thread_establish"; + case 85: return "sys_event_flag_wait"; + case 86: return "sys_event_flag_trywait"; + case 87: return "sys_event_flag_set"; + case 88: return "sys_interrupt_thread_eoi"; + case 89: return "_sys_interrupt_thread_disestablish"; + case 90: return "sys_semaphore_create"; + case 91: return "sys_semaphore_destroy"; + case 92: return "sys_semaphore_wait"; + case 93: return "sys_semaphore_trywait"; + case 94: return "sys_semaphore_post"; + case 95: return "_sys_lwmutex_create"; + case 96: return "_sys_lwmutex_destroy"; + case 97: return "_sys_lwmutex_lock"; + case 98: return "_sys_lwmutex_unlock"; + case 99: return "_sys_lwmutex_trylock"; + case 100: return "sys_mutex_create"; + case 101: return "sys_mutex_destroy"; + case 102: return "sys_mutex_lock"; + case 103: return "sys_mutex_trylock"; + case 104: return "sys_mutex_unlock"; + case 105: return "sys_cond_create"; + case 106: return "sys_cond_destroy"; + case 107: return "sys_cond_wait"; + case 108: return "sys_cond_signal"; + case 109: return "sys_cond_signal_all"; + case 110: return "sys_cond_signal_to"; + case 111: return "_sys_lwcond_create"; + case 112: return "_sys_lwcond_destroy"; + case 113: return "_sys_lwcond_queue_wait"; + case 114: return "sys_semaphore_get_value"; + case 115: return "_sys_lwcond_signal"; + case 116: return "_sys_lwcond_signal_all"; + case 118: return "sys_event_flag_clear"; + case 120: return "sys_rwlock_create"; + case 121: return "sys_rwlock_destroy"; + case 122: return "sys_rwlock_rlock"; + case 123: return "sys_rwlock_tryrlock"; + case 124: return "sys_rwlock_runlock"; + case 125: return "sys_rwlock_wlock"; + case 126: return "sys_rwlock_trywlock"; + case 127: return "sys_rwlock_wunlock"; + case 128: return "sys_event_queue_create"; + case 129: return "sys_event_queue_destroy"; + case 130: return "sys_event_queue_receive"; + case 131: return "sys_event_queue_tryreceive"; + case 132: return "sys_event_flag_cancel"; + case 133: return "sys_event_queue_drain"; + case 134: return "sys_event_port_create"; + case 135: return "sys_event_port_destroy"; + case 136: return "sys_event_port_connect_local"; + case 137: return "sys_event_port_disconnect"; + case 138: return "sys_event_port_send"; + case 139: return "sys_event_flag_get"; + case 140: return "sys_event_port_connect_ipc"; + case 141: return "sys_timer_usleep"; + case 142: return "sys_timer_sleep"; + case 143: return "sys_time_set_timezone"; + case 144: return "sys_time_get_timezone"; + case 145: return "sys_time_get_current_time"; + case 146: return "sys_time_get_system_time"; + case 147: return "sys_time_get_timebase_frequency"; + case 148: return "_sys_rwlock_trywlock"; + case 150: return "sys_raw_spu_create_interrupt_tag"; + case 151: return "sys_raw_spu_set_int_mask"; + case 152: return "sys_raw_spu_get_int_mask"; + case 153: return "sys_raw_spu_set_int_stat"; + case 154: return "sys_raw_spu_get_int_stat"; + case 155: return "sys_spu_image_get_information?"; + case 156: return "sys_spu_image_open"; + case 157: return "sys_spu_image_import"; + case 158: return "sys_spu_image_close"; + case 159: return "sys_raw_spu_load"; + case 160: return "sys_raw_spu_create"; + case 161: return "sys_raw_spu_destroy"; + case 163: return "sys_raw_spu_read_puint_mb"; + case 165: return "sys_spu_thread_get_exit_status"; + case 166: return "sys_spu_thread_set_argument"; + case 167: return "sys_spu_thread_group_start_on_exit"; + case 169: return "sys_spu_initialize"; + case 170: return "sys_spu_thread_group_create"; + case 171: return "sys_spu_thread_group_destroy"; + case 172: return "sys_spu_thread_initialize"; + case 173: return "sys_spu_thread_group_start"; + case 174: return "sys_spu_thread_group_suspend"; + case 175: return "sys_spu_thread_group_resume"; + case 176: return "sys_spu_thread_group_yield"; + case 177: return "sys_spu_thread_group_terminate"; + case 178: return "sys_spu_thread_group_join"; + case 179: return "sys_spu_thread_group_set_priority"; + case 180: return "sys_spu_thread_group_get_priority"; + case 181: return "sys_spu_thread_write_ls"; + case 182: return "sys_spu_thread_read_ls"; + case 184: return "sys_spu_thread_write_snr"; + case 185: return "sys_spu_thread_group_connect_event"; + case 186: return "sys_spu_thread_group_disconnect_event"; + case 187: return "sys_spu_thread_set_spu_cfg"; + case 188: return "sys_spu_thread_get_spu_cfg"; + case 190: return "sys_spu_thread_write_spu_mb"; + case 191: return "sys_spu_thread_connect_event"; + case 192: return "sys_spu_thread_disconnect_event"; + case 193: return "sys_spu_thread_bind_queue"; + case 194: return "sys_spu_thread_unbind_queue"; + case 196: return "sys_raw_spu_set_spu_cfg"; + case 197: return "sys_raw_spu_get_spu_cfg"; + case 198: return "sys_spu_thread_recover_page_fault"; + case 199: return "sys_raw_spu_recover_page_fault"; + case 215: return "sys_dbg_mat_set_condition"; + case 216: return "sys_dbg_mat_get_condition"; + case 230: return "sys_isolated_spu_create"; + case 231: return "sys_isolated_spu_destroy"; + case 232: return "sys_isolated_spu_start"; + case 233: return "sys_isolated_spu_create_interrupt_tag"; + case 234: return "sys_isolated_spu_set_int_mask"; + case 235: return "sys_isolated_spu_get_int_mask"; + case 236: return "sys_isolated_spu_set_int_stat"; + case 237: return "sys_isolated_spu_get_int_stat"; + case 238: return "sys_isolated_spu_set_spu_cfg"; + case 239: return "sys_isolated_spu_get_spu_cfg"; + case 240: return "sys_isolated_spu_read_puint_mb"; + case 244: return "sys_spu_thread_group_system_set_next_group"; + case 245: return "sys_spu_thread_group_system_unset_next_group"; + case 246: return "sys_spu_thread_group_system_set_switch_group"; + case 247: return "sys_spu_thread_group_system_unset_switch_group"; + case 250: return "sys_spu_thread_group_set_cooperative_victims"; + case 251: return "sys_spu_thread_group_connect_event_all_threads"; + case 252: return "sys_spu_thread_group_disconnect_event_all_threads"; + case 254: return "sys_spu_thread_group_log"; + case 260: return "sys_spu_image_open_by_fd"; + case 300: return "sys_vm_memory_map"; + case 301: return "sys_vm_unmap"; + case 302: return "sys_vm_append_memory"; + case 303: return "sys_vm_return_memory"; + case 304: return "sys_vm_lock"; + case 305: return "sys_vm_unlock"; + case 306: return "sys_vm_touch"; + case 307: return "sys_vm_flush"; + case 308: return "sys_vm_invalidate"; + case 309: return "sys_vm_store"; + case 310: return "sys_vm_sync"; + case 311: return "sys_vm_test"; + case 312: return "sys_vm_get_statistics"; + case 324: return "sys_memory_container_create"; + case 325: return "sys_memory_container_destroy"; + case 326: return "sys_mmapper_allocate_fixed_address"; + case 327: return "sys_mmapper_enable_page_fault_notification"; + case 329: return "sys_mmapper_free_shared_memory"; + case 330: return "sys_mmapper_allocate_address"; + case 331: return "sys_mmapper_free_address"; + case 332: return "sys_mmapper_allocate_shared_memory"; + case 333: return "sys_mmapper_set_shared_memory_flag"; + case 334: return "sys_mmapper_map_shared_memory"; + case 335: return "sys_mmapper_unmap_shared_memory"; + case 336: return "sys_mmapper_change_address_access_right"; + case 337: return "sys_mmapper_search_and_map"; + case 338: return "sys_mmapper_get_shared_memory_attribute"; + case 341: return "sys_memory_container_create"; + case 342: return "sys_memory_container_destroy"; + case 343: return "sys_memory_container_get_size"; + case 344: return "sys_memory_budget_set"; + case 348: return "sys_memory_allocate"; + case 349: return "sys_memory_free"; + case 350: return "sys_memory_allocate_from_container"; + case 351: return "sys_memory_get_page_attribute"; + case 352: return "sys_memory_get_user_memory_size"; + case 353: return "sys_memory_get_user_memory_stat"; + case 356: return "sys_memory_allocate_colored"; + case 361: return "sys_memory_allocate_from_container_colored"; + case 362: return "sys_mmapper_allocate_memory_from_container"; + case 367: return "sys_uart_initialize"; + case 368: return "sys_uart_receive"; + case 369: return "sys_uart_send"; + case 370: return "sys_uart_get_params"; + case 372: return "sys_game_watchdog_start"; + case 373: return "sys_game_watchdog_stop"; + case 374: return "sys_game_watchdog_clear"; + case 375: return "sys_game_set_system_sw_version"; + case 376: return "sys_game_get_system_sw_version"; + case 377: return "sys_sm_set_shop_mode"; + case 378: return "sys_sm_get_ext_event2"; + case 379: return "sys_sm_shutdown"; + case 380: return "sys_sm_get_params"; + case 381: return "sys_sm_get_inter_lpar_parameter"; + case 383: return "sys_game_get_temperature"; + case 384: return "sys_sm_get_tzpb"; + case 385: return "sys_sm_request_led"; + case 386: return "sys_sm_control_led"; + case 387: return "sys_sm_get_platform_info"; + case 388: return "sys_sm_ring_buzzer"; + case 389: return "sys_sm_set_fan_policy"; + case 390: return "sys_sm_request_error_log"; + case 391: return "sys_sm_request_be_count"; + case 392: return "sys_sm_ring_buzzer"; + case 393: return "sys_sm_get_hw_config"; + case 394: return "sys_sm_request_scversion"; + case 395: return "sys_sm_request_system_event_log"; + case 396: return "sys_sm_set_rtc_alarm"; + case 397: return "sys_sm_get_rtc_alarm"; + case 398: return "sys_console_write"; + case 402: return "sys_tty_read"; + case 403: return "sys_tty_write"; + case 408: return "sys_sm_get_tzpb"; + case 409: return "sys_sm_get_fan_policy"; + case 410: return "sys_game_board_storage_read"; + case 411: return "sys_game_board_storage_write"; + case 412: return "sys_game_get_rtc_status"; + case 450: return "sys_overlay_load_module"; + case 451: return "sys_overlay_unload_module"; + case 452: return "sys_overlay_get_module_list"; + case 453: return "sys_overlay_get_module_info"; + case 454: return "sys_overlay_load_module_by_fd"; + case 455: return "sys_overlay_get_module_info2"; + case 456: return "sys_overlay_get_sdk_version"; + case 457: return "sys_overlay_get_module_dbg_info"; + case 458: return "sys_overlay_get_module_dbg_info"; + case 460: return "sys_prx_dbg_get_module_id_list"; + case 461: return "sys_prx_get_module_id_by_address"; + case 463: return "sys_prx_load_module_by_fd"; + case 464: return "sys_prx_load_module_on_memcontainer_by_fd"; + case 465: return "sys_prx_load_module_list"; + case 466: return "sys_prx_load_module_list_on_memcontainer"; + case 467: return "sys_prx_get_ppu_guid"; + case 480: return "sys_prx_load_module"; + case 481: return "sys_prx_start_module"; + case 482: return "sys_prx_stop_module"; + case 483: return "sys_prx_unload_module"; + case 484: return "sys_prx_register_module"; + case 485: return "sys_prx_query_module"; + case 486: return "sys_prx_register_library"; + case 487: return "sys_prx_unregister_library"; + case 488: return "sys_prx_link_library"; + case 489: return "sys_prx_unlink_library"; + case 490: return "sys_prx_query_library"; + case 493: return "sys_prx_dbg_get_module_info"; + case 494: return "sys_prx_get_module_list"; + case 495: return "sys_prx_get_module_info"; + case 496: return "sys_prx_get_module_id_by_name"; + case 497: return "sys_prx_load_module_on_memcontainer"; + case 498: return "sys_prx_start"; + case 499: return "sys_prx_stop"; + case 500: return "sys_hid_manager_open"; + case 501: return "sys_hid_manager_close"; + case 502: return "sys_hid_manager_read"; + case 503: return "sys_hid_manager_ioctl"; + case 504: return "sys_hid_manager_map_logical_id_to_port_id"; + case 505: return "sys_hid_manager_unmap_logical_id_to_port_id"; + case 506: return "sys_hid_manager_add_hot_key_observer"; + case 507: return "sys_hid_manager_remove_hot_key_observer"; + case 508: return "sys_hid_manager_grab_focus"; + case 509: return "sys_hid_manager_release_focus"; + case 516: return "sys_config_open"; + case 517: return "sys_config_close"; + case 518: return "sys_config_get_service_event"; + case 519: return "sys_config_add_service_listener"; + case 520: return "sys_config_remove_service_listener"; + case 521: return "sys_config_register_service"; + case 522: return "sys_config_unregister_service"; + case 523: return "sys_config_io_event"; + case 530: return "sys_usbd_initialize"; + case 531: return "sys_usbd_finalize"; + case 532: return "sys_usbd_get_device_list"; + case 533: return "sys_usbd_get_descriptor_size"; + case 534: return "sys_usbd_get_descriptor"; + case 535: return "sys_usbd_register_ldd"; + case 536: return "sys_usbd_unregister_ldd"; + case 537: return "sys_usbd_open_pipe"; + case 538: return "sys_usbd_open_default_pipe"; + case 539: return "sys_usbd_close_pipe"; + case 540: return "sys_usbd_receive_event"; + case 541: return "sys_usbd_detect_event"; + case 542: return "sys_usbd_attach"; + case 543: return "sys_usbd_transfer_data"; + case 544: return "sys_usbd_isochronous_transfer_data"; + case 545: return "sys_usbd_get_transfer_status"; + case 546: return "sys_usbd_get_isochronous_transfer_status"; + case 547: return "sys_usbd_get_device_location"; + case 548: return "sys_usbd_send_event"; + case 550: return "sys_usbd_allocate_memory"; + case 551: return "sys_usbd_free_memory"; + case 556: return "sys_usbd_get_device_speed"; + case 559: return "sys_usbd_register_extra_ldd"; + case 571: return "sys_pad_ldd_unregister_controller"; + case 572: return "sys_pad_ldd_data_insert"; + case 573: return "sys_pad_dbg_ldd_set_data_insert_mode"; + case 574: return "sys_pad_ldd_register_controller"; + case 575: return "sys_pad_ldd_get_port_no"; + case 577: return "sys_pad_manager_..."; + case 600: return "sys_storage_open"; + case 601: return "sys_storage_close"; + case 602: return "sys_storage_read"; + case 603: return "sys_storage_write"; + case 604: return "sys_storage_send_device_command"; + case 605: return "sys_storage_async_configure"; + case 606: return "sys_storage_async_read"; + case 607: return "sys_storage_async_write"; + case 608: return "sys_storage_async_cancel"; + case 609: return "sys_storage_get_device_info"; + case 610: return "sys_storage_get_device_config"; + case 611: return "sys_storage_report_devices"; + case 612: return "sys_storage_configure_medium_event"; + case 613: return "sys_storage_set_medium_polling_interval"; + case 614: return "sys_storage_create_region"; + case 615: return "sys_storage_delete_region"; + case 616: return "sys_storage_execute_device_command"; + case 617: return "sys_storage_check_region_acl"; + case 618: return "sys_storage_set_region_acl"; + case 619: return "sys_storage_async_send_device_command"; + case 621: return "sys_gamepad_ycon_if"; + case 622: return "sys_storage_get_region_offset"; + case 623: return "sys_storage_set_emulated_speed"; + case 624: return "sys_io_buffer_create"; + case 625: return "sys_io_buffer_destroy"; + case 626: return "sys_io_buffer_allocate"; + case 627: return "sys_io_buffer_free"; + case 630: return "sys_gpio_set"; + case 631: return "sys_gpio_get"; + case 633: return "sys_fsw_connect_event"; + case 634: return "sys_fsw_disconnect_event"; + case 635: return "sys_btsetting_if"; + case 650: return "sys_rsxaudio_initialize"; + case 651: return "sys_rsxaudio_finalize"; + case 652: return "sys_rsxaudio_import_shared_memory"; + case 653: return "sys_rsxaudio_unimport_shared_memory"; + case 654: return "sys_rsxaudio_create_connection"; + case 655: return "sys_rsxaudio_close_connection"; + case 656: return "sys_rsxaudio_prepare_process"; + case 657: return "sys_rsxaudio_start_process"; + case 666: return "sys_rsx_device_open"; + case 667: return "sys_rsx_device_close"; + case 668: return "sys_rsx_memory_allocate"; + case 669: return "sys_rsx_memory_free"; + case 670: return "sys_rsx_context_allocate"; + case 671: return "sys_rsx_context_free"; + case 672: return "sys_rsx_context_iomap"; + case 673: return "sys_rsx_context_iounmap"; + case 674: return "sys_rsx_context_attribute"; + case 675: return "sys_rsx_device_map"; + case 676: return "sys_rsx_device_unmap"; + case 677: return "sys_rsx_attribute"; + case 699: return "sys_bdemu_send_command"; + case 700: return "sys_net_bnet_accept"; + case 701: return "sys_net_bnet_bind"; + case 702: return "sys_net_bnet_connect"; + case 703: return "sys_net_bnet_getpeername"; + case 704: return "sys_net_bnet_getsockname"; + case 705: return "sys_net_bnet_getsockopt"; + case 706: return "sys_net_bnet_listen"; + case 707: return "sys_net_bnet_recvfrom"; + case 708: return "sys_net_bnet_recvmsg"; + case 709: return "sys_net_bnet_sendmsg"; + case 710: return "sys_net_bnet_sendto"; + case 711: return "sys_net_bnet_setsockop"; + case 712: return "sys_net_bnet_shutdown"; + case 713: return "sys_net_bnet_socket"; + case 714: return "sys_net_bnet_close"; + case 715: return "sys_net_bnet_poll"; + case 716: return "sys_net_bnet_select"; + case 717: return "sys_net_open_dump"; + case 718: return "sys_net_read_dump"; + case 719: return "sys_net_close_dump"; + case 720: return "sys_net_write_dump"; + case 721: return "sys_net_abort"; + case 722: return "sys_net_infoctl"; + case 723: return "sys_net_control"; + case 724: return "sys_net_bnet_ioctl"; + case 725: return "sys_net_bnet_sysctl"; + case 726: return "sys_net_eurus_post_command"; + case 800: return "sys_fs_test"; + case 801: return "sys_fs_open"; + case 802: return "sys_fs_read"; + case 803: return "sys_fs_write"; + case 804: return "sys_fs_close"; + case 805: return "sys_fs_opendir"; + case 806: return "sys_fs_readdir"; + case 807: return "sys_fs_closedir"; + case 808: return "sys_fs_stat"; + case 809: return "sys_fs_fstat"; + case 810: return "sys_fs_link"; + case 811: return "sys_fs_mkdir"; + case 812: return "sys_fs_rename"; + case 813: return "sys_fs_rmdir"; + case 814: return "sys_fs_unlink"; + case 815: return "sys_fs_utime"; + case 816: return "sys_fs_access"; + case 817: return "sys_fs_fcntl"; + case 818: return "sys_fs_lseek"; + case 819: return "sys_fs_fdatasync"; + case 820: return "sys_fs_fsync"; + case 821: return "sys_fs_fget_block_size"; + case 822: return "sys_fs_get_block_size"; + case 823: return "sys_fs_acl_read"; + case 824: return "sys_fs_acl_write"; + case 825: return "sys_fs_lsn_get_cda_size"; + case 826: return "sys_fs_lsn_get_cda"; + case 827: return "sys_fs_lsn_lock"; + case 828: return "sys_fs_lsn_unlock"; + case 829: return "sys_fs_lsn_read"; + case 830: return "sys_fs_lsn_write"; + case 831: return "sys_fs_truncate"; + case 832: return "sys_fs_ftruncate"; + case 833: return "sys_fs_symbolic_link"; + case 834: return "sys_fs_chmod"; + case 835: return "sys_fs_chown"; + case 836: return "sys_fs_newfs"; + case 837: return "sys_fs_mount"; + case 838: return "sys_fs_unmount"; + case 839: return "sys_fs_sync"; + case 840: return "sys_fs_disk_free"; + case 841: return "sys_fs_get_mount_info_size"; + case 842: return "sys_fs_get_mount_info"; + case 843: return "sys_fs_get_fs_info_size"; + case 844: return "sys_fs_get_fs_info"; + case 845: return "sys_fs_mapped_allocate"; + case 846: return "sys_fs_mapped_free"; + case 847: return "sys_fs_truncate2"; + case 860: return "sys_ss_get_cache_of_analog_sunset_flag"; + case 865: return "sys_ss_random_number_generator"; + case 870: return "sys_ss_get_console_id"; + case 871: return "sys_ss_access_control_engine"; + case 872: return "sys_ss_get_open_psid"; + case 873: return "sys_ss_get_cache_of_product_mode"; + case 874: return "sys_ss_get_cache_of_flash_ext_flag"; + case 875: return "sys_ss_get_boot_device"; + case 876: return "sys_ss_disc_access_control"; + case 877: return "sys_ss_~utoken_if"; + case 878: return "sys_ss_ad_sign"; + case 879: return "sys_ss_media_id"; + case 880: return "sys_deci3_open"; + case 881: return "sys_deci3_create_event_path"; + case 882: return "sys_deci3_close"; + case 883: return "sys_deci3_send"; + case 884: return "sys_deci3_receive"; + case 885: return "sys_deci3_open2"; + case 890: return "sys_deci3_initialize"; + case 891: return "sys_deci3_terminate"; + case 892: return "sys_deci3_debug_mode"; + case 893: return "sys_deci3_show_status"; + case 894: return "sys_deci3_echo_test"; + case 895: return "sys_deci3_send_dcmp_packet"; + case 896: return "sys_deci3_dump_cp_register"; + case 897: return "sys_deci3_dump_cp_buffer"; + case 899: return "sys_deci3_test"; + case 900: return "sys_dbg_stop_processes"; + case 901: return "sys_dbg_continue_processes"; + case 902: return "sys_dbg_stop_threads"; + case 903: return "sys_dbg_continue_threads"; + case 904: return "sys_dbg_read_process_memory"; + case 905: return "sys_dbg_write_process_memory"; + case 906: return "sys_dbg_read_thread_register"; + case 907: return "sys_dbg_write_thread_register"; + case 908: return "sys_dbg_get_process_list"; + case 909: return "sys_dbg_get_thread_list"; + case 910: return "sys_dbg_get_thread_info"; + case 911: return "sys_dbg_spu_thread_read_from_ls"; + case 912: return "sys_dbg_spu_thread_write_to_ls"; + case 913: return "sys_dbg_kill_process"; + case 914: return "sys_dbg_get_process_info"; + case 915: return "sys_dbg_set_run_control_bit_to_spu"; + case 916: return "sys_dbg_spu_thread_get_exception_cause"; + case 917: return "sys_dbg_create_kernel_event_queue"; + case 918: return "sys_dbg_read_kernel_event_queue"; + case 919: return "sys_dbg_destroy_kernel_event_queue"; + case 920: return "sys_dbg_get_process_event_ctrl_flag"; + case 921: return "sys_dbg_set_process_event_cntl_flag"; + case 922: return "sys_dbg_get_spu_thread_group_event_cntl_flag"; + case 923: return "sys_dbg_set_spu_thread_group_event_cntl_flag"; + case 925: return "sys_dbg_get_raw_spu_list"; + case 932: return "sys_dbg_get_mutex_list"; + case 933: return "sys_dbg_get_mutex_information"; + case 934: return "sys_dbg_get_cond_list"; + case 935: return "sys_dbg_get_cond_information"; + case 936: return "sys_dbg_get_rwlock_list"; + case 937: return "sys_dbg_get_rwlock_information"; + case 938: return "sys_dbg_get_lwmutex_list"; + case 939: return "sys_dbg_get_address_from_dabr"; + case 940: return "sys_dbg_set_address_to_dabr"; + case 941: return "sys_dbg_get_lwmutex_information"; + case 942: return "sys_dbg_get_event_queue_list"; + case 943: return "sys_dbg_get_event_queue_information"; + case 944: return "sys_dbg_initialize_ppu_exception_handler"; + case 945: return "sys_dbg_finalize_ppu_exception_handler"; + case 946: return "sys_dbg_get_semaphore_list"; + case 947: return "sys_dbg_get_semaphore_information"; + case 948: return "sys_dbg_get_kernel_thread_list"; + case 949: return "sys_dbg_get_kernel_thread_info"; + case 950: return "sys_dbg_get_lwcond_list"; + case 951: return "sys_dbg_get_lwcond_information"; + case 952: return "sys_dbg_create_scratch_data_area_ext"; + case 953: return "sys_dbg_vm_get_page_information"; + case 954: return "sys_dbg_vm_get_info"; + case 955: return "sys_dbg_enable_floating_point_enabled_exception"; + case 956: return "sys_dbg_disable_floating_point_enabled_exception"; + case 960: return "sys_dbg_perfomance_monitor"; + case 970: return "sys_dbg_get_event_flag_list"; + case 971: return "sys_dbg_get_event_flag_information"; + case 975: return "sys_dbg_read_spu_thread_context2"; + case 985: return "sys_dbg_get_console_type"; + } + + return fmt::format("syscall_%llu", code); +} + +// Get function name by FNID +extern std::string ppu_get_function_name(const std::string& module, u32 fnid) +{ + // Check known FNIDs + if (module == "sys_libc" || module == "sys_libm") switch (fnid) + { + case 0x00acf0e5: return "spu_printf_finalize"; + case 0x00fb4a6b: return "spu_thread_sprintf"; + case 0x0125b2ca: return "_rand_int32_TT800"; + case 0x01508f24: return "raw_spu_write_float"; + case 0x0264f468: return "_Wctomb"; + case 0x02f4d325: return "spu_thread_read_double"; + case 0x02f52a3c: return "_filep_close_it"; + case 0x03becf3c: return "_Defloc"; + case 0x04a183fc: return "strcpy"; + case 0x04a1f19d: return "raw_spu_write_short"; + case 0x05d821c4: return "_Stoullx"; + case 0x077cdb23: return "btowc"; + case 0x07c7971d: return "_Stoldx"; + case 0x0871ffb0: return "mspace_malloc_usable_size"; + case 0x0891a3fa: return "_Tlsfree"; + case 0x09cbee1e: return "strxfrm"; + case 0x0a1d4b00: return "spu_thread_read_uint"; + case 0x0a4e2541: return "spu_thread_read_ldouble"; + case 0x0ae275a4: return "_Stolx"; + case 0x0b0d272f: return "_malloc_finalize"; + case 0x0b9d04d0: return "_Getnloc"; + case 0x0b9ecb98: return "toupper_ascii"; + case 0x0cae547f: return "raw_spu_write_double"; + case 0x0d2a593b: return "srand"; + case 0x0d8a2de0: return "_CStrxfrm"; + case 0x0df8809f: return "__call_functions_registered_with_atexit"; + case 0x0f60eb63: return "vfwscanf"; + case 0x0ff4722c: return "raw_spu_read_ushort"; + case 0x1096f8f1: return "ispunct_ascii"; + case 0x1098a99d: return "localeconv"; + case 0x112ea8ea: return "strspn"; + case 0x115e2f70: return "spu_thread_snprintf"; + case 0x116cda13: return "wcstol"; + case 0x118712ea: return "islower"; + case 0x11d270d2: return "exitspawn"; + case 0x126656b7: return "_Btowc"; + case 0x128b334f: return "raw_spu_read_mem"; + case 0x12a55fb7: return "mbrtowc"; + case 0x130d20a5: return "towlower"; + case 0x1365b52a: return "fcntl"; + case 0x13808972: return "wcstok"; + case 0x14052ae0: return "absi4"; + case 0x14348b57: return "divi4"; + case 0x145853cd: return "mspace_destroy"; + case 0x15362bc9: return "spu_thread_read_long"; + case 0x153b364a: return "mkdir"; + case 0x15bdcc00: return "rand"; + case 0x15c2e29d: return "isgraph_ascii"; + case 0x17752bab: return "wcsftime"; + case 0x17bc0136: return "_Lrv2d"; + case 0x17c031d7: return "spu_thread_read_ulong"; + case 0x1855b9b1: return "setlocale"; + case 0x1895908d: return "mspace_realloc"; + case 0x18e48b5d: return "wscanf"; + case 0x18f7b77d: return "_Dnorm"; + case 0x1970cd7e: return "getpid"; + case 0x19ccbb81: return "mktime"; + case 0x1ab01ea8: return "truncate"; + case 0x1abd0985: return "div"; + case 0x1ae06860: return "wcstoumax"; + case 0x1b4c3ff0: return "atexit"; + case 0x1c0e8ab6: return "vswscanf"; + case 0x1c2ef212: return "getwc"; + case 0x1cf4d80a: return "iswalpha"; + case 0x1dcd8609: return "_Strxfrmx"; + case 0x1dd0d4c5: return "spu_printf_attach_group"; + case 0x1df4732e: return "_Getptolower"; + case 0x1e9d2b4f: return "spu_thread_read_int"; + case 0x1ecae195: return "_Vacopy"; + case 0x1f913e8d: return "chmod"; + case 0x1f925c41: return "_allocate_mapped_pages"; + case 0x206612c4: return "spu_thread_read_ptr"; + case 0x216984ed: return "spu_thread_write_long"; + case 0x216fcd2a: return "_Atrealloc"; + case 0x21807b8e: return "towctrans"; + case 0x225702e1: return "_fs_initialize"; + case 0x22b0e566: return "_Stollx"; + case 0x23d3bca7: return "_Eadd"; + case 0x242c603e: return "_Frprep"; + case 0x243b52d8: return "_Mbtowcx"; + case 0x24802244: return "iswcntrl"; + case 0x24c9e021: return "abs"; + case 0x24e230d2: return "_Wctob"; + case 0x24f6cbdd: return "clock"; + case 0x253b7210: return "_rand_real2_TT800"; + case 0x25beee5a: return "__raw_spu_printf"; + case 0x25da8fbb: return "iscntrl"; + case 0x266311a0: return "localtime"; + case 0x2677568c: return "putchar"; + case 0x26f023d5: return "ftell"; + case 0x273b9711: return "sprintf"; + case 0x28b92ebf: return "raw_spu_read_uchar"; + case 0x296bc72f: return "_FDunscale"; + case 0x2b45cb34: return "wcsrtombs"; + case 0x2b7ba4ca: return "_Tlsset"; + case 0x2b81fb7f: return "readdir"; + case 0x2bc9dee6: return "raw_spu_read_short"; + case 0x2caea755: return "_Once"; + case 0x2d067448: return "ftruncate64"; + case 0x2d17ca7f: return "_Puttxt"; + case 0x2eea9f25: return "_Esub"; + case 0x2f45d39c: return "strlen"; + case 0x2fecec13: return "getwchar"; + case 0x30fb2899: return "_Getmem"; + case 0x312be3b3: return "_malloc_init_lv2"; + case 0x313f04ab: return "raw_spu_read_char"; + case 0x329a4540: return "_WPrintf"; + case 0x32e4a30a: return "_Mtxdst"; + case 0x336b4191: return "_Getint"; + case 0x33d6ae54: return "ferror"; + case 0x344eca7e: return "_WGetstr"; + case 0x34dd6650: return "_Getcloc"; + case 0x34e7c97e: return "_Unlocksyslock"; + case 0x3512ad38: return "tmpnam"; + case 0x355fd1fd: return "mbtowc"; + case 0x3574d37d: return "_Wcsxfrmx"; + case 0x36c067c1: return "_Stoll"; + case 0x36f2b4ed: return "strtoull"; + case 0x36feb965: return "raw_spu_write_llong"; + case 0x3704840e: return "_fs_finalize"; + case 0x38426d25: return "_Wctombx"; + case 0x3902363a: return "malloc_footprint"; + case 0x39bf419c: return "valloc"; + case 0x3a210c93: return "swscanf"; + case 0x3a840ae3: return "snprintf"; + case 0x3b22e88a: return "isxdigit"; + case 0x3b8097ac: return "_WScanf"; + case 0x3bce073b: return "putc"; + case 0x3bd9ce0a: return "fsync"; + case 0x3ca81c76: return "_Iswctype"; + case 0x3d1460e9: return "_Strerror"; + case 0x3d541975: return "atoi"; + case 0x3d5fdea7: return "vfwprintf"; + case 0x3d85d6f8: return "strcmp"; + case 0x3dbc3bee: return "opendir"; + case 0x3e57dfac: return "_Genld"; + case 0x3ec99a66: return "_Getptimes"; + case 0x3ee29d0b: return "_Stof"; + case 0x3f125e2e: return "spu_thread_write_short"; + case 0x3f4ccdc7: return "isdigit"; + case 0x3f650700: return "mspace_is_heap_empty"; + case 0x40a2599a: return "atol"; + case 0x40d04e4e: return "fwide"; + case 0x40e0ff25: return "_WGenld"; + case 0x41283333: return "isdigit_ascii"; + case 0x418bdfe1: return "_get_fd"; + case 0x4217b4cf: return "difftime"; + case 0x433fe2a9: return "fwscanf"; + case 0x44115dd0: return "_Geterrno"; + case 0x44796e5c: return "strerror"; + case 0x449317ed: return "_Fopen"; + case 0x44d7cae8: return "raw_spu_read_float"; + case 0x4544c2de: return "spu_thread_write_mem"; + case 0x4569518c: return "malloc_stats"; + case 0x459072c3: return "_init_TT800"; + case 0x4595c42b: return "wcsxfrm"; + case 0x468b45dc: return "mspace_calloc"; + case 0x4911ff9c: return "rand_int31_TT800"; + case 0x498a5036: return "raw_spu_write_mem"; + case 0x4a0049c6: return "_Getpctype"; + case 0x4ab5fbe2: return "_Printf"; + case 0x4b36c0e0: return "vfscanf"; + case 0x4b6a4010: return "vswprintf"; + case 0x4bb8e2b2: return "raw_spu_write_ushort"; + case 0x4c3f5f29: return "_Getgloballocale"; + case 0x4c7dc863: return "iswupper"; + case 0x4d348427: return "fputs"; + case 0x4e4be299: return "longjmp"; + case 0x4e72f810: return "wmemchr"; + case 0x4ffba189: return "feof"; + case 0x508196b4: return "raw_spu_printf"; + case 0x508e00c6: return "_Getloc"; + case 0x51b28904: return "_Stodx"; + case 0x526a496a: return "write"; + case 0x532b03be: return "raw_spu_read_uint"; + case 0x53eb43a1: return "_Getpmbstate"; + case 0x54b383bc: return "_Locvar"; + case 0x54c2844e: return "spu_raw_snprintf"; + case 0x54f57626: return "rewind"; + case 0x5516bbbf: return "iswctype"; + case 0x55d4866e: return "fgetws"; + case 0x5751acf9: return "_LDscale"; + case 0x575fb268: return "wctrans"; + case 0x57ff7dd7: return "_WStod"; + case 0x58320830: return "_WLitob"; + case 0x589b5314: return "strncat"; + case 0x5909e3c4: return "memset"; + case 0x59640bc6: return "raw_spu_read_ullong"; + case 0x59c1bb1f: return "_Getpwcstate"; + case 0x59e8dd58: return "strtoll"; + case 0x5a74f774: return "spu_thread_read_float"; + case 0x5b162b7f: return "memmove"; + case 0x5b4b6d6d: return "wcspbrk"; + case 0x5cc71eee: return "raw_spu_write_ldouble"; + case 0x5d43c1a3: return "_Mbtowc"; + case 0x5dbceee3: return "rand_int32_TT800"; + case 0x5e06c3fe: return "__getpid"; + case 0x5e7888f0: return "bsearch"; + case 0x5eb95641: return "_Stold"; + case 0x5f922a30: return "_Dscale"; + case 0x5f9a65c7: return "_WStold"; + case 0x5fa1e497: return "_Unlockfilelock"; + case 0x60627fb3: return "_LDunscale"; + case 0x6075a3c6: return "_Ld2rv"; + case 0x609080ec: return "isspace_ascii"; + case 0x6137d196: return "memalign"; + case 0x6287ac6a: return "iswdigit"; + case 0x62bf1d6c: return "swprintf"; + case 0x64aaf016: return "raw_spu_read_ldouble"; + case 0x6514dbe5: return "wcstold"; + case 0x6539ff6d: return "_Gentime"; + case 0x6545b7de: return "fgetpos"; + case 0x65e8d4d0: return "wcslen"; + case 0x6660fc8d: return "TlsGetValue"; + case 0x6687fba4: return "_Fgpos"; + case 0x66b71b17: return "wcsspn"; + case 0x67582370: return "spu_thread_write_double"; + case 0x676e3e7a: return "raw_spu_write_ptr"; + case 0x67d6334b: return "strtof"; + case 0x6823c180: return "iswprint"; + case 0x69106fd2: return "_init_by_array_TT800"; + case 0x692b497f: return "perror"; + case 0x6995f5e8: return "_Ldtob"; + case 0x69c27c12: return "fopen"; + case 0x69ff1b9b: return "fseek"; + case 0x6ba10474: return "_Tlsalloc"; + case 0x6cf78f3e: return "_Mtxunlock"; + case 0x6d5115b0: return "wcsncmp"; + case 0x6e988e5f: return "_rand_int31_TT800"; + case 0x7028dea9: return "_Locksyslock"; + case 0x703ec767: return "setvbuf"; + case 0x70b0e833: return "mblen"; + case 0x714c9618: return "__raw_spu_putfld"; + case 0x717b2502: return "stat"; + case 0x72236cbc: return "raw_spu_write_ullong"; + case 0x72b84004: return "spu_printf_attach_thread"; + case 0x73096858: return "wctob"; + case 0x7345b4be: return "_WStoll"; + case 0x73eae03d: return "strrchr"; + case 0x744d2505: return "ispunct"; + case 0x74fe4a7b: return "iswgraph"; + case 0x759e0635: return "malloc"; + case 0x75d4485c: return "rename"; + case 0x75f98579: return "wcscoll"; + case 0x76da0c84: return "ftruncate"; + case 0x76ed4243: return "_Wcsftime"; + case 0x770bfaee: return "wctype"; + case 0x77a602dd: return "free"; + case 0x77c15441: return "_WGetfloat"; + case 0x77e241bc: return "_Skip"; + case 0x7817edf0: return "raw_spu_write_uint"; + case 0x783636d1: return "spu_thread_read_char"; + case 0x78429d81: return "putwchar"; + case 0x79819dbf: return "fputc"; + case 0x7994c28d: return "_FDtentox"; + case 0x79eadf05: return "malloc_usable_size"; + case 0x7aaab95c: return "iswblank"; + case 0x7ae82e0f: return "vsprintf"; + case 0x7aee5acd: return "_Lockfilelock"; + case 0x7b5aac20: return "spu_thread_write_ptr"; + case 0x7b7a687a: return "_WPutfld"; + case 0x7b9c592e: return "spu_thread_read_ullong"; + case 0x7c1bcf37: return "isalnum_ascii"; + case 0x7c370679: return "_Foprep"; + case 0x7cec7b39: return "_Putfld"; + case 0x7d894764: return "_Readloc"; + case 0x7e7017b1: return "rmdir"; + case 0x7ea8d860: return "spu_printf_detach_group"; + case 0x7efd420a: return "_Daysto"; + case 0x7fd325c4: return "mspace_malloc_stats"; + case 0x7fdcf73e: return "wcscat"; + case 0x806fd281: return "isblank_ascii"; + case 0x809a143f: return "kill"; + case 0x813a9666: return "ungetwc"; + case 0x814d8cb0: return "fflush"; + case 0x81a0a858: return "_memset_int"; + case 0x82a3cc30: return "wcschr"; + case 0x82a4561a: return "_put_fd"; + case 0x831d70a5: return "memcpy"; + case 0x8342b757: return "utime"; + case 0x84378ddc: return "wcsncpy"; + case 0x86532174: return "imaxdiv"; + case 0x867275d7: return "_Stoul"; + case 0x86b4c669: return "tolower_ascii"; + case 0x8713c859: return "link"; + case 0x8725a1a7: return "_memset_vmx"; + case 0x87e8f748: return "memset_vmx"; + case 0x8809cdfd: return "_Getpwctytab"; + case 0x882689f2: return "_Makeloc"; + case 0x882e7760: return "raw_spu_write_uchar"; + case 0x889d5804: return "_Dunscale"; + case 0x88e009f5: return "vwprintf"; + case 0x896e1bfd: return "spu_thread_write_uchar"; + case 0x89b62f56: return "_Etentox"; + case 0x89f6f026: return "time"; + case 0x8a6830e7: return "abort"; + case 0x8a71132c: return "remove"; + case 0x8a847b51: return "tmpfile"; + case 0x8ab0abc6: return "strncpy"; + case 0x8b439438: return "clearerr"; + case 0x8b9d8dd2: return "iswpunct"; + case 0x8cb6bfdc: return "_Locsum"; + case 0x8d7ffaf1: return "_WStopfx"; + case 0x8e2484f1: return "_Emul"; + case 0x8ed71e8b: return "_WGetfld"; + case 0x8ef85e47: return "_WPuttxt"; + case 0x8f5dd179: return "_Nnl"; + case 0x90010029: return "gets"; + case 0x9027fd99: return "_WStoldx"; + case 0x90457fe3: return "raw_spu_read_long"; + case 0x90b27880: return "strtoumax"; + case 0x9234f738: return "raw_spu_read_int"; + case 0x93427cb9: return "setbuf"; + case 0x938bfcf7: return "spu_thread_write_char"; + case 0x93a3e3ac: return "tolower"; + case 0x9439e4cd: return "wcsncat"; + case 0x96b6baa6: return "spu_thread_read_mem"; + case 0x96e6303b: return "_WStoxflt"; + case 0x96ea4de6: return "wctomb"; + case 0x97896359: return "isspace"; + case 0x9800573c: return "_WLdtob"; + case 0x980d3ea7: return "_Getfld"; + case 0x9886810c: return "_FDnorm"; + case 0x98f0eeab: return "raw_spu_write_ulong"; + case 0x99782342: return "strncasecmp_ascii"; + case 0x99a72146: return "vsnprintf"; + case 0x99b38ce7: return "wmemmove"; + case 0x9a87bb3a: return "_Getmbcurmax"; + case 0x9abe8c74: return "wprintf"; + case 0x9c7028a5: return "spu_thread_write_uint"; + case 0x9c9d7b0d: return "strtold"; + case 0x9cab08d1: return "spu_thread_write_int"; + case 0x9d140351: return "_Destroytls"; + case 0x9eb25e00: return "strcoll"; + case 0x9eee5387: return "truncate64"; + case 0x9ff08d57: return "_Clearlocks"; + case 0xa0ab76d5: return "_absi4"; + case 0xa0bc0efb: return "mallinfo"; + case 0xa0ddba8e: return "_Stoulx"; + case 0xa1dbb466: return "_Gettime"; + case 0xa2945229: return "_WGetint"; + case 0xa30d4797: return "wcstoll"; + case 0xa3440924: return "closedir"; + case 0xa3da58f6: return "rand_real1_TT800"; + case 0xa45a0313: return "mspace_create"; + case 0xa483d50d: return "_rv2d"; + case 0xa53800c2: return "_malloc_finalize_lv2"; + case 0xa568db82: return "spu_thread_read_ushort"; + case 0xa57cc615: return "iswspace"; + case 0xa5bc0e19: return "getchar"; + case 0xa6463518: return "__rename"; + case 0xa650df19: return "toupper"; + case 0xa65886b8: return "_Findloc"; + case 0xa72a7595: return "calloc"; + case 0xa797790f: return "wcsstr"; + case 0xa82d70da: return "_Tlsget"; + case 0xa835be11: return "__cxa_atexit"; + case 0xa874036a: return "wcstof"; + case 0xa8a6f615: return "TlsSetValue"; + case 0xa8b07f1b: return "wmemcpy"; + case 0xa9f68eff: return "qsort"; + case 0xaa1e687d: return "isgraph"; + case 0xaa266d35: return "_malloc_init"; + case 0xaa9635d7: return "strcat"; + case 0xab4c7ca1: return "_CWcsxfrm"; + case 0xab77019f: return "fstat"; + case 0xabc27420: return "wcstoul"; + case 0xac758d20: return "wmemcmp"; + case 0xac893127: return "fgetc"; + case 0xace90be4: return "_Dtentox"; + case 0xad62a342: return "ldiv"; + case 0xad8e9ad0: return "_Initlocks"; + case 0xaec7c970: return "lseek"; + case 0xaf002043: return "independent_comalloc"; + case 0xaf44a615: return "fgets"; + case 0xaf6bdcb0: return "_Nonfatal_Assert"; + case 0xaf89fdbd: return "_Assert"; + case 0xafa39179: return "_WPutstr"; + case 0xb120f6ca: return "close"; + case 0xb17b79d0: return "isalpha"; + case 0xb18cc115: return "freopen"; + case 0xb1cc43e3: return "_CStrftime"; + case 0xb1f4779d: return "spu_thread_printf"; + case 0xb24cb8d6: return "_Locterm"; + case 0xb2702e15: return "wcrtomb"; + case 0xb2748a9f: return "_Freeloc"; + case 0xb30042ce: return "lldiv"; + case 0xb37982ea: return "_Getstr"; + case 0xb3c495bd: return "imaxabs"; + case 0xb3d98d59: return "_rand_real1_TT800"; + case 0xb400f226: return "isupper_ascii"; + case 0xb4225825: return "mbsinit"; + case 0xb43c25c7: return "wcstoull"; + case 0xb49eea74: return "_init_malloc_lock0"; + case 0xb4a54446: return "_Stofx"; + case 0xb4fc7078: return "_close_all_FILE"; + case 0xb529d259: return "isalnum"; + case 0xb569849d: return "reallocalign"; + case 0xb57bdf7b: return "iswxdigit"; + case 0xb5d353e8: return "_LDtentox"; + case 0xb6002508: return "_Putstr"; + case 0xb6257e3d: return "strncasecmp"; + case 0xb680e240: return "wcstombs"; + case 0xb6af290e: return "_WFrprep"; + case 0xb6d92ac3: return "strcasecmp"; + case 0xb738027a: return "strtok_r"; + case 0xb794631e: return "_WStofx"; + case 0xb7ab5127: return "wcsrchr"; + case 0xb7b793ed: return "get_state_TT800"; + case 0xb7ba4aeb: return "_WStoul"; + case 0xb7d3427f: return "iscntrl_ascii"; + case 0xb81cd66a: return "mbrlen"; + case 0xb9ed25d4: return "raw_spu_read_ulong"; + case 0xba62681f: return "mspace_memalign"; + case 0xbb605c96: return "pvalloc"; + case 0xbbd4582f: return "_Setloc"; + case 0xbc1d69c5: return "atoll"; + case 0xbc374779: return "_Getlname"; + case 0xbc5af0b5: return "fgetwc"; + case 0xbc7b4b8e: return "ctime"; + case 0xbe11beaa: return "_wremove"; + case 0xbe251a29: return "islower_ascii"; + case 0xbe6e5c58: return "spu_thread_read_uchar"; + case 0xbec43f86: return "raw_spu_read_ptr"; + case 0xbf5bf5ea: return "lseek64"; + case 0xbfcd1b3b: return "_Getdst"; + case 0xc01d9f97: return "printf"; + case 0xc08cc41d: return "wcstod"; + case 0xc0e27b2c: return "_Makestab"; + case 0xc155a73f: return "_WStoull"; + case 0xc15e657e: return "spu_raw_sprintf"; + case 0xc1a71972: return "_d2rv"; + case 0xc1b4bbb9: return "raw_spu_write_char"; + case 0xc1c8737c: return "_Getptoupper"; + case 0xc291e698: return "exit"; + case 0xc3c598e2: return "spu_printf_initialize"; + case 0xc3e14cbe: return "memcmp"; + case 0xc4178000: return "_rand_real3_TT800"; + case 0xc41c6e5d: return "_Scanf"; + case 0xc57337f8: return "_Fofind"; + case 0xc5c09834: return "strstr"; + case 0xc63c354f: return "_Exit"; + case 0xc69b2427: return "labs"; + case 0xc78df618: return "rand_real3_TT800"; + case 0xc7b62ab8: return "spu_thread_write_ullong"; + case 0xc9471fac: return "_Mtxinit"; + case 0xc94b27e3: return "_WStof"; + case 0xc95b20d3: return "fputwc"; + case 0xc9607d35: return "_Stopfx"; + case 0xc97a17d7: return "vsscanf"; + case 0xcab654bf: return "_Once_ctor"; + case 0xcb85ac70: return "mspace_malloc"; + case 0xcb9c535b: return "strftime"; + case 0xcbac7ad7: return "memchr"; + case 0xcbdc3a6d: return "raw_spu_write_int"; + case 0xcc5e0c72: return "_divi4"; + case 0xcca68e9c: return "putwc"; + case 0xce7a9e76: return "isprint_ascii"; + case 0xcecbcdc4: return "_Frv2d"; + case 0xcf863219: return "_Fwprep"; + case 0xcfbfb7a7: return "spu_printf_detach_thread"; + case 0xd14ece90: return "strtol"; + case 0xd1d69cb8: return "_Stod"; + case 0xd20f6601: return "independent_calloc"; + case 0xd2a99b1e: return "isprint"; + case 0xd2ac48d7: return "iswalnum"; + case 0xd360dcb4: return "fileno"; + case 0xd3964a09: return "__spu_thread_putfld"; + case 0xd40723d6: return "fread"; + case 0xd417eeb5: return "_Stoull"; + case 0xd4912ee3: return "_FDscale"; + case 0xd5c8cb55: return "spu_thread_write_ushort"; + case 0xd69c513d: return "_Wcscollx"; + case 0xd784459d: return "isupper"; + case 0xd7dc3a8f: return "strtod"; + case 0xd8b4eb20: return "__spu_thread_puttxt"; + case 0xd9674905: return "mspace_reallocalign"; + case 0xd9a4f812: return "atoff"; + case 0xda5a7eb8: return "strtoul"; + case 0xdaeada07: return "mallopt"; + case 0xddbac025: return "strcasecmp_ascii"; + case 0xddc71a75: return "_SCE_Assert"; + case 0xde1bb092: return "init_by_array_TT800"; + case 0xde32a334: return "_Exitspawn"; + case 0xde7aff7a: return "memcpy16"; + case 0xdebee2af: return "strchr"; + case 0xdef86a83: return "isxdigit_ascii"; + case 0xdfb52083: return "_Stoxflt"; + case 0xe03c7ab1: return "_Fspos"; + case 0xe1858899: return "_Getpwctrtab"; + case 0xe1bd3587: return "fclose"; + case 0xe1e83c65: return "strncmp"; + case 0xe2c5274a: return "_WStoflt"; + case 0xe3812672: return "fdopen"; + case 0xe3cc73f3: return "puts"; + case 0xe3d91db3: return "raw_spu_read_double"; + case 0xe40ba755: return "strtok"; + case 0xe44bf0bf: return "atof"; + case 0xe469fb20: return "_Atexit"; + case 0xe48348e9: return "vprintf"; + case 0xe4c51d4c: return "wcstoimax"; + case 0xe5ea9e2b: return "_Isdst"; + case 0xe5f09c80: return "llabs"; + case 0xe60ee9e5: return "fputws"; + case 0xe6a7de0a: return "ungetc"; + case 0xe7def231: return "_Getfloat"; + case 0xe89071ad: return "isalpha_ascii"; + case 0xe9137453: return "fwprintf"; + case 0xe9a2cc40: return "raw_spu_write_long"; + case 0xe9b560a5: return "sscanf"; + case 0xeb26298c: return "gmtime"; + case 0xeb40c9ec: return "rand_real2_TT800"; + case 0xeb8abe73: return "vwscanf"; + case 0xec9e7cb9: return "spu_thread_read_llong"; + case 0xecddba69: return "_WStodx"; + case 0xed6ec979: return "fsetpos"; + case 0xeda48c80: return "malloc_trim"; + case 0xeddcee2c: return "init_TT800"; + case 0xedec777d: return "_Ttotm"; + case 0xeeeb4f3e: return "_get_state_TT800"; + case 0xeeffc9a6: return "_wrename"; + case 0xef110b6b: return "unlink"; + case 0xf06eed36: return "wmemset"; + case 0xf0776a44: return "wcscmp"; + case 0xf0e022c6: return "getc"; + case 0xf2bbbee9: return "_Litob"; + case 0xf2fca4b2: return "spu_thread_write_llong"; + case 0xf356418c: return "open"; + case 0xf3ef3678: return "wcscspn"; + case 0xf41355f9: return "wcscpy"; + case 0xf418ee84: return "_WFwprep"; + case 0xf4207734: return "spu_thread_write_ulong"; + case 0xf5a32994: return "_Getpcostate"; + case 0xf5ef229c: return "_Getpwcostate"; + case 0xf5f7dda8: return "towupper"; + case 0xf68e2ac9: return "_init_malloc_lock"; + case 0xf7583d67: return "vscanf"; + case 0xf7908e27: return "strcspn"; + case 0xf7a14a22: return "realloc"; + case 0xf7d51596: return "scanf"; + case 0xf7ddb471: return "_Setgloballocale"; + case 0xf88f26c4: return "fwrite"; + case 0xf8935fe3: return "spu_thread_write_float"; + case 0xf89dc648: return "strpbrk"; + case 0xf9dae72c: return "setjmp"; + case 0xf9dba140: return "_Mtxlock"; + case 0xf9e26b72: return "_Once_dtor"; + case 0xfa00d211: return "read"; + case 0xfae4b063: return "_Strcollx"; + case 0xfaec8c60: return "fprintf"; + case 0xfb0f0018: return "_Makewct"; + case 0xfb2081fd: return "vfprintf"; + case 0xfb81426d: return "iswlower"; + case 0xfb8ea4d2: return "_Fd2rv"; + case 0xfc0428a6: return "strdup"; + case 0xfc60575c: return "__spu_thread_printf"; + case 0xfc606237: return "mbsrtowcs"; + case 0xfcac2e8e: return "mbstowcs"; + case 0xfd0cb96d: return "spu_thread_read_short"; + case 0xfd461e85: return "spu_thread_write_ldouble"; + case 0xfd6a1ddb: return "raw_spu_read_llong"; + case 0xfd81f6ca: return "_Stoflt"; + case 0xfe0261aa: return "mspace_free"; + case 0xfe630fd9: return "isblank"; + case 0xfe88e97e: return "fscanf"; + case 0xff689124: return "strtoimax"; + case 0xffbae95e: return "asctime"; + case 0xffbd876b: return "__raw_spu_puttxt"; + case 0x003395d9: return "_Feraise"; + case 0x00367be0: return "fminl"; + case 0x007854f4: return "_FDclass"; + case 0x00fde072: return "f_powf"; + case 0x010818fc: return "asinf4"; + case 0x012d0a91: return "_fminf4"; + case 0x016556df: return "_sinf4"; + case 0x01b84b27: return "llround"; + case 0x01ecef7d: return "_FCbuild"; + case 0x02e68d44: return "_f_fmodf"; + case 0x032cc709: return "csin"; + case 0x03593d2c: return "_f_expf"; + case 0x03aea906: return "divf4"; + case 0x0522d1af: return "_recipf4"; + case 0x054aae63: return "_fdimf4"; + case 0x05cb1718: return "f_fdimf"; + case 0x05e27a13: return "log10f4fast"; + case 0x05efc660: return "asin"; + case 0x05f1dc9e: return "_FExp"; + case 0x07274304: return "csinh"; + case 0x07daed62: return "log2f4"; + case 0x07f400e3: return "_LCbuild"; + case 0x080414bd: return "conjl"; + case 0x08139bd2: return "_fmaxf4"; + case 0x0829a21d: return "asinhl"; + case 0x0a242ed5: return "sinf4"; + case 0x0b3f4e90: return "catanhf"; + case 0x0bb036a6: return "_cosf4"; + case 0x0c14cfcc: return "fesetenv"; + case 0x0c9b8305: return "hypotf4"; + case 0x0cbdae68: return "sinf"; + case 0x0cf9b8bd: return "_Erfc"; + case 0x0d86295d: return "_LCaddcr"; + case 0x0e53319f: return "_asinf4"; + case 0x0e8573dc: return "expm1l"; + case 0x0f02f882: return "llrintl"; + case 0x0f428f0f: return "rint"; + case 0x0f721a9d: return "_LCsubcc"; + case 0x10627248: return "f_fmodf"; + case 0x11c51388: return "tgamma"; + case 0x1225dd31: return "casinf"; + case 0x12de4e46: return "_powf4"; + case 0x12e04cd7: return "cimagl"; + case 0x1313a420: return "acos"; + case 0x137f7e77: return "expf4"; + case 0x14208b00: return "_asinf4fast"; + case 0x1498a072: return "_Cmulcr"; + case 0x16bf208a: return "log10f"; + case 0x17316bee: return "log2"; + case 0x178d98dd: return "atanf4fast"; + case 0x17cd5d87: return "_recipf4fast"; + case 0x182cd542: return "tgammal"; + case 0x18668ce3: return "exp"; + case 0x18b26998: return "remainderl"; + case 0x18ec6099: return "rintl"; + case 0x1988732d: return "clog10"; + case 0x1a1adede: return "rsqrtf4fast"; + case 0x1acb2b16: return "acosf4"; + case 0x1bbdcd9f: return "expm1f4"; + case 0x1bcdeb47: return "_LSinh"; + case 0x1be996cc: return "_LCdivcc"; + case 0x1c11885d: return "_floorf4"; + case 0x1d35bfe4: return "_LLog"; + case 0x1d5bf5d0: return "_modff4"; + case 0x1e623f95: return "truncf4"; + case 0x1e85ef02: return "f_atanf"; + case 0x1e9fd6ba: return "_sinf4fast"; + case 0x2033eeb7: return "csqrt"; + case 0x2118fe46: return "cexpl"; + case 0x21a37b3e: return "log1pf"; + case 0x21e6d304: return "ceil"; + case 0x22c3e308: return "_exp2f4"; + case 0x238af59b: return "fegetenv"; + case 0x23b985f7: return "floorf"; + case 0x241f9337: return "_FCmulcr"; + case 0x24497c52: return "cosf"; + case 0x246ea8d0: return "f_sqrtf"; + case 0x2627d6b2: return "erfc"; + case 0x266d2473: return "_Caddcr"; + case 0x26deed0b: return "cosl"; + case 0x26ef50ed: return "asinh"; + case 0x28faaa5a: return "ilogbf4"; + case 0x29685118: return "_negatef4"; + case 0x2a138d2b: return "truncf"; + case 0x2a4dcbad: return "cacosl"; + case 0x2a89ce33: return "llrintf"; + case 0x2af4b73b: return "fmax"; + case 0x2b282ebb: return "sqrtl"; + case 0x2bb0f2c9: return "logb"; + case 0x2c45fe6a: return "fmaxl"; + case 0x2c601f3b: return "csinl"; + case 0x2cbb6f53: return "f_hypotf"; + case 0x2dcab6a4: return "nanl"; + case 0x2df339bc: return "_f_floorf"; + case 0x2e69bb2a: return "_FCosh"; + case 0x2ec867b4: return "exp2f4fast"; + case 0x30bc7a53: return "logf4"; + case 0x315673f6: return "_Csubcc"; + case 0x31be25c3: return "scalblnf"; + case 0x31db8c89: return "atan2"; + case 0x321c55de: return "nexttowardl"; + case 0x3261de11: return "fesetexceptflag"; + case 0x329ec019: return "rsqrtf4"; + case 0x32f994a1: return "cosf4fast"; + case 0x33e5929b: return "_LDsign"; + case 0x33f27f25: return "_FCdivcr"; + case 0x3436f008: return "csinhf"; + case 0x3459748b: return "log10f4"; + case 0x347c1ee1: return "atanf4"; + case 0x34c0371e: return "powl"; + case 0x358d7f93: return "_f_lrintf"; + case 0x3593a445: return "clog"; + case 0x35b6e70a: return "lrintl"; + case 0x35d3f688: return "creal"; + case 0x36778d1b: return "coshf"; + case 0x373054d1: return "cpow"; + case 0x37345541: return "log1pl"; + case 0x376fb27f: return "sinhl"; + case 0x3792b12d: return "lroundl"; + case 0x38ba5590: return "ccosl"; + case 0x38e69f09: return "pow"; + case 0x398483aa: return "_expm1f4fast"; + case 0x39ef81c9: return "f_fmaxf"; + case 0x3ad203fa: return "lrint"; + case 0x3adc01d7: return "f_frexpf"; + case 0x3b802524: return "ldexpf4"; + case 0x3c057fbd: return "atanf"; + case 0x3c616743: return "_LDtest"; + case 0x3cb818fa: return "_f_fdimf"; + case 0x3d4efafb: return "atan2l"; + case 0x3d549f2a: return "ctanhl"; + case 0x3d901a10: return "_ceilf4"; + case 0x3da55602: return "fabsf"; + case 0x3dfa060f: return "scalbnl"; + case 0x3e7eb58f: return "frexpf4"; + case 0x3e919cba: return "scalbnf"; + case 0x3ec9de23: return "_cbrtf4"; + case 0x3eeedb0e: return "_Dclass"; + case 0x3f6262b3: return "f_fminf"; + case 0x3f701e78: return "_Poly"; + case 0x4020f5ef: return "cbrt"; + case 0x405f9727: return "_log1pf4fast"; + case 0x40a2e212: return "_fabsf4"; + case 0x4111b546: return "_LExp"; + case 0x411434bb: return "asinf"; + case 0x414c5ecc: return "_f_hypotf"; + case 0x4152669c: return "scalbln"; + case 0x417851ce: return "feholdexcept"; + case 0x418036e3: return "_FTgamma"; + case 0x4189a367: return "remquo"; + case 0x41d1b236: return "_f_rintf"; + case 0x430309a1: return "ldexpf"; + case 0x434881a0: return "cacosf"; + case 0x43d522f4: return "cabsl"; + case 0x44cd6308: return "remainder"; + case 0x44cf744b: return "tanhl"; + case 0x45034943: return "nan"; + case 0x452ac4bb: return "floorf4"; + case 0x453f9e91: return "cbrtf"; + case 0x46b66f76: return "csqrtl"; + case 0x46cf72d9: return "fdimf"; + case 0x47433144: return "expm1f4fast"; + case 0x475d855b: return "trunc"; + case 0x476b5591: return "fmaf"; + case 0x48157605: return "_f_llrintf"; + case 0x4826db61: return "fma"; + case 0x4875601d: return "_exp2f4fast"; + case 0x487bbd1c: return "tanf4"; + case 0x488df791: return "cexp"; + case 0x48d462a9: return "_FDint"; + case 0x4930ac11: return "logbl"; + case 0x4a5ae27d: return "f_exp2f"; + case 0x4a6ca9a6: return "powf4"; + case 0x4ab22a63: return "_Caddcc"; + case 0x4add664c: return "feclearexcept"; + case 0x4ae52dd3: return "exp2"; + case 0x4b03d5b2: return "f_rintf"; + case 0x4b584841: return "f_asinf"; + case 0x4cb5fa99: return "nexttoward"; + case 0x4d878773: return "remainderf4"; + case 0x4ddb926b: return "powf"; + case 0x4e010403: return "copysign"; + case 0x4eb5eb51: return "sin"; + case 0x4fa4f5ec: return "nexttowardf"; + case 0x501c412f: return "cargf"; + case 0x519ebb77: return "floor"; + case 0x547fb4a7: return "sinf4fast"; + case 0x54d2fb8c: return "rintf"; + case 0x5516d621: return "acosl"; + case 0x55c8a549: return "truncl"; + case 0x56c573a8: return "log1p"; + case 0x575e9b6e: return "asinl"; + case 0x58eb9e57: return "fabs"; + case 0x596ab55c: return "atanh"; + case 0x5b18eded: return "clogl"; + case 0x5b474c22: return "casinhl"; + case 0x5bfd37be: return "_FCaddcc"; + case 0x5e48dede: return "exp2f4"; + case 0x5ee10a95: return "catanh"; + case 0x5ee37927: return "_LErfc"; + case 0x60e9ff3c: return "_expm1f4"; + case 0x61250988: return "catanl"; + case 0x6261c0b5: return "_log10f4"; + case 0x63bbdfa6: return "_FCmulcc"; + case 0x642e3d18: return "_frexpf4"; + case 0x642f7d6b: return "f_copysignf"; + case 0x645557bd: return "copysignl"; + case 0x64abdb4d: return "csinhl"; + case 0x657d0e83: return "divf4fast"; + case 0x65935877: return "ilogbf"; + case 0x659e011e: return "sqrt"; + case 0x6636c4a5: return "frexpf"; + case 0x664e04b9: return "negatef4"; + case 0x6764c707: return "f_log2f"; + case 0x683cacb3: return "sinh"; + case 0x68a8957f: return "casinhf"; + case 0x68f72416: return "nextafterl"; + case 0x69040b9b: return "logbf4"; + case 0x69725dce: return "lgamma"; + case 0x6ad1c42b: return "_sincosf4"; + case 0x6b660894: return "_acosf4fast"; + case 0x6b6ab2a9: return "_LDclass"; + case 0x6c009c56: return "f_log10f"; + case 0x6c6285c6: return "acoshf"; + case 0x6cc4bd13: return "casinh"; + case 0x6ddd31b2: return "hypot"; + case 0x6df35518: return "floorl"; + case 0x6e9eb0dc: return "sincosf4fast"; + case 0x6ef6b083: return "_FCsubcr"; + case 0x6f5dd7d2: return "cexpf"; + case 0x6f639afb: return "f_llroundf"; + case 0x6fcc1e27: return "_FPoly"; + case 0x70357b12: return "_atanf4fast"; + case 0x7048396e: return "carg"; + case 0x705d9e24: return "f_acosf"; + case 0x70f71871: return "_FCdivcc"; + case 0x71293b71: return "_FLog"; + case 0x714adce1: return "log"; + case 0x71f2bc56: return "_divf4fast"; + case 0x728149e5: return "f_ldexpf"; + case 0x729b7269: return "cproj"; + case 0x72a3ed28: return "fesettrapenable"; + case 0x72f1f64b: return "_logbf4"; + case 0x734ca589: return "_f_cosf"; + case 0x742f12b4: return "_Sin"; + case 0x74902d4b: return "expf4fast"; + case 0x749440f9: return "lgammal"; + case 0x752fa85e: return "fmaxf4"; + case 0x758f33dc: return "nearbyint"; + case 0x75e3e2e9: return "nearbyintl"; + case 0x76afaf04: return "_sqrtf4"; + case 0x76e639ec: return "_atanf4"; + case 0x772f1e4d: return "lround"; + case 0x7793a86b: return "ctanf"; + case 0x7831a2e0: return "hypotl"; + case 0x78e4590a: return "acosh"; + case 0x790c53bd: return "_Fpcomp"; + case 0x7919f414: return "_f_nearbyintf"; + case 0x79ba9b5c: return "expl"; + case 0x7a893af1: return "_rsqrtf4"; + case 0x7ab679da: return "f_cosf"; + case 0x7c2eaeb5: return "fminf"; + case 0x7d02a5ca: return "sqrtf4fast"; + case 0x7d6191d0: return "_Cosh"; + case 0x7f381837: return "frexp"; + case 0x7f579e03: return "atan"; + case 0x7f91cd41: return "tanf4fast"; + case 0x812ed488: return "cabsf"; + case 0x81daf880: return "_LCsubcr"; + case 0x8217e783: return "cosh"; + case 0x833e6b0e: return "cimag"; + case 0x834f5917: return "ccosh"; + case 0x842cb14d: return "_log1pf4"; + case 0x8451edf0: return "sqrtf"; + case 0x889cccb0: return "llroundl"; + case 0x88fb4a66: return "recipf4fast"; + case 0x892f2590: return "fegetround"; + case 0x895cdb49: return "fmaxf"; + case 0x89b507b3: return "catanhl"; + case 0x89d1d168: return "_LAtan"; + case 0x8b168769: return "fdiml"; + case 0x8bd1deb2: return "_LTgamma"; + case 0x8bd67efc: return "erf"; + case 0x8c85369b: return "_f_fminf"; + case 0x8d5858db: return "_f_exp2f"; + case 0x8e01379e: return "cacoshf"; + case 0x8e258fa0: return "cacos"; + case 0x8ecae294: return "nextafter"; + case 0x8f2bcdb5: return "_logf4"; + case 0x8f96319e: return "log10l"; + case 0x8fb7bac7: return "_sqrtf4fast"; + case 0x904e646b: return "cargl"; + case 0x90f0242f: return "_f_sinf"; + case 0x9110708a: return "modfl"; + case 0x91cdfdb0: return "asinf4fast"; + case 0x9232baea: return "_FDtest"; + case 0x9245e01b: return "_divf4"; + case 0x9379e36e: return "tanf"; + case 0x938fb946: return "_tanf4fast"; + case 0x947ae18e: return "_LHypot"; + case 0x9558ed08: return "lrintf"; + case 0x95dfecb1: return "_FCsubcc"; + case 0x961688d1: return "f_nearbyintf"; + case 0x9616e336: return "_FHypot"; + case 0x964ac044: return "creall"; + case 0x96d1b95e: return "log2f4fast"; + case 0x9700d9cd: return "clogf"; + case 0x970a3432: return "cacosh"; + case 0x99a6c261: return "catanf"; + case 0x99c228fc: return "roundl"; + case 0x9a81e583: return "fmodf"; + case 0x9af30eaf: return "casin"; + case 0x9e289062: return "_f_ceilf"; + case 0x9e3ada21: return "logl"; + case 0x9e8130b6: return "ccos"; + case 0x9f03dd3e: return "lgammaf"; + case 0x9f0efc6e: return "exp2l"; + case 0x9f46f5a4: return "tgammaf"; + case 0x9f65bd34: return "fdimf4"; + case 0x9f78f052: return "cos"; + case 0x9fded78a: return "_acosf4"; + case 0xa0160c30: return "_copysignf4"; + case 0xa20827a8: return "ctanl"; + case 0xa2c81938: return "_LSin"; + case 0xa4578433: return "fmin"; + case 0xa46a70a1: return "atanhl"; + case 0xa4ca5cf2: return "llroundf"; + case 0xa56557b6: return "catan"; + case 0xa5d0b260: return "acoshl"; + case 0xa713f8cf: return "modf"; + case 0xa7658186: return "log1pf4"; + case 0xa823836b: return "ilogb"; + case 0xa8c16038: return "_FDsign"; + case 0xa8d180e8: return "_Cbuild"; + case 0xa92bcc85: return "cabs"; + case 0xa9e039c4: return "erfcf"; + case 0xaaa270dc: return "_LCdivcr"; + case 0xab377381: return "log2f"; + case 0xabdccc7a: return "f_atan2f"; + case 0xacca2f83: return "copysignf"; + case 0xad17e787: return "_Dint"; + case 0xad3a093d: return "_LCosh"; + case 0xad5d3e57: return "_FLgamma"; + case 0xaddce673: return "erfcl"; + case 0xafa13040: return "f_llrintf"; + case 0xafcfdad7: return "_Lgamma"; + case 0xafd9a625: return "cimagf"; + case 0xb0fa1592: return "clog10l"; + case 0xb24bd2f8: return "logbf"; + case 0xb348c5c2: return "_LLgamma"; + case 0xb412a8dc: return "_LDint"; + case 0xb4ef29d5: return "f_floorf"; + case 0xb4f4513e: return "_Tgamma"; + case 0xb54cc9a1: return "f_sinf"; + case 0xb5961d4e: return "_sincosf4fast"; + case 0xb598a495: return "fmodl"; + case 0xb5e28191: return "_FSin"; + case 0xb7696143: return "nextafterf"; + case 0xb79012ba: return "modff"; + case 0xb89863bc: return "_rsqrtf4fast"; + case 0xb8aa984e: return "_expf4"; + case 0xb94b9d13: return "_Dtest"; + case 0xb9d2ad22: return "remquol"; + case 0xba136594: return "csinf"; + case 0xba84eab5: return "coshl"; + case 0xbaf11866: return "ceilf"; + case 0xbb165807: return "expm1f"; + case 0xbb208b20: return "cbrtf4fast"; + case 0xbb761c89: return "remquof"; + case 0xbbaa300b: return "f_log1pf"; + case 0xbbf7354e: return "fegetexceptflag"; + case 0xbd7410d9: return "recipf4"; + case 0xbd8bb75c: return "asinhf"; + case 0xbf23f2e7: return "cprojl"; + case 0xbfda6837: return "_f_log10f"; + case 0xc0609820: return "nearbyintf"; + case 0xc0bcf25e: return "_logf4fast"; + case 0xc357b33a: return "frexpl"; + case 0xc406dd09: return "cbrtf4"; + case 0xc41f01db: return "fminf4"; + case 0xc477c0f6: return "f_lroundf"; + case 0xc4cccd1f: return "modff4"; + case 0xc7369fce: return "_Atan"; + case 0xc78ac9d0: return "scalbn"; + case 0xc7b45a19: return "_LFpcomp"; + case 0xc7f1d407: return "fmal"; + case 0xc7fb73d6: return "f_lrintf"; + case 0xc8910002: return "ilogbl"; + case 0xc8dd9279: return "expm1"; + case 0xc90f4bbc: return "_atan2f4"; + case 0xc9481758: return "_tanf4"; + case 0xc94fcc63: return "cbrtl"; + case 0xc977e1ea: return "fetestexcept"; + case 0xc984bf53: return "roundf"; + case 0xc9c536ce: return "_ldexpf4"; + case 0xca239640: return "fmodf4"; + case 0xca463458: return "_Log"; + case 0xcaaf7ae7: return "cprojf"; + case 0xcac167a5: return "_Cmulcc"; + case 0xcb6599c0: return "exp2f"; + case 0xcb6a147e: return "_cosf4fast"; + case 0xcbdf9afb: return "_log10f4fast"; + case 0xccc66f11: return "_FSinh"; + case 0xce91ff18: return "nanf"; + case 0xcfee82d8: return "_remainderf4"; + case 0xd0fd3ca8: return "_hypotf4"; + case 0xd125b89e: return "conjf"; + case 0xd1a3574c: return "clog10f"; + case 0xd231e30a: return "ldexpl"; + case 0xd28ef6dd: return "_Hypot"; + case 0xd2a666c9: return "ctanh"; + case 0xd3a346a8: return "tanl"; + case 0xd40f3f2c: return "erff"; + case 0xd42904b7: return "fabsl"; + case 0xd477852d: return "logf"; + case 0xd48eaae1: return "scalblnl"; + case 0xd4f37b9d: return "tanhf"; + case 0xd50277ad: return "tan"; + case 0xd54039cb: return "fegettrapenable"; + case 0xd5adc4b2: return "cpowl"; + case 0xd5d38552: return "_LCaddcc"; + case 0xd612fa16: return "_Sinh"; + case 0xd70df92a: return "_FCaddcr"; + case 0xd7653782: return "sinhf"; + case 0xd76a16da: return "_fmaf4"; + case 0xd8270894: return "fdim"; + case 0xd8c4096d: return "atan2f4"; + case 0xd8d157f5: return "f_expf"; + case 0xd8f79f4c: return "log10"; + case 0xd97852b7: return "sinl"; + case 0xd97ce5d4: return "fesetround"; + case 0xda217d1f: return "atanl"; + case 0xda31fc5d: return "_FFpcomp"; + case 0xdc14974c: return "fmaf4"; + case 0xdc151707: return "_f_log2f"; + case 0xdd8660d2: return "atan2f4fast"; + case 0xdd92118e: return "ceill"; + case 0xdddabb32: return "remainderf"; + case 0xde7833f2: return "_log2f4fast"; + case 0xdece76a6: return "acosf"; + case 0xdfd41734: return "_Exp"; + case 0xdffb4e3c: return "casinl"; + case 0xe1288c47: return "atanhf"; + case 0xe1c71b05: return "ccoshl"; + case 0xe2b596ec: return "ccosf"; + case 0xe2de89e6: return "csqrtf"; + case 0xe2f1d4b2: return "tanh"; + case 0xe31cc0d3: return "_ilogbf4"; + case 0xe3e379b8: return "_expf4fast"; + case 0xe584836c: return "_LPoly"; + case 0xe58fc9b5: return "erfl"; + case 0xe5a0be9f: return "_powf4fast"; + case 0xe5d2293f: return "_Force_raise"; + case 0xe5ea65e8: return "feraiseexcept"; + case 0xe6c1ff41: return "llrint"; + case 0xe769e5cf: return "fmod"; + case 0xe8fcf1f8: return "acosf4fast"; + case 0xe913a166: return "logf4fast"; + case 0xe92f3fb8: return "_f_fmaf"; + case 0xe93abfca: return "ctan"; + case 0xe9ac8223: return "_LCmulcr"; + case 0xe9f501df: return "crealf"; + case 0xea1e83e3: return "f_logf"; + case 0xeac62795: return "_Cdivcc"; + case 0xeac7ca2c: return "ceilf4"; + case 0xebb4e08a: return "hypotf"; + case 0xec43b983: return "_f_sqrtf"; + case 0xec7da0c8: return "_atan2f4fast"; + case 0xed05c265: return "sqrtf4"; + case 0xed9d1ac5: return "f_tanf"; + case 0xeda86c48: return "copysignf4"; + case 0xee0db701: return "_Csubcr"; + case 0xee204ac6: return "f_ceilf"; + case 0xee303936: return "_Dsign"; + case 0xeed82401: return "_f_logf"; + case 0xf0947035: return "ctanhf"; + case 0xf0ab77c1: return "ccoshf"; + case 0xf16568af: return "_FAtan"; + case 0xf19c5e94: return "sincosf4"; + case 0xf1aaa2f8: return "conj"; + case 0xf3bd7d08: return "_cbrtf4fast"; + case 0xf3ec0258: return "round"; + case 0xf4ad6ea8: return "ldexp"; + case 0xf537d837: return "_truncf4"; + case 0xf5cd1e19: return "cosf4"; + case 0xf7844153: return "_f_fmaxf"; + case 0xf83a372f: return "f_fmaf"; + case 0xf95b7769: return "powf4fast"; + case 0xf99da2fc: return "fabsf4"; + case 0xfa28434b: return "log2l"; + case 0xfa765d42: return "_Cdivcr"; + case 0xfa97afbf: return "feupdateenv"; + case 0xfae9e727: return "_f_copysignf"; + case 0xfb6e6213: return "log1pf4fast"; + case 0xfb932a56: return "atan2f"; + case 0xfbb4047a: return "lroundf"; + case 0xfbe88922: return "_FErfc"; + case 0xfcedabc3: return "_fmodf4"; + case 0xfcf08193: return "expf"; + case 0xfdec16e1: return "cacoshl"; + case 0xfe23dbe9: return "_log2f4"; + case 0xff036800: return "cpowf"; + case 0xfffe79bf: return "_LCmulcc"; + } + + if (module == "sys_libstdcxx") switch (fnid) + { + case 0x002c338b: return "_ZNKSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE16do_get_monthnameES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateEPSt2tm"; + case 0x002e18d8: return "_ZNSt6locale7_LocimpD0Ev"; + case 0x0091a3fd: return "_ZNKSt6locale9_GetfacetEj"; + case 0x00c3975e: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE5_LockEv"; + case 0x00cf44f7: return "_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_RSt8ios_basecl"; + case 0x01409785: return "_ZNKSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE7_GetintERS3_S5_iiRi"; + case 0x01aa0cef: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERx"; + case 0x01c4ef01: return "_ZNSt6localeC2ERKS_S1_i"; + case 0x01d9b3f5: return "_ZNSt6localeC1EPKci"; + case 0x01f81190: return "_ZNSt12codecvt_baseD1Ev"; + case 0x020b22f3: return "_ZNKSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_RSt8ios_basewPKv"; + case 0x02e40598: return "_ZNSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE5_InitERKSt8_Locinfo"; + case 0x03217f6f: return "_ZNSt19istreambuf_iteratorIcSt11char_traitsIcEE5_PeekEv"; + case 0x0339259c: return "_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_RSt8ios_basecPKv"; + case 0x033c18f4: return "_ZNSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEED1Ev"; + case 0x03cca12f: return "_ZNSt6localeC1ERKS_PKci"; + case 0x040c18ff: return "_ZNKSt7_MpunctIwE16do_decimal_pointEv"; + case 0x045e124a: return "_ZdaPv"; + case 0x0490855d: return "_ZNSt8numpunctIwE7_GetcatEPPKNSt6locale5facetE"; + case 0x055c1462: return "_ZNSt15basic_streambufIcSt11char_traitsIcEED1Ev"; + case 0x05903101: return "_ZNKSt7collateIcE7do_hashEPKcS2_"; + case 0x05a9cef6: return "_ZNSt7_MpunctIcE5_InitERKSt8_Locinfo"; + case 0x05ec37c8: return "_ZSt10_MaklocstrIwEPT_PKcS1_RKSt7_Cvtvec"; + case 0x06bc5b51: return "_ZNKSt7_MpunctIwE16do_positive_signEv"; + case 0x07a3bd16: return "_ZNSt6locale7_LocimpD1Ev"; + case 0x07b6c924: return "_ZTv0_n12_NSt13basic_ostreamIwSt11char_traitsIwEED1Ev"; + case 0x085bff4f: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE5_LockEv"; + case 0x08e1865c: return "_ZNKSt8numpunctIwE16do_thousands_sepEv"; + case 0x09e73a2a: return "_ZNKSt7codecvtIwcSt9_MbstatetE11do_encodingEv"; + case 0x0ba5483c: return "_ZNKSt12codecvt_base11do_encodingEv"; + case 0x0bc08c57: return "_ZNKSt7collateIwE7do_hashEPKwS2_"; + case 0x0bcc1910: return "_ZNSt10ostrstreamD2Ev"; + case 0x0d4290d2: return "_ZNSt12length_errorD0Ev"; + case 0x0d644dca: return "_ZNKSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE11do_get_dateES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateEPSt2tm"; + case 0x0e147a9d: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE9pbackfailEi"; + case 0x0e744ef5: return "_ZNSt9money_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEED1Ev"; + case 0x0e9698af: return "_ZNSt7codecvtIwcSt9_MbstatetED1Ev"; + case 0x0e9a5554: return "_ZNSt13basic_istreamIwSt11char_traitsIwEED0Ev"; + case 0x0f930fdd: return "_ZNSt13messages_baseD2Ev"; + case 0x0ff264b9: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE4syncEv"; + case 0x10231873: return "_ZNSt13runtime_errorD1Ev"; + case 0x10dc3f6c: return "_ZNSbIwSt11char_traitsIwESaIwEE6appendEjw"; + case 0x113a515f: return "_ZNKSt8messagesIcE7do_openERKSsRKSt6locale"; + case 0x114e9178: return "_ZNSt11logic_errorD0Ev"; + case 0x128cd621: return "_ZNKSt5ctypeIwE10do_scan_isEsPKwS2_"; + case 0x12de5772: return "_ZNKSt9money_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_bRSt8ios_baseRNSt5_IosbIiE8_IostateERSs"; + case 0x1374b8c8: return "_ZNSt10moneypunctIcLb0EED1Ev"; + case 0x143048bf: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE7seekoffElNSt5_IosbIiE8_SeekdirENS4_9_OpenmodeE"; + case 0x1474ac53: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERt"; + case 0x14e3faa5: return "_ZNKSt5ctypeIwE9do_narrowEwc"; + case 0x1527fe95: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE4syncEv"; + case 0x1692ae0c: return "_ZNSt6localeD1Ev"; + case 0x16df5ecb: return "_ZNKSt12codecvt_base16do_always_noconvEv"; + case 0x17dd0a4e: return "_ZNKSt7_MpunctIwE16do_negative_signEv"; + case 0x18628537: return "_ZNKSt8numpunctIcE16do_decimal_pointEv"; + case 0x186bcc94: return "_ZNSt8ios_base4InitD1Ev"; + case 0x18a38254: return "_ZNSt10ctype_baseD1Ev"; + case 0x197fc348: return "_ZNSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEED1Ev"; + case 0x1989f59c: return "_ZNSt8ios_base17register_callbackEPFvNS_5eventERS_iEi"; + case 0x19c901ce: return "_ZTv0_n12_NSt9strstreamD0Ev"; + case 0x1a00f889: return "_ZNSt9exceptionD2Ev"; + case 0x1a4f2fa6: return "_ZNSt8ios_base7failureD0Ev"; + case 0x1a7f963c: return "_ZNKSt8numpunctIcE11do_truenameEv"; + case 0x1b266c3d: return "_ZNSt9money_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE7_GetcatEPPKNSt6locale5facetE"; + case 0x1b6a7482: return "_ZNKSt7_MpunctIwE13do_neg_formatEv"; + case 0x1b6ad260: return "_ZSt13resetiosflagsNSt5_IosbIiE9_FmtflagsE"; + case 0x1b9b3b5c: return "_ZNSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEED0Ev"; + case 0x1bccd2ca: return "_ZNKSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE7_GetintERS3_S5_iiRi"; + case 0x1c3f1c4f: return "_ZNSt6_MutexD1Ev"; + case 0x1c8083c5: return "_ZNSt12strstreambufD0Ev"; + case 0x1c8405dc: return "_ZNSt7_MpunctIcEC2Ejb"; + case 0x1cf6785d: return "_ZSt9use_facetISt5ctypeIwEERKT_RKSt6locale"; + case 0x1d43fb44: return "_ZSt9use_facetISt8numpunctIwEERKT_RKSt6locale"; + case 0x1ee13e83: return "_ZNSt6locale5facetD0Ev"; + case 0x1f2e9f4e: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE9underflowEv"; + case 0x1f3a9ada: return "_ZNSt12strstreambuf7seekposESt4fposISt9_MbstatetENSt5_IosbIiE9_OpenmodeE"; + case 0x2070a73d: return "_ZNSt6locale7_LocimpC1ERKS0_"; + case 0x207b56fa: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE8_GetffldEPcRS3_S6_RKSt6locale"; + case 0x20a02b6d: return "_ZNSt6locale2idcvjEv"; + case 0x20f7e066: return "_ZNSt10moneypunctIwLb0EED0Ev"; + case 0x21659e45: return "_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE5_FputES3_RSt8ios_basecPKcjjjj"; + case 0x22777290: return "_ZNSs7replaceEjjPKcj"; + case 0x229a0963: return "_ZNKSt5ctypeIwE5do_isEsw"; + case 0x2354ec0a: return "_ZNKSt7codecvtIwcSt9_MbstatetE10do_unshiftERS0_PcS3_RS3_"; + case 0x2356ef16: return "_ZnajRKSt9nothrow_t"; + case 0x23a87483: return "_ZNKSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE11do_get_timeES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateEPSt2tm"; + case 0x23ef7642: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE8_GetifldEPcRS3_S6_NSt5_IosbIiE9_FmtflagsERKSt6locale"; + case 0x258359df: return "_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_RSt8ios_basece"; + case 0x2670b433: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE8_GetffldEPcRS3_S6_RKSt6locale"; + case 0x268c3ea5: return "_ZNKSt7_MpunctIwE13do_pos_formatEv"; + case 0x26e8e1cf: return "_ZNKSt5ctypeIwE5do_isEPKwS2_Ps"; + case 0x273be056: return "_ZNKSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE8_PutmfldES3_bRSt8ios_basecbSs"; + case 0x281f9107: return "_ZTv0_n12_NSiD1Ev"; + case 0x294779fb: return "_ZNSt8ios_base4InitD2Ev"; + case 0x2954d64d: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE9underflowEv"; + case 0x29c11f46: return "_ZNKSt7codecvtIccSt9_MbstatetE9do_lengthERKS0_PKcS5_j"; + case 0x29c90b94: return "_ZNKSt8numpunctIcE16do_thousands_sepEv"; + case 0x2a16469d: return "_ZNSt8ios_base5imbueERKSt6locale"; + case 0x2ac890f4: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERb"; + case 0x2adccb1a: return "_ZNKSt7_MpunctIcE14do_frac_digitsEv"; + case 0x2af79bd6: return "_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE5_IputES3_RSt8ios_basecPcj"; + case 0x2b05b95a: return "_ZNKSt7_MpunctIcE11do_groupingEv"; + case 0x2b88f26e: return "_ZNSt15basic_streambufIwSt11char_traitsIwEED0Ev"; + case 0x2c241d13: return "_ZnajjRKSt9nothrow_t"; + case 0x2c6ce396: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERd"; + case 0x2cf8ea50: return "_ZNKSt7codecvtIwcSt9_MbstatetE16do_always_noconvEv"; + case 0x2d489b47: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE9underflowEv"; + case 0x2d50650f: return "_ZSt9use_facetISt10moneypunctIcLb1EEERKT_RKSt6locale"; + case 0x2d8be7e8: return "_ZNKSt9exception6_RaiseEv"; + case 0x2daa5a42: return "_ZTv0_n12_NSt9strstreamD1Ev"; + case 0x2e2b80c8: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERPv"; + case 0x2e84ebb3: return "_ZNSt8_LocinfoC1EiPKc"; + case 0x2eb5c13a: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE4syncEv"; + case 0x2f29da90: return "_ZNSt12strstreambuf5_TidyEv"; + case 0x2ff8d101: return "_ZNSt6localeC1ERKS_S1_i"; + case 0x30195cf5: return "_ZNKSt8numpunctIcE11do_groupingEv"; + case 0x30ce43d4: return "_ZNSt8numpunctIcED0Ev"; + case 0x30e297ea: return "_ZNSt7_MpunctIcEC2ERKSt8_Locinfojb"; + case 0x316b7a34: return "_ZNSt9exceptionD1Ev"; + case 0x31a81476: return "_ZdlPvj"; + case 0x31b3e5cc: return "_ZNSs5_TidyEbj"; + case 0x3286b855: return "_ZNSt8time_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE7_GetcatEPPKNSt6locale5facetE"; + case 0x332f8409: return "_ZNSt8time_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE7_GetcatEPPKNSt6locale5facetE"; + case 0x336e904e: return "_ZNSdD0Ev"; + case 0x33e04d8e: return "_ZNKSt7collateIwE12do_transformEPKwS2_"; + case 0x34b63588: return "_ZNKSt5ctypeIwE9_DonarrowEwc"; + case 0x34edd72b: return "_ZNSt10moneypunctIwLb0EED1Ev"; + case 0x360f8a4f: return "_ZNSt9money_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEED1Ev"; + case 0x3697bbd3: return "_ZNSt8ios_base5_InitEv"; + case 0x36e7826a: return "_ZNSt7collateIcED1Ev"; + case 0x3783acfa: return "_ZTv0_n12_NSt13basic_istreamIwSt11char_traitsIwEED1Ev"; + case 0x38783beb: return "_ZNKSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE11do_get_yearES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateEPSt2tm"; + case 0x3933645f: return "_ZNKSt7_MpunctIwE14do_frac_digitsEv"; + case 0x3937f2f8: return "_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_RSt8ios_basecm"; + case 0x39775ce9: return "_ZNSt11logic_errorD2Ev"; + case 0x3ad12959: return "_ZNSt9basic_iosIcSt11char_traitsIcEE4initEPSt15basic_streambufIcS1_Eb"; + case 0x3bac19dc: return "_ZThn8_NSdD0Ev"; + case 0x3bda45a7: return "_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_RSt8ios_basecy"; + case 0x3d32a7f4: return "_ZNSt6localeC2EPKci"; + case 0x3da21a90: return "_ZNSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEED1Ev"; + case 0x3e18602a: return "_ZNKSt12codecvt_base13do_max_lengthEv"; + case 0x3eeb7167: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE7_UnlockEv"; + case 0x3f6a6e68: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE9_EndwriteEv"; + case 0x3f9cb259: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERl"; + case 0x3fc2324d: return "_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_RSt8ios_basecd"; + case 0x409409af: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE6setbufEPci"; + case 0x411b923e: return "_ZSt9use_facetISt8numpunctIcEERKT_RKSt6locale"; + case 0x4148e091: return "_ZNKSt9money_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE8_GetmfldERS3_S5_bRSt8ios_base"; + case 0x417f47af: return "_ZSt9use_facetISt10moneypunctIcLb0EEERKT_RKSt6locale"; + case 0x42c40b2f: return "_ZNSt12out_of_rangeD0Ev"; + case 0x45010630: return "_ZNSt10moneypunctIcLb1EED0Ev"; + case 0x4520d6a2: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE5_LockEv"; + case 0x46034d2e: return "_ZNSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEED0Ev"; + case 0x460e5cb7: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE7seekposESt4fposISt9_MbstatetENSt5_IosbIiE9_OpenmodeE"; + case 0x4761783a: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE5imbueERKSt6locale"; + case 0x47aab531: return "_ZNSt7_MpunctIcED0Ev"; + case 0x47e5c318: return "_ZNSt8_LocinfoD2Ev"; + case 0x4827e6be: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERe"; + case 0x48d101ef: return "_ZNKSt8ios_base7failure8_DoraiseEv"; + case 0x493212da: return "_ZNSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEED0Ev"; + case 0x4952490e: return "_ZNSt8ios_base5clearENSt5_IosbIiE8_IostateEb"; + case 0x496c6f50: return "_Getctyptab"; + case 0x49d9ddaf: return "_ZNKSt8numpunctIwE12do_falsenameEv"; + case 0x49da8c5f: return "_ZNKSt9money_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_bRSt8ios_baseRNSt5_IosbIiE8_IostateERe"; + case 0x49f7d434: return "_ZNSt8numpunctIwED0Ev"; + case 0x4a40969d: return "_Fac_tidy"; + case 0x4a799510: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERl"; + case 0x4aec14d5: return "_ZNSt12length_errorD1Ev"; + case 0x4aff73cc: return "_ZSt14_Debug_messagePKcS0_"; + case 0x4b1ad744: return "_ZdaPvjRKSt9nothrow_t"; + case 0x4b5a8abc: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE6setbufEPwi"; + case 0x4bc193c7: return "_ZNSt10ostrstreamC2EPciNSt5_IosbIiE9_OpenmodeE"; + case 0x4bda379a: return "_ZNSt8ios_base4InitC1Ev"; + case 0x4bee7ba9: return "_ZNSt8ios_base7failureD1Ev"; + case 0x4cb35e7d: return "_ZNSt9time_baseD1Ev"; + case 0x4cdab0ba: return "_ZNSt7_MpunctIwED0Ev"; + case 0x4daf3fcf: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE6xsgetnEPci"; + case 0x4e34cf83: return "_ZNSbIwSt11char_traitsIwESaIwEE5_GrowEjb"; + case 0x4e5cd916: return "_ZNKSt8numpunctIwE11do_groupingEv"; + case 0x4ec89bf8: return "_ZNSt7collateIcE7_GetcatEPPKNSt6locale5facetE"; + case 0x4ef0eb8e: return "_ZNSt12strstreambuf7seekoffElNSt5_IosbIiE8_SeekdirENS1_9_OpenmodeE"; + case 0x4fde96de: return "_ZNSt15basic_streambufIwSt11char_traitsIwEED1Ev"; + case 0x5015b8d3: return "_ZSt7_FiopenPKwNSt5_IosbIiE9_OpenmodeEi"; + case 0x50b34c09: return "_ZNKSt9exception4whatEv"; + case 0x5102ac61: return "_ZNKSt7_MpunctIwE14do_curr_symbolEv"; + case 0x5119680b: return "_ZNSt8_LocinfoD1Ev"; + case 0x5127dcd1: return "_ZNSsC1Ev"; + case 0x522b0457: return "_ZNSt10istrstreamD0Ev"; + case 0x52330fbd: return "_ZNSt13runtime_errorD0Ev"; + case 0x5298ef8e: return "_ZdaPvRKSt9nothrow_t"; + case 0x5333bdc9: return "_ZNKSt13runtime_error4whatEv"; + case 0x53693d40: return "_ZSt11setiosflagsNSt5_IosbIiE9_FmtflagsE"; + case 0x5438d7d8: return "_ZdaPvS_"; + case 0x550255f7: return "_ZNKSt7codecvtIccSt9_MbstatetE10do_unshiftERS0_PcS3_RS3_"; + case 0x55481e6f: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE9showmanycEv"; + case 0x5560c79e: return "_ZNSdD1Ev"; + case 0x55b3ebf2: return "_ZNSt9strstreamC2EPciNSt5_IosbIiE9_OpenmodeE"; + case 0x563fd2be: return "_ZNSt6localeC2ERKS_PKci"; + case 0x5656ccff: return "_ZNKSt7collateIcE10do_compareEPKcS2_S2_S2_"; + case 0x56d3d4f0: return "_ZNSt9bad_allocD1Ev"; + case 0x56fac416: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERe"; + case 0x577c2695: return "_ZNSt6_Mutex5_LockEv"; + case 0x57ef52f0: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE7_UnlockEv"; + case 0x581fc95b: return "_ZNSt5ctypeIcED0Ev"; + case 0x58fad1c1: return "_ZNSt5ctypeIwE7_GetcatEPPKNSt6locale5facetE"; + case 0x5949408e: return "_ZNSt8ios_base5_TidyEv"; + case 0x59c77266: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERd"; + case 0x5a3ad4bd: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERf"; + case 0x5a5a9107: return "_ZNSt6localeC2Ev"; + case 0x5a6e4e50: return "_ZNSt6locale7_Locimp9_MakewlocERKSt8_LocinfoiPS0_PKS_"; + case 0x5a898327: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE7seekoffElNSt5_IosbIiE8_SeekdirENS4_9_OpenmodeE"; + case 0x5adf9060: return "_ZNKSt5ctypeIcE8do_widenEPKcS2_Pc"; + case 0x5b71b85d: return "_ZNSt19istreambuf_iteratorIwSt11char_traitsIwEE4_IncEv"; + case 0x5c15972f: return "_ZNSt13basic_ostreamIwSt11char_traitsIwEED1Ev"; + case 0x5ca98e4a: return "_ZNSt13basic_filebufIcSt11char_traitsIcEED0Ev"; + case 0x5e1f2d37: return "_ZNKSt9exception8_DoraiseEv"; + case 0x5e55ab8c: return "_ZSt10_GetloctxtIwSt19istreambuf_iteratorIwSt11char_traitsIwEEEiRT0_S5_jPKT_"; + case 0x5ed4fb7a: return "_ZTv0_n12_NSt13basic_istreamIwSt11char_traitsIwEED0Ev"; + case 0x604fec95: return "_ZNSt12out_of_rangeD1Ev"; + case 0x605131d5: return "_ZNSt8_LocinfoC1EPKc"; + case 0x6051c802: return "_ZNSt7codecvtIccSt9_MbstatetED0Ev"; + case 0x608abbb5: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE5uflowEv"; + case 0x61119152: return "_ZNSt6locale5_InitEv"; + case 0x61248c80: return "_ZNKSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE13do_date_orderEv"; + case 0x61a23009: return "_ZNKSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE5_FputES3_RSt8ios_basewPKcjjjj"; + case 0x61f55c30: return "_ZNKSt5ctypeIcE8do_widenEc"; + case 0x629b8531: return "_ZNKSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE5_IputES3_RSt8ios_basewPcj"; + case 0x62d6bf82: return "_ZNSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEED1Ev"; + case 0x62f52bb0: return "_ZNSt7_MpunctIwEC2ERKSt8_Locinfojb"; + case 0x635166c3: return "_ZNKSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_bRSt8ios_basewe"; + case 0x63a2b2cc: return "_ZNKSt8messagesIcE8do_closeEi"; + case 0x643235cf: return "_ZNSt9strstreamD1Ev"; + case 0x6437a975: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERt"; + case 0x643e67f4: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERPv"; + case 0x6463d9ea: return "_ZNKSt8messagesIwE6do_getEiiiRKSbIwSt11char_traitsIwESaIwEE"; + case 0x64ce0374: return "_ZNSbIwSt11char_traitsIwESaIwEE7replaceEjjPKwj"; + case 0x64ed868e: return "_ZSt9terminatev"; + case 0x6500d2d5: return "_ZNSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE7_GetcatEPPKNSt6locale5facetE"; + case 0x65f19631: return "_ZTv0_n12_NSiD0Ev"; + case 0x660882e8: return "_ZNSt6localeC1Ev"; + case 0x667d741b: return "_ZNSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEED0Ev"; + case 0x668b31c6: return "_ZNSs5_GrowEjb"; + case 0x66f39adb: return "_ZNSt8numpunctIwED1Ev"; + case 0x66fcc6f4: return "_ZNSt8messagesIwE7_GetcatEPPKNSt6locale5facetE"; + case 0x67948307: return "_ZNKSt7codecvtIwcSt9_MbstatetE9do_lengthERKS0_PKcS5_j"; + case 0x67c09257: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERx"; + case 0x67edde2f: return "_ZdlPvjRKSt9nothrow_t"; + case 0x67fbabf0: return "_ZNKSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE14do_get_weekdayES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateEPSt2tm"; + case 0x683ca70a: return "_ZNKSt12_String_base5_XlenEv"; + case 0x6863452e: return "_ZNSt6locale5facetD1Ev"; + case 0x6929318d: return "_ZNSs6assignERKSsjj"; + case 0x696b47f2: return "_ZNKSt7_MpunctIcE13do_neg_formatEv"; + case 0x6a6b90c9: return "_ZSt15set_new_handlerPFvvE"; + case 0x6adc320a: return "_ZNSt9money_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEED0Ev"; + case 0x6b493669: return "_ZSt7setbasei"; + case 0x6b913d53: return "_ZNSs6insertEjjc"; + case 0x6c19db26: return "_ZNKSt7_MpunctIcE16do_thousands_sepEv"; + case 0x6c386f54: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE7seekposESt4fposISt9_MbstatetENSt5_IosbIiE9_OpenmodeE"; + case 0x6c8dc459: return "_ZNKSt8bad_cast4whatEv"; + case 0x6cb1a335: return "_ZNSt6locale5facet7_DecrefEv"; + case 0x6d483b7a: return "_ZNSt12strstreambuf9pbackfailEi"; + case 0x6daed882: return "_ZNSt8ios_baseD0Ev"; + case 0x6dbbb9de: return "_ZNKSt5ctypeIcE10do_toupperEc"; + case 0x6e0bf85d: return "_ZTv0_n12_NSt10istrstreamD1Ev"; + case 0x6e4a84c1: return "_ZNSt5ctypeIcED1Ev"; + case 0x6e61426d: return "_ZNSt13basic_filebufIwSt11char_traitsIwEED1Ev"; + case 0x6f1945fc: return "_ZNSoD1Ev"; + case 0x6fe060a0: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE7seekposESt4fposISt9_MbstatetENSt5_IosbIiE9_OpenmodeE"; + case 0x7008e209: return "_ZNKSt5ctypeIwE10do_toupperEw"; + case 0x708cf940: return "_ZNKSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE11do_get_dateES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateEPSt2tm"; + case 0x709ab035: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE6setbufEPci"; + case 0x7142ad20: return "_ZNKSt7_MpunctIcE16do_decimal_pointEv"; + case 0x718977c5: return "_ZNSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE7_GetcatEPPKNSt6locale5facetE"; + case 0x736c5f22: return "_ZNSoD0Ev"; + case 0x74a39b4f: return "_ZThn8_NSt9strstreamD1Ev"; + case 0x753c71db: return "_ZNKSt7_MpunctIcE13do_pos_formatEv"; + case 0x75824de0: return "_ZNSt6_MutexC1Ev"; + case 0x75975eb4: return "_ZNSsC1EPKc"; + case 0x75a0617c: return "_ZNKSt7_MpunctIwE11do_groupingEv"; + case 0x764ceaa4: return "_ZNSt10ostrstreamD0Ev"; + case 0x767a4e70: return "_ZNSt6_WinitC2Ev"; + case 0x76db6974: return "_ZNSt7codecvtIwcSt9_MbstatetED0Ev"; + case 0x76de9b0f: return "_ZNSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEED1Ev"; + case 0x76e846b2: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE6xsputnEPKwi"; + case 0x77c1d3a9: return "_ZNKSt13runtime_error8_DoraiseEv"; + case 0x7882e64e: return "_ZNSt7collateIwED0Ev"; + case 0x78a142d0: return "_ZSt7_FiopenPKcNSt5_IosbIiE9_OpenmodeEi"; + case 0x79a415f8: return "_ZNSbIwSt11char_traitsIwESaIwEE6insertEjjw"; + case 0x79ad3575: return "_ZTv0_n12_NSoD1Ev"; + case 0x7a180518: return "_ZNSt10money_baseD0Ev"; + case 0x7b1db41e: return "_ZNSt6locale7_AddfacEPNS_5facetEjj"; + case 0x7b5fce95: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE6setbufEPwi"; + case 0x7c391411: return "_ZNSt10moneypunctIcLb0EED0Ev"; + case 0x7cdbda48: return "_ZNSt7collateIcED0Ev"; + case 0x7d23aa12: return "_ZNSt10moneypunctIwLb0EE7_GetcatEPPKNSt6locale5facetE"; + case 0x7da7fdb1: return "_ZNKSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_RSt8ios_basewy"; + case 0x7e7ac30e: return "_ZNSt6locale5emptyEv"; + case 0x7ebad3f0: return "_ZNKSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE8_PutmfldES3_bRSt8ios_basewbSbIwS2_SaIwEE"; + case 0x7fe08910: return "_ZNSt10moneypunctIcLb0EE7_GetcatEPPKNSt6locale5facetE"; + case 0x7ff35597: return "_ZNSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE7_GetcatEPPKNSt6locale5facetE"; + case 0x8006c4ec: return "_ZNSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEED0Ev"; + case 0x8044f596: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE5_LockEv"; + case 0x81027e75: return "_ZNSt7_MpunctIwE5_InitERKSt8_Locinfo"; + case 0x816aebc3: return "_ZNSt9bad_allocD0Ev"; + case 0x823759d3: return "_ZNKSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_RSt8ios_basewl"; + case 0x8341b529: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE8overflowEi"; + case 0x83b2cc6f: return "_Znwj"; + case 0x83bca135: return "_ZNKSt11logic_error4whatEv"; + case 0x83cba890: return "_ZNSt6locale5facetD2Ev"; + case 0x84023c03: return "_ZSt12setprecisioni"; + case 0x854bc7c7: return "_ZNSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEED0Ev"; + case 0x85b3c6da: return "_ZNKSt8_Locinfo7_GetcvtEv"; + case 0x85ba062f: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE7_UnlockEv"; + case 0x867956a4: return "_ZNSt9basic_iosIcSt11char_traitsIcEED1Ev"; + case 0x868531a3: return "_ZdaPvj"; + case 0x86c66cfc: return "_ZNSsD1Ev"; + case 0x871506ea: return "_ZNSbIwSt11char_traitsIwESaIwEE6assignERKS2_jj"; + case 0x8729f617: return "_ZNSt10ostrstreamC1EPciNSt5_IosbIiE9_OpenmodeE"; + case 0x87b1f5eb: return "_ZNSt9exceptionD0Ev"; + case 0x88052736: return "_ZTv0_n12_NSt10ostrstreamD0Ev"; + case 0x883e1f16: return "_ZNKSt11logic_error8_DoraiseEv"; + case 0x884b021b: return "_ZNKSt5ctypeIwE8_DowidenEc"; + case 0x8a665143: return "_ZNSt8_Locinfo8_AddcatsEiPKc"; + case 0x8a85d688: return "_ZNKSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_RSt8ios_basewx"; + case 0x8bfd4395: return "_ZNSt9basic_iosIwSt11char_traitsIwEE4initEPSt15basic_streambufIwS1_Eb"; + case 0x8c2e6d06: return "_ZNKSt8messagesIwE7do_openERKSsRKSt6locale"; + case 0x8c3afd4c: return "_ZSt10unexpectedv"; + case 0x8c6b8d39: return "_ZNSt13basic_filebufIcSt11char_traitsIcEED1Ev"; + case 0x8cda1f3b: return "_ZSt10_GetloctxtIcSt19istreambuf_iteratorIcSt11char_traitsIcEEEiRT0_S5_jPKT_"; + case 0x8d4e266b: return "_ZNKSt8_Locinfo9_GetctypeEv"; + case 0x8fa764f3: return "_ZNSt6_WinitC1Ev"; + case 0x900d1fa4: return "_ZNSt8time_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEED0Ev"; + case 0x903afa37: return "_ZTv0_n12_NSt13basic_ostreamIwSt11char_traitsIwEED0Ev"; + case 0x904dbd32: return "_ZNSt6locale7_LocimpC1Eb"; + case 0x9111ec36: return "_ZNSt13messages_baseD0Ev"; + case 0x91959ed6: return "_ZNKSt5ctypeIcE9do_narrowEcc"; + case 0x91b0e37e: return "_ZSt14set_unexpectedPFvvE"; + case 0x9268d6e7: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERj"; + case 0x928fbe36: return "_ZTv0_n12_NSdD1Ev"; + case 0x93c638e9: return "_ZNSt19istreambuf_iteratorIwSt11char_traitsIwEE5_PeekEv"; + case 0x94c49383: return "_ZdlPvS_"; + case 0x94fa1f5b: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE5uflowEv"; + case 0x95082493: return "_ZNKSt8messagesIcE6do_getEiiiRKSs"; + case 0x95b43c9d: return "_ZNSt6locale7_LocimpD2Ev"; + case 0x96634e42: return "_ZNKSt9bad_alloc4whatEv"; + case 0x96bc2578: return "_Znajj"; + case 0x97911f5f: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE5uflowEv"; + case 0x984ce3d7: return "_ZNSt8numpunctIcED1Ev"; + case 0x9891bf45: return "_ZNKSt7_MpunctIwE16do_thousands_sepEv"; + case 0x9a194306: return "_ZNSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE5_InitERKSt8_Locinfo"; + case 0x9a449047: return "_ZNSt7_MpunctIwEC2Ejb"; + case 0x9aa7a8b3: return "_ZNSt10istrstreamD2Ev"; + case 0x9afa5d71: return "_ZNSt10money_baseD2Ev"; + case 0x9b5358f9: return "_ZNKSt7_MpunctIcE16do_positive_signEv"; + case 0x9c40d1f9: return "_ZNKSt8numpunctIwE16do_decimal_pointEv"; + case 0x9c486668: return "_ZNSt6locale7_Locimp9_MakexlocERKSt8_LocinfoiPS0_PKS_"; + case 0x9cb73ee0: return "_ZSt6_ThrowRKSt9exception"; + case 0x9cfc0eaf: return "_ZNSiD1Ev"; + case 0x9d6a8167: return "_ZNSbIwSt11char_traitsIwESaIwEE5eraseEjj"; + case 0x9dbbe07d: return "_ZNKSt9money_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE8_GetmfldERS3_S5_bRSt8ios_base"; + case 0x9dc040e4: return "_Deletegloballocale"; + case 0x9dcb4bcb: return "_ZNKSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE14do_get_weekdayES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateEPSt2tm"; + case 0x9e741d47: return "_ZNSsC1ERKSs"; + case 0x9ec88ae6: return "_ZNKSt5ctypeIwE10do_tolowerEPwPKw"; + case 0x9ef60bf3: return "_ZNKSt5ctypeIwE10do_tolowerEw"; + case 0x9f528cd3: return "_ZNKSt7codecvtIccSt9_MbstatetE6do_outERS0_PKcS4_RS4_PcS6_RS6_"; + case 0x9f959451: return "_ZNSt13basic_istreamIwSt11char_traitsIwEED1Ev"; + case 0x9facb533: return "_ZNSt13messages_baseD1Ev"; + case 0x9fd2eea9: return "_ZNSt8_LocinfoC2EiPKc"; + case 0xa1c6fc55: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE7_UnlockEv"; + case 0xa1de25c2: return "_ZTv0_n12_NSt10ostrstreamD1Ev"; + case 0xa22d5dda: return "_ZNSt8messagesIcED0Ev"; + case 0xa2fd0ec5: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE9pbackfailEi"; + case 0xa35033e8: return "_ZNKSt5ctypeIwE8do_widenEPKcS2_Pw"; + case 0xa37c3e51: return "_ZNKSt5ctypeIwE8do_widenEc"; + case 0xa3f5c3b2: return "_ZNSt9strstreamD2Ev"; + case 0xa433147a: return "_ZNSt8messagesIcE7_GetcatEPPKNSt6locale5facetE"; + case 0xa464c70a: return "_ZNKSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_bRSt8ios_basewRKSbIwS2_SaIwEE"; + case 0xa4f6a919: return "_ZThn8_NSdD1Ev"; + case 0xa5306edb: return "_ZNSt10moneypunctIwLb1EED1Ev"; + case 0xa562099c: return "_ZNSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEED1Ev"; + case 0xa700bc7d: return "_ZNKSt7codecvtIwcSt9_MbstatetE6do_outERS0_PKwS4_RS4_PcS6_RS6_"; + case 0xa74e5a27: return "_ZNKSt6localeeqERKS_"; + case 0xa79c4516: return "_ZNSt15basic_streambufIcSt11char_traitsIcEED0Ev"; + case 0xa8ece2e0: return "_ZSt9use_facetISt10moneypunctIwLb0EEERKT_RKSt6locale"; + case 0xa8f64fdb: return "_ZNKSt5ctypeIcE10do_tolowerEPcPKc"; + case 0xa90c4ff2: return "_ZNSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE7_GetcatEPPKNSt6locale5facetE"; + case 0xa9116516: return "_ZNSs6appendEjc"; + case 0xa94be0fa: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE9_EndwriteEv"; + case 0xa957adcc: return "_ZNKSt5ctypeIcE9do_narrowEPKcS2_cPc"; + case 0xa9e5bb16: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERm"; + case 0xaa520d9f: return "_ZNSt6locale7_Locimp7_AddfacEPNS_5facetEj"; + case 0xaae64804: return "_ZNSt8ios_base8_FindarrEi"; + case 0xab211d97: return "_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_RSt8ios_basecb"; + case 0xab5832fd: return "_ZNSt10money_baseD1Ev"; + case 0xabd92bcc: return "_ZNSt7collateIwE7_GetcatEPPKNSt6locale5facetE"; + case 0xabdc2b49: return "_ZNSt9money_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE7_GetcatEPPKNSt6locale5facetE"; + case 0xac6c23c0: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERy"; + case 0xad3777a2: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE8overflowEi"; + case 0xad382a99: return "_ZdlPvRKSt9nothrow_t"; + case 0xad6d839f: return "_ZNSt12codecvt_baseD0Ev"; + case 0xad6dbac2: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERm"; + case 0xadc2263b: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE6xsputnEPKci"; + case 0xae7d042f: return "_ZNSt7codecvtIwcSt9_MbstatetE7_GetcatEPPKNSt6locale5facetE"; + case 0xaea59ceb: return "_ZNSt10ctype_baseD0Ev"; + case 0xb0c185b7: return "_ZNSt10moneypunctIcLb1EE7_GetcatEPPKNSt6locale5facetE"; + case 0xb0e7c2f3: return "_ZNSiD0Ev"; + case 0xb1550b3c: return "_ZNKSt7num_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_RSt8ios_basecx"; + case 0xb1ac1fa3: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE6xsgetnEPwi"; + case 0xb1d696f7: return "_ZNKSt8numpunctIcE12do_falsenameEv"; + case 0xb326f699: return "_ZNKSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_bRSt8ios_basece"; + case 0xb33ef042: return "_ZNSt8bad_castD0Ev"; + case 0xb3f05af3: return "_ZNKSt7collateIcE12do_transformEPKcS2_"; + case 0xb4352488: return "_ZNKSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_bRSt8ios_basecRKSs"; + case 0xb4a8791f: return "_ZNSt8time_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEED1Ev"; + case 0xb509ab64: return "_ZNSt10moneypunctIcLb1EED1Ev"; + case 0xb53fa02e: return "_ZnwjjRKSt9nothrow_t"; + case 0xb6a4d760: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE7seekposESt4fposISt9_MbstatetENSt5_IosbIiE9_OpenmodeE"; + case 0xb6a7ba7a: return "_ZNSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEED0Ev"; + case 0xb74f7b8f: return "_ZNSt6locale7_LocimpC2ERKS0_"; + case 0xb7dcbfdd: return "__Setgloballocale"; + case 0xb80ca215: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE5imbueERKSt6locale"; + case 0xb87c4b43: return "_ZNSt12strstreambuf6freezeEb"; + case 0xb8836b50: return "_ZNSt9exception18_Set_raise_handlerEPFvRKS_E"; + case 0xb8ec13a5: return "_ZNKSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_RSt8ios_basewb"; + case 0xb9a2282d: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE8overflowEi"; + case 0xba0b6300: return "_ZNSt9basic_iosIwSt11char_traitsIwEED1Ev"; + case 0xba85ce08: return "_ZNSt12strstreambufD2Ev"; + case 0xbaa15803: return "_ZSt4setwi"; + case 0xbb4599c5: return "_ZNSt11logic_errorD1Ev"; + case 0xbb712718: return "_ZnwjRKSt9nothrow_t"; + case 0xbc5ad91c: return "_ZNKSt7collateIwE10do_compareEPKwS2_S2_S2_"; + case 0xbd140e12: return "_ZNKSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE11do_get_timeES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateEPSt2tm"; + case 0xbd316983: return "_ZNSt8numpunctIcE5_InitERKSt8_Locinfo"; + case 0xbd35830b: return "_ZdaPvjS_"; + case 0xbd58ea5a: return "_ZNSt19ostreambuf_iteratorIwSt11char_traitsIwEEaSEw"; + case 0xbda26024: return "_ZNSt9strstreamD0Ev"; + case 0xbf9c3609: return "_ZNKSt5ctypeIwE10do_toupperEPwPKw"; + case 0xc013acd8: return "_ZNSt8ios_base8_CallfnsENS_5eventE"; + case 0xc06a4cd8: return "_ZNSt7_MpunctIwED1Ev"; + case 0xc22cebd8: return "_ZNSt8messagesIwED1Ev"; + case 0xc3d24eb3: return "_ZNSt9basic_iosIwSt11char_traitsIwEED0Ev"; + case 0xc41d676d: return "_ZNSt9time_baseD2Ev"; + case 0xc4c7993b: return "_ZNSbIwSt11char_traitsIwESaIwEE5_TidyEbj"; + case 0xc53ab1c0: return "_ZNSt8numpunctIwE5_InitERKSt8_Locinfo"; + case 0xc5977986: return "_ZNSt8ios_base7_AddstdEv"; + case 0xc612a38e: return "_ZNSt6_WinitD1Ev"; + case 0xc6e09225: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE5_InitEPSt6_FiletNS2_7_InitflE"; + case 0xc6ea0fd0: return "_ZNSt6locale7classicEv"; + case 0xc6f18e84: return "_ZNKSt9money_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_bRSt8ios_baseRNSt5_IosbIiE8_IostateERSbIwS2_SaIwEE"; + case 0xc79278ec: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE5imbueERKSt6locale"; + case 0xc7931798: return "_ZNKSt12_String_base5_XranEv"; + case 0xc7d0ee0c: return "_ZNKSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE16do_get_monthnameES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateEPSt2tm"; + case 0xc862f7c8: return "_ZNSt12strstreambuf8overflowEi"; + case 0xcac83a05: return "_ZNSt6locale7_LocimpC2Eb"; + case 0xcb7d00a4: return "_ZNSt6_WinitD2Ev"; + case 0xcb82e0dc: return "_ZSt13set_terminatePFvvE"; + case 0xcbe74ad3: return "_ZNKSt8messagesIwE8do_closeEi"; + case 0xcc79f55d: return "_ZNKSt7_MpunctIcE16do_negative_signEv"; + case 0xccf14bd5: return "_ZNSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE7_GetcatEPPKNSt6locale5facetE"; + case 0xcd33ed4f: return "_ZNSbIwSt11char_traitsIwESaIwEEC1Ev"; + case 0xcdafdf19: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE9showmanycEv"; + case 0xce653b6c: return "_ZNSt6_MutexC2Ev"; + case 0xce6705c3: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE8_GetifldEPcRS3_S6_NSt5_IosbIiE9_FmtflagsERKSt6locale"; + case 0xce8c6abc: return "_ZNSt8ios_base4InitC2Ev"; + case 0xcf9b4d80: return "_ZNSt10moneypunctIwLb1EED0Ev"; + case 0xd05ea37c: return "_ZNKSt19istreambuf_iteratorIwSt11char_traitsIwEEdeEv"; + case 0xd1b043b7: return "_ZSt10_MaklocchrIwET_cPS0_RKSt7_Cvtvec"; + case 0xd1ee6195: return "_ZNKSt8time_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE6do_putES3_RSt8ios_basecPKSt2tmcc"; + case 0xd2f9d93d: return "_ZNKSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_RSt8ios_basewe"; + case 0xd356aefd: return "_ZNSt6_Mutex7_UnlockEv"; + case 0xd38f4018: return "_ZSt11_MaklocbyteIwEcT_RKSt7_Cvtvec"; + case 0xd4838fbd: return "_ZNKSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_RSt8ios_basewm"; + case 0xd4ba5b31: return "_ZNSt8_LocinfoC2EPKc"; + case 0xd5244a29: return "_ZNSt10moneypunctIwLb1EE7_GetcatEPPKNSt6locale5facetE"; + case 0xd5c5ee3d: return "_ZNKSt7num_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERj"; + case 0xd6ee1090: return "_ZNKSt9money_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE6do_getES3_S3_bRSt8ios_baseRNSt5_IosbIiE8_IostateERe"; + case 0xd73321ed: return "_ZNSt10ostrstreamD1Ev"; + case 0xd76b2e07: return "_ZNKSt7codecvtIwcSt9_MbstatetE13do_max_lengthEv"; + case 0xd78efcc3: return "_ZNSt12strstreambuf9underflowEv"; + case 0xd7bc220d: return "_ZNSt8time_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEED1Ev"; + case 0xd7d92e51: return "_ZNSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEED0Ev"; + case 0xd830252c: return "_ZNSt12strstreambuf5_InitEiPcS0_i"; + case 0xd84b3689: return "_ZdlPv"; + case 0xd8aeb94a: return "_ZNSt8messagesIcED1Ev"; + case 0xd8b23008: return "_ZNSt8ios_baseD2Ev"; + case 0xd93d52b1: return "_ZNSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEED1Ev"; + case 0xd9a12c5e: return "_ZNKSt5ctypeIcE10do_toupperEPcPKc"; + case 0xd9d8af82: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE8overflowEi"; + case 0xda1088ce: return "_ZNSt6locale5facet7_IncrefEv"; + case 0xda1b159a: return "_ZNSt6_MutexD2Ev"; + case 0xda5469b3: return "_ZNSt9time_baseD0Ev"; + case 0xdab0a910: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE9pbackfailEi"; + case 0xdaf3996f: return "_ZNSt6locale6globalERKS_"; + case 0xdb5eae26: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE5_InitEPSt6_FiletNS2_7_InitflE"; + case 0xdc0c889c: return "_ZNSt8ios_base7copyfmtERKS_"; + case 0xdc4d7540: return "_ZNSt5ctypeIwED1Ev"; + case 0xdc65ab00: return "_ZNSt9money_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEED1Ev"; + case 0xdc981b5f: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE9underflowEv"; + case 0xdd8b1d47: return "_ZNSs5eraseEjj"; + case 0xdefe3230: return "_ZNSt8ios_baseD1Ev"; + case 0xdf1e09e1: return "_ZNKSt5ctypeIwE9do_narrowEPKwS2_cPc"; + case 0xdf7edb4d: return "_ZSt9use_facetISt10moneypunctIwLb1EEERKT_RKSt6locale"; + case 0xe177fd02: return "_ZNSt7_MpunctIcED2Ev"; + case 0xe196beab: return "_ZNSt9money_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEED0Ev"; + case 0xe206c08f: return "_ZNSt13basic_filebufIwSt11char_traitsIwEED0Ev"; + case 0xe2b2ac5a: return "_ZNSt6locale5facet9_RegisterEv"; + case 0xe3edd790: return "_ZNSt8bad_castD1Ev"; + case 0xe528a368: return "_ZNKSt7_MpunctIcE14do_curr_symbolEv"; + case 0xe54f1fe0: return "_ZNKSt9bad_alloc8_DoraiseEv"; + case 0xe5e1dcbc: return "_ZNSt15basic_streambufIwSt11char_traitsIwEE5imbueERKSt6locale"; + case 0xe6547e35: return "_ZNSt8messagesIwED0Ev"; + case 0xe667985a: return "_ZNSt8time_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEED0Ev"; + case 0xe75f6e21: return "_ZNKSt12length_error8_DoraiseEv"; + case 0xe7d8449e: return "_ZdlPvjS_"; + case 0xe82a422d: return "_ZNKSt8numpunctIwE11do_truenameEv"; + case 0xe8691be5: return "_ZNSt5ctypeIwED0Ev"; + case 0xe8c15f8a: return "_ZNSt7_MpunctIwED2Ev"; + case 0xe9d7a4ae: return "_ZNKSt8time_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_RSt8ios_basewPKSt2tmcc"; + case 0xeb76301c: return "_ZNSt15basic_streambufIcSt11char_traitsIcEE9pbackfailEi"; + case 0xebd4b51d: return "_ZNKSt8time_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE11do_get_yearES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateEPSt2tm"; + case 0xece969c0: return "_ZTv0_n12_NSt10istrstreamD0Ev"; + case 0xed3da02b: return "_Znwjj"; + case 0xee853baf: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE4syncEv"; + case 0xef62751c: return "_ZNKSt8time_getIcSt19istreambuf_iteratorIcSt11char_traitsIcEEE13do_date_orderEv"; + case 0xef6f90d8: return "_ZNKSt5ctypeIwE11do_scan_notEsPKwS2_"; + case 0xef959a6d: return "_ZThn8_NSt9strstreamD0Ev"; + case 0xf001a741: return "_ZNSt12strstreambufD1Ev"; + case 0xf00401d2: return "_ZNSt9basic_iosIcSt11char_traitsIcEED0Ev"; + case 0xf01deff8: return "_ZNKSt7codecvtIwcSt9_MbstatetE5do_inERS0_PKcS4_RS4_PwS6_RS6_"; + case 0xf05df017: return "_ZNSt5ctypeIcE7_GetcatEPPKNSt6locale5facetE"; + case 0xf127e816: return "_ZNSt10istrstreamD1Ev"; + case 0xf1543f02: return "_ZNKSt8_Locinfo8_GetcollEv"; + case 0xf1c86c92: return "_ZNKSt12out_of_range8_DoraiseEv"; + case 0xf1cff87d: return "_ZNSt10ctype_baseD2Ev"; + case 0xf2b9ab86: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERf"; + case 0xf30d3407: return "_ZNKSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE6do_putES3_RSt8ios_basewd"; + case 0xf51dc289: return "_ZNSt7codecvtIccSt9_MbstatetED1Ev"; + case 0xf53021e0: return "_ZNSt8bad_castC1Ev"; + case 0xf5825c7d: return "_ZNSt7collateIwED1Ev"; + case 0xf584de56: return "_ZNSt6locale7_Locimp8_MakelocERKSt8_LocinfoiPS0_PKS_"; + case 0xf58e83a5: return "_Znaj"; + case 0xf67a7e17: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE5uflowEv"; + case 0xf73f6afc: return "_ZNSt13basic_filebufIcSt11char_traitsIcEE7seekoffElNSt5_IosbIiE8_SeekdirENS4_9_OpenmodeE"; + case 0xf7845d1c: return "_ZNSt7_MpunctIcED1Ev"; + case 0xf7ba51fd: return "_ZNSt13basic_ostreamIwSt11char_traitsIwEED0Ev"; + case 0xf83e8d95: return "_ZNKSt5ctypeIcE10do_tolowerEc"; + case 0xf9ff46a1: return "_ZNSt13basic_filebufIwSt11char_traitsIwEE7seekoffElNSt5_IosbIiE8_SeekdirENS4_9_OpenmodeE"; + case 0xfb36c588: return "_ZNSt9strstreamC1EPciNSt5_IosbIiE9_OpenmodeE"; + case 0xfc563813: return "_ZNKSt7codecvtIccSt9_MbstatetE5do_inERS0_PKcS4_RS4_PcS6_RS6_"; + case 0xfc825dda: return "_ZNSt7num_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE7_GetcatEPPKNSt6locale5facetE"; + case 0xfe468b7a: return "_ZTv0_n12_NSdD0Ev"; + case 0xfeb4107c: return "_ZNSt12codecvt_baseD2Ev"; + case 0xfefd7d3a: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERy"; + case 0xffaf3218: return "_ZTv0_n12_NSoD0Ev"; + case 0xfff6ef55: return "_ZNKSt7num_getIwSt19istreambuf_iteratorIwSt11char_traitsIwEEE6do_getES3_S3_RSt8ios_baseRNSt5_IosbIiE8_IostateERb"; + } + + if (module == "sysPrxForUser") switch (fnid) + { + case 0x0341bb97: return "sys_prx_get_module_id_by_address"; + case 0x04e83d2c: return "_sys_strncmp"; + case 0x052d29a6: return "_sys_strcat"; + case 0x05c65656: return "sys_mempool_try_allocate_block"; + case 0x0618936b: return "_sys_vsnprintf"; + case 0x06574237: return "_sys_snprintf"; + case 0x1573dc3f: return "sys_lwmutex_lock"; + case 0x191f0c4a: return "_sys_strrchr"; + case 0x1ae10b92: return "_sys_spu_printf_attach_thread"; + case 0x1bc200f4: return "sys_lwmutex_unlock"; + case 0x1c9a942c: return "sys_lwcond_destroy"; + case 0x1ca525a2: return "_sys_strncasecmp"; + case 0x1ed454ce: return "sys_spu_elf_get_information"; + case 0x24a1ea07: return "sys_ppu_thread_create"; + case 0x25596f51: return "sys_mempool_get_count"; + case 0x26090058: return "sys_prx_load_module"; + case 0x27427742: return "_sys_memmove"; + case 0x2a6d9d51: return "sys_lwcond_wait"; + case 0x2c847572: return "_sys_process_atexitspawn"; + case 0x2d36462b: return "_sys_strlen"; + case 0x2f85c0ef: return "sys_lwmutex_create"; + case 0x3172759d: return "sys_game_get_temperature"; + case 0x318f17e1: return "_sys_memalign"; + case 0x350d454e: return "sys_ppu_thread_get_id"; + case 0x35168520: return "_sys_heap_malloc"; + case 0x3bd53c7b: return "_sys_memchr"; + case 0x3dd4a957: return "sys_ppu_thread_register_atexit"; + case 0x409ad939: return "sys_mmapper_free_memory"; + case 0x42b23552: return "sys_prx_register_library"; + case 0x44265c08: return "_sys_heap_memalign"; + case 0x459b4393: return "_sys_strcmp"; + case 0x45fe2fce: return "_sys_spu_printf_initialize"; + case 0x4643ba6e: return "sys_mmapper_unmap_memory"; + case 0x4a071d98: return "sys_interrupt_thread_disestablish"; + case 0x4b2f301a: return "_sys_tolower"; + case 0x5267cb35: return "sys_spinlock_unlock"; + case 0x52aadadf: return "sys_lwcond_signal_to"; + case 0x5fdfb2fe: return "_sys_spu_printf_detach_group"; + case 0x608212fc: return "sys_mempool_free_block"; + case 0x620e35a7: return "sys_game_get_system_sw_version"; + case 0x67f9fedb: return "sys_game_process_exitspawn2"; + case 0x68b9b011: return "_sys_memset"; + case 0x6bf66ea7: return "_sys_memcpy"; + case 0x6e05231d: return "sys_game_watchdog_stop"; + case 0x70258515: return "sys_mmapper_allocate_memory_from_container"; + case 0x71a8472a: return "sys_get_random_number"; + case 0x722a0254: return "sys_spinlock_trylock"; + case 0x74311398: return "sys_prx_get_my_module_id"; + case 0x744680a2: return "sys_initialize_tls"; + case 0x7498887b: return "_sys_strchr"; + case 0x791b9219: return "_sys_vsprintf"; + case 0x80fb0c19: return "sys_prx_stop_module"; + case 0x8461e528: return "sys_time_get_system_time"; + case 0x84bb6774: return "sys_prx_get_module_info"; + case 0x893305fa: return "sys_raw_spu_load"; + case 0x8985b5b6: return "_sys_heap_stats"; + case 0x8a2f159b: return "console_getc"; + case 0x8a561d92: return "_sys_heap_free"; + case 0x8bb03ab8: return "sys_game_board_storage_write"; + case 0x8c2bb498: return "sys_spinlock_initialize"; + case 0x96328741: return "_sys_process_at_Exitspawn"; + case 0x4f7172c9: return "sys_process_is_stack"; + case 0x996f7cf8: return "_sys_strncat"; + case 0x99c88692: return "_sys_strcpy"; + case 0x9d3c0f81: return "sys_mempool_destroy"; + case 0x9e0623b5: return "sys_game_watchdog_start"; + case 0x9f04f7af: return "_sys_printf"; + case 0x9f18429d: return "sys_prx_start_module"; + case 0x9f950780: return "sys_game_get_rtc_status"; + case 0xa146a143: return "sys_mempool_allocate_block"; + case 0xa1f9eafe: return "_sys_sprintf"; + case 0xa285139d: return "sys_spinlock_lock"; + case 0xa2c7ba64: return "sys_prx_exitspawn_with_level"; + case 0xa330ad84: return "sys_prx_load_module_on_memcontainer_by_fd"; + case 0xa3e3be68: return "sys_ppu_thread_once"; + case 0xa5d06bf0: return "sys_prx_get_module_list"; + case 0xaa6d9bff: return "sys_prx_load_module_on_memcontainer"; + case 0xac6fc404: return "sys_ppu_thread_unregister_atexit"; + case 0xacad8fb6: return "sys_game_watchdog_clear"; + case 0xaeb78725: return "sys_lwmutex_trylock"; + case 0xaede4b03: return "_sys_heap_delete_heap"; + case 0xaff080a4: return "sys_ppu_thread_exit"; + case 0xb257540b: return "sys_mmapper_allocate_memory"; + case 0xb27c8ae7: return "sys_prx_load_module_list"; + case 0xb2fcf2c8: return "_sys_heap_create_heap"; + case 0xb3bbcf2a: return "_sys_spu_printf_detach_thread"; + case 0xb6369393: return "_sys_heap_get_total_free_size"; + case 0xb995662e: return "sys_raw_spu_image_load"; + case 0xb9bf1078: return "_sys_heap_alloc_heap_memory"; + case 0xbdb18f83: return "_sys_malloc"; + case 0xc3476d0c: return "sys_lwmutex_destroy"; + case 0xc4fd6121: return "_sys_qsort"; + case 0xca9a60bf: return "sys_mempool_create"; + case 0xd0ea47a7: return "sys_prx_unregister_library"; + case 0xd1ad4570: return "_sys_heap_get_mallinfo"; + case 0xd3039d4d: return "_sys_strncpy"; + case 0xda0eb71a: return "sys_lwcond_create"; + case 0xdb6b3250: return "sys_spu_elf_get_segments"; + case 0xdc578057: return "sys_mmapper_map_memory"; + case 0xdd0c1e09: return "_sys_spu_printf_attach_group"; + case 0xdd3b27ac: return "_sys_spu_printf_finalize"; + case 0xe0998dbf: return "sys_prx_get_module_id_by_name"; + case 0xe0da8efd: return "sys_spu_image_close"; + case 0xe66bac36: return "console_putc"; + case 0xe6f2c1e7: return "sys_process_exit"; + case 0xe76964f5: return "sys_game_board_storage_read"; + case 0xe7ef3a80: return "sys_prx_load_module_list_on_memcontainer"; + case 0xe9a1bd84: return "sys_lwcond_signal_all"; + case 0xebe5f72f: return "sys_spu_image_import"; + case 0xeef75113: return "_sys_toupper"; + case 0xef68c17c: return "sys_prx_load_module_by_fd"; + case 0xef87a695: return "sys_lwcond_signal"; + case 0xf0aece0d: return "sys_prx_unload_module"; + case 0xf57e1d6f: return "console_write"; + case 0xf7f7fb20: return "_sys_free"; + case 0xfa7f693d: return "_sys_vprintf"; + case 0xfb5db080: return "_sys_memcmp"; + case 0xfc52a7a9: return "sys_game_process_exitspawn"; + } + + // Check registered functions + if (const auto sm = ppu_module_manager::get_module(module)) + { + const auto found = sm->functions.find(fnid); + + if (found != sm->functions.end()) + { + return found->second.name; + } + } + + return fmt::format("0x%08X", fnid); +} + +// Get variable name by VNID +extern std::string ppu_get_variable_name(const std::string& module, u32 vnid) +{ + // Check registered variables + if (const auto sm = ppu_module_manager::get_module(module)) + { + const auto found = sm->variables.find(vnid); + + if (found != sm->variables.end()) + { + return found->second.name; + } + } + + return fmt::format("0x%08X", vnid); +} + +s32 ppu_error_code::report(s32 error, const char* text) +{ + if (auto thread = get_current_cpu_thread()) + { + if (thread->type == cpu_type::ppu) + { + if (auto func = static_cast(thread)->last_function) + { + LOG_ERROR(PPU, "Function '%s' failed with 0x%08x : %s", func, error, text); + } + else + { + LOG_ERROR(PPU, "Unknown function failed with 0x%08x : %s", error, text); + } + + return error; + } + } + + LOG_ERROR(PPU, "Illegal call to ppu_report_error(0x%x, '%s')!"); + return error; +} diff --git a/rpcs3/Emu/SysCalls/SC_FUNC.h b/rpcs3/Emu/Cell/PPUFunction.h similarity index 68% rename from rpcs3/Emu/SysCalls/SC_FUNC.h rename to rpcs3/Emu/Cell/PPUFunction.h index 510c7fd0ff..184e8bba7b 100644 --- a/rpcs3/Emu/SysCalls/SC_FUNC.h +++ b/rpcs3/Emu/Cell/PPUFunction.h @@ -1,14 +1,14 @@ #pragma once -#include "Emu/Cell/PPUThread.h" +#include "PPUThread.h" -using ppu_func_caller = void(*)(PPUThread&); +using ppu_function_t = void(*)(PPUThread&); + +#define BIND_FUNC(func) [](PPUThread& ppu){ ppu.last_function = #func; ppu_func_detail::do_call(ppu, func); } struct ppu_va_args_t { - u32 g_count; - u32 f_count; - u32 v_count; + u32 count; // Number of 64-bit args passed }; namespace ppu_func_detail @@ -16,12 +16,12 @@ namespace ppu_func_detail // argument type classification enum arg_class : u32 { - ARG_GENERAL, // argument is stored in GPR registers (from r3 to r10) - ARG_FLOAT, // argument is stored in FPR registers (from f1 to f13) - ARG_VECTOR, // argument is stored in VPR registers (from v2 to v13) - ARG_STACK, // argument is stored on the stack + ARG_GENERAL, // argument stored in GPR (from r3 to r10) + ARG_FLOAT, // argument stored in FPR (from f1 to f13) + ARG_VECTOR, // argument stored in VR (from v2 to v13) + ARG_STACK, // argument stored on the stack ARG_CONTEXT, // PPUThread& passed, doesn't affect g/f/v_count - ARG_VARIADIC, // information about arg counts already passed, doesn't affect g/f/v_count + ARG_VARIADIC, // argument count at specific position, doesn't affect g/f/v_count ARG_UNKNOWN, }; @@ -33,9 +33,9 @@ namespace ppu_func_detail static_assert(!std::is_reference::value, "Invalid function argument type (reference)"); static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_GENERAL"); - static force_inline T get_arg(PPUThread& ppu) + static inline T get_arg(PPUThread& ppu) { - return cast_from_ppu_gpr(ppu.GPR[g_count + 2]); + return ppu_gpr_cast(ppu.GPR[g_count + 2]); } }; @@ -44,7 +44,7 @@ namespace ppu_func_detail { static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_FLOAT"); - static force_inline T get_arg(PPUThread& ppu) + static inline T get_arg(PPUThread& ppu) { return static_cast(ppu.FPR[f_count]); } @@ -53,26 +53,22 @@ namespace ppu_func_detail template struct bind_arg { - static_assert(std::is_same, v128>::value, "Invalid function argument type for ARG_VECTOR"); + static_assert(std::is_same::value, "Invalid function argument type for ARG_VECTOR"); static force_inline T get_arg(PPUThread& ppu) { - return ppu.VPR[v_count + 1]; + return ppu.VR[v_count + 1]; } }; template struct bind_arg { - static_assert(f_count <= 13, "TODO: Unsupported stack argument type (float)"); - static_assert(v_count <= 12, "TODO: Unsupported stack argument type (vector)"); - static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_STACK"); + static_assert(alignof(T) <= 16, "Unsupported type alignment for ARG_STACK"); static force_inline T get_arg(PPUThread& ppu) { - // TODO: check stack argument displacement - const u64 res = ppu.get_stack_arg(8 + std::max(g_count - 8, 0) + std::max(f_count - 13, 0) + std::max(v_count - 12, 0)); - return cast_from_ppu_gpr(res); + return ppu_gpr_cast(*ppu.get_stack_arg(g_count, alignof(T))); // TODO } }; @@ -94,7 +90,7 @@ namespace ppu_func_detail static force_inline ppu_va_args_t get_arg(PPUThread& ppu) { - return{ g_count, f_count, v_count }; + return{ g_count }; } }; @@ -106,7 +102,7 @@ namespace ppu_func_detail static force_inline void put_result(PPUThread& ppu, const T& result) { - ppu.GPR[3] = cast_to_ppu_gpr(result); + ppu.GPR[3] = ppu_gpr_cast(result); } }; @@ -124,11 +120,11 @@ namespace ppu_func_detail template struct bind_result { - static_assert(std::is_same, v128>::value, "Invalid function result type for ARG_VECTOR"); + static_assert(std::is_same::value, "Invalid function result type for ARG_VECTOR"); static force_inline void put_result(PPUThread& ppu, const T& result) { - ppu.VPR[2] = result; + ppu.VR[2] = result; } }; @@ -176,9 +172,9 @@ namespace ppu_func_detail // TODO: check calculations const bool is_float = std::is_floating_point::value; - const bool is_vector = std::is_same, v128>::value; + const bool is_vector = std::is_same::value; const bool is_context = std::is_same::value; - const bool is_variadic = std::is_same, ppu_va_args_t>::value; + const bool is_variadic = std::is_same::value; const bool is_general = !is_float && !is_vector && !is_context && !is_variadic; const arg_class t = @@ -189,19 +185,20 @@ namespace ppu_func_detail is_variadic ? ARG_VARIADIC : ARG_UNKNOWN; - const u32 g = g_count + is_general; + const u32 g = g_count + (is_general || is_float ? 1 : is_vector ? ::align(g_count, 2) + 2 : 0); const u32 f = f_count + is_float; const u32 v = v_count + is_vector; return call(ppu, func, arg_info_pack_t{}); } - template struct result_type + template + struct result_type { static_assert(!std::is_pointer::value, "Invalid function result type (pointer)"); static_assert(!std::is_reference::value, "Invalid function result type (reference)"); static const bool is_float = std::is_floating_point::value; - static const bool is_vector = std::is_same, v128>::value; + static const bool is_vector = std::is_same::value; static const arg_class value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL); }; @@ -229,10 +226,66 @@ namespace ppu_func_detail } }; - template force_inline void do_call(PPUThread& ppu, RT(*func)(T...)) + template + force_inline void do_call(PPUThread& ppu, RT(*func)(T...)) { func_binder::do_call(ppu, func); } } -#define BIND_FUNC(func) [](PPUThread& ppu){ ppu_func_detail::do_call(ppu, func); } +class ppu_function_manager +{ + // Global variable for each registered function + template + struct registered + { + static u32 index; + }; + + // Access global function list + static never_inline auto& access() + { + static std::vector list + { + nullptr, + [](PPUThread& ppu) { ppu.state += cpu_state::ret; }, + }; + + return list; + } + + static never_inline u32 add_function(ppu_function_t function) + { + auto& list = access(); + + list.push_back(function); + + return ::size32(list) - 1; + } + +public: + // Register function (shall only be called during global initialization) + template + static inline u32 register_function(ppu_function_t func) + { + return registered::index = add_function(func); + } + + // Get function index + template + static inline u32 get_index() + { + return registered::index; + } + + // Read all registered functions + static inline const auto& get() + { + return access(); + } +}; + +template +u32 ppu_function_manager::registered::index = 0; + +#define FIND_FUNC(func) ppu_function_manager::get_index() diff --git a/rpcs3/Emu/Cell/PPUInterpreter.cpp b/rpcs3/Emu/Cell/PPUInterpreter.cpp index ec051c8ab1..1a33bad5a6 100644 --- a/rpcs3/Emu/Cell/PPUInterpreter.cpp +++ b/rpcs3/Emu/Cell/PPUInterpreter.cpp @@ -1,13 +1,40 @@ #include "stdafx.h" -#include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/Cell/PPUThread.h" -#include "Emu/SysCalls/SysCalls.h" -#include "Emu/SysCalls/Modules.h" -#include "Emu/Cell/PPUDecoder.h" -#include "PPUInstrTable.h" +#include "PPUThread.h" #include "PPUInterpreter.h" -#include "PPUInterpreter2.h" + +inline u8 rol8(const u8 x, const u8 n) { return x << n | x >> (8 - n); } +inline u16 rol16(const u16 x, const u16 n) { return x << n | x >> (16 - n); } +inline u32 rol32(const u32 x, const u32 n) { return x << n | x >> (32 - n); } +inline u64 rol64(const u64 x, const u64 n) { return x << n | x >> (64 - n); } +inline u64 dup32(const u32 x) { return x | static_cast(x) << 32; } + +#if defined(__GNUG__) +inline std::uint64_t UMULH64(std::uint64_t a, std::uint64_t b) +{ + std::uint64_t result; + __asm__("mulq %[b]" : "=d" (result) : [a] "a" (a), [b] "rm" (b)); + return result; +} + +inline std::int64_t MULH64(std::int64_t a, std::int64_t b) +{ + std::int64_t result; + __asm__("imulq %[b]" : "=d" (result) : [a] "a" (a), [b] "rm" (b)); + return result; +} +#endif + +#if defined(_MSC_VER) +#define UMULH64 __umulh +#define MULH64 __mulh +#endif + +extern u64 get_timebased_time(); +extern void ppu_execute_syscall(PPUThread& ppu, u64 code); +extern void ppu_execute_function(PPUThread& ppu, u32 index); + +namespace vm { using namespace ps3; } class ppu_scale_table_t { @@ -30,20 +57,10 @@ public: const g_ppu_scale_table; -void ppu_interpreter::NULL_OP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::TDI(PPUThread& ppu, ppu_opcode_t op) { - PPUInterpreter inter(CPU); (*PPU_instr::main_list)(&inter, op.opcode); -} - -void ppu_interpreter::NOP(PPUThread& CPU, ppu_opcode_t op) -{ -} - - -void ppu_interpreter::TDI(PPUThread& CPU, ppu_opcode_t op) -{ - const s64 a = CPU.GPR[op.ra], b = op.simm16; - const u64 a_ = a, b_ = b; // unsigned + const s64 a = ppu.GPR[op.ra], b = op.simm16; + const u64 a_ = a, b_ = b; if (((op.bo & 0x10) && a < b) || ((op.bo & 0x8) && a > b) || @@ -51,14 +68,14 @@ void ppu_interpreter::TDI(PPUThread& CPU, ppu_opcode_t op) ((op.bo & 0x2) && a_ < b_) || ((op.bo & 0x1) && a_ > b_)) { - throw EXCEPTION(""); + throw std::runtime_error("Trap!" HERE); } } -void ppu_interpreter::TWI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::TWI(PPUThread& ppu, ppu_opcode_t op) { - const s32 a = (s32)CPU.GPR[op.ra], b = op.simm16; - const u32 a_ = a, b_ = b; // unsigned + const s32 a = u32(ppu.GPR[op.ra]), b = op.simm16; + const u32 a_ = a, b_ = b; if (((op.bo & 0x10) && a < b) || ((op.bo & 0x8) && a > b) || @@ -66,511 +83,439 @@ void ppu_interpreter::TWI(PPUThread& CPU, ppu_opcode_t op) ((op.bo & 0x2) && a_ < b_) || ((op.bo & 0x1) && a_ > b_)) { - throw EXCEPTION(""); + throw std::runtime_error("Trap!" HERE); } } -void ppu_interpreter::MFVSCR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MFVSCR(PPUThread& ppu, ppu_opcode_t op) { - throw EXCEPTION(""); + throw std::runtime_error("MFVSCR" HERE); } -void ppu_interpreter::MTVSCR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MTVSCR(PPUThread& ppu, ppu_opcode_t op) { - // ignored (MFVSCR disabled) + LOG_WARNING(PPU, "MTVSCR"); } -void ppu_interpreter::VADDCUW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDCUW(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; - CPU.VPR[op.vd].vi = _mm_srli_epi32(_mm_cmpgt_epi32(_mm_xor_si128(b, _mm_set1_epi32(0x80000000)), _mm_xor_si128(a, _mm_set1_epi32(0x7fffffff))), 31); + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; + ppu.VR[op.vd].vi = _mm_srli_epi32(_mm_cmpgt_epi32(_mm_xor_si128(b, _mm_set1_epi32(0x80000000)), _mm_xor_si128(a, _mm_set1_epi32(0x7fffffff))), 31); } -void ppu_interpreter::VADDFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::addfs(CPU.VPR[op.va], CPU.VPR[op.vb]); + ppu.VR[op.vd] = v128::addfs(ppu.VR[op.va], ppu.VR[op.vb]); } -void ppu_interpreter::VADDSBS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDSBS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_adds_epi8(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_adds_epi8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VADDSHS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDSHS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_adds_epi16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_adds_epi16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VADDSWS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDSWS(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va]; - const auto b = CPU.VPR[op.vb]; + const auto a = ppu.VR[op.va]; + const auto b = ppu.VR[op.vb]; const auto s = v128::add32(a, b); // a + b const auto m = (a ^ s) & (b ^ s); // overflow bit const auto x = _mm_srai_epi32(m.vi, 31); // saturation mask const auto y = _mm_srai_epi32(_mm_and_si128(s.vi, m.vi), 31); // positive saturation mask - CPU.VPR[op.vd].vi = _mm_xor_si128(_mm_xor_si128(_mm_srli_epi32(x, 1), y), _mm_or_si128(s.vi, x)); + ppu.VR[op.vd].vi = _mm_xor_si128(_mm_xor_si128(_mm_srli_epi32(x, 1), y), _mm_or_si128(s.vi, x)); } -void ppu_interpreter::VADDUBM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDUBM(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::add8(CPU.VPR[op.va], CPU.VPR[op.vb]); + ppu.VR[op.vd] = v128::add8(ppu.VR[op.va], ppu.VR[op.vb]); } -void ppu_interpreter::VADDUBS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDUBS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_adds_epu8(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_adds_epu8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VADDUHM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDUHM(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::add16(CPU.VPR[op.va], CPU.VPR[op.vb]); + ppu.VR[op.vd] = v128::add16(ppu.VR[op.va], ppu.VR[op.vb]); } -void ppu_interpreter::VADDUHS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDUHS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_adds_epu16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_adds_epu16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VADDUWM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDUWM(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::add32(CPU.VPR[op.va], CPU.VPR[op.vb]); + ppu.VR[op.vd] = v128::add32(ppu.VR[op.va], ppu.VR[op.vb]); } -void ppu_interpreter::VADDUWS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VADDUWS(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_add_epi32(a, b), _mm_cmpgt_epi32(_mm_xor_si128(b, _mm_set1_epi32(0x80000000)), _mm_xor_si128(a, _mm_set1_epi32(0x7fffffff)))); + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; + ppu.VR[op.vd].vi = _mm_or_si128(_mm_add_epi32(a, b), _mm_cmpgt_epi32(_mm_xor_si128(b, _mm_set1_epi32(0x80000000)), _mm_xor_si128(a, _mm_set1_epi32(0x7fffffff)))); } -void ppu_interpreter::VAND(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VAND(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = CPU.VPR[op.va] & CPU.VPR[op.vb]; + ppu.VR[op.vd] = ppu.VR[op.va] & ppu.VR[op.vb]; } -void ppu_interpreter::VANDC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VANDC(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = CPU.VPR[op.va] & ~CPU.VPR[op.vb]; + ppu.VR[op.vd] = v128::andnot(ppu.VR[op.vb], ppu.VR[op.va]); } -void ppu_interpreter::VAVGSB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VAVGSB(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va]; - const auto b = v128::add8(CPU.VPR[op.vb], v128::from8p(1)); // add 1 + const auto a = ppu.VR[op.va]; + const auto b = v128::add8(ppu.VR[op.vb], v128::from8p(1)); // add 1 const auto summ = v128::add8(a, b) & v128::from8p(0xfe); const auto sign = v128::from8p(0x80); const auto overflow = (((a ^ summ) & (b ^ summ)) ^ summ ^ v128::eq8(b, sign)) & sign; // calculate msb - CPU.VPR[op.vd].vi = _mm_or_si128(overflow.vi, _mm_srli_epi64(summ.vi, 1)); + ppu.VR[op.vd].vi = _mm_or_si128(overflow.vi, _mm_srli_epi64(summ.vi, 1)); } -void ppu_interpreter::VAVGSH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VAVGSH(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va]; - const auto b = v128::add16(CPU.VPR[op.vb], v128::from16p(1)); // add 1 + const auto a = ppu.VR[op.va]; + const auto b = v128::add16(ppu.VR[op.vb], v128::from16p(1)); // add 1 const auto summ = v128::add16(a, b); const auto sign = v128::from16p(0x8000); const auto overflow = (((a ^ summ) & (b ^ summ)) ^ summ ^ v128::eq16(b, sign)) & sign; // calculate msb - CPU.VPR[op.vd].vi = _mm_or_si128(overflow.vi, _mm_srli_epi16(summ.vi, 1)); + ppu.VR[op.vd].vi = _mm_or_si128(overflow.vi, _mm_srli_epi16(summ.vi, 1)); } -void ppu_interpreter::VAVGSW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VAVGSW(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va]; - const auto b = v128::add32(CPU.VPR[op.vb], v128::from32p(1)); // add 1 + const auto a = ppu.VR[op.va]; + const auto b = v128::add32(ppu.VR[op.vb], v128::from32p(1)); // add 1 const auto summ = v128::add32(a, b); const auto sign = v128::from32p(0x80000000); const auto overflow = (((a ^ summ) & (b ^ summ)) ^ summ ^ v128::eq32(b, sign)) & sign; // calculate msb - CPU.VPR[op.vd].vi = _mm_or_si128(overflow.vi, _mm_srli_epi32(summ.vi, 1)); + ppu.VR[op.vd].vi = _mm_or_si128(overflow.vi, _mm_srli_epi32(summ.vi, 1)); } -void ppu_interpreter::VAVGUB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VAVGUB(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_avg_epu8(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_avg_epu8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VAVGUH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VAVGUH(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_avg_epu16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_avg_epu16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VAVGUW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VAVGUW(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va]; - const auto b = CPU.VPR[op.vb]; + const auto a = ppu.VR[op.va]; + const auto b = ppu.VR[op.vb]; const auto summ = v128::add32(v128::add32(a, b), v128::from32p(1)); const auto carry = _mm_xor_si128(_mm_slli_epi32(sse_cmpgt_epu32(summ.vi, a.vi), 31), _mm_set1_epi32(0x80000000)); - CPU.VPR[op.vd].vi = _mm_or_si128(carry, _mm_srli_epi32(summ.vi, 1)); + ppu.VR[op.vd].vi = _mm_or_si128(carry, _mm_srli_epi32(summ.vi, 1)); } -void ppu_interpreter::VCFSX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCFSX(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = _mm_mul_ps(_mm_cvtepi32_ps(CPU.VPR[op.vb].vi), g_ppu_scale_table[0 - op.vuimm]); + ppu.VR[op.vd].vf = _mm_mul_ps(_mm_cvtepi32_ps(ppu.VR[op.vb].vi), g_ppu_scale_table[0 - op.vuimm]); } -void ppu_interpreter::VCFUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCFUX(PPUThread& ppu, ppu_opcode_t op) { - const auto b = CPU.VPR[op.vb].vi; + const auto b = ppu.VR[op.vb].vi; const auto fix = _mm_and_ps(_mm_castsi128_ps(_mm_srai_epi32(b, 31)), _mm_set1_ps(0x80000000)); - CPU.VPR[op.vd].vf = _mm_mul_ps(_mm_add_ps(_mm_cvtepi32_ps(_mm_and_si128(b, _mm_set1_epi32(0x7fffffff))), fix), g_ppu_scale_table[0 - op.vuimm]); + ppu.VR[op.vd].vf = _mm_mul_ps(_mm_add_ps(_mm_cvtepi32_ps(_mm_and_si128(b, _mm_set1_epi32(0x7fffffff))), fix), g_ppu_scale_table[0 - op.vuimm]); } -void ppu_interpreter::VCMPBFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPBFP(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vf; - const auto b = CPU.VPR[op.vb].vf; + const auto a = ppu.VR[op.va].vf; + const auto b = ppu.VR[op.vb].vf; const auto sign = _mm_castsi128_ps(_mm_set1_epi32(0x80000000)); - const auto bneg = _mm_xor_ps(b, sign); - CPU.VPR[op.vd].vf = _mm_or_ps(_mm_and_ps(_mm_cmpnle_ps(a, b), sign), _mm_and_ps(_mm_cmpnge_ps(a, bneg), _mm_castsi128_ps(_mm_set1_epi32(0x40000000)))); + const auto cmp1 = _mm_cmpnle_ps(a, b); + const auto cmp2 = _mm_cmpnge_ps(a, _mm_xor_ps(b, sign)); + ppu.VR[op.vd].vf = _mm_or_ps(_mm_and_ps(cmp1, sign), _mm_and_ps(cmp2, _mm_castsi128_ps(_mm_set1_epi32(0x40000000)))); + if (op.oe) ppu.SetCR(6, false, false, _mm_movemask_ps(_mm_or_ps(cmp1, cmp2)) == 0, false); } -void ppu_interpreter::VCMPBFP_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPEQFP(PPUThread& ppu, ppu_opcode_t op) { - VCMPBFP(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? 0 : 2; // set 2 if all in bounds + const auto rmask = _mm_movemask_ps(ppu.VR[op.vd].vf = _mm_cmpeq_ps(ppu.VR[op.va].vf, ppu.VR[op.vb].vf)); + if (op.oe) ppu.SetCR(6, rmask == 0xf, false, rmask == 0, false); } -void ppu_interpreter::VCMPEQFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPEQUB(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = _mm_cmpeq_ps(CPU.VPR[op.va].vf, CPU.VPR[op.vb].vf); + const auto rmask = _mm_movemask_epi8((ppu.VR[op.vd] = v128::eq8(ppu.VR[op.va], ppu.VR[op.vb])).vi); + if (op.oe) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); } -void ppu_interpreter::VCMPEQFP_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPEQUH(PPUThread& ppu, ppu_opcode_t op) { - VCMPEQFP(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; // set 2 if none equal, 8 if all equal + const auto rmask = _mm_movemask_epi8((ppu.VR[op.vd] = v128::eq16(ppu.VR[op.va], ppu.VR[op.vb])).vi); + if (op.oe) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); } -void ppu_interpreter::VCMPEQUB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPEQUW(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::eq8(CPU.VPR[op.va], CPU.VPR[op.vb]); + const auto rmask = _mm_movemask_epi8((ppu.VR[op.vd] = v128::eq32(ppu.VR[op.va], ppu.VR[op.vb])).vi); + if (op.oe) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); } -void ppu_interpreter::VCMPEQUB_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPGEFP(PPUThread& ppu, ppu_opcode_t op) { - VCMPEQUB(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; // set 2 if none equal, 8 if all equal + const auto rmask = _mm_movemask_ps(ppu.VR[op.vd].vf = _mm_cmpge_ps(ppu.VR[op.va].vf, ppu.VR[op.vb].vf)); + if (op.oe) ppu.SetCR(6, rmask == 0xf, false, rmask == 0, false); } -void ppu_interpreter::VCMPEQUH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPGTFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::eq16(CPU.VPR[op.va], CPU.VPR[op.vb]); + const auto rmask = _mm_movemask_ps(ppu.VR[op.vd].vf = _mm_cmpgt_ps(ppu.VR[op.va].vf, ppu.VR[op.vb].vf)); + if (op.oe) ppu.SetCR(6, rmask == 0xf, false, rmask == 0, false); } -void ppu_interpreter::VCMPEQUH_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPGTSB(PPUThread& ppu, ppu_opcode_t op) { - VCMPEQUH(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; // set 2 if none equal, 8 if all equal + const auto rmask = _mm_movemask_epi8(ppu.VR[op.vd].vi = _mm_cmpgt_epi8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi)); + if (op.oe) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); } -void ppu_interpreter::VCMPEQUW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPGTSH(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::eq32(CPU.VPR[op.va], CPU.VPR[op.vb]); + const auto rmask = _mm_movemask_epi8(ppu.VR[op.vd].vi = _mm_cmpgt_epi16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi)); + if (op.oe) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); } -void ppu_interpreter::VCMPEQUW_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPGTSW(PPUThread& ppu, ppu_opcode_t op) { - VCMPEQUW(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; // set 2 if none equal, 8 if all equal + const auto rmask = _mm_movemask_epi8(ppu.VR[op.vd].vi = _mm_cmpgt_epi32(ppu.VR[op.va].vi, ppu.VR[op.vb].vi)); + if (op.oe) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); } -void ppu_interpreter::VCMPGEFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPGTUB(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = _mm_cmpge_ps(CPU.VPR[op.va].vf, CPU.VPR[op.vb].vf); + const auto rmask = _mm_movemask_epi8(ppu.VR[op.vd].vi = sse_cmpgt_epu8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi)); + if (op.oe) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); } -void ppu_interpreter::VCMPGEFP_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPGTUH(PPUThread& ppu, ppu_opcode_t op) { - VCMPGEFP(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; + const auto rmask = _mm_movemask_epi8(ppu.VR[op.vd].vi = sse_cmpgt_epu16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi)); + if (op.oe) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); } -void ppu_interpreter::VCMPGTFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCMPGTUW(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = _mm_cmpgt_ps(CPU.VPR[op.va].vf, CPU.VPR[op.vb].vf); + const auto rmask = _mm_movemask_epi8(ppu.VR[op.vd].vi = sse_cmpgt_epu32(ppu.VR[op.va].vi, ppu.VR[op.vb].vi)); + if (op.oe) ppu.SetCR(6, rmask == 0xffff, false, rmask == 0, false); } -void ppu_interpreter::VCMPGTFP_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCTSXS(PPUThread& ppu, ppu_opcode_t op) { - VCMPGTFP(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; + const auto scaled = _mm_mul_ps(ppu.VR[op.vb].vf, g_ppu_scale_table[op.vuimm]); + ppu.VR[op.vd].vi = _mm_xor_si128(_mm_cvttps_epi32(scaled), _mm_castps_si128(_mm_cmpge_ps(scaled, _mm_set1_ps(0x80000000)))); } -void ppu_interpreter::VCMPGTSB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VCTUXS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_cmpgt_epi8(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); -} - -void ppu_interpreter::VCMPGTSB_(PPUThread& CPU, ppu_opcode_t op) -{ - VCMPGTSB(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; -} - -void ppu_interpreter::VCMPGTSH(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.VPR[op.vd].vi = _mm_cmpgt_epi16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); -} - -void ppu_interpreter::VCMPGTSH_(PPUThread& CPU, ppu_opcode_t op) -{ - VCMPGTSH(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; -} - -void ppu_interpreter::VCMPGTSW(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.VPR[op.vd].vi = _mm_cmpgt_epi32(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); -} - -void ppu_interpreter::VCMPGTSW_(PPUThread& CPU, ppu_opcode_t op) -{ - VCMPGTSW(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; -} - -void ppu_interpreter::VCMPGTUB(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.VPR[op.vd].vi = sse_cmpgt_epu8(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); -} - -void ppu_interpreter::VCMPGTUB_(PPUThread& CPU, ppu_opcode_t op) -{ - VCMPGTUB(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; -} - -void ppu_interpreter::VCMPGTUH(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.VPR[op.vd].vi = sse_cmpgt_epu16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); -} - -void ppu_interpreter::VCMPGTUH_(PPUThread& CPU, ppu_opcode_t op) -{ - VCMPGTUH(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; -} - -void ppu_interpreter::VCMPGTUW(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.VPR[op.vd].vi = sse_cmpgt_epu32(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); -} - -void ppu_interpreter::VCMPGTUW_(PPUThread& CPU, ppu_opcode_t op) -{ - VCMPGTUW(CPU, op); - - CPU.CR.cr6 = CPU.VPR[op.vd].is_any_1() ? (CPU.VPR[op.vd].is_any_0() ? 0 : 8) : 2; -} - -void ppu_interpreter::VCTSXS(PPUThread& CPU, ppu_opcode_t op) -{ - const auto scaled = _mm_mul_ps(CPU.VPR[op.vb].vf, g_ppu_scale_table[op.vuimm]); - CPU.VPR[op.vd].vi = _mm_xor_si128(_mm_cvttps_epi32(scaled), _mm_castps_si128(_mm_cmpge_ps(scaled, _mm_set1_ps(0x80000000)))); -} - -void ppu_interpreter::VCTUXS(PPUThread& CPU, ppu_opcode_t op) -{ - const auto scaled1 = _mm_max_ps(_mm_mul_ps(CPU.VPR[op.vb].vf, g_ppu_scale_table[op.vuimm]), _mm_set1_ps(0.0f)); + const auto scaled1 = _mm_max_ps(_mm_mul_ps(ppu.VR[op.vb].vf, g_ppu_scale_table[op.vuimm]), _mm_set1_ps(0.0f)); const auto scaled2 = _mm_and_ps(_mm_sub_ps(scaled1, _mm_set1_ps(0x80000000)), _mm_cmpge_ps(scaled1, _mm_set1_ps(0x80000000))); - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_or_si128(_mm_cvttps_epi32(scaled1), _mm_cvttps_epi32(scaled2)), _mm_castps_si128(_mm_cmpge_ps(scaled1, _mm_set1_ps(0x100000000)))); + ppu.VR[op.vd].vi = _mm_or_si128(_mm_or_si128(_mm_cvttps_epi32(scaled1), _mm_cvttps_epi32(scaled2)), _mm_castps_si128(_mm_cmpge_ps(scaled1, _mm_set1_ps(0x100000000)))); } -void ppu_interpreter::VEXPTEFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VEXPTEFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = sse_exp2_ps(CPU.VPR[op.vb].vf); + ppu.VR[op.vd].vf = sse_exp2_ps(ppu.VR[op.vb].vf); } -void ppu_interpreter::VLOGEFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VLOGEFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = sse_log2_ps(CPU.VPR[op.vb].vf); + ppu.VR[op.vd].vf = sse_log2_ps(ppu.VR[op.vb].vf); } -void ppu_interpreter::VMADDFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMADDFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = _mm_add_ps(_mm_mul_ps(CPU.VPR[op.va].vf, CPU.VPR[op.vc].vf), CPU.VPR[op.vb].vf); + ppu.VR[op.vd].vf = _mm_add_ps(_mm_mul_ps(ppu.VR[op.va].vf, ppu.VR[op.vc].vf), ppu.VR[op.vb].vf); } -void ppu_interpreter::VMAXFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMAXFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = _mm_max_ps(CPU.VPR[op.va].vf, CPU.VPR[op.vb].vf); + ppu.VR[op.vd].vf = _mm_max_ps(ppu.VR[op.va].vf, ppu.VR[op.vb].vf); } -void ppu_interpreter::VMAXSB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMAXSB(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; const auto m = _mm_cmpgt_epi8(a, b); - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_and_si128(m, a), _mm_andnot_si128(m, b)); + ppu.VR[op.vd].vi = _mm_or_si128(_mm_and_si128(m, a), _mm_andnot_si128(m, b)); } -void ppu_interpreter::VMAXSH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMAXSH(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_max_epi16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_max_epi16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VMAXSW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMAXSW(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; const auto m = _mm_cmpgt_epi32(a, b); - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_and_si128(m, a), _mm_andnot_si128(m, b)); + ppu.VR[op.vd].vi = _mm_or_si128(_mm_and_si128(m, a), _mm_andnot_si128(m, b)); } -void ppu_interpreter::VMAXUB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMAXUB(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_max_epu8(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_max_epu8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VMAXUH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMAXUH(PPUThread& ppu, ppu_opcode_t op) { const auto mask = _mm_set1_epi32(0x80008000); - CPU.VPR[op.vd].vi = _mm_xor_si128(_mm_max_epi16(_mm_xor_si128(CPU.VPR[op.va].vi, mask), _mm_xor_si128(CPU.VPR[op.vb].vi, mask)), mask); + ppu.VR[op.vd].vi = _mm_xor_si128(_mm_max_epi16(_mm_xor_si128(ppu.VR[op.va].vi, mask), _mm_xor_si128(ppu.VR[op.vb].vi, mask)), mask); } -void ppu_interpreter::VMAXUW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMAXUW(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; const auto m = sse_cmpgt_epu32(a, b); - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_and_si128(m, a), _mm_andnot_si128(m, b)); + ppu.VR[op.vd].vi = _mm_or_si128(_mm_and_si128(m, a), _mm_andnot_si128(m, b)); } -void ppu_interpreter::VMHADDSHS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMHADDSHS(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; - const auto c = CPU.VPR[op.vc].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; + const auto c = ppu.VR[op.vc].vi; const auto m = _mm_or_si128(_mm_srli_epi16(_mm_mullo_epi16(a, b), 15), _mm_slli_epi16(_mm_mulhi_epi16(a, b), 1)); const auto s = _mm_cmpeq_epi16(m, _mm_set1_epi16(-0x8000)); // detect special case (positive 0x8000) - CPU.VPR[op.vd].vi = _mm_adds_epi16(_mm_adds_epi16(_mm_xor_si128(m, s), c), _mm_srli_epi16(s, 15)); + ppu.VR[op.vd].vi = _mm_adds_epi16(_mm_adds_epi16(_mm_xor_si128(m, s), c), _mm_srli_epi16(s, 15)); } -void ppu_interpreter::VMHRADDSHS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMHRADDSHS(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; - const auto c = CPU.VPR[op.vc].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; + const auto c = ppu.VR[op.vc].vi; const auto m = _mm_mulhrs_epi16(a, b); const auto s = _mm_cmpeq_epi16(m, _mm_set1_epi16(-0x8000)); // detect special case (positive 0x8000) - CPU.VPR[op.vd].vi = _mm_adds_epi16(_mm_adds_epi16(_mm_xor_si128(m, s), c), _mm_srli_epi16(s, 15)); + ppu.VR[op.vd].vi = _mm_adds_epi16(_mm_adds_epi16(_mm_xor_si128(m, s), c), _mm_srli_epi16(s, 15)); } -void ppu_interpreter::VMINFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMINFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = _mm_min_ps(CPU.VPR[op.va].vf, CPU.VPR[op.vb].vf); + ppu.VR[op.vd].vf = _mm_min_ps(ppu.VR[op.va].vf, ppu.VR[op.vb].vf); } -void ppu_interpreter::VMINSB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMINSB(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; const auto m = _mm_cmpgt_epi8(a, b); - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_andnot_si128(m, a), _mm_and_si128(m, b)); + ppu.VR[op.vd].vi = _mm_or_si128(_mm_andnot_si128(m, a), _mm_and_si128(m, b)); } -void ppu_interpreter::VMINSH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMINSH(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_min_epi16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_min_epi16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VMINSW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMINSW(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; const auto m = _mm_cmpgt_epi32(a, b); - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_andnot_si128(m, a), _mm_and_si128(m, b)); + ppu.VR[op.vd].vi = _mm_or_si128(_mm_andnot_si128(m, a), _mm_and_si128(m, b)); } -void ppu_interpreter::VMINUB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMINUB(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_min_epu8(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_min_epu8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VMINUH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMINUH(PPUThread& ppu, ppu_opcode_t op) { const auto mask = _mm_set1_epi32(0x80008000); - CPU.VPR[op.vd].vi = _mm_xor_si128(_mm_min_epi16(_mm_xor_si128(CPU.VPR[op.va].vi, mask), _mm_xor_si128(CPU.VPR[op.vb].vi, mask)), mask); + ppu.VR[op.vd].vi = _mm_xor_si128(_mm_min_epi16(_mm_xor_si128(ppu.VR[op.va].vi, mask), _mm_xor_si128(ppu.VR[op.vb].vi, mask)), mask); } -void ppu_interpreter::VMINUW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMINUW(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; const auto m = sse_cmpgt_epu32(a, b); - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_andnot_si128(m, a), _mm_and_si128(m, b)); + ppu.VR[op.vd].vi = _mm_or_si128(_mm_andnot_si128(m, a), _mm_and_si128(m, b)); } -void ppu_interpreter::VMLADDUHM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMLADDUHM(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_add_epi16(_mm_mullo_epi16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi), CPU.VPR[op.vc].vi); + ppu.VR[op.vd].vi = _mm_add_epi16(_mm_mullo_epi16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi), ppu.VR[op.vc].vi); } -void ppu_interpreter::VMRGHB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMRGHB(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_unpackhi_epi8(CPU.VPR[op.vb].vi, CPU.VPR[op.va].vi); + ppu.VR[op.vd].vi = _mm_unpackhi_epi8(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); } -void ppu_interpreter::VMRGHH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMRGHH(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_unpackhi_epi16(CPU.VPR[op.vb].vi, CPU.VPR[op.va].vi); + ppu.VR[op.vd].vi = _mm_unpackhi_epi16(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); } -void ppu_interpreter::VMRGHW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMRGHW(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_unpackhi_epi32(CPU.VPR[op.vb].vi, CPU.VPR[op.va].vi); + ppu.VR[op.vd].vi = _mm_unpackhi_epi32(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); } -void ppu_interpreter::VMRGLB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMRGLB(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_unpacklo_epi8(CPU.VPR[op.vb].vi, CPU.VPR[op.va].vi); + ppu.VR[op.vd].vi = _mm_unpacklo_epi8(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); } -void ppu_interpreter::VMRGLH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMRGLH(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_unpacklo_epi16(CPU.VPR[op.vb].vi, CPU.VPR[op.va].vi); + ppu.VR[op.vd].vi = _mm_unpacklo_epi16(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); } -void ppu_interpreter::VMRGLW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMRGLW(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_unpacklo_epi32(CPU.VPR[op.vb].vi, CPU.VPR[op.va].vi); + ppu.VR[op.vd].vi = _mm_unpacklo_epi32(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); } -void ppu_interpreter::VMSUMMBM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMSUMMBM(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; // signed bytes - const auto b = CPU.VPR[op.vb].vi; // unsigned bytes - const auto c = CPU.VPR[op.vc].vi; + const auto a = ppu.VR[op.va].vi; // signed bytes + const auto b = ppu.VR[op.vb].vi; // unsigned bytes + const auto c = ppu.VR[op.vc].vi; const auto ah = _mm_srai_epi16(a, 8); const auto bh = _mm_srli_epi16(b, 8); const auto al = _mm_srai_epi16(_mm_slli_epi16(a, 8), 8); const auto bl = _mm_and_si128(b, _mm_set1_epi16(0x00ff)); const auto sh = _mm_madd_epi16(ah, bh); const auto sl = _mm_madd_epi16(al, bl); - CPU.VPR[op.vd].vi = _mm_add_epi32(_mm_add_epi32(c, sh), sl); + ppu.VR[op.vd].vi = _mm_add_epi32(_mm_add_epi32(c, sh), sl); } -void ppu_interpreter::VMSUMSHM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMSUMSHM(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_add_epi32(_mm_madd_epi16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi), CPU.VPR[op.vc].vi); + ppu.VR[op.vd].vi = _mm_add_epi32(_mm_madd_epi16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi), ppu.VR[op.vc].vi); } -void ppu_interpreter::VMSUMSHS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMSUMSHS(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + const auto& c = ppu.VR[op.vc]; + for (uint w = 0; w < 4; w++) { s64 result = 0; @@ -578,10 +523,10 @@ void ppu_interpreter::VMSUMSHS(PPUThread& CPU, ppu_opcode_t op) for (uint h = 0; h < 2; h++) { - result += CPU.VPR[op.va]._s16[w * 2 + h] * CPU.VPR[op.vb]._s16[w * 2 + h]; + result += a._s16[w * 2 + h] * b._s16[w * 2 + h]; } - result += CPU.VPR[op.vc]._s32[w]; + result += c._s32[w]; if (result > 0x7fffffff) { @@ -594,15 +539,15 @@ void ppu_interpreter::VMSUMSHS(PPUThread& CPU, ppu_opcode_t op) else saturated = (s32)result; - CPU.VPR[op.vd]._s32[w] = saturated; + d._s32[w] = saturated; } } -void ppu_interpreter::VMSUMUBM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMSUMUBM(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; - const auto c = CPU.VPR[op.vc].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; + const auto c = ppu.VR[op.vc].vi; const auto mask = _mm_set1_epi16(0x00ff); const auto ah = _mm_srli_epi16(a, 8); const auto al = _mm_and_si128(a, mask); @@ -610,23 +555,28 @@ void ppu_interpreter::VMSUMUBM(PPUThread& CPU, ppu_opcode_t op) const auto bl = _mm_and_si128(b, mask); const auto sh = _mm_madd_epi16(ah, bh); const auto sl = _mm_madd_epi16(al, bl); - CPU.VPR[op.vd].vi = _mm_add_epi32(_mm_add_epi32(c, sh), sl); + ppu.VR[op.vd].vi = _mm_add_epi32(_mm_add_epi32(c, sh), sl); } -void ppu_interpreter::VMSUMUHM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMSUMUHM(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; - const auto c = CPU.VPR[op.vc].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; + const auto c = ppu.VR[op.vc].vi; const auto ml = _mm_mullo_epi16(a, b); // low results const auto mh = _mm_mulhi_epu16(a, b); // high results const auto ls = _mm_add_epi32(_mm_srli_epi32(ml, 16), _mm_and_si128(ml, _mm_set1_epi32(0x0000ffff))); const auto hs = _mm_add_epi32(_mm_slli_epi32(mh, 16), _mm_and_si128(mh, _mm_set1_epi32(0xffff0000))); - CPU.VPR[op.vd].vi = _mm_add_epi32(_mm_add_epi32(c, ls), hs); + ppu.VR[op.vd].vi = _mm_add_epi32(_mm_add_epi32(c, ls), hs); } -void ppu_interpreter::VMSUMUHS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMSUMUHS(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + const auto& c = ppu.VR[op.vc]; + for (uint w = 0; w < 4; w++) { u64 result = 0; @@ -634,10 +584,10 @@ void ppu_interpreter::VMSUMUHS(PPUThread& CPU, ppu_opcode_t op) for (uint h = 0; h < 2; h++) { - result += (u64)CPU.VPR[op.va]._u16[w * 2 + h] * (u64)CPU.VPR[op.vb]._u16[w * 2 + h]; + result += (u64)a._u16[w * 2 + h] * (u64)b._u16[w * 2 + h]; } - result += CPU.VPR[op.vc]._u32[w]; + result += c._u32[w]; if (result > 0xffffffffu) { @@ -646,88 +596,89 @@ void ppu_interpreter::VMSUMUHS(PPUThread& CPU, ppu_opcode_t op) else saturated = (u32)result; - CPU.VPR[op.vd]._u32[w] = saturated; + d._u32[w] = saturated; } } -void ppu_interpreter::VMULESB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMULESB(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_mullo_epi16(_mm_srai_epi16(CPU.VPR[op.va].vi, 8), _mm_srai_epi16(CPU.VPR[op.vb].vi, 8)); + ppu.VR[op.vd].vi = _mm_mullo_epi16(_mm_srai_epi16(ppu.VR[op.va].vi, 8), _mm_srai_epi16(ppu.VR[op.vb].vi, 8)); } -void ppu_interpreter::VMULESH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMULESH(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_madd_epi16(_mm_srli_epi32(CPU.VPR[op.va].vi, 16), _mm_srli_epi32(CPU.VPR[op.vb].vi, 16)); + ppu.VR[op.vd].vi = _mm_madd_epi16(_mm_srli_epi32(ppu.VR[op.va].vi, 16), _mm_srli_epi32(ppu.VR[op.vb].vi, 16)); } -void ppu_interpreter::VMULEUB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMULEUB(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_mullo_epi16(_mm_srli_epi16(CPU.VPR[op.va].vi, 8), _mm_srli_epi16(CPU.VPR[op.vb].vi, 8)); + ppu.VR[op.vd].vi = _mm_mullo_epi16(_mm_srli_epi16(ppu.VR[op.va].vi, 8), _mm_srli_epi16(ppu.VR[op.vb].vi, 8)); } -void ppu_interpreter::VMULEUH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMULEUH(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; const auto ml = _mm_mullo_epi16(a, b); const auto mh = _mm_mulhi_epu16(a, b); - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_srli_epi32(ml, 16), _mm_and_si128(mh, _mm_set1_epi32(0xffff0000))); + ppu.VR[op.vd].vi = _mm_or_si128(_mm_srli_epi32(ml, 16), _mm_and_si128(mh, _mm_set1_epi32(0xffff0000))); } -void ppu_interpreter::VMULOSB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMULOSB(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_mullo_epi16(_mm_srai_epi16(_mm_slli_epi16(CPU.VPR[op.va].vi, 8), 8), _mm_srai_epi16(_mm_slli_epi16(CPU.VPR[op.vb].vi, 8), 8)); + ppu.VR[op.vd].vi = _mm_mullo_epi16(_mm_srai_epi16(_mm_slli_epi16(ppu.VR[op.va].vi, 8), 8), _mm_srai_epi16(_mm_slli_epi16(ppu.VR[op.vb].vi, 8), 8)); } -void ppu_interpreter::VMULOSH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMULOSH(PPUThread& ppu, ppu_opcode_t op) { const auto mask = _mm_set1_epi32(0x0000ffff); - CPU.VPR[op.vd].vi = _mm_madd_epi16(_mm_and_si128(CPU.VPR[op.va].vi, mask), _mm_and_si128(CPU.VPR[op.vb].vi, mask)); + ppu.VR[op.vd].vi = _mm_madd_epi16(_mm_and_si128(ppu.VR[op.va].vi, mask), _mm_and_si128(ppu.VR[op.vb].vi, mask)); } -void ppu_interpreter::VMULOUB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMULOUB(PPUThread& ppu, ppu_opcode_t op) { const auto mask = _mm_set1_epi16(0x00ff); - CPU.VPR[op.vd].vi = _mm_mullo_epi16(_mm_and_si128(CPU.VPR[op.va].vi, mask), _mm_and_si128(CPU.VPR[op.vb].vi, mask)); + ppu.VR[op.vd].vi = _mm_mullo_epi16(_mm_and_si128(ppu.VR[op.va].vi, mask), _mm_and_si128(ppu.VR[op.vb].vi, mask)); } -void ppu_interpreter::VMULOUH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VMULOUH(PPUThread& ppu, ppu_opcode_t op) { - const auto a = CPU.VPR[op.va].vi; - const auto b = CPU.VPR[op.vb].vi; + const auto a = ppu.VR[op.va].vi; + const auto b = ppu.VR[op.vb].vi; const auto ml = _mm_mullo_epi16(a, b); const auto mh = _mm_mulhi_epu16(a, b); - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_slli_epi32(mh, 16), _mm_and_si128(ml, _mm_set1_epi32(0x0000ffff))); + ppu.VR[op.vd].vi = _mm_or_si128(_mm_slli_epi32(mh, 16), _mm_and_si128(ml, _mm_set1_epi32(0x0000ffff))); } -void ppu_interpreter::VNMSUBFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VNMSUBFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = _mm_sub_ps(CPU.VPR[op.vb].vf, _mm_mul_ps(CPU.VPR[op.va].vf, CPU.VPR[op.vc].vf)); + ppu.VR[op.vd].vf = _mm_sub_ps(ppu.VR[op.vb].vf, _mm_mul_ps(ppu.VR[op.va].vf, ppu.VR[op.vc].vf)); } -void ppu_interpreter::VNOR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VNOR(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = ~(CPU.VPR[op.va] | CPU.VPR[op.vb]); + ppu.VR[op.vd] = ~(ppu.VR[op.va] | ppu.VR[op.vb]); } -void ppu_interpreter::VOR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VOR(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = CPU.VPR[op.va] | CPU.VPR[op.vb]; + ppu.VR[op.vd] = ppu.VR[op.va] | ppu.VR[op.vb]; } -void ppu_interpreter::VPERM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VPERM(PPUThread& ppu, ppu_opcode_t op) { - const auto index = _mm_andnot_si128(CPU.VPR[op.vc].vi, _mm_set1_epi8(0x1f)); + const auto index = _mm_andnot_si128(ppu.VR[op.vc].vi, _mm_set1_epi8(0x1f)); const auto mask = _mm_cmpgt_epi8(index, _mm_set1_epi8(0xf)); - const auto sa = _mm_shuffle_epi8(CPU.VPR[op.va].vi, index); - const auto sb = _mm_shuffle_epi8(CPU.VPR[op.vb].vi, index); - CPU.VPR[op.vd].vi = _mm_or_si128(_mm_and_si128(mask, sa), _mm_andnot_si128(mask, sb)); + const auto sa = _mm_shuffle_epi8(ppu.VR[op.va].vi, index); + const auto sb = _mm_shuffle_epi8(ppu.VR[op.vb].vi, index); + ppu.VR[op.vd].vi = _mm_or_si128(_mm_and_si128(mask, sa), _mm_andnot_si128(mask, sb)); } -void ppu_interpreter::VPKPX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VPKPX(PPUThread& ppu, ppu_opcode_t op) { - v128 VA = CPU.VPR[op.va]; - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VA = ppu.VR[op.va]; + v128 VB = ppu.VR[op.vb]; for (uint h = 0; h < 4; h++) { u16 bb7 = VB._u8[15 - (h * 4 + 0)] & 0x1; @@ -739,32 +690,32 @@ void ppu_interpreter::VPKPX(PPUThread& CPU, ppu_opcode_t op) u16 ab16 = VA._u8[15 - (h * 4 + 2)] >> 3; u16 ab24 = VA._u8[15 - (h * 4 + 3)] >> 3; - CPU.VPR[op.vd]._u16[3 - h] = (bb7 << 15) | (bb8 << 10) | (bb16 << 5) | bb24; - CPU.VPR[op.vd]._u16[4 + (3 - h)] = (ab7 << 15) | (ab8 << 10) | (ab16 << 5) | ab24; + d._u16[3 - h] = (bb7 << 15) | (bb8 << 10) | (bb16 << 5) | bb24; + d._u16[4 + (3 - h)] = (ab7 << 15) | (ab8 << 10) | (ab16 << 5) | ab24; } } -void ppu_interpreter::VPKSHSS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VPKSHSS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_packs_epi16(CPU.VPR[op.vb].vi, CPU.VPR[op.va].vi); + ppu.VR[op.vd].vi = _mm_packs_epi16(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); } -void ppu_interpreter::VPKSHUS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VPKSHUS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_packus_epi16(CPU.VPR[op.vb].vi, CPU.VPR[op.va].vi); + ppu.VR[op.vd].vi = _mm_packus_epi16(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); } -void ppu_interpreter::VPKSWSS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VPKSWSS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_packs_epi32(CPU.VPR[op.vb].vi, CPU.VPR[op.va].vi); + ppu.VR[op.vd].vi = _mm_packs_epi32(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); } -void ppu_interpreter::VPKSWUS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VPKSWUS(PPUThread& ppu, ppu_opcode_t op) { - //CPU.VPR[op.vd].vi = _mm_packus_epi32(CPU.VPR[op.vb].vi, CPU.VPR[op.va].vi); - - v128 VA = CPU.VPR[op.va]; - v128 VB = CPU.VPR[op.vb]; + //ppu.VR[op.vd].vi = _mm_packus_epi32(ppu.VR[op.vb].vi, ppu.VR[op.va].vi); + auto& d = ppu.VR[op.vd]; + v128 VA = ppu.VR[op.va]; + v128 VB = ppu.VR[op.vb]; for (uint h = 0; h < 4; h++) { s32 result = VA._s32[h]; @@ -778,7 +729,7 @@ void ppu_interpreter::VPKSWUS(PPUThread& CPU, ppu_opcode_t op) result = 0; } - CPU.VPR[op.vd]._u16[h + 4] = result; + d._u16[h + 4] = result; result = VB._s32[h]; @@ -791,25 +742,27 @@ void ppu_interpreter::VPKSWUS(PPUThread& CPU, ppu_opcode_t op) result = 0; } - CPU.VPR[op.vd]._u16[h] = result; + d._u16[h] = result; } } -void ppu_interpreter::VPKUHUM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VPKUHUM(PPUThread& ppu, ppu_opcode_t op) { - v128 VA = CPU.VPR[op.va]; - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VA = ppu.VR[op.va]; + v128 VB = ppu.VR[op.vb]; for (uint b = 0; b < 8; b++) { - CPU.VPR[op.vd]._u8[b + 8] = VA._u8[b * 2]; - CPU.VPR[op.vd]._u8[b] = VB._u8[b * 2]; + d._u8[b + 8] = VA._u8[b * 2]; + d._u8[b] = VB._u8[b * 2]; } } -void ppu_interpreter::VPKUHUS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VPKUHUS(PPUThread& ppu, ppu_opcode_t op) { - v128 VA = CPU.VPR[op.va]; - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VA = ppu.VR[op.va]; + v128 VB = ppu.VR[op.vb]; for (uint b = 0; b < 8; b++) { u16 result = VA._u16[b]; @@ -819,7 +772,7 @@ void ppu_interpreter::VPKUHUS(PPUThread& CPU, ppu_opcode_t op) result = UINT8_MAX; } - CPU.VPR[op.vd]._u8[b + 8] = (u8)result; + d._u8[b + 8] = (u8)result; result = VB._u16[b]; @@ -828,25 +781,27 @@ void ppu_interpreter::VPKUHUS(PPUThread& CPU, ppu_opcode_t op) result = UINT8_MAX; } - CPU.VPR[op.vd]._u8[b] = (u8)result; + d._u8[b] = (u8)result; } } -void ppu_interpreter::VPKUWUM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VPKUWUM(PPUThread& ppu, ppu_opcode_t op) { - v128 VA = CPU.VPR[op.va]; - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VA = ppu.VR[op.va]; + v128 VB = ppu.VR[op.vb]; for (uint h = 0; h < 4; h++) { - CPU.VPR[op.vd]._u16[h + 4] = VA._u16[h * 2]; - CPU.VPR[op.vd]._u16[h] = VB._u16[h * 2]; + d._u16[h + 4] = VA._u16[h * 2]; + d._u16[h] = VB._u16[h * 2]; } } -void ppu_interpreter::VPKUWUS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VPKUWUS(PPUThread& ppu, ppu_opcode_t op) { - v128 VA = CPU.VPR[op.va]; - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VA = ppu.VR[op.va]; + v128 VB = ppu.VR[op.vb]; for (uint h = 0; h < 4; h++) { u32 result = VA._u32[h]; @@ -856,7 +811,7 @@ void ppu_interpreter::VPKUWUS(PPUThread& CPU, ppu_opcode_t op) result = UINT16_MAX; } - CPU.VPR[op.vd]._u16[h + 4] = result; + d._u16[h + 4] = result; result = VB._u32[h]; @@ -865,830 +820,935 @@ void ppu_interpreter::VPKUWUS(PPUThread& CPU, ppu_opcode_t op) result = UINT16_MAX; } - CPU.VPR[op.vd]._u16[h] = result; + d._u16[h] = result; } } -void ppu_interpreter::VREFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VREFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = _mm_rcp_ps(CPU.VPR[op.vb].vf); + ppu.VR[op.vd].vf = _mm_rcp_ps(ppu.VR[op.vb].vf); } -void ppu_interpreter::VRFIM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VRFIM(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - const float b = CPU.VPR[op.vb]._f[w]; - CPU.VPR[op.vd]._f[w] = floorf(CPU.VPR[op.vb]._f[w]); + d._f[w] = floorf(b._f[w]); } } -void ppu_interpreter::VRFIN(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VRFIN(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - const float b = CPU.VPR[op.vb]._f[w]; - CPU.VPR[op.vd]._f[w] = nearbyintf(CPU.VPR[op.vb]._f[w]); + d._f[w] = nearbyintf(b._f[w]); } } -void ppu_interpreter::VRFIP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VRFIP(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - const float b = CPU.VPR[op.vb]._f[w]; - CPU.VPR[op.vd]._f[w] = ceilf(CPU.VPR[op.vb]._f[w]); + d._f[w] = ceilf(b._f[w]); } } -void ppu_interpreter::VRFIZ(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VRFIZ(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - const float b = CPU.VPR[op.vb]._f[w]; - CPU.VPR[op.vd]._f[w] = truncf(CPU.VPR[op.vb]._f[w]); + d._f[w] = truncf(b._f[w]); } } -void ppu_interpreter::VRLB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VRLB(PPUThread& ppu, ppu_opcode_t op) { - for (uint b = 0; b < 16; b++) + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + + for (uint i = 0; i < 16; i++) { - int nRot = CPU.VPR[op.vb]._u8[b] & 0x7; - - CPU.VPR[op.vd]._u8[b] = (CPU.VPR[op.va]._u8[b] << nRot) | (CPU.VPR[op.va]._u8[b] >> (8 - nRot)); + d._u8[i] = rol8(a._u8[i], b._u8[i] & 0x7); } } -void ppu_interpreter::VRLH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VRLH(PPUThread& ppu, ppu_opcode_t op) { - for (uint h = 0; h < 8; h++) + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + + for (uint i = 0; i < 8; i++) { - CPU.VPR[op.vd]._u16[h] = rotl16(CPU.VPR[op.va]._u16[h], CPU.VPR[op.vb]._u8[h * 2] & 0xf); + d._u16[i] = rol16(a._u16[i], b._u8[i * 2] & 0xf); } } -void ppu_interpreter::VRLW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VRLW(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - CPU.VPR[op.vd]._u32[w] = (u32)rotl32(CPU.VPR[op.va]._u32[w], CPU.VPR[op.vb]._u8[w * 4] & 0x1f); + d._u32[w] = rol32(a._u32[w], b._u8[w * 4] & 0x1f); } } -void ppu_interpreter::VRSQRTEFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VRSQRTEFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vf = _mm_rsqrt_ps(CPU.VPR[op.vb].vf); + ppu.VR[op.vd].vf = _mm_rsqrt_ps(ppu.VR[op.vb].vf); } -void ppu_interpreter::VSEL(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSEL(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = (CPU.VPR[op.vb] & CPU.VPR[op.vc]) | (CPU.VPR[op.va] & ~CPU.VPR[op.vc]); + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + const auto& c = ppu.VR[op.vc]; + + d = (b & c) | v128::andnot(c, a); } -void ppu_interpreter::VSL(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSL(PPUThread& ppu, ppu_opcode_t op) { - v128 VA = CPU.VPR[op.va]; - u8 sh = CPU.VPR[op.vb]._u8[0] & 0x7; + auto& d = ppu.VR[op.vd]; + v128 VA = ppu.VR[op.va]; + u8 sh = ppu.VR[op.vb]._u8[0] & 0x7; - CPU.VPR[op.vd]._u8[0] = VA._u8[0] << sh; + d._u8[0] = VA._u8[0] << sh; for (uint b = 1; b < 16; b++) { - CPU.VPR[op.vd]._u8[b] = (VA._u8[b] << sh) | (VA._u8[b - 1] >> (8 - sh)); + d._u8[b] = (VA._u8[b] << sh) | (VA._u8[b - 1] >> (8 - sh)); } } -void ppu_interpreter::VSLB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSLB(PPUThread& ppu, ppu_opcode_t op) { - for (uint b = 0; b < 16; b++) + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + + for (uint i = 0; i < 16; i++) { - CPU.VPR[op.vd]._u8[b] = CPU.VPR[op.va]._u8[b] << (CPU.VPR[op.vb]._u8[b] & 0x7); + d._u8[i] = a._u8[i] << (b._u8[i] & 0x7); } } -void ppu_interpreter::VSLDOI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSLDOI(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; u8 tmpSRC[32]; - std::memcpy(tmpSRC, CPU.VPR + op.vb, 16); - std::memcpy(tmpSRC + 16, CPU.VPR + op.va, 16); + std::memcpy(tmpSRC, &ppu.VR[op.vb], 16); + std::memcpy(tmpSRC + 16, &ppu.VR[op.va], 16); for (uint b = 0; b<16; b++) { - CPU.VPR[op.vd]._u8[15 - b] = tmpSRC[31 - (b + op.vsh)]; + d._u8[15 - b] = tmpSRC[31 - (b + op.vsh)]; } } -void ppu_interpreter::VSLH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSLH(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint h = 0; h < 8; h++) { - CPU.VPR[op.vd]._u16[h] = CPU.VPR[op.va]._u16[h] << (CPU.VPR[op.vb]._u16[h] & 0xf); + d._u16[h] = a._u16[h] << (b._u16[h] & 0xf); } } -void ppu_interpreter::VSLO(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSLO(PPUThread& ppu, ppu_opcode_t op) { - v128 VA = CPU.VPR[op.va]; - u8 nShift = (CPU.VPR[op.vb]._u8[0] >> 3) & 0xf; + auto& d = ppu.VR[op.vd]; + v128 VA = ppu.VR[op.va]; + u8 nShift = (ppu.VR[op.vb]._u8[0] >> 3) & 0xf; - CPU.VPR[op.vd].clear(); + d.clear(); for (u8 b = 0; b < 16 - nShift; b++) { - CPU.VPR[op.vd]._u8[15 - b] = VA._u8[15 - (b + nShift)]; + d._u8[15 - b] = VA._u8[15 - (b + nShift)]; } } -void ppu_interpreter::VSLW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSLW(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - CPU.VPR[op.vd]._u32[w] = CPU.VPR[op.va]._u32[w] << (CPU.VPR[op.vb]._u32[w] & 0x1f); + d._u32[w] = a._u32[w] << (b._u32[w] & 0x1f); } } -void ppu_interpreter::VSPLTB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSPLTB(PPUThread& ppu, ppu_opcode_t op) { - u8 byte = CPU.VPR[op.vb]._u8[15 - op.vuimm]; + auto& d = ppu.VR[op.vd]; + u8 byte = ppu.VR[op.vb]._u8[15 - op.vuimm]; for (uint b = 0; b < 16; b++) { - CPU.VPR[op.vd]._u8[b] = byte; + d._u8[b] = byte; } } -void ppu_interpreter::VSPLTH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSPLTH(PPUThread& ppu, ppu_opcode_t op) { - assert(op.vuimm < 8); + auto& d = ppu.VR[op.vd]; + Expects(op.vuimm < 8); - u16 hword = CPU.VPR[op.vb]._u16[7 - op.vuimm]; + u16 hword = ppu.VR[op.vb]._u16[7 - op.vuimm]; for (uint h = 0; h < 8; h++) { - CPU.VPR[op.vd]._u16[h] = hword; + d._u16[h] = hword; } } -void ppu_interpreter::VSPLTISB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSPLTISB(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const s8 imm = op.vsimm; + for (uint b = 0; b < 16; b++) { - CPU.VPR[op.vd]._u8[b] = op.vsimm; + d._u8[b] = imm; } } -void ppu_interpreter::VSPLTISH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSPLTISH(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const s16 imm = op.vsimm; + for (uint h = 0; h < 8; h++) { - CPU.VPR[op.vd]._u16[h] = (s16)op.vsimm; + d._u16[h] = imm; } } -void ppu_interpreter::VSPLTISW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSPLTISW(PPUThread& ppu, ppu_opcode_t op) { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[op.vd]._u32[w] = (s32)op.vsimm; - } -} - -void ppu_interpreter::VSPLTW(PPUThread& CPU, ppu_opcode_t op) -{ - assert(op.vuimm < 4); - - u32 word = CPU.VPR[op.vb]._u32[3 - op.vuimm]; + auto& d = ppu.VR[op.vd]; + const s32 imm = op.vsimm; for (uint w = 0; w < 4; w++) { - CPU.VPR[op.vd]._u32[w] = word; + d._u32[w] = imm; } } -void ppu_interpreter::VSR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSPLTW(PPUThread& ppu, ppu_opcode_t op) { - v128 VA = CPU.VPR[op.va]; - u8 sh = CPU.VPR[op.vb]._u8[0] & 0x7; + auto& d = ppu.VR[op.vd]; + Expects(op.vuimm < 4); - CPU.VPR[op.vd]._u8[15] = VA._u8[15] >> sh; + u32 word = ppu.VR[op.vb]._u32[3 - op.vuimm]; + + for (uint w = 0; w < 4; w++) + { + d._u32[w] = word; + } +} + +void ppu_interpreter::VSR(PPUThread& ppu, ppu_opcode_t op) +{ + auto& d = ppu.VR[op.vd]; + v128 VA = ppu.VR[op.va]; + u8 sh = ppu.VR[op.vb]._u8[0] & 0x7; + + d._u8[15] = VA._u8[15] >> sh; for (uint b = 14; ~b; b--) { - CPU.VPR[op.vd]._u8[b] = (VA._u8[b] >> sh) | (VA._u8[b + 1] << (8 - sh)); + d._u8[b] = (VA._u8[b] >> sh) | (VA._u8[b + 1] << (8 - sh)); } } -void ppu_interpreter::VSRAB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSRAB(PPUThread& ppu, ppu_opcode_t op) { - for (uint b = 0; b < 16; b++) + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + + for (uint i = 0; i < 16; i++) { - CPU.VPR[op.vd]._s8[b] = CPU.VPR[op.va]._s8[b] >> (CPU.VPR[op.vb]._u8[b] & 0x7); + d._s8[i] = a._s8[i] >> (b._u8[i] & 0x7); } } -void ppu_interpreter::VSRAH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSRAH(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint h = 0; h < 8; h++) { - CPU.VPR[op.vd]._s16[h] = CPU.VPR[op.va]._s16[h] >> (CPU.VPR[op.vb]._u16[h] & 0xf); + d._s16[h] = a._s16[h] >> (b._u16[h] & 0xf); } } -void ppu_interpreter::VSRAW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSRAW(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - CPU.VPR[op.vd]._s32[w] = CPU.VPR[op.va]._s32[w] >> (CPU.VPR[op.vb]._u32[w] & 0x1f); + d._s32[w] = a._s32[w] >> (b._u32[w] & 0x1f); } } -void ppu_interpreter::VSRB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSRB(PPUThread& ppu, ppu_opcode_t op) { - for (uint b = 0; b < 16; b++) + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + + for (uint i = 0; i < 16; i++) { - CPU.VPR[op.vd]._u8[b] = CPU.VPR[op.va]._u8[b] >> (CPU.VPR[op.vb]._u8[b] & 0x7); + d._u8[i] = a._u8[i] >> (b._u8[i] & 0x7); } } -void ppu_interpreter::VSRH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSRH(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint h = 0; h < 8; h++) { - CPU.VPR[op.vd]._u16[h] = CPU.VPR[op.va]._u16[h] >> (CPU.VPR[op.vb]._u16[h] & 0xf); + d._u16[h] = a._u16[h] >> (b._u16[h] & 0xf); } } -void ppu_interpreter::VSRO(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSRO(PPUThread& ppu, ppu_opcode_t op) { - v128 VA = CPU.VPR[op.va]; - u8 nShift = (CPU.VPR[op.vb]._u8[0] >> 3) & 0xf; + auto& d = ppu.VR[op.vd]; + v128 VA = ppu.VR[op.va]; + u8 nShift = (ppu.VR[op.vb]._u8[0] >> 3) & 0xf; - CPU.VPR[op.vd].clear(); + d.clear(); for (u8 b = 0; b < 16 - nShift; b++) { - CPU.VPR[op.vd]._u8[b] = VA._u8[b + nShift]; + d._u8[b] = VA._u8[b + nShift]; } } -void ppu_interpreter::VSRW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSRW(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - CPU.VPR[op.vd]._u32[w] = CPU.VPR[op.va]._u32[w] >> (CPU.VPR[op.vb]._u32[w] & 0x1f); + d._u32[w] = a._u32[w] >> (b._u32[w] & 0x1f); } } -void ppu_interpreter::VSUBCUW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBCUW(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - CPU.VPR[op.vd]._u32[w] = CPU.VPR[op.va]._u32[w] < CPU.VPR[op.vb]._u32[w] ? 0 : 1; + d._u32[w] = a._u32[w] < b._u32[w] ? 0 : 1; } } -void ppu_interpreter::VSUBFP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBFP(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::subfs(CPU.VPR[op.va], CPU.VPR[op.vb]); + ppu.VR[op.vd] = v128::subfs(ppu.VR[op.va], ppu.VR[op.vb]); } -void ppu_interpreter::VSUBSBS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBSBS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_subs_epi8(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_subs_epi8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VSUBSHS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBSHS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_subs_epi16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_subs_epi16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VSUBSWS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBSWS(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - s64 result = (s64)CPU.VPR[op.va]._s32[w] - (s64)CPU.VPR[op.vb]._s32[w]; + s64 result = (s64)a._s32[w] - (s64)b._s32[w]; if (result < INT32_MIN) { - CPU.VPR[op.vd]._s32[w] = (s32)INT32_MIN; + d._s32[w] = (s32)INT32_MIN; } else if (result > INT32_MAX) { - CPU.VPR[op.vd]._s32[w] = (s32)INT32_MAX; + d._s32[w] = (s32)INT32_MAX; } else - CPU.VPR[op.vd]._s32[w] = (s32)result; + d._s32[w] = (s32)result; } } -void ppu_interpreter::VSUBUBM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBUBM(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::sub8(CPU.VPR[op.va], CPU.VPR[op.vb]); + ppu.VR[op.vd] = v128::sub8(ppu.VR[op.va], ppu.VR[op.vb]); } -void ppu_interpreter::VSUBUBS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBUBS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_subs_epu8(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_subs_epu8(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VSUBUHM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBUHM(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::sub16(CPU.VPR[op.va], CPU.VPR[op.vb]); + ppu.VR[op.vd] = v128::sub16(ppu.VR[op.va], ppu.VR[op.vb]); } -void ppu_interpreter::VSUBUHS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBUHS(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd].vi = _mm_subs_epu16(CPU.VPR[op.va].vi, CPU.VPR[op.vb].vi); + ppu.VR[op.vd].vi = _mm_subs_epu16(ppu.VR[op.va].vi, ppu.VR[op.vb].vi); } -void ppu_interpreter::VSUBUWM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBUWM(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = v128::sub32(CPU.VPR[op.va], CPU.VPR[op.vb]); + ppu.VR[op.vd] = v128::sub32(ppu.VR[op.va], ppu.VR[op.vb]); } -void ppu_interpreter::VSUBUWS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUBUWS(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - s64 result = (s64)CPU.VPR[op.va]._u32[w] - (s64)CPU.VPR[op.vb]._u32[w]; + s64 result = (s64)a._u32[w] - (s64)b._u32[w]; if (result < 0) { - CPU.VPR[op.vd]._u32[w] = 0; + d._u32[w] = 0; } else - CPU.VPR[op.vd]._u32[w] = (u32)result; + d._u32[w] = (u32)result; } } -void ppu_interpreter::VSUMSWS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUMSWS(PPUThread& ppu, ppu_opcode_t op) { - s64 sum = CPU.VPR[op.vb]._s32[0]; + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + + s64 sum = b._s32[0]; for (uint w = 0; w < 4; w++) { - sum += CPU.VPR[op.va]._s32[w]; + sum += a._s32[w]; } - CPU.VPR[op.vd].clear(); + d.clear(); if (sum > INT32_MAX) { - CPU.VPR[op.vd]._s32[0] = (s32)INT32_MAX; + d._s32[0] = (s32)INT32_MAX; } else if (sum < INT32_MIN) { - CPU.VPR[op.vd]._s32[0] = (s32)INT32_MIN; + d._s32[0] = (s32)INT32_MIN; } else - CPU.VPR[op.vd]._s32[0] = (s32)sum; + d._s32[0] = (s32)sum; } -void ppu_interpreter::VSUM2SWS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUM2SWS(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint n = 0; n < 2; n++) { - s64 sum = (s64)CPU.VPR[op.va]._s32[n * 2] + CPU.VPR[op.va]._s32[n * 2 + 1] + CPU.VPR[op.vb]._s32[n * 2]; + s64 sum = (s64)a._s32[n * 2] + a._s32[n * 2 + 1] + b._s32[n * 2]; if (sum > INT32_MAX) { - CPU.VPR[op.vd]._s32[n * 2] = (s32)INT32_MAX; + d._s32[n * 2] = (s32)INT32_MAX; } else if (sum < INT32_MIN) { - CPU.VPR[op.vd]._s32[n * 2] = (s32)INT32_MIN; + d._s32[n * 2] = (s32)INT32_MIN; } else - CPU.VPR[op.vd]._s32[n * 2] = (s32)sum; + d._s32[n * 2] = (s32)sum; } - CPU.VPR[op.vd]._s32[1] = 0; - CPU.VPR[op.vd]._s32[3] = 0; + d._s32[1] = 0; + d._s32[3] = 0; } -void ppu_interpreter::VSUM4SBS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUM4SBS(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - s64 sum = CPU.VPR[op.vb]._s32[w]; + s64 sum = b._s32[w]; for (uint b = 0; b < 4; b++) { - sum += CPU.VPR[op.va]._s8[w * 4 + b]; + sum += a._s8[w * 4 + b]; } if (sum > INT32_MAX) { - CPU.VPR[op.vd]._s32[w] = (s32)INT32_MAX; + d._s32[w] = (s32)INT32_MAX; } else if (sum < INT32_MIN) { - CPU.VPR[op.vd]._s32[w] = (s32)INT32_MIN; + d._s32[w] = (s32)INT32_MIN; } else - CPU.VPR[op.vd]._s32[w] = (s32)sum; + d._s32[w] = (s32)sum; } } -void ppu_interpreter::VSUM4SHS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUM4SHS(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - s64 sum = CPU.VPR[op.vb]._s32[w]; + s64 sum = b._s32[w]; for (uint h = 0; h < 2; h++) { - sum += CPU.VPR[op.va]._s16[w * 2 + h]; + sum += a._s16[w * 2 + h]; } if (sum > INT32_MAX) { - CPU.VPR[op.vd]._s32[w] = (s32)INT32_MAX; + d._s32[w] = (s32)INT32_MAX; } else if (sum < INT32_MIN) { - CPU.VPR[op.vd]._s32[w] = (s32)INT32_MIN; + d._s32[w] = (s32)INT32_MIN; } else - CPU.VPR[op.vd]._s32[w] = (s32)sum; + d._s32[w] = (s32)sum; } } -void ppu_interpreter::VSUM4UBS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VSUM4UBS(PPUThread& ppu, ppu_opcode_t op) { + auto& d = ppu.VR[op.vd]; + const auto& a = ppu.VR[op.va]; + const auto& b = ppu.VR[op.vb]; + for (uint w = 0; w < 4; w++) { - u64 sum = CPU.VPR[op.vb]._u32[w]; + u64 sum = b._u32[w]; for (uint b = 0; b < 4; b++) { - sum += CPU.VPR[op.va]._u8[w * 4 + b]; + sum += a._u8[w * 4 + b]; } if (sum > UINT32_MAX) { - CPU.VPR[op.vd]._u32[w] = (u32)UINT32_MAX; + d._u32[w] = (u32)UINT32_MAX; } else - CPU.VPR[op.vd]._u32[w] = (u32)sum; + d._u32[w] = (u32)sum; } } -void ppu_interpreter::VUPKHPX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VUPKHPX(PPUThread& ppu, ppu_opcode_t op) { - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VB = ppu.VR[op.vb]; for (uint w = 0; w < 4; w++) { - CPU.VPR[op.vd]._s8[w * 4 + 3] = VB._s8[8 + w * 2 + 1] >> 7; // signed shift sign extends - CPU.VPR[op.vd]._u8[w * 4 + 2] = (VB._u8[8 + w * 2 + 1] >> 2) & 0x1f; - CPU.VPR[op.vd]._u8[w * 4 + 1] = ((VB._u8[8 + w * 2 + 1] & 0x3) << 3) | ((VB._u8[8 + w * 2 + 0] >> 5) & 0x7); - CPU.VPR[op.vd]._u8[w * 4 + 0] = VB._u8[8 + w * 2 + 0] & 0x1f; + d._s8[w * 4 + 3] = VB._s8[8 + w * 2 + 1] >> 7; // signed shift sign extends + d._u8[w * 4 + 2] = (VB._u8[8 + w * 2 + 1] >> 2) & 0x1f; + d._u8[w * 4 + 1] = ((VB._u8[8 + w * 2 + 1] & 0x3) << 3) | ((VB._u8[8 + w * 2 + 0] >> 5) & 0x7); + d._u8[w * 4 + 0] = VB._u8[8 + w * 2 + 0] & 0x1f; } } -void ppu_interpreter::VUPKHSB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VUPKHSB(PPUThread& ppu, ppu_opcode_t op) { - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VB = ppu.VR[op.vb]; for (uint h = 0; h < 8; h++) { - CPU.VPR[op.vd]._s16[h] = VB._s8[8 + h]; + d._s16[h] = VB._s8[8 + h]; } } -void ppu_interpreter::VUPKHSH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VUPKHSH(PPUThread& ppu, ppu_opcode_t op) { - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VB = ppu.VR[op.vb]; for (uint w = 0; w < 4; w++) { - CPU.VPR[op.vd]._s32[w] = VB._s16[4 + w]; + d._s32[w] = VB._s16[4 + w]; } } -void ppu_interpreter::VUPKLPX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VUPKLPX(PPUThread& ppu, ppu_opcode_t op) { - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VB = ppu.VR[op.vb]; for (uint w = 0; w < 4; w++) { - CPU.VPR[op.vd]._s8[w * 4 + 3] = VB._s8[w * 2 + 1] >> 7; // signed shift sign extends - CPU.VPR[op.vd]._u8[w * 4 + 2] = (VB._u8[w * 2 + 1] >> 2) & 0x1f; - CPU.VPR[op.vd]._u8[w * 4 + 1] = ((VB._u8[w * 2 + 1] & 0x3) << 3) | ((VB._u8[w * 2 + 0] >> 5) & 0x7); - CPU.VPR[op.vd]._u8[w * 4 + 0] = VB._u8[w * 2 + 0] & 0x1f; + d._s8[w * 4 + 3] = VB._s8[w * 2 + 1] >> 7; // signed shift sign extends + d._u8[w * 4 + 2] = (VB._u8[w * 2 + 1] >> 2) & 0x1f; + d._u8[w * 4 + 1] = ((VB._u8[w * 2 + 1] & 0x3) << 3) | ((VB._u8[w * 2 + 0] >> 5) & 0x7); + d._u8[w * 4 + 0] = VB._u8[w * 2 + 0] & 0x1f; } } -void ppu_interpreter::VUPKLSB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VUPKLSB(PPUThread& ppu, ppu_opcode_t op) { - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VB = ppu.VR[op.vb]; for (uint h = 0; h < 8; h++) { - CPU.VPR[op.vd]._s16[h] = VB._s8[h]; + d._s16[h] = VB._s8[h]; } } -void ppu_interpreter::VUPKLSH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VUPKLSH(PPUThread& ppu, ppu_opcode_t op) { - v128 VB = CPU.VPR[op.vb]; + auto& d = ppu.VR[op.vd]; + v128 VB = ppu.VR[op.vb]; for (uint w = 0; w < 4; w++) { - CPU.VPR[op.vd]._s32[w] = VB._s16[w]; + d._s32[w] = VB._s16[w]; } } -void ppu_interpreter::VXOR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::VXOR(PPUThread& ppu, ppu_opcode_t op) { - CPU.VPR[op.vd] = CPU.VPR[op.va] ^ CPU.VPR[op.vb]; + ppu.VR[op.vd] = ppu.VR[op.va] ^ ppu.VR[op.vb]; } -void ppu_interpreter::MULLI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MULLI(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.rd] = (s64)CPU.GPR[op.ra] * op.simm16; + ppu.GPR[op.rd] = (s64)ppu.GPR[op.ra] * op.simm16; } -void ppu_interpreter::SUBFIC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SUBFIC(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - const u64 IMM = (s64)op.simm16; - CPU.GPR[op.rd] = ~RA + IMM + 1; - - CPU.XER.CA = CPU.IsCarry(~RA, IMM, 1); + const u64 a = ppu.GPR[op.ra]; + const s64 i = op.simm16; + const auto r = add64_flags(~a, i, 1); + ppu.GPR[op.rd] = r.result; + ppu.CA = r.carry; } -void ppu_interpreter::CMPLI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CMPLI(PPUThread& ppu, ppu_opcode_t op) { - CPU.UpdateCRnU(op.l10, op.crfd, CPU.GPR[op.ra], op.uimm16); + if (op.l10) + { + ppu.SetCR(op.crfd, ppu.GPR[op.ra], op.uimm16); + } + else + { + ppu.SetCR(op.crfd, u32(ppu.GPR[op.ra]), op.uimm16); + } } -void ppu_interpreter::CMPI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CMPI(PPUThread& ppu, ppu_opcode_t op) { - CPU.UpdateCRnS(op.l10, op.crfd, CPU.GPR[op.ra], op.simm16); + if (op.l10) + { + ppu.SetCR(op.crfd, ppu.GPR[op.ra], op.simm16); + } + else + { + ppu.SetCR(op.crfd, u32(ppu.GPR[op.ra]), op.simm16); + } } -void ppu_interpreter::ADDIC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ADDIC(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - CPU.GPR[op.rd] = RA + op.simm16; - CPU.XER.CA = CPU.IsCarry(RA, op.simm16); + const s64 a = ppu.GPR[op.ra]; + const s64 i = op.simm16; + const auto r = add64_flags(a, i); + ppu.GPR[op.rd] = r.result; + ppu.CA = r.carry; + if (op.main & 1) ppu.SetCR(0, r.result, 0); } -void ppu_interpreter::ADDIC_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ADDI(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - CPU.GPR[op.rd] = RA + op.simm16; - CPU.XER.CA = CPU.IsCarry(RA, op.simm16); - CPU.UpdateCR0(CPU.GPR[op.rd]); + ppu.GPR[op.rd] = op.ra ? ((s64)ppu.GPR[op.ra] + op.simm16) : op.simm16; } -void ppu_interpreter::ADDI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ADDIS(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.rd] = op.ra ? ((s64)CPU.GPR[op.ra] + op.simm16) : op.simm16; + ppu.GPR[op.rd] = op.ra ? ((s64)ppu.GPR[op.ra] + (op.simm16 << 16)) : (op.simm16 << 16); } -void ppu_interpreter::ADDIS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::BC(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.rd] = op.ra ? ((s64)CPU.GPR[op.ra] + (op.simm16 << 16)) : (op.simm16 << 16); -} + const bool bo0 = (op.bo & 0x10) != 0; + const bool bo1 = (op.bo & 0x08) != 0; + const bool bo2 = (op.bo & 0x04) != 0; + const bool bo3 = (op.bo & 0x02) != 0; -void ppu_interpreter::BC(PPUThread& CPU, ppu_opcode_t op) -{ - const u8 bo0 = (op.bo & 0x10) ? 1 : 0; - const u8 bo1 = (op.bo & 0x08) ? 1 : 0; - const u8 bo2 = (op.bo & 0x04) ? 1 : 0; - const u8 bo3 = (op.bo & 0x02) ? 1 : 0; + ppu.CTR -= (bo2 ^ true); - if (!bo2) --CPU.CTR; - - const u8 ctr_ok = bo2 | ((CPU.CTR != 0) ^ bo3); - const u8 cond_ok = bo0 | (CPU.IsCR(op.bi) ^ (~bo1 & 0x1)); + const bool ctr_ok = bo2 | ((ppu.CTR != 0) ^ bo3); + const bool cond_ok = bo0 | (ppu.CR[op.bi] ^ (bo1 ^ true)); if (ctr_ok && cond_ok) { - const u32 nextLR = CPU.PC + 4; - CPU.PC = PPUOpcodes::branchTarget((op.aa ? 0 : CPU.PC), op.simm16) - 4; - if (op.lk) CPU.LR = nextLR; + const u32 nextLR = ppu.PC + 4; + ppu.PC = ppu_branch_target((op.aa ? 0 : ppu.PC), op.simm16) - 4; + if (op.lk) ppu.LR = nextLR; } } -void ppu_interpreter::HACK(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::HACK(PPUThread& ppu, ppu_opcode_t op) { - execute_ppu_func_by_index(CPU, op.opcode & 0x3ffffff); + ppu_execute_function(ppu, op.opcode & 0x3ffffff); } -void ppu_interpreter::SC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SC(PPUThread& ppu, ppu_opcode_t op) { - switch (op.lev) + switch (u32 lv = op.lev) { - case 0x0: execute_syscall_by_index(CPU, CPU.GPR[11]); break; - case 0x3: CPU.fast_stop(); break; - default: throw EXCEPTION(""); + case 0x0: ppu_execute_syscall(ppu, ppu.GPR[11]); break; + default: throw fmt::exception("SC lv%u", lv); } } -void ppu_interpreter::B(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::B(PPUThread& ppu, ppu_opcode_t op) { - const u32 nextLR = CPU.PC + 4; - CPU.PC = PPUOpcodes::branchTarget(op.aa ? 0 : CPU.PC, op.ll) - 4; - if (op.lk) CPU.LR = nextLR; + const u32 nextLR = ppu.PC + 4; + ppu.PC = ppu_branch_target(op.aa ? 0 : ppu.PC, op.ll) - 4; + if (op.lk) ppu.LR = nextLR; } -void ppu_interpreter::MCRF(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MCRF(PPUThread& ppu, ppu_opcode_t op) { - CPU.SetCR(op.crfd, CPU.GetCR(op.crfs)); + CHECK_SIZE(PPUThread::CR, 32); + reinterpret_cast(ppu.CR)[op.crfd] = reinterpret_cast(ppu.CR)[op.crfs]; } -void ppu_interpreter::BCLR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::BCLR(PPUThread& ppu, ppu_opcode_t op) { - const u8 bo0 = (op.bo & 0x10) ? 1 : 0; - const u8 bo1 = (op.bo & 0x08) ? 1 : 0; - const u8 bo2 = (op.bo & 0x04) ? 1 : 0; - const u8 bo3 = (op.bo & 0x02) ? 1 : 0; + const bool bo0 = (op.bo & 0x10) != 0; + const bool bo1 = (op.bo & 0x08) != 0; + const bool bo2 = (op.bo & 0x04) != 0; + const bool bo3 = (op.bo & 0x02) != 0; - if (!bo2) --CPU.CTR; + ppu.CTR -= (bo2 ^ true); - const u8 ctr_ok = bo2 | ((CPU.CTR != 0) ^ bo3); - const u8 cond_ok = bo0 | (CPU.IsCR(op.bi) ^ (~bo1 & 0x1)); + const bool ctr_ok = bo2 | ((ppu.CTR != 0) ^ bo3); + const bool cond_ok = bo0 | (ppu.CR[op.bi] ^ (bo1 ^ true)); if (ctr_ok && cond_ok) { - const u32 nextLR = CPU.PC + 4; - CPU.PC = PPUOpcodes::branchTarget(0, (u32)CPU.LR) - 4; - if (op.lk) CPU.LR = nextLR; + const u32 nextLR = ppu.PC + 4; + ppu.PC = ppu_branch_target(0, (u32)ppu.LR) - 4; + if (op.lk) ppu.LR = nextLR; } } -void ppu_interpreter::CRNOR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CRNOR(PPUThread& ppu, ppu_opcode_t op) { - const u8 v = 1 ^ (CPU.IsCR(op.crba) | CPU.IsCR(op.crbb)); - CPU.SetCRBit2(op.crbd, v & 0x1); + ppu.CR[op.crbd] = (ppu.CR[op.crba] | ppu.CR[op.crbb]) ^ true; } -void ppu_interpreter::CRANDC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CRANDC(PPUThread& ppu, ppu_opcode_t op) { - const u8 v = CPU.IsCR(op.crba) & (1 ^ CPU.IsCR(op.crbb)); - CPU.SetCRBit2(op.crbd, v & 0x1); + ppu.CR[op.crbd] = ppu.CR[op.crba] & (ppu.CR[op.crbb] ^ true); } -void ppu_interpreter::ISYNC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ISYNC(PPUThread& ppu, ppu_opcode_t op) { _mm_mfence(); } -void ppu_interpreter::CRXOR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CRXOR(PPUThread& ppu, ppu_opcode_t op) { - const u8 v = CPU.IsCR(op.crba) ^ CPU.IsCR(op.crbb); - CPU.SetCRBit2(op.crbd, v & 0x1); + ppu.CR[op.crbd] = ppu.CR[op.crba] ^ ppu.CR[op.crbb]; } -void ppu_interpreter::CRNAND(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CRNAND(PPUThread& ppu, ppu_opcode_t op) { - const u8 v = 1 ^ (CPU.IsCR(op.crba) & CPU.IsCR(op.crbb)); - CPU.SetCRBit2(op.crbd, v & 0x1); + ppu.CR[op.crbd] = (ppu.CR[op.crba] & ppu.CR[op.crbb]) ^ true; } -void ppu_interpreter::CRAND(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CRAND(PPUThread& ppu, ppu_opcode_t op) { - const u8 v = CPU.IsCR(op.crba) & CPU.IsCR(op.crbb); - CPU.SetCRBit2(op.crbd, v & 0x1); + ppu.CR[op.crbd] = ppu.CR[op.crba] & ppu.CR[op.crbb]; } -void ppu_interpreter::CREQV(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CREQV(PPUThread& ppu, ppu_opcode_t op) { - const u8 v = 1 ^ (CPU.IsCR(op.crba) ^ CPU.IsCR(op.crbb)); - CPU.SetCRBit2(op.crbd, v & 0x1); + ppu.CR[op.crbd] = (ppu.CR[op.crba] ^ ppu.CR[op.crbb]) ^ true; } -void ppu_interpreter::CRORC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CRORC(PPUThread& ppu, ppu_opcode_t op) { - const u8 v = CPU.IsCR(op.crba) | (1 ^ CPU.IsCR(op.crbb)); - CPU.SetCRBit2(op.crbd, v & 0x1); + ppu.CR[op.crbd] = ppu.CR[op.crba] | (ppu.CR[op.crbb] ^ true); } -void ppu_interpreter::CROR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CROR(PPUThread& ppu, ppu_opcode_t op) { - const u8 v = CPU.IsCR(op.crba) | CPU.IsCR(op.crbb); - CPU.SetCRBit2(op.crbd, v & 0x1); + ppu.CR[op.crbd] = ppu.CR[op.crba] | ppu.CR[op.crbb]; } -void ppu_interpreter::BCCTR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::BCCTR(PPUThread& ppu, ppu_opcode_t op) { - if (op.bo & 0x10 || CPU.IsCR(op.bi) == ((op.bo & 0x8) != 0)) + if (op.bo & 0x10 || ppu.CR[op.bi] == ((op.bo & 0x8) != 0)) { - const u32 nextLR = CPU.PC + 4; - CPU.PC = PPUOpcodes::branchTarget(0, (u32)CPU.CTR) - 4; - if (op.lk) CPU.LR = nextLR; + const u32 nextLR = ppu.PC + 4; + ppu.PC = ppu_branch_target(0, (u32)ppu.CTR) - 4; + if (op.lk) ppu.LR = nextLR; } } -void ppu_interpreter::RLWIMI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::RLWIMI(PPUThread& ppu, ppu_opcode_t op) { - const u64 mask = rotate_mask[32 + op.mb][32 + op.me]; - CPU.GPR[op.ra] = (CPU.GPR[op.ra] & ~mask) | (rotl32(CPU.GPR[op.rs], op.sh) & mask); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + const u64 mask = ppu_rotate_mask(32 + op.mb32, 32 + op.me32); + ppu.GPR[op.ra] = (ppu.GPR[op.ra] & ~mask) | (dup32(rol32(u32(ppu.GPR[op.rs]), op.sh32)) & mask); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::RLWINM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::RLWINM(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = rotl32(CPU.GPR[op.rs], op.sh) & rotate_mask[32 + op.mb][32 + op.me]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = dup32(rol32(u32(ppu.GPR[op.rs]), op.sh32)) & ppu_rotate_mask(32 + op.mb32, 32 + op.me32); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::RLWNM(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::RLWNM(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = rotl32(CPU.GPR[op.rs], CPU.GPR[op.rb] & 0x1f) & rotate_mask[32 + op.mb][32 + op.me]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = dup32(rol32(u32(ppu.GPR[op.rs]), ppu.GPR[op.rb] & 0x1f)) & ppu_rotate_mask(32 + op.mb32, 32 + op.me32); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::ORI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ORI(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = CPU.GPR[op.rs] | op.uimm16; + ppu.GPR[op.ra] = ppu.GPR[op.rs] | op.uimm16; } -void ppu_interpreter::ORIS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ORIS(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = CPU.GPR[op.rs] | ((u64)op.uimm16 << 16); + ppu.GPR[op.ra] = ppu.GPR[op.rs] | ((u64)op.uimm16 << 16); } -void ppu_interpreter::XORI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::XORI(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = CPU.GPR[op.rs] ^ op.uimm16; + ppu.GPR[op.ra] = ppu.GPR[op.rs] ^ op.uimm16; } -void ppu_interpreter::XORIS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::XORIS(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = CPU.GPR[op.rs] ^ ((u64)op.uimm16 << 16); + ppu.GPR[op.ra] = ppu.GPR[op.rs] ^ ((u64)op.uimm16 << 16); } -void ppu_interpreter::ANDI_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ANDI(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = CPU.GPR[op.rs] & op.uimm16; - CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = ppu.GPR[op.rs] & op.uimm16; + ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::ANDIS_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ANDIS(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = CPU.GPR[op.rs] & ((u64)op.uimm16 << 16); - CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = ppu.GPR[op.rs] & ((u64)op.uimm16 << 16); + ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::RLDICL(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::RLDICL(PPUThread& ppu, ppu_opcode_t op) { - auto sh = (op.shh << 5) | op.shl; - auto mb = (op.mbmeh << 5) | op.mbmel; - - CPU.GPR[op.ra] = rotl64(CPU.GPR[op.rs], sh) & rotate_mask[mb][63]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = rol64(ppu.GPR[op.rs], op.sh64) & ppu_rotate_mask(op.mbe64, 63); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::RLDICR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::RLDICR(PPUThread& ppu, ppu_opcode_t op) { - auto sh = (op.shh << 5) | op.shl; - auto me = (op.mbmeh << 5) | op.mbmel; - - CPU.GPR[op.ra] = rotl64(CPU.GPR[op.rs], sh) & rotate_mask[0][me]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = rol64(ppu.GPR[op.rs], op.sh64) & ppu_rotate_mask(0, op.mbe64); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::RLDIC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::RLDIC(PPUThread& ppu, ppu_opcode_t op) { - auto sh = (op.shh << 5) | op.shl; - auto mb = (op.mbmeh << 5) | op.mbmel; - - CPU.GPR[op.ra] = rotl64(CPU.GPR[op.rs], sh) & rotate_mask[mb][63 - sh]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = rol64(ppu.GPR[op.rs], op.sh64) & ppu_rotate_mask(op.mbe64, op.sh64 ^ 63); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::RLDIMI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::RLDIMI(PPUThread& ppu, ppu_opcode_t op) { - auto sh = (op.shh << 5) | op.shl; - auto mb = (op.mbmeh << 5) | op.mbmel; - - const u64 mask = rotate_mask[mb][63 - sh]; - CPU.GPR[op.ra] = (CPU.GPR[op.ra] & ~mask) | (rotl64(CPU.GPR[op.rs], sh) & mask); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + const u64 mask = ppu_rotate_mask(op.mbe64, op.sh64 ^ 63); + ppu.GPR[op.ra] = (ppu.GPR[op.ra] & ~mask) | (rol64(ppu.GPR[op.rs], op.sh64) & mask); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::RLDC_LR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::RLDCL(PPUThread& ppu, ppu_opcode_t op) { - auto sh = (u32)(CPU.GPR[op.rb] & 0x3F); - auto mbme = (op.mbmeh << 5) | op.mbmel; + ppu.GPR[op.ra] = rol64(ppu.GPR[op.rs], ppu.GPR[op.rb] & 0x3f) & ppu_rotate_mask(op.mbe64, 63); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); +} - if (op.aa) // rldcr +void ppu_interpreter::RLDCR(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.GPR[op.ra] = rol64(ppu.GPR[op.rs], ppu.GPR[op.rb] & 0x3f) & ppu_rotate_mask(0, op.mbe64); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); +} + +void ppu_interpreter::CMP(PPUThread& ppu, ppu_opcode_t op) +{ + if (op.l10) { - CPU.GPR[op.ra] = rotl64(CPU.GPR[op.rs], sh) & rotate_mask[0][mbme]; + ppu.SetCR(op.crfd, ppu.GPR[op.ra], ppu.GPR[op.rb]); } - else // rldcl + else { - CPU.GPR[op.ra] = rotl64(CPU.GPR[op.rs], sh) & rotate_mask[mbme][63]; + ppu.SetCR(op.crfd, u32(ppu.GPR[op.ra]), u32(ppu.GPR[op.rb])); } - - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); } -void ppu_interpreter::CMP(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::TW(PPUThread& ppu, ppu_opcode_t op) { - CPU.UpdateCRnS(op.l10, op.crfd, CPU.GPR[op.ra], CPU.GPR[op.rb]); -} - -void ppu_interpreter::TW(PPUThread& CPU, ppu_opcode_t op) -{ - s32 a = (s32)CPU.GPR[op.ra]; - s32 b = (s32)CPU.GPR[op.rb]; + s32 a = (s32)ppu.GPR[op.ra]; + s32 b = (s32)ppu.GPR[op.rb]; if ((a < b && (op.bo & 0x10)) || (a > b && (op.bo & 0x8)) || @@ -1696,13 +1756,13 @@ void ppu_interpreter::TW(PPUThread& CPU, ppu_opcode_t op) ((u32)a < (u32)b && (op.bo & 0x2)) || ((u32)a >(u32)b && (op.bo & 0x1))) { - throw EXCEPTION(""); + throw std::runtime_error("Trap!" HERE); } } -void ppu_interpreter::LVSL(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LVSL(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; static const u64 lvsl_values[0x10][2] = { @@ -1724,125 +1784,140 @@ void ppu_interpreter::LVSL(PPUThread& CPU, ppu_opcode_t op) { 0x1718191A1B1C1D1E, 0x0F10111213141516 }, }; - CPU.VPR[op.vd]._u64[0] = lvsl_values[addr & 0xf][0]; - CPU.VPR[op.vd]._u64[1] = lvsl_values[addr & 0xf][1]; + ppu.VR[op.vd]._u64[0] = lvsl_values[addr & 0xf][0]; + ppu.VR[op.vd]._u64[1] = lvsl_values[addr & 0xf][1]; } -void ppu_interpreter::LVEBX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LVEBX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - CPU.VPR[op.vd]._u8[15 - (addr & 0xf)] = vm::read8(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.VR[op.vd]._u8[15 - (addr & 0xf)] = vm::read8(vm::cast(addr, HERE)); } -void ppu_interpreter::SUBFC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SUBFC(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - const u64 RB = CPU.GPR[op.rb]; - CPU.GPR[op.rd] = ~RA + RB + 1; - CPU.XER.CA = CPU.IsCarry(~RA, RB, 1); - if (op.oe) CPU.SetOV((~RA >> 63 == RB >> 63) && (~RA >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const u64 RA = ppu.GPR[op.ra]; + const u64 RB = ppu.GPR[op.rb]; + const auto r = add64_flags(~RA, RB, 1); + ppu.GPR[op.rd] = r.result; + ppu.CA = r.carry; + if (op.oe) ppu.SetOV((~RA >> 63 == RB >> 63) && (~RA >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, r.result, 0); } -void ppu_interpreter::MULHDU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MULHDU(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.rd] = UMULH64(CPU.GPR[op.ra], CPU.GPR[op.rb]); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + ppu.GPR[op.rd] = UMULH64(ppu.GPR[op.ra], ppu.GPR[op.rb]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.rd], 0); } -void ppu_interpreter::ADDC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ADDC(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - const u64 RB = CPU.GPR[op.rb]; - CPU.GPR[op.rd] = RA + RB; - CPU.XER.CA = CPU.IsCarry(RA, RB); - if (op.oe) CPU.SetOV((RA >> 63 == RB >> 63) && (RA >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const u64 RA = ppu.GPR[op.ra]; + const u64 RB = ppu.GPR[op.rb]; + const auto r = add64_flags(RA, RB); + ppu.GPR[op.rd] = r.result; + ppu.CA = r.carry; + if (op.oe) ppu.SetOV((RA >> 63 == RB >> 63) && (RA >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, r.result, 0); } -void ppu_interpreter::MULHWU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MULHWU(PPUThread& ppu, ppu_opcode_t op) { - u32 a = (u32)CPU.GPR[op.ra]; - u32 b = (u32)CPU.GPR[op.rb]; - CPU.GPR[op.rd] = ((u64)a * (u64)b) >> 32; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + u32 a = (u32)ppu.GPR[op.ra]; + u32 b = (u32)ppu.GPR[op.rb]; + ppu.GPR[op.rd] = ((u64)a * (u64)b) >> 32; + if (op.rc) ppu.SetCR(0, false, false, false, ppu.SO); } -void ppu_interpreter::MFOCRF(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MFOCRF(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.rd] = CPU.CR.CR; + if (op.l11) + { + // MFOCRF + const u32 n = cntlz32(op.crm) & 7; + const u32 p = n * 4; + const u32 v = ppu.CR[p + 0] << 3 | ppu.CR[p + 1] << 2 | ppu.CR[p + 2] << 1 | ppu.CR[p + 3] << 0; + + ppu.GPR[op.rd] = v << (p ^ 0x1c); + } + else + { + // MFCR + auto* lanes = reinterpret_cast*>(ppu.CR); + const u32 mh = _mm_movemask_epi8(_mm_slli_epi64(lanes[0].value().vi, 7)); + const u32 ml = _mm_movemask_epi8(_mm_slli_epi64(lanes[1].value().vi, 7)); + + ppu.GPR[op.rd] = (mh << 16) | ml; + } } -void ppu_interpreter::LWARX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LWARX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; be_t value; - vm::reservation_acquire(&value, VM_CAST(addr), SIZE_32(value)); + vm::reservation_acquire(&value, vm::cast(addr, HERE), SIZE_32(value)); - CPU.GPR[op.rd] = value; + ppu.GPR[op.rd] = value; } -void ppu_interpreter::LDX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LDX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - CPU.GPR[op.rd] = vm::read64(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::read64(vm::cast(addr, HERE)); } -void ppu_interpreter::LWZX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LWZX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - CPU.GPR[op.rd] = vm::read32(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::read32(vm::cast(addr, HERE)); } -void ppu_interpreter::SLW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SLW(PPUThread& ppu, ppu_opcode_t op) { - u32 n = CPU.GPR[op.rb] & 0x1f; - u32 r = (u32)rotl32((u32)CPU.GPR[op.rs], n); - u32 m = ((u32)CPU.GPR[op.rb] & 0x20) ? 0 : (u32)rotate_mask[32][63 - n]; - - CPU.GPR[op.ra] = r & m; - - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = u32(ppu.GPR[op.rs] << (ppu.GPR[op.rb] & 0x3f)); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::CNTLZW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CNTLZW(PPUThread& ppu, ppu_opcode_t op) { - u32 i; - for (i = 0; i < 32; i++) + ppu.GPR[op.ra] = cntlz32(u32(ppu.GPR[op.rs])); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); +} + +void ppu_interpreter::SLD(PPUThread& ppu, ppu_opcode_t op) +{ + u32 n = ppu.GPR[op.rb] & 0x3f; + u64 r = rol64(ppu.GPR[op.rs], n); + u64 m = (ppu.GPR[op.rb] & 0x40) ? 0 : ppu_rotate_mask(0, 63 - n); + + ppu.GPR[op.ra] = r & m; + + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); +} + +void ppu_interpreter::AND(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.GPR[op.ra] = ppu.GPR[op.rs] & ppu.GPR[op.rb]; + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); +} + +void ppu_interpreter::CMPL(PPUThread& ppu, ppu_opcode_t op) +{ + if (op.l10) { - if (CPU.GPR[op.rs] & (1ULL << (31 - i))) break; + ppu.SetCR(op.crfd, ppu.GPR[op.ra], ppu.GPR[op.rb]); + } + else + { + ppu.SetCR(op.crfd, u32(ppu.GPR[op.ra]), u32(ppu.GPR[op.rb])); } - - CPU.GPR[op.ra] = i; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); } -void ppu_interpreter::SLD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LVSR(PPUThread& ppu, ppu_opcode_t op) { - u32 n = CPU.GPR[op.rb] & 0x3f; - u64 r = rotl64(CPU.GPR[op.rs], n); - u64 m = (CPU.GPR[op.rb] & 0x40) ? 0 : rotate_mask[0][63 - n]; - - CPU.GPR[op.ra] = r & m; - - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); -} - -void ppu_interpreter::AND(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.GPR[op.ra] = CPU.GPR[op.rs] & CPU.GPR[op.rb]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); -} - -void ppu_interpreter::CMPL(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.UpdateCRnU(op.l10, op.crfd, CPU.GPR[op.ra], CPU.GPR[op.rb]); -} - -void ppu_interpreter::LVSR(PPUThread& CPU, ppu_opcode_t op) -{ - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; static const u64 lvsr_values[0x10][2] = { @@ -1864,696 +1939,636 @@ void ppu_interpreter::LVSR(PPUThread& CPU, ppu_opcode_t op) { 0x090A0B0C0D0E0F10, 0x0102030405060708 }, }; - CPU.VPR[op.vd]._u64[0] = lvsr_values[addr & 0xf][0]; - CPU.VPR[op.vd]._u64[1] = lvsr_values[addr & 0xf][1]; + ppu.VR[op.vd]._u64[0] = lvsr_values[addr & 0xf][0]; + ppu.VR[op.vd]._u64[1] = lvsr_values[addr & 0xf][1]; } -void ppu_interpreter::LVEHX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LVEHX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = (op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]) & ~1ULL; - CPU.VPR[op.vd]._u16[7 - ((addr >> 1) & 0x7)] = vm::read16(VM_CAST(addr)); + const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]) & ~1ULL; + ppu.VR[op.vd]._u16[7 - ((addr >> 1) & 0x7)] = vm::read16(vm::cast(addr, HERE)); } -void ppu_interpreter::SUBF(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SUBF(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - const u64 RB = CPU.GPR[op.rb]; - CPU.GPR[op.rd] = RB - RA; - if (op.oe) CPU.SetOV((~RA >> 63 == RB >> 63) && (~RA >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const u64 RA = ppu.GPR[op.ra]; + const u64 RB = ppu.GPR[op.rb]; + ppu.GPR[op.rd] = RB - RA; + if (op.oe) ppu.SetOV((~RA >> 63 == RB >> 63) && (~RA >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.rd], 0); } -void ppu_interpreter::LDUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LDUX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - CPU.GPR[op.rd] = vm::read64(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::read64(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::DCBST(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::DCBST(PPUThread& ppu, ppu_opcode_t op) { } -void ppu_interpreter::LWZUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LWZUX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - CPU.GPR[op.rd] = vm::read32(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::read32(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::CNTLZD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::CNTLZD(PPUThread& ppu, ppu_opcode_t op) { - u32 i; - for (i = 0; i < 64; i++) + ppu.GPR[op.ra] = cntlz64(ppu.GPR[op.rs]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); +} + +void ppu_interpreter::ANDC(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.GPR[op.ra] = ppu.GPR[op.rs] & ~ppu.GPR[op.rb]; + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); +} + +void ppu_interpreter::TD(PPUThread& ppu, ppu_opcode_t op) +{ + const s64 a = ppu.GPR[op.ra], b = ppu.GPR[op.rb]; + const u64 a_ = a, b_ = b; + + if (((op.bo & 0x10) && a < b) || + ((op.bo & 0x8) && a > b) || + ((op.bo & 0x4) && a == b) || + ((op.bo & 0x2) && a_ < b_) || + ((op.bo & 0x1) && a_ > b_)) { - if (CPU.GPR[op.rs] & (1ULL << (63 - i))) break; + throw std::runtime_error("Trap!" HERE); } - - CPU.GPR[op.ra] = i; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); } -void ppu_interpreter::ANDC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LVEWX(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = CPU.GPR[op.rs] & ~CPU.GPR[op.rb]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]) & ~3ULL; + ppu.VR[op.vd]._u32[3 - ((addr >> 2) & 0x3)] = vm::read32(vm::cast(addr, HERE)); } -void ppu_interpreter::TD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MULHD(PPUThread& ppu, ppu_opcode_t op) { - throw EXCEPTION(""); + ppu.GPR[op.rd] = MULH64(ppu.GPR[op.ra], ppu.GPR[op.rb]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.rd], 0); } -void ppu_interpreter::LVEWX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MULHW(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = (op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]) & ~3ULL; - CPU.VPR[op.vd]._u32[3 - ((addr >> 2) & 0x3)] = vm::read32(VM_CAST(addr)); + s32 a = (s32)ppu.GPR[op.ra]; + s32 b = (s32)ppu.GPR[op.rb]; + ppu.GPR[op.rd] = ((s64)a * (s64)b) >> 32; + if (op.rc) ppu.SetCR(0, false, false, false, ppu.SO); } -void ppu_interpreter::MULHD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LDARX(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.rd] = MULH64(CPU.GPR[op.ra], CPU.GPR[op.rb]); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); -} - -void ppu_interpreter::MULHW(PPUThread& CPU, ppu_opcode_t op) -{ - s32 a = (s32)CPU.GPR[op.ra]; - s32 b = (s32)CPU.GPR[op.rb]; - CPU.GPR[op.rd] = ((s64)a * (s64)b) >> 32; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); -} - -void ppu_interpreter::LDARX(PPUThread& CPU, ppu_opcode_t op) -{ - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; be_t value; - vm::reservation_acquire(&value, VM_CAST(addr), SIZE_32(value)); + vm::reservation_acquire(&value, vm::cast(addr, HERE), SIZE_32(value)); - CPU.GPR[op.rd] = value; + ppu.GPR[op.rd] = value; } -void ppu_interpreter::DCBF(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::DCBF(PPUThread& ppu, ppu_opcode_t op) { } -void ppu_interpreter::LBZX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LBZX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - CPU.GPR[op.rd] = vm::read8(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::read8(vm::cast(addr, HERE)); } -void ppu_interpreter::LVX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LVX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = (op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]) & ~0xfull; - CPU.VPR[op.vd] = vm::_ref(VM_CAST(addr)); + const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]) & ~0xfull; + ppu.VR[op.vd] = vm::_ref(vm::cast(addr, HERE)); } -void ppu_interpreter::NEG(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::NEG(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - CPU.GPR[op.rd] = 0 - RA; - if (op.oe) CPU.SetOV((~RA >> 63 == 0) && (~RA >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const u64 RA = ppu.GPR[op.ra]; + ppu.GPR[op.rd] = 0 - RA; + if (op.oe) ppu.SetOV((~RA >> 63 == 0) && (~RA >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.rd], 0); } -void ppu_interpreter::LBZUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LBZUX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - CPU.GPR[op.rd] = vm::read8(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::read8(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::NOR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::NOR(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = ~(CPU.GPR[op.rs] | CPU.GPR[op.rb]); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = ~(ppu.GPR[op.rs] | ppu.GPR[op.rb]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::STVEBX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STVEBX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; const u8 eb = addr & 0xf; - vm::write8(VM_CAST(addr), CPU.VPR[op.vs]._u8[15 - eb]); + vm::write8(vm::cast(addr, HERE), ppu.VR[op.vs]._u8[15 - eb]); } -void ppu_interpreter::SUBFE(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SUBFE(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - const u64 RB = CPU.GPR[op.rb]; - CPU.GPR[op.rd] = ~RA + RB + CPU.XER.CA; - CPU.XER.CA = CPU.IsCarry(~RA, RB, CPU.XER.CA); - if (op.oe) CPU.SetOV((~RA >> 63 == RB >> 63) && (~RA >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const u64 RA = ppu.GPR[op.ra]; + const u64 RB = ppu.GPR[op.rb]; + const auto r = add64_flags(~RA, RB, ppu.CA); + ppu.GPR[op.rd] = r.result; + ppu.CA = r.carry; + if (op.oe) ppu.SetOV((~RA >> 63 == RB >> 63) && (~RA >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, r.result, 0); } -void ppu_interpreter::ADDE(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ADDE(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - const u64 RB = CPU.GPR[op.rb]; - if (CPU.XER.CA) - { - if (RA == ~0ULL) //-1 - { - CPU.GPR[op.rd] = RB; - CPU.XER.CA = 1; - } - else - { - CPU.GPR[op.rd] = RA + 1 + RB; - CPU.XER.CA = CPU.IsCarry(RA + 1, RB); - } - } - else - { - CPU.GPR[op.rd] = RA + RB; - CPU.XER.CA = CPU.IsCarry(RA, RB); - } - if (op.oe) CPU.SetOV((RA >> 63 == RB >> 63) && (RA >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const u64 RA = ppu.GPR[op.ra]; + const u64 RB = ppu.GPR[op.rb]; + const auto r = add64_flags(RA, RB, ppu.CA); + ppu.GPR[op.rd] = r.result; + ppu.CA = r.carry; + if (op.oe) ppu.SetOV((RA >> 63 == RB >> 63) && (RA >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, r.result, 0); } -void ppu_interpreter::MTOCRF(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MTOCRF(PPUThread& ppu, ppu_opcode_t op) { + const u64 s = ppu.GPR[op.rs]; + if (op.l11) { - u32 n = 0, count = 0; - for (u32 i = 0; i<8; ++i) - { - if (op.crm & (1 << i)) - { - n = i; - count++; - } - } + // MTOCRF - if (count == 1) - { - //CR[4*n : 4*n+3] = RS[32+4*n : 32+4*n+3]; - CPU.SetCR(7 - n, (CPU.GPR[op.rs] >> (4 * n)) & 0xf); - } - else - CPU.CR.CR = 0; + const u32 n = cntlz32(op.crm) & 7; + const u32 p = n * 4; + const u64 v = s >> (p ^ 0x1c); + ppu.CR[p + 0] = (v & 8) != 0; + ppu.CR[p + 1] = (v & 4) != 0; + ppu.CR[p + 2] = (v & 2) != 0; + ppu.CR[p + 3] = (v & 1) != 0; } else { - for (u32 i = 0; i<8; ++i) + // MTCRF + + for (u32 i = 0; i < 8; i++) { - if (op.crm & (1 << i)) + const u32 p = i * 4; + const u64 v = s >> (p ^ 0x1c); + + if (op.crm & (128 >> i)) { - CPU.SetCR(7 - i, (CPU.GPR[op.rs] >> (i * 4)) & 0xf); + ppu.CR[p + 0] = (v & 8) != 0; + ppu.CR[p + 1] = (v & 4) != 0; + ppu.CR[p + 2] = (v & 2) != 0; + ppu.CR[p + 3] = (v & 1) != 0; } } } } -void ppu_interpreter::STDX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STDX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - vm::write64(VM_CAST(addr), CPU.GPR[op.rs]); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + vm::write64(vm::cast(addr, HERE), ppu.GPR[op.rs]); } -void ppu_interpreter::STWCX_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STWCX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; - const be_t value = (u32)CPU.GPR[op.rs]; - CPU.SetCR_EQ(0, vm::reservation_update(VM_CAST(addr), &value, SIZE_32(value))); + const be_t value = (u32)ppu.GPR[op.rs]; + ppu.SetCR(0, false, false, vm::reservation_update(vm::cast(addr, HERE), &value, SIZE_32(value)), ppu.SO); } -void ppu_interpreter::STWX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STWX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - vm::write32(VM_CAST(addr), (u32)CPU.GPR[op.rs]); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + vm::write32(vm::cast(addr, HERE), (u32)ppu.GPR[op.rs]); } -void ppu_interpreter::STVEHX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STVEHX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = (op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]) & ~1ULL; + const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]) & ~1ULL; const u8 eb = (addr & 0xf) >> 1; - vm::write16(VM_CAST(addr), CPU.VPR[op.vs]._u16[7 - eb]); + vm::write16(vm::cast(addr, HERE), ppu.VR[op.vs]._u16[7 - eb]); } -void ppu_interpreter::STDUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STDUX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - vm::write64(VM_CAST(addr), CPU.GPR[op.rs]); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + vm::write64(vm::cast(addr, HERE), ppu.GPR[op.rs]); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::STWUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STWUX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - vm::write32(VM_CAST(addr), (u32)CPU.GPR[op.rs]); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + vm::write32(vm::cast(addr, HERE), (u32)ppu.GPR[op.rs]); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::STVEWX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STVEWX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = (op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]) & ~3ULL; + const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]) & ~3ULL; const u8 eb = (addr & 0xf) >> 2; - vm::write32(VM_CAST(addr), CPU.VPR[op.vs]._u32[3 - eb]); + vm::write32(vm::cast(addr, HERE), ppu.VR[op.vs]._u32[3 - eb]); } -void ppu_interpreter::SUBFZE(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SUBFZE(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - CPU.GPR[op.rd] = ~RA + CPU.XER.CA; - CPU.XER.CA = CPU.IsCarry(~RA, CPU.XER.CA); - if (op.oe) CPU.SetOV((~RA >> 63 == 0) && (~RA >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const u64 RA = ppu.GPR[op.ra]; + const auto r = add64_flags(~RA, 0, ppu.CA); + ppu.GPR[op.rd] = r.result; + ppu.CA = r.carry; + if (op.oe) ppu.SetOV((~RA >> 63 == 0) && (~RA >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, r.result, 0); } -void ppu_interpreter::ADDZE(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ADDZE(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - CPU.GPR[op.rd] = RA + CPU.XER.CA; - CPU.XER.CA = CPU.IsCarry(RA, CPU.XER.CA); - if (op.oe) CPU.SetOV((RA >> 63 == 0) && (RA >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const u64 RA = ppu.GPR[op.ra]; + const auto r = add64_flags(RA, 0, ppu.CA); + ppu.GPR[op.rd] = r.result; + ppu.CA = r.carry; + if (op.oe) ppu.SetOV((RA >> 63 == 0) && (RA >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, r.result, 0); } -void ppu_interpreter::STDCX_(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STDCX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; - const be_t value = CPU.GPR[op.rs]; - CPU.SetCR_EQ(0, vm::reservation_update(VM_CAST(addr), &value, SIZE_32(value))); + const be_t value = ppu.GPR[op.rs]; + ppu.SetCR(0, false, false, vm::reservation_update(vm::cast(addr, HERE), &value, SIZE_32(value)), ppu.SO); } -void ppu_interpreter::STBX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STBX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - vm::write8(VM_CAST(addr), (u8)CPU.GPR[op.rs]); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + vm::write8(vm::cast(addr, HERE), (u8)ppu.GPR[op.rs]); } -void ppu_interpreter::STVX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STVX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = (op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]) & ~0xfull; - vm::_ref(VM_CAST(addr)) = CPU.VPR[op.vs]; + const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]) & ~0xfull; + vm::_ref(vm::cast(addr, HERE)) = ppu.VR[op.vs]; } -void ppu_interpreter::MULLD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MULLD(PPUThread& ppu, ppu_opcode_t op) { - const s64 RA = CPU.GPR[op.ra]; - const s64 RB = CPU.GPR[op.rb]; - CPU.GPR[op.rd] = (s64)(RA * RB); + const s64 RA = ppu.GPR[op.ra]; + const s64 RB = ppu.GPR[op.rb]; + ppu.GPR[op.rd] = (s64)(RA * RB); if (op.oe) { const s64 high = MULH64(RA, RB); - CPU.SetOV(high != s64(CPU.GPR[op.rd]) >> 63); + ppu.SetOV(high != s64(ppu.GPR[op.rd]) >> 63); } - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.rd], 0); } -void ppu_interpreter::SUBFME(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SUBFME(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - CPU.GPR[op.rd] = ~RA + CPU.XER.CA + ~0ULL; - CPU.XER.CA = CPU.IsCarry(~RA, CPU.XER.CA, ~0ULL); - if (op.oe) CPU.SetOV((~RA >> 63 == 1) && (~RA >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const u64 RA = ppu.GPR[op.ra]; + const auto r = add64_flags(~RA, ~0ull, ppu.CA); + ppu.GPR[op.rd] = r.result; + ppu.CA = r.carry; + if (op.oe) ppu.SetOV((~RA >> 63 == 1) && (~RA >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, r.result, 0); } -void ppu_interpreter::ADDME(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ADDME(PPUThread& ppu, ppu_opcode_t op) { - const s64 RA = CPU.GPR[op.ra]; - CPU.GPR[op.rd] = RA + CPU.XER.CA - 1; - CPU.XER.CA |= RA != 0; - - if (op.oe) CPU.SetOV((u64(RA) >> 63 == 1) && (u64(RA) >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const s64 RA = ppu.GPR[op.ra]; + const auto r = add64_flags(RA, ~0ull, ppu.CA); + ppu.GPR[op.rd] = r.result; + ppu.CA = r.carry; + if (op.oe) ppu.SetOV((u64(RA) >> 63 == 1) && (u64(RA) >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, r.result, 0); } -void ppu_interpreter::MULLW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MULLW(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.rd] = (s64)((s64)(s32)CPU.GPR[op.ra] * (s64)(s32)CPU.GPR[op.rb]); - if (op.oe) CPU.SetOV(s64(CPU.GPR[op.rd]) < s64(-1) << 31 || s64(CPU.GPR[op.rd]) >= s64(1) << 31); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + ppu.GPR[op.rd] = (s64)((s64)(s32)ppu.GPR[op.ra] * (s64)(s32)ppu.GPR[op.rb]); + if (op.oe) ppu.SetOV(s64(ppu.GPR[op.rd]) < s64(-1) << 31 || s64(ppu.GPR[op.rd]) >= s64(1) << 31); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::DCBTST(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::DCBTST(PPUThread& ppu, ppu_opcode_t op) { } -void ppu_interpreter::STBUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STBUX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - vm::write8(VM_CAST(addr), (u8)CPU.GPR[op.rs]); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + vm::write8(vm::cast(addr, HERE), (u8)ppu.GPR[op.rs]); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::ADD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ADD(PPUThread& ppu, ppu_opcode_t op) { - const u64 RA = CPU.GPR[op.ra]; - const u64 RB = CPU.GPR[op.rb]; - CPU.GPR[op.rd] = RA + RB; - if (op.oe) CPU.SetOV((RA >> 63 == RB >> 63) && (RA >> 63 != CPU.GPR[op.rd] >> 63)); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + const u64 RA = ppu.GPR[op.ra]; + const u64 RB = ppu.GPR[op.rb]; + ppu.GPR[op.rd] = RA + RB; + if (op.oe) ppu.SetOV((RA >> 63 == RB >> 63) && (RA >> 63 != ppu.GPR[op.rd] >> 63)); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.rd], 0); } -void ppu_interpreter::DCBT(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::DCBT(PPUThread& ppu, ppu_opcode_t op) { } -void ppu_interpreter::LHZX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LHZX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - CPU.GPR[op.rd] = vm::read16(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::read16(vm::cast(addr, HERE)); } -void ppu_interpreter::EQV(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::EQV(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = ~(CPU.GPR[op.rs] ^ CPU.GPR[op.rb]); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = ~(ppu.GPR[op.rs] ^ ppu.GPR[op.rb]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::ECIWX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ECIWX(PPUThread& ppu, ppu_opcode_t op) { - throw EXCEPTION(""); + throw std::runtime_error("ECIWX" HERE); } -void ppu_interpreter::LHZUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LHZUX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - CPU.GPR[op.rd] = vm::read16(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::read16(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::XOR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::XOR(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = CPU.GPR[op.rs] ^ CPU.GPR[op.rb]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = ppu.GPR[op.rs] ^ ppu.GPR[op.rb]; + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::MFSPR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MFSPR(PPUThread& ppu, ppu_opcode_t op) { const u32 n = (op.spr >> 5) | ((op.spr & 0x1f) << 5); switch (n) { - case 0x001: CPU.GPR[op.rd] = CPU.XER.XER; return; - case 0x008: CPU.GPR[op.rd] = CPU.LR; return; - case 0x009: CPU.GPR[op.rd] = CPU.CTR; return; - case 0x100: CPU.GPR[op.rd] = CPU.VRSAVE; return; - case 0x103: CPU.GPR[op.rd] = CPU.SPRG[3]; return; + case 0x001: ppu.GPR[op.rd] = u32{ ppu.SO } << 31 | ppu.OV << 30 | ppu.CA << 29 | ppu.XCNT; return; + case 0x008: ppu.GPR[op.rd] = ppu.LR; return; + case 0x009: ppu.GPR[op.rd] = ppu.CTR; return; + case 0x100: ppu.GPR[op.rd] = ppu.VRSAVE; return; - case 0x10C: CPU.TB = get_timebased_time(); CPU.GPR[op.rd] = CPU.TB; return; - case 0x10D: CPU.TB = get_timebased_time(); CPU.GPR[op.rd] = CPU.TB >> 32; return; - - case 0x110: - case 0x111: - case 0x112: - case 0x113: - case 0x114: - case 0x115: - case 0x116: - case 0x117: CPU.GPR[op.rd] = CPU.SPRG[n - 0x110]; return; + case 0x10C: ppu.GPR[op.rd] = get_timebased_time() & 0xffffffff; return; + case 0x10D: ppu.GPR[op.rd] = get_timebased_time() >> 32; return; } - throw EXCEPTION(""); + throw fmt::exception("MFSPR 0x%x" HERE, n); } -void ppu_interpreter::LWAX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LWAX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - CPU.GPR[op.rd] = (s64)(s32)vm::read32(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = (s64)(s32)vm::read32(vm::cast(addr, HERE)); } -void ppu_interpreter::DST(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::DST(PPUThread& ppu, ppu_opcode_t op) { } -void ppu_interpreter::LHAX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LHAX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - CPU.GPR[op.rd] = (s64)(s16)vm::read16(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = (s64)(s16)vm::read16(vm::cast(addr, HERE)); } -void ppu_interpreter::LVXL(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LVXL(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = (op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]) & ~0xfull; - CPU.VPR[op.vd] = vm::_ref(VM_CAST(addr)); + const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]) & ~0xfull; + ppu.VR[op.vd] = vm::_ref(vm::cast(addr, HERE)); } -void ppu_interpreter::MFTB(PPUThread& CPU, ppu_opcode_t op) -{ - const u32 n = (op.spr >> 5) | ((op.spr & 0x1f) << 5); - - CPU.TB = get_timebased_time(); - switch (n) - { - case 0x10C: CPU.GPR[op.rd] = CPU.TB; break; - case 0x10D: CPU.GPR[op.rd] = CPU.TB >> 32; break; - default: throw EXCEPTION(""); - } -} - -void ppu_interpreter::LWAUX(PPUThread& CPU, ppu_opcode_t op) -{ - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - CPU.GPR[op.rd] = (s64)(s32)vm::read32(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; -} - -void ppu_interpreter::DSTST(PPUThread& CPU, ppu_opcode_t op) -{ -} - -void ppu_interpreter::LHAUX(PPUThread& CPU, ppu_opcode_t op) -{ - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - CPU.GPR[op.rd] = (s64)(s16)vm::read16(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; -} - -void ppu_interpreter::STHX(PPUThread& CPU, ppu_opcode_t op) -{ - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - vm::write16(VM_CAST(addr), (u16)CPU.GPR[op.rs]); -} - -void ppu_interpreter::ORC(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.GPR[op.ra] = CPU.GPR[op.rs] | ~CPU.GPR[op.rb]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); -} - -void ppu_interpreter::ECOWX(PPUThread& CPU, ppu_opcode_t op) -{ - throw EXCEPTION(""); -} - -void ppu_interpreter::STHUX(PPUThread& CPU, ppu_opcode_t op) -{ - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - vm::write16(VM_CAST(addr), (u16)CPU.GPR[op.rs]); - CPU.GPR[op.ra] = addr; -} - -void ppu_interpreter::OR(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.GPR[op.ra] = CPU.GPR[op.rs] | CPU.GPR[op.rb]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); -} - -void ppu_interpreter::DIVDU(PPUThread& CPU, ppu_opcode_t op) -{ - const u64 RA = CPU.GPR[op.ra]; - const u64 RB = CPU.GPR[op.rb]; - - if (RB == 0) - { - if (op.oe) CPU.SetOV(true); - CPU.GPR[op.rd] = 0; - } - else - { - if (op.oe) CPU.SetOV(false); - CPU.GPR[op.rd] = RA / RB; - } - - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); -} - -void ppu_interpreter::DIVWU(PPUThread& CPU, ppu_opcode_t op) -{ - const u32 RA = (u32)CPU.GPR[op.ra]; - const u32 RB = (u32)CPU.GPR[op.rb]; - - if (RB == 0) - { - if (op.oe) CPU.SetOV(true); - CPU.GPR[op.rd] = 0; - } - else - { - if (op.oe) CPU.SetOV(false); - CPU.GPR[op.rd] = RA / RB; - } - - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); -} - -void ppu_interpreter::MTSPR(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MFTB(PPUThread& ppu, ppu_opcode_t op) { const u32 n = (op.spr >> 5) | ((op.spr & 0x1f) << 5); switch (n) { - case 0x001: CPU.XER.XER = CPU.GPR[op.rs]; return; - case 0x008: CPU.LR = CPU.GPR[op.rs]; return; - case 0x009: CPU.CTR = CPU.GPR[op.rs]; return; - case 0x100: CPU.VRSAVE = (u32)CPU.GPR[op.rs]; return; - - case 0x110: - case 0x111: - case 0x112: - case 0x113: - case 0x114: - case 0x115: - case 0x116: - case 0x117: CPU.SPRG[n - 0x110] = CPU.GPR[op.rs]; return; + case 0x10C: ppu.GPR[op.rd] = get_timebased_time() & 0xffffffff; break; + case 0x10D: ppu.GPR[op.rd] = get_timebased_time() >> 32; break; + default: throw fmt::exception("MFSPR 0x%x" HERE, n); } - - throw EXCEPTION(""); } -void ppu_interpreter::DCBI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LWAUX(PPUThread& ppu, ppu_opcode_t op) +{ + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = (s64)(s32)vm::read32(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; +} + +void ppu_interpreter::DSTST(PPUThread& ppu, ppu_opcode_t op) { } -void ppu_interpreter::NAND(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LHAUX(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = ~(CPU.GPR[op.rs] & CPU.GPR[op.rb]); - - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = (s64)(s16)vm::read16(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::STVXL(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STHX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = (op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]) & ~0xfull; - vm::_ref(VM_CAST(addr)) = CPU.VPR[op.vs]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + vm::write16(vm::cast(addr, HERE), (u16)ppu.GPR[op.rs]); } -void ppu_interpreter::DIVD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ORC(PPUThread& ppu, ppu_opcode_t op) { - const s64 RA = CPU.GPR[op.ra]; - const s64 RB = CPU.GPR[op.rb]; + ppu.GPR[op.ra] = ppu.GPR[op.rs] | ~ppu.GPR[op.rb]; + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); +} - if (RB == 0 || ((u64)RA == (1ULL << 63) && RB == -1)) +void ppu_interpreter::ECOWX(PPUThread& ppu, ppu_opcode_t op) +{ + throw std::runtime_error("ECOWX" HERE); +} + +void ppu_interpreter::STHUX(PPUThread& ppu, ppu_opcode_t op) +{ + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + vm::write16(vm::cast(addr, HERE), (u16)ppu.GPR[op.rs]); + ppu.GPR[op.ra] = addr; +} + +void ppu_interpreter::OR(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.GPR[op.ra] = ppu.GPR[op.rs] | ppu.GPR[op.rb]; + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); +} + +void ppu_interpreter::DIVDU(PPUThread& ppu, ppu_opcode_t op) +{ + const u64 RA = ppu.GPR[op.ra]; + const u64 RB = ppu.GPR[op.rb]; + ppu.GPR[op.rd] = RB == 0 ? 0 : RA / RB; + if (op.oe) ppu.SetOV(RB == 0); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.rd], 0); +} + +void ppu_interpreter::DIVWU(PPUThread& ppu, ppu_opcode_t op) +{ + const u32 RA = (u32)ppu.GPR[op.ra]; + const u32 RB = (u32)ppu.GPR[op.rb]; + ppu.GPR[op.rd] = RB == 0 ? 0 : RA / RB; + if (op.oe) ppu.SetOV(RB == 0); + if (op.rc) ppu.SetCR(0, false, false, false, ppu.SO); +} + +void ppu_interpreter::MTSPR(PPUThread& ppu, ppu_opcode_t op) +{ + const u32 n = (op.spr >> 5) | ((op.spr & 0x1f) << 5); + + switch (n) { - if (op.oe) CPU.SetOV(true); - CPU.GPR[op.rd] = /*(((u64)RA & (1ULL << 63)) && RB == 0) ? -1 :*/ 0; - } - else + case 0x001: { - if (op.oe) CPU.SetOV(false); - CPU.GPR[op.rd] = RA / RB; + const u64 value = ppu.GPR[op.rs]; + ppu.SO = (value & 0x80000000) != 0; + ppu.OV = (value & 0x40000000) != 0; + ppu.CA = (value & 0x20000000) != 0; + ppu.XCNT = value & 0x7f; + return; + } + case 0x008: ppu.LR = ppu.GPR[op.rs]; return; + case 0x009: ppu.CTR = ppu.GPR[op.rs]; return; + case 0x100: ppu.VRSAVE = (u32)ppu.GPR[op.rs]; return; } - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); + throw fmt::exception("MTSPR 0x%x" HERE, n); } -void ppu_interpreter::DIVW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::DCBI(PPUThread& ppu, ppu_opcode_t op) { - const s32 RA = (s32)CPU.GPR[op.ra]; - const s32 RB = (s32)CPU.GPR[op.rb]; - - if (RB == 0 || ((u32)RA == (1 << 31) && RB == -1)) - { - if (op.oe) CPU.SetOV(true); - CPU.GPR[op.rd] = /*(((u32)RA & (1 << 31)) && RB == 0) ? -1 :*/ 0; - } - else - { - if (op.oe) CPU.SetOV(false); - CPU.GPR[op.rd] = (u32)(RA / RB); - } - - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.rd]); } -void ppu_interpreter::LVLX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::NAND(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + ppu.GPR[op.ra] = ~(ppu.GPR[op.rs] & ppu.GPR[op.rb]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); +} + +void ppu_interpreter::STVXL(PPUThread& ppu, ppu_opcode_t op) +{ + const u64 addr = (op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]) & ~0xfull; + vm::_ref(vm::cast(addr, HERE)) = ppu.VR[op.vs]; +} + +void ppu_interpreter::DIVD(PPUThread& ppu, ppu_opcode_t op) +{ + const s64 RA = ppu.GPR[op.ra]; + const s64 RB = ppu.GPR[op.rb]; + const bool o = RB == 0 || ((u64)RA == (1ULL << 63) && RB == -1); + ppu.GPR[op.rd] = o ? 0 : RA / RB; + if (op.oe) ppu.SetOV(o); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.rd], 0); +} + +void ppu_interpreter::DIVW(PPUThread& ppu, ppu_opcode_t op) +{ + const s32 RA = (s32)ppu.GPR[op.ra]; + const s32 RB = (s32)ppu.GPR[op.rb]; + const bool o = RB == 0 || ((u32)RA == (1 << 31) && RB == -1); + ppu.GPR[op.rd] = o ? 0 : u32(RA / RB); + if (op.oe) ppu.SetOV(o); + if (op.rc) ppu.SetCR(0, false, false, false, ppu.SO); +} + +void ppu_interpreter::LVLX(PPUThread& ppu, ppu_opcode_t op) +{ + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; const u32 eb = addr & 0xf; - CPU.VPR[op.vd].clear(); - for (u32 i = 0; i < 16u - eb; ++i) CPU.VPR[op.vd]._u8[15 - i] = vm::read8(VM_CAST(addr + i)); + ppu.VR[op.vd].clear(); + for (u32 i = 0; i < 16u - eb; ++i) ppu.VR[op.vd]._u8[15 - i] = vm::read8(vm::cast(addr + i, HERE)); } -void ppu_interpreter::LDBRX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LDBRX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - CPU.GPR[op.rd] = vm::_ref>(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::_ref>(vm::cast(addr, HERE)); } -void ppu_interpreter::LSWX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LSWX(PPUThread& ppu, ppu_opcode_t op) { - u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - u32 count = CPU.XER.XER & 0x7F; + u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + u32 count = ppu.XCNT & 0x7f; for (; count >= 4; count -= 4, addr += 4, op.rd = (op.rd + 1) & 31) { - CPU.GPR[op.rd] = vm::_ref(VM_CAST(addr)); + ppu.GPR[op.rd] = vm::_ref(vm::cast(addr, HERE)); } if (count) { u32 value = 0; for (u32 byte = 0; byte < count; byte++) { - u32 byte_value = vm::_ref(VM_CAST(addr + byte)); + u32 byte_value = vm::_ref(vm::cast(addr + byte, HERE)); value |= byte_value << ((3 ^ byte) * 8); } - CPU.GPR[op.rd] = value; + ppu.GPR[op.rd] = value; } } -void ppu_interpreter::LWBRX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LWBRX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - CPU.GPR[op.rd] = vm::_ref>(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::_ref>(vm::cast(addr, HERE)); } -void ppu_interpreter::LFSX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LFSX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - CPU.FPR[op.frd]._double = vm::_ref(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.FPR[op.frd] = vm::_ref(vm::cast(addr, HERE)); } -void ppu_interpreter::SRW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SRW(PPUThread& ppu, ppu_opcode_t op) { - u32 n = CPU.GPR[op.rb] & 0x1f; - u32 r = (u32)rotl32((u32)CPU.GPR[op.rs], 64 - n); - u32 m = ((u32)CPU.GPR[op.rb] & 0x20) ? 0 : (u32)rotate_mask[32 + n][63]; - CPU.GPR[op.ra] = r & m; - - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = (ppu.GPR[op.rs] & 0xffffffff) >> (ppu.GPR[op.rb] & 0x3f); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::SRD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SRD(PPUThread& ppu, ppu_opcode_t op) { - u32 n = CPU.GPR[op.rb] & 0x3f; - u64 r = rotl64(CPU.GPR[op.rs], 64 - n); - u64 m = (CPU.GPR[op.rb] & 0x40) ? 0 : rotate_mask[n][63]; - CPU.GPR[op.ra] = r & m; + u32 n = ppu.GPR[op.rb] & 0x3f; + u64 r = rol64(ppu.GPR[op.rs], 64 - n); + u64 m = (ppu.GPR[op.rb] & 0x40) ? 0 : ppu_rotate_mask(n, 63); + ppu.GPR[op.ra] = r & m; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::LVRX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LVRX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; const u8 eb = addr & 0xf; - CPU.VPR[op.vd].clear(); - for (u32 i = 16 - eb; i < 16; ++i) CPU.VPR[op.vd]._u8[15 - i] = vm::read8(VM_CAST(addr + i - 16)); + ppu.VR[op.vd].clear(); + for (u32 i = 16 - eb; i < 16; ++i) ppu.VR[op.vd]._u8[15 - i] = vm::read8(vm::cast(addr + i - 16, HERE)); } -void ppu_interpreter::LSWI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LSWI(PPUThread& ppu, ppu_opcode_t op) { - u64 addr = op.ra ? CPU.GPR[op.ra] : 0; + u64 addr = op.ra ? ppu.GPR[op.ra] : 0; u64 N = op.rb ? op.rb : 32; u8 reg = op.rd; @@ -2561,7 +2576,7 @@ void ppu_interpreter::LSWI(PPUThread& CPU, ppu_opcode_t op) { if (N > 3) { - CPU.GPR[reg] = vm::read32(VM_CAST(addr)); + ppu.GPR[reg] = vm::read32(vm::cast(addr, HERE)); addr += 4; N -= 4; } @@ -2572,104 +2587,104 @@ void ppu_interpreter::LSWI(PPUThread& CPU, ppu_opcode_t op) while (N > 0) { N = N - 1; - buf |= vm::read8(VM_CAST(addr)) << (i * 8); + buf |= vm::read8(vm::cast(addr, HERE)) << (i * 8); addr++; i--; } - CPU.GPR[reg] = buf; + ppu.GPR[reg] = buf; } reg = (reg + 1) % 32; } } -void ppu_interpreter::LFSUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LFSUX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - CPU.FPR[op.frd]._double = vm::_ref(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + ppu.FPR[op.frd] = vm::_ref(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::SYNC(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SYNC(PPUThread& ppu, ppu_opcode_t op) { _mm_mfence(); } -void ppu_interpreter::LFDX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LFDX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - CPU.FPR[op.frd]._double = vm::_ref(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.FPR[op.frd] = vm::_ref(vm::cast(addr, HERE)); } -void ppu_interpreter::LFDUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LFDUX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - CPU.FPR[op.frd]._double = vm::_ref(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + ppu.FPR[op.frd] = vm::_ref(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::STVLX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STVLX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; const u32 eb = addr & 0xf; - for (u32 i = 0; i < 16u - eb; ++i) vm::write8(VM_CAST(addr + i), CPU.VPR[op.vs]._u8[15 - i]); + for (u32 i = 0; i < 16u - eb; ++i) vm::write8(vm::cast(addr + i, HERE), ppu.VR[op.vs]._u8[15 - i]); } -void ppu_interpreter::STDBRX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STDBRX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - vm::_ref>(VM_CAST(addr)) = CPU.GPR[op.rs]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + vm::_ref>(vm::cast(addr, HERE)) = ppu.GPR[op.rs]; } -void ppu_interpreter::STSWX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STSWX(PPUThread& ppu, ppu_opcode_t op) { - u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - u32 count = CPU.XER.XER & 0x7F; + u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + u32 count = ppu.XCNT & 0x7F; for (; count >= 4; count -= 4, addr += 4, op.rs = (op.rs + 1) & 31) { - vm::write32(VM_CAST(addr), (u32)CPU.GPR[op.rs]); + vm::write32(vm::cast(addr, HERE), (u32)ppu.GPR[op.rs]); } if (count) { - u32 value = (u32)CPU.GPR[op.rs]; + u32 value = (u32)ppu.GPR[op.rs]; for (u32 byte = 0; byte < count; byte++) { u32 byte_value = (u8)(value >> ((3 ^ byte) * 8)); - vm::write8(VM_CAST(addr + byte), byte_value); + vm::write8(vm::cast(addr + byte, HERE), byte_value); } } } -void ppu_interpreter::STWBRX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STWBRX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - vm::_ref>(VM_CAST(addr)) = (u32)CPU.GPR[op.rs]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + vm::_ref>(vm::cast(addr, HERE)) = (u32)ppu.GPR[op.rs]; } -void ppu_interpreter::STFSX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STFSX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - vm::_ref(VM_CAST(addr)) = static_cast(CPU.FPR[op.frs]); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + vm::_ref(vm::cast(addr, HERE)) = static_cast(ppu.FPR[op.frs]); } -void ppu_interpreter::STVRX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STVRX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; const u8 eb = addr & 0xf; - for (u32 i = 16 - eb; i < 16; ++i) vm::write8(VM_CAST(addr + i - 16), CPU.VPR[op.vs]._u8[15 - i]); + for (u32 i = 16 - eb; i < 16; ++i) vm::write8(vm::cast(addr + i - 16, HERE), ppu.VR[op.vs]._u8[15 - i]); } -void ppu_interpreter::STFSUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STFSUX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - vm::_ref(VM_CAST(addr)) = static_cast(CPU.FPR[op.frs]); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + vm::_ref(vm::cast(addr, HERE)) = static_cast(ppu.FPR[op.frs]); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::STSWI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STSWI(PPUThread& ppu, ppu_opcode_t op) { - u64 addr = op.ra ? CPU.GPR[op.ra] : 0; + u64 addr = op.ra ? ppu.GPR[op.ra] : 0; u64 N = op.rb ? op.rb : 32; u8 reg = op.rd; @@ -2677,17 +2692,17 @@ void ppu_interpreter::STSWI(PPUThread& CPU, ppu_opcode_t op) { if (N > 3) { - vm::write32(VM_CAST(addr), (u32)CPU.GPR[reg]); + vm::write32(vm::cast(addr, HERE), (u32)ppu.GPR[reg]); addr += 4; N -= 4; } else { - u32 buf = (u32)CPU.GPR[reg]; + u32 buf = (u32)ppu.GPR[reg]; while (N > 0) { N = N - 1; - vm::write8(VM_CAST(addr), (0xFF000000 & buf) >> 24); + vm::write8(vm::cast(addr, HERE), (0xFF000000 & buf) >> 24); buf <<= 8; addr++; } @@ -2696,631 +2711,598 @@ void ppu_interpreter::STSWI(PPUThread& CPU, ppu_opcode_t op) } } -void ppu_interpreter::STFDX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STFDX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - vm::_ref(VM_CAST(addr)) = CPU.FPR[op.frs]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + vm::_ref(vm::cast(addr, HERE)) = ppu.FPR[op.frs]; } -void ppu_interpreter::STFDUX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STFDUX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + CPU.GPR[op.rb]; - vm::_ref(VM_CAST(addr)) = CPU.FPR[op.frs]; - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + ppu.GPR[op.rb]; + vm::_ref(vm::cast(addr, HERE)) = ppu.FPR[op.frs]; + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::LVLXL(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LVLXL(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; const u32 eb = addr & 0xf; - CPU.VPR[op.vd].clear(); - for (u32 i = 0; i < 16u - eb; ++i) CPU.VPR[op.vd]._u8[15 - i] = vm::read8(VM_CAST(addr + i)); + ppu.VR[op.vd].clear(); + for (u32 i = 0; i < 16u - eb; ++i) ppu.VR[op.vd]._u8[15 - i] = vm::read8(vm::cast(addr + i, HERE)); } -void ppu_interpreter::LHBRX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LHBRX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - CPU.GPR[op.rd] = vm::_ref>(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + ppu.GPR[op.rd] = vm::_ref>(vm::cast(addr, HERE)); } -void ppu_interpreter::SRAW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SRAW(PPUThread& ppu, ppu_opcode_t op) { - s32 RS = (s32)CPU.GPR[op.rs]; - u8 shift = CPU.GPR[op.rb] & 63; + s32 RS = (s32)ppu.GPR[op.rs]; + u8 shift = ppu.GPR[op.rb] & 63; if (shift > 31) { - CPU.GPR[op.ra] = 0 - (RS < 0); - CPU.XER.CA = (RS < 0); + ppu.GPR[op.ra] = 0 - (RS < 0); + ppu.CA = (RS < 0); } else { - CPU.GPR[op.ra] = RS >> shift; - CPU.XER.CA = (RS < 0) & ((CPU.GPR[op.ra] << shift) != RS); + ppu.GPR[op.ra] = RS >> shift; + ppu.CA = (RS < 0) && ((ppu.GPR[op.ra] << shift) != RS); } - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::SRAD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SRAD(PPUThread& ppu, ppu_opcode_t op) { - s64 RS = CPU.GPR[op.rs]; - u8 shift = CPU.GPR[op.rb] & 127; + s64 RS = ppu.GPR[op.rs]; + u8 shift = ppu.GPR[op.rb] & 127; if (shift > 63) { - CPU.GPR[op.ra] = 0 - (RS < 0); - CPU.XER.CA = (RS < 0); + ppu.GPR[op.ra] = 0 - (RS < 0); + ppu.CA = (RS < 0); } else { - CPU.GPR[op.ra] = RS >> shift; - CPU.XER.CA = (RS < 0) & ((CPU.GPR[op.ra] << shift) != RS); + ppu.GPR[op.ra] = RS >> shift; + ppu.CA = (RS < 0) && ((ppu.GPR[op.ra] << shift) != RS); } - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::LVRXL(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LVRXL(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; const u8 eb = addr & 0xf; - CPU.VPR[op.vd].clear(); - for (u32 i = 16 - eb; i < 16; ++i) CPU.VPR[op.vd]._u8[15 - i] = vm::read8(VM_CAST(addr + i - 16)); + ppu.VR[op.vd].clear(); + for (u32 i = 16 - eb; i < 16; ++i) ppu.VR[op.vd]._u8[15 - i] = vm::read8(vm::cast(addr + i - 16, HERE)); } -void ppu_interpreter::DSS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::DSS(PPUThread& ppu, ppu_opcode_t op) { } -void ppu_interpreter::SRAWI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SRAWI(PPUThread& ppu, ppu_opcode_t op) { - s32 RS = (u32)CPU.GPR[op.rs]; - CPU.GPR[op.ra] = RS >> op.sh; - CPU.XER.CA = (RS < 0) & ((u32)(CPU.GPR[op.ra] << op.sh) != RS); + s32 RS = (u32)ppu.GPR[op.rs]; + ppu.GPR[op.ra] = RS >> op.sh32; + ppu.CA = (RS < 0) && ((u32)(ppu.GPR[op.ra] << op.sh32) != RS); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::SRADI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::SRADI(PPUThread& ppu, ppu_opcode_t op) { - auto sh = (op.shh << 5) | op.shl; - s64 RS = CPU.GPR[op.rs]; - CPU.GPR[op.ra] = RS >> sh; - CPU.XER.CA = (RS < 0) & ((CPU.GPR[op.ra] << sh) != RS); + auto sh = op.sh64; + s64 RS = ppu.GPR[op.rs]; + ppu.GPR[op.ra] = RS >> sh; + ppu.CA = (RS < 0) && ((ppu.GPR[op.ra] << sh) != RS); - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::EIEIO(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::EIEIO(PPUThread& ppu, ppu_opcode_t op) { _mm_mfence(); } -void ppu_interpreter::STVLXL(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STVLXL(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; const u32 eb = addr & 0xf; - for (u32 i = 0; i < 16u - eb; ++i) vm::write8(VM_CAST(addr + i), CPU.VPR[op.vs]._u8[15 - i]); + for (u32 i = 0; i < 16u - eb; ++i) vm::write8(vm::cast(addr + i, HERE), ppu.VR[op.vs]._u8[15 - i]); } -void ppu_interpreter::STHBRX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STHBRX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - vm::_ref>(VM_CAST(addr)) = (u16)CPU.GPR[op.rs]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + vm::_ref>(vm::cast(addr, HERE)) = (u16)ppu.GPR[op.rs]; } -void ppu_interpreter::EXTSH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::EXTSH(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = (s64)(s16)CPU.GPR[op.rs]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = (s64)(s16)ppu.GPR[op.rs]; + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::STVRXL(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STVRXL(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; const u8 eb = addr & 0xf; - for (u32 i = 16 - eb; i < 16; ++i) vm::write8(VM_CAST(addr + i - 16), CPU.VPR[op.vs]._u8[15 - i]); + for (u32 i = 16 - eb; i < 16; ++i) vm::write8(vm::cast(addr + i - 16, HERE), ppu.VR[op.vs]._u8[15 - i]); } -void ppu_interpreter::EXTSB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::EXTSB(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = (s64)(s8)CPU.GPR[op.rs]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = (s64)(s8)ppu.GPR[op.rs]; + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::STFIWX(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STFIWX(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; - vm::write32(VM_CAST(addr), (u32&)CPU.FPR[op.frs]); + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; + vm::write32(vm::cast(addr, HERE), (u32&)ppu.FPR[op.frs]); } -void ppu_interpreter::EXTSW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::EXTSW(PPUThread& ppu, ppu_opcode_t op) { - CPU.GPR[op.ra] = (s64)(s32)CPU.GPR[op.rs]; - if (op.rc) CPU.UpdateCR0(CPU.GPR[op.ra]); + ppu.GPR[op.ra] = (s64)(s32)ppu.GPR[op.rs]; + if (op.rc) ppu.SetCR(0, ppu.GPR[op.ra], 0); } -void ppu_interpreter::ICBI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::ICBI(PPUThread& ppu, ppu_opcode_t op) { } -void ppu_interpreter::DCBZ(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::DCBZ(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + CPU.GPR[op.rb] : CPU.GPR[op.rb]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + ppu.GPR[op.rb] : ppu.GPR[op.rb]; - std::memset(vm::base(VM_CAST(addr) & ~127), 0, 128); + std::memset(vm::base(vm::cast(addr, HERE) & ~127), 0, 128); } -void ppu_interpreter::LWZ(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LWZ(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - CPU.GPR[op.rd] = vm::read32(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + ppu.GPR[op.rd] = vm::read32(vm::cast(addr, HERE)); } -void ppu_interpreter::LWZU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LWZU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - CPU.GPR[op.rd] = vm::read32(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + ppu.GPR[op.rd] = vm::read32(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::LBZ(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LBZ(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - CPU.GPR[op.rd] = vm::read8(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + ppu.GPR[op.rd] = vm::read8(vm::cast(addr, HERE)); } -void ppu_interpreter::LBZU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LBZU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - CPU.GPR[op.rd] = vm::read8(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + ppu.GPR[op.rd] = vm::read8(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::STW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STW(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - vm::write32(VM_CAST(addr), (u32)CPU.GPR[op.rs]); + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + vm::write32(vm::cast(addr, HERE), (u32)ppu.GPR[op.rs]); } -void ppu_interpreter::STWU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STWU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - vm::write32(VM_CAST(addr), (u32)CPU.GPR[op.rs]); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + vm::write32(vm::cast(addr, HERE), (u32)ppu.GPR[op.rs]); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::STB(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STB(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - vm::write8(VM_CAST(addr), (u8)CPU.GPR[op.rs]); + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + vm::write8(vm::cast(addr, HERE), (u8)ppu.GPR[op.rs]); } -void ppu_interpreter::STBU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STBU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - vm::write8(VM_CAST(addr), (u8)CPU.GPR[op.rs]); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + vm::write8(vm::cast(addr, HERE), (u8)ppu.GPR[op.rs]); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::LHZ(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LHZ(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - CPU.GPR[op.rd] = vm::read16(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + ppu.GPR[op.rd] = vm::read16(vm::cast(addr, HERE)); } -void ppu_interpreter::LHZU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LHZU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - CPU.GPR[op.rd] = vm::read16(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + ppu.GPR[op.rd] = vm::read16(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::LHA(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LHA(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - CPU.GPR[op.rd] = (s64)(s16)vm::read16(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + ppu.GPR[op.rd] = (s64)(s16)vm::read16(vm::cast(addr, HERE)); } -void ppu_interpreter::LHAU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LHAU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - CPU.GPR[op.rd] = (s64)(s16)vm::read16(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + ppu.GPR[op.rd] = (s64)(s16)vm::read16(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::STH(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STH(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - vm::write16(VM_CAST(addr), (u16)CPU.GPR[op.rs]); + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + vm::write16(vm::cast(addr, HERE), (u16)ppu.GPR[op.rs]); } -void ppu_interpreter::STHU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STHU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - vm::write16(VM_CAST(addr), (u16)CPU.GPR[op.rs]); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + vm::write16(vm::cast(addr, HERE), (u16)ppu.GPR[op.rs]); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::LMW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LMW(PPUThread& ppu, ppu_opcode_t op) { - u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; + u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; for (u32 i = op.rd; i<32; ++i, addr += 4) { - CPU.GPR[i] = vm::read32(VM_CAST(addr)); + ppu.GPR[i] = vm::read32(vm::cast(addr, HERE)); } } -void ppu_interpreter::STMW(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STMW(PPUThread& ppu, ppu_opcode_t op) { - u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; + u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; for (u32 i = op.rs; i<32; ++i, addr += 4) { - vm::write32(VM_CAST(addr), (u32)CPU.GPR[i]); + vm::write32(vm::cast(addr, HERE), (u32)ppu.GPR[i]); } } -void ppu_interpreter::LFS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LFS(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - CPU.FPR[op.frd]._double = vm::_ref(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + ppu.FPR[op.frd] = vm::_ref(vm::cast(addr, HERE)); } -void ppu_interpreter::LFSU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LFSU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - CPU.FPR[op.frd]._double = vm::_ref(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + ppu.FPR[op.frd] = vm::_ref(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::LFD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LFD(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - CPU.FPR[op.frd]._double = vm::_ref(VM_CAST(addr)); + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + ppu.FPR[op.frd] = vm::_ref(vm::cast(addr, HERE)); } -void ppu_interpreter::LFDU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LFDU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - CPU.FPR[op.frd]._double = vm::_ref(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + ppu.FPR[op.frd] = vm::_ref(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::STFS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STFS(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - vm::_ref(VM_CAST(addr)) = static_cast(CPU.FPR[op.frs]); + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + vm::_ref(vm::cast(addr, HERE)) = static_cast(ppu.FPR[op.frs]); } -void ppu_interpreter::STFSU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STFSU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - vm::_ref(VM_CAST(addr)) = static_cast(CPU.FPR[op.frs]); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + vm::_ref(vm::cast(addr, HERE)) = static_cast(ppu.FPR[op.frs]); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::STFD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STFD(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = op.ra ? CPU.GPR[op.ra] + op.simm16 : op.simm16; - vm::_ref(VM_CAST(addr)) = CPU.FPR[op.frs]; + const u64 addr = op.ra ? ppu.GPR[op.ra] + op.simm16 : op.simm16; + vm::_ref(vm::cast(addr, HERE)) = ppu.FPR[op.frs]; } -void ppu_interpreter::STFDU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STFDU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + op.simm16; - vm::_ref(VM_CAST(addr)) = CPU.FPR[op.frs]; - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + op.simm16; + vm::_ref(vm::cast(addr, HERE)) = ppu.FPR[op.frs]; + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::LD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LD(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = (op.simm16 & ~3) + (op.ra ? CPU.GPR[op.ra] : 0); - CPU.GPR[op.rd] = vm::read64(VM_CAST(addr)); + const u64 addr = (op.simm16 & ~3) + (op.ra ? ppu.GPR[op.ra] : 0); + ppu.GPR[op.rd] = vm::read64(vm::cast(addr, HERE)); } -void ppu_interpreter::LDU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LDU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + (op.simm16 & ~3); - CPU.GPR[op.rd] = vm::read64(VM_CAST(addr)); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + (op.simm16 & ~3); + ppu.GPR[op.rd] = vm::read64(vm::cast(addr, HERE)); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::LWA(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::LWA(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = (op.simm16 & ~3) + (op.ra ? CPU.GPR[op.ra] : 0); - CPU.GPR[op.rd] = (s64)(s32)vm::read32(VM_CAST(addr)); + const u64 addr = (op.simm16 & ~3) + (op.ra ? ppu.GPR[op.ra] : 0); + ppu.GPR[op.rd] = (s64)(s32)vm::read32(vm::cast(addr, HERE)); } -void ppu_interpreter::FDIVS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::FDIVS(PPUThread& ppu, ppu_opcode_t op) { - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] / CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); + ppu.FPR[op.frd] = f32(ppu.FPR[op.fra] / ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::FSUBS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::FSUBS(PPUThread& ppu, ppu_opcode_t op) { - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] - CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); + ppu.FPR[op.frd] = f32(ppu.FPR[op.fra] - ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::FADDS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::FADDS(PPUThread& ppu, ppu_opcode_t op) { - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] + CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); + ppu.FPR[op.frd] = f32(ppu.FPR[op.fra] + ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::FSQRTS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::FSQRTS(PPUThread& ppu, ppu_opcode_t op) { - CPU.FPR[op.frd]._double = sqrt(CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); + ppu.FPR[op.frd] = f32(sqrt(ppu.FPR[op.frb])); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::FRES(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::FRES(PPUThread& ppu, ppu_opcode_t op) { - CPU.FPR[op.frd]._double = 1.0 / CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); + ppu.FPR[op.frd] = f32(1.0 / ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::FMULS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::FMULS(PPUThread& ppu, ppu_opcode_t op) { - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] * CPU.FPR[op.frc]; - if (op.rc) CPU.UpdateCR1(); + ppu.FPR[op.frd] = f32(ppu.FPR[op.fra] * ppu.FPR[op.frc]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::FMADDS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::FMADDS(PPUThread& ppu, ppu_opcode_t op) { - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] * CPU.FPR[op.frc] + CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); + ppu.FPR[op.frd] = f32(ppu.FPR[op.fra] * ppu.FPR[op.frc] + ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::FMSUBS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::FMSUBS(PPUThread& ppu, ppu_opcode_t op) { - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] * CPU.FPR[op.frc] - CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); + ppu.FPR[op.frd] = f32(ppu.FPR[op.fra] * ppu.FPR[op.frc] - ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::FNMSUBS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::FNMSUBS(PPUThread& ppu, ppu_opcode_t op) { - CPU.FPR[op.frd]._double = -(CPU.FPR[op.fra] * CPU.FPR[op.frc]) + CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); + ppu.FPR[op.frd] = f32(-(ppu.FPR[op.fra] * ppu.FPR[op.frc]) + ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::FNMADDS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::FNMADDS(PPUThread& ppu, ppu_opcode_t op) { - CPU.FPR[op.frd]._double = -(CPU.FPR[op.fra] * CPU.FPR[op.frc]) - CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); + ppu.FPR[op.frd] = f32(-(ppu.FPR[op.fra] * ppu.FPR[op.frc]) - ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::STD(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STD(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = (op.simm16 & ~3) + (op.ra ? CPU.GPR[op.ra] : 0); - vm::write64(VM_CAST(addr), CPU.GPR[op.rs]); + const u64 addr = (op.simm16 & ~3) + (op.ra ? ppu.GPR[op.ra] : 0); + vm::write64(vm::cast(addr, HERE), ppu.GPR[op.rs]); } -void ppu_interpreter::STDU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::STDU(PPUThread& ppu, ppu_opcode_t op) { - const u64 addr = CPU.GPR[op.ra] + (op.simm16 & ~3); - vm::write64(VM_CAST(addr), CPU.GPR[op.rs]); - CPU.GPR[op.ra] = addr; + const u64 addr = ppu.GPR[op.ra] + (op.simm16 & ~3); + vm::write64(vm::cast(addr, HERE), ppu.GPR[op.rs]); + ppu.GPR[op.ra] = addr; } -void ppu_interpreter::MTFSB1(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MTFSB1(PPUThread& ppu, ppu_opcode_t op) { - u32 mask = 1 << (31 - op.crbd); - if ((op.crbd >= 3 && op.crbd <= 6) && !(CPU.FPSCR.FPSCR & mask)) mask |= 1ULL << 31; //FPSCR.FX - if ((op.crbd == 29) && !CPU.FPSCR.NI) LOG_WARNING(PPU, "Non-IEEE mode enabled"); - CPU.SetFPSCR(CPU.FPSCR.FPSCR | mask); - - if (op.rc) CPU.UpdateCR1(); + LOG_WARNING(PPU, "MTFSB1"); + if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::MCRFS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MCRFS(PPUThread& ppu, ppu_opcode_t op) { - CPU.SetCR(op.crfd, (CPU.FPSCR.FPSCR >> ((7 - op.crfs) * 4)) & 0xf); - const u32 exceptions_mask = 0x9FF80700; - CPU.SetFPSCR(CPU.FPSCR.FPSCR & ~(exceptions_mask & 0xf << ((7 - op.crfs) * 4))); + LOG_WARNING(PPU, "MCRFS"); + ppu.SetCR(op.crfd, false, false, false, false); } -void ppu_interpreter::MTFSB0(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MTFSB0(PPUThread& ppu, ppu_opcode_t op) { - u32 mask = 1 << (31 - op.crbd); - if ((op.crbd == 29) && !CPU.FPSCR.NI) LOG_WARNING(PPU, "Non-IEEE mode disabled"); - CPU.SetFPSCR(CPU.FPSCR.FPSCR & ~mask); - - if (op.rc) CPU.UpdateCR1(); + LOG_WARNING(PPU, "MTFSB0"); + if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::MTFSFI(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MTFSFI(PPUThread& ppu, ppu_opcode_t op) { - u32 mask = 0xF0000000 >> (op.crfd * 4); - u32 val = (op.i & 0xF) << ((7 - op.crfd) * 4); - - const u32 oldNI = CPU.FPSCR.NI; - CPU.SetFPSCR((CPU.FPSCR.FPSCR & ~mask) | val); - if (CPU.FPSCR.NI != oldNI) - { - if (oldNI) - LOG_WARNING(PPU, "Non-IEEE mode disabled"); - else - LOG_WARNING(PPU, "Non-IEEE mode enabled"); - } - - if (op.rc) CPU.UpdateCR1(); + LOG_WARNING(PPU, "MTFSFI"); + if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::MFFS(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MFFS(PPUThread& ppu, ppu_opcode_t op) { - (u64&)CPU.FPR[op.frd]._double = CPU.FPSCR.FPSCR; - if (op.rc) CPU.UpdateCR1(); + LOG_WARNING(PPU, "MFFS"); + ppu.FPR[op.frd] = 0.0; + if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::MTFSF(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::MTFSF(PPUThread& ppu, ppu_opcode_t op) { - u32 mask = 0; - for (u32 i = 0; i<8; ++i) - { - if (op.flm & (1 << i)) mask |= 0xf << (i * 4); - } - mask &= ~0x60000000; + LOG_WARNING(PPU, "MTFSF"); + if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} - const u32 oldNI = CPU.FPSCR.NI; - CPU.SetFPSCR((CPU.FPSCR.FPSCR & ~mask) | ((u32&)CPU.FPR[op.frb] & mask)); - if (CPU.FPSCR.NI != oldNI) - { - if (oldNI) - LOG_WARNING(PPU, "Non-IEEE mode disabled"); - else - LOG_WARNING(PPU, "Non-IEEE mode enabled"); - } - if (op.rc) CPU.UpdateCR1(); +void ppu_interpreter::FCMPU(PPUThread& ppu, ppu_opcode_t op) +{ + const f64 a = ppu.FPR[op.fra]; + const f64 b = ppu.FPR[op.frb]; + ppu.FG = a > b; + ppu.FL = a < b; + ppu.FE = a == b; + //ppu.FU = a != a || b != b; + ppu.SetCR(op.crfd, ppu.FL, ppu.FG, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FRSP(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = f32(ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FCTIW(PPUThread& ppu, ppu_opcode_t op) +{ + (s32&)ppu.FPR[op.frd] = lrint(ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FCTIWZ(PPUThread& ppu, ppu_opcode_t op) +{ + (s32&)ppu.FPR[op.frd] = static_cast(ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FDIV(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = ppu.FPR[op.fra] / ppu.FPR[op.frb]; + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FSUB(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = ppu.FPR[op.fra] - ppu.FPR[op.frb]; + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FADD(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = ppu.FPR[op.fra] + ppu.FPR[op.frb]; + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FSQRT(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = sqrt(ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FSEL(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = ppu.FPR[op.fra] >= 0.0 ? ppu.FPR[op.frc] : ppu.FPR[op.frb]; + if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FMUL(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = ppu.FPR[op.fra] * ppu.FPR[op.frc]; + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FRSQRTE(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = 1.0 / sqrt(ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FMSUB(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = ppu.FPR[op.fra] * ppu.FPR[op.frc] - ppu.FPR[op.frb]; + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FMADD(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = ppu.FPR[op.fra] * ppu.FPR[op.frc] + ppu.FPR[op.frb]; + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FNMSUB(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = -(ppu.FPR[op.fra] * ppu.FPR[op.frc]) + ppu.FPR[op.frb]; + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FNMADD(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = -(ppu.FPR[op.fra] * ppu.FPR[op.frc]) - ppu.FPR[op.frb]; + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FCMPO(PPUThread& ppu, ppu_opcode_t op) +{ + return FCMPU(ppu, op); +} + +void ppu_interpreter::FNEG(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = -ppu.FPR[op.frb]; + if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FMR(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = ppu.FPR[op.frb]; + if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FNABS(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = -fabs(ppu.FPR[op.frb]); + if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FABS(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = fabs(ppu.FPR[op.frb]); + if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FCTID(PPUThread& ppu, ppu_opcode_t op) +{ + (s64&)ppu.FPR[op.frd] = llrint(ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FCTIDZ(PPUThread& ppu, ppu_opcode_t op) +{ + (s64&)ppu.FPR[op.frd] = static_cast(ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); +} + +void ppu_interpreter::FCFID(PPUThread& ppu, ppu_opcode_t op) +{ + ppu.FPR[op.frd] = static_cast((s64&)ppu.FPR[op.frb]); + ASSERT(!op.rc); //if (op.rc) ppu.SetCR(1, ppu.FG, ppu.FL, ppu.FE, ppu.FU); } -void ppu_interpreter::FCMPU(PPUThread& CPU, ppu_opcode_t op) +void ppu_interpreter::UNK(PPUThread& ppu, ppu_opcode_t op) { - s32 cmp_res = FPRdouble::Cmp(CPU.FPR[op.fra], CPU.FPR[op.frb]); - //CPU.FPSCR.FPRF = cmp_res; - CPU.SetCR(op.crfd, cmp_res); -} - -void ppu_interpreter::FRSP(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = static_cast(CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FCTIW(PPUThread& CPU, ppu_opcode_t op) -{ - (s32&)CPU.FPR[op.frd]._double = lrint(CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FCTIWZ(PPUThread& CPU, ppu_opcode_t op) -{ - (s32&)CPU.FPR[op.frd]._double = static_cast(CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FDIV(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] / CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FSUB(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] - CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FADD(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] + CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FSQRT(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = sqrt(CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FSEL(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] >= 0.0 ? CPU.FPR[op.frc] : CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FMUL(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] * CPU.FPR[op.frc]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FRSQRTE(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = 1.0 / sqrt(CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FMSUB(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] * CPU.FPR[op.frc] - CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FMADD(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = CPU.FPR[op.fra] * CPU.FPR[op.frc] + CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FNMSUB(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = -(CPU.FPR[op.fra] * CPU.FPR[op.frc]) + CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FNMADD(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = -(CPU.FPR[op.fra] * CPU.FPR[op.frc]) - CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FCMPO(PPUThread& CPU, ppu_opcode_t op) -{ - s32 cmp_res = FPRdouble::Cmp(CPU.FPR[op.fra], CPU.FPR[op.frb]); - //CPU.FPSCR.FPRF = cmp_res; - CPU.SetCR(op.crfd, cmp_res); -} - -void ppu_interpreter::FNEG(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = -CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FMR(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = CPU.FPR[op.frb]; - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FNABS(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = -fabs(CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FABS(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = fabs(CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FCTID(PPUThread& CPU, ppu_opcode_t op) -{ - (s64&)CPU.FPR[op.frd]._double = llrint(CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FCTIDZ(PPUThread& CPU, ppu_opcode_t op) -{ - (s64&)CPU.FPR[op.frd]._double = static_cast(CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); -} - -void ppu_interpreter::FCFID(PPUThread& CPU, ppu_opcode_t op) -{ - CPU.FPR[op.frd]._double = static_cast((s64&)CPU.FPR[op.frb]); - if (op.rc) CPU.UpdateCR1(); -} - - -void ppu_interpreter::UNK(PPUThread& CPU, ppu_opcode_t op) -{ - throw EXCEPTION(""); + throw fmt::exception("Unknown/Illegal opcode: 0x%08x" HERE, op.opcode); } diff --git a/rpcs3/Emu/Cell/PPUInterpreter.h b/rpcs3/Emu/Cell/PPUInterpreter.h index 984723c34e..ddca283103 100644 --- a/rpcs3/Emu/Cell/PPUInterpreter.h +++ b/rpcs3/Emu/Cell/PPUInterpreter.h @@ -1,4719 +1,403 @@ #pragma once -#include "Emu/Cell/PPUOpcodes.h" -#include "Emu/Memory/Memory.h" +#include "PPUOpcodes.h" -#if defined(_MSC_VER) -#include -#else -#include -#define _rotl64(x,r) (((u64)(x) << (r)) | ((u64)(x) >> (64 - (r)))) -#endif +class PPUThread; -#if defined(__GNUG__) -inline std::uint64_t UMULH64(std::uint64_t a, std::uint64_t b) +using ppu_inter_func_t = void(*)(PPUThread& ppu, ppu_opcode_t op); + +struct ppu_interpreter { - std::uint64_t result; - __asm__("mulq %[b]" : "=d" (result) : [a] "a" (a), [b] "rm" (b)); - return result; -} - -inline std::int64_t MULH64(std::int64_t a, std::int64_t b) -{ - std::int64_t result; - __asm__("imulq %[b]" : "=d" (result) : [a] "a" (a), [b] "rm" (b)); - return result; -} -#else -#define UMULH64 __umulh -#define MULH64 __mulh -#endif - -#include - -extern u64 rotate_mask[64][64]; // defined in PPUThread.cpp -extern u64 get_timebased_time(); - -inline void InitRotateMask() -{ - static bool inited = false; - if(inited) return; - - for(u32 mb=0; mb<64; mb++) for(u32 me=0; me<64; me++) - { - const u64 mask = ((u64)-1 >> mb) ^ ((me >= 63) ? 0 : (u64)-1 >> (me + 1)); - rotate_mask[mb][me] = mb > me ? ~mask : mask; - } - - inited = true; -} - -inline u8 rotl8(const u8 x, const u8 n) { return (x << n) | (x >> (8 - n)); } -inline u8 rotr8(const u8 x, const u8 n) { return (x >> n) | (x << (8 - n)); } - -inline u16 rotl16(const u16 x, const u8 n) { return (x << n) | (x >> (16 - n)); } -inline u16 rotr16(const u16 x, const u8 n) { return (x >> n) | (x << (16 - n)); } -/* -u32 rotl32(const u32 x, const u8 n) { return (x << n) | (x >> (32 - n)); } -u32 rotr32(const u32 x, const u8 n) { return (x >> n) | (x << (32 - n)); } -u64 rotl64(const u64 x, const u8 n) { return (x << n) | (x >> (64 - n)); } -u64 rotr64(const u64 x, const u8 n) { return (x >> n) | (x << (64 - n)); } -*/ - -#define rotl32(x, n) _rotl64((u64)(u32)x | ((u64)(u32)x << 32), n) -#define rotr32(x, n) _rotr64((u64)(u32)x | ((u64)(u32)x << 32), n) -#define rotl64 _rotl64 -#define rotr64 _rotr64 - -static double SilenceNaN(double x) -{ - u64 bits = (u64&)x; - bits |= 0x0008000000000000ULL; - return (double&)bits; -} - -static float SilenceNaN(float x) -{ - return static_cast(SilenceNaN(static_cast(x))); -} - -static void SetHostRoundingMode(u32 rn) -{ - switch (rn) - { - case FPSCR_RN_NEAR: - fesetround(FE_TONEAREST); - break; - case FPSCR_RN_ZERO: - fesetround(FE_TOWARDZERO); - break; - case FPSCR_RN_PINF: - fesetround(FE_UPWARD); - break; - case FPSCR_RN_MINF: - fesetround(FE_DOWNWARD); - break; - } -} - - -namespace ppu_recompiler_llvm { - class Compiler; - class RecompilationEngine; -} - -class ppu_llvm_test_class; - -class PPUInterpreter : public PPUOpcodes -{ -#ifdef PPU_LLVM_RECOMPILER - friend class ppu_recompiler_llvm::Compiler; - friend class ppu_llvm_test_class; - friend class ppu_recompiler_llvm::RecompilationEngine; -#endif -private: - PPUThread& CPU; - -public: - PPUInterpreter(PPUThread& cpu) : CPU(cpu) - { - } - -private: - void CheckHostFPExceptions() - { - CPU.SetFPSCR_FI(fetestexcept(FE_INEXACT) != 0); - if (fetestexcept(FE_UNDERFLOW)) CPU.SetFPSCRException(FPSCR_UX); - if (fetestexcept(FE_OVERFLOW)) CPU.SetFPSCRException(FPSCR_OX); - } - - void NULL_OP() override - { - throw EXCEPTION("Null operation"); - } - - void NOP() override - { - //__asm nop - } - - float CheckVSCR_NJ(const float v) const - { - if(!CPU.VSCR.NJ) return v; - - const int fpc = _fpclass(v); -#ifdef __GNUG__ - if(fpc == FP_SUBNORMAL) - return std::signbit(v) ? -0.0f : 0.0f; -#else - if(fpc & _FPCLASS_ND) return -0.0f; - if(fpc & _FPCLASS_PD) return 0.0f; -#endif - - return v; - } - - bool CheckCondition(u32 bo, u32 bi) - { - const u8 bo0 = (bo & 0x10) ? 1 : 0; - const u8 bo1 = (bo & 0x08) ? 1 : 0; - const u8 bo2 = (bo & 0x04) ? 1 : 0; - const u8 bo3 = (bo & 0x02) ? 1 : 0; - - if(!bo2) --CPU.CTR; - - const u8 ctr_ok = bo2 | ((CPU.CTR != 0) ^ bo3); - const u8 cond_ok = bo0 | (CPU.IsCR(bi) ^ (~bo1 & 0x1)); - - return ctr_ok && cond_ok; - } - - u64 ReadSPR(u32 spr) - { - const u32 n = (spr >> 5) | ((spr & 0x1f) << 5); - - switch (n) - { - case 0x001: return CPU.XER.XER; - case 0x008: return CPU.LR; - case 0x009: return CPU.CTR; - case 0x100: return CPU.VRSAVE; - case 0x103: return CPU.SPRG[3]; - - case 0x10C: CPU.TB = get_timebased_time(); return CPU.TB; - case 0x10D: CPU.TB = get_timebased_time(); return CPU.TB >> 32; - - case 0x110: - case 0x111: - case 0x112: - case 0x113: - case 0x114: - case 0x115: - case 0x116: - case 0x117: return CPU.SPRG[n - 0x110]; - } - - throw EXCEPTION("Unknown SPR (spr=0x%x, n=0x%x)", spr, n); - } - - void WriteSPR(u32 spr, u64 value) - { - const u32 n = (spr >> 5) | ((spr & 0x1f) << 5); - - switch (n) - { - case 0x001: CPU.XER.XER = value; return; - case 0x008: CPU.LR = value; return; - case 0x009: CPU.CTR = value; return; - case 0x100: CPU.VRSAVE = (u32)value; return; - case 0x103: throw EXCEPTION("WriteSPR(0x103, 0x%llx): Write to read-only SPR", value); - - case 0x10C: throw EXCEPTION("WriteSPR(0x10C, 0x%llx): Write to time-based SPR", value); - case 0x10D: throw EXCEPTION("WriteSPR(0x10D, 0x%llx): Write to time-based SPR", value); - - case 0x110: - case 0x111: - case 0x112: - case 0x113: - case 0x114: - case 0x115: - case 0x116: - case 0x117: CPU.SPRG[n - 0x110] = value; return; - } - - throw EXCEPTION("Unknown SPR (spr=0x%x, n=0x%x, value=0x%llx)", spr, n, value); - } - - void TDI(u32 to, u32 ra, s32 simm16) override - { - s64 a = CPU.GPR[ra]; - - if( (a < (s64)simm16 && (to & 0x10)) || - (a > (s64)simm16 && (to & 0x8)) || - (a == (s64)simm16 && (to & 0x4)) || - ((u64)a < (u64)simm16 && (to & 0x2)) || - ((u64)a > (u64)simm16 && (to & 0x1)) ) - { - throw EXCEPTION("Trap! (tdi 0x%x, r%d, 0x%x)", to, ra, simm16); - } - } - - static void TWI_impl(PPUThread *CPU, u32 to, u32 ra, s32 simm16) - { - s32 a = (s32)CPU->GPR[ra]; - - if ((a < simm16 && (to & 0x10)) || - (a > simm16 && (to & 0x8)) || - (a == simm16 && (to & 0x4)) || - ((u32)a < (u32)simm16 && (to & 0x2)) || - ((u32)a > (u32)simm16 && (to & 0x1)) ) - { - throw EXCEPTION("Trap! (twi 0x%x, r%d, 0x%x)", to, ra, simm16); - } - } - - void TWI(u32 to, u32 ra, s32 simm16) override - { - TWI_impl(&CPU, to, ra, simm16); - } - - void MFVSCR(u32 vd) override //nf - { - CPU.VPR[vd].clear(); - CPU.VPR[vd]._u32[0] = CPU.VSCR.VSCR; - } - void MTVSCR(u32 vb) override - { - CPU.VSCR.VSCR = CPU.VPR[vb]._u32[0]; - CPU.VSCR.X = CPU.VSCR.Y = 0; - } - void VADDCUW(u32 vd, u32 va, u32 vb) override //nf - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = ~CPU.VPR[va]._u32[w] < CPU.VPR[vb]._u32[w]; - } - } - void VADDFP(u32 vd, u32 va, u32 vb) override - { - SetHostRoundingMode(FPSCR_RN_NEAR); - for (uint w = 0; w < 4; w++) - { - const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]); - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(a)) - CPU.VPR[vd]._f[w] = SilenceNaN(a); - else if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else if (std::isinf(a) && std::isinf(b) && a != b) - CPU.VPR[vd]._f[w] = (float)FPR_NAN; - else - CPU.VPR[vd]._f[w] = CheckVSCR_NJ(a + b); - } - } - void VADDSBS(u32 vd, u32 va, u32 vb) override //nf - { - for(u32 b=0; b<16; ++b) - { - s16 result = (s16)CPU.VPR[va]._s8[b] + (s16)CPU.VPR[vb]._s8[b]; - - if (result > 0x7f) - { - CPU.VPR[vd]._s8[b] = 0x7f; - CPU.VSCR.SAT = 1; - } - else if (result < -0x80) - { - CPU.VPR[vd]._s8[b] = -0x80; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s8[b] = (s8)result; - } - } - void VADDSHS(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - s32 result = (s32)CPU.VPR[va]._s16[h] + (s32)CPU.VPR[vb]._s16[h]; - - if (result > 0x7fff) - { - CPU.VPR[vd]._s16[h] = 0x7fff; - CPU.VSCR.SAT = 1; - } - else if (result < -0x8000) - { - CPU.VPR[vd]._s16[h] = -0x8000; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s16[h] = result; - } - } - void VADDSWS(u32 vd, u32 va, u32 vb) override //nf - { - for (uint w = 0; w < 4; w++) - { - s64 result = (s64)CPU.VPR[va]._s32[w] + (s64)CPU.VPR[vb]._s32[w]; - - if (result > 0x7fffffff) - { - CPU.VPR[vd]._s32[w] = 0x7fffffff; - CPU.VSCR.SAT = 1; - } - else if (result < (s32)0x80000000) - { - CPU.VPR[vd]._s32[w] = 0x80000000; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s32[w] = (s32)result; - } - } - void VADDUBM(u32 vd, u32 va, u32 vb) override - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._u8[b] = CPU.VPR[va]._u8[b] + CPU.VPR[vb]._u8[b]; - } - } - void VADDUBS(u32 vd, u32 va, u32 vb) override - { - for (uint b = 0; b < 16; b++) - { - u16 result = (u16)CPU.VPR[va]._u8[b] + (u16)CPU.VPR[vb]._u8[b]; - - if (result > 0xff) - { - CPU.VPR[vd]._u8[b] = 0xff; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._u8[b] = (u8)result; - } - } - void VADDUHM(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = CPU.VPR[va]._u16[h] + CPU.VPR[vb]._u16[h]; - } - } - void VADDUHS(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - u32 result = (u32)CPU.VPR[va]._u16[h] + (u32)CPU.VPR[vb]._u16[h]; - - if (result > 0xffff) - { - CPU.VPR[vd]._u16[h] = 0xffff; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._u16[h] = result; - } - } - void VADDUWM(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] + CPU.VPR[vb]._u32[w]; - } - } - void VADDUWS(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - u64 result = (u64)CPU.VPR[va]._u32[w] + (u64)CPU.VPR[vb]._u32[w]; - - if (result > 0xffffffff) - { - CPU.VPR[vd]._u32[w] = 0xffffffff; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._u32[w] = (u32)result; - } - } - void VAND(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] & CPU.VPR[vb]._u32[w]; - } - } - void VANDC(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] & (~CPU.VPR[vb]._u32[w]); - } - } - void VAVGSB(u32 vd, u32 va, u32 vb) override //nf - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._s8[b] = (CPU.VPR[va]._s8[b] + CPU.VPR[vb]._s8[b] + 1) >> 1; - } - } - void VAVGSH(u32 vd, u32 va, u32 vb) override //nf - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._s16[h] = (CPU.VPR[va]._s16[h] + CPU.VPR[vb]._s16[h] + 1) >> 1; - } - } - void VAVGSW(u32 vd, u32 va, u32 vb) override //nf - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._s32[w] = ((s64)CPU.VPR[va]._s32[w] + (s64)CPU.VPR[vb]._s32[w] + 1) >> 1; - } - } - void VAVGUB(u32 vd, u32 va, u32 vb) override - { - for (uint b = 0; b < 16; b++) - CPU.VPR[vd]._u8[b] = (CPU.VPR[va]._u8[b] + CPU.VPR[vb]._u8[b] + 1) >> 1; - } - void VAVGUH(u32 vd, u32 va, u32 vb) override //nf - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = (CPU.VPR[va]._u16[h] + CPU.VPR[vb]._u16[h] + 1) >> 1; - } - } - void VAVGUW(u32 vd, u32 va, u32 vb) override //nf - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = ((u64)CPU.VPR[va]._u32[w] + (u64)CPU.VPR[vb]._u32[w] + 1) >> 1; - } - } - void VCFSX(u32 vd, u32 uimm5, u32 vb) override - { - SetHostRoundingMode(FPSCR_RN_NEAR); - u32 scale = 1 << uimm5; - - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._f[w] = ((float)CPU.VPR[vb]._s32[w]) / scale; - } - } - void VCFUX(u32 vd, u32 uimm5, u32 vb) override - { - SetHostRoundingMode(FPSCR_RN_NEAR); - u32 scale = 1 << uimm5; - - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._f[w] = ((float)CPU.VPR[vb]._u32[w]) / scale; - } - } - void VCMPBFP(u32 vd, u32 va, u32 vb, u32 rc) - { - bool allInBounds = true; - - for (uint w = 0; w < 4; w++) - { - u32 mask = 1<<31 | 1<<30; - - const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]); - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - - if (a <= b) mask &= ~(1 << 31); - if (a >= -b) mask &= ~(1 << 30); - - CPU.VPR[vd]._u32[w] = mask; - - if (mask) - allInBounds = false; - } - - if (rc) - { - // Bit n°2 of CR6 - CPU.SetCR(6, 0); - CPU.SetCRBit(6, 0x2, allInBounds); - } - } - void VCMPBFP(u32 vd, u32 va, u32 vb) override {VCMPBFP(vd, va, vb, false);} - void VCMPBFP_(u32 vd, u32 va, u32 vb) override {VCMPBFP(vd, va, vb, true);} - void VCMPEQFP(u32 vd, u32 va, u32 vb, u32 rc) - { - int all_equal = 0x8; - int none_equal = 0x2; - - for (uint w = 0; w < 4; w++) - { - if (CPU.VPR[va]._f[w] == CPU.VPR[vb]._f[w]) - { - CPU.VPR[vd]._u32[w] = 0xffffffff; - none_equal = 0; - } - else - { - CPU.VPR[vd]._u32[w] = 0; - all_equal = 0; - } - } - - if (rc) CPU.CR.cr6 = all_equal | none_equal; - } - void VCMPEQFP(u32 vd, u32 va, u32 vb) override {VCMPEQFP(vd, va, vb, false);} - void VCMPEQFP_(u32 vd, u32 va, u32 vb) override {VCMPEQFP(vd, va, vb, true);} - void VCMPEQUB(u32 vd, u32 va, u32 vb, u32 rc) - { - int all_equal = 0x8; - int none_equal = 0x2; - - for (uint b = 0; b < 16; b++) - { - if (CPU.VPR[va]._u8[b] == CPU.VPR[vb]._u8[b]) - { - CPU.VPR[vd]._u8[b] = 0xff; - none_equal = 0; - } - else - { - CPU.VPR[vd]._u8[b] = 0; - all_equal = 0; - } - } - - if (rc) CPU.CR.cr6 = all_equal | none_equal; - } - void VCMPEQUB(u32 vd, u32 va, u32 vb) override {VCMPEQUB(vd, va, vb, false);} - void VCMPEQUB_(u32 vd, u32 va, u32 vb) override {VCMPEQUB(vd, va, vb, true);} - void VCMPEQUH(u32 vd, u32 va, u32 vb, u32 rc) //nf - { - int all_equal = 0x8; - int none_equal = 0x2; - - for (uint h = 0; h < 8; h++) - { - if (CPU.VPR[va]._u16[h] == CPU.VPR[vb]._u16[h]) - { - CPU.VPR[vd]._u16[h] = 0xffff; - none_equal = 0; - } - else - { - CPU.VPR[vd]._u16[h] = 0; - all_equal = 0; - } - } - - if (rc) CPU.CR.cr6 = all_equal | none_equal; - } - void VCMPEQUH(u32 vd, u32 va, u32 vb) override {VCMPEQUH(vd, va, vb, false);} - void VCMPEQUH_(u32 vd, u32 va, u32 vb) override {VCMPEQUH(vd, va, vb, true);} - void VCMPEQUW(u32 vd, u32 va, u32 vb, u32 rc) - { - int all_equal = 0x8; - int none_equal = 0x2; - - for (uint w = 0; w < 4; w++) - { - if (CPU.VPR[va]._u32[w] == CPU.VPR[vb]._u32[w]) - { - CPU.VPR[vd]._u32[w] = 0xffffffff; - none_equal = 0; - } - else - { - CPU.VPR[vd]._u32[w] = 0; - all_equal = 0; - } - } - - if (rc) CPU.CR.cr6 = all_equal | none_equal; - } - void VCMPEQUW(u32 vd, u32 va, u32 vb) override {VCMPEQUW(vd, va, vb, false);} - void VCMPEQUW_(u32 vd, u32 va, u32 vb) override {VCMPEQUW(vd, va, vb, true);} - void VCMPGEFP(u32 vd, u32 va, u32 vb, u32 rc) - { - int all_ge = 0x8; - int none_ge = 0x2; - - for (uint w = 0; w < 4; w++) - { - if (CPU.VPR[va]._f[w] >= CPU.VPR[vb]._f[w]) - { - CPU.VPR[vd]._u32[w] = 0xffffffff; - none_ge = 0; - } - else - { - CPU.VPR[vd]._u32[w] = 0; - all_ge = 0; - } - } - - if (rc) CPU.CR.cr6 = all_ge | none_ge; - } - void VCMPGEFP(u32 vd, u32 va, u32 vb) override {VCMPGEFP(vd, va, vb, false);} - void VCMPGEFP_(u32 vd, u32 va, u32 vb) override {VCMPGEFP(vd, va, vb, true);} - void VCMPGTFP(u32 vd, u32 va, u32 vb, u32 rc) - { - int all_ge = 0x8; - int none_ge = 0x2; - - for (uint w = 0; w < 4; w++) - { - if (CPU.VPR[va]._f[w] > CPU.VPR[vb]._f[w]) - { - CPU.VPR[vd]._u32[w] = 0xffffffff; - none_ge = 0; - } - else - { - CPU.VPR[vd]._u32[w] = 0; - all_ge = 0; - } - } - - if (rc) CPU.CR.cr6 = all_ge | none_ge; - } - void VCMPGTFP(u32 vd, u32 va, u32 vb) override {VCMPGTFP(vd, va, vb, false);} - void VCMPGTFP_(u32 vd, u32 va, u32 vb) override {VCMPGTFP(vd, va, vb, true);} - void VCMPGTSB(u32 vd, u32 va, u32 vb, u32 rc) //nf - { - int all_gt = 0x8; - int none_gt = 0x2; - - for (uint b = 0; b < 16; b++) - { - if (CPU.VPR[va]._s8[b] > CPU.VPR[vb]._s8[b]) - { - CPU.VPR[vd]._u8[b] = 0xff; - none_gt = 0; - } - else - { - CPU.VPR[vd]._u8[b] = 0; - all_gt = 0; - } - } - - if (rc) CPU.CR.cr6 = all_gt | none_gt; - } - void VCMPGTSB(u32 vd, u32 va, u32 vb) override {VCMPGTSB(vd, va, vb, false);} - void VCMPGTSB_(u32 vd, u32 va, u32 vb) override {VCMPGTSB(vd, va, vb, true);} - void VCMPGTSH(u32 vd, u32 va, u32 vb, u32 rc) - { - int all_gt = 0x8; - int none_gt = 0x2; - - for (uint h = 0; h < 8; h++) - { - if (CPU.VPR[va]._s16[h] > CPU.VPR[vb]._s16[h]) - { - CPU.VPR[vd]._u16[h] = 0xffff; - none_gt = 0; - } - else - { - CPU.VPR[vd]._u16[h] = 0; - all_gt = 0; - } - } - - if (rc) CPU.CR.cr6 = all_gt | none_gt; - } - void VCMPGTSH(u32 vd, u32 va, u32 vb) override {VCMPGTSH(vd, va, vb, false);} - void VCMPGTSH_(u32 vd, u32 va, u32 vb) override {VCMPGTSH(vd, va, vb, true);} - void VCMPGTSW(u32 vd, u32 va, u32 vb, u32 rc) - { - int all_gt = 0x8; - int none_gt = 0x2; - - for (uint w = 0; w < 4; w++) - { - if (CPU.VPR[va]._s32[w] > CPU.VPR[vb]._s32[w]) - { - CPU.VPR[vd]._u32[w] = 0xffffffff; - none_gt = 0; - } - else - { - CPU.VPR[vd]._u32[w] = 0; - all_gt = 0; - } - } - - if (rc) CPU.CR.cr6 = all_gt | none_gt; - } - void VCMPGTSW(u32 vd, u32 va, u32 vb) override {VCMPGTSW(vd, va, vb, false);} - void VCMPGTSW_(u32 vd, u32 va, u32 vb) override {VCMPGTSW(vd, va, vb, true);} - void VCMPGTUB(u32 vd, u32 va, u32 vb, u32 rc) - { - int all_gt = 0x8; - int none_gt = 0x2; - - for (uint b = 0; b < 16; b++) - { - if (CPU.VPR[va]._u8[b] > CPU.VPR[vb]._u8[b]) - { - CPU.VPR[vd]._u8[b] = 0xff; - none_gt = 0; - } - else - { - CPU.VPR[vd]._u8[b] = 0; - all_gt = 0; - } - } - - if (rc) CPU.CR.cr6 = all_gt | none_gt; - } - void VCMPGTUB(u32 vd, u32 va, u32 vb) override {VCMPGTUB(vd, va, vb, false);} - void VCMPGTUB_(u32 vd, u32 va, u32 vb) override {VCMPGTUB(vd, va, vb, true);} - void VCMPGTUH(u32 vd, u32 va, u32 vb, u32 rc) - { - int all_gt = 0x8; - int none_gt = 0x2; - - for (uint h = 0; h < 8; h++) - { - if (CPU.VPR[va]._u16[h] > CPU.VPR[vb]._u16[h]) - { - CPU.VPR[vd]._u16[h] = 0xffff; - none_gt = 0; - } - else - { - CPU.VPR[vd]._u16[h] = 0; - all_gt = 0; - } - } - - if (rc) CPU.CR.cr6 = all_gt | none_gt; - } - void VCMPGTUH(u32 vd, u32 va, u32 vb) override {VCMPGTUH(vd, va, vb, false);} - void VCMPGTUH_(u32 vd, u32 va, u32 vb) override {VCMPGTUH(vd, va, vb, true);} - void VCMPGTUW(u32 vd, u32 va, u32 vb, u32 rc) - { - int all_gt = 0x8; - int none_gt = 0x2; - - for (uint w = 0; w < 4; w++) - { - if (CPU.VPR[va]._u32[w] > CPU.VPR[vb]._u32[w]) - { - CPU.VPR[vd]._u32[w] = 0xffffffff; - none_gt = 0; - } - else - { - CPU.VPR[vd]._u32[w] = 0; - all_gt = 0; - } - } - - if (rc) CPU.CR.cr6 = all_gt | none_gt; - } - void VCMPGTUW(u32 vd, u32 va, u32 vb) override {VCMPGTUW(vd, va, vb, false);} - void VCMPGTUW_(u32 vd, u32 va, u32 vb) override {VCMPGTUW(vd, va, vb, true);} - void VCTSXS(u32 vd, u32 uimm5, u32 vb) override - { - u32 nScale = 1 << uimm5; - - for (uint w = 0; w < 4; w++) - { - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(b)) - { - CPU.VPR[vd]._s32[w] = 0; - } - else - { - double result = (double)b * nScale; - if (result > 0x7fffffff) - { - CPU.VPR[vd]._s32[w] = (int)0x7fffffff; - CPU.VSCR.SAT = 1; - } - else if (result < -pow(2, 31)) - { - CPU.VPR[vd]._s32[w] = (int)0x80000000; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s32[w] = (int)trunc(result); - } - } - } - void VCTUXS(u32 vd, u32 uimm5, u32 vb) override - { - u32 nScale = 1 << uimm5; - - for (uint w = 0; w < 4; w++) - { - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(b)) - { - CPU.VPR[vd]._s32[w] = 0; - } - else - { - double result = (double)b * nScale; - if (result > 0xffffffffu) - { - CPU.VPR[vd]._u32[w] = 0xffffffffu; - CPU.VSCR.SAT = 1; - } - else if (result < 0) - { - CPU.VPR[vd]._u32[w] = 0; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._u32[w] = (u32)trunc(result); - } - } - } - void VEXPTEFP(u32 vd, u32 vb) override - { - // vd = 2^x - // ISA : Note that the value placed into the element of vD may vary between implementations - // and between different executions on the same implementation. - SetHostRoundingMode(FPSCR_RN_NEAR); - for (uint w = 0; w < 4; w++) - { - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else - CPU.VPR[vd]._f[w] = CheckVSCR_NJ(powf(2.0f, b)); - } - } - void VLOGEFP(u32 vd, u32 vb) override - { - // ISA : Note that the value placed into the element of vD may vary between implementations - // and between different executions on the same implementation. - SetHostRoundingMode(FPSCR_RN_NEAR); - for (uint w = 0; w < 4; w++) - { - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else - CPU.VPR[vd]._f[w] = log2f(b); // Can never be denormal. - } - } - void VMADDFP(u32 vd, u32 va, u32 vc, u32 vb) override - { - SetHostRoundingMode(FPSCR_RN_NEAR); - for (uint w = 0; w < 4; w++) - { - const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]); - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - const float c = CheckVSCR_NJ(CPU.VPR[vc]._f[w]); - if (std::isnan(a)) - CPU.VPR[vd]._f[w] = SilenceNaN(a); - else if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else if (std::isnan(c)) - CPU.VPR[vd]._f[w] = SilenceNaN(c); - else if ((std::isinf(a) && c == 0) || (a == 0 && std::isinf(c))) - CPU.VPR[vd]._f[w] = (float)FPR_NAN; - else - { - const float result = fmaf(a, c, b); - if (std::isnan(result)) - CPU.VPR[vd]._f[w] = (float)FPR_NAN; - else - CPU.VPR[vd]._f[w] = CheckVSCR_NJ(result); - } - } - } - void VMAXFP(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]); - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(a)) - CPU.VPR[vd]._f[w] = SilenceNaN(a); - else if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else if (a > b) - CPU.VPR[vd]._f[w] = a; - else if (b > a) - CPU.VPR[vd]._f[w] = b; - else if (CPU.VPR[vb]._u32[w] == 0x80000000) - CPU.VPR[vd]._f[w] = a; // max(+0,-0) = +0 - else - CPU.VPR[vd]._f[w] = b; - } - } - void VMAXSB(u32 vd, u32 va, u32 vb) override //nf - { - for (uint b = 0; b < 16; b++) - CPU.VPR[vd]._s8[b] = std::max(CPU.VPR[va]._s8[b], CPU.VPR[vb]._s8[b]); - } - void VMAXSH(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._s16[h] = std::max(CPU.VPR[va]._s16[h], CPU.VPR[vb]._s16[h]); - } - } - void VMAXSW(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._s32[w] = std::max(CPU.VPR[va]._s32[w], CPU.VPR[vb]._s32[w]); - } - } - void VMAXUB(u32 vd, u32 va, u32 vb) override - { - for (uint b = 0; b < 16; b++) - CPU.VPR[vd]._u8[b] = std::max(CPU.VPR[va]._u8[b], CPU.VPR[vb]._u8[b]); - } - void VMAXUH(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = std::max(CPU.VPR[va]._u16[h], CPU.VPR[vb]._u16[h]); - } - } - void VMAXUW(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = std::max(CPU.VPR[va]._u32[w], CPU.VPR[vb]._u32[w]); - } - } - void VMHADDSHS(u32 vd, u32 va, u32 vb, u32 vc) override - { - for (uint h = 0; h < 8; h++) - { - s32 result = (s32)CPU.VPR[va]._s16[h] * (s32)CPU.VPR[vb]._s16[h]; - result = (result >> 15) + (s32)CPU.VPR[vc]._s16[h]; - - if (result > INT16_MAX) - { - CPU.VPR[vd]._s16[h] = (s16)INT16_MAX; - CPU.VSCR.SAT = 1; - } - else if (result < INT16_MIN) - { - CPU.VPR[vd]._s16[h] = (s16)INT16_MIN; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s16[h] = (s16)result; - } - } - void VMHRADDSHS(u32 vd, u32 va, u32 vb, u32 vc) override - { - for (uint h = 0; h < 8; h++) - { - s32 result = ((s32)CPU.VPR[va]._s16[h] * (s32)CPU.VPR[vb]._s16[h]) + 0x4000; - result = (result >> 15) + (s32)CPU.VPR[vc]._s16[h]; - - if (result > INT16_MAX) - { - CPU.VPR[vd]._s16[h] = (s16)INT16_MAX; - CPU.VSCR.SAT = 1; - } - else if (result < INT16_MIN) - { - CPU.VPR[vd]._s16[h] = (s16)INT16_MIN; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s16[h] = (s16)result; - } - } - void VMINFP(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]); - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(a)) - CPU.VPR[vd]._f[w] = SilenceNaN(a); - else if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else if (a < b) - CPU.VPR[vd]._f[w] = a; - else if (b < a) - CPU.VPR[vd]._f[w] = b; - else if (CPU.VPR[vb]._u32[w] == 0x00000000) - CPU.VPR[vd]._f[w] = a; // min(-0,+0) = -0 - else - CPU.VPR[vd]._f[w] = b; - } - } - void VMINSB(u32 vd, u32 va, u32 vb) override //nf - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._s8[b] = std::min(CPU.VPR[va]._s8[b], CPU.VPR[vb]._s8[b]); - } - } - void VMINSH(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._s16[h] = std::min(CPU.VPR[va]._s16[h], CPU.VPR[vb]._s16[h]); - } - } - void VMINSW(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._s32[w] = std::min(CPU.VPR[va]._s32[w], CPU.VPR[vb]._s32[w]); - } - } - void VMINUB(u32 vd, u32 va, u32 vb)override - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._u8[b] = std::min(CPU.VPR[va]._u8[b], CPU.VPR[vb]._u8[b]); - } - } - void VMINUH(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = std::min(CPU.VPR[va]._u16[h], CPU.VPR[vb]._u16[h]); - } - } - void VMINUW(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = std::min(CPU.VPR[va]._u32[w], CPU.VPR[vb]._u32[w]); - } - } - void VMLADDUHM(u32 vd, u32 va, u32 vb, u32 vc) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = CPU.VPR[va]._u16[h] * CPU.VPR[vb]._u16[h] + CPU.VPR[vc]._u16[h]; - } - } - void VMRGHB(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u8[15 - h*2] = VA._u8[15 - h]; - CPU.VPR[vd]._u8[15 - h*2 - 1] = VB._u8[15 - h]; - } - } - void VMRGHH(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u16[7 - w*2] = VA._u16[7 - w]; - CPU.VPR[vd]._u16[7 - w*2 - 1] = VB._u16[7 - w]; - } - } - void VMRGHW(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint d = 0; d < 2; d++) - { - CPU.VPR[vd]._u32[3 - d*2] = VA._u32[3 - d]; - CPU.VPR[vd]._u32[3 - d*2 - 1] = VB._u32[3 - d]; - } - } - void VMRGLB(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u8[15 - h*2] = VA._u8[7 - h]; - CPU.VPR[vd]._u8[15 - h*2 - 1] = VB._u8[7 - h]; - } - } - void VMRGLH(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u16[7 - w*2] = VA._u16[3 - w]; - CPU.VPR[vd]._u16[7 - w*2 - 1] = VB._u16[3 - w]; - } - } - void VMRGLW(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint d = 0; d < 2; d++) - { - CPU.VPR[vd]._u32[3 - d*2] = VA._u32[1 - d]; - CPU.VPR[vd]._u32[3 - d*2 - 1] = VB._u32[1 - d]; - } - } - void VMSUMMBM(u32 vd, u32 va, u32 vb, u32 vc) override //nf - { - for (uint w = 0; w < 4; w++) - { - s32 result = 0; - - for (uint b = 0; b < 4; b++) - { - result += CPU.VPR[va]._s8[w*4 + b] * CPU.VPR[vb]._u8[w*4 + b]; - } - - result += CPU.VPR[vc]._s32[w]; - CPU.VPR[vd]._s32[w] = result; - } - } - void VMSUMSHM(u32 vd, u32 va, u32 vb, u32 vc) override //nf - { - for (uint w = 0; w < 4; w++) - { - s32 result = 0; - - for (uint h = 0; h < 2; h++) - { - result += CPU.VPR[va]._s16[w*2 + h] * CPU.VPR[vb]._s16[w*2 + h]; - } - - result += CPU.VPR[vc]._s32[w]; - CPU.VPR[vd]._s32[w] = result; - } - } - void VMSUMSHS(u32 vd, u32 va, u32 vb, u32 vc) override //nf - { - for (uint w = 0; w < 4; w++) - { - s64 result = 0; - s32 saturated = 0; - - for (uint h = 0; h < 2; h++) - { - result += CPU.VPR[va]._s16[w*2 + h] * CPU.VPR[vb]._s16[w*2 + h]; - } - - result += CPU.VPR[vc]._s32[w]; - - if (result > 0x7fffffff) - { - saturated = 0x7fffffff; - CPU.VSCR.SAT = 1; - } - else if (result < (s64)(s32)0x80000000) - { - saturated = 0x80000000; - CPU.VSCR.SAT = 1; - } - else - saturated = (s32)result; - - CPU.VPR[vd]._s32[w] = saturated; - } - } - void VMSUMUBM(u32 vd, u32 va, u32 vb, u32 vc) override - { - for (uint w = 0; w < 4; w++) - { - u32 result = 0; - - for (uint b = 0; b < 4; b++) - { - result += (u32)CPU.VPR[va]._u8[w*4 + b] * (u32)CPU.VPR[vb]._u8[w*4 + b]; - } - - result += CPU.VPR[vc]._u32[w]; - CPU.VPR[vd]._u32[w] = result; - } - } - void VMSUMUHM(u32 vd, u32 va, u32 vb, u32 vc) override //nf - { - for (uint w = 0; w < 4; w++) - { - u32 result = 0; - - for (uint h = 0; h < 2; h++) - { - result += (u32)CPU.VPR[va]._u16[w*2 + h] * (u32)CPU.VPR[vb]._u16[w*2 + h]; - } - - result += CPU.VPR[vc]._u32[w]; - CPU.VPR[vd]._u32[w] = result; - } - } - void VMSUMUHS(u32 vd, u32 va, u32 vb, u32 vc) override //nf - { - for (uint w = 0; w < 4; w++) - { - u64 result = 0; - u32 saturated = 0; - - for (uint h = 0; h < 2; h++) - { - result += (u64)CPU.VPR[va]._u16[w*2 + h] * (u64)CPU.VPR[vb]._u16[w*2 + h]; - } - - result += CPU.VPR[vc]._u32[w]; - - if (result > 0xffffffffu) - { - saturated = 0xffffffff; - CPU.VSCR.SAT = 1; - } - else - saturated = (u32)result; - - CPU.VPR[vd]._u32[w] = saturated; - } - } - void VMULESB(u32 vd, u32 va, u32 vb) override //nf - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._s16[h] = (s16)CPU.VPR[va]._s8[h*2+1] * (s16)CPU.VPR[vb]._s8[h*2+1]; - } - } - void VMULESH(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._s32[w] = (s32)CPU.VPR[va]._s16[w*2+1] * (s32)CPU.VPR[vb]._s16[w*2+1]; - } - } - void VMULEUB(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = (u16)CPU.VPR[va]._u8[h*2+1] * (u16)CPU.VPR[vb]._u8[h*2+1]; - } - } - void VMULEUH(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = (u32)CPU.VPR[va]._u16[w*2+1] * (u32)CPU.VPR[vb]._u16[w*2+1]; - } - } - void VMULOSB(u32 vd, u32 va, u32 vb) override //nf - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._s16[h] = (s16)CPU.VPR[va]._s8[h*2] * (s16)CPU.VPR[vb]._s8[h*2]; - } - } - void VMULOSH(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._s32[w] = (s32)CPU.VPR[va]._s16[w*2] * (s32)CPU.VPR[vb]._s16[w*2]; - } - } - void VMULOUB(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = (u16)CPU.VPR[va]._u8[h*2] * (u16)CPU.VPR[vb]._u8[h*2]; - } - } - void VMULOUH(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = (u32)CPU.VPR[va]._u16[w*2] * (u32)CPU.VPR[vb]._u16[w*2]; - } - } - void VNMSUBFP(u32 vd, u32 va, u32 vc, u32 vb) override - { - SetHostRoundingMode(FPSCR_RN_NEAR); - for (uint w = 0; w < 4; w++) - { - const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]); - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - const float c = CheckVSCR_NJ(CPU.VPR[vc]._f[w]); - if (std::isnan(a)) - CPU.VPR[vd]._f[w] = SilenceNaN(a); - else if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else if (std::isnan(c)) - CPU.VPR[vd]._f[w] = SilenceNaN(c); - else if ((std::isinf(a) && c == 0) || (a == 0 && std::isinf(c))) - CPU.VPR[vd]._f[w] = (float)FPR_NAN; - else - { - const float result = -fmaf(a, c, -b); - if (std::isnan(result)) - CPU.VPR[vd]._f[w] = (float)FPR_NAN; - else - CPU.VPR[vd]._f[w] = CheckVSCR_NJ(result); - } - } - } - void VNOR(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = ~(CPU.VPR[va]._u32[w] | CPU.VPR[vb]._u32[w]); - } - } - void VOR(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] | CPU.VPR[vb]._u32[w]; - } - } - void VPERM(u32 vd, u32 va, u32 vb, u32 vc) override - { - u8 tmpSRC[32]; - std::memcpy(tmpSRC, CPU.VPR + vb, 16); - std::memcpy(tmpSRC + 16, CPU.VPR + va, 16); - - for (uint b = 0; b < 16; b++) - { - u8 index = CPU.VPR[vc]._u8[b] & 0x1f; - - CPU.VPR[vd]._u8[b] = tmpSRC[0x1f - index]; - } - } - void VPKPX(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint h = 0; h < 4; h++) - { - u16 bb7 = VB._u8[15 - (h*4 + 0)] & 0x1; - u16 bb8 = VB._u8[15 - (h*4 + 1)] >> 3; - u16 bb16 = VB._u8[15 - (h*4 + 2)] >> 3; - u16 bb24 = VB._u8[15 - (h*4 + 3)] >> 3; - u16 ab7 = VA._u8[15 - (h*4 + 0)] & 0x1; - u16 ab8 = VA._u8[15 - (h*4 + 1)] >> 3; - u16 ab16 = VA._u8[15 - (h*4 + 2)] >> 3; - u16 ab24 = VA._u8[15 - (h*4 + 3)] >> 3; - - CPU.VPR[vd]._u16[3 - h] = (bb7 << 15) | (bb8 << 10) | (bb16 << 5) | bb24; - CPU.VPR[vd]._u16[4 + (3 - h)] = (ab7 << 15) | (ab8 << 10) | (ab16 << 5) | ab24; - } - } - void VPKSHSS(u32 vd, u32 va, u32 vb) override //nf - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint b = 0; b < 8; b++) - { - s16 result = VA._s16[b]; - - if (result > INT8_MAX) - { - result = INT8_MAX; - CPU.VSCR.SAT = 1; - } - else if (result < INT8_MIN) - { - result = INT8_MIN; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._s8[b+8] = (s8)result; - - result = VB._s16[b]; - - if (result > INT8_MAX) - { - result = INT8_MAX; - CPU.VSCR.SAT = 1; - } - else if (result < INT8_MIN) - { - result = INT8_MIN; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._s8[b] = (s8)result; - } - } - void VPKSHUS(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint b = 0; b < 8; b++) - { - s16 result = VA._s16[b]; - - if (result > UINT8_MAX) - { - result = UINT8_MAX; - CPU.VSCR.SAT = 1; - } - else if (result < 0) - { - result = 0; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._u8[b+8] = (u8)result; - - result = VB._s16[b]; - - if (result > UINT8_MAX) - { - result = UINT8_MAX; - CPU.VSCR.SAT = 1; - } - else if (result < 0) - { - result = 0; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._u8[b] = (u8)result; - } - } - void VPKSWSS(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint h = 0; h < 4; h++) - { - s32 result = VA._s32[h]; - - if (result > INT16_MAX) - { - result = INT16_MAX; - CPU.VSCR.SAT = 1; - } - else if (result < INT16_MIN) - { - result = INT16_MIN; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._s16[h+4] = result; - - result = VB._s32[h]; - - if (result > INT16_MAX) - { - result = INT16_MAX; - CPU.VSCR.SAT = 1; - } - else if (result < INT16_MIN) - { - result = INT16_MIN; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._s16[h] = result; - } - } - void VPKSWUS(u32 vd, u32 va, u32 vb) override //nf - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint h = 0; h < 4; h++) - { - s32 result = VA._s32[h]; - - if (result > UINT16_MAX) - { - result = UINT16_MAX; - CPU.VSCR.SAT = 1; - } - else if (result < 0) - { - result = 0; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._u16[h+4] = result; - - result = VB._s32[h]; - - if (result > UINT16_MAX) - { - result = UINT16_MAX; - CPU.VSCR.SAT = 1; - } - else if (result < 0) - { - result = 0; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._u16[h] = result; - } - } - void VPKUHUM(u32 vd, u32 va, u32 vb) override //nf - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint b = 0; b < 8; b++) - { - CPU.VPR[vd]._u8[b+8] = VA._u8[b*2]; - CPU.VPR[vd]._u8[b ] = VB._u8[b*2]; - } - } - void VPKUHUS(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint b = 0; b < 8; b++) - { - u16 result = VA._u16[b]; - - if (result > UINT8_MAX) - { - result = UINT8_MAX; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._u8[b+8] = (u8)result; - - result = VB._u16[b]; - - if (result > UINT8_MAX) - { - result = UINT8_MAX; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._u8[b] = (u8)result; - } - } - void VPKUWUM(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint h = 0; h < 4; h++) - { - CPU.VPR[vd]._u16[h+4] = VA._u16[h*2]; - CPU.VPR[vd]._u16[h ] = VB._u16[h*2]; - } - } - void VPKUWUS(u32 vd, u32 va, u32 vb) override //nf - { - v128 VA = CPU.VPR[va]; - v128 VB = CPU.VPR[vb]; - for (uint h = 0; h < 4; h++) - { - u32 result = VA._u32[h]; - - if (result > UINT16_MAX) - { - result = UINT16_MAX; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._u16[h+4] = result; - - result = VB._u32[h]; - - if (result > UINT16_MAX) - { - result = UINT16_MAX; - CPU.VSCR.SAT = 1; - } - - CPU.VPR[vd]._u16[h] = result; - } - } - void VREFP(u32 vd, u32 vb) override - { - SetHostRoundingMode(FPSCR_RN_NEAR); - for (uint w = 0; w < 4; w++) - { - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else - CPU.VPR[vd]._f[w] = CheckVSCR_NJ(1.0f / b); - } - } - void VRFIM(u32 vd, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else - CPU.VPR[vd]._f[w] = floorf(CPU.VPR[vb]._f[w]); - } - } - void VRFIN(u32 vd, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else - { - SetHostRoundingMode(FPSCR_RN_NEAR); - CPU.VPR[vd]._f[w] = nearbyintf(CPU.VPR[vb]._f[w]); - } - } - } - void VRFIP(u32 vd, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else - CPU.VPR[vd]._f[w] = ceilf(CPU.VPR[vb]._f[w]); - } - } - void VRFIZ(u32 vd, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else - CPU.VPR[vd]._f[w] = truncf(CPU.VPR[vb]._f[w]); - } - } - void VRLB(u32 vd, u32 va, u32 vb) override //nf - { - for (uint b = 0; b < 16; b++) - { - int nRot = CPU.VPR[vb]._u8[b] & 0x7; - - CPU.VPR[vd]._u8[b] = (CPU.VPR[va]._u8[b] << nRot) | (CPU.VPR[va]._u8[b] >> (8 - nRot)); - } - } - void VRLH(u32 vd, u32 va, u32 vb) override //nf - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = rotl16(CPU.VPR[va]._u16[h], CPU.VPR[vb]._u8[h*2] & 0xf); - } - } - void VRLW(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = (u32)rotl32(CPU.VPR[va]._u32[w], CPU.VPR[vb]._u8[w*4] & 0x1f); - } - } - void VRSQRTEFP(u32 vd, u32 vb) override - { - SetHostRoundingMode(FPSCR_RN_NEAR); - for (uint w = 0; w < 4; w++) - { - //TODO: accurate div - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else if (b < 0) - CPU.VPR[vd]._f[w] = (float)FPR_NAN; - else - CPU.VPR[vd]._f[w] = 1.0f / sqrtf(b); // Can never be denormal. - } - } - void VSEL(u32 vd, u32 va, u32 vb, u32 vc) override - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._u8[b] = (CPU.VPR[vb]._u8[b] & CPU.VPR[vc]._u8[b]) | (CPU.VPR[va]._u8[b] & (~CPU.VPR[vc]._u8[b])); - } - } - void VSL(u32 vd, u32 va, u32 vb) override //nf - { - v128 VA = CPU.VPR[va]; - u8 sh = CPU.VPR[vb]._u8[0] & 0x7; - - CPU.VPR[vd]._u8[0] = VA._u8[0] << sh; - for (uint b = 1; b < 16; b++) - { - CPU.VPR[vd]._u8[b] = (VA._u8[b] << sh) | (VA._u8[b-1] >> (8 - sh)); - } - } - void VSLB(u32 vd, u32 va, u32 vb) override - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._u8[b] = CPU.VPR[va]._u8[b] << (CPU.VPR[vb]._u8[b] & 0x7); - } - } - void VSLDOI(u32 vd, u32 va, u32 vb, u32 sh) override - { - u8 tmpSRC[32]; - std::memcpy(tmpSRC, CPU.VPR + vb, 16); - std::memcpy(tmpSRC + 16, CPU.VPR + va, 16); - - for(uint b=0; b<16; b++) - { - CPU.VPR[vd]._u8[15 - b] = tmpSRC[31 - (b + sh)]; - } - } - void VSLH(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = CPU.VPR[va]._u16[h] << (CPU.VPR[vb]._u16[h] & 0xf); - } - } - void VSLO(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - u8 nShift = (CPU.VPR[vb]._u8[0] >> 3) & 0xf; - - CPU.VPR[vd].clear(); - - for (u8 b = 0; b < 16 - nShift; b++) - { - CPU.VPR[vd]._u8[15 - b] = VA._u8[15 - (b + nShift)]; - } - } - void VSLW(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] << (CPU.VPR[vb]._u32[w] & 0x1f); - } - } - void VSPLTB(u32 vd, u32 uimm5, u32 vb) override - { - u8 byte = CPU.VPR[vb]._u8[15 - uimm5]; - - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._u8[b] = byte; - } - } - void VSPLTH(u32 vd, u32 uimm5, u32 vb) override - { - assert(uimm5 < 8); - - u16 hword = CPU.VPR[vb]._u16[7 - uimm5]; - - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = hword; - } - } - void VSPLTISB(u32 vd, s32 simm5) override - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._u8[b] = simm5; - } - } - void VSPLTISH(u32 vd, s32 simm5) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = (s16)simm5; - } - } - void VSPLTISW(u32 vd, s32 simm5) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = (s32)simm5; - } - } - void VSPLTW(u32 vd, u32 uimm5, u32 vb) override - { - assert(uimm5 < 4); - - u32 word = CPU.VPR[vb]._u32[3 - uimm5]; - - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = word; - } - } - void VSR(u32 vd, u32 va, u32 vb) override //nf - { - v128 VA = CPU.VPR[va]; - u8 sh = CPU.VPR[vb]._u8[0] & 0x7; - - CPU.VPR[vd]._u8[15] = VA._u8[15] >> sh; - for (uint b = 14; ~b; b--) - { - CPU.VPR[vd]._u8[b] = (VA._u8[b] >> sh) | (VA._u8[b+1] << (8 - sh)); - } - } - void VSRAB(u32 vd, u32 va, u32 vb) override //nf - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._s8[b] = CPU.VPR[va]._s8[b] >> (CPU.VPR[vb]._u8[b] & 0x7); - } - } - void VSRAH(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._s16[h] = CPU.VPR[va]._s16[h] >> (CPU.VPR[vb]._u16[h] & 0xf); - } - } - void VSRAW(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._s32[w] = CPU.VPR[va]._s32[w] >> (CPU.VPR[vb]._u32[w] & 0x1f); - } - } - void VSRB(u32 vd, u32 va, u32 vb) override - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._u8[b] = CPU.VPR[va]._u8[b] >> (CPU.VPR[vb]._u8[b] & 0x7); - } - } - void VSRH(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = CPU.VPR[va]._u16[h] >> (CPU.VPR[vb]._u16[h] & 0xf); - } - } - void VSRO(u32 vd, u32 va, u32 vb) override - { - v128 VA = CPU.VPR[va]; - u8 nShift = (CPU.VPR[vb]._u8[0] >> 3) & 0xf; - - CPU.VPR[vd].clear(); - - for (u8 b = 0; b < 16 - nShift; b++) - { - CPU.VPR[vd]._u8[b] = VA._u8[b + nShift]; - } - } - void VSRW(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] >> (CPU.VPR[vb]._u32[w] & 0x1f); - } - } - void VSUBCUW(u32 vd, u32 va, u32 vb) override //nf - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] < CPU.VPR[vb]._u32[w] ? 0 : 1; - } - } - void VSUBFP(u32 vd, u32 va, u32 vb) override - { - SetHostRoundingMode(FPSCR_RN_NEAR); - for (uint w = 0; w < 4; w++) - { - const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]); - const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (std::isnan(a)) - CPU.VPR[vd]._f[w] = SilenceNaN(a); - else if (std::isnan(b)) - CPU.VPR[vd]._f[w] = SilenceNaN(b); - else if (std::isinf(a) && std::isinf(b) && a == b) - CPU.VPR[vd]._f[w] = (float)FPR_NAN; - else - CPU.VPR[vd]._f[w] = CheckVSCR_NJ(a - b); - } - } - void VSUBSBS(u32 vd, u32 va, u32 vb) override //nf - { - for (uint b = 0; b < 16; b++) - { - s16 result = (s16)CPU.VPR[va]._s8[b] - (s16)CPU.VPR[vb]._s8[b]; - - if (result < INT8_MIN) - { - CPU.VPR[vd]._s8[b] = INT8_MIN; - CPU.VSCR.SAT = 1; - } - else if (result > INT8_MAX) - { - CPU.VPR[vd]._s8[b] = INT8_MAX; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s8[b] = (s8)result; - } - } - void VSUBSHS(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - s32 result = (s32)CPU.VPR[va]._s16[h] - (s32)CPU.VPR[vb]._s16[h]; - - if (result < INT16_MIN) - { - CPU.VPR[vd]._s16[h] = (s16)INT16_MIN; - CPU.VSCR.SAT = 1; - } - else if (result > INT16_MAX) - { - CPU.VPR[vd]._s16[h] = (s16)INT16_MAX; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s16[h] = (s16)result; - } - } - void VSUBSWS(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - s64 result = (s64)CPU.VPR[va]._s32[w] - (s64)CPU.VPR[vb]._s32[w]; - - if (result < INT32_MIN) - { - CPU.VPR[vd]._s32[w] = (s32)INT32_MIN; - CPU.VSCR.SAT = 1; - } - else if (result > INT32_MAX) - { - CPU.VPR[vd]._s32[w] = (s32)INT32_MAX; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s32[w] = (s32)result; - } - } - void VSUBUBM(u32 vd, u32 va, u32 vb) override - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._u8[b] = (u8)((CPU.VPR[va]._u8[b] - CPU.VPR[vb]._u8[b]) & 0xff); - } - } - void VSUBUBS(u32 vd, u32 va, u32 vb) override - { - for (uint b = 0; b < 16; b++) - { - s16 result = (s16)CPU.VPR[va]._u8[b] - (s16)CPU.VPR[vb]._u8[b]; - - if (result < 0) - { - CPU.VPR[vd]._u8[b] = 0; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._u8[b] = (u8)result; - } - } - void VSUBUHM(u32 vd, u32 va, u32 vb) override - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = CPU.VPR[va]._u16[h] - CPU.VPR[vb]._u16[h]; - } - } - void VSUBUHS(u32 vd, u32 va, u32 vb) override //nf - { - for (uint h = 0; h < 8; h++) - { - s32 result = (s32)CPU.VPR[va]._u16[h] - (s32)CPU.VPR[vb]._u16[h]; - - if (result < 0) - { - CPU.VPR[vd]._u16[h] = 0; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._u16[h] = (u16)result; - } - } - void VSUBUWM(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] - CPU.VPR[vb]._u32[w]; - } - } - void VSUBUWS(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - s64 result = (s64)CPU.VPR[va]._u32[w] - (s64)CPU.VPR[vb]._u32[w]; - - if (result < 0) - { - CPU.VPR[vd]._u32[w] = 0; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._u32[w] = (u32)result; - } - } - void VSUMSWS(u32 vd, u32 va, u32 vb) override - { - s64 sum = CPU.VPR[vb]._s32[0]; - - for (uint w = 0; w < 4; w++) - { - sum += CPU.VPR[va]._s32[w]; - } - - CPU.VPR[vd].clear(); - if (sum > INT32_MAX) - { - CPU.VPR[vd]._s32[0] = (s32)INT32_MAX; - CPU.VSCR.SAT = 1; - } - else if (sum < INT32_MIN) - { - CPU.VPR[vd]._s32[0] = (s32)INT32_MIN; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s32[0] = (s32)sum; - } - void VSUM2SWS(u32 vd, u32 va, u32 vb) override - { - for (uint n = 0; n < 2; n++) - { - s64 sum = (s64)CPU.VPR[va]._s32[n*2] + CPU.VPR[va]._s32[n*2 + 1] + CPU.VPR[vb]._s32[n*2]; - - if (sum > INT32_MAX) - { - CPU.VPR[vd]._s32[n*2] = (s32)INT32_MAX; - CPU.VSCR.SAT = 1; - } - else if (sum < INT32_MIN) - { - CPU.VPR[vd]._s32[n*2] = (s32)INT32_MIN; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s32[n*2] = (s32)sum; - } - CPU.VPR[vd]._s32[1] = 0; - CPU.VPR[vd]._s32[3] = 0; - } - void VSUM4SBS(u32 vd, u32 va, u32 vb) override //nf - { - for (uint w = 0; w < 4; w++) - { - s64 sum = CPU.VPR[vb]._s32[w]; - - for (uint b = 0; b < 4; b++) - { - sum += CPU.VPR[va]._s8[w*4 + b]; - } - - if (sum > INT32_MAX) - { - CPU.VPR[vd]._s32[w] = (s32)INT32_MAX; - CPU.VSCR.SAT = 1; - } - else if (sum < INT32_MIN) - { - CPU.VPR[vd]._s32[w] = (s32)INT32_MIN; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s32[w] = (s32)sum; - } - } - void VSUM4SHS(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - s64 sum = CPU.VPR[vb]._s32[w]; - - for (uint h = 0; h < 2; h++) - { - sum += CPU.VPR[va]._s16[w*2 + h]; - } - - if (sum > INT32_MAX) - { - CPU.VPR[vd]._s32[w] = (s32)INT32_MAX; - CPU.VSCR.SAT = 1; - } - else if (sum < INT32_MIN) - { - CPU.VPR[vd]._s32[w] = (s32)INT32_MIN; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._s32[w] = (s32)sum; - } - } - void VSUM4UBS(u32 vd, u32 va, u32 vb) override - { - for (uint w = 0; w < 4; w++) - { - u64 sum = CPU.VPR[vb]._u32[w]; - - for (uint b = 0; b < 4; b++) - { - sum += CPU.VPR[va]._u8[w*4 + b]; - } - - if (sum > UINT32_MAX) - { - CPU.VPR[vd]._u32[w] = (u32)UINT32_MAX; - CPU.VSCR.SAT = 1; - } - else - CPU.VPR[vd]._u32[w] = (u32)sum; - } - } - void VUPKHPX(u32 vd, u32 vb) override - { - v128 VB = CPU.VPR[vb]; - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._s8[w*4 + 3] = VB._s8[8 + w*2 + 1] >> 7; // signed shift sign extends - CPU.VPR[vd]._u8[w*4 + 2] = (VB._u8[8 + w*2 + 1] >> 2) & 0x1f; - CPU.VPR[vd]._u8[w*4 + 1] = ((VB._u8[8 + w*2 + 1] & 0x3) << 3) | ((VB._u8[8 + w*2 + 0] >> 5) & 0x7); - CPU.VPR[vd]._u8[w*4 + 0] = VB._u8[8 + w*2 + 0] & 0x1f; - } - } - void VUPKHSB(u32 vd, u32 vb) override - { - v128 VB = CPU.VPR[vb]; - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._s16[h] = VB._s8[8 + h]; - } - } - void VUPKHSH(u32 vd, u32 vb) override - { - v128 VB = CPU.VPR[vb]; - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._s32[w] = VB._s16[4 + w]; - } - } - void VUPKLPX(u32 vd, u32 vb) override - { - v128 VB = CPU.VPR[vb]; - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._s8[w*4 + 3] = VB._s8[w*2 + 1] >> 7; // signed shift sign extends - CPU.VPR[vd]._u8[w*4 + 2] = (VB._u8[w*2 + 1] >> 2) & 0x1f; - CPU.VPR[vd]._u8[w*4 + 1] = ((VB._u8[w*2 + 1] & 0x3) << 3) | ((VB._u8[w*2 + 0] >> 5) & 0x7); - CPU.VPR[vd]._u8[w*4 + 0] = VB._u8[w*2 + 0] & 0x1f; - } - } - void VUPKLSB(u32 vd, u32 vb) override //nf - { - v128 VB = CPU.VPR[vb]; - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._s16[h] = VB._s8[h]; - } - } - void VUPKLSH(u32 vd, u32 vb) override - { - v128 VB = CPU.VPR[vb]; - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._s32[w] = VB._s16[w]; - } - } - void VXOR(u32 vd, u32 va, u32 vb) override - { - CPU.VPR[vd]._u32[0] = CPU.VPR[va]._u32[0] ^ CPU.VPR[vb]._u32[0]; - CPU.VPR[vd]._u32[1] = CPU.VPR[va]._u32[1] ^ CPU.VPR[vb]._u32[1]; - CPU.VPR[vd]._u32[2] = CPU.VPR[va]._u32[2] ^ CPU.VPR[vb]._u32[2]; - CPU.VPR[vd]._u32[3] = CPU.VPR[va]._u32[3] ^ CPU.VPR[vb]._u32[3]; - } - static void MULLI_impl(PPUThread *CPU, u32 rd, u32 ra, s32 simm16) - { - CPU->GPR[rd] = (s64)CPU->GPR[ra] * simm16; - } - void MULLI(u32 rd, u32 ra, s32 simm16) override - { - MULLI_impl(&CPU, rd, ra, simm16); - } - static void SUBFIC_impl(PPUThread *CPU, u32 rd, u32 ra, s32 simm16) - { - const u64 RA = CPU->GPR[ra]; - const u64 IMM = (s64)simm16; - CPU->GPR[rd] = ~RA + IMM + 1; - - CPU->XER.CA = CPU->IsCarry(~RA, IMM, 1); - } - void SUBFIC(u32 rd, u32 ra, s32 simm16) override - { - SUBFIC_impl(&CPU, rd, ra, simm16); - } - - static void CMPLI_impl(PPUThread *CPU, u32 crfd, u32 l, u32 ra, u32 uimm16) - { - CPU->UpdateCRnU(l, crfd, CPU->GPR[ra], uimm16); - } - void CMPLI(u32 crfd, u32 l, u32 ra, u32 uimm16) override - { - CMPLI_impl(&CPU, crfd, l, ra, uimm16); - } - - static void CMPI_impl(PPUThread *CPU, u32 crfd, u32 l, u32 ra, s32 simm16) - { - CPU->UpdateCRnS(l, crfd, CPU->GPR[ra], simm16); - } - void CMPI(u32 crfd, u32 l, u32 ra, s32 simm16) override - { - CMPI_impl(&CPU, crfd, l, ra, simm16); - } - - static void ADDIC_impl(PPUThread *CPU, u32 rd, u32 ra, s32 simm16) - { - const u64 RA = CPU->GPR[ra]; - CPU->GPR[rd] = RA + simm16; - CPU->XER.CA = CPU->IsCarry(RA, simm16); - } - void ADDIC(u32 rd, u32 ra, s32 simm16) override - { - ADDIC_impl(&CPU, rd, ra, simm16); - } - static void ADDIC__impl(PPUThread *CPU, u32 rd, u32 ra, s32 simm16) - { - const u64 RA = CPU->GPR[ra]; - CPU->GPR[rd] = RA + simm16; - CPU->XER.CA = CPU->IsCarry(RA, simm16); - CPU->UpdateCR0(CPU->GPR[rd]); - } - void ADDIC_(u32 rd, u32 ra, s32 simm16) override - { - ADDIC__impl(&CPU, rd, ra, simm16); - } - - static void ADDI_impl(PPUThread *CPU, u32 rd, u32 ra, s32 simm16) - { - CPU->GPR[rd] = ra ? ((s64)CPU->GPR[ra] + simm16) : simm16; - } - void ADDI(u32 rd, u32 ra, s32 simm16) override - { - ADDI_impl(&CPU, rd, ra, simm16); - } - - static void ADDIS_impl(PPUThread *CPU, u32 rd, u32 ra, s32 simm16) - { - CPU->GPR[rd] = ra ? ((s64)CPU->GPR[ra] + (static_cast(simm16) << 16)) : (static_cast(simm16) << 16); - } - void ADDIS(u32 rd, u32 ra, s32 simm16) override - { - ADDIS_impl(&CPU, rd, ra, simm16); - } - - void BC(u32 bo, u32 bi, s32 bd, u32 aa, u32 lk) override - { - if (CheckCondition(bo, bi)) - { - const u32 nextLR = CPU.PC + 4; - CPU.PC = branchTarget((aa ? 0 : CPU.PC), bd) - 4; - if(lk) CPU.LR = nextLR; - } - } - void HACK(u32 index) override - { - extern void execute_ppu_func_by_index(PPUThread& ppu, u32 index); - - execute_ppu_func_by_index(CPU, index); - } - void SC(u32 lev) override - { - extern void execute_syscall_by_index(PPUThread& ppu, u64 code); - - switch (lev) - { - case 0x0: execute_syscall_by_index(CPU, CPU.GPR[11]); break; - case 0x1: throw EXCEPTION("HyperCall LV1"); - case 0x3: CPU.fast_stop(); break; - default: throw EXCEPTION("Unknown level (0x%x)", lev); - } - } - void B(s32 ll, u32 aa, u32 lk) override - { - const u32 nextLR = CPU.PC + 4; - CPU.PC = branchTarget(aa ? 0 : CPU.PC, ll) - 4; - if(lk) CPU.LR = nextLR; - } - static void MCRF_impl(PPUThread *CPU, u32 crfd, u32 crfs) - { - CPU->SetCR(crfd, CPU->GetCR(crfs)); - } - void MCRF(u32 crfd, u32 crfs) override - { - MCRF_impl(&CPU, crfd, crfs); - } - void BCLR(u32 bo, u32 bi, u32 bh, u32 lk) override - { - if (CheckCondition(bo, bi)) - { - const u32 nextLR = CPU.PC + 4; - CPU.PC = branchTarget(0, (u32)CPU.LR) - 4; - if(lk) CPU.LR = nextLR; - } - } - static void CRNOR_impl(PPUThread *CPU, u32 crbd, u32 crba, u32 crbb) - { - const u8 v = 1 ^ (CPU->IsCR(crba) | CPU->IsCR(crbb)); - CPU->SetCRBit2(crbd, v & 0x1); - } - void CRNOR(u32 crbd, u32 crba, u32 crbb) override - { - CRNOR_impl(&CPU, crbd, crba, crbb); - } - static void CRANDC_impl(PPUThread *CPU, u32 crbd, u32 crba, u32 crbb) - { - const u8 v = CPU->IsCR(crba) & (1 ^ CPU->IsCR(crbb)); - CPU->SetCRBit2(crbd, v & 0x1); - } - void CRANDC(u32 crbd, u32 crba, u32 crbb) override - { - CRANDC_impl(&CPU, crbd, crba, crbb); - } - void ISYNC() override - { - _mm_mfence(); - } - static void CRXOR_impl(PPUThread *CPU, u32 crbd, u32 crba, u32 crbb) - { - const u8 v = CPU->IsCR(crba) ^ CPU->IsCR(crbb); - CPU->SetCRBit2(crbd, v & 0x1); - } - void CRXOR(u32 crbd, u32 crba, u32 crbb) override - { - CRXOR_impl(&CPU, crbd, crba, crbb); - } - static void CRNAND_impl(PPUThread *CPU, u32 crbd, u32 crba, u32 crbb) - { - const u8 v = 1 ^ (CPU->IsCR(crba) & CPU->IsCR(crbb)); - CPU->SetCRBit2(crbd, v & 0x1); - } - void CRNAND(u32 crbd, u32 crba, u32 crbb)override - { - CRNAND_impl(&CPU, crbd, crba, crbb); - } - static void CRAND_impl(PPUThread *CPU, u32 crbd, u32 crba, u32 crbb) - { - const u8 v = CPU->IsCR(crba) & CPU->IsCR(crbb); - CPU->SetCRBit2(crbd, v & 0x1); - } - void CRAND(u32 crbd, u32 crba, u32 crbb) override - { - CRAND_impl(&CPU, crbd, crba, crbb); - } - static void CREQV_impl(PPUThread *CPU, u32 crbd, u32 crba, u32 crbb) - { - const u8 v = 1 ^ (CPU->IsCR(crba) ^ CPU->IsCR(crbb)); - CPU->SetCRBit2(crbd, v & 0x1); - } - void CREQV(u32 crbd, u32 crba, u32 crbb) override - { - CREQV_impl(&CPU, crbd, crba, crbb); - } - static void CRORC_impl(PPUThread *CPU, u32 crbd, u32 crba, u32 crbb) - { - const u8 v = CPU->IsCR(crba) | (1 ^ CPU->IsCR(crbb)); - CPU->SetCRBit2(crbd, v & 0x1); - } - void CRORC(u32 crbd, u32 crba, u32 crbb) override - { - CRORC_impl(&CPU, crbd, crba, crbb); - } - static void CROR_impl(PPUThread *CPU, u32 crbd, u32 crba, u32 crbb) - { - const u8 v = CPU->IsCR(crba) | CPU->IsCR(crbb); - CPU->SetCRBit2(crbd, v & 0x1); - } - void CROR(u32 crbd, u32 crba, u32 crbb) override - { - CROR_impl(&CPU, crbd, crba, crbb); - } - void BCCTR(u32 bo, u32 bi, u32 bh, u32 lk) override - { - if(bo & 0x10 || CPU.IsCR(bi) == ((bo & 0x8) != 0)) - { - const u32 nextLR = CPU.PC + 4; - CPU.PC = branchTarget(0, (u32)CPU.CTR) - 4; - if(lk) CPU.LR = nextLR; - } - } - static void RLWIMI_impl(PPUThread *CPU, u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) - { - const u64 mask = rotate_mask[32 + mb][32 + me]; - CPU->GPR[ra] = (CPU->GPR[ra] & ~mask) | (rotl32(CPU->GPR[rs], sh) & mask); - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void RLWIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) override - { - RLWIMI_impl(&CPU, ra, rs, sh, mb, me, rc); - } - - static void RLWINM_impl(PPUThread *CPU, u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) - { - CPU->GPR[ra] = rotl32(CPU->GPR[rs], sh) & rotate_mask[32 + mb][32 + me]; - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void RLWINM(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) override - { - RLWINM_impl(&CPU, ra, rs, sh, mb, me, rc); - } - static void RLWNM_impl(PPUThread *CPU, u32 ra, u32 rs, u32 rb, u32 mb, u32 me, u32 rc) - { - CPU->GPR[ra] = rotl32(CPU->GPR[rs], CPU->GPR[rb] & 0x1f) & rotate_mask[32 + mb][32 + me]; - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void RLWNM(u32 ra, u32 rs, u32 rb, u32 mb, u32 me, u32 rc) override - { - RLWNM_impl(&CPU, ra, rs, rb, mb, me, rc); - } - - static void ORI_impl(PPUThread *CPU, u32 ra, u32 rs, u32 uimm16) - { - CPU->GPR[ra] = CPU->GPR[rs] | uimm16; - } - void ORI(u32 ra, u32 rs, u32 uimm16) override - { - ORI_impl(&CPU, ra, rs, uimm16); - } - static void ORIS_impl(PPUThread *CPU, u32 ra, u32 rs, u32 uimm16) - { - CPU->GPR[ra] = CPU->GPR[rs] | ((u64)uimm16 << 16); - } - void ORIS(u32 ra, u32 rs, u32 uimm16) override - { - ORIS_impl(&CPU, ra, rs, uimm16); - } - static void XORI_impl(PPUThread *CPU, u32 ra, u32 rs, u32 uimm16) - { - CPU->GPR[ra] = CPU->GPR[rs] ^ uimm16; - } - void XORI(u32 ra, u32 rs, u32 uimm16) override - { - XORI_impl(&CPU, ra, rs, uimm16); - } - static void XORIS_impl(PPUThread *CPU, u32 ra, u32 rs, u32 uimm16) - { - CPU->GPR[ra] = CPU->GPR[rs] ^ ((u64)uimm16 << 16); - } - void XORIS(u32 ra, u32 rs, u32 uimm16) override - { - XORIS_impl(&CPU, ra, rs, uimm16); - } - static void ANDI__impl(PPUThread *CPU, u32 ra, u32 rs, u32 uimm16) - { - CPU->GPR[ra] = CPU->GPR[rs] & uimm16; - CPU->UpdateCR0(CPU->GPR[ra]); - } - void ANDI_(u32 ra, u32 rs, u32 uimm16) override - { - ANDI__impl(&CPU, ra, rs, uimm16); - } - static void ANDIS__impl(PPUThread *CPU, u32 ra, u32 rs, u32 uimm16) - { - CPU->GPR[ra] = CPU->GPR[rs] & ((u64)uimm16 << 16); - CPU->UpdateCR0(CPU->GPR[ra]); - } - void ANDIS_(u32 ra, u32 rs, u32 uimm16) override - { - ANDIS__impl(&CPU, ra, rs, uimm16); - } - - static - void RLDICL_impl(PPUThread *CPU, u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) - { - CPU->GPR[ra] = rotl64(CPU->GPR[rs], sh) & rotate_mask[mb][63]; - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void RLDICL(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) override - { - RLDICL_impl(&CPU, ra, rs, sh, mb, rc); - } - - static - void RLDICR_impl(PPUThread *CPU, u32 ra, u32 rs, u32 sh, u32 me, u32 rc) - { - CPU->GPR[ra] = rotl64(CPU->GPR[rs], sh) & rotate_mask[0][me]; - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - - void RLDICR(u32 ra, u32 rs, u32 sh, u32 me, u32 rc) override - { - RLDICR_impl(&CPU, ra, rs, sh, me, rc); - } - static void RLDIC_impl(PPUThread *CPU, u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) - { - CPU->GPR[ra] = rotl64(CPU->GPR[rs], sh) & rotate_mask[mb][63 - sh]; - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void RLDIC(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) override - { - RLDIC_impl(&CPU, ra, rs, sh, mb, rc); - } - static void RLDIMI_impl(PPUThread *CPU, u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) - { - const u64 mask = rotate_mask[mb][63 - sh]; - CPU->GPR[ra] = (CPU->GPR[ra] & ~mask) | (rotl64(CPU->GPR[rs], sh) & mask); - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void RLDIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) override - { - RLDIMI_impl(&CPU, ra, rs, sh, mb, rc); - } - static void RLDC_LR_impl(PPUThread *CPU, u32 ra, u32 rs, u32 rb, u32 m_eb, u32 is_r, u32 rc) - { - if (is_r) // rldcr - { - RLDICR_impl(CPU, ra, rs, (u32)(CPU->GPR[rb] & 0x3F), m_eb, rc); - } - else // rldcl - { - RLDICL_impl(CPU, ra, rs, (u32)(CPU->GPR[rb] & 0x3F), m_eb, rc); - } - } - void RLDC_LR(u32 ra, u32 rs, u32 rb, u32 m_eb, u32 is_r, u32 rc) override - { - RLDC_LR_impl(&CPU, ra, rs, rb, m_eb, is_r, rc); - } - - static void CMP_impl(PPUThread *CPU, u32 crfd, u32 l, u32 ra, u32 rb) - { - CPU->UpdateCRnS(l, crfd, CPU->GPR[ra], CPU->GPR[rb]); - } - void CMP(u32 crfd, u32 l, u32 ra, u32 rb) override - { - CMP_impl(&CPU, crfd, l, ra, rb); - } - - void TW(u32 to, u32 ra, u32 rb) override - { - s32 a = (s32)CPU.GPR[ra]; - s32 b = (s32)CPU.GPR[rb]; - - if( (a < b && (to & 0x10)) || - (a > b && (to & 0x8)) || - (a == b && (to & 0x4)) || - ((u32)a < (u32)b && (to & 0x2)) || - ((u32)a > (u32)b && (to & 0x1)) ) - { - throw EXCEPTION("Trap! (tw 0x%x, r%d, r%d)", to, ra, rb); - } - } - void LVSL(u32 vd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - - static const u64 lvsl_values[0x10][2] = - { - {0x08090A0B0C0D0E0F, 0x0001020304050607}, - {0x090A0B0C0D0E0F10, 0x0102030405060708}, - {0x0A0B0C0D0E0F1011, 0x0203040506070809}, - {0x0B0C0D0E0F101112, 0x030405060708090A}, - {0x0C0D0E0F10111213, 0x0405060708090A0B}, - {0x0D0E0F1011121314, 0x05060708090A0B0C}, - {0x0E0F101112131415, 0x060708090A0B0C0D}, - {0x0F10111213141516, 0x0708090A0B0C0D0E}, - {0x1011121314151617, 0x08090A0B0C0D0E0F}, - {0x1112131415161718, 0x090A0B0C0D0E0F10}, - {0x1213141516171819, 0x0A0B0C0D0E0F1011}, - {0x131415161718191A, 0x0B0C0D0E0F101112}, - {0x1415161718191A1B, 0x0C0D0E0F10111213}, - {0x15161718191A1B1C, 0x0D0E0F1011121314}, - {0x161718191A1B1C1D, 0x0E0F101112131415}, - {0x1718191A1B1C1D1E, 0x0F10111213141516}, - }; - - CPU.VPR[vd]._u64[0] = lvsl_values[addr & 0xf][0]; - CPU.VPR[vd]._u64[1] = lvsl_values[addr & 0xf][1]; - } - void LVEBX(u32 vd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.VPR[vd]._u8[15 - (addr & 0xf)] = vm::read8(VM_CAST(addr)); - // It's bad idea to read 128 bit there - } - void SUBFC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - const u64 RA = CPU.GPR[ra]; - const u64 RB = CPU.GPR[rb]; - CPU.GPR[rd] = ~RA + RB + 1; - CPU.XER.CA = CPU.IsCarry(~RA, RB, 1); - if(oe) CPU.SetOV((~RA>>63 == RB>>63) && (~RA>>63 != CPU.GPR[rd]>>63)); - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - void MULHDU(u32 rd, u32 ra, u32 rb, u32 rc) override - { - CPU.GPR[rd] = UMULH64(CPU.GPR[ra], CPU.GPR[rb]); - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - void ADDC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - const u64 RA = CPU.GPR[ra]; - const u64 RB = CPU.GPR[rb]; - CPU.GPR[rd] = RA + RB; - CPU.XER.CA = CPU.IsCarry(RA, RB); - if(oe) CPU.SetOV((RA>>63 == RB>>63) && (RA>>63 != CPU.GPR[rd]>>63)); - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - void MULHWU(u32 rd, u32 ra, u32 rb, u32 rc) override - { - u32 a = (u32)CPU.GPR[ra]; - u32 b = (u32)CPU.GPR[rb]; - CPU.GPR[rd] = ((u64)a * (u64)b) >> 32; - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - - static void MFOCRF_impl(PPUThread *CPU, u32 a, u32 rd, u32 crm) - { - CPU->GPR[rd] = CPU->CR.CR; - } - void MFOCRF(u32 a, u32 rd, u32 crm) override - { - MFOCRF_impl(&CPU, a, rd, crm); - } - static void LWARX_impl(PPUThread *CPU, u32 rd, u32 ra, u32 rb) - { - const u64 addr = ra ? CPU->GPR[ra] + CPU->GPR[rb] : CPU->GPR[rb]; - - be_t value; - vm::reservation_acquire(&value, VM_CAST(addr), sizeof(value)); - - CPU->GPR[rd] = value; - } - void LWARX(u32 rd, u32 ra, u32 rb) override - { - LWARX_impl(&CPU, rd, ra, rb); - } - void LDX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = vm::ps3::read64(VM_CAST(addr)); - } - void LWZX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = vm::ps3::read32(VM_CAST(addr)); - } - void SLW(u32 ra, u32 rs, u32 rb, u32 rc) override - { - u32 n = CPU.GPR[rb] & 0x1f; - u32 r = (u32)rotl32((u32)CPU.GPR[rs], n); - u32 m = ((u32)CPU.GPR[rb] & 0x20) ? 0 : (u32)rotate_mask[32][63 - n]; - - CPU.GPR[ra] = r & m; - - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void CNTLZW(u32 ra, u32 rs, u32 rc) override - { - u32 i; - for(i=0; i < 32; i++) - { - if(CPU.GPR[rs] & (1ULL << (31 - i))) break; - } - - CPU.GPR[ra] = i; - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void SLD(u32 ra, u32 rs, u32 rb, u32 rc) override - { - u32 n = CPU.GPR[rb] & 0x3f; - u64 r = rotl64(CPU.GPR[rs], n); - u64 m = (CPU.GPR[rb] & 0x40) ? 0 : rotate_mask[0][63 - n]; - - CPU.GPR[ra] = r & m; - - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - - static void AND_impl(PPUThread *CPU, u32 ra, u32 rs, u32 rb, u32 rc) - { - CPU->GPR[ra] = CPU->GPR[rs] & CPU->GPR[rb]; - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void AND(u32 ra, u32 rs, u32 rb, u32 rc) override - { - AND_impl(&CPU, ra, rs, rb, rc); - } - - static void CMPL_impl(PPUThread *CPU, u32 crfd, u32 l, u32 ra, u32 rb) - { - CPU->UpdateCRnU(l, crfd, CPU->GPR[ra], CPU->GPR[rb]); - } - void CMPL(u32 crfd, u32 l, u32 ra, u32 rb) override - { - CMPL_impl(&CPU, crfd, l, ra, rb); - } - - void LVSR(u32 vd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - - static const u64 lvsr_values[0x10][2] = - { - {0x18191A1B1C1D1E1F, 0x1011121314151617}, - {0x1718191A1B1C1D1E, 0x0F10111213141516}, - {0x161718191A1B1C1D, 0x0E0F101112131415}, - {0x15161718191A1B1C, 0x0D0E0F1011121314}, - {0x1415161718191A1B, 0x0C0D0E0F10111213}, - {0x131415161718191A, 0x0B0C0D0E0F101112}, - {0x1213141516171819, 0x0A0B0C0D0E0F1011}, - {0x1112131415161718, 0x090A0B0C0D0E0F10}, - {0x1011121314151617, 0x08090A0B0C0D0E0F}, - {0x0F10111213141516, 0x0708090A0B0C0D0E}, - {0x0E0F101112131415, 0x060708090A0B0C0D}, - {0x0D0E0F1011121314, 0x05060708090A0B0C}, - {0x0C0D0E0F10111213, 0x0405060708090A0B}, - {0x0B0C0D0E0F101112, 0x030405060708090A}, - {0x0A0B0C0D0E0F1011, 0x0203040506070809}, - {0x090A0B0C0D0E0F10, 0x0102030405060708}, - }; - - CPU.VPR[vd]._u64[0] = lvsr_values[addr & 0xf][0]; - CPU.VPR[vd]._u64[1] = lvsr_values[addr & 0xf][1]; - } - void LVEHX(u32 vd, u32 ra, u32 rb) override - { - const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~1ULL; - CPU.VPR[vd]._u16[7 - ((addr >> 1) & 0x7)] = vm::ps3::read16(VM_CAST(addr)); - // It's bad idea to read 128 bit there - } - - static void SUBF_impl(PPUThread *CPU, u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - const u64 RA = CPU->GPR[ra]; - const u64 RB = CPU->GPR[rb]; - CPU->GPR[rd] = RB - RA; - if(oe) CPU->SetOV((~RA >> 63 == RB >> 63) && (~RA >> 63 != CPU->GPR[rd] >> 63)); - if(rc) CPU->UpdateCR0(CPU->GPR[rd]); - } - void SUBF(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - SUBF_impl(&CPU, rd, ra, rb, oe, rc); - } - - void LDUX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - CPU.GPR[rd] = vm::ps3::read64(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - void DCBST(u32 ra, u32 rb) override - { - } - void LWZUX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - CPU.GPR[rd] = vm::ps3::read32(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - void CNTLZD(u32 ra, u32 rs, u32 rc) override - { - u32 i; - for(i=0; i < 64; i++) - { - if(CPU.GPR[rs] & (1ULL << (63 - i))) break; - } - - CPU.GPR[ra] = i; - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void ANDC(u32 ra, u32 rs, u32 rb, u32 rc) override - { - CPU.GPR[ra] = CPU.GPR[rs] & ~CPU.GPR[rb]; - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void TD(u32 to, u32 ra, u32 rb) override - { - throw EXCEPTION(""); - } - void LVEWX(u32 vd, u32 ra, u32 rb) override - { - const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~3ULL; - CPU.VPR[vd]._u32[3 - ((addr >> 2) & 0x3)] = vm::ps3::read32(VM_CAST(addr)); - // It's bad idea to read 128 bit there - } - void MULHD(u32 rd, u32 ra, u32 rb, u32 rc) override - { - CPU.GPR[rd] = MULH64(CPU.GPR[ra], CPU.GPR[rb]); - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - void MULHW(u32 rd, u32 ra, u32 rb, u32 rc) override - { - s32 a = (s32)CPU.GPR[ra]; - s32 b = (s32)CPU.GPR[rb]; - CPU.GPR[rd] = ((s64)a * (s64)b) >> 32; - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - void LDARX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - - be_t value; - vm::reservation_acquire(&value, VM_CAST(addr), sizeof(value)); - - CPU.GPR[rd] = value; - } - void DCBF(u32 ra, u32 rb) override - { - } - void LBZX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = vm::read8(VM_CAST(addr)); - } - void LVX(u32 vd, u32 ra, u32 rb) override - { - const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~0xfull; - CPU.VPR[vd] = vm::ps3::_ref(VM_CAST(addr)); - } - - static void NEG_impl(PPUThread *CPU, u32 rd, u32 ra, u32 oe, u32 rc) - { - const u64 RA = CPU->GPR[ra]; - CPU->GPR[rd] = 0 - RA; - if(oe) CPU->SetOV((~RA >> 63 == 0) && (~RA >> 63 != CPU->GPR[rd] >> 63)); - if(rc) CPU->UpdateCR0(CPU->GPR[rd]); - } - void NEG(u32 rd, u32 ra, u32 oe, u32 rc) override - { - NEG_impl(&CPU, rd, ra, oe, rc); - } - - void LBZUX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - CPU.GPR[rd] = vm::read8(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - void NOR(u32 ra, u32 rs, u32 rb, u32 rc) override - { - CPU.GPR[ra] = ~(CPU.GPR[rs] | CPU.GPR[rb]); - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void STVEBX(u32 vs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - const u8 eb = addr & 0xf; - vm::write8(VM_CAST(addr), CPU.VPR[vs]._u8[15 - eb]); - } - void SUBFE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - const u64 RA = CPU.GPR[ra]; - const u64 RB = CPU.GPR[rb]; - CPU.GPR[rd] = ~RA + RB + CPU.XER.CA; - CPU.XER.CA = CPU.IsCarry(~RA, RB, CPU.XER.CA); - if(oe) CPU.SetOV((~RA>>63 == RB>>63) && (~RA>>63 != CPU.GPR[rd]>>63)); - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - void ADDE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - const u64 RA = CPU.GPR[ra]; - const u64 RB = CPU.GPR[rb]; - if (CPU.XER.CA) - { - if (RA == ~0ULL) //-1 - { - CPU.GPR[rd] = RB; - CPU.XER.CA = 1; - } - else - { - CPU.GPR[rd] = RA + 1 + RB; - CPU.XER.CA = CPU.IsCarry(RA + 1, RB); - } - } - else - { - CPU.GPR[rd] = RA + RB; - CPU.XER.CA = CPU.IsCarry(RA, RB); - } - if(oe) CPU.SetOV((RA>>63 == RB>>63) && (RA>>63 != CPU.GPR[rd]>>63)); - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - - static void MTOCRF_impl(PPUThread *CPU, u32 l, u32 crm, u32 rs) - { - if(l) - { - u32 n = 0, count = 0; - for(u32 i=0; i<8; ++i) - { - if (crm & (1 << i)) - { - n = i; - count++; - } - } - - if(count == 1) - { - //CR[4*n : 4*n+3] = RS[32+4*n : 32+4*n+3]; - CPU->SetCR(7 - n, (CPU->GPR[rs] >> (4 * n)) & 0xf); - } - else - CPU->CR.CR = 0; - } - else - { - for(u32 i=0; i<8; ++i) - { - if(crm & (1 << i)) - { - CPU->SetCR(7 - i, (CPU->GPR[rs] >> (i * 4)) & 0xf); - } - } - } - } - void MTOCRF(u32 l, u32 crm, u32 rs) override - { - MTOCRF_impl(&CPU, l, crm, rs); - } - - void STDX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::ps3::write64(VM_CAST(addr), CPU.GPR[rs]); - } - static void STWCX__impl(PPUThread* CPU, u32 rs, u32 ra, u32 rb) - { - const u64 addr = ra ? CPU->GPR[ra] + CPU->GPR[rb] : CPU->GPR[rb]; - - const be_t value = (u32)CPU->GPR[rs]; - CPU->SetCR_EQ(0, vm::reservation_update(VM_CAST(addr), &value, sizeof(value))); - } - void STWCX_(u32 rs, u32 ra, u32 rb) override - { - STWCX__impl(&CPU, rs, ra, rb); - } - void STWX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::ps3::write32(VM_CAST(addr), (u32)CPU.GPR[rs]); - } - void STVEHX(u32 vs, u32 ra, u32 rb) override - { - const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~1ULL; - const u8 eb = (addr & 0xf) >> 1; - vm::ps3::write16(VM_CAST(addr), CPU.VPR[vs]._u16[7 - eb]); - } - void STDUX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - vm::ps3::write64(VM_CAST(addr), CPU.GPR[rs]); - CPU.GPR[ra] = addr; - } - void STWUX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - vm::ps3::write32(VM_CAST(addr), (u32)CPU.GPR[rs]); - CPU.GPR[ra] = addr; - } - void STVEWX(u32 vs, u32 ra, u32 rb) override - { - const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~3ULL; - const u8 eb = (addr & 0xf) >> 2; - vm::ps3::write32(VM_CAST(addr), CPU.VPR[vs]._u32[3 - eb]); - } - void SUBFZE(u32 rd, u32 ra, u32 oe, u32 rc) override - { - const u64 RA = CPU.GPR[ra]; - CPU.GPR[rd] = ~RA + CPU.XER.CA; - CPU.XER.CA = CPU.IsCarry(~RA, CPU.XER.CA); - if(oe) CPU.SetOV((~RA>>63 == 0) && (~RA>>63 != CPU.GPR[rd]>>63)); - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - void ADDZE(u32 rd, u32 ra, u32 oe, u32 rc) override - { - const u64 RA = CPU.GPR[ra]; - CPU.GPR[rd] = RA + CPU.XER.CA; - CPU.XER.CA = CPU.IsCarry(RA, CPU.XER.CA); - if(oe) CPU.SetOV((RA>>63 == 0) && (RA>>63 != CPU.GPR[rd]>>63)); - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - void STDCX_(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - - const be_t value = CPU.GPR[rs]; - CPU.SetCR_EQ(0, vm::reservation_update(VM_CAST(addr), &value, sizeof(value))); - } - void STBX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::write8(VM_CAST(addr), (u8)CPU.GPR[rs]); - } - void STVX(u32 vs, u32 ra, u32 rb) override - { - const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~0xfull; - vm::ps3::_ref(VM_CAST(addr)) = CPU.VPR[vs]; - } - void MULLD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - const s64 RA = CPU.GPR[ra]; - const s64 RB = CPU.GPR[rb]; - CPU.GPR[rd] = (s64)(RA * RB); - if(oe) - { - const s64 high = MULH64(RA, RB); - CPU.SetOV(high != s64(CPU.GPR[rd]) >> 63); - } - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - void SUBFME(u32 rd, u32 ra, u32 oe, u32 rc) override - { - const u64 RA = CPU.GPR[ra]; - CPU.GPR[rd] = ~RA + CPU.XER.CA + ~0ULL; - CPU.XER.CA = CPU.IsCarry(~RA, CPU.XER.CA, ~0ULL); - if(oe) CPU.SetOV((~RA>>63 == 1) && (~RA>>63 != CPU.GPR[rd]>>63)); - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - void ADDME(u32 rd, u32 ra, u32 oe, u32 rc) override - { - const s64 RA = CPU.GPR[ra]; - CPU.GPR[rd] = RA + CPU.XER.CA - 1; - CPU.XER.CA |= RA != 0; - - if(oe) CPU.SetOV((u64(RA)>>63 == 1) && (u64(RA)>>63 != CPU.GPR[rd]>>63)); - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - - static void MULLW_impl(PPUThread *CPU, u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - CPU->GPR[rd] = (s64)((s64)(s32)CPU->GPR[ra] * (s64)(s32)CPU->GPR[rb]); - if(oe) CPU->SetOV(s64(CPU->GPR[rd]) < s64(-1) << 31 || s64(CPU->GPR[rd]) >= s64(1) << 31); - if(rc) CPU->UpdateCR0(CPU->GPR[rd]); - } - void MULLW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - MULLW_impl(&CPU, rd, ra, rb, oe, rc); - } - - void DCBTST(u32 ra, u32 rb, u32 th) override - { - } - void STBUX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - vm::write8(VM_CAST(addr), (u8)CPU.GPR[rs]); - CPU.GPR[ra] = addr; - } - - static void ADD_impl(PPUThread *CPU, u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - const u64 RA = CPU->GPR[ra]; - const u64 RB = CPU->GPR[rb]; - CPU->GPR[rd] = RA + RB; - if(oe) CPU->SetOV((RA >> 63 == RB >> 63) && (RA >> 63 != CPU->GPR[rd] >> 63)); - if(rc) CPU->UpdateCR0(CPU->GPR[rd]); - } - void ADD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - ADD_impl(&CPU, rd, ra, rb, oe, rc); - } - - void DCBT(u32 ra, u32 rb, u32 th) override - { - } - void LHZX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = vm::ps3::read16(VM_CAST(addr)); - } - void EQV(u32 ra, u32 rs, u32 rb, u32 rc) override - { - CPU.GPR[ra] = ~(CPU.GPR[rs] ^ CPU.GPR[rb]); - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void ECIWX(u32 rd, u32 ra, u32 rb) override - { - throw EXCEPTION("Privileged instruction"); - } - void LHZUX(u32 rd, u32 ra, u32 rb)override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = vm::ps3::read16(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - void XOR(u32 ra, u32 rs, u32 rb, u32 rc) override - { - CPU.GPR[ra] = CPU.GPR[rs] ^ CPU.GPR[rb]; - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void MFSPR(u32 rd, u32 spr) override - { - CPU.GPR[rd] = ReadSPR(spr); - } - void LWAX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = (s64)(s32)vm::ps3::read32(VM_CAST(addr)); - } - void DST(u32 ra, u32 rb, u32 strm, u32 t) override - { - } - void LHAX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = (s64)(s16)vm::ps3::read16(VM_CAST(addr)); - } - void LVXL(u32 vd, u32 ra, u32 rb) override - { - const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~0xfull; - CPU.VPR[vd] = vm::ps3::_ref(VM_CAST(addr)); - } - void MFTB(u32 rd, u32 spr) override - { - const u32 n = (spr >> 5) | ((spr & 0x1f) << 5); - - CPU.TB = get_timebased_time(); - switch(n) - { - case 0x10C: CPU.GPR[rd] = CPU.TB; break; - case 0x10D: CPU.GPR[rd] = CPU.TB >> 32; break; - default: throw EXCEPTION("mftb r%d, %d", rd, spr); - } - } - void LWAUX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = (s64)(s32)vm::ps3::read32(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - void DSTST(u32 ra, u32 rb, u32 strm, u32 t) override - { - } - void LHAUX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = (s64)(s16)vm::ps3::read16(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - void STHX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::ps3::write16(VM_CAST(addr), (u16)CPU.GPR[rs]); - } - void ORC(u32 ra, u32 rs, u32 rb, u32 rc) override - { - CPU.GPR[ra] = CPU.GPR[rs] | ~CPU.GPR[rb]; - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void ECOWX(u32 rs, u32 ra, u32 rb) override - { - throw EXCEPTION("Privileged instruction"); - } - void STHUX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - vm::ps3::write16(VM_CAST(addr), (u16)CPU.GPR[rs]); - CPU.GPR[ra] = addr; - } - - static void OR_impl(PPUThread *CPU, u32 ra, u32 rs, u32 rb, u32 rc) - { - CPU->GPR[ra] = CPU->GPR[rs] | CPU->GPR[rb]; - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void OR(u32 ra, u32 rs, u32 rb, u32 rc) override - { - OR_impl(&CPU, ra, rs, rb, rc); - } - - void DIVDU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - const u64 RA = CPU.GPR[ra]; - const u64 RB = CPU.GPR[rb]; - - if(RB == 0) - { - if(oe) CPU.SetOV(true); - CPU.GPR[rd] = 0; - } - else - { - if(oe) CPU.SetOV(false); - CPU.GPR[rd] = RA / RB; - } - - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - - static void DIVWU_impl(PPUThread *CPU, u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - const u32 RA = (u32)CPU->GPR[ra]; - const u32 RB = (u32)CPU->GPR[rb]; - - if(RB == 0) - { - if(oe) CPU->SetOV(true); - CPU->GPR[rd] = 0; - } - else - { - if(oe) CPU->SetOV(false); - CPU->GPR[rd] = RA / RB; - } - - if(rc) CPU->UpdateCR0(CPU->GPR[rd]); - } - void DIVWU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - DIVWU_impl(&CPU, rd, ra, rb, oe, rc); - } - - void MTSPR(u32 spr, u32 rs) override - { - WriteSPR(spr, CPU.GPR[rs]); - } - void DCBI(u32 ra, u32 rb) override - { - } - void NAND(u32 ra, u32 rs, u32 rb, u32 rc) override - { - CPU.GPR[ra] = ~(CPU.GPR[rs] & CPU.GPR[rb]); - - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void STVXL(u32 vs, u32 ra, u32 rb) override - { - const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~0xfull; - vm::ps3::_ref(VM_CAST(addr)) = CPU.VPR[vs]; - } - void DIVD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - const s64 RA = CPU.GPR[ra]; - const s64 RB = CPU.GPR[rb]; - - if (RB == 0 || ((u64)RA == (1ULL << 63) && RB == -1)) - { - if(oe) CPU.SetOV(true); - CPU.GPR[rd] = /*(((u64)RA & (1ULL << 63)) && RB == 0) ? -1 :*/ 0; - } - else - { - if(oe) CPU.SetOV(false); - CPU.GPR[rd] = RA / RB; - } - - if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - } - - static void DIVW_impl(PPUThread *CPU, u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) - { - const s32 RA = (s32)CPU->GPR[ra]; - const s32 RB = (s32)CPU->GPR[rb]; - - if (RB == 0 || ((u32)RA == (1 << 31) && RB == -1)) - { - if(oe) CPU->SetOV(true); - CPU->GPR[rd] = /*(((u32)RA & (1 << 31)) && RB == 0) ? -1 :*/ 0; - } - else - { - if(oe) CPU->SetOV(false); - CPU->GPR[rd] = (u32)(RA / RB); - } - - if(rc) CPU->UpdateCR0(CPU->GPR[rd]); - } - void DIVW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override - { - DIVW_impl(&CPU, rd, ra, rb, oe, rc); - } - - void LVLX(u32 vd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - const u32 eb = addr & 0xf; - - CPU.VPR[vd].clear(); - for (u32 i = 0; i < 16u - eb; ++i) CPU.VPR[vd]._u8[15 - i] = vm::read8(VM_CAST(addr + i)); - } - void LDBRX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = vm::ps3::_ref>(VM_CAST(addr)); - } - void LSWX(u32 rd, u32 ra, u32 rb) override - { - u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - u32 count = CPU.XER.XER & 0x7F; - for (; count >= 4; count -= 4, addr += 4, rd = (rd+1) & 31) - { - CPU.GPR[rd] = vm::ps3::_ref(VM_CAST(addr)); - } - if (count) - { - u32 value = 0; - for (u32 byte = 0; byte < count; byte++) - { - u32 byte_value = vm::ps3::_ref(VM_CAST(addr+byte)); - value |= byte_value << ((3^byte)*8); - } - CPU.GPR[rd] = value; - } - } - void LWBRX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = vm::ps3::_ref>(VM_CAST(addr)); - } - void LFSX(u32 frd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - const f32 val = vm::ps3::_ref(VM_CAST(addr)); - if (!FPRdouble::IsNaN(val)) - { - CPU.FPR[frd] = val; - } - else - { - u64 bits = (u32&)val; - (u64&)CPU.FPR[frd] = (bits & 0x80000000) << 32 | 7ULL << 60 | (bits & 0x7fffffff) << 29; - } - } - void SRW(u32 ra, u32 rs, u32 rb, u32 rc) override - { - u32 n = CPU.GPR[rb] & 0x1f; - u32 r = (u32)rotl32((u32)CPU.GPR[rs], 64 - n); - u32 m = ((u32)CPU.GPR[rb] & 0x20) ? 0 : (u32)rotate_mask[32 + n][63]; - CPU.GPR[ra] = r & m; - - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void SRD(u32 ra, u32 rs, u32 rb, u32 rc) override - { - u32 n = CPU.GPR[rb] & 0x3f; - u64 r = rotl64(CPU.GPR[rs], 64 - n); - u64 m = (CPU.GPR[rb] & 0x40) ? 0 : rotate_mask[n][63]; - CPU.GPR[ra] = r & m; - - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void LVRX(u32 vd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - const u8 eb = addr & 0xf; - - CPU.VPR[vd].clear(); - for (u32 i = 16 - eb; i < 16; ++i) CPU.VPR[vd]._u8[15 - i] = vm::read8(VM_CAST(addr + i - 16)); - } - void LSWI(u32 rd, u32 ra, u32 nb) override - { - u64 addr = ra ? CPU.GPR[ra] : 0; - u64 N = nb ? nb : 32; - u8 reg = rd; - - while (N > 0) - { - if (N > 3) - { - CPU.GPR[reg] = vm::ps3::read32(VM_CAST(addr)); - addr += 4; - N -= 4; - } - else - { - u32 buf = 0; - u32 i = 3; - while (N > 0) - { - N = N - 1; - buf |= vm::read8(VM_CAST(addr)) << (i * 8); - addr++; - i--; - } - CPU.GPR[reg] = buf; - } - reg = (reg + 1) % 32; - } - } - void LFSUX(u32 frd, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - const f32 val = vm::ps3::_ref(VM_CAST(addr)); - if (!FPRdouble::IsNaN(val)) - { - CPU.FPR[frd] = val; - } - else - { - u64 bits = (u32&)val; - (u64&)CPU.FPR[frd] = (bits & 0x80000000) << 32 | 7ULL << 60 | (bits & 0x7fffffff) << 29; - } - CPU.GPR[ra] = addr; - } - void SYNC(u32 l) override - { - _mm_mfence(); - } - void LFDX(u32 frd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.FPR[frd]._double = vm::ps3::_ref(VM_CAST(addr)); - } - void LFDUX(u32 frd, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - CPU.FPR[frd]._double = vm::ps3::_ref(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - void STVLX(u32 vs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - const u32 eb = addr & 0xf; - - for (u32 i = 0; i < 16u - eb; ++i) vm::write8(VM_CAST(addr + i), CPU.VPR[vs]._u8[15 - i]); - } - void STDBRX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::ps3::_ref>(VM_CAST(addr)) = CPU.GPR[rs]; - } - void STSWX(u32 rs, u32 ra, u32 rb) override - { - u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - u32 count = CPU.XER.XER & 0x7F; - for (; count >= 4; count -= 4, addr += 4, rs = (rs+1) & 31) - { - vm::ps3::write32(VM_CAST(addr), (u32)CPU.GPR[rs]); - } - if (count) - { - u32 value = (u32)CPU.GPR[rs]; - for (u32 byte = 0; byte < count; byte++) - { - u32 byte_value = (u8)(value >> ((3^byte)*8)); - vm::write8(VM_CAST(addr+byte), byte_value); - } - } - } - void STWBRX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::ps3::_ref>(VM_CAST(addr)) = (u32)CPU.GPR[rs]; - } - void STFSX(u32 frs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - double val = CPU.FPR[frs]; - if (!FPRdouble::IsNaN(val)) - { - vm::ps3::_ref(VM_CAST(addr)) = (float)val; - } - else - { - u64 bits = (u64&)val; - u32 bits32 = (bits>>32 & 0x80000000) | (bits>>29 & 0x7fffffff); - vm::ps3::_ref(VM_CAST(addr)) = bits32; - } - } - void STVRX(u32 vs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - const u8 eb = addr & 0xf; - - for (u32 i = 16 - eb; i < 16; ++i) vm::write8(VM_CAST(addr + i - 16), CPU.VPR[vs]._u8[15 - i]); - } - void STFSUX(u32 frs, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - double val = CPU.FPR[frs]; - if (!FPRdouble::IsNaN(val)) - { - vm::ps3::_ref(VM_CAST(addr)) = (float)val; - } - else - { - u64 bits = (u64&)val; - u32 bits32 = (bits>>32 & 0x80000000) | (bits>>29 & 0x7fffffff); - vm::ps3::_ref(VM_CAST(addr)) = bits32; - } - CPU.GPR[ra] = addr; - } - void STSWI(u32 rd, u32 ra, u32 nb) override - { - u64 addr = ra ? CPU.GPR[ra] : 0; - u64 N = nb ? nb : 32; - u8 reg = rd; - - while (N > 0) - { - if (N > 3) - { - vm::ps3::write32(VM_CAST(addr), (u32)CPU.GPR[reg]); - addr += 4; - N -= 4; - } - else - { - u32 buf = (u32)CPU.GPR[reg]; - while (N > 0) - { - N = N - 1; - vm::write8(VM_CAST(addr), (0xFF000000 & buf) >> 24); - buf <<= 8; - addr++; - } - } - reg = (reg + 1) % 32; - } - } - void STFDX(u32 frs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::ps3::_ref(VM_CAST(addr)) = CPU.FPR[frs]; - } - void STFDUX(u32 frs, u32 ra, u32 rb) override - { - const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - vm::ps3::_ref(VM_CAST(addr)) = CPU.FPR[frs]; - CPU.GPR[ra] = addr; - } - void LVLXL(u32 vd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - const u32 eb = addr & 0xf; - - CPU.VPR[vd].clear(); - for (u32 i = 0; i < 16u - eb; ++i) CPU.VPR[vd]._u8[15 - i] = vm::read8(VM_CAST(addr + i)); - } - void LHBRX(u32 rd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.GPR[rd] = vm::ps3::_ref>(VM_CAST(addr)); - } - void SRAW(u32 ra, u32 rs, u32 rb, u32 rc) override - { - s32 RS = (s32)CPU.GPR[rs]; - u8 shift = CPU.GPR[rb] & 63; - if (shift > 31) - { - CPU.GPR[ra] = 0 - (RS < 0); - CPU.XER.CA = (RS < 0); - } - else - { - CPU.GPR[ra] = RS >> shift; - CPU.XER.CA = (RS < 0) & ((CPU.GPR[ra] << shift) != RS); - } - - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void SRAD(u32 ra, u32 rs, u32 rb, u32 rc) override - { - s64 RS = CPU.GPR[rs]; - u8 shift = CPU.GPR[rb] & 127; - if (shift > 63) - { - CPU.GPR[ra] = 0 - (RS < 0); - CPU.XER.CA = (RS < 0); - } - else - { - CPU.GPR[ra] = RS >> shift; - CPU.XER.CA = (RS < 0) & ((CPU.GPR[ra] << shift) != RS); - } - - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void LVRXL(u32 vd, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - const u8 eb = addr & 0xf; - - CPU.VPR[vd].clear(); - for (u32 i = 16 - eb; i < 16; ++i) CPU.VPR[vd]._u8[15 - i] = vm::read8(VM_CAST(addr + i - 16)); - } - void DSS(u32 strm, u32 a) override - { - } - - static void SRAWI_impl(PPUThread *CPU, u32 ra, u32 rs, u32 sh, u32 rc) - { - s32 RS = (u32)CPU->GPR[rs]; - CPU->GPR[ra] = RS >> sh; - CPU->XER.CA = (RS < 0) & ((u32)(CPU->GPR[ra] << sh) != RS); - - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void SRAWI(u32 ra, u32 rs, u32 sh, u32 rc) override - { - SRAWI_impl(&CPU, ra, rs, sh, rc); - } - - void SRADI1(u32 ra, u32 rs, u32 sh, u32 rc) override - { - s64 RS = CPU.GPR[rs]; - CPU.GPR[ra] = RS >> sh; - CPU.XER.CA = (RS < 0) & ((CPU.GPR[ra] << sh) != RS); - - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void SRADI2(u32 ra, u32 rs, u32 sh, u32 rc) override - { - SRADI1(ra, rs, sh, rc); - } - void EIEIO() override - { - _mm_mfence(); - } - void STVLXL(u32 vs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - const u32 eb = addr & 0xf; - - for (u32 i = 0; i < 16u - eb; ++i) vm::write8(VM_CAST(addr + i), CPU.VPR[vs]._u8[15 - i]); - } - void STHBRX(u32 rs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::ps3::_ref>(VM_CAST(addr)) = (u16)CPU.GPR[rs]; - } - void EXTSH(u32 ra, u32 rs, u32 rc) override - { - CPU.GPR[ra] = (s64)(s16)CPU.GPR[rs]; - if(rc) CPU.UpdateCR0(CPU.GPR[ra]); - } - void STVRXL(u32 vs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - const u8 eb = addr & 0xf; - - for (u32 i = 16 - eb; i < 16; ++i) vm::write8(VM_CAST(addr + i - 16), CPU.VPR[vs]._u8[15 - i]); - } - - static void EXTSB_impl(PPUThread *CPU, u32 ra, u32 rs, u32 rc) - { - CPU->GPR[ra] = (s64)(s8)CPU->GPR[rs]; - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void EXTSB(u32 ra, u32 rs, u32 rc) override - { - EXTSB_impl(&CPU, ra, rs, rc); - } - - void STFIWX(u32 frs, u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::ps3::write32(VM_CAST(addr), (u32&)CPU.FPR[frs]); - } - - static void EXTSW_impl(PPUThread *CPU, u32 ra, u32 rs, u32 rc) - { - CPU->GPR[ra] = (s64)(s32)CPU->GPR[rs]; - if(rc) CPU->UpdateCR0(CPU->GPR[ra]); - } - void EXTSW(u32 ra, u32 rs, u32 rc) override - { - EXTSW_impl(&CPU, ra, rs, rc); - } - - void ICBI(u32 ra, u32 rs) override - { - // Clear jit for the specified block? Nothing to do in the interpreter. - } - void DCBZ(u32 ra, u32 rb) override - { - const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - - std::memset(vm::base(VM_CAST(addr) & ~127), 0, 128); - } - - static void LWZ_impl(PPUThread *CPU, u32 rd, u32 ra, s32 d) - { - const u64 addr = ra ? CPU->GPR[ra] + d : d; - CPU->GPR[rd] = vm::ps3::read32(VM_CAST(addr)); - } - void LWZ(u32 rd, u32 ra, s32 d) override - { - LWZ_impl(&CPU, rd, ra, d); - } - - void LWZU(u32 rd, u32 ra, s32 d) override - { - const u64 addr = CPU.GPR[ra] + d; - CPU.GPR[rd] = vm::ps3::read32(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - - static void LBZ_impl(PPUThread *CPU, u32 rd, u32 ra, s32 d) - { - const u64 addr = ra ? CPU->GPR[ra] + d : d; - CPU->GPR[rd] = vm::read8(VM_CAST(addr)); - } - void LBZ(u32 rd, u32 ra, s32 d) override - { - LBZ_impl(&CPU, rd, ra, d); - } - - void LBZU(u32 rd, u32 ra, s32 d) override - { - const u64 addr = CPU.GPR[ra] + d; - CPU.GPR[rd] = vm::read8(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - - static void STW_impl(PPUThread *CPU, u32 rs, u32 ra, s32 d) - { - const u64 addr = ra ? CPU->GPR[ra] + d : d; - vm::ps3::write32(VM_CAST(addr), (u32)CPU->GPR[rs]); - } - void STW(u32 rs, u32 ra, s32 d) override - { - STW_impl(&CPU, rs, ra, d); - } - - void STWU(u32 rs, u32 ra, s32 d) override - { - const u64 addr = CPU.GPR[ra] + d; - vm::ps3::write32(VM_CAST(addr), (u32)CPU.GPR[rs]); - CPU.GPR[ra] = addr; - } - void STB(u32 rs, u32 ra, s32 d) override - { - const u64 addr = ra ? CPU.GPR[ra] + d : d; - vm::write8(VM_CAST(addr), (u8)CPU.GPR[rs]); - } - void STBU(u32 rs, u32 ra, s32 d) override - { - const u64 addr = CPU.GPR[ra] + d; - vm::write8(VM_CAST(addr), (u8)CPU.GPR[rs]); - CPU.GPR[ra] = addr; - } - static void LHZ_impl(PPUThread *CPU, u32 rd, u32 ra, s32 d) - { - const u64 addr = ra ? CPU->GPR[ra] + d : d; - CPU->GPR[rd] = vm::ps3::read16(VM_CAST(addr)); - } - void LHZ(u32 rd, u32 ra, s32 d) override - { - LHZ_impl(&CPU, rd, ra, d); - } - void LHZU(u32 rd, u32 ra, s32 d) override - { - const u64 addr = CPU.GPR[ra] + d; - CPU.GPR[rd] = vm::ps3::read16(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - void LHA(u32 rd, u32 ra, s32 d) override - { - const u64 addr = ra ? CPU.GPR[ra] + d : d; - CPU.GPR[rd] = (s64)(s16)vm::ps3::read16(VM_CAST(addr)); - } - void LHAU(u32 rd, u32 ra, s32 d) override - { - const u64 addr = CPU.GPR[ra] + d; - CPU.GPR[rd] = (s64)(s16)vm::ps3::read16(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - void STH(u32 rs, u32 ra, s32 d) override - { - const u64 addr = ra ? CPU.GPR[ra] + d : d; - vm::ps3::write16(VM_CAST(addr), (u16)CPU.GPR[rs]); - } - void STHU(u32 rs, u32 ra, s32 d) override - { - const u64 addr = CPU.GPR[ra] + d; - vm::ps3::write16(VM_CAST(addr), (u16)CPU.GPR[rs]); - CPU.GPR[ra] = addr; - } - void LMW(u32 rd, u32 ra, s32 d) override - { - u64 addr = ra ? CPU.GPR[ra] + d : d; - for(u32 i=rd; i<32; ++i, addr += 4) - { - CPU.GPR[i] = vm::ps3::read32(VM_CAST(addr)); - } - } - void STMW(u32 rs, u32 ra, s32 d) override - { - u64 addr = ra ? CPU.GPR[ra] + d : d; - for(u32 i=rs; i<32; ++i, addr += 4) - { - vm::ps3::write32(VM_CAST(addr), (u32)CPU.GPR[i]); - } - } - - static void LFS_impl(PPUThread *CPU, u32 frd, u32 ra, s32 d) - { - const u64 addr = ra ? CPU->GPR[ra] + d : d; - const f32 val = vm::ps3::_ref(VM_CAST(addr)); - if (!FPRdouble::IsNaN(val)) - { - CPU->FPR[frd] = val; - } - else - { - u64 bits = (u32&)val; - (u64&)CPU->FPR[frd] = (bits & 0x80000000) << 32 | 7ULL << 60 | (bits & 0x7fffffff) << 29; - } - } - void LFS(u32 frd, u32 ra, s32 d) override - { - LFS_impl(&CPU, frd, ra, d); - } - - void LFSU(u32 frd, u32 ra, s32 ds) override - { - const u64 addr = CPU.GPR[ra] + ds; - const f32 val = vm::ps3::_ref(VM_CAST(addr)); - if (!FPRdouble::IsNaN(val)) - { - CPU.FPR[frd] = val; - } - else - { - u64 bits = (u32&)val; - (u64&)CPU.FPR[frd] = (bits & 0x80000000) << 32 | 7ULL << 60 | (bits & 0x7fffffff) << 29; - } - CPU.GPR[ra] = addr; - } - void LFD(u32 frd, u32 ra, s32 d) override - { - const u64 addr = ra ? CPU.GPR[ra] + d : d; - CPU.FPR[frd]._double = vm::ps3::_ref(VM_CAST(addr)); - } - void LFDU(u32 frd, u32 ra, s32 ds) override - { - const u64 addr = CPU.GPR[ra] + ds; - CPU.FPR[frd]._double = vm::ps3::_ref(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - - static void STFS_impl(PPUThread *CPU, u32 frs, u32 ra, s32 d) - { - const u64 addr = ra ? CPU->GPR[ra] + d : d; - double val = CPU->FPR[frs]; - if (!FPRdouble::IsNaN(val)) - { - vm::ps3::_ref(VM_CAST(addr)) = (float)val; - } - else - { - u64 bits = (u64&)val; - u32 bits32 = (bits>>32 & 0x80000000) | (bits>>29 & 0x7fffffff); - vm::ps3::_ref(VM_CAST(addr)) = bits32; - } - } - void STFS(u32 frs, u32 ra, s32 d) override - { - STFS_impl(&CPU, frs, ra, d); - } - - void STFSU(u32 frs, u32 ra, s32 d) override - { - const u64 addr = CPU.GPR[ra] + d; - double val = CPU.FPR[frs]; - if (!FPRdouble::IsNaN(val)) - { - vm::ps3::_ref(VM_CAST(addr)) = (float)val; - } - else - { - u64 bits = (u64&)val; - u32 bits32 = (bits>>32 & 0x80000000) | (bits>>29 & 0x7fffffff); - vm::ps3::_ref(VM_CAST(addr)) = bits32; - } - CPU.GPR[ra] = addr; - } - void STFD(u32 frs, u32 ra, s32 d) override - { - const u64 addr = ra ? CPU.GPR[ra] + d : d; - vm::ps3::_ref(VM_CAST(addr)) = CPU.FPR[frs]; - } - void STFDU(u32 frs, u32 ra, s32 d) override - { - const u64 addr = CPU.GPR[ra] + d; - vm::ps3::_ref(VM_CAST(addr)) = CPU.FPR[frs]; - CPU.GPR[ra] = addr; - } - - static void LD_impl(PPUThread *CPU, u32 rd, u32 ra, s32 ds) - { - const u64 addr = ra ? CPU->GPR[ra] + ds : ds; - CPU->GPR[rd] = vm::ps3::read64(VM_CAST(addr)); - } - void LD(u32 rd, u32 ra, s32 ds) override - { - LD_impl(&CPU, rd, ra, ds); - } - - void LDU(u32 rd, u32 ra, s32 ds) override - { - const u64 addr = CPU.GPR[ra] + ds; - CPU.GPR[rd] = vm::ps3::read64(VM_CAST(addr)); - CPU.GPR[ra] = addr; - } - void LWA(u32 rd, u32 ra, s32 ds) override - { - const u64 addr = ra ? CPU.GPR[ra] + ds : ds; - CPU.GPR[rd] = (s64)(s32)vm::ps3::read32(VM_CAST(addr)); - } - void FDIVS(u32 frd, u32 fra, u32 frb, u32 rc) override {FDIV(frd, fra, frb, rc, true);} - void FSUBS(u32 frd, u32 fra, u32 frb, u32 rc) override {FSUB(frd, fra, frb, rc, true);} - void FADDS(u32 frd, u32 fra, u32 frb, u32 rc) override {FADD(frd, fra, frb, rc, true);} - void FSQRTS(u32 frd, u32 frb, u32 rc) override {FSQRT(frd, frb, rc, true);} - void FRES(u32 frd, u32 frb, u32 rc) override - { - SetHostRoundingMode(CPU.FPSCR.RN); - const double b = CPU.FPR[frb]; - if(FPRdouble::IsSNaN(b)) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - } - if(FPRdouble::IsNaN(b)) - { - CPU.FPR[frd] = SilenceNaN(b); - } - else if(b == 0.0) - { - CPU.SetFPSCRException(FPSCR_ZX); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if (CPU.FPSCR.ZE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = 1.0 / b; - } - else - { - feclearexcept(FE_ALL_EXCEPT); - CPU.FPR[frd] = static_cast(1.0 / b); - CheckHostFPExceptions(); - } - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) CPU.UpdateCR1(); - } - void FMULS(u32 frd, u32 fra, u32 frc, u32 rc) override {FMUL(frd, fra, frc, rc, true);} - void FMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override {FMADD(frd, fra, frc, frb, rc, false, false, true);} - void FMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override {FMADD(frd, fra, frc, frb, rc, false, true, true);} - void FNMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override {FMADD(frd, fra, frc, frb, rc, true, true, true);} - void FNMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override {FMADD(frd, fra, frc, frb, rc, true, false, true);} - - static void STD_impl(PPUThread *CPU, u32 rs, u32 ra, s32 d) - { - const u64 addr = ra ? CPU->GPR[ra] + d : d; - vm::ps3::write64(VM_CAST(addr), CPU->GPR[rs]); - } - - void STD(u32 rs, u32 ra, s32 d) override - { - STD_impl(&CPU, rs, ra, d); - } - - static void STDU_impl(PPUThread *CPU, u32 rs, u32 ra, s32 ds) - { - const u64 addr = CPU->GPR[ra] + ds; - vm::ps3::write64(VM_CAST(addr), CPU->GPR[rs]); - CPU->GPR[ra] = addr; - } - - void STDU(u32 rs, u32 ra, s32 ds) override - { - STDU_impl(&CPU, rs, ra, ds); - } - - void MTFSB1(u32 crbd, u32 rc) override - { - u32 mask = 1 << (31 - crbd); - if ((crbd >= 3 && crbd <= 6) && !(CPU.FPSCR.FPSCR & mask)) mask |= 1 << 31; //FPSCR.FX - if ((crbd == 29) && !CPU.FPSCR.NI) LOG_WARNING(PPU, "Non-IEEE mode enabled"); - CPU.SetFPSCR(CPU.FPSCR.FPSCR | mask); - - if(rc) CPU.UpdateCR1(); - } - void MCRFS(u32 crbd, u32 crbs) override - { - CPU.SetCR(crbd, (CPU.FPSCR.FPSCR >> ((7 - crbs) * 4)) & 0xf); - const u32 exceptions_mask = 0x9FF80700; - CPU.SetFPSCR(CPU.FPSCR.FPSCR & ~(exceptions_mask & 0xf << ((7 - crbs) * 4))); - } - void MTFSB0(u32 crbd, u32 rc) override - { - u32 mask = 1 << (31 - crbd); - if ((crbd == 29) && !CPU.FPSCR.NI) LOG_WARNING(PPU, "Non-IEEE mode disabled"); - CPU.SetFPSCR(CPU.FPSCR.FPSCR & ~mask); - - if(rc) CPU.UpdateCR1(); - } - void MTFSFI(u32 crfd, u32 i, u32 rc) override - { - u32 mask = 0xF0000000 >> (crfd * 4); - u32 val = (i & 0xF) << ((7 - crfd) * 4); - - const u32 oldNI = CPU.FPSCR.NI; - CPU.SetFPSCR((CPU.FPSCR.FPSCR & ~mask) | val); - if (CPU.FPSCR.NI != oldNI) - { - if (oldNI) - LOG_WARNING(PPU, "Non-IEEE mode disabled"); - else - LOG_WARNING(PPU, "Non-IEEE mode enabled"); - } - - if(rc) CPU.UpdateCR1(); - } - void MFFS(u32 frd, u32 rc) override - { - (u64&)CPU.FPR[frd] = CPU.FPSCR.FPSCR; - if(rc) CPU.UpdateCR1(); - } - void MTFSF(u32 flm, u32 frb, u32 rc) override - { - u32 mask = 0; - for(u32 i=0; i<8; ++i) - { - if(flm & (1 << i)) mask |= 0xf << (i * 4); - } - mask &= ~0x60000000; - - const u32 oldNI = CPU.FPSCR.NI; - CPU.SetFPSCR((CPU.FPSCR.FPSCR & ~mask) | ((u32&)CPU.FPR[frb] & mask)); - if (CPU.FPSCR.NI != oldNI) - { - if (oldNI) - LOG_WARNING(PPU, "Non-IEEE mode disabled"); - else - LOG_WARNING(PPU, "Non-IEEE mode enabled"); - } - if(rc) CPU.UpdateCR1(); - } - void FCMPU(u32 crfd, u32 fra, u32 frb) override - { - int cmp_res = FPRdouble::Cmp(CPU.FPR[fra], CPU.FPR[frb]); - - if(cmp_res == CR_SO) - { - if(FPRdouble::IsSNaN(CPU.FPR[fra]) || FPRdouble::IsSNaN(CPU.FPR[frb])) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - } - } - - CPU.FPSCR.FPRF = cmp_res; - CPU.SetCR(crfd, cmp_res); - } - void FRSP(u32 frd, u32 frb, u32 rc) override - { - SetHostRoundingMode(CPU.FPSCR.RN); - const double b = CPU.FPR[frb]; - if (FPRdouble::IsSNaN(b)) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if (CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - } - double b0 = b; - if(CPU.FPSCR.NI) - { - if (((u64&)b0 & DOUBLE_EXP) < 0x3800000000000000ULL) (u64&)b0 &= DOUBLE_SIGN; - } - feclearexcept(FE_ALL_EXCEPT); - const double r = static_cast(b0); - if (FPRdouble::IsNaN(r)) - { - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - } - else - { - CPU.FPSCR.FR = fabs(r) > fabs(b); - CheckHostFPExceptions(); - } - u32 type = PPCdouble(r).GetType(); - if (type == FPR_PN && r < ldexp(1.0, -126)) type = FPR_PD; - else if (type == FPR_NN && r > ldexp(-1.0, -126)) type = FPR_ND; - CPU.FPSCR.FPRF = type; - CPU.FPR[frd] = r; - if(rc) CPU.UpdateCR1(); - } - void FCTIW(u32 frd, u32 frb, u32 rc) override {FCTIW(frd, frb, rc, false);} - void FCTIW(u32 frd, u32 frb, u32 rc, bool truncate) - { - const double b = CPU.FPR[frb]; - u32 r; - if (FPRdouble::IsNaN(b) || b < -(double)0x80000000) - { - CPU.SetFPSCRException(FPSCR_VXCVI); - if(FPRdouble::IsSNaN(b)) CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FI = 0; - CPU.FPSCR.FR = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - r = 0x80000000; - } - else if(b > (double)0x7fffffff) - { - CPU.SetFPSCRException(FPSCR_VXCVI); - CPU.FPSCR.FI = 0; - CPU.FPSCR.FR = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - r = 0x7fffffff; - } - else - { - s32 i = 0; - const u32 rn = truncate ? FPSCR_RN_ZERO : CPU.FPSCR.RN; - switch(rn) - { - case FPSCR_RN_NEAR: - SetHostRoundingMode(FPSCR_RN_NEAR); - i = (s32)nearbyint(b); - break; - case FPSCR_RN_ZERO: - i = (s32)b; - break; - case FPSCR_RN_PINF: - i = (s32)ceil(b); - break; - case FPSCR_RN_MINF: - i = (s32)floor(b); - break; - } - r = (u32)i; - double di = i; - if (di == b) - { - CPU.SetFPSCR_FI(0); - CPU.FPSCR.FR = 0; - } - else - { - CPU.SetFPSCR_FI(1); - CPU.FPSCR.FR = fabs(di) > fabs(b); - } - } - - (u64&)CPU.FPR[frd] = r; - if(rc) CPU.UpdateCR1(); - } - void FCTIWZ(u32 frd, u32 frb, u32 rc) override {FCTIW(frd, frb, rc, true);} - void FDIV(u32 frd, u32 fra, u32 frb, u32 rc) override {FDIV(frd, fra, frb, rc, false);} - void FDIV(u32 frd, u32 fra, u32 frb, u32 rc, bool single) - { - SetHostRoundingMode(CPU.FPSCR.RN); - const double a = CPU.FPR[fra]; - const double b = CPU.FPR[frb]; - if(FPRdouble::IsSNaN(a) || FPRdouble::IsSNaN(b)) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - } - if(FPRdouble::IsNaN(a)) - { - CPU.FPR[frd] = SilenceNaN(a); - } - else if(FPRdouble::IsNaN(b)) - { - CPU.FPR[frd] = SilenceNaN(b); - } - else if(a == 0.0 && b == 0.0) - { - CPU.SetFPSCRException(FPSCR_VXZDZ); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = FPR_NAN; - } - else if(FPRdouble::IsINF(a) && FPRdouble::IsINF(b)) - { - CPU.SetFPSCRException(FPSCR_VXIDI); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = FPR_NAN; - } - else - { - if(b == 0.0) - { - CPU.SetFPSCRException(FPSCR_ZX); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if (CPU.FPSCR.ZE) - { - if(rc) CPU.UpdateCR1(); - return; - } - } - feclearexcept(FE_ALL_EXCEPT); - const double res = a / b; - if(single) CPU.FPR[frd] = (float)res; - else CPU.FPR[frd] = res; - CheckHostFPExceptions(); - } - - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) CPU.UpdateCR1(); - } - void FSUB(u32 frd, u32 fra, u32 frb, u32 rc) override {FSUB(frd, fra, frb, rc, false);} - void FSUB(u32 frd, u32 fra, u32 frb, u32 rc, bool single) - { - SetHostRoundingMode(CPU.FPSCR.RN); - const double a = CPU.FPR[fra]; - const double b = CPU.FPR[frb]; - if(FPRdouble::IsSNaN(a) || FPRdouble::IsSNaN(b)) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - } - if(FPRdouble::IsNaN(a)) - { - CPU.FPR[frd] = SilenceNaN(a); - } - else if(FPRdouble::IsNaN(b)) - { - CPU.FPR[frd] = SilenceNaN(b); - } - else if(FPRdouble::IsINF(a) && FPRdouble::IsINF(b) && a == b) - { - CPU.SetFPSCRException(FPSCR_VXISI); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = FPR_NAN; - } - else - { - feclearexcept(FE_ALL_EXCEPT); - const double res = a - b; - if(single) CPU.FPR[frd] = (float)res; - else CPU.FPR[frd] = res; - CheckHostFPExceptions(); - } - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) CPU.UpdateCR1(); - } - void FADD(u32 frd, u32 fra, u32 frb, u32 rc) override {FADD(frd, fra, frb, rc, false);} - void FADD(u32 frd, u32 fra, u32 frb, u32 rc, bool single) - { - SetHostRoundingMode(CPU.FPSCR.RN); - const double a = CPU.FPR[fra]; - const double b = CPU.FPR[frb]; - if(FPRdouble::IsSNaN(a) || FPRdouble::IsSNaN(b)) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - } - if(FPRdouble::IsNaN(a)) - { - CPU.FPR[frd] = SilenceNaN(a); - } - else if(FPRdouble::IsNaN(b)) - { - CPU.FPR[frd] = SilenceNaN(b); - } - else if(FPRdouble::IsINF(a) && FPRdouble::IsINF(b) && a != b) - { - CPU.SetFPSCRException(FPSCR_VXISI); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = FPR_NAN; - } - else - { - feclearexcept(FE_ALL_EXCEPT); - const double res = a + b; - if(single) CPU.FPR[frd] = (float)res; - else CPU.FPR[frd] = res; - CheckHostFPExceptions(); - } - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) CPU.UpdateCR1(); - } - void FSQRT(u32 frd, u32 frb, u32 rc) override {FSQRT(frd, frb, rc, false);} - void FSQRT(u32 frd, u32 frb, u32 rc, bool single) - { - SetHostRoundingMode(CPU.FPSCR.RN); - const double b = CPU.FPR[frb]; - if(FPRdouble::IsSNaN(b)) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - } - if(FPRdouble::IsNaN(b)) - { - CPU.FPR[frd] = SilenceNaN(b); - } - else if(b < 0.0) - { - CPU.SetFPSCRException(FPSCR_VXSQRT); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = FPR_NAN; - } - else - { - feclearexcept(FE_ALL_EXCEPT); - const double res = sqrt(b); - if(single) CPU.FPR[frd] = (float)res; - else CPU.FPR[frd] = res; - CheckHostFPExceptions(); - } - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) CPU.UpdateCR1(); - } - void FSEL(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override - { - CPU.FPR[frd] = CPU.FPR[fra] >= 0.0 ? CPU.FPR[frc] : CPU.FPR[frb]; - if(rc) CPU.UpdateCR1(); - } - void FMUL(u32 frd, u32 fra, u32 frc, u32 rc) override {FMUL(frd, fra, frc, rc, false);} - void FMUL(u32 frd, u32 fra, u32 frc, u32 rc, bool single) - { - SetHostRoundingMode(CPU.FPSCR.RN); - const double a = CPU.FPR[fra]; - const double c = CPU.FPR[frc]; - if(FPRdouble::IsSNaN(a) || FPRdouble::IsSNaN(c)) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - } - if(FPRdouble::IsNaN(a)) - { - CPU.FPR[frd] = SilenceNaN(a); - } - else if(FPRdouble::IsNaN(c)) - { - CPU.FPR[frd] = SilenceNaN(c); - } - else if((FPRdouble::IsINF(a) && c == 0.0) || (a == 0.0 && FPRdouble::IsINF(c))) - { - CPU.SetFPSCRException(FPSCR_VXIMZ); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = FPR_NAN; - } - else - { - feclearexcept(FE_ALL_EXCEPT); - const double res = a * c; - if(single) CPU.FPR[frd] = (float)res; - else CPU.FPR[frd] = res; - CheckHostFPExceptions(); - } - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) CPU.UpdateCR1(); - } - void FRSQRTE(u32 frd, u32 frb, u32 rc) override - { - SetHostRoundingMode(CPU.FPSCR.RN); - const double b = CPU.FPR[frb]; - if(FPRdouble::IsSNaN(b)) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - } - if(FPRdouble::IsNaN(b)) - { - CPU.FPR[frd] = SilenceNaN(b); - } - else if(b < 0.0) - { - CPU.SetFPSCRException(FPSCR_VXSQRT); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = FPR_NAN; - } - else if(b == 0.0) - { - CPU.SetFPSCRException(FPSCR_ZX); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if (CPU.FPSCR.ZE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = 1.0 / b; - } - else - { - feclearexcept(FE_ALL_EXCEPT); - CPU.FPR[frd] = 1.0 / sqrt(b); - CheckHostFPExceptions(); - } - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) CPU.UpdateCR1(); - } - void FMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override {FMADD(frd, fra, frc, frb, rc, false, true, false);} - void FMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override {FMADD(frd, fra, frc, frb, rc, false, false, false);} - void FMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc, bool neg, bool sub, bool single) - { - SetHostRoundingMode(CPU.FPSCR.RN); - const double a = CPU.FPR[fra]; - const double b = CPU.FPR[frb]; - const double c = CPU.FPR[frc]; - if(FPRdouble::IsSNaN(a) || FPRdouble::IsSNaN(b) || FPRdouble::IsSNaN(c)) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - } - if(FPRdouble::IsNaN(a)) - { - CPU.FPR[frd] = SilenceNaN(a); - } - else if(FPRdouble::IsNaN(b)) - { - CPU.FPR[frd] = SilenceNaN(b); - } - else if(FPRdouble::IsNaN(c)) - { - CPU.FPR[frd] = SilenceNaN(c); - } - else if((FPRdouble::IsINF(a) && c == 0.0) || (a == 0.0 && FPRdouble::IsINF(c))) - { - CPU.SetFPSCRException(FPSCR_VXIMZ); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = FPR_NAN; - } - else - { - const double res = fma(a, c, sub ? -b : b); - if(FPRdouble::IsNaN(res)) - { - CPU.SetFPSCRException(FPSCR_VXISI); - CPU.FPSCR.FR = 0; - CPU.FPSCR.FI = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - CPU.FPR[frd] = FPR_NAN; - } - else - { - feclearexcept(FE_ALL_EXCEPT); - if(single) CPU.FPR[frd] = (float)(neg ? -res : res); - else CPU.FPR[frd] = (neg ? -res : res); - CheckHostFPExceptions(); - } - } - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) CPU.UpdateCR1(); - } - void FNMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override {FMADD(frd, fra, frc, frb, rc, true, true, false);} - void FNMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override {FMADD(frd, fra, frc, frb, rc, true, false, false);} - void FCMPO(u32 crfd, u32 fra, u32 frb) override - { - int cmp_res = FPRdouble::Cmp(CPU.FPR[fra], CPU.FPR[frb]); - - if(cmp_res == CR_SO) - { - if(FPRdouble::IsSNaN(CPU.FPR[fra]) || FPRdouble::IsSNaN(CPU.FPR[frb])) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - if(!CPU.FPSCR.VE) CPU.SetFPSCRException(FPSCR_VXVC); - } - else - { - CPU.SetFPSCRException(FPSCR_VXVC); - } - - CPU.FPSCR.FX = 1; - } - - CPU.FPSCR.FPRF = cmp_res; - CPU.SetCR(crfd, cmp_res); - } - void FNEG(u32 frd, u32 frb, u32 rc) override - { - CPU.FPR[frd] = -CPU.FPR[frb]; - if(rc) CPU.UpdateCR1(); - } - void FMR(u32 frd, u32 frb, u32 rc) override - { - CPU.FPR[frd] = CPU.FPR[frb]; - if(rc) CPU.UpdateCR1(); - } - void FNABS(u32 frd, u32 frb, u32 rc) override - { - CPU.FPR[frd] = -fabs(CPU.FPR[frb]); - if(rc) CPU.UpdateCR1(); - } - void FABS(u32 frd, u32 frb, u32 rc) override - { - CPU.FPR[frd] = fabs(CPU.FPR[frb]); - if(rc) CPU.UpdateCR1(); - } - void FCTID(u32 frd, u32 frb, u32 rc) override {FCTID(frd, frb, rc, false);} - void FCTID(u32 frd, u32 frb, u32 rc, bool truncate) - { - const double b = CPU.FPR[frb]; - u64 r; - if (FPRdouble::IsNaN(b) || b < -(double)0x8000000000000000) - { - CPU.SetFPSCRException(FPSCR_VXCVI); - if(FPRdouble::IsSNaN(b)) CPU.SetFPSCRException(FPSCR_VXSNAN); - CPU.FPSCR.FI = 0; - CPU.FPSCR.FR = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - r = 0x8000000000000000; - } - else if(b >= (double)0x8000000000000000) - { - CPU.SetFPSCRException(FPSCR_VXCVI); - CPU.FPSCR.FI = 0; - CPU.FPSCR.FR = 0; - if(CPU.FPSCR.VE) - { - if(rc) CPU.UpdateCR1(); - return; - } - r = 0x7fffffffffffffff; - } - else - { - s64 i = 0; - const u32 rn = truncate ? FPSCR_RN_ZERO : CPU.FPSCR.RN; - switch(rn) - { - case FPSCR_RN_NEAR: - SetHostRoundingMode(FPSCR_RN_NEAR); - i = (s64)nearbyint(b); - break; - case FPSCR_RN_ZERO: - i = (s64)b; - break; - case FPSCR_RN_PINF: - i = (s64)ceil(b); - break; - case FPSCR_RN_MINF: - i = (s64)floor(b); - break; - } - r = (u64)i; - double di = (double)i; - if (di == b) - { - CPU.SetFPSCR_FI(0); - CPU.FPSCR.FR = 0; - } - else - { - CPU.SetFPSCR_FI(1); - CPU.FPSCR.FR = fabs(di) > fabs(b); - } - } - - (u64&)CPU.FPR[frd] = r; - if(rc) CPU.UpdateCR1(); - } - void FCTIDZ(u32 frd, u32 frb, u32 rc) override {FCTID(frd, frb, rc, true);} - void FCFID(u32 frd, u32 frb, u32 rc) override - { - s64 bi = (s64&)CPU.FPR[frb]; - double bf = (double)bi; - s64 bfi = (s64)bf; - - if(bi == bfi) - { - CPU.SetFPSCR_FI(0); - CPU.FPSCR.FR = 0; - } - else - { - CPU.SetFPSCR_FI(1); - CPU.FPSCR.FR = std::abs(bfi) > std::abs(bi); - } - - CPU.FPR[frd] = bf; - - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) CPU.UpdateCR1(); - } - - void UNK(const u32 code, const u32 opcode, const u32 gcode) override - { - throw EXCEPTION("Unknown/Illegal opcode! (0x%08x : 0x%x : 0x%x)", code, opcode, gcode); - } + static void TDI(PPUThread&, ppu_opcode_t); + static void TWI(PPUThread&, ppu_opcode_t); + static void MFVSCR(PPUThread&, ppu_opcode_t); + static void MTVSCR(PPUThread&, ppu_opcode_t); + static void VADDCUW(PPUThread&, ppu_opcode_t); + static void VADDFP(PPUThread&, ppu_opcode_t); + static void VADDSBS(PPUThread&, ppu_opcode_t); + static void VADDSHS(PPUThread&, ppu_opcode_t); + static void VADDSWS(PPUThread&, ppu_opcode_t); + static void VADDUBM(PPUThread&, ppu_opcode_t); + static void VADDUBS(PPUThread&, ppu_opcode_t); + static void VADDUHM(PPUThread&, ppu_opcode_t); + static void VADDUHS(PPUThread&, ppu_opcode_t); + static void VADDUWM(PPUThread&, ppu_opcode_t); + static void VADDUWS(PPUThread&, ppu_opcode_t); + static void VAND(PPUThread&, ppu_opcode_t); + static void VANDC(PPUThread&, ppu_opcode_t); + static void VAVGSB(PPUThread&, ppu_opcode_t); + static void VAVGSH(PPUThread&, ppu_opcode_t); + static void VAVGSW(PPUThread&, ppu_opcode_t); + static void VAVGUB(PPUThread&, ppu_opcode_t); + static void VAVGUH(PPUThread&, ppu_opcode_t); + static void VAVGUW(PPUThread&, ppu_opcode_t); + static void VCFSX(PPUThread&, ppu_opcode_t); + static void VCFUX(PPUThread&, ppu_opcode_t); + static void VCMPBFP(PPUThread&, ppu_opcode_t); + static void VCMPEQFP(PPUThread&, ppu_opcode_t); + static void VCMPEQUB(PPUThread&, ppu_opcode_t); + static void VCMPEQUH(PPUThread&, ppu_opcode_t); + static void VCMPEQUW(PPUThread&, ppu_opcode_t); + static void VCMPGEFP(PPUThread&, ppu_opcode_t); + static void VCMPGTFP(PPUThread&, ppu_opcode_t); + static void VCMPGTSB(PPUThread&, ppu_opcode_t); + static void VCMPGTSH(PPUThread&, ppu_opcode_t); + static void VCMPGTSW(PPUThread&, ppu_opcode_t); + static void VCMPGTUB(PPUThread&, ppu_opcode_t); + static void VCMPGTUH(PPUThread&, ppu_opcode_t); + static void VCMPGTUW(PPUThread&, ppu_opcode_t); + static void VCTSXS(PPUThread&, ppu_opcode_t); + static void VCTUXS(PPUThread&, ppu_opcode_t); + static void VEXPTEFP(PPUThread&, ppu_opcode_t); + static void VLOGEFP(PPUThread&, ppu_opcode_t); + static void VMADDFP(PPUThread&, ppu_opcode_t); + static void VMAXFP(PPUThread&, ppu_opcode_t); + static void VMAXSB(PPUThread&, ppu_opcode_t); + static void VMAXSH(PPUThread&, ppu_opcode_t); + static void VMAXSW(PPUThread&, ppu_opcode_t); + static void VMAXUB(PPUThread&, ppu_opcode_t); + static void VMAXUH(PPUThread&, ppu_opcode_t); + static void VMAXUW(PPUThread&, ppu_opcode_t); + static void VMHADDSHS(PPUThread&, ppu_opcode_t); + static void VMHRADDSHS(PPUThread&, ppu_opcode_t); + static void VMINFP(PPUThread&, ppu_opcode_t); + static void VMINSB(PPUThread&, ppu_opcode_t); + static void VMINSH(PPUThread&, ppu_opcode_t); + static void VMINSW(PPUThread&, ppu_opcode_t); + static void VMINUB(PPUThread&, ppu_opcode_t); + static void VMINUH(PPUThread&, ppu_opcode_t); + static void VMINUW(PPUThread&, ppu_opcode_t); + static void VMLADDUHM(PPUThread&, ppu_opcode_t); + static void VMRGHB(PPUThread&, ppu_opcode_t); + static void VMRGHH(PPUThread&, ppu_opcode_t); + static void VMRGHW(PPUThread&, ppu_opcode_t); + static void VMRGLB(PPUThread&, ppu_opcode_t); + static void VMRGLH(PPUThread&, ppu_opcode_t); + static void VMRGLW(PPUThread&, ppu_opcode_t); + static void VMSUMMBM(PPUThread&, ppu_opcode_t); + static void VMSUMSHM(PPUThread&, ppu_opcode_t); + static void VMSUMSHS(PPUThread&, ppu_opcode_t); + static void VMSUMUBM(PPUThread&, ppu_opcode_t); + static void VMSUMUHM(PPUThread&, ppu_opcode_t); + static void VMSUMUHS(PPUThread&, ppu_opcode_t); + static void VMULESB(PPUThread&, ppu_opcode_t); + static void VMULESH(PPUThread&, ppu_opcode_t); + static void VMULEUB(PPUThread&, ppu_opcode_t); + static void VMULEUH(PPUThread&, ppu_opcode_t); + static void VMULOSB(PPUThread&, ppu_opcode_t); + static void VMULOSH(PPUThread&, ppu_opcode_t); + static void VMULOUB(PPUThread&, ppu_opcode_t); + static void VMULOUH(PPUThread&, ppu_opcode_t); + static void VNMSUBFP(PPUThread&, ppu_opcode_t); + static void VNOR(PPUThread&, ppu_opcode_t); + static void VOR(PPUThread&, ppu_opcode_t); + static void VPERM(PPUThread&, ppu_opcode_t); + static void VPKPX(PPUThread&, ppu_opcode_t); + static void VPKSHSS(PPUThread&, ppu_opcode_t); + static void VPKSHUS(PPUThread&, ppu_opcode_t); + static void VPKSWSS(PPUThread&, ppu_opcode_t); + static void VPKSWUS(PPUThread&, ppu_opcode_t); + static void VPKUHUM(PPUThread&, ppu_opcode_t); + static void VPKUHUS(PPUThread&, ppu_opcode_t); + static void VPKUWUM(PPUThread&, ppu_opcode_t); + static void VPKUWUS(PPUThread&, ppu_opcode_t); + static void VREFP(PPUThread&, ppu_opcode_t); + static void VRFIM(PPUThread&, ppu_opcode_t); + static void VRFIN(PPUThread&, ppu_opcode_t); + static void VRFIP(PPUThread&, ppu_opcode_t); + static void VRFIZ(PPUThread&, ppu_opcode_t); + static void VRLB(PPUThread&, ppu_opcode_t); + static void VRLH(PPUThread&, ppu_opcode_t); + static void VRLW(PPUThread&, ppu_opcode_t); + static void VRSQRTEFP(PPUThread&, ppu_opcode_t); + static void VSEL(PPUThread&, ppu_opcode_t); + static void VSL(PPUThread&, ppu_opcode_t); + static void VSLB(PPUThread&, ppu_opcode_t); + static void VSLDOI(PPUThread&, ppu_opcode_t); + static void VSLH(PPUThread&, ppu_opcode_t); + static void VSLO(PPUThread&, ppu_opcode_t); + static void VSLW(PPUThread&, ppu_opcode_t); + static void VSPLTB(PPUThread&, ppu_opcode_t); + static void VSPLTH(PPUThread&, ppu_opcode_t); + static void VSPLTISB(PPUThread&, ppu_opcode_t); + static void VSPLTISH(PPUThread&, ppu_opcode_t); + static void VSPLTISW(PPUThread&, ppu_opcode_t); + static void VSPLTW(PPUThread&, ppu_opcode_t); + static void VSR(PPUThread&, ppu_opcode_t); + static void VSRAB(PPUThread&, ppu_opcode_t); + static void VSRAH(PPUThread&, ppu_opcode_t); + static void VSRAW(PPUThread&, ppu_opcode_t); + static void VSRB(PPUThread&, ppu_opcode_t); + static void VSRH(PPUThread&, ppu_opcode_t); + static void VSRO(PPUThread&, ppu_opcode_t); + static void VSRW(PPUThread&, ppu_opcode_t); + static void VSUBCUW(PPUThread&, ppu_opcode_t); + static void VSUBFP(PPUThread&, ppu_opcode_t); + static void VSUBSBS(PPUThread&, ppu_opcode_t); + static void VSUBSHS(PPUThread&, ppu_opcode_t); + static void VSUBSWS(PPUThread&, ppu_opcode_t); + static void VSUBUBM(PPUThread&, ppu_opcode_t); + static void VSUBUBS(PPUThread&, ppu_opcode_t); + static void VSUBUHM(PPUThread&, ppu_opcode_t); + static void VSUBUHS(PPUThread&, ppu_opcode_t); + static void VSUBUWM(PPUThread&, ppu_opcode_t); + static void VSUBUWS(PPUThread&, ppu_opcode_t); + static void VSUMSWS(PPUThread&, ppu_opcode_t); + static void VSUM2SWS(PPUThread&, ppu_opcode_t); + static void VSUM4SBS(PPUThread&, ppu_opcode_t); + static void VSUM4SHS(PPUThread&, ppu_opcode_t); + static void VSUM4UBS(PPUThread&, ppu_opcode_t); + static void VUPKHPX(PPUThread&, ppu_opcode_t); + static void VUPKHSB(PPUThread&, ppu_opcode_t); + static void VUPKHSH(PPUThread&, ppu_opcode_t); + static void VUPKLPX(PPUThread&, ppu_opcode_t); + static void VUPKLSB(PPUThread&, ppu_opcode_t); + static void VUPKLSH(PPUThread&, ppu_opcode_t); + static void VXOR(PPUThread&, ppu_opcode_t); + static void MULLI(PPUThread&, ppu_opcode_t); + static void SUBFIC(PPUThread&, ppu_opcode_t); + static void CMPLI(PPUThread&, ppu_opcode_t); + static void CMPI(PPUThread&, ppu_opcode_t); + static void ADDIC(PPUThread&, ppu_opcode_t); + static void ADDI(PPUThread&, ppu_opcode_t); + static void ADDIS(PPUThread&, ppu_opcode_t); + static void BC(PPUThread&, ppu_opcode_t); + static void HACK(PPUThread&, ppu_opcode_t); + static void SC(PPUThread&, ppu_opcode_t); + static void B(PPUThread&, ppu_opcode_t); + static void MCRF(PPUThread&, ppu_opcode_t); + static void BCLR(PPUThread&, ppu_opcode_t); + static void CRNOR(PPUThread&, ppu_opcode_t); + static void CRANDC(PPUThread&, ppu_opcode_t); + static void ISYNC(PPUThread&, ppu_opcode_t); + static void CRXOR(PPUThread&, ppu_opcode_t); + static void CRNAND(PPUThread&, ppu_opcode_t); + static void CRAND(PPUThread&, ppu_opcode_t); + static void CREQV(PPUThread&, ppu_opcode_t); + static void CRORC(PPUThread&, ppu_opcode_t); + static void CROR(PPUThread&, ppu_opcode_t); + static void BCCTR(PPUThread&, ppu_opcode_t); + static void RLWIMI(PPUThread&, ppu_opcode_t); + static void RLWINM(PPUThread&, ppu_opcode_t); + static void RLWNM(PPUThread&, ppu_opcode_t); + static void ORI(PPUThread&, ppu_opcode_t); + static void ORIS(PPUThread&, ppu_opcode_t); + static void XORI(PPUThread&, ppu_opcode_t); + static void XORIS(PPUThread&, ppu_opcode_t); + static void ANDI(PPUThread&, ppu_opcode_t); + static void ANDIS(PPUThread&, ppu_opcode_t); + static void RLDICL(PPUThread&, ppu_opcode_t); + static void RLDICR(PPUThread&, ppu_opcode_t); + static void RLDIC(PPUThread&, ppu_opcode_t); + static void RLDIMI(PPUThread&, ppu_opcode_t); + static void RLDCL(PPUThread&, ppu_opcode_t); + static void RLDCR(PPUThread&, ppu_opcode_t); + static void CMP(PPUThread&, ppu_opcode_t); + static void TW(PPUThread&, ppu_opcode_t); + static void LVSL(PPUThread&, ppu_opcode_t); + static void LVEBX(PPUThread&, ppu_opcode_t); + static void SUBFC(PPUThread&, ppu_opcode_t); + static void MULHDU(PPUThread&, ppu_opcode_t); + static void ADDC(PPUThread&, ppu_opcode_t); + static void MULHWU(PPUThread&, ppu_opcode_t); + static void MFOCRF(PPUThread&, ppu_opcode_t); + static void LWARX(PPUThread&, ppu_opcode_t); + static void LDX(PPUThread&, ppu_opcode_t); + static void LWZX(PPUThread&, ppu_opcode_t); + static void SLW(PPUThread&, ppu_opcode_t); + static void CNTLZW(PPUThread&, ppu_opcode_t); + static void SLD(PPUThread&, ppu_opcode_t); + static void AND(PPUThread&, ppu_opcode_t); + static void CMPL(PPUThread&, ppu_opcode_t); + static void LVSR(PPUThread&, ppu_opcode_t); + static void LVEHX(PPUThread&, ppu_opcode_t); + static void SUBF(PPUThread&, ppu_opcode_t); + static void LDUX(PPUThread&, ppu_opcode_t); + static void DCBST(PPUThread&, ppu_opcode_t); + static void LWZUX(PPUThread&, ppu_opcode_t); + static void CNTLZD(PPUThread&, ppu_opcode_t); + static void ANDC(PPUThread&, ppu_opcode_t); + static void TD(PPUThread&, ppu_opcode_t); + static void LVEWX(PPUThread&, ppu_opcode_t); + static void MULHD(PPUThread&, ppu_opcode_t); + static void MULHW(PPUThread&, ppu_opcode_t); + static void LDARX(PPUThread&, ppu_opcode_t); + static void DCBF(PPUThread&, ppu_opcode_t); + static void LBZX(PPUThread&, ppu_opcode_t); + static void LVX(PPUThread&, ppu_opcode_t); + static void NEG(PPUThread&, ppu_opcode_t); + static void LBZUX(PPUThread&, ppu_opcode_t); + static void NOR(PPUThread&, ppu_opcode_t); + static void STVEBX(PPUThread&, ppu_opcode_t); + static void SUBFE(PPUThread&, ppu_opcode_t); + static void ADDE(PPUThread&, ppu_opcode_t); + static void MTOCRF(PPUThread&, ppu_opcode_t); + static void STDX(PPUThread&, ppu_opcode_t); + static void STWCX(PPUThread&, ppu_opcode_t); + static void STWX(PPUThread&, ppu_opcode_t); + static void STVEHX(PPUThread&, ppu_opcode_t); + static void STDUX(PPUThread&, ppu_opcode_t); + static void STWUX(PPUThread&, ppu_opcode_t); + static void STVEWX(PPUThread&, ppu_opcode_t); + static void SUBFZE(PPUThread&, ppu_opcode_t); + static void ADDZE(PPUThread&, ppu_opcode_t); + static void STDCX(PPUThread&, ppu_opcode_t); + static void STBX(PPUThread&, ppu_opcode_t); + static void STVX(PPUThread&, ppu_opcode_t); + static void MULLD(PPUThread&, ppu_opcode_t); + static void SUBFME(PPUThread&, ppu_opcode_t); + static void ADDME(PPUThread&, ppu_opcode_t); + static void MULLW(PPUThread&, ppu_opcode_t); + static void DCBTST(PPUThread&, ppu_opcode_t); + static void STBUX(PPUThread&, ppu_opcode_t); + static void ADD(PPUThread&, ppu_opcode_t); + static void DCBT(PPUThread&, ppu_opcode_t); + static void LHZX(PPUThread&, ppu_opcode_t); + static void EQV(PPUThread&, ppu_opcode_t); + static void ECIWX(PPUThread&, ppu_opcode_t); + static void LHZUX(PPUThread&, ppu_opcode_t); + static void XOR(PPUThread&, ppu_opcode_t); + static void MFSPR(PPUThread&, ppu_opcode_t); + static void LWAX(PPUThread&, ppu_opcode_t); + static void DST(PPUThread&, ppu_opcode_t); + static void LHAX(PPUThread&, ppu_opcode_t); + static void LVXL(PPUThread&, ppu_opcode_t); + static void MFTB(PPUThread&, ppu_opcode_t); + static void LWAUX(PPUThread&, ppu_opcode_t); + static void DSTST(PPUThread&, ppu_opcode_t); + static void LHAUX(PPUThread&, ppu_opcode_t); + static void STHX(PPUThread&, ppu_opcode_t); + static void ORC(PPUThread&, ppu_opcode_t); + static void ECOWX(PPUThread&, ppu_opcode_t); + static void STHUX(PPUThread&, ppu_opcode_t); + static void OR(PPUThread&, ppu_opcode_t); + static void DIVDU(PPUThread&, ppu_opcode_t); + static void DIVWU(PPUThread&, ppu_opcode_t); + static void MTSPR(PPUThread&, ppu_opcode_t); + static void DCBI(PPUThread&, ppu_opcode_t); + static void NAND(PPUThread&, ppu_opcode_t); + static void STVXL(PPUThread&, ppu_opcode_t); + static void DIVD(PPUThread&, ppu_opcode_t); + static void DIVW(PPUThread&, ppu_opcode_t); + static void LVLX(PPUThread&, ppu_opcode_t); + static void LDBRX(PPUThread&, ppu_opcode_t); + static void LSWX(PPUThread&, ppu_opcode_t); + static void LWBRX(PPUThread&, ppu_opcode_t); + static void LFSX(PPUThread&, ppu_opcode_t); + static void SRW(PPUThread&, ppu_opcode_t); + static void SRD(PPUThread&, ppu_opcode_t); + static void LVRX(PPUThread&, ppu_opcode_t); + static void LSWI(PPUThread&, ppu_opcode_t); + static void LFSUX(PPUThread&, ppu_opcode_t); + static void SYNC(PPUThread&, ppu_opcode_t); + static void LFDX(PPUThread&, ppu_opcode_t); + static void LFDUX(PPUThread&, ppu_opcode_t); + static void STVLX(PPUThread&, ppu_opcode_t); + static void STDBRX(PPUThread&, ppu_opcode_t); + static void STSWX(PPUThread&, ppu_opcode_t); + static void STWBRX(PPUThread&, ppu_opcode_t); + static void STFSX(PPUThread&, ppu_opcode_t); + static void STVRX(PPUThread&, ppu_opcode_t); + static void STFSUX(PPUThread&, ppu_opcode_t); + static void STSWI(PPUThread&, ppu_opcode_t); + static void STFDX(PPUThread&, ppu_opcode_t); + static void STFDUX(PPUThread&, ppu_opcode_t); + static void LVLXL(PPUThread&, ppu_opcode_t); + static void LHBRX(PPUThread&, ppu_opcode_t); + static void SRAW(PPUThread&, ppu_opcode_t); + static void SRAD(PPUThread&, ppu_opcode_t); + static void LVRXL(PPUThread&, ppu_opcode_t); + static void DSS(PPUThread&, ppu_opcode_t); + static void SRAWI(PPUThread&, ppu_opcode_t); + static void SRADI(PPUThread&, ppu_opcode_t); + static void EIEIO(PPUThread&, ppu_opcode_t); + static void STVLXL(PPUThread&, ppu_opcode_t); + static void STHBRX(PPUThread&, ppu_opcode_t); + static void EXTSH(PPUThread&, ppu_opcode_t); + static void STVRXL(PPUThread&, ppu_opcode_t); + static void EXTSB(PPUThread&, ppu_opcode_t); + static void STFIWX(PPUThread&, ppu_opcode_t); + static void EXTSW(PPUThread&, ppu_opcode_t); + static void ICBI(PPUThread&, ppu_opcode_t); + static void DCBZ(PPUThread&, ppu_opcode_t); + static void LWZ(PPUThread&, ppu_opcode_t); + static void LWZU(PPUThread&, ppu_opcode_t); + static void LBZ(PPUThread&, ppu_opcode_t); + static void LBZU(PPUThread&, ppu_opcode_t); + static void STW(PPUThread&, ppu_opcode_t); + static void STWU(PPUThread&, ppu_opcode_t); + static void STB(PPUThread&, ppu_opcode_t); + static void STBU(PPUThread&, ppu_opcode_t); + static void LHZ(PPUThread&, ppu_opcode_t); + static void LHZU(PPUThread&, ppu_opcode_t); + static void LHA(PPUThread&, ppu_opcode_t); + static void LHAU(PPUThread&, ppu_opcode_t); + static void STH(PPUThread&, ppu_opcode_t); + static void STHU(PPUThread&, ppu_opcode_t); + static void LMW(PPUThread&, ppu_opcode_t); + static void STMW(PPUThread&, ppu_opcode_t); + static void LFS(PPUThread&, ppu_opcode_t); + static void LFSU(PPUThread&, ppu_opcode_t); + static void LFD(PPUThread&, ppu_opcode_t); + static void LFDU(PPUThread&, ppu_opcode_t); + static void STFS(PPUThread&, ppu_opcode_t); + static void STFSU(PPUThread&, ppu_opcode_t); + static void STFD(PPUThread&, ppu_opcode_t); + static void STFDU(PPUThread&, ppu_opcode_t); + static void LD(PPUThread&, ppu_opcode_t); + static void LDU(PPUThread&, ppu_opcode_t); + static void LWA(PPUThread&, ppu_opcode_t); + static void FDIVS(PPUThread&, ppu_opcode_t); + static void FSUBS(PPUThread&, ppu_opcode_t); + static void FADDS(PPUThread&, ppu_opcode_t); + static void FSQRTS(PPUThread&, ppu_opcode_t); + static void FRES(PPUThread&, ppu_opcode_t); + static void FMULS(PPUThread&, ppu_opcode_t); + static void FMADDS(PPUThread&, ppu_opcode_t); + static void FMSUBS(PPUThread&, ppu_opcode_t); + static void FNMSUBS(PPUThread&, ppu_opcode_t); + static void FNMADDS(PPUThread&, ppu_opcode_t); + static void STD(PPUThread&, ppu_opcode_t); + static void STDU(PPUThread&, ppu_opcode_t); + static void MTFSB1(PPUThread&, ppu_opcode_t); + static void MCRFS(PPUThread&, ppu_opcode_t); + static void MTFSB0(PPUThread&, ppu_opcode_t); + static void MTFSFI(PPUThread&, ppu_opcode_t); + static void MFFS(PPUThread&, ppu_opcode_t); + static void MTFSF(PPUThread&, ppu_opcode_t); + static void FCMPU(PPUThread&, ppu_opcode_t); + static void FRSP(PPUThread&, ppu_opcode_t); + static void FCTIW(PPUThread&, ppu_opcode_t); + static void FCTIWZ(PPUThread&, ppu_opcode_t); + static void FDIV(PPUThread&, ppu_opcode_t); + static void FSUB(PPUThread&, ppu_opcode_t); + static void FADD(PPUThread&, ppu_opcode_t); + static void FSQRT(PPUThread&, ppu_opcode_t); + static void FSEL(PPUThread&, ppu_opcode_t); + static void FMUL(PPUThread&, ppu_opcode_t); + static void FRSQRTE(PPUThread&, ppu_opcode_t); + static void FMSUB(PPUThread&, ppu_opcode_t); + static void FMADD(PPUThread&, ppu_opcode_t); + static void FNMSUB(PPUThread&, ppu_opcode_t); + static void FNMADD(PPUThread&, ppu_opcode_t); + static void FCMPO(PPUThread&, ppu_opcode_t); + static void FNEG(PPUThread&, ppu_opcode_t); + static void FMR(PPUThread&, ppu_opcode_t); + static void FNABS(PPUThread&, ppu_opcode_t); + static void FABS(PPUThread&, ppu_opcode_t); + static void FCTID(PPUThread&, ppu_opcode_t); + static void FCTIDZ(PPUThread&, ppu_opcode_t); + static void FCFID(PPUThread&, ppu_opcode_t); + + static void UNK(PPUThread&, ppu_opcode_t); +}; + +struct ppu_interpreter_precise final : ppu_interpreter +{ + // TODO +}; + +struct ppu_interpreter_fast final : ppu_interpreter +{ + // TODO }; diff --git a/rpcs3/Emu/Cell/PPUInterpreter2.h b/rpcs3/Emu/Cell/PPUInterpreter2.h deleted file mode 100644 index 051c70b3dd..0000000000 --- a/rpcs3/Emu/Cell/PPUInterpreter2.h +++ /dev/null @@ -1,870 +0,0 @@ -#pragma once - -#include "PPUOpcodes.h" - -class PPUThread; - -union ppu_opcode_t -{ - u32 opcode; - - bf_t shh; // 30 - bf_t mbmeh; // 26 - bf_t mbmel; // 21..25 - bf_t shl; // 16..20 - bf_t vuimm; // 11..15 - bf_t vs; // 6..10 - bf_t vsh; // 22..25 - bf_t oe; // 21 - bf_t spr; // 11..20 - bf_t vc; // 21..25 - bf_t vb; // 16..20 - bf_t va; // 11..15 - bf_t vd; // 6..10 - bf_t lk; // 31 - bf_t aa; // 30 - bf_t rb; // 16..20 - bf_t ra; // 11..15 - bf_t rd; // 6..10 - bf_t uimm16; // 16..31 - bf_t l11; // 11 - bf_t rs; // 6..10 - bf_t simm16; // 16..31, signed - bf_t vsimm; // 11..15, signed - bf_t ll; // 6..31, signed - bf_t lev; // 20..26 - bf_t i; // 16..19 - bf_t crfs; // 11..13 - bf_t l10; // 10 - bf_t crfd; // 6..8 - bf_t crbb; // 16..20 - bf_t crba; // 11..15 - bf_t crbd; // 6..10 - bf_t rc; // 31 - bf_t me; // 26..30 - bf_t mb; // 21..25 - bf_t sh; // 16..20 - bf_t bi; // 11..15 - bf_t bo; // 6..10 - bf_t frc; // 21..25 - bf_t frb; // 16..20 - bf_t fra; // 11..15 - bf_t frd; // 6..10 - bf_t crm; // 12..19 - bf_t frs; // 6..10 - bf_t flm; // 7..14 -}; - -namespace ppu_interpreter -{ - void NULL_OP(PPUThread& CPU, ppu_opcode_t op); - void NOP(PPUThread& CPU, ppu_opcode_t op); - - void TDI(PPUThread& CPU, ppu_opcode_t op); - void TWI(PPUThread& CPU, ppu_opcode_t op); - - void MFVSCR(PPUThread& CPU, ppu_opcode_t op); - void MTVSCR(PPUThread& CPU, ppu_opcode_t op); - void VADDCUW(PPUThread& CPU, ppu_opcode_t op); - void VADDFP(PPUThread& CPU, ppu_opcode_t op); - void VADDSBS(PPUThread& CPU, ppu_opcode_t op); - void VADDSHS(PPUThread& CPU, ppu_opcode_t op); - void VADDSWS(PPUThread& CPU, ppu_opcode_t op); - void VADDUBM(PPUThread& CPU, ppu_opcode_t op); - void VADDUBS(PPUThread& CPU, ppu_opcode_t op); - void VADDUHM(PPUThread& CPU, ppu_opcode_t op); - void VADDUHS(PPUThread& CPU, ppu_opcode_t op); - void VADDUWM(PPUThread& CPU, ppu_opcode_t op); - void VADDUWS(PPUThread& CPU, ppu_opcode_t op); - void VAND(PPUThread& CPU, ppu_opcode_t op); - void VANDC(PPUThread& CPU, ppu_opcode_t op); - void VAVGSB(PPUThread& CPU, ppu_opcode_t op); - void VAVGSH(PPUThread& CPU, ppu_opcode_t op); - void VAVGSW(PPUThread& CPU, ppu_opcode_t op); - void VAVGUB(PPUThread& CPU, ppu_opcode_t op); - void VAVGUH(PPUThread& CPU, ppu_opcode_t op); - void VAVGUW(PPUThread& CPU, ppu_opcode_t op); - void VCFSX(PPUThread& CPU, ppu_opcode_t op); - void VCFUX(PPUThread& CPU, ppu_opcode_t op); - void VCMPBFP(PPUThread& CPU, ppu_opcode_t op); - void VCMPBFP_(PPUThread& CPU, ppu_opcode_t op); - void VCMPEQFP(PPUThread& CPU, ppu_opcode_t op); - void VCMPEQFP_(PPUThread& CPU, ppu_opcode_t op); - void VCMPEQUB(PPUThread& CPU, ppu_opcode_t op); - void VCMPEQUB_(PPUThread& CPU, ppu_opcode_t op); - void VCMPEQUH(PPUThread& CPU, ppu_opcode_t op); - void VCMPEQUH_(PPUThread& CPU, ppu_opcode_t op); - void VCMPEQUW(PPUThread& CPU, ppu_opcode_t op); - void VCMPEQUW_(PPUThread& CPU, ppu_opcode_t op); - void VCMPGEFP(PPUThread& CPU, ppu_opcode_t op); - void VCMPGEFP_(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTFP(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTFP_(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTSB(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTSB_(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTSH(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTSH_(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTSW(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTSW_(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTUB(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTUB_(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTUH(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTUH_(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTUW(PPUThread& CPU, ppu_opcode_t op); - void VCMPGTUW_(PPUThread& CPU, ppu_opcode_t op); - void VCTSXS(PPUThread& CPU, ppu_opcode_t op); - void VCTUXS(PPUThread& CPU, ppu_opcode_t op); - void VEXPTEFP(PPUThread& CPU, ppu_opcode_t op); - void VLOGEFP(PPUThread& CPU, ppu_opcode_t op); - void VMADDFP(PPUThread& CPU, ppu_opcode_t op); - void VMAXFP(PPUThread& CPU, ppu_opcode_t op); - void VMAXSB(PPUThread& CPU, ppu_opcode_t op); - void VMAXSH(PPUThread& CPU, ppu_opcode_t op); - void VMAXSW(PPUThread& CPU, ppu_opcode_t op); - void VMAXUB(PPUThread& CPU, ppu_opcode_t op); - void VMAXUH(PPUThread& CPU, ppu_opcode_t op); - void VMAXUW(PPUThread& CPU, ppu_opcode_t op); - void VMHADDSHS(PPUThread& CPU, ppu_opcode_t op); - void VMHRADDSHS(PPUThread& CPU, ppu_opcode_t op); - void VMINFP(PPUThread& CPU, ppu_opcode_t op); - void VMINSB(PPUThread& CPU, ppu_opcode_t op); - void VMINSH(PPUThread& CPU, ppu_opcode_t op); - void VMINSW(PPUThread& CPU, ppu_opcode_t op); - void VMINUB(PPUThread& CPU, ppu_opcode_t op); - void VMINUH(PPUThread& CPU, ppu_opcode_t op); - void VMINUW(PPUThread& CPU, ppu_opcode_t op); - void VMLADDUHM(PPUThread& CPU, ppu_opcode_t op); - void VMRGHB(PPUThread& CPU, ppu_opcode_t op); - void VMRGHH(PPUThread& CPU, ppu_opcode_t op); - void VMRGHW(PPUThread& CPU, ppu_opcode_t op); - void VMRGLB(PPUThread& CPU, ppu_opcode_t op); - void VMRGLH(PPUThread& CPU, ppu_opcode_t op); - void VMRGLW(PPUThread& CPU, ppu_opcode_t op); - void VMSUMMBM(PPUThread& CPU, ppu_opcode_t op); - void VMSUMSHM(PPUThread& CPU, ppu_opcode_t op); - void VMSUMSHS(PPUThread& CPU, ppu_opcode_t op); - void VMSUMUBM(PPUThread& CPU, ppu_opcode_t op); - void VMSUMUHM(PPUThread& CPU, ppu_opcode_t op); - void VMSUMUHS(PPUThread& CPU, ppu_opcode_t op); - void VMULESB(PPUThread& CPU, ppu_opcode_t op); - void VMULESH(PPUThread& CPU, ppu_opcode_t op); - void VMULEUB(PPUThread& CPU, ppu_opcode_t op); - void VMULEUH(PPUThread& CPU, ppu_opcode_t op); - void VMULOSB(PPUThread& CPU, ppu_opcode_t op); - void VMULOSH(PPUThread& CPU, ppu_opcode_t op); - void VMULOUB(PPUThread& CPU, ppu_opcode_t op); - void VMULOUH(PPUThread& CPU, ppu_opcode_t op); - void VNMSUBFP(PPUThread& CPU, ppu_opcode_t op); - void VNOR(PPUThread& CPU, ppu_opcode_t op); - void VOR(PPUThread& CPU, ppu_opcode_t op); - void VPERM(PPUThread& CPU, ppu_opcode_t op); - void VPKPX(PPUThread& CPU, ppu_opcode_t op); - void VPKSHSS(PPUThread& CPU, ppu_opcode_t op); - void VPKSHUS(PPUThread& CPU, ppu_opcode_t op); - void VPKSWSS(PPUThread& CPU, ppu_opcode_t op); - void VPKSWUS(PPUThread& CPU, ppu_opcode_t op); - void VPKUHUM(PPUThread& CPU, ppu_opcode_t op); - void VPKUHUS(PPUThread& CPU, ppu_opcode_t op); - void VPKUWUM(PPUThread& CPU, ppu_opcode_t op); - void VPKUWUS(PPUThread& CPU, ppu_opcode_t op); - void VREFP(PPUThread& CPU, ppu_opcode_t op); - void VRFIM(PPUThread& CPU, ppu_opcode_t op); - void VRFIN(PPUThread& CPU, ppu_opcode_t op); - void VRFIP(PPUThread& CPU, ppu_opcode_t op); - void VRFIZ(PPUThread& CPU, ppu_opcode_t op); - void VRLB(PPUThread& CPU, ppu_opcode_t op); - void VRLH(PPUThread& CPU, ppu_opcode_t op); - void VRLW(PPUThread& CPU, ppu_opcode_t op); - void VRSQRTEFP(PPUThread& CPU, ppu_opcode_t op); - void VSEL(PPUThread& CPU, ppu_opcode_t op); - void VSL(PPUThread& CPU, ppu_opcode_t op); - void VSLB(PPUThread& CPU, ppu_opcode_t op); - void VSLDOI(PPUThread& CPU, ppu_opcode_t op); - void VSLH(PPUThread& CPU, ppu_opcode_t op); - void VSLO(PPUThread& CPU, ppu_opcode_t op); - void VSLW(PPUThread& CPU, ppu_opcode_t op); - void VSPLTB(PPUThread& CPU, ppu_opcode_t op); - void VSPLTH(PPUThread& CPU, ppu_opcode_t op); - void VSPLTISB(PPUThread& CPU, ppu_opcode_t op); - void VSPLTISH(PPUThread& CPU, ppu_opcode_t op); - void VSPLTISW(PPUThread& CPU, ppu_opcode_t op); - void VSPLTW(PPUThread& CPU, ppu_opcode_t op); - void VSR(PPUThread& CPU, ppu_opcode_t op); - void VSRAB(PPUThread& CPU, ppu_opcode_t op); - void VSRAH(PPUThread& CPU, ppu_opcode_t op); - void VSRAW(PPUThread& CPU, ppu_opcode_t op); - void VSRB(PPUThread& CPU, ppu_opcode_t op); - void VSRH(PPUThread& CPU, ppu_opcode_t op); - void VSRO(PPUThread& CPU, ppu_opcode_t op); - void VSRW(PPUThread& CPU, ppu_opcode_t op); - void VSUBCUW(PPUThread& CPU, ppu_opcode_t op); - void VSUBFP(PPUThread& CPU, ppu_opcode_t op); - void VSUBSBS(PPUThread& CPU, ppu_opcode_t op); - void VSUBSHS(PPUThread& CPU, ppu_opcode_t op); - void VSUBSWS(PPUThread& CPU, ppu_opcode_t op); - void VSUBUBM(PPUThread& CPU, ppu_opcode_t op); - void VSUBUBS(PPUThread& CPU, ppu_opcode_t op); - void VSUBUHM(PPUThread& CPU, ppu_opcode_t op); - void VSUBUHS(PPUThread& CPU, ppu_opcode_t op); - void VSUBUWM(PPUThread& CPU, ppu_opcode_t op); - void VSUBUWS(PPUThread& CPU, ppu_opcode_t op); - void VSUMSWS(PPUThread& CPU, ppu_opcode_t op); - void VSUM2SWS(PPUThread& CPU, ppu_opcode_t op); - void VSUM4SBS(PPUThread& CPU, ppu_opcode_t op); - void VSUM4SHS(PPUThread& CPU, ppu_opcode_t op); - void VSUM4UBS(PPUThread& CPU, ppu_opcode_t op); - void VUPKHPX(PPUThread& CPU, ppu_opcode_t op); - void VUPKHSB(PPUThread& CPU, ppu_opcode_t op); - void VUPKHSH(PPUThread& CPU, ppu_opcode_t op); - void VUPKLPX(PPUThread& CPU, ppu_opcode_t op); - void VUPKLSB(PPUThread& CPU, ppu_opcode_t op); - void VUPKLSH(PPUThread& CPU, ppu_opcode_t op); - void VXOR(PPUThread& CPU, ppu_opcode_t op); - void MULLI(PPUThread& CPU, ppu_opcode_t op); - void SUBFIC(PPUThread& CPU, ppu_opcode_t op); - void CMPLI(PPUThread& CPU, ppu_opcode_t op); - void CMPI(PPUThread& CPU, ppu_opcode_t op); - void ADDIC(PPUThread& CPU, ppu_opcode_t op); - void ADDIC_(PPUThread& CPU, ppu_opcode_t op); - void ADDI(PPUThread& CPU, ppu_opcode_t op); - void ADDIS(PPUThread& CPU, ppu_opcode_t op); - void BC(PPUThread& CPU, ppu_opcode_t op); - void HACK(PPUThread& CPU, ppu_opcode_t op); - void SC(PPUThread& CPU, ppu_opcode_t op); - void B(PPUThread& CPU, ppu_opcode_t op); - void MCRF(PPUThread& CPU, ppu_opcode_t op); - void BCLR(PPUThread& CPU, ppu_opcode_t op); - void CRNOR(PPUThread& CPU, ppu_opcode_t op); - void CRANDC(PPUThread& CPU, ppu_opcode_t op); - void ISYNC(PPUThread& CPU, ppu_opcode_t op); - void CRXOR(PPUThread& CPU, ppu_opcode_t op); - void CRNAND(PPUThread& CPU, ppu_opcode_t op); - void CRAND(PPUThread& CPU, ppu_opcode_t op); - void CREQV(PPUThread& CPU, ppu_opcode_t op); - void CRORC(PPUThread& CPU, ppu_opcode_t op); - void CROR(PPUThread& CPU, ppu_opcode_t op); - void BCCTR(PPUThread& CPU, ppu_opcode_t op); - void RLWIMI(PPUThread& CPU, ppu_opcode_t op); - void RLWINM(PPUThread& CPU, ppu_opcode_t op); - void RLWNM(PPUThread& CPU, ppu_opcode_t op); - void ORI(PPUThread& CPU, ppu_opcode_t op); - void ORIS(PPUThread& CPU, ppu_opcode_t op); - void XORI(PPUThread& CPU, ppu_opcode_t op); - void XORIS(PPUThread& CPU, ppu_opcode_t op); - void ANDI_(PPUThread& CPU, ppu_opcode_t op); - void ANDIS_(PPUThread& CPU, ppu_opcode_t op); - void RLDICL(PPUThread& CPU, ppu_opcode_t op); - void RLDICR(PPUThread& CPU, ppu_opcode_t op); - void RLDIC(PPUThread& CPU, ppu_opcode_t op); - void RLDIMI(PPUThread& CPU, ppu_opcode_t op); - void RLDC_LR(PPUThread& CPU, ppu_opcode_t op); - void CMP(PPUThread& CPU, ppu_opcode_t op); - void TW(PPUThread& CPU, ppu_opcode_t op); - void LVSL(PPUThread& CPU, ppu_opcode_t op); - void LVEBX(PPUThread& CPU, ppu_opcode_t op); - void SUBFC(PPUThread& CPU, ppu_opcode_t op); - void MULHDU(PPUThread& CPU, ppu_opcode_t op); - void ADDC(PPUThread& CPU, ppu_opcode_t op); - void MULHWU(PPUThread& CPU, ppu_opcode_t op); - void MFOCRF(PPUThread& CPU, ppu_opcode_t op); - void LWARX(PPUThread& CPU, ppu_opcode_t op); - void LDX(PPUThread& CPU, ppu_opcode_t op); - void LWZX(PPUThread& CPU, ppu_opcode_t op); - void SLW(PPUThread& CPU, ppu_opcode_t op); - void CNTLZW(PPUThread& CPU, ppu_opcode_t op); - void SLD(PPUThread& CPU, ppu_opcode_t op); - void AND(PPUThread& CPU, ppu_opcode_t op); - void CMPL(PPUThread& CPU, ppu_opcode_t op); - void LVSR(PPUThread& CPU, ppu_opcode_t op); - void LVEHX(PPUThread& CPU, ppu_opcode_t op); - void SUBF(PPUThread& CPU, ppu_opcode_t op); - void LDUX(PPUThread& CPU, ppu_opcode_t op); - void DCBST(PPUThread& CPU, ppu_opcode_t op); - void LWZUX(PPUThread& CPU, ppu_opcode_t op); - void CNTLZD(PPUThread& CPU, ppu_opcode_t op); - void ANDC(PPUThread& CPU, ppu_opcode_t op); - void TD(PPUThread& CPU, ppu_opcode_t op); - void LVEWX(PPUThread& CPU, ppu_opcode_t op); - void MULHD(PPUThread& CPU, ppu_opcode_t op); - void MULHW(PPUThread& CPU, ppu_opcode_t op); - void LDARX(PPUThread& CPU, ppu_opcode_t op); - void DCBF(PPUThread& CPU, ppu_opcode_t op); - void LBZX(PPUThread& CPU, ppu_opcode_t op); - void LVX(PPUThread& CPU, ppu_opcode_t op); - void NEG(PPUThread& CPU, ppu_opcode_t op); - void LBZUX(PPUThread& CPU, ppu_opcode_t op); - void NOR(PPUThread& CPU, ppu_opcode_t op); - void STVEBX(PPUThread& CPU, ppu_opcode_t op); - void SUBFE(PPUThread& CPU, ppu_opcode_t op); - void ADDE(PPUThread& CPU, ppu_opcode_t op); - void MTOCRF(PPUThread& CPU, ppu_opcode_t op); - void STDX(PPUThread& CPU, ppu_opcode_t op); - void STWCX_(PPUThread& CPU, ppu_opcode_t op); - void STWX(PPUThread& CPU, ppu_opcode_t op); - void STVEHX(PPUThread& CPU, ppu_opcode_t op); - void STDUX(PPUThread& CPU, ppu_opcode_t op); - void STWUX(PPUThread& CPU, ppu_opcode_t op); - void STVEWX(PPUThread& CPU, ppu_opcode_t op); - void SUBFZE(PPUThread& CPU, ppu_opcode_t op); - void ADDZE(PPUThread& CPU, ppu_opcode_t op); - void STDCX_(PPUThread& CPU, ppu_opcode_t op); - void STBX(PPUThread& CPU, ppu_opcode_t op); - void STVX(PPUThread& CPU, ppu_opcode_t op); - void MULLD(PPUThread& CPU, ppu_opcode_t op); - void SUBFME(PPUThread& CPU, ppu_opcode_t op); - void ADDME(PPUThread& CPU, ppu_opcode_t op); - void MULLW(PPUThread& CPU, ppu_opcode_t op); - void DCBTST(PPUThread& CPU, ppu_opcode_t op); - void STBUX(PPUThread& CPU, ppu_opcode_t op); - void ADD(PPUThread& CPU, ppu_opcode_t op); - void DCBT(PPUThread& CPU, ppu_opcode_t op); - void LHZX(PPUThread& CPU, ppu_opcode_t op); - void EQV(PPUThread& CPU, ppu_opcode_t op); - void ECIWX(PPUThread& CPU, ppu_opcode_t op); - void LHZUX(PPUThread& CPU, ppu_opcode_t op); - void XOR(PPUThread& CPU, ppu_opcode_t op); - void MFSPR(PPUThread& CPU, ppu_opcode_t op); - void LWAX(PPUThread& CPU, ppu_opcode_t op); - void DST(PPUThread& CPU, ppu_opcode_t op); - void LHAX(PPUThread& CPU, ppu_opcode_t op); - void LVXL(PPUThread& CPU, ppu_opcode_t op); - void MFTB(PPUThread& CPU, ppu_opcode_t op); - void LWAUX(PPUThread& CPU, ppu_opcode_t op); - void DSTST(PPUThread& CPU, ppu_opcode_t op); - void LHAUX(PPUThread& CPU, ppu_opcode_t op); - void STHX(PPUThread& CPU, ppu_opcode_t op); - void ORC(PPUThread& CPU, ppu_opcode_t op); - void ECOWX(PPUThread& CPU, ppu_opcode_t op); - void STHUX(PPUThread& CPU, ppu_opcode_t op); - void OR(PPUThread& CPU, ppu_opcode_t op); - void DIVDU(PPUThread& CPU, ppu_opcode_t op); - void DIVWU(PPUThread& CPU, ppu_opcode_t op); - void MTSPR(PPUThread& CPU, ppu_opcode_t op); - void DCBI(PPUThread& CPU, ppu_opcode_t op); - void NAND(PPUThread& CPU, ppu_opcode_t op); - void STVXL(PPUThread& CPU, ppu_opcode_t op); - void DIVD(PPUThread& CPU, ppu_opcode_t op); - void DIVW(PPUThread& CPU, ppu_opcode_t op); - void LVLX(PPUThread& CPU, ppu_opcode_t op); - void LDBRX(PPUThread& CPU, ppu_opcode_t op); - void LSWX(PPUThread& CPU, ppu_opcode_t op); - void LWBRX(PPUThread& CPU, ppu_opcode_t op); - void LFSX(PPUThread& CPU, ppu_opcode_t op); - void SRW(PPUThread& CPU, ppu_opcode_t op); - void SRD(PPUThread& CPU, ppu_opcode_t op); - void LVRX(PPUThread& CPU, ppu_opcode_t op); - void LSWI(PPUThread& CPU, ppu_opcode_t op); - void LFSUX(PPUThread& CPU, ppu_opcode_t op); - void SYNC(PPUThread& CPU, ppu_opcode_t op); - void LFDX(PPUThread& CPU, ppu_opcode_t op); - void LFDUX(PPUThread& CPU, ppu_opcode_t op); - void STVLX(PPUThread& CPU, ppu_opcode_t op); - void STDBRX(PPUThread& CPU, ppu_opcode_t op); - void STSWX(PPUThread& CPU, ppu_opcode_t op); - void STWBRX(PPUThread& CPU, ppu_opcode_t op); - void STFSX(PPUThread& CPU, ppu_opcode_t op); - void STVRX(PPUThread& CPU, ppu_opcode_t op); - void STFSUX(PPUThread& CPU, ppu_opcode_t op); - void STSWI(PPUThread& CPU, ppu_opcode_t op); - void STFDX(PPUThread& CPU, ppu_opcode_t op); - void STFDUX(PPUThread& CPU, ppu_opcode_t op); - void LVLXL(PPUThread& CPU, ppu_opcode_t op); - void LHBRX(PPUThread& CPU, ppu_opcode_t op); - void SRAW(PPUThread& CPU, ppu_opcode_t op); - void SRAD(PPUThread& CPU, ppu_opcode_t op); - void LVRXL(PPUThread& CPU, ppu_opcode_t op); - void DSS(PPUThread& CPU, ppu_opcode_t op); - void SRAWI(PPUThread& CPU, ppu_opcode_t op); - void SRADI(PPUThread& CPU, ppu_opcode_t op); - void EIEIO(PPUThread& CPU, ppu_opcode_t op); - void STVLXL(PPUThread& CPU, ppu_opcode_t op); - void STHBRX(PPUThread& CPU, ppu_opcode_t op); - void EXTSH(PPUThread& CPU, ppu_opcode_t op); - void STVRXL(PPUThread& CPU, ppu_opcode_t op); - void EXTSB(PPUThread& CPU, ppu_opcode_t op); - void STFIWX(PPUThread& CPU, ppu_opcode_t op); - void EXTSW(PPUThread& CPU, ppu_opcode_t op); - void ICBI(PPUThread& CPU, ppu_opcode_t op); - void DCBZ(PPUThread& CPU, ppu_opcode_t op); - void LWZ(PPUThread& CPU, ppu_opcode_t op); - void LWZU(PPUThread& CPU, ppu_opcode_t op); - void LBZ(PPUThread& CPU, ppu_opcode_t op); - void LBZU(PPUThread& CPU, ppu_opcode_t op); - void STW(PPUThread& CPU, ppu_opcode_t op); - void STWU(PPUThread& CPU, ppu_opcode_t op); - void STB(PPUThread& CPU, ppu_opcode_t op); - void STBU(PPUThread& CPU, ppu_opcode_t op); - void LHZ(PPUThread& CPU, ppu_opcode_t op); - void LHZU(PPUThread& CPU, ppu_opcode_t op); - void LHA(PPUThread& CPU, ppu_opcode_t op); - void LHAU(PPUThread& CPU, ppu_opcode_t op); - void STH(PPUThread& CPU, ppu_opcode_t op); - void STHU(PPUThread& CPU, ppu_opcode_t op); - void LMW(PPUThread& CPU, ppu_opcode_t op); - void STMW(PPUThread& CPU, ppu_opcode_t op); - void LFS(PPUThread& CPU, ppu_opcode_t op); - void LFSU(PPUThread& CPU, ppu_opcode_t op); - void LFD(PPUThread& CPU, ppu_opcode_t op); - void LFDU(PPUThread& CPU, ppu_opcode_t op); - void STFS(PPUThread& CPU, ppu_opcode_t op); - void STFSU(PPUThread& CPU, ppu_opcode_t op); - void STFD(PPUThread& CPU, ppu_opcode_t op); - void STFDU(PPUThread& CPU, ppu_opcode_t op); - void LD(PPUThread& CPU, ppu_opcode_t op); - void LDU(PPUThread& CPU, ppu_opcode_t op); - void LWA(PPUThread& CPU, ppu_opcode_t op); - void FDIVS(PPUThread& CPU, ppu_opcode_t op); - void FSUBS(PPUThread& CPU, ppu_opcode_t op); - void FADDS(PPUThread& CPU, ppu_opcode_t op); - void FSQRTS(PPUThread& CPU, ppu_opcode_t op); - void FRES(PPUThread& CPU, ppu_opcode_t op); - void FMULS(PPUThread& CPU, ppu_opcode_t op); - void FMADDS(PPUThread& CPU, ppu_opcode_t op); - void FMSUBS(PPUThread& CPU, ppu_opcode_t op); - void FNMSUBS(PPUThread& CPU, ppu_opcode_t op); - void FNMADDS(PPUThread& CPU, ppu_opcode_t op); - void STD(PPUThread& CPU, ppu_opcode_t op); - void STDU(PPUThread& CPU, ppu_opcode_t op); - void MTFSB1(PPUThread& CPU, ppu_opcode_t op); - void MCRFS(PPUThread& CPU, ppu_opcode_t op); - void MTFSB0(PPUThread& CPU, ppu_opcode_t op); - void MTFSFI(PPUThread& CPU, ppu_opcode_t op); - void MFFS(PPUThread& CPU, ppu_opcode_t op); - void MTFSF(PPUThread& CPU, ppu_opcode_t op); - - void FCMPU(PPUThread& CPU, ppu_opcode_t op); - void FRSP(PPUThread& CPU, ppu_opcode_t op); - void FCTIW(PPUThread& CPU, ppu_opcode_t op); - void FCTIWZ(PPUThread& CPU, ppu_opcode_t op); - void FDIV(PPUThread& CPU, ppu_opcode_t op); - void FSUB(PPUThread& CPU, ppu_opcode_t op); - void FADD(PPUThread& CPU, ppu_opcode_t op); - void FSQRT(PPUThread& CPU, ppu_opcode_t op); - void FSEL(PPUThread& CPU, ppu_opcode_t op); - void FMUL(PPUThread& CPU, ppu_opcode_t op); - void FRSQRTE(PPUThread& CPU, ppu_opcode_t op); - void FMSUB(PPUThread& CPU, ppu_opcode_t op); - void FMADD(PPUThread& CPU, ppu_opcode_t op); - void FNMSUB(PPUThread& CPU, ppu_opcode_t op); - void FNMADD(PPUThread& CPU, ppu_opcode_t op); - void FCMPO(PPUThread& CPU, ppu_opcode_t op); - void FNEG(PPUThread& CPU, ppu_opcode_t op); - void FMR(PPUThread& CPU, ppu_opcode_t op); - void FNABS(PPUThread& CPU, ppu_opcode_t op); - void FABS(PPUThread& CPU, ppu_opcode_t op); - void FCTID(PPUThread& CPU, ppu_opcode_t op); - void FCTIDZ(PPUThread& CPU, ppu_opcode_t op); - void FCFID(PPUThread& CPU, ppu_opcode_t op); - - void UNK(PPUThread& CPU, ppu_opcode_t op); -} - -class PPUInterpreter2 : public PPUOpcodes -{ -public: - virtual ~PPUInterpreter2() {} - - ppu_inter_func_t func; - - virtual void NULL_OP() { func = ppu_interpreter::NULL_OP; } - virtual void NOP() { func = ppu_interpreter::NOP; } - - virtual void TDI(u32 to, u32 ra, s32 simm16) { func = ppu_interpreter::TDI; } - virtual void TWI(u32 to, u32 ra, s32 simm16) { func = ppu_interpreter::TWI; } - - virtual void MFVSCR(u32 vd) { func = ppu_interpreter::MFVSCR; } - virtual void MTVSCR(u32 vb) { func = ppu_interpreter::MTVSCR; } - virtual void VADDCUW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDCUW; } - virtual void VADDFP(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDFP; } - virtual void VADDSBS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDSBS; } - virtual void VADDSHS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDSHS; } - virtual void VADDSWS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDSWS; } - virtual void VADDUBM(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDUBM; } - virtual void VADDUBS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDUBS; } - virtual void VADDUHM(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDUHM; } - virtual void VADDUHS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDUHS; } - virtual void VADDUWM(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDUWM; } - virtual void VADDUWS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VADDUWS; } - virtual void VAND(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VAND; } - virtual void VANDC(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VANDC; } - virtual void VAVGSB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VAVGSB; } - virtual void VAVGSH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VAVGSH; } - virtual void VAVGSW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VAVGSW; } - virtual void VAVGUB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VAVGUB; } - virtual void VAVGUH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VAVGUH; } - virtual void VAVGUW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VAVGUW; } - virtual void VCFSX(u32 vd, u32 uimm5, u32 vb) { func = ppu_interpreter::VCFSX; } - virtual void VCFUX(u32 vd, u32 uimm5, u32 vb) { func = ppu_interpreter::VCFUX; } - virtual void VCMPBFP(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPBFP; } - virtual void VCMPBFP_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPBFP_; } - virtual void VCMPEQFP(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPEQFP; } - virtual void VCMPEQFP_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPEQFP_; } - virtual void VCMPEQUB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPEQUB; } - virtual void VCMPEQUB_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPEQUB_; } - virtual void VCMPEQUH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPEQUH; } - virtual void VCMPEQUH_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPEQUH_; } - virtual void VCMPEQUW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPEQUW; } - virtual void VCMPEQUW_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPEQUW_; } - virtual void VCMPGEFP(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGEFP; } - virtual void VCMPGEFP_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGEFP_; } - virtual void VCMPGTFP(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTFP; } - virtual void VCMPGTFP_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTFP_; } - virtual void VCMPGTSB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTSB; } - virtual void VCMPGTSB_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTSB_; } - virtual void VCMPGTSH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTSH; } - virtual void VCMPGTSH_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTSH_; } - virtual void VCMPGTSW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTSW; } - virtual void VCMPGTSW_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTSW_; } - virtual void VCMPGTUB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTUB; } - virtual void VCMPGTUB_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTUB_; } - virtual void VCMPGTUH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTUH; } - virtual void VCMPGTUH_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTUH_; } - virtual void VCMPGTUW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTUW; } - virtual void VCMPGTUW_(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VCMPGTUW_; } - virtual void VCTSXS(u32 vd, u32 uimm5, u32 vb) { func = ppu_interpreter::VCTSXS; } - virtual void VCTUXS(u32 vd, u32 uimm5, u32 vb) { func = ppu_interpreter::VCTUXS; } - virtual void VEXPTEFP(u32 vd, u32 vb) { func = ppu_interpreter::VEXPTEFP; } - virtual void VLOGEFP(u32 vd, u32 vb) { func = ppu_interpreter::VLOGEFP; } - virtual void VMADDFP(u32 vd, u32 va, u32 vc, u32 vb) { func = ppu_interpreter::VMADDFP; } - virtual void VMAXFP(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMAXFP; } - virtual void VMAXSB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMAXSB; } - virtual void VMAXSH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMAXSH; } - virtual void VMAXSW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMAXSW; } - virtual void VMAXUB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMAXUB; } - virtual void VMAXUH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMAXUH; } - virtual void VMAXUW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMAXUW; } - virtual void VMHADDSHS(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VMHADDSHS; } - virtual void VMHRADDSHS(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VMHRADDSHS; } - virtual void VMINFP(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMINFP; } - virtual void VMINSB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMINSB; } - virtual void VMINSH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMINSH; } - virtual void VMINSW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMINSW; } - virtual void VMINUB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMINUB; } - virtual void VMINUH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMINUH; } - virtual void VMINUW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMINUW; } - virtual void VMLADDUHM(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VMLADDUHM; } - virtual void VMRGHB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMRGHB; } - virtual void VMRGHH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMRGHH; } - virtual void VMRGHW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMRGHW; } - virtual void VMRGLB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMRGLB; } - virtual void VMRGLH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMRGLH; } - virtual void VMRGLW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMRGLW; } - virtual void VMSUMMBM(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VMSUMMBM; } - virtual void VMSUMSHM(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VMSUMSHM; } - virtual void VMSUMSHS(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VMSUMSHS; } - virtual void VMSUMUBM(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VMSUMUBM; } - virtual void VMSUMUHM(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VMSUMUHM; } - virtual void VMSUMUHS(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VMSUMUHS; } - virtual void VMULESB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMULESB; } - virtual void VMULESH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMULESH; } - virtual void VMULEUB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMULEUB; } - virtual void VMULEUH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMULEUH; } - virtual void VMULOSB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMULOSB; } - virtual void VMULOSH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMULOSH; } - virtual void VMULOUB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMULOUB; } - virtual void VMULOUH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VMULOUH; } - virtual void VNMSUBFP(u32 vd, u32 va, u32 vc, u32 vb) { func = ppu_interpreter::VNMSUBFP; } - virtual void VNOR(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VNOR; } - virtual void VOR(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VOR; } - virtual void VPERM(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VPERM; } - virtual void VPKPX(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VPKPX; } - virtual void VPKSHSS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VPKSHSS; } - virtual void VPKSHUS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VPKSHUS; } - virtual void VPKSWSS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VPKSWSS; } - virtual void VPKSWUS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VPKSWUS; } - virtual void VPKUHUM(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VPKUHUM; } - virtual void VPKUHUS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VPKUHUS; } - virtual void VPKUWUM(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VPKUWUM; } - virtual void VPKUWUS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VPKUWUS; } - virtual void VREFP(u32 vd, u32 vb) { func = ppu_interpreter::VREFP; } - virtual void VRFIM(u32 vd, u32 vb) { func = ppu_interpreter::VRFIM; } - virtual void VRFIN(u32 vd, u32 vb) { func = ppu_interpreter::VRFIN; } - virtual void VRFIP(u32 vd, u32 vb) { func = ppu_interpreter::VRFIP; } - virtual void VRFIZ(u32 vd, u32 vb) { func = ppu_interpreter::VRFIZ; } - virtual void VRLB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VRLB; } - virtual void VRLH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VRLH; } - virtual void VRLW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VRLW; } - virtual void VRSQRTEFP(u32 vd, u32 vb) { func = ppu_interpreter::VRSQRTEFP; } - virtual void VSEL(u32 vd, u32 va, u32 vb, u32 vc) { func = ppu_interpreter::VSEL; } - virtual void VSL(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSL; } - virtual void VSLB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSLB; } - virtual void VSLDOI(u32 vd, u32 va, u32 vb, u32 sh) { func = ppu_interpreter::VSLDOI; } - virtual void VSLH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSLH; } - virtual void VSLO(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSLO; } - virtual void VSLW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSLW; } - virtual void VSPLTB(u32 vd, u32 uimm5, u32 vb) { func = ppu_interpreter::VSPLTB; } - virtual void VSPLTH(u32 vd, u32 uimm5, u32 vb) { func = ppu_interpreter::VSPLTH; } - virtual void VSPLTISB(u32 vd, s32 simm5) { func = ppu_interpreter::VSPLTISB; } - virtual void VSPLTISH(u32 vd, s32 simm5) { func = ppu_interpreter::VSPLTISH; } - virtual void VSPLTISW(u32 vd, s32 simm5) { func = ppu_interpreter::VSPLTISW; } - virtual void VSPLTW(u32 vd, u32 uimm5, u32 vb) { func = ppu_interpreter::VSPLTW; } - virtual void VSR(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSR; } - virtual void VSRAB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSRAB; } - virtual void VSRAH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSRAH; } - virtual void VSRAW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSRAW; } - virtual void VSRB(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSRB; } - virtual void VSRH(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSRH; } - virtual void VSRO(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSRO; } - virtual void VSRW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSRW; } - virtual void VSUBCUW(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBCUW; } - virtual void VSUBFP(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBFP; } - virtual void VSUBSBS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBSBS; } - virtual void VSUBSHS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBSHS; } - virtual void VSUBSWS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBSWS; } - virtual void VSUBUBM(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBUBM; } - virtual void VSUBUBS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBUBS; } - virtual void VSUBUHM(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBUHM; } - virtual void VSUBUHS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBUHS; } - virtual void VSUBUWM(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBUWM; } - virtual void VSUBUWS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUBUWS; } - virtual void VSUMSWS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUMSWS; } - virtual void VSUM2SWS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUM2SWS; } - virtual void VSUM4SBS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUM4SBS; } - virtual void VSUM4SHS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUM4SHS; } - virtual void VSUM4UBS(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VSUM4UBS; } - virtual void VUPKHPX(u32 vd, u32 vb) { func = ppu_interpreter::VUPKHPX; } - virtual void VUPKHSB(u32 vd, u32 vb) { func = ppu_interpreter::VUPKHSB; } - virtual void VUPKHSH(u32 vd, u32 vb) { func = ppu_interpreter::VUPKHSH; } - virtual void VUPKLPX(u32 vd, u32 vb) { func = ppu_interpreter::VUPKLPX; } - virtual void VUPKLSB(u32 vd, u32 vb) { func = ppu_interpreter::VUPKLSB; } - virtual void VUPKLSH(u32 vd, u32 vb) { func = ppu_interpreter::VUPKLSH; } - virtual void VXOR(u32 vd, u32 va, u32 vb) { func = ppu_interpreter::VXOR; } - virtual void MULLI(u32 rd, u32 ra, s32 simm16) { func = ppu_interpreter::MULLI; } - virtual void SUBFIC(u32 rd, u32 ra, s32 simm16) { func = ppu_interpreter::SUBFIC; } - virtual void CMPLI(u32 bf, u32 l, u32 ra, u32 uimm16) { func = ppu_interpreter::CMPLI; } - virtual void CMPI(u32 bf, u32 l, u32 ra, s32 simm16) { func = ppu_interpreter::CMPI; } - virtual void ADDIC(u32 rd, u32 ra, s32 simm16) { func = ppu_interpreter::ADDIC; } - virtual void ADDIC_(u32 rd, u32 ra, s32 simm16) { func = ppu_interpreter::ADDIC_; } - virtual void ADDI(u32 rd, u32 ra, s32 simm16) { func = ppu_interpreter::ADDI; } - virtual void ADDIS(u32 rd, u32 ra, s32 simm16) { func = ppu_interpreter::ADDIS; } - virtual void BC(u32 bo, u32 bi, s32 bd, u32 aa, u32 lk) { func = ppu_interpreter::BC; } - virtual void HACK(u32 index) { func = ppu_interpreter::HACK; } - virtual void SC(u32 lev) { func = ppu_interpreter::SC; } - virtual void B(s32 ll, u32 aa, u32 lk) { func = ppu_interpreter::B; } - virtual void MCRF(u32 crfd, u32 crfs) { func = ppu_interpreter::MCRF; } - virtual void BCLR(u32 bo, u32 bi, u32 bh, u32 lk) { func = ppu_interpreter::BCLR; } - virtual void CRNOR(u32 bt, u32 ba, u32 bb) { func = ppu_interpreter::CRNOR; } - virtual void CRANDC(u32 bt, u32 ba, u32 bb) { func = ppu_interpreter::CRANDC; } - virtual void ISYNC() { func = ppu_interpreter::ISYNC; } - virtual void CRXOR(u32 bt, u32 ba, u32 bb) { func = ppu_interpreter::CRXOR; } - virtual void CRNAND(u32 bt, u32 ba, u32 bb) { func = ppu_interpreter::CRNAND; } - virtual void CRAND(u32 bt, u32 ba, u32 bb) { func = ppu_interpreter::CRAND; } - virtual void CREQV(u32 bt, u32 ba, u32 bb) { func = ppu_interpreter::CREQV; } - virtual void CRORC(u32 bt, u32 ba, u32 bb) { func = ppu_interpreter::CRORC; } - virtual void CROR(u32 bt, u32 ba, u32 bb) { func = ppu_interpreter::CROR; } - virtual void BCCTR(u32 bo, u32 bi, u32 bh, u32 lk) { func = ppu_interpreter::BCCTR; } - virtual void RLWIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) { func = ppu_interpreter::RLWIMI; } - virtual void RLWINM(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) { func = ppu_interpreter::RLWINM; } - virtual void RLWNM(u32 ra, u32 rs, u32 rb, u32 MB, u32 ME, u32 rc) { func = ppu_interpreter::RLWNM; } - virtual void ORI(u32 rs, u32 ra, u32 uimm16) { func = ppu_interpreter::ORI; } - virtual void ORIS(u32 rs, u32 ra, u32 uimm16) { func = ppu_interpreter::ORIS; } - virtual void XORI(u32 ra, u32 rs, u32 uimm16) { func = ppu_interpreter::XORI; } - virtual void XORIS(u32 ra, u32 rs, u32 uimm16) { func = ppu_interpreter::XORIS; } - virtual void ANDI_(u32 ra, u32 rs, u32 uimm16) { func = ppu_interpreter::ANDI_; } - virtual void ANDIS_(u32 ra, u32 rs, u32 uimm16) { func = ppu_interpreter::ANDIS_; } - virtual void RLDICL(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) { func = ppu_interpreter::RLDICL; } - virtual void RLDICR(u32 ra, u32 rs, u32 sh, u32 me, u32 rc) { func = ppu_interpreter::RLDICR; } - virtual void RLDIC(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) { func = ppu_interpreter::RLDIC; } - virtual void RLDIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) { func = ppu_interpreter::RLDIMI; } - virtual void RLDC_LR(u32 ra, u32 rs, u32 rb, u32 m_eb, u32 is_r, u32 rc) { func = ppu_interpreter::RLDC_LR; } - virtual void CMP(u32 crfd, u32 l, u32 ra, u32 rb) { func = ppu_interpreter::CMP; } - virtual void TW(u32 to, u32 ra, u32 rb) { func = ppu_interpreter::TW; } - virtual void LVSL(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVSL; } - virtual void LVEBX(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVEBX; } - virtual void SUBFC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::SUBFC; } - virtual void MULHDU(u32 rd, u32 ra, u32 rb, u32 rc) { func = ppu_interpreter::MULHDU; } - virtual void ADDC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::ADDC; } - virtual void MULHWU(u32 rd, u32 ra, u32 rb, u32 rc) { func = ppu_interpreter::MULHWU; } - virtual void MFOCRF(u32 a, u32 rd, u32 crm) { func = ppu_interpreter::MFOCRF; } - virtual void LWARX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LWARX; } - virtual void LDX(u32 ra, u32 rs, u32 rb) { func = ppu_interpreter::LDX; } - virtual void LWZX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LWZX; } - virtual void SLW(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::SLW; } - virtual void CNTLZW(u32 ra, u32 rs, u32 rc) { func = ppu_interpreter::CNTLZW; } - virtual void SLD(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::SLD; } - virtual void AND(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::AND; } - virtual void CMPL(u32 bf, u32 l, u32 ra, u32 rb) { func = ppu_interpreter::CMPL; } - virtual void LVSR(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVSR; } - virtual void LVEHX(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVEHX; } - virtual void SUBF(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::SUBF; } - virtual void LDUX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LDUX; } - virtual void DCBST(u32 ra, u32 rb) { func = ppu_interpreter::DCBST; } - virtual void LWZUX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LWZUX; } - virtual void CNTLZD(u32 ra, u32 rs, u32 rc) { func = ppu_interpreter::CNTLZD; } - virtual void ANDC(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::ANDC; } - virtual void TD(u32 to, u32 ra, u32 rb) { func = ppu_interpreter::TD; } - virtual void LVEWX(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVEWX; } - virtual void MULHD(u32 rd, u32 ra, u32 rb, u32 rc) { func = ppu_interpreter::MULHD; } - virtual void MULHW(u32 rd, u32 ra, u32 rb, u32 rc) { func = ppu_interpreter::MULHW; } - virtual void LDARX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LDARX; } - virtual void DCBF(u32 ra, u32 rb) { func = ppu_interpreter::DCBF; } - virtual void LBZX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LBZX; } - virtual void LVX(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVX; } - virtual void NEG(u32 rd, u32 ra, u32 oe, u32 rc) { func = ppu_interpreter::NEG; } - virtual void LBZUX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LBZUX; } - virtual void NOR(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::NOR; } - virtual void STVEBX(u32 vs, u32 ra, u32 rb) { func = ppu_interpreter::STVEBX; } - virtual void SUBFE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::SUBFE; } - virtual void ADDE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::ADDE; } - virtual void MTOCRF(u32 l, u32 crm, u32 rs) { func = ppu_interpreter::MTOCRF; } - virtual void STDX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STDX; } - virtual void STWCX_(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STWCX_; } - virtual void STWX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STWX; } - virtual void STVEHX(u32 vs, u32 ra, u32 rb) { func = ppu_interpreter::STVEHX; } - virtual void STDUX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STDUX; } - virtual void STWUX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STWUX; } - virtual void STVEWX(u32 vs, u32 ra, u32 rb) { func = ppu_interpreter::STVEWX; } - virtual void SUBFZE(u32 rd, u32 ra, u32 oe, u32 rc) { func = ppu_interpreter::SUBFZE; } - virtual void ADDZE(u32 rd, u32 ra, u32 oe, u32 rc) { func = ppu_interpreter::ADDZE; } - virtual void STDCX_(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STDCX_; } - virtual void STBX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STBX; } - virtual void STVX(u32 vs, u32 ra, u32 rb) { func = ppu_interpreter::STVX; } - virtual void MULLD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::MULLD; } - virtual void SUBFME(u32 rd, u32 ra, u32 oe, u32 rc) { func = ppu_interpreter::SUBFME; } - virtual void ADDME(u32 rd, u32 ra, u32 oe, u32 rc) { func = ppu_interpreter::ADDME; } - virtual void MULLW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::MULLW; } - virtual void DCBTST(u32 ra, u32 rb, u32 th) { func = ppu_interpreter::DCBTST; } - virtual void STBUX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STBUX; } - virtual void ADD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::ADD; } - virtual void DCBT(u32 ra, u32 rb, u32 th) { func = ppu_interpreter::DCBT; } - virtual void LHZX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LHZX; } - virtual void EQV(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::EQV; } - virtual void ECIWX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::ECIWX; } - virtual void LHZUX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LHZUX; } - virtual void XOR(u32 rs, u32 ra, u32 rb, u32 rc) { func = ppu_interpreter::XOR; } - virtual void MFSPR(u32 rd, u32 spr) { func = ppu_interpreter::MFSPR; } - virtual void LWAX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LWAX; } - virtual void DST(u32 ra, u32 rb, u32 strm, u32 t) { func = ppu_interpreter::DST; } - virtual void LHAX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LHAX; } - virtual void LVXL(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVXL; } - virtual void MFTB(u32 rd, u32 spr) { func = ppu_interpreter::MFTB; } - virtual void LWAUX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LWAUX; } - virtual void DSTST(u32 ra, u32 rb, u32 strm, u32 t) { func = ppu_interpreter::DSTST; } - virtual void LHAUX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LHAUX; } - virtual void STHX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STHX; } - virtual void ORC(u32 rs, u32 ra, u32 rb, u32 rc) { func = ppu_interpreter::ORC; } - virtual void ECOWX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::ECOWX; } - virtual void STHUX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STHUX; } - virtual void OR(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::OR; } - virtual void DIVDU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::DIVDU; } - virtual void DIVWU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::DIVWU; } - virtual void MTSPR(u32 spr, u32 rs) { func = ppu_interpreter::MTSPR; } - virtual void DCBI(u32 ra, u32 rb) { func = ppu_interpreter::DCBI; } - virtual void NAND(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::NAND; } - virtual void STVXL(u32 vs, u32 ra, u32 rb) { func = ppu_interpreter::STVXL; } - virtual void DIVD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::DIVD; } - virtual void DIVW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) { func = ppu_interpreter::DIVW; } - virtual void LVLX(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVLX; } - virtual void LDBRX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LDBRX; } - virtual void LSWX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LSWX; } - virtual void LWBRX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LWBRX; } - virtual void LFSX(u32 frd, u32 ra, u32 rb) { func = ppu_interpreter::LFSX; } - virtual void SRW(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::SRW; } - virtual void SRD(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::SRD; } - virtual void LVRX(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVRX; } - virtual void LSWI(u32 rd, u32 ra, u32 nb) { func = ppu_interpreter::LSWI; } - virtual void LFSUX(u32 frd, u32 ra, u32 rb) { func = ppu_interpreter::LFSUX; } - virtual void SYNC(u32 l) { func = ppu_interpreter::SYNC; } - virtual void LFDX(u32 frd, u32 ra, u32 rb) { func = ppu_interpreter::LFDX; } - virtual void LFDUX(u32 frd, u32 ra, u32 rb) { func = ppu_interpreter::LFDUX; } - virtual void STVLX(u32 vs, u32 ra, u32 rb) { func = ppu_interpreter::STVLX; } - virtual void STDBRX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STDBRX; } - virtual void STSWX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STSWX; } - virtual void STWBRX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STWBRX; } - virtual void STFSX(u32 frs, u32 ra, u32 rb) { func = ppu_interpreter::STFSX; } - virtual void STVRX(u32 vs, u32 ra, u32 rb) { func = ppu_interpreter::STVRX; } - virtual void STFSUX(u32 frs, u32 ra, u32 rb) { func = ppu_interpreter::STFSUX; } - virtual void STSWI(u32 rd, u32 ra, u32 nb) { func = ppu_interpreter::STSWI; } - virtual void STFDX(u32 frs, u32 ra, u32 rb) { func = ppu_interpreter::STFDX; } - virtual void STFDUX(u32 frs, u32 ra, u32 rb) { func = ppu_interpreter::STFDUX; } - virtual void LVLXL(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVLXL; } - virtual void LHBRX(u32 rd, u32 ra, u32 rb) { func = ppu_interpreter::LHBRX; } - virtual void SRAW(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::SRAW; } - virtual void SRAD(u32 ra, u32 rs, u32 rb, u32 rc) { func = ppu_interpreter::SRAD; } - virtual void LVRXL(u32 vd, u32 ra, u32 rb) { func = ppu_interpreter::LVRXL; } - virtual void DSS(u32 strm, u32 a) { func = ppu_interpreter::DSS; } - virtual void SRAWI(u32 ra, u32 rs, u32 sh, u32 rc) { func = ppu_interpreter::SRAWI; } - virtual void SRADI1(u32 ra, u32 rs, u32 sh, u32 rc) { func = ppu_interpreter::SRADI; } - virtual void SRADI2(u32 ra, u32 rs, u32 sh, u32 rc) { func = ppu_interpreter::SRADI; } - virtual void EIEIO() { func = ppu_interpreter::EIEIO; } - virtual void STVLXL(u32 vs, u32 ra, u32 rb) { func = ppu_interpreter::STVLXL; } - virtual void STHBRX(u32 rs, u32 ra, u32 rb) { func = ppu_interpreter::STHBRX; } - virtual void EXTSH(u32 ra, u32 rs, u32 rc) { func = ppu_interpreter::EXTSH; } - virtual void STVRXL(u32 sd, u32 ra, u32 rb) { func = ppu_interpreter::STVRXL; } - virtual void EXTSB(u32 ra, u32 rs, u32 rc) { func = ppu_interpreter::EXTSB; } - virtual void STFIWX(u32 frs, u32 ra, u32 rb) { func = ppu_interpreter::STFIWX; } - virtual void EXTSW(u32 ra, u32 rs, u32 rc) { func = ppu_interpreter::EXTSW; } - virtual void ICBI(u32 ra, u32 rb) { func = ppu_interpreter::ICBI; } - virtual void DCBZ(u32 ra, u32 rb) { func = ppu_interpreter::DCBZ; } - virtual void LWZ(u32 rd, u32 ra, s32 d) { func = ppu_interpreter::LWZ; } - virtual void LWZU(u32 rd, u32 ra, s32 d) { func = ppu_interpreter::LWZU; } - virtual void LBZ(u32 rd, u32 ra, s32 d) { func = ppu_interpreter::LBZ; } - virtual void LBZU(u32 rd, u32 ra, s32 d) { func = ppu_interpreter::LBZU; } - virtual void STW(u32 rs, u32 ra, s32 d) { func = ppu_interpreter::STW; } - virtual void STWU(u32 rs, u32 ra, s32 d) { func = ppu_interpreter::STWU; } - virtual void STB(u32 rs, u32 ra, s32 d) { func = ppu_interpreter::STB; } - virtual void STBU(u32 rs, u32 ra, s32 d) { func = ppu_interpreter::STBU; } - virtual void LHZ(u32 rd, u32 ra, s32 d) { func = ppu_interpreter::LHZ; } - virtual void LHZU(u32 rd, u32 ra, s32 d) { func = ppu_interpreter::LHZU; } - virtual void LHA(u32 rs, u32 ra, s32 d) { func = ppu_interpreter::LHA; } - virtual void LHAU(u32 rs, u32 ra, s32 d) { func = ppu_interpreter::LHAU; } - virtual void STH(u32 rs, u32 ra, s32 d) { func = ppu_interpreter::STH; } - virtual void STHU(u32 rs, u32 ra, s32 d) { func = ppu_interpreter::STHU; } - virtual void LMW(u32 rd, u32 ra, s32 d) { func = ppu_interpreter::LMW; } - virtual void STMW(u32 rs, u32 ra, s32 d) { func = ppu_interpreter::STMW; } - virtual void LFS(u32 frd, u32 ra, s32 d) { func = ppu_interpreter::LFS; } - virtual void LFSU(u32 frd, u32 ra, s32 d) { func = ppu_interpreter::LFSU; } - virtual void LFD(u32 frd, u32 ra, s32 d) { func = ppu_interpreter::LFD; } - virtual void LFDU(u32 frd, u32 ra, s32 d) { func = ppu_interpreter::LFDU; } - virtual void STFS(u32 frs, u32 ra, s32 d) { func = ppu_interpreter::STFS; } - virtual void STFSU(u32 frs, u32 ra, s32 d) { func = ppu_interpreter::STFSU; } - virtual void STFD(u32 frs, u32 ra, s32 d) { func = ppu_interpreter::STFD; } - virtual void STFDU(u32 frs, u32 ra, s32 d) { func = ppu_interpreter::STFDU; } - virtual void LD(u32 rd, u32 ra, s32 ds) { func = ppu_interpreter::LD; } - virtual void LDU(u32 rd, u32 ra, s32 ds) { func = ppu_interpreter::LDU; } - virtual void LWA(u32 rd, u32 ra, s32 ds) { func = ppu_interpreter::LWA; } - virtual void FDIVS(u32 frd, u32 fra, u32 frb, u32 rc) { func = ppu_interpreter::FDIVS; } - virtual void FSUBS(u32 frd, u32 fra, u32 frb, u32 rc) { func = ppu_interpreter::FSUBS; } - virtual void FADDS(u32 frd, u32 fra, u32 frb, u32 rc) { func = ppu_interpreter::FADDS; } - virtual void FSQRTS(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FSQRTS; } - virtual void FRES(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FRES; } - virtual void FMULS(u32 frd, u32 fra, u32 frc, u32 rc) { func = ppu_interpreter::FMULS; } - virtual void FMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { func = ppu_interpreter::FMADDS; } - virtual void FMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { func = ppu_interpreter::FMSUBS; } - virtual void FNMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { func = ppu_interpreter::FNMSUBS; } - virtual void FNMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { func = ppu_interpreter::FNMADDS; } - virtual void STD(u32 rs, u32 ra, s32 ds) { func = ppu_interpreter::STD; } - virtual void STDU(u32 rs, u32 ra, s32 ds) { func = ppu_interpreter::STDU; } - virtual void MTFSB1(u32 bt, u32 rc) { func = ppu_interpreter::MTFSB1; } - virtual void MCRFS(u32 bf, u32 bfa) { func = ppu_interpreter::MCRFS; } - virtual void MTFSB0(u32 bt, u32 rc) { func = ppu_interpreter::MTFSB0; } - virtual void MTFSFI(u32 crfd, u32 i, u32 rc) { func = ppu_interpreter::MTFSFI; } - virtual void MFFS(u32 frd, u32 rc) { func = ppu_interpreter::MFFS; } - virtual void MTFSF(u32 flm, u32 frb, u32 rc) { func = ppu_interpreter::MTFSF; } - - virtual void FCMPU(u32 bf, u32 fra, u32 frb) { func = ppu_interpreter::FCMPU; } - virtual void FRSP(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FRSP; } - virtual void FCTIW(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FCTIW; } - virtual void FCTIWZ(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FCTIWZ; } - virtual void FDIV(u32 frd, u32 fra, u32 frb, u32 rc) { func = ppu_interpreter::FDIV; } - virtual void FSUB(u32 frd, u32 fra, u32 frb, u32 rc) { func = ppu_interpreter::FSUB; } - virtual void FADD(u32 frd, u32 fra, u32 frb, u32 rc) { func = ppu_interpreter::FADD; } - virtual void FSQRT(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FSQRT; } - virtual void FSEL(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { func = ppu_interpreter::FSEL; } - virtual void FMUL(u32 frd, u32 fra, u32 frc, u32 rc) { func = ppu_interpreter::FMUL; } - virtual void FRSQRTE(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FRSQRTE; } - virtual void FMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { func = ppu_interpreter::FMSUB; } - virtual void FMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { func = ppu_interpreter::FMADD; } - virtual void FNMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { func = ppu_interpreter::FNMSUB; } - virtual void FNMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) { func = ppu_interpreter::FNMADD; } - virtual void FCMPO(u32 crfd, u32 fra, u32 frb) { func = ppu_interpreter::FCMPO; } - virtual void FNEG(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FNEG; } - virtual void FMR(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FMR; } - virtual void FNABS(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FNABS; } - virtual void FABS(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FABS; } - virtual void FCTID(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FCTID; } - virtual void FCTIDZ(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FCTIDZ; } - virtual void FCFID(u32 frd, u32 frb, u32 rc) { func = ppu_interpreter::FCFID; } - - virtual void UNK(const u32 code, const u32 opcode, const u32 gcode) { func = ppu_interpreter::UNK; } -}; \ No newline at end of file diff --git a/rpcs3/Emu/Cell/PPUModule.cpp b/rpcs3/Emu/Cell/PPUModule.cpp new file mode 100644 index 0000000000..faec008071 --- /dev/null +++ b/rpcs3/Emu/Cell/PPUModule.cpp @@ -0,0 +1,1152 @@ +#include "stdafx.h" +#include "Utilities/AutoPause.h" +#include "Crypto/sha1.h" +#include "Loader/ELF.h" +#include "Emu/System.h" +#include "Emu/IdManager.h" + +#include "Emu/Cell/PPUOpcodes.h" +#include "Emu/Cell/PPUModule.h" + +#include "Emu/Cell/lv2/sys_prx.h" + +cfg::bool_entry g_cfg_hook_ppu_funcs(cfg::root.core, "Hook static functions"); +cfg::bool_entry g_cfg_load_liblv2(cfg::root.core, "Load liblv2.sprx only"); + +cfg::set_entry g_cfg_load_libs(cfg::root.core, "Load libraries"); + +extern std::string ppu_get_function_name(const std::string& module, u32 fnid); +extern std::string ppu_get_variable_name(const std::string& module, u32 vnid); + +extern void sys_initialize_tls(PPUThread&, u64, u32, u32, u32); + +// Function lookup table. Not supposed to grow after emulation start. +std::vector g_ppu_function_cache; + +// Function NID cache for autopause. Autopause tool should probably be rewritten. +std::vector g_ppu_fnid_cache; + +extern void ppu_execute_function(PPUThread& ppu, u32 index) +{ + if (index < g_ppu_function_cache.size()) + { + // If autopause occures, check_status() will hold the thread until unpaused. + if (debug::autopause::pause_function(g_ppu_fnid_cache[index]) && ppu.check_status()) throw cpu_state::ret; + + if (const auto func = g_ppu_function_cache[index]) + { + const auto previous_function = ppu.last_function; // TODO: use gsl::finally or something, but only if it's equally fast + + try + { + func(ppu); + } + catch (...) + { + LOG_WARNING(PPU, "Function '%s' aborted", ppu.last_function); + ppu.last_function = previous_function; + throw; + } + + LOG_TRACE(PPU, "Function '%s' finished, r3=0x%llx", ppu.last_function, ppu.GPR[3]); + ppu.last_function = previous_function; + return; + } + } + + throw fmt::exception("Function not registered (index %u)" HERE, index); +} + +extern u32 ppu_generate_id(const char* name) +{ + // Symbol name suffix + const auto suffix = "\x67\x59\x65\x99\x04\x25\x04\x90\x56\x64\x27\x49\x94\x89\x74\x1A"; + + sha1_context ctx; + u8 output[20]; + + // Compute SHA-1 hash + sha1_starts(&ctx); + sha1_update(&ctx, reinterpret_cast(name), std::strlen(name)); + sha1_update(&ctx, reinterpret_cast(suffix), std::strlen(suffix)); + sha1_finish(&ctx, output); + + return reinterpret_cast&>(output[0]); +} + +ppu_static_module::ppu_static_module(const char* name) + : name(name) +{ + ppu_module_manager::register_module(this); +} + +// Initialize static modules. +static void ppu_initialize_modules() +{ + const std::initializer_list registered + { + &ppu_module_manager::cellAdec, + &ppu_module_manager::cellAtrac, + &ppu_module_manager::cellAtracMulti, + &ppu_module_manager::cellAudio, + &ppu_module_manager::cellAvconfExt, + &ppu_module_manager::cellBGDL, + &ppu_module_manager::cellCamera, + &ppu_module_manager::cellCelp8Enc, + &ppu_module_manager::cellCelpEnc, + &ppu_module_manager::cellDaisy, + &ppu_module_manager::cellDmux, + &ppu_module_manager::cellFiber, + &ppu_module_manager::cellFont, + &ppu_module_manager::cellFontFT, + &ppu_module_manager::cellFs, + &ppu_module_manager::cellGame, + &ppu_module_manager::cellGameExec, + &ppu_module_manager::cellGcmSys, + &ppu_module_manager::cellGem, + &ppu_module_manager::cellGifDec, + &ppu_module_manager::cellHttp, + &ppu_module_manager::cellHttps, + &ppu_module_manager::cellHttpUtil, + &ppu_module_manager::cellImeJp, + &ppu_module_manager::cellJpgDec, + &ppu_module_manager::cellJpgEnc, + &ppu_module_manager::cellKey2char, + &ppu_module_manager::cellL10n, + &ppu_module_manager::cellMic, + &ppu_module_manager::cellMusic, + &ppu_module_manager::cellMusicDecode, + &ppu_module_manager::cellMusicExport, + &ppu_module_manager::cellNetCtl, + &ppu_module_manager::cellOskDialog, + &ppu_module_manager::cellOvis, + &ppu_module_manager::cellPamf, + &ppu_module_manager::cellPhotoDecode, + &ppu_module_manager::cellPhotoExport, + &ppu_module_manager::cellPhotoImportUtil, + &ppu_module_manager::cellPngDec, + &ppu_module_manager::cellPngEnc, + &ppu_module_manager::cellPrint, + &ppu_module_manager::cellRec, + &ppu_module_manager::cellRemotePlay, + &ppu_module_manager::cellResc, + &ppu_module_manager::cellRtc, + &ppu_module_manager::cellRudp, + &ppu_module_manager::cellSail, + &ppu_module_manager::cellSailRec, + &ppu_module_manager::cellSaveData, + &ppu_module_manager::cellMinisSaveData, + &ppu_module_manager::cellScreenShot, + &ppu_module_manager::cellSearch, + &ppu_module_manager::cellSheap, + &ppu_module_manager::cellSpudll, + &ppu_module_manager::cellSpurs, + &ppu_module_manager::cellSpursJq, + &ppu_module_manager::cellSsl, + &ppu_module_manager::cellSubdisplay, + &ppu_module_manager::cellSync, + &ppu_module_manager::cellSync2, + &ppu_module_manager::cellSysconf, + &ppu_module_manager::cellSysmodule, + &ppu_module_manager::cellSysutil, + &ppu_module_manager::cellSysutilAp, + &ppu_module_manager::cellSysutilAvc, + &ppu_module_manager::cellSysutilAvc2, + &ppu_module_manager::cellSysutilMisc, + &ppu_module_manager::cellUsbd, + &ppu_module_manager::cellUsbPspcm, + &ppu_module_manager::cellUserInfo, + &ppu_module_manager::cellVdec, + &ppu_module_manager::cellVideoExport, + &ppu_module_manager::cellVideoUpload, + &ppu_module_manager::cellVoice, + &ppu_module_manager::cellVpost, + &ppu_module_manager::libmixer, + &ppu_module_manager::libsnd3, + &ppu_module_manager::libsynth2, + &ppu_module_manager::sceNp, + &ppu_module_manager::sceNp2, + &ppu_module_manager::sceNpClans, + &ppu_module_manager::sceNpCommerce2, + &ppu_module_manager::sceNpSns, + &ppu_module_manager::sceNpTrophy, + &ppu_module_manager::sceNpTus, + &ppu_module_manager::sceNpUtil, + &ppu_module_manager::sys_io, + &ppu_module_manager::libnet, + &ppu_module_manager::sysPrxForUser, + &ppu_module_manager::sys_libc, + &ppu_module_manager::sys_lv2dbg, + }; + + // Reinitialize function cache + g_ppu_function_cache = ppu_function_manager::get(); + g_ppu_fnid_cache = std::vector(g_ppu_function_cache.size()); + + // "Use" all the modules for correct linkage + for (auto& module : registered) + { + LOG_TRACE(LOADER, "Registered static module: %s", module->name); + + for (auto& function : module->functions) + { + LOG_TRACE(LOADER, "** 0x%08X: %s", function.first, function.second.name); + g_ppu_fnid_cache.at(function.second.index) = function.first; + } + + for (auto& variable : module->variables) + { + LOG_TRACE(LOADER, "** &0x%08X: %s (size=0x%x, align=0x%x)", variable.first, variable.second.name, variable.second.size, variable.second.align); + variable.second.var->set(0); + } + } +} + +// Detect import stub at specified address and inject HACK instruction with index immediate. +static bool ppu_patch_import_stub(u32 addr, u32 index) +{ + const auto data = vm::cptr::make(addr); + + using namespace ppu_instructions; + + // Check various patterns: + + if (vm::check_addr(addr, 32) && + (data[0] & 0xffff0000) == LI(r12, 0) && + (data[1] & 0xffff0000) == ORIS(r12, r12, 0) && + (data[2] & 0xffff0000) == LWZ(r12, r12, 0) && + data[3] == STD(r2, r1, 0x28) && + data[4] == LWZ(r0, r12, 0) && + data[5] == LWZ(r2, r12, 4) && + data[6] == MTCTR(r0) && + data[7] == BCTR()) + { + std::memset(vm::base(addr), 0, 32); + vm::write32(addr + 0, STD(r2, r1, 0x28)); // Save RTOC + vm::write32(addr + 4, HACK(index)); + vm::write32(addr + 8, BLR()); + return true; + } + + if (vm::check_addr(addr, 12) && + (data[0] & 0xffff0000) == LI(r0, 0) && + (data[1] & 0xffff0000) == ORIS(r0, r0, 0) && + (data[2] & 0xfc000003) == B(0, 0, 0)) + { + const auto sub = vm::cptr::make(addr + 8 + ((s32)data[2] << 6 >> 8 << 2)); + + if (vm::check_addr(sub.addr(), 60) && + sub[0x0] == STDU(r1, r1, -0x80) && + sub[0x1] == STD(r2, r1, 0x70) && + sub[0x2] == MR(r2, r0) && + sub[0x3] == MFLR(r0) && + sub[0x4] == STD(r0, r1, 0x90) && + sub[0x5] == LWZ(r2, r2, 0) && + sub[0x6] == LWZ(r0, r2, 0) && + sub[0x7] == LWZ(r2, r2, 4) && + sub[0x8] == MTCTR(r0) && + sub[0x9] == BCTRL() && + sub[0xa] == LD(r2, r1, 0x70) && + sub[0xb] == ADDI(r1, r1, 0x80) && + sub[0xc] == LD(r0, r1, 0x10) && + sub[0xd] == MTLR(r0) && + sub[0xe] == BLR()) + { + vm::write32(addr + 0, HACK(index)); + vm::write32(addr + 4, BLR()); + vm::write32(addr + 8, 0); + return true; + } + } + + if (vm::check_addr(addr, 64) && + data[0x0] == MFLR(r0) && + data[0x1] == STD(r0, r1, 0x10) && + data[0x2] == STDU(r1, r1, -0x80) && + data[0x3] == STD(r2, r1, 0x70) && + (data[0x4] & 0xffff0000) == LI(r2, 0) && + (data[0x5] & 0xffff0000) == ORIS(r2, r2, 0) && + data[0x6] == LWZ(r2, r2, 0) && + data[0x7] == LWZ(r0, r2, 0) && + data[0x8] == LWZ(r2, r2, 4) && + data[0x9] == MTCTR(r0) && + data[0xa] == BCTRL() && + data[0xb] == LD(r2, r1, 0x70) && + data[0xc] == ADDI(r1, r1, 0x80) && + data[0xd] == LD(r0, r1, 0x10) && + data[0xe] == MTLR(r0) && + data[0xf] == BLR()) + { + std::memset(vm::base(addr), 0, 64); + vm::write32(addr + 0, HACK(index)); + vm::write32(addr + 4, BLR()); + return true; + } + + if (vm::check_addr(addr, 64) && + data[0x0] == MFLR(r0) && + data[0x1] == STD(r0, r1, 0x10) && + data[0x2] == STDU(r1, r1, -0x80) && + data[0x3] == STD(r2, r1, 0x70) && + (data[0x4] & 0xffff0000) == LIS(r12, 0) && + (data[0x5] & 0xffff0000) == LWZ(r12, r12, 0) && + data[0x6] == LWZ(r0, r12, 0) && + data[0x7] == LWZ(r2, r12, 4) && + data[0x8] == MTCTR(r0) && + data[0x9] == BCTRL() && + data[0xa] == LD(r2, r1, 0x70) && + data[0xb] == ADDI(r1, r1, 0x80) && + data[0xc] == LD(r0, r1, 0x10) && + data[0xd] == MTLR(r0) && + data[0xe] == BLR()) + { + std::memset(vm::base(addr), 0, 64); + vm::write32(addr + 0, HACK(index)); + vm::write32(addr + 4, BLR()); + return true; + } + + if (vm::check_addr(addr, 56) && + (data[0x0] & 0xffff0000) == LI(r12, 0) && + (data[0x1] & 0xffff0000) == ORIS(r12, r12, 0) && + (data[0x2] & 0xffff0000) == LWZ(r12, r12, 0) && + data[0x3] == STD(r2, r1, 0x28) && + data[0x4] == MFLR(r0) && + data[0x5] == STD(r0, r1, 0x20) && + data[0x6] == LWZ(r0, r12, 0) && + data[0x7] == LWZ(r2, r12, 4) && + data[0x8] == MTCTR(r0) && + data[0x9] == BCTRL() && + data[0xa] == LD(r0, r1, 0x20) && + data[0xb] == MTLR(r0) && + data[0xc] == LD(r2, r1, 0x28) && + data[0xd] == BLR()) + { + std::memset(vm::base(addr), 0, 56); + vm::write32(addr + 0, HACK(index)); + vm::write32(addr + 4, BLR()); + return true; + } + + return false; +} + +// Global linkage information +struct ppu_linkage_info +{ + struct module + { + using info_t = std::unordered_map>>; + + info_t functions; + info_t variables; + }; + + // Module -> (NID -> (export; [imports...])) + std::unordered_map modules; +}; + +// Link variable +static void ppu_patch_variable_stub(u32 vref, u32 vaddr) +{ + struct vref_t + { + be_t type; + be_t addr; + be_t unk0; + }; + + for (auto ref = vm::ptr::make(vref); ref->type; ref++) + { + if (ref->unk0) LOG_ERROR(LOADER, "**** VREF(%u): Unknown values (0x%x, 0x%x)", ref->type, ref->addr, ref->unk0); + + // OPs are probably similar to relocations + switch (u32 type = ref->type) + { + case 0x1: + { + const u32 value = vm::_ref(ref->addr) = vaddr; + LOG_WARNING(LOADER, "**** VREF(1): 0x%x <- 0x%x", ref->addr, value); + break; + } + + case 0x4: + case 0x6: + default: LOG_ERROR(LOADER, "**** VREF(%u): Unknown/Illegal type (0x%x, 0x%x)", ref->type, ref->addr, ref->unk0); + } + } +} + +// Export or import module struct +struct ppu_prx_module_info +{ + u8 size; + u8 unk0; + be_t version; + be_t attributes; + be_t num_func; + be_t num_var; + be_t num_tlsvar; + u8 info_hash; + u8 info_tlshash; + u8 unk1[2]; + vm::bcptr name; + vm::bcptr nids; // Imported FNIDs, Exported NIDs + vm::bptr addrs; + vm::bcptr vnids; // Imported VNIDs + vm::bcptr vstubs; + be_t unk4; + be_t unk5; +}; + +// Load and register exports; return special exports found (nameless module) +static auto ppu_load_exports(const std::shared_ptr& link, u32 exports_start, u32 exports_end) +{ + std::unordered_map result; + + for (u32 addr = exports_start; addr < exports_end;) + { + const auto& lib = vm::_ref(addr); + + if (!lib.name) + { + // Set special exports + for (u32 i = 0, end = lib.num_func + lib.num_var; i < end; i++) + { + const u32 nid = lib.nids[i]; + const u32 addr = lib.addrs[i]; + + if (i < lib.num_func) + { + LOG_NOTICE(LOADER, "** Special: [%s] at 0x%x", ppu_get_function_name({}, nid), addr); + } + else + { + LOG_NOTICE(LOADER, "** Special: &[%s] at 0x%x", ppu_get_variable_name({}, nid), addr); + } + + result.emplace(nid, addr); + } + + addr += lib.size ? lib.size : sizeof(ppu_prx_module_info); + continue; + } + + const std::string module_name(lib.name.get_ptr()); + + LOG_NOTICE(LOADER, "** Exported module '%s' (0x%x, 0x%x, 0x%x, 0x%x)", module_name, lib.vnids, lib.vstubs, lib.unk4, lib.unk5); + + if (lib.num_tlsvar) + { + LOG_FATAL(LOADER, "Unexpected num_tlsvar (%u)!", lib.num_tlsvar); + } + + // Static module + const auto _sm = ppu_module_manager::get_module(module_name); + + const auto fnids = +lib.nids; + const auto faddrs = +lib.addrs; + + // Get functions + for (u32 i = 0, end = lib.num_func; i < end; i++) + { + const u32 fnid = fnids[i]; + const u32 faddr = faddrs[i]; + LOG_NOTICE(LOADER, "**** %s export: [%s] at 0x%x", module_name, ppu_get_function_name(module_name, fnid), faddr); + + // Function linkage info + auto& flink = link->modules[module_name].functions[fnid]; + + if (flink.first) + { + LOG_FATAL(LOADER, "Already linked function '%s' in module '%s'", ppu_get_function_name(module_name, fnid), module_name); + } + else + { + // Static function + const auto _sf = _sm && _sm->functions.count(fnid) ? &_sm->functions.at(fnid) : nullptr; + + if (_sf && (_sf->flags & MFF_FORCED_HLE)) + { + // Inject HACK instruction (TODO: guess function size and analyse B instruction, or reimplement BLR flag for HACK instruction) + const auto code = vm::ptr::make(vm::read32(faddr)); + code[0] = ppu_instructions::HACK(_sf->index); + code[1] = ppu_instructions::BLR(); + } + else + { + // Set exported function + flink.first = faddr; + + // Fix imports + for (const auto addr : flink.second) + { + vm::write32(addr, faddr); + //LOG_WARNING(LOADER, "Exported function '%s' in module '%s'", ppu_get_function_name(module_name, fnid), module_name); + } + } + } + } + + const auto vnids = lib.nids + lib.num_func; + const auto vaddrs = lib.addrs + lib.num_func; + + // Get variables + for (u32 i = 0, end = lib.num_var; i < end; i++) + { + const u32 vnid = vnids[i]; + const u32 vaddr = vaddrs[i]; + LOG_NOTICE(LOADER, "**** %s export: &[%s] at 0x%x", module_name, ppu_get_variable_name(module_name, vnid), vaddr); + + // Variable linkage info + auto& vlink = link->modules[module_name].variables[vnid]; + + if (vlink.first) + { + LOG_FATAL(LOADER, "Already linked variable '%s' in module '%s'", ppu_get_variable_name(module_name, vnid), module_name); + } + else + { + // Set exported variable + vlink.first = vaddr; + + // Fix imports + for (const auto vref : vlink.second) + { + ppu_patch_variable_stub(vref, vaddr); + //LOG_WARNING(LOADER, "Exported variable '%s' in module '%s'", ppu_get_variable_name(module_name, vnid), module_name); + } + } + } + + addr += lib.size ? lib.size : sizeof(ppu_prx_module_info); + } + + return result; +} + +static void ppu_load_imports(const std::shared_ptr& link, u32 imports_start, u32 imports_end) +{ + for (u32 addr = imports_start; addr < imports_end;) + { + const auto& lib = vm::_ref(addr); + + const std::string module_name(lib.name.get_ptr()); + + LOG_NOTICE(LOADER, "** Imported module '%s' (0x%x, 0x%x)", module_name, lib.unk4, lib.unk5); + + if (lib.num_tlsvar) + { + LOG_FATAL(LOADER, "Unexpected num_tlsvar (%u)!", lib.num_tlsvar); + } + + // Static module + const auto _sm = ppu_module_manager::get_module(module_name); + + const auto fnids = +lib.nids; + const auto faddrs = +lib.addrs; + + for (u32 i = 0, end = lib.num_func; i < end; i++) + { + const u32 fnid = fnids[i]; + const u32 fstub = faddrs[i]; + const u32 faddr = (faddrs + i).addr(); + LOG_NOTICE(LOADER, "**** %s import: [%s] -> 0x%x", module_name, ppu_get_function_name(module_name, fnid), fstub); + + // Function linkage info + auto& flink = link->modules[module_name].functions[fnid]; + + // Add new import + flink.second.emplace(faddr); + + // Link if available + if (flink.first) vm::write32(faddr, flink.first); + + //LOG_WARNING(LOADER, "Imported function '%s' in module '%s' (0x%x)", ppu_get_function_name(module_name, fnid), module_name, faddr); + } + + const auto vnids = +lib.vnids; + const auto vstubs = +lib.vstubs; + + for (u32 i = 0, end = lib.num_var; i < end; i++) + { + const u32 vnid = vnids[i]; + const u32 vref = vstubs[i]; + LOG_NOTICE(LOADER, "**** %s import: &[%s] (ref=*0x%x)", module_name, ppu_get_variable_name(module_name, vnid), vref); + + // Variable linkage info + auto& vlink = link->modules[module_name].variables[vnid]; + + // Add new import + vlink.second.emplace(vref); + + // Link if available + if (vlink.first) ppu_patch_variable_stub(vref, vlink.first); + + //LOG_WARNING(LOADER, "Imported variable '%s' in module '%s' (0x%x)", ppu_get_variable_name(module_name, vnid), module_name, vlink.first); + } + + addr += lib.size ? lib.size : sizeof(ppu_prx_module_info); + } +} + +template<> +std::shared_ptr ppu_prx_loader::load() const +{ + std::vector segments; + + for (const auto& prog : progs) + { + LOG_NOTICE(LOADER, "** Segment: p_type=0x%x, p_vaddr=0x%llx, p_filesz=0x%llx, p_memsz=0x%llx, flags=0x%x", prog.p_type, prog.p_vaddr, prog.p_filesz, prog.p_memsz, prog.p_flags); + + switch (const u32 p_type = prog.p_type) + { + case 0x1: // LOAD + { + if (prog.p_memsz) + { + const u32 mem_size = fmt::narrow("Invalid p_memsz (0x%llx)" HERE, prog.p_memsz); + const u32 file_size = fmt::narrow("Invalid p_filesz (0x%llx)" HERE, prog.p_filesz); + const u32 init_addr = fmt::narrow("Invalid p_vaddr (0x%llx)" HERE, prog.p_vaddr); + + // Alloc segment memory + const u32 addr = vm::alloc(mem_size, vm::main); + + if (!addr) + { + throw fmt::exception("vm::alloc() failed (size=0x%x)", mem_size); + } + + // Copy data + std::memcpy(vm::base(addr), prog.bin.data(), file_size); + LOG_WARNING(LOADER, "**** Loaded to 0x%x (size=0x%x)", addr, mem_size); + + segments.push_back(addr); + } + + break; + } + + case 0x700000a4: break; // Relocations + + default: LOG_ERROR(LOADER, "Unknown segment type! 0x%08x", p_type); + } + } + + // Do relocations + for (auto& prog : progs) + { + switch (const u32 p_type = prog.p_type) + { + case 0x700000a4: + { + // Relocation information of the SCE_PPURELA segment + struct ppu_prx_relocation_info + { + be_t offset; + be_t unk0; + u8 index_value; + u8 index_addr; + be_t type; + vm::bptr ptr; + }; + + for (uint i = 0; i < prog.p_filesz; i += sizeof(ppu_prx_relocation_info)) + { + const auto& rel = reinterpret_cast(prog.bin[i]); + + const u32 raddr = vm::cast(segments.at(rel.index_addr) + rel.offset, HERE); + const u64 rdata = segments.at(rel.index_value) + rel.ptr.addr(); + + switch (const u32 type = rel.type) + { + case 1: + { + const u32 value = vm::_ref(raddr) = static_cast(rdata); + LOG_TRACE(LOADER, "**** RELOCATION(1): 0x%x <- 0x%08x (0x%llx)", raddr, value, rdata); + break; + } + + case 4: + { + const u16 value = vm::_ref(raddr) = static_cast(rdata); + LOG_TRACE(LOADER, "**** RELOCATION(4): 0x%x <- 0x%04x (0x%llx)", raddr, value, rdata); + break; + } + + case 5: + { + const u16 value = vm::_ref(raddr) = static_cast(rdata >> 16); + LOG_TRACE(LOADER, "**** RELOCATION(5): 0x%x <- 0x%04x (0x%llx)", raddr, value, rdata); + break; + } + + case 6: + { + const u16 value = vm::_ref(raddr) = static_cast(rdata >> 16) + (rdata & 0x8000 ? 1 : 0); + LOG_TRACE(LOADER, "**** RELOCATION(6): 0x%x <- 0x%04x (0x%llx)", raddr, value, rdata); + break; + } + + case 10: + case 44: + case 57: + default: LOG_ERROR(LOADER, "**** RELOCATION(%u): Illegal/Unknown type! (addr=0x%x)", type, raddr); + } + } + + break; + } + } + } + + // Access linkage information object + const auto link = fxm::get_always(); + + // Create new PRX object + auto prx = idm::make_ptr(); + + if (!progs.empty() && progs[0].p_paddr) + { + struct ppu_prx_library_info + { + be_t attributes; + be_t version; + char name[28]; + be_t toc; + be_t exports_start; + be_t exports_end; + be_t imports_start; + be_t imports_end; + }; + + // Access library information (TODO) + const auto& lib_info = vm::_ref(vm::cast(segments[0] + progs[0].p_paddr - progs[0].p_offset, HERE)); + const auto& lib_name = std::string(lib_info.name); + + LOG_WARNING(LOADER, "Library %s (toc=0x%x, rtoc=0x%x):", lib_name, lib_info.toc, lib_info.toc + segments[0]); + + prx->specials = ppu_load_exports(link, lib_info.exports_start, lib_info.exports_end); + + ppu_load_imports(link, lib_info.imports_start, lib_info.imports_end); + } + else + { + LOG_FATAL(LOADER, "Library %s: PRX library info not found"); + } + + prx->start.set(prx->specials[0xbc9a0086]); + prx->stop.set(prx->specials[0xab779874]); + prx->exit.set(prx->specials[0x3ab9a95e]); + + return prx; +} + +template<> +void ppu_exec_loader::load() const +{ + ppu_initialize_modules(); + + if (g_cfg_hook_ppu_funcs) + { + LOG_TODO(LOADER, "'Hook static functions' option deactivated"); + } + + // Access linkage information object + const auto link = fxm::get_always(); + + // Allocate memory at fixed positions + for (const auto& prog : progs) + { + const u32 addr = vm::cast(prog.p_vaddr, HERE); + const u32 size = fmt::narrow("Invalid p_memsz: 0x%llx" HERE, prog.p_memsz); + + if (prog.p_type == 0x1 /* LOAD */ && prog.p_memsz) + { + if (prog.bin.size() > size || prog.bin.size() != prog.p_filesz) + throw fmt::exception("Invalid binary size (0x%llx, memsz=0x%x)", prog.bin.size(), size); + + if (!vm::falloc(addr, size, vm::main)) + throw fmt::exception("vm::falloc() failed (addr=0x%x, memsz=0x%x)", addr, size); + + std::memcpy(vm::base(addr), prog.bin.data(), prog.bin.size()); + } + } + + // Load other programs + for (auto& prog : progs) + { + switch (const u32 p_type = prog.p_type) + { + case 0x00000001: break; //LOAD + + case 0x00000007: //TLS + { + const u32 addr = vm::cast(prog.p_vaddr, HERE); + const u32 filesz = fmt::narrow("Invalid p_filesz (0x%llx)" HERE, prog.p_filesz); + const u32 memsz = fmt::narrow("Invalid p_memsz (0x%llx)" HERE, prog.p_memsz); + Emu.SetTLSData(addr, filesz, memsz); + LOG_NOTICE(LOADER, "*** TLS segment addr: 0x%08x", Emu.GetTLSAddr()); + LOG_NOTICE(LOADER, "*** TLS segment size: 0x%08x", Emu.GetTLSFilesz()); + LOG_NOTICE(LOADER, "*** TLS memory size: 0x%08x", Emu.GetTLSMemsz()); + break; + } + + case 0x60000001: //LOOS+1 + { + if (prog.p_filesz) + { + struct process_param_t + { + be_t size; + be_t magic; + be_t version; + be_t sdk_version; + be_t primary_prio; + be_t primary_stacksize; + be_t malloc_pagesize; + be_t ppc_seg; + //be_t crash_dump_param_addr; + }; + + const auto& info = vm::ps3::_ref(vm::cast(prog.p_vaddr, HERE)); + + if (info.size < sizeof(process_param_t)) + { + LOG_WARNING(LOADER, "Bad process_param size! [0x%x : 0x%x]", info.size, SIZE_32(process_param_t)); + } + if (info.magic != 0x13bcc5f6) + { + LOG_ERROR(LOADER, "Bad process_param magic! [0x%x]", info.magic); + } + else + { + LOG_NOTICE(LOADER, "*** sdk version: 0x%x", info.sdk_version); + LOG_NOTICE(LOADER, "*** primary prio: %d", info.primary_prio); + LOG_NOTICE(LOADER, "*** primary stacksize: 0x%x", info.primary_stacksize); + LOG_NOTICE(LOADER, "*** malloc pagesize: 0x%x", info.malloc_pagesize); + LOG_NOTICE(LOADER, "*** ppc seg: 0x%x", info.ppc_seg); + //LOG_NOTICE(LOADER, "*** crash dump param addr: 0x%x", info.crash_dump_param_addr); + + Emu.SetParams(info.sdk_version, info.malloc_pagesize, std::max(info.primary_stacksize, 0x4000), info.primary_prio); + } + } + break; + } + + case 0x60000002: //LOOS+2 + { + if (prog.p_filesz) + { + struct ppu_proc_prx_param_t + { + be_t size; + be_t magic; + be_t version; + be_t unk0; + be_t libent_start; + be_t libent_end; + be_t libstub_start; + be_t libstub_end; + be_t ver; + be_t unk1; + be_t unk2; + }; + + const auto& proc_prx_param = vm::_ref(vm::cast(prog.p_vaddr, HERE)); + + if (proc_prx_param.magic != 0x1b434cec) + { + throw fmt::exception("Bad magic! (0x%x)", proc_prx_param.magic); + } + + ppu_load_exports(link, proc_prx_param.libent_start, proc_prx_param.libent_end); + ppu_load_imports(link, proc_prx_param.libstub_start, proc_prx_param.libstub_end); + } + break; + } + default: + { + LOG_ERROR(LOADER, "Unknown phdr type (0x%08x)", p_type); + } + } + } + + // Initialize process + std::vector start_funcs; + + // Load modules + const std::string& lle_dir = vfs::get("/dev_flash/sys/external"); + + if (g_cfg_load_liblv2) + { + const ppu_prx_loader loader = fs::file(lle_dir + "/liblv2.sprx"); + + if (loader == elf_error::ok) + { + start_funcs.push_back(loader.load()->start.addr()); + } + else + { + throw fmt::exception("Failed to load liblv2.sprx: %s", bijective_find(loader, "???")); + } + } + else + { + for (const auto& name : g_cfg_load_libs.get_set()) + { + const ppu_prx_loader loader = fs::file(lle_dir + '/' + name); + + if (loader == elf_error::ok) + { + LOG_WARNING(LOADER, "Loading library: %s", name); + + const auto prx = loader.load(); + + if (prx->start) + { + start_funcs.push_back(prx->start.addr()); + } + } + else + { + LOG_FATAL(LOADER, "Failed to load %s: %s", name, bijective_find(loader, "???")); + } + } + } + + // Check unlinked functions and variables + for (auto& module : link->modules) + { + const auto _sm = ppu_module_manager::get_module(module.first); + + if (!_sm) + { + LOG_ERROR(LOADER, "Unknown module '%s'", module.first); + } + else + { + // Allocate HLE variables (TODO) + for (auto& var : _sm->variables) + { + var.second.var->set(vm::alloc(var.second.size, vm::main, std::max(var.second.align, 4096))); + LOG_WARNING(LOADER, "Allocated variable '%s' in module '%s' at *0x%x", var.second.name, module.first, var.second.var->addr()); + } + + // Initialize HLE variables (TODO) + for (auto& var : _sm->variables) + { + var.second.init(); + } + } + + for (auto& entry : module.second.functions) + { + const u32 fnid = entry.first; + const u32 faddr = entry.second.first; + + if (faddr == 0) + { + if (const auto _sf = _sm && _sm->functions.count(fnid) ? &_sm->functions.at(fnid) : nullptr) + { + // Static function + for (auto& import : entry.second.second) + { + const u32 stub = vm::read32(import); + + if (!ppu_patch_import_stub(stub, _sf->index)) + { + LOG_ERROR(LOADER, "Failed to inject code for function '%s' in module '%s' (0x%x)", _sf->name, module.first, stub); + } + else + { + LOG_NOTICE(LOADER, "Injected hack for function '%s' in module '%s' (*0x%x)", _sf->name, module.first, stub); + } + } + } + else + { + // TODO + const u32 index = ::size32(g_ppu_function_cache); + g_ppu_function_cache.emplace_back(); + g_ppu_fnid_cache.emplace_back(fnid); + + LOG_ERROR(LOADER, "Unknown function '%s' in module '%s' (index %u)", ppu_get_function_name(module.first, fnid), module.first, index); + + for (auto& import : entry.second.second) + { + if (_sm) + { + const u32 stub = vm::read32(import); + + if (!ppu_patch_import_stub(stub, index)) + { + LOG_ERROR(LOADER, "Failed to inject code for function '%s' in module '%s' (0x%x)", ppu_get_function_name(module.first, fnid), module.first, stub); + } + else + { + LOG_NOTICE(LOADER, "Injected hack for function '%s' in module '%s' (*0x%x)", ppu_get_function_name(module.first, fnid), module.first, stub); + } + } + + LOG_WARNING(LOADER, "** Not linked at *0x%x", import); + } + } + } + } + + for (auto& entry : module.second.variables) + { + const u32 vnid = entry.first; + const u32 vaddr = entry.second.first; + + if (vaddr == 0) + { + // Static variable + if (const auto _sv = _sm && _sm->variables.count(vnid) ? &_sm->variables.at(vnid) : nullptr) + { + LOG_NOTICE(LOADER, "Linking HLE variable '%s' in module '%s' (*0x%x):", ppu_get_variable_name(module.first, vnid), module.first, _sv->var->addr()); + + for (auto& ref : entry.second.second) + { + ppu_patch_variable_stub(ref, _sv->var->addr()); + LOG_NOTICE(LOADER, "** Linked at ref=*0x%x", ref); + } + } + else + { + LOG_ERROR(LOADER, "Unknown variable '%s' in module '%s'", ppu_get_variable_name(module.first, vnid), module.first); + + for (auto& ref : entry.second.second) + { + LOG_WARNING(LOADER, "** Not linked at ref=*0x%x", ref); + } + } + } + else + { + // Retro-link LLE variable (TODO: HLE must not be allocated/initialized in this case) + if (const auto _sv = _sm && _sm->variables.count(vnid) ? &_sm->variables.at(vnid) : nullptr) + { + _sv->var->set(vaddr); + LOG_NOTICE(LOADER, "Linked LLE variable '%s' in module '%s' -> 0x%x", ppu_get_variable_name(module.first, vnid), module.first, vaddr); + } + } + } + } + + // TODO: adjust for liblv2 loading option + using namespace ppu_instructions; + + auto ppu_thr_stop_data = vm::ptr::make(vm::alloc(2 * 4, vm::main)); + Emu.SetCPUThreadStop(ppu_thr_stop_data.addr()); + ppu_thr_stop_data[0] = HACK(1); + ppu_thr_stop_data[1] = BLR(); + + static const int branch_size = 10 * 4; + + auto make_branch = [](vm::ptr& ptr, u32 addr) + { + const u32 stub = vm::read32(addr); + const u32 rtoc = vm::read32(addr + 4); + + *ptr++ = LI(r0, 0); + *ptr++ = ORI(r0, r0, stub & 0xffff); + *ptr++ = ORIS(r0, r0, stub >> 16); + *ptr++ = LI(r2, 0); + *ptr++ = ORI(r2, r2, rtoc & 0xffff); + *ptr++ = ORIS(r2, r2, rtoc >> 16); + *ptr++ = MTCTR(r0); + *ptr++ = BCTRL(); + }; + + auto entry = vm::ptr::make(vm::alloc(48 + branch_size * (::size32(start_funcs) + 1), vm::main)); + + // Save initialization args + *entry++ = MR(r14, r3); + *entry++ = MR(r15, r4); + *entry++ = MR(r16, r5); + *entry++ = MR(r17, r6); + *entry++ = MR(r18, r11); + *entry++ = MR(r19, r12); + + if (!g_cfg_load_liblv2) + { + // Call sys_initialize_tls explicitly + *entry++ = MR(r3, r7); + *entry++ = MR(r4, r8); + *entry++ = MR(r5, r9); + *entry++ = MR(r6, r10); + *entry++ = HACK(FIND_FUNC(sys_initialize_tls)); + } + + for (auto& f : start_funcs) + { + // Reset arguments (TODO) + *entry++ = LI(r3, 0); + *entry++ = LI(r4, 0); + make_branch(entry, f); + } + + // Restore initialization args + *entry++ = MR(r3, r14); + *entry++ = MR(r4, r15); + *entry++ = MR(r5, r16); + *entry++ = MR(r6, r17); + *entry++ = MR(r11, r18); + *entry++ = MR(r12, r19); + + // Branch to initialization + make_branch(entry, vm::cast(header.e_entry, HERE)); + + auto ppu = idm::make_ptr("main_thread"); + + ppu->PC = entry.addr() & -0x1000; + ppu->stack_size = Emu.GetPrimaryStackSize(); + ppu->prio = Emu.GetPrimaryPrio(); + ppu->cpu_init(); + + ppu->GPR[2] = 0xdeadbeef; // rtoc + ppu->GPR[11] = 0xabadcafe; // OPD ??? + ppu->GPR[12] = Emu.GetMallocPageSize(); + + std::initializer_list args = { Emu.GetPath()/*, "-emu"s*/ }; + + auto argv = vm::ptr::make(vm::alloc(SIZE_32(u64) * ::size32(args), vm::main)); + auto envp = vm::ptr::make(vm::alloc(::align(SIZE_32(u64), 0x10), vm::main)); + *envp = 0; + + ppu->GPR[3] = args.size(); // argc + ppu->GPR[4] = argv.addr(); + ppu->GPR[5] = envp.addr(); + ppu->GPR[6] = 0; // ??? + + for (const auto& arg : args) + { + const u32 arg_size = ::align(::size32(arg) + 1, 0x10); + const u32 arg_addr = vm::alloc(arg_size, vm::main); + + std::memcpy(vm::base(arg_addr), arg.data(), arg_size); + + *argv++ = arg_addr; + } + + // Arguments for sys_initialize_tls() + ppu->GPR[7] = ppu->id; + ppu->GPR[8] = Emu.GetTLSAddr(); + ppu->GPR[9] = Emu.GetTLSFilesz(); + ppu->GPR[10] = Emu.GetTLSMemsz(); + + // Set memory protections + //for (const auto& prog : progs) + //{ + // const u32 addr = static_cast(prog.p_vaddr); + // const u32 size = static_cast(prog.p_memsz); + + // if (prog.p_type == 0x1 /* LOAD */ && prog.p_memsz && (prog.p_flags & 0x2) == 0 /* W */) + // { + // // Set memory protection to read-only where necessary + // ASSERT(vm::page_protect(addr, ::align(size, 0x1000), 0, 0, vm::page_writable)); + // } + //} +} diff --git a/rpcs3/Emu/Cell/PPUModule.h b/rpcs3/Emu/Cell/PPUModule.h new file mode 100644 index 0000000000..81d4dadfcf --- /dev/null +++ b/rpcs3/Emu/Cell/PPUModule.h @@ -0,0 +1,255 @@ +#pragma once + +#include "Utilities/Config.h" +#include "PPUFunction.h" +#include "PPUCallback.h" +#include "ErrorCodes.h" + +namespace vm { using namespace ps3; } + +// Generate FNID or VNID for given name +extern u32 ppu_generate_id(const char* name); + +// Flags set with REG_FUNC +enum ppu_static_function_flags : u32 +{ + MFF_FORCED_HLE = (1 << 0), // Always call HLE function (TODO: deactivated) + + MFF_PERFECT = MFF_FORCED_HLE, // Indicates that function is completely implemented and can replace LLE implementation +}; + +// HLE function information +struct ppu_static_function +{ + const char* name; + u32 index; // Index for ppu_function_manager + u32 flags; +}; + +// HLE variable information +struct ppu_static_variable +{ + const char* name; + vm::gvar* var; // Pointer to variable address storage + void(*init)(); // Variable initialization function + u32 size; + u32 align; +}; + +// HLE module information +class ppu_static_module final +{ +public: + const std::string name; + + task_stack on_load; + task_stack on_unload; + + std::unordered_map functions; + std::unordered_map variables; + +public: + ppu_static_module(const char* name); + + ppu_static_module(const char* name, void(*init)()) + : ppu_static_module(name) + { + init(); + } + + ppu_static_module(const char* name, void(*init)(ppu_static_module* _this)) + : ppu_static_module(name) + { + init(this); + } +}; + +class ppu_module_manager final +{ + friend class ppu_static_module; + + static never_inline auto& access() + { + static std::unordered_map map; + + return map; + } + + static never_inline void register_module(ppu_static_module* module) + { + access().emplace(module->name, module); + } + + static never_inline auto& access_static_function(const char* module, u32 fnid) + { + return access().at(module)->functions[fnid]; + } + + static never_inline auto& access_static_variable(const char* module, u32 vnid) + { + return access().at(module)->variables[vnid]; + } + +public: + static never_inline const ppu_static_module* get_module(const std::string& name) + { + const auto& map = access(); + const auto found = map.find(name); + return found != map.end() ? found->second : nullptr; + } + + template + static void register_static_function(const char* module, const char* name, ppu_function_t func, u32 fnid, u32 flags) + { + auto& info = access_static_function(module, fnid); + + info.name = name; + info.index = ppu_function_manager::register_function(func); + info.flags = flags; + } + + template + static void register_static_variable(const char* module, const char* name, u32 vnid, void(*init)()) + { + static_assert(std::is_same::value, "Static variable registration: vm::gvar expected"); + + auto& info = access_static_variable(module, vnid); + + info.name = name; + info.var = reinterpret_cast*>(Var); + info.init = init ? init : [] {}; + info.size = SIZE_32(typename T::type); + info.align = ALIGN_32(typename T::type); + } + + static const ppu_static_module cellAdec; + static const ppu_static_module cellAtrac; + static const ppu_static_module cellAtracMulti; + static const ppu_static_module cellAudio; + static const ppu_static_module cellAvconfExt; + static const ppu_static_module cellBGDL; + static const ppu_static_module cellCamera; + static const ppu_static_module cellCelp8Enc; + static const ppu_static_module cellCelpEnc; + static const ppu_static_module cellDaisy; + static const ppu_static_module cellDmux; + static const ppu_static_module cellFiber; + static const ppu_static_module cellFont; + static const ppu_static_module cellFontFT; + static const ppu_static_module cellFs; + static const ppu_static_module cellGame; + static const ppu_static_module cellGameExec; + static const ppu_static_module cellGcmSys; + static const ppu_static_module cellGem; + static const ppu_static_module cellGifDec; + static const ppu_static_module cellHttp; + static const ppu_static_module cellHttps; + static const ppu_static_module cellHttpUtil; + static const ppu_static_module cellImeJp; + static const ppu_static_module cellJpgDec; + static const ppu_static_module cellJpgEnc; + static const ppu_static_module cellKey2char; + static const ppu_static_module cellL10n; + static const ppu_static_module cellMic; + static const ppu_static_module cellMusic; + static const ppu_static_module cellMusicDecode; + static const ppu_static_module cellMusicExport; + static const ppu_static_module cellNetCtl; + static const ppu_static_module cellOskDialog; + static const ppu_static_module cellOvis; + static const ppu_static_module cellPamf; + static const ppu_static_module cellPhotoDecode; + static const ppu_static_module cellPhotoExport; + static const ppu_static_module cellPhotoImportUtil; + static const ppu_static_module cellPngDec; + static const ppu_static_module cellPngEnc; + static const ppu_static_module cellPrint; + static const ppu_static_module cellRec; + static const ppu_static_module cellRemotePlay; + static const ppu_static_module cellResc; + static const ppu_static_module cellRtc; + static const ppu_static_module cellRudp; + static const ppu_static_module cellSail; + static const ppu_static_module cellSailRec; + static const ppu_static_module cellSaveData; + static const ppu_static_module cellMinisSaveData; + static const ppu_static_module cellScreenShot; + static const ppu_static_module cellSearch; + static const ppu_static_module cellSheap; + static const ppu_static_module cellSpudll; + static const ppu_static_module cellSpurs; + static const ppu_static_module cellSpursJq; + static const ppu_static_module cellSsl; + static const ppu_static_module cellSubdisplay; + static const ppu_static_module cellSync; + static const ppu_static_module cellSync2; + static const ppu_static_module cellSysconf; + static const ppu_static_module cellSysmodule; + static const ppu_static_module cellSysutil; + static const ppu_static_module cellSysutilAp; + static const ppu_static_module cellSysutilAvc; + static const ppu_static_module cellSysutilAvc2; + static const ppu_static_module cellSysutilMisc; + static const ppu_static_module cellUsbd; + static const ppu_static_module cellUsbPspcm; + static const ppu_static_module cellUserInfo; + static const ppu_static_module cellVdec; + static const ppu_static_module cellVideoExport; + static const ppu_static_module cellVideoUpload; + static const ppu_static_module cellVoice; + static const ppu_static_module cellVpost; + static const ppu_static_module libmixer; + static const ppu_static_module libsnd3; + static const ppu_static_module libsynth2; + static const ppu_static_module sceNp; + static const ppu_static_module sceNp2; + static const ppu_static_module sceNpClans; + static const ppu_static_module sceNpCommerce2; + static const ppu_static_module sceNpSns; + static const ppu_static_module sceNpTrophy; + static const ppu_static_module sceNpTus; + static const ppu_static_module sceNpUtil; + static const ppu_static_module sys_io; + static const ppu_static_module libnet; + static const ppu_static_module sysPrxForUser; + static const ppu_static_module sys_libc; + static const ppu_static_module sys_lv2dbg; +}; + +// Call specified function directly if LLE is not available, call LLE equivalent in callback style otherwise +template> +inline RT ppu_execute_function_or_callback(const char* name, PPUThread& ppu, Args&&... args) +{ + const auto previous_function = ppu.last_function; // TODO + + try + { + return Func(std::forward(args)...); + } + catch (const std::exception&) + { + LOG_ERROR(PPU, "Function '%s' aborted", ppu.last_function); + ppu.last_function = previous_function; + throw; + } + catch (...) + { + LOG_WARNING(PPU, "Function '%s' aborted", ppu.last_function); + ppu.last_function = previous_function; + throw; + } + + ppu.last_function = previous_function; +} + +#define CALL_FUNC(ppu, func, ...) ppu_execute_function_or_callback(#func, ppu, __VA_ARGS__) + +#define REG_FNID(module, nid, func, ...) ppu_module_manager::register_static_function(#module, #func, BIND_FUNC(func), nid, {__VA_ARGS__}) + +#define REG_FUNC(module, func, ...) REG_FNID(module, ppu_generate_id(#func), func, __VA_ARGS__) + +#define REG_VNID(module, nid, var, ...) ppu_module_manager::register_static_variable(#module, #var, nid, {__VA_ARGS__}) + +#define REG_VAR(module, var, ...) REG_VNID(module, ppu_generate_id(#var), var, __VA_ARGS__) + +#define UNIMPLEMENTED_FUNC(module) module.todo("%s", __func__) diff --git a/rpcs3/Emu/Cell/PPUOpcodes.h b/rpcs3/Emu/Cell/PPUOpcodes.h index 185f22905b..36691c9c8e 100644 --- a/rpcs3/Emu/Cell/PPUOpcodes.h +++ b/rpcs3/Emu/Cell/PPUOpcodes.h @@ -1,881 +1,652 @@ #pragma once -namespace PPU_opcodes +#include "../../../Utilities/BitField.h" + +template using ppu_bf_t = bf_t; + +union ppu_opcode_t { - enum PPU_MainOpcodes - { - HACK = 0x01, //HLE Call - TDI = 0x02, //Trap Doubleword Immediate - TWI = 0x03, //Trap Word Immediate - G_04 = 0x04, - MULLI = 0x07, //Multiply Low Immediate - SUBFIC = 0x08, //Subtract from Immediate Carrying - //DOZI = 0x09, - CMPLI = 0x0a, //Compare Logical Immediate - CMPI = 0x0b, //Compare Immediate - ADDIC = 0x0c, //Add Immediate Carrying - ADDIC_ = 0x0d, //Add Immediate Carrying and Record - ADDI = 0x0e, //Add Immediate - ADDIS = 0x0f, //Add Immediate Shifted - BC = 0x10, //Branch Conditional - SC = 0x11, //System Call - B = 0x12, //Branch - G_13 = 0x13, - RLWIMI = 0x14, //Rotate Left Word Immediate then Mask Insert - RLWINM = 0x15, //Rotate Left Word Immediate then AND with Mask - RLWNM = 0x17, //Rotate Left Word then AND with Mask - ORI = 0x18, //OR Immediate - ORIS = 0x19, //OR Immediate Shifted - XORI = 0x1a, //XOR Immediate - XORIS = 0x1b, //XOR Immediate Shifted - ANDI_ = 0x1c, //AND Immediate - ANDIS_ = 0x1d, //AND Immediate Shifted - G_1e = 0x1e, - G_1f = 0x1f, - LWZ = 0x20, //Load Word and Zero Indexed - LWZU = 0x21, //Load Word and Zero with Update Indexed - LBZ = 0x22, //Load Byte and Zero - LBZU = 0x23, //Load Byte and Zero with Update - STW = 0x24, //Store Word - STWU = 0x25, //Store Word with Update - STB = 0x26, //Store Byte - STBU = 0x27, //Store Byte with Update - LHZ = 0x28, //Load Halfword and Zero - LHZU = 0x29, //Load Halfword and Zero with Update - LHA = 0x2a, //Load Halfword Algebraic with Update - LHAU = 0x2b, //Load Halfword Algebraic - STH = 0x2c, //Store Halfword - STHU = 0x2d, //Store Halfword with Update - LMW = 0x2e, //Load Multiple Word - STMW = 0x2f, //Store Multiple Word - LFS = 0x30, //Load Floating-Point Single - LFSU = 0x31, //Load Floating-Point Single with Update - LFD = 0x32, //Load Floating-Point Double - LFDU = 0x33, //Load Floating-Point Double with Update - STFS = 0x34, //Store Floating-Point Single - STFSU = 0x35, //Store Floating-Point Single with Update - STFD = 0x36, //Store Floating-Point Double - STFDU = 0x37, //Store Floating-Point Double with Update - LFQ = 0x38, // - LFQU = 0x39, // - G_3a = 0x3a, - G_3b = 0x3b, - G_3e = 0x3e, - G_3f = 0x3f, - }; + u32 opcode; - enum G_04Opcodes - { - VADDUBM = 0x0, - VMAXUB = 0x2, - VRLB = 0x4, - VCMPEQUB = 0x6, - VMULOUB = 0x8, - VADDFP = 0xa, - VMRGHB = 0xc, - VPKUHUM = 0xe, - VADDUHM = 0x40, - VMAXUH = 0x42, - VRLH = 0x44, - VCMPEQUH = 0x46, - VMULOUH = 0x48, - VSUBFP = 0x4a, - VMRGHH = 0x4c, - VPKUWUM = 0x4e, - VADDUWM = 0x80, - VMAXUW = 0x82, - VRLW = 0x84, - VCMPEQUW = 0x86, - VMRGHW = 0x8c, - VPKUHUS = 0x8e, - VCMPEQFP = 0xc6, - VPKUWUS = 0xce, - VMAXSB = 0x102, - VSLB = 0x104, - VMULOSB = 0x108, - VREFP = 0x10a, - VMRGLB = 0x10c, - VPKSHUS = 0x10e, - VMAXSH = 0x142, - VSLH = 0x144, - VMULOSH = 0x148, - VRSQRTEFP = 0x14a, - VMRGLH = 0x14c, - VPKSWUS = 0x14e, - VADDCUW = 0x180, - VMAXSW = 0x182, - VSLW = 0x184, - VEXPTEFP = 0x18a, - VMRGLW = 0x18c, - VPKSHSS = 0x18e, - VSL = 0x1c4, - VCMPGEFP = 0x1c6, - VLOGEFP = 0x1ca, - VPKSWSS = 0x1ce, - VADDUBS = 0x200, - VMINUB = 0x202, - VSRB = 0x204, - VCMPGTUB = 0x206, - VMULEUB = 0x208, - VRFIN = 0x20a, - VSPLTB = 0x20c, - VUPKHSB = 0x20e, - VADDUHS = 0x240, - VMINUH = 0x242, - VSRH = 0x244, - VCMPGTUH = 0x246, - VMULEUH = 0x248, - VRFIZ = 0x24a, - VSPLTH = 0x24c, - VUPKHSH = 0x24e, - VADDUWS = 0x280, - VMINUW = 0x282, - VSRW = 0x284, - VCMPGTUW = 0x286, - VRFIP = 0x28a, - VSPLTW = 0x28c, - VUPKLSB = 0x28e, - VSR = 0x2c4, - VCMPGTFP = 0x2c6, - VRFIM = 0x2ca, - VUPKLSH = 0x2ce, - VADDSBS = 0x300, - VMINSB = 0x302, - VSRAB = 0x304, - VCMPGTSB = 0x306, - VMULESB = 0x308, - VCFUX = 0x30a, - VSPLTISB = 0x30c, - VPKPX = 0x30e, - VADDSHS = 0x340, - VMINSH = 0x342, - VSRAH = 0x344, - VCMPGTSH = 0x346, - VMULESH = 0x348, - VCFSX = 0x34a, - VSPLTISH = 0x34c, - VUPKHPX = 0x34e, - VADDSWS = 0x380, - VMINSW = 0x382, - VSRAW = 0x384, - VCMPGTSW = 0x386, - VCTUXS = 0x38a, - VSPLTISW = 0x38c, - VCMPBFP = 0x3c6, - VCTSXS = 0x3ca, - VUPKLPX = 0x3ce, - VSUBUBM = 0x400, - VAVGUB = 0x402, - VAND = 0x404, - VCMPEQUB_ = 0x406, - VMAXFP = 0x40a, - VSLO = 0x40c, - VSUBUHM = 0x440, - VAVGUH = 0x442, - VANDC = 0x444, - VCMPEQUH_ = 0x446, - VMINFP = 0x44a, - VSRO = 0x44c, - VSUBUWM = 0x480, - VAVGUW = 0x482, - VOR = 0x484, - VCMPEQUW_ = 0x486, - VXOR = 0x4c4, - VCMPEQFP_ = 0x4c6, - VAVGSB = 0x502, - VNOR = 0x504, - VAVGSH = 0x542, - VSUBCUW = 0x580, - VAVGSW = 0x582, - VCMPGEFP_ = 0x5c6, - VSUBUBS = 0x600, - MFVSCR = 0x604, - VCMPGTUB_ = 0x606, - VSUM4UBS = 0x608, - VSUBUHS = 0x640, - MTVSCR = 0x644, - VCMPGTUH_ = 0x646, - VSUM4SHS = 0x648, - VSUBUWS = 0x680, - VCMPGTUW_ = 0x686, - VSUM2SWS = 0x688, - VCMPGTFP_ = 0x6c6, - VSUBSBS = 0x700, - VCMPGTSB_ = 0x706, - VSUM4SBS = 0x708, - VSUBSHS = 0x740, - VCMPGTSH_ = 0x746, - VSUBSWS = 0x780, - VCMPGTSW_ = 0x786, - VSUMSWS = 0x788, - VCMPBFP_ = 0x7c6, - }; + ppu_bf_t main; // 0..5 + cf_t, ppu_bf_t> sh64; // 30 + 16..20 + cf_t, ppu_bf_t> mbe64; // 26 + 21..25 + ppu_bf_t vuimm; // 11..15 + ppu_bf_t vs; // 6..10 + ppu_bf_t vsh; // 22..25 + ppu_bf_t oe; // 21 + ppu_bf_t spr; // 11..20 + ppu_bf_t vc; // 21..25 + ppu_bf_t vb; // 16..20 + ppu_bf_t va; // 11..15 + ppu_bf_t vd; // 6..10 + ppu_bf_t lk; // 31 + ppu_bf_t aa; // 30 + ppu_bf_t rb; // 16..20 + ppu_bf_t ra; // 11..15 + ppu_bf_t rd; // 6..10 + ppu_bf_t uimm16; // 16..31 + ppu_bf_t l11; // 11 + ppu_bf_t rs; // 6..10 + ppu_bf_t simm16; // 16..31, signed + ppu_bf_t ds; // 16..29, signed + ppu_bf_t vsimm; // 11..15, signed + ppu_bf_t ll; // 6..31, signed + ppu_bf_t lev; // 20..26 + ppu_bf_t i; // 16..19 + ppu_bf_t crfs; // 11..13 + ppu_bf_t l10; // 10 + ppu_bf_t crfd; // 6..8 + ppu_bf_t crbb; // 16..20 + ppu_bf_t crba; // 11..15 + ppu_bf_t crbd; // 6..10 + ppu_bf_t rc; // 31 + ppu_bf_t me32; // 26..30 + ppu_bf_t mb32; // 21..25 + ppu_bf_t sh32; // 16..20 + ppu_bf_t bi; // 11..15 + ppu_bf_t bo; // 6..10 + ppu_bf_t bh; // 19..20 + ppu_bf_t frc; // 21..25 + ppu_bf_t frb; // 16..20 + ppu_bf_t fra; // 11..15 + ppu_bf_t frd; // 6..10 + ppu_bf_t crm; // 12..19 + ppu_bf_t frs; // 6..10 + ppu_bf_t flm; // 7..14 + ppu_bf_t l6; // 6 + ppu_bf_t l15; // 15 +}; - enum G_04_VA_Opcodes - { - VMHADDSHS = 0x20, - VMHRADDSHS = 0x21, - VMLADDUHM = 0x22, - VMSUMUBM = 0x24, - VMSUMMBM = 0x25, - VMSUMUHM = 0x26, - VMSUMUHS = 0x27, - VMSUMSHM = 0x28, - VMSUMSHS = 0x29, - VSEL = 0x2a, - VPERM = 0x2b, - VSLDOI = 0x2c, - VMADDFP = 0x2e, - VNMSUBFP = 0x2f, - }; - - enum G_13Opcodes //Field 21 - 30 - { - MCRF = 0x000, - BCLR = 0x010, - CRNOR = 0x021, - CRANDC = 0x081, - ISYNC = 0x096, - CRXOR = 0x0c1, - CRNAND = 0x0e1, - CRAND = 0x101, - CREQV = 0x121, - CRORC = 0x1a1, - CROR = 0x1c1, - BCCTR = 0x210, - }; - - enum G_1eOpcodes //Field 27 - 29 - { - RLDICL = 0x0, - RLDICR = 0x1, - RLDIC = 0x2, - RLDIMI = 0x3, - RLDC_LR = 0x4, - }; - - enum G_1fOpcodes //Field 21 - 30 - { - CMP = 0x000, - TW = 0x004, - LVSL = 0x006, //Load Vector for Shift Left - LVEBX = 0x007, //Load Vector Element Byte Indexed - SUBFC = 0x008, //Subtract from Carrying - MULHDU = 0x009, - ADDC = 0x00a, - MULHWU = 0x00b, - MFOCRF = 0x013, - LWARX = 0x014, - LDX = 0x015, - LWZX = 0x017, - SLW = 0x018, - CNTLZW = 0x01a, - SLD = 0x01b, - AND = 0x01c, - CMPL = 0x020, - LVSR = 0x026, //Load Vector for Shift Right - LVEHX = 0x027, //Load Vector Element Halfword Indexed - SUBF = 0x028, - LDUX = 0x035, //Load Doubleword with Update Indexed - DCBST = 0x036, //Data Cache Block Store - LWZUX = 0x037, - CNTLZD = 0x03a, - ANDC = 0x03c, - TD = 0x044, - LVEWX = 0x047, //Load Vector Element Word Indexed - MULHD = 0x049, - MULHW = 0x04b, - LDARX = 0x054, - DCBF = 0x056, //Data Cache Block Flush - LBZX = 0x057, - LVX = 0x067, //Load Vector Indexed - NEG = 0x068, - LBZUX = 0x077, - NOR = 0x07c, - STVEBX = 0x087, //Store Vector Element Byte Indexed - SUBFE = 0x088, //Subtract from Extended - ADDE = 0x08a, - MTOCRF = 0x090, - STDX = 0x095, - STWCX_ = 0x096, - STWX = 0x097, - STVEHX = 0x0a7, //Store Vector Element Halfword Indexed - STDUX = 0x0b5, - STWUX = 0x0b7, - STVEWX = 0x0c7, //Store Vector Element Word Indexed - SUBFZE = 0x0c8, - ADDZE = 0x0ca, - STDCX_ = 0x0d6, - STBX = 0x0d7, - STVX = 0x0e7, - SUBFME = 0x0e8, - MULLD = 0x0e9, - ADDME = 0x0ea, - MULLW = 0x0eb, - DCBTST = 0x0f6, //Data Cache Block Touch for Store - STBUX = 0x0f7, - DOZ = 0x108, - ADD = 0x10a, - DCBT = 0x116, //Data Cache Block Touch - LHZX = 0x117, - EQV = 0x11c, - ECIWX = 0x136, - LHZUX = 0x137, - XOR = 0x13c, - MFSPR = 0x153, - LWAX = 0x155, - DST = 0x156, //Data Stream Touch - LHAX = 0x157, - LVXL = 0x167, //Load Vector Indexed Last - MFTB = 0x173, - LWAUX = 0x175, - DSTST = 0x176, //Data Stream Touch for Store - LHAUX = 0x177, - STHX = 0x197, //Store Halfword Indexed - ORC = 0x19c, //OR with Complement - ECOWX = 0x1b6, - STHUX = 0x1b7, - OR = 0x1bc, - DIVDU = 0x1c9, - DIVWU = 0x1cb, - MTSPR = 0x1d3, - DCBI = 0x1d6, //Data Cache Block Invalidate - NAND = 0x1dc, - STVXL = 0x1e7, //Store Vector Indexed Last - DIVD = 0x1e9, - DIVW = 0x1eb, - LVLX = 0x207, //Load Vector Left Indexed - SUBFCO = 0x208, - ADDCO = 0x20a, - LDBRX = 0x214, - LSWX = 0x215, - LWBRX = 0x216, - LFSX = 0x217, - SRW = 0x218, - SRD = 0x21b, - LVRX = 0x227, //Load Vector Right Indexed - SUBFO = 0x228, - LFSUX = 0x237, - LSWI = 0x255, - SYNC = 0x256, - LFDX = 0x257, - NEGO = 0x268, - LFDUX = 0x277, - STVLX = 0x287, //Store Vector Left Indexed - SUBFEO = 0x288, - ADDEO = 0x28a, - STDBRX = 0x294, - STSWX = 0x295, - STWBRX = 0x296, - STFSX = 0x297, - STVRX = 0x2a7, //Store Vector Right Indexed - STFSUX = 0x2b7, - SUBFZEO= 0x2c8, - ADDZEO = 0x2ca, - STSWI = 0x2d5, - STFDX = 0x2d7, //Store Floating-Point Double Indexed - SUBFMEO= 0x2e8, - MULLDO = 0x2e9, - ADDMEO = 0x2ea, - MULLWO = 0x2eb, - STFDUX = 0x2f7, - LVLXL = 0x307, //Load Vector Left Indexed Last - ADDO = 0x30a, - LHBRX = 0x316, - SRAW = 0x318, - SRAD = 0x31a, - LVRXL = 0x327, //Load Vector Right Indexed Last - DSS = 0x336, //Data Stream Stop - SRAWI = 0x338, - SRADI1 = 0x33a, //sh_5 == 0 - SRADI2 = 0x33b, //sh_5 != 0 - EIEIO = 0x356, - STVLXL = 0x387, //Store Vector Left Indexed Last - STHBRX = 0x396, - EXTSH = 0x39a, - STVRXL = 0x3a7, //Store Vector Right Indexed Last - EXTSB = 0x3ba, - DIVDUO = 0x3c9, - DIVWUO = 0x3cb, - STFIWX = 0x3d7, - EXTSW = 0x3da, - ICBI = 0x3d6, //Instruction Cache Block Invalidate - DIVDO = 0x3e9, - DIVWO = 0x3eb, - DCBZ = 0x3f6, //Data Cache Block Set to Zero - }; - - enum G_3aOpcodes //Field 30 - 31 - { - LD = 0x0, - LDU = 0x1, - LWA = 0x2, - }; - - enum G_3bOpcodes //Field 26 - 30 - { - FDIVS = 0x12, - FSUBS = 0x14, - FADDS = 0x15, - FSQRTS = 0x16, - FRES = 0x18, - FMULS = 0x19, - FMSUBS = 0x1c, - FMADDS = 0x1d, - FNMSUBS = 0x1e, - FNMADDS = 0x1f, - }; - - enum G_3eOpcodes //Field 30 - 31 - { - STD = 0x0, - STDU = 0x1, - }; - - enum G_3fOpcodes //Field 21 - 30 - { - MTFSB1 = 0x026, - MCRFS = 0x040, - MTFSB0 = 0x046, - MTFSFI = 0x086, - MFFS = 0x247, - MTFSF = 0x2c7, - - FCMPU = 0x000, - FRSP = 0x00c, - FCTIW = 0x00e, - FCTIWZ = 0x00f, - FDIV = 0x012, - FSUB = 0x014, - FADD = 0x015, - FSQRT = 0x016, - FSEL = 0x017, - FMUL = 0x019, - FRSQRTE = 0x01a, - FMSUB = 0x01c, - FMADD = 0x01d, - FNMSUB = 0x01e, - FNMADD = 0x01f, - FCMPO = 0x020, - FNEG = 0x028, - FMR = 0x048, - FNABS = 0x088, - FABS = 0x108, - FCTID = 0x32e, - FCTIDZ = 0x32f, - FCFID = 0x34e, - }; +inline u32 ppu_branch_target(u32 pc, u32 imm) +{ + return pc + (imm & ~0x3u); } -class PPUOpcodes +inline u64 ppu_branch_target(u64 pc, u64 imm) { -public: - virtual ~PPUOpcodes() {} + return pc + (imm & ~0x3ull); +} - static u32 branchTarget(const u32 pc, const u32 imm) +inline u64 ppu_rotate_mask(u32 mb, u32 me) +{ + const u64 mask = ~0ull << (63 ^ (me - mb)); + return mask >> mb | mask << (64 - mb); // Rotate +} + +inline u32 ppu_decode(u32 inst) +{ + return (inst >> 26 | inst << (32 - 26)) & 0x1ffff; // Rotate + mask +} + +// PPU decoder object. D provides functions. T is function pointer type returned. +template +class ppu_decoder +{ + // Fast lookup table + std::array m_table; + + struct instruction_info { - return pc + (imm & ~0x3ULL); + u32 value; + T pointer; + u32 magn; // Non-zero for "columns" (effectively, number of most significant bits "eaten") + }; + + // Fill lookup table + void fill_table(u32 main_op, u32 count, u32 sh, std::initializer_list entries) + { + if (sh < 11) + { + for (const auto& v : entries) + { + for (u32 i = 0; i < 1u << (v.magn + (11 - sh - count)); i++) + { + for (u32 j = 0; j < 1u << sh; j++) + { + m_table.at((((((i << (count - v.magn)) | v.value) << sh) | j) << 6) | main_op) = v.pointer; + } + } + } + } + else + { + // Main table (special case) + for (const auto& v : entries) + { + for (u32 i = 0; i < 1u << 11; i++) + { + m_table.at(i << 6 | v.value) = v.pointer; + } + } + } } - virtual void NULL_OP() = 0; - virtual void NOP() = 0; +public: + ppu_decoder() + { + m_table.fill(&D::UNK); - virtual void TDI(u32 to, u32 ra, s32 simm16) = 0; - virtual void TWI(u32 to, u32 ra, s32 simm16) = 0; + // Main opcodes (field 0..5) + fill_table(0x00, 6, -1, + { + { 0x01, &D::HACK }, + { 0x02, &D::TDI }, + { 0x03, &D::TWI }, + { 0x07, &D::MULLI }, + { 0x08, &D::SUBFIC }, + { 0x0a, &D::CMPLI }, + { 0x0b, &D::CMPI }, + { 0x0c, &D::ADDIC }, + { 0x0d, &D::ADDIC }, + { 0x0e, &D::ADDI }, + { 0x0f, &D::ADDIS }, + { 0x10, &D::BC }, + { 0x11, &D::SC }, + { 0x12, &D::B }, + { 0x14, &D::RLWIMI }, + { 0x15, &D::RLWINM }, + { 0x17, &D::RLWNM }, + { 0x18, &D::ORI }, + { 0x19, &D::ORIS }, + { 0x1a, &D::XORI }, + { 0x1b, &D::XORIS }, + { 0x1c, &D::ANDI }, + { 0x1d, &D::ANDIS }, + { 0x20, &D::LWZ }, + { 0x21, &D::LWZU }, + { 0x22, &D::LBZ }, + { 0x23, &D::LBZU }, + { 0x24, &D::STW }, + { 0x25, &D::STWU }, + { 0x26, &D::STB }, + { 0x27, &D::STBU }, + { 0x28, &D::LHZ }, + { 0x29, &D::LHZU }, + { 0x2a, &D::LHA }, + { 0x2b, &D::LHAU }, + { 0x2c, &D::STH }, + { 0x2d, &D::STHU }, + { 0x2e, &D::LMW }, + { 0x2f, &D::STMW }, + { 0x30, &D::LFS }, + { 0x31, &D::LFSU }, + { 0x32, &D::LFD }, + { 0x33, &D::LFDU }, + { 0x34, &D::STFS }, + { 0x35, &D::STFSU }, + { 0x36, &D::STFD }, + { 0x37, &D::STFDU }, + }); - virtual void MFVSCR(u32 vd) = 0; - virtual void MTVSCR(u32 vb) = 0; - virtual void VADDCUW(u32 vd, u32 va, u32 vb) = 0; - virtual void VADDFP(u32 vd, u32 va, u32 vb) = 0; - virtual void VADDSBS(u32 vd, u32 va, u32 vb) = 0; - virtual void VADDSHS(u32 vd, u32 va, u32 vb) = 0; - virtual void VADDSWS(u32 vd, u32 va, u32 vb) = 0; - virtual void VADDUBM(u32 vd, u32 va, u32 vb) = 0; - virtual void VADDUBS(u32 vd, u32 va, u32 vb) = 0; - virtual void VADDUHM(u32 vd, u32 va, u32 vb) = 0; - virtual void VADDUHS(u32 vd, u32 va, u32 vb) = 0; - virtual void VADDUWM(u32 vd, u32 va, u32 vb) = 0; - virtual void VADDUWS(u32 vd, u32 va, u32 vb) = 0; - virtual void VAND(u32 vd, u32 va, u32 vb) = 0; - virtual void VANDC(u32 vd, u32 va, u32 vb) = 0; - virtual void VAVGSB(u32 vd, u32 va, u32 vb) = 0; - virtual void VAVGSH(u32 vd, u32 va, u32 vb) = 0; - virtual void VAVGSW(u32 vd, u32 va, u32 vb) = 0; - virtual void VAVGUB(u32 vd, u32 va, u32 vb) = 0; - virtual void VAVGUH(u32 vd, u32 va, u32 vb) = 0; - virtual void VAVGUW(u32 vd, u32 va, u32 vb) = 0; - virtual void VCFSX(u32 vd, u32 uimm5, u32 vb) = 0; - virtual void VCFUX(u32 vd, u32 uimm5, u32 vb) = 0; - virtual void VCMPBFP(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPBFP_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPEQFP(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPEQFP_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPEQUB(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPEQUB_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPEQUH(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPEQUH_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPEQUW(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPEQUW_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGEFP(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGEFP_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTFP(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTFP_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTSB(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTSB_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTSH(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTSH_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTSW(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTSW_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTUB(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTUB_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTUH(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTUH_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTUW(u32 vd, u32 va, u32 vb) = 0; - virtual void VCMPGTUW_(u32 vd, u32 va, u32 vb) = 0; - virtual void VCTSXS(u32 vd, u32 uimm5, u32 vb) = 0; - virtual void VCTUXS(u32 vd, u32 uimm5, u32 vb) = 0; - virtual void VEXPTEFP(u32 vd, u32 vb) = 0; - virtual void VLOGEFP(u32 vd, u32 vb) = 0; - virtual void VMADDFP(u32 vd, u32 va, u32 vc, u32 vb) = 0; - virtual void VMAXFP(u32 vd, u32 va, u32 vb) = 0; - virtual void VMAXSB(u32 vd, u32 va, u32 vb) = 0; - virtual void VMAXSH(u32 vd, u32 va, u32 vb) = 0; - virtual void VMAXSW(u32 vd, u32 va, u32 vb) = 0; - virtual void VMAXUB(u32 vd, u32 va, u32 vb) = 0; - virtual void VMAXUH(u32 vd, u32 va, u32 vb) = 0; - virtual void VMAXUW(u32 vd, u32 va, u32 vb) = 0; - virtual void VMHADDSHS(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VMHRADDSHS(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VMINFP(u32 vd, u32 va, u32 vb) = 0; - virtual void VMINSB(u32 vd, u32 va, u32 vb) = 0; - virtual void VMINSH(u32 vd, u32 va, u32 vb) = 0; - virtual void VMINSW(u32 vd, u32 va, u32 vb) = 0; - virtual void VMINUB(u32 vd, u32 va, u32 vb) = 0; - virtual void VMINUH(u32 vd, u32 va, u32 vb) = 0; - virtual void VMINUW(u32 vd, u32 va, u32 vb) = 0; - virtual void VMLADDUHM(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VMRGHB(u32 vd, u32 va, u32 vb) = 0; - virtual void VMRGHH(u32 vd, u32 va, u32 vb) = 0; - virtual void VMRGHW(u32 vd, u32 va, u32 vb) = 0; - virtual void VMRGLB(u32 vd, u32 va, u32 vb) = 0; - virtual void VMRGLH(u32 vd, u32 va, u32 vb) = 0; - virtual void VMRGLW(u32 vd, u32 va, u32 vb) = 0; - virtual void VMSUMMBM(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VMSUMSHM(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VMSUMSHS(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VMSUMUBM(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VMSUMUHM(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VMSUMUHS(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VMULESB(u32 vd, u32 va, u32 vb) = 0; - virtual void VMULESH(u32 vd, u32 va, u32 vb) = 0; - virtual void VMULEUB(u32 vd, u32 va, u32 vb) = 0; - virtual void VMULEUH(u32 vd, u32 va, u32 vb) = 0; - virtual void VMULOSB(u32 vd, u32 va, u32 vb) = 0; - virtual void VMULOSH(u32 vd, u32 va, u32 vb) = 0; - virtual void VMULOUB(u32 vd, u32 va, u32 vb) = 0; - virtual void VMULOUH(u32 vd, u32 va, u32 vb) = 0; - virtual void VNMSUBFP(u32 vd, u32 va, u32 vc, u32 vb) = 0; - virtual void VNOR(u32 vd, u32 va, u32 vb) = 0; - virtual void VOR(u32 vd, u32 va, u32 vb) = 0; - virtual void VPERM(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VPKPX(u32 vd, u32 va, u32 vb) = 0; - virtual void VPKSHSS(u32 vd, u32 va, u32 vb) = 0; - virtual void VPKSHUS(u32 vd, u32 va, u32 vb) = 0; - virtual void VPKSWSS(u32 vd, u32 va, u32 vb) = 0; - virtual void VPKSWUS(u32 vd, u32 va, u32 vb) = 0; - virtual void VPKUHUM(u32 vd, u32 va, u32 vb) = 0; - virtual void VPKUHUS(u32 vd, u32 va, u32 vb) = 0; - virtual void VPKUWUM(u32 vd, u32 va, u32 vb) = 0; - virtual void VPKUWUS(u32 vd, u32 va, u32 vb) = 0; - virtual void VREFP(u32 vd, u32 vb) = 0; - virtual void VRFIM(u32 vd, u32 vb) = 0; - virtual void VRFIN(u32 vd, u32 vb) = 0; - virtual void VRFIP(u32 vd, u32 vb) = 0; - virtual void VRFIZ(u32 vd, u32 vb) = 0; - virtual void VRLB(u32 vd, u32 va, u32 vb) = 0; - virtual void VRLH(u32 vd, u32 va, u32 vb) = 0; - virtual void VRLW(u32 vd, u32 va, u32 vb) = 0; - virtual void VRSQRTEFP(u32 vd, u32 vb) = 0; - virtual void VSEL(u32 vd, u32 va, u32 vb, u32 vc) = 0; - virtual void VSL(u32 vd, u32 va, u32 vb) = 0; - virtual void VSLB(u32 vd, u32 va, u32 vb) = 0; - virtual void VSLDOI(u32 vd, u32 va, u32 vb, u32 sh) = 0; - virtual void VSLH(u32 vd, u32 va, u32 vb) = 0; - virtual void VSLO(u32 vd, u32 va, u32 vb) = 0; - virtual void VSLW(u32 vd, u32 va, u32 vb) = 0; - virtual void VSPLTB(u32 vd, u32 uimm5, u32 vb) = 0; - virtual void VSPLTH(u32 vd, u32 uimm5, u32 vb) = 0; - virtual void VSPLTISB(u32 vd, s32 simm5) = 0; - virtual void VSPLTISH(u32 vd, s32 simm5) = 0; - virtual void VSPLTISW(u32 vd, s32 simm5) = 0; - virtual void VSPLTW(u32 vd, u32 uimm5, u32 vb) = 0; - virtual void VSR(u32 vd, u32 va, u32 vb) = 0; - virtual void VSRAB(u32 vd, u32 va, u32 vb) = 0; - virtual void VSRAH(u32 vd, u32 va, u32 vb) = 0; - virtual void VSRAW(u32 vd, u32 va, u32 vb) = 0; - virtual void VSRB(u32 vd, u32 va, u32 vb) = 0; - virtual void VSRH(u32 vd, u32 va, u32 vb) = 0; - virtual void VSRO(u32 vd, u32 va, u32 vb) = 0; - virtual void VSRW(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBCUW(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBFP(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBSBS(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBSHS(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBSWS(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBUBM(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBUBS(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBUHM(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBUHS(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBUWM(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUBUWS(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUMSWS(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUM2SWS(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUM4SBS(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUM4SHS(u32 vd, u32 va, u32 vb) = 0; - virtual void VSUM4UBS(u32 vd, u32 va, u32 vb) = 0; - virtual void VUPKHPX(u32 vd, u32 vb) = 0; - virtual void VUPKHSB(u32 vd, u32 vb) = 0; - virtual void VUPKHSH(u32 vd, u32 vb) = 0; - virtual void VUPKLPX(u32 vd, u32 vb) = 0; - virtual void VUPKLSB(u32 vd, u32 vb) = 0; - virtual void VUPKLSH(u32 vd, u32 vb) = 0; - virtual void VXOR(u32 vd, u32 va, u32 vb) = 0; - virtual void MULLI(u32 rd, u32 ra, s32 simm16) = 0; - virtual void SUBFIC(u32 rd, u32 ra, s32 simm16) = 0; - virtual void CMPLI(u32 bf, u32 l, u32 ra, u32 uimm16) = 0; - virtual void CMPI(u32 bf, u32 l, u32 ra, s32 simm16) = 0; - virtual void ADDIC(u32 rd, u32 ra, s32 simm16) = 0; - virtual void ADDIC_(u32 rd, u32 ra, s32 simm16) = 0; - virtual void ADDI(u32 rd, u32 ra, s32 simm16) = 0; - virtual void ADDIS(u32 rd, u32 ra, s32 simm16) = 0; - virtual void BC(u32 bo, u32 bi, s32 bd, u32 aa, u32 lk) = 0; - virtual void HACK(u32 index) = 0; - virtual void SC(u32 lev) = 0; - virtual void B(s32 ll, u32 aa, u32 lk) = 0; - virtual void MCRF(u32 crfd, u32 crfs) = 0; - virtual void BCLR(u32 bo, u32 bi, u32 bh, u32 lk) = 0; - virtual void CRNOR(u32 bt, u32 ba, u32 bb) = 0; - virtual void CRANDC(u32 bt, u32 ba, u32 bb) = 0; - virtual void ISYNC() = 0; - virtual void CRXOR(u32 bt, u32 ba, u32 bb) = 0; - virtual void CRNAND(u32 bt, u32 ba, u32 bb) = 0; - virtual void CRAND(u32 bt, u32 ba, u32 bb) = 0; - virtual void CREQV(u32 bt, u32 ba, u32 bb) = 0; - virtual void CRORC(u32 bt, u32 ba, u32 bb) = 0; - virtual void CROR(u32 bt, u32 ba, u32 bb) = 0; - virtual void BCCTR(u32 bo, u32 bi, u32 bh, u32 lk) = 0; - virtual void RLWIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) = 0; - virtual void RLWINM(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) = 0; - virtual void RLWNM(u32 ra, u32 rs, u32 rb, u32 MB, u32 ME, u32 rc) = 0; - virtual void ORI(u32 rs, u32 ra, u32 uimm16) = 0; - virtual void ORIS(u32 rs, u32 ra, u32 uimm16) = 0; - virtual void XORI(u32 ra, u32 rs, u32 uimm16) = 0; - virtual void XORIS(u32 ra, u32 rs, u32 uimm16) = 0; - virtual void ANDI_(u32 ra, u32 rs, u32 uimm16) = 0; - virtual void ANDIS_(u32 ra, u32 rs, u32 uimm16) = 0; - virtual void RLDICL(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) = 0; - virtual void RLDICR(u32 ra, u32 rs, u32 sh, u32 me, u32 rc) = 0; - virtual void RLDIC(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) = 0; - virtual void RLDIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) = 0; - virtual void RLDC_LR(u32 ra, u32 rs, u32 rb, u32 m_eb, u32 is_r, u32 rc) = 0; - virtual void CMP(u32 crfd, u32 l, u32 ra, u32 rb) = 0; - virtual void TW(u32 to, u32 ra, u32 rb) = 0; - virtual void LVSL(u32 vd, u32 ra, u32 rb) = 0; - virtual void LVEBX(u32 vd, u32 ra, u32 rb) = 0; - virtual void SUBFC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void MULHDU(u32 rd, u32 ra, u32 rb, u32 rc) = 0; - virtual void ADDC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void MULHWU(u32 rd, u32 ra, u32 rb, u32 rc) = 0; - virtual void MFOCRF(u32 a, u32 rd, u32 crm) = 0; - virtual void LWARX(u32 rd, u32 ra, u32 rb) = 0; - virtual void LDX(u32 ra, u32 rs, u32 rb) = 0; - virtual void LWZX(u32 rd, u32 ra, u32 rb) = 0; - virtual void SLW(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void CNTLZW(u32 ra, u32 rs, u32 rc) = 0; - virtual void SLD(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void AND(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void CMPL(u32 bf, u32 l, u32 ra, u32 rb) = 0; - virtual void LVSR(u32 vd, u32 ra, u32 rb) = 0; - virtual void LVEHX(u32 vd, u32 ra, u32 rb) = 0; - virtual void SUBF(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void LDUX(u32 rd, u32 ra, u32 rb) = 0; - virtual void DCBST(u32 ra, u32 rb) = 0; - virtual void LWZUX(u32 rd, u32 ra, u32 rb) = 0; - virtual void CNTLZD(u32 ra, u32 rs, u32 rc) = 0; - virtual void ANDC(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void TD(u32 to, u32 ra, u32 rb) = 0; - virtual void LVEWX(u32 vd, u32 ra, u32 rb) = 0; - virtual void MULHD(u32 rd, u32 ra, u32 rb, u32 rc) = 0; - virtual void MULHW(u32 rd, u32 ra, u32 rb, u32 rc) = 0; - virtual void LDARX(u32 rd, u32 ra, u32 rb) = 0; - virtual void DCBF(u32 ra, u32 rb) = 0; - virtual void LBZX(u32 rd, u32 ra, u32 rb) = 0; - virtual void LVX(u32 vd, u32 ra, u32 rb) = 0; - virtual void NEG(u32 rd, u32 ra, u32 oe, u32 rc) = 0; - virtual void LBZUX(u32 rd, u32 ra, u32 rb) = 0; - virtual void NOR(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void STVEBX(u32 vs, u32 ra, u32 rb) = 0; - virtual void SUBFE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void ADDE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void MTOCRF(u32 l, u32 crm, u32 rs) = 0; - virtual void STDX(u32 rs, u32 ra, u32 rb) = 0; - virtual void STWCX_(u32 rs, u32 ra, u32 rb) = 0; - virtual void STWX(u32 rs, u32 ra, u32 rb) = 0; - virtual void STVEHX(u32 vs, u32 ra, u32 rb) = 0; - virtual void STDUX(u32 rs, u32 ra, u32 rb) = 0; - virtual void STWUX(u32 rs, u32 ra, u32 rb) = 0; - virtual void STVEWX(u32 vs, u32 ra, u32 rb) = 0; - virtual void SUBFZE(u32 rd, u32 ra, u32 oe, u32 rc) = 0; - virtual void ADDZE(u32 rd, u32 ra, u32 oe, u32 rc) = 0; - virtual void STDCX_(u32 rs, u32 ra, u32 rb) = 0; - virtual void STBX(u32 rs, u32 ra, u32 rb) = 0; - virtual void STVX(u32 vs, u32 ra, u32 rb) = 0; - virtual void MULLD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void SUBFME(u32 rd, u32 ra, u32 oe, u32 rc) = 0; - virtual void ADDME(u32 rd, u32 ra, u32 oe, u32 rc) = 0; - virtual void MULLW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void DCBTST(u32 ra, u32 rb, u32 th) = 0; - virtual void STBUX(u32 rs, u32 ra, u32 rb) = 0; - virtual void ADD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void DCBT(u32 ra, u32 rb, u32 th) = 0; - virtual void LHZX(u32 rd, u32 ra, u32 rb) = 0; - virtual void EQV(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void ECIWX(u32 rd, u32 ra, u32 rb) = 0; - virtual void LHZUX(u32 rd, u32 ra, u32 rb) = 0; - virtual void XOR(u32 rs, u32 ra, u32 rb, u32 rc) = 0; - virtual void MFSPR(u32 rd, u32 spr) = 0; - virtual void LWAX(u32 rd, u32 ra, u32 rb) = 0; - virtual void DST(u32 ra, u32 rb, u32 strm, u32 t) = 0; - virtual void LHAX(u32 rd, u32 ra, u32 rb) = 0; - virtual void LVXL(u32 vd, u32 ra, u32 rb) = 0; - virtual void MFTB(u32 rd, u32 spr) = 0; - virtual void LWAUX(u32 rd, u32 ra, u32 rb) = 0; - virtual void DSTST(u32 ra, u32 rb, u32 strm, u32 t) = 0; - virtual void LHAUX(u32 rd, u32 ra, u32 rb) = 0; - virtual void STHX(u32 rs, u32 ra, u32 rb) = 0; - virtual void ORC(u32 rs, u32 ra, u32 rb, u32 rc) = 0; - virtual void ECOWX(u32 rs, u32 ra, u32 rb) = 0; - virtual void STHUX(u32 rs, u32 ra, u32 rb) = 0; - virtual void OR(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void DIVDU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void DIVWU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void MTSPR(u32 spr, u32 rs) = 0; - virtual void DCBI(u32 ra, u32 rb) = 0; - virtual void NAND(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void STVXL(u32 vs, u32 ra, u32 rb) = 0; - virtual void DIVD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void DIVW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) = 0; - virtual void LVLX(u32 vd, u32 ra, u32 rb) = 0; - virtual void LDBRX(u32 rd, u32 ra, u32 rb) = 0; - virtual void LSWX(u32 rd, u32 ra, u32 rb) = 0; - virtual void LWBRX(u32 rd, u32 ra, u32 rb) = 0; - virtual void LFSX(u32 frd, u32 ra, u32 rb) = 0; - virtual void SRW(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void SRD(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void LVRX(u32 vd, u32 ra, u32 rb) = 0; - virtual void LSWI(u32 rd, u32 ra, u32 nb) = 0; - virtual void LFSUX(u32 frd, u32 ra, u32 rb) = 0; - virtual void SYNC(u32 l) = 0; - virtual void LFDX(u32 frd, u32 ra, u32 rb) = 0; - virtual void LFDUX(u32 frd, u32 ra, u32 rb) = 0; - virtual void STVLX(u32 vs, u32 ra, u32 rb) = 0; - virtual void STDBRX(u32 rs, u32 ra, u32 rb) = 0; - virtual void STSWX(u32 rs, u32 ra, u32 rb) = 0; - virtual void STWBRX(u32 rs, u32 ra, u32 rb) = 0; - virtual void STFSX(u32 frs, u32 ra, u32 rb) = 0; - virtual void STVRX(u32 vs, u32 ra, u32 rb) = 0; - virtual void STFSUX(u32 frs, u32 ra, u32 rb) = 0; - virtual void STSWI(u32 rd, u32 ra, u32 nb) = 0; - virtual void STFDX(u32 frs, u32 ra, u32 rb) = 0; - virtual void STFDUX(u32 frs, u32 ra, u32 rb) = 0; - virtual void LVLXL(u32 vd, u32 ra, u32 rb) = 0; - virtual void LHBRX(u32 rd, u32 ra, u32 rb) = 0; - virtual void SRAW(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void SRAD(u32 ra, u32 rs, u32 rb, u32 rc) = 0; - virtual void LVRXL(u32 vd, u32 ra, u32 rb) = 0; - virtual void DSS(u32 strm, u32 a) = 0; - virtual void SRAWI(u32 ra, u32 rs, u32 sh, u32 rc) = 0; - virtual void SRADI1(u32 ra, u32 rs, u32 sh, u32 rc) = 0; - virtual void SRADI2(u32 ra, u32 rs, u32 sh, u32 rc) = 0; - virtual void EIEIO() = 0; - virtual void STVLXL(u32 vs, u32 ra, u32 rb) = 0; - virtual void STHBRX(u32 rs, u32 ra, u32 rb) = 0; - virtual void EXTSH(u32 ra, u32 rs, u32 rc) = 0; - virtual void STVRXL(u32 sd, u32 ra, u32 rb) = 0; - virtual void EXTSB(u32 ra, u32 rs, u32 rc) = 0; - virtual void STFIWX(u32 frs, u32 ra, u32 rb) = 0; - virtual void EXTSW(u32 ra, u32 rs, u32 rc) = 0; - virtual void ICBI(u32 ra, u32 rb) = 0; - virtual void DCBZ(u32 ra, u32 rb) = 0; - virtual void LWZ(u32 rd, u32 ra, s32 d) = 0; - virtual void LWZU(u32 rd, u32 ra, s32 d) = 0; - virtual void LBZ(u32 rd, u32 ra, s32 d) = 0; - virtual void LBZU(u32 rd, u32 ra, s32 d) = 0; - virtual void STW(u32 rs, u32 ra, s32 d) = 0; - virtual void STWU(u32 rs, u32 ra, s32 d) = 0; - virtual void STB(u32 rs, u32 ra, s32 d) = 0; - virtual void STBU(u32 rs, u32 ra, s32 d) = 0; - virtual void LHZ(u32 rd, u32 ra, s32 d) = 0; - virtual void LHZU(u32 rd, u32 ra, s32 d) = 0; - virtual void LHA(u32 rs, u32 ra, s32 d) = 0; - virtual void LHAU(u32 rs, u32 ra, s32 d) = 0; - virtual void STH(u32 rs, u32 ra, s32 d) = 0; - virtual void STHU(u32 rs, u32 ra, s32 d) = 0; - virtual void LMW(u32 rd, u32 ra, s32 d) = 0; - virtual void STMW(u32 rs, u32 ra, s32 d) = 0; - virtual void LFS(u32 frd, u32 ra, s32 d) = 0; - virtual void LFSU(u32 frd, u32 ra, s32 d) = 0; - virtual void LFD(u32 frd, u32 ra, s32 d) = 0; - virtual void LFDU(u32 frd, u32 ra, s32 d) = 0; - virtual void STFS(u32 frs, u32 ra, s32 d) = 0; - virtual void STFSU(u32 frs, u32 ra, s32 d) = 0; - virtual void STFD(u32 frs, u32 ra, s32 d) = 0; - virtual void STFDU(u32 frs, u32 ra, s32 d) = 0; - virtual void LD(u32 rd, u32 ra, s32 ds) = 0; - virtual void LDU(u32 rd, u32 ra, s32 ds) = 0; - virtual void LWA(u32 rd, u32 ra, s32 ds) = 0; - virtual void FDIVS(u32 frd, u32 fra, u32 frb, u32 rc) = 0; - virtual void FSUBS(u32 frd, u32 fra, u32 frb, u32 rc) = 0; - virtual void FADDS(u32 frd, u32 fra, u32 frb, u32 rc) = 0; - virtual void FSQRTS(u32 frd, u32 frb, u32 rc) = 0; - virtual void FRES(u32 frd, u32 frb, u32 rc) = 0; - virtual void FMULS(u32 frd, u32 fra, u32 frc, u32 rc) = 0; - virtual void FMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) = 0; - virtual void FMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) = 0; - virtual void FNMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) = 0; - virtual void FNMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) = 0; - virtual void STD(u32 rs, u32 ra, s32 ds) = 0; - virtual void STDU(u32 rs, u32 ra, s32 ds) = 0; - virtual void MTFSB1(u32 bt, u32 rc) = 0; - virtual void MCRFS(u32 bf, u32 bfa) = 0; - virtual void MTFSB0(u32 bt, u32 rc) = 0; - virtual void MTFSFI(u32 crfd, u32 i, u32 rc) = 0; - virtual void MFFS(u32 frd, u32 rc) = 0; - virtual void MTFSF(u32 flm, u32 frb, u32 rc) = 0; + // Group 0x04 opcodes (field 21..31) + fill_table(0x04, 11, 0, + { + { 0x0, &D::VADDUBM }, + { 0x2, &D::VMAXUB }, + { 0x4, &D::VRLB }, + { 0x6, &D::VCMPEQUB, 1 }, + { 0x8, &D::VMULOUB }, + { 0xa, &D::VADDFP }, + { 0xc, &D::VMRGHB }, + { 0xe, &D::VPKUHUM }, - virtual void FCMPU(u32 bf, u32 fra, u32 frb) = 0; - virtual void FRSP(u32 frd, u32 frb, u32 rc) = 0; - virtual void FCTIW(u32 frd, u32 frb, u32 rc) = 0; - virtual void FCTIWZ(u32 frd, u32 frb, u32 rc) = 0; - virtual void FDIV(u32 frd, u32 fra, u32 frb, u32 rc) = 0; - virtual void FSUB(u32 frd, u32 fra, u32 frb, u32 rc) = 0; - virtual void FADD(u32 frd, u32 fra, u32 frb, u32 rc) = 0; - virtual void FSQRT(u32 frd, u32 frb, u32 rc) = 0; - virtual void FSEL(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) = 0; - virtual void FMUL(u32 frd, u32 fra, u32 frc, u32 rc) = 0; - virtual void FRSQRTE(u32 frd, u32 frb, u32 rc) = 0; - virtual void FMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) = 0; - virtual void FMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) = 0; - virtual void FNMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) = 0; - virtual void FNMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) = 0; - virtual void FCMPO(u32 crfd, u32 fra, u32 frb) = 0; - virtual void FNEG(u32 frd, u32 frb, u32 rc) = 0; - virtual void FMR(u32 frd, u32 frb, u32 rc) = 0; - virtual void FNABS(u32 frd, u32 frb, u32 rc) = 0; - virtual void FABS(u32 frd, u32 frb, u32 rc) = 0; - virtual void FCTID(u32 frd, u32 frb, u32 rc) = 0; - virtual void FCTIDZ(u32 frd, u32 frb, u32 rc) = 0; - virtual void FCFID(u32 frd, u32 frb, u32 rc) = 0; + { 0x20, &D::VMHADDSHS, 5 }, + { 0x21, &D::VMHRADDSHS, 5 }, + { 0x22, &D::VMLADDUHM, 5 }, + { 0x24, &D::VMSUMUBM, 5 }, + { 0x25, &D::VMSUMMBM, 5 }, + { 0x26, &D::VMSUMUHM, 5 }, + { 0x27, &D::VMSUMUHS, 5 }, + { 0x28, &D::VMSUMSHM, 5 }, + { 0x29, &D::VMSUMSHS, 5 }, + { 0x2a, &D::VSEL, 5 }, + { 0x2b, &D::VPERM, 5 }, + { 0x2c, &D::VSLDOI, 5 }, + { 0x2e, &D::VMADDFP, 5 }, + { 0x2f, &D::VNMSUBFP, 5 }, - virtual void UNK(const u32 code, const u32 opcode, const u32 gcode) = 0; + { 0x40, &D::VADDUHM }, + { 0x42, &D::VMAXUH }, + { 0x44, &D::VRLH }, + { 0x46, &D::VCMPEQUH, 1 }, + { 0x48, &D::VMULOUH }, + { 0x4a, &D::VSUBFP }, + { 0x4c, &D::VMRGHH }, + { 0x4e, &D::VPKUWUM }, + { 0x80, &D::VADDUWM }, + { 0x82, &D::VMAXUW }, + { 0x84, &D::VRLW }, + { 0x86, &D::VCMPEQUW, 1 }, + { 0x8c, &D::VMRGHW }, + { 0x8e, &D::VPKUHUS }, + { 0xc6, &D::VCMPEQFP, 1 }, + { 0xce, &D::VPKUWUS }, + + { 0x102, &D::VMAXSB }, + { 0x104, &D::VSLB }, + { 0x108, &D::VMULOSB }, + { 0x10a, &D::VREFP }, + { 0x10c, &D::VMRGLB }, + { 0x10e, &D::VPKSHUS }, + { 0x142, &D::VMAXSH }, + { 0x144, &D::VSLH }, + { 0x148, &D::VMULOSH }, + { 0x14a, &D::VRSQRTEFP }, + { 0x14c, &D::VMRGLH }, + { 0x14e, &D::VPKSWUS }, + { 0x180, &D::VADDCUW }, + { 0x182, &D::VMAXSW }, + { 0x184, &D::VSLW }, + { 0x18a, &D::VEXPTEFP }, + { 0x18c, &D::VMRGLW }, + { 0x18e, &D::VPKSHSS }, + { 0x1c4, &D::VSL }, + { 0x1c6, &D::VCMPGEFP, 1 }, + { 0x1ca, &D::VLOGEFP }, + { 0x1ce, &D::VPKSWSS }, + { 0x200, &D::VADDUBS }, + { 0x202, &D::VMINUB }, + { 0x204, &D::VSRB }, + { 0x206, &D::VCMPGTUB, 1 }, + { 0x208, &D::VMULEUB }, + { 0x20a, &D::VRFIN }, + { 0x20c, &D::VSPLTB }, + { 0x20e, &D::VUPKHSB }, + { 0x240, &D::VADDUHS }, + { 0x242, &D::VMINUH }, + { 0x244, &D::VSRH }, + { 0x246, &D::VCMPGTUH, 1 }, + { 0x248, &D::VMULEUH }, + { 0x24a, &D::VRFIZ }, + { 0x24c, &D::VSPLTH }, + { 0x24e, &D::VUPKHSH }, + { 0x280, &D::VADDUWS }, + { 0x282, &D::VMINUW }, + { 0x284, &D::VSRW }, + { 0x286, &D::VCMPGTUW, 1 }, + { 0x28a, &D::VRFIP }, + { 0x28c, &D::VSPLTW }, + { 0x28e, &D::VUPKLSB }, + { 0x2c4, &D::VSR }, + { 0x2c6, &D::VCMPGTFP, 1 }, + { 0x2ca, &D::VRFIM }, + { 0x2ce, &D::VUPKLSH }, + { 0x300, &D::VADDSBS }, + { 0x302, &D::VMINSB }, + { 0x304, &D::VSRAB }, + { 0x306, &D::VCMPGTSB, 1 }, + { 0x308, &D::VMULESB }, + { 0x30a, &D::VCFUX }, + { 0x30c, &D::VSPLTISB }, + { 0x30e, &D::VPKPX }, + { 0x340, &D::VADDSHS }, + { 0x342, &D::VMINSH }, + { 0x344, &D::VSRAH }, + { 0x346, &D::VCMPGTSH, 1 }, + { 0x348, &D::VMULESH }, + { 0x34a, &D::VCFSX }, + { 0x34c, &D::VSPLTISH }, + { 0x34e, &D::VUPKHPX }, + { 0x380, &D::VADDSWS }, + { 0x382, &D::VMINSW }, + { 0x384, &D::VSRAW }, + { 0x386, &D::VCMPGTSW, 1 }, + { 0x38a, &D::VCTUXS }, + { 0x38c, &D::VSPLTISW }, + { 0x3c6, &D::VCMPBFP, 1 }, + { 0x3ca, &D::VCTSXS }, + { 0x3ce, &D::VUPKLPX }, + { 0x400, &D::VSUBUBM }, + { 0x402, &D::VAVGUB }, + { 0x404, &D::VAND }, + { 0x40a, &D::VMAXFP }, + { 0x40c, &D::VSLO }, + { 0x440, &D::VSUBUHM }, + { 0x442, &D::VAVGUH }, + { 0x444, &D::VANDC }, + { 0x44a, &D::VMINFP }, + { 0x44c, &D::VSRO }, + { 0x480, &D::VSUBUWM }, + { 0x482, &D::VAVGUW }, + { 0x484, &D::VOR }, + { 0x4c4, &D::VXOR }, + { 0x502, &D::VAVGSB }, + { 0x504, &D::VNOR }, + { 0x542, &D::VAVGSH }, + { 0x580, &D::VSUBCUW }, + { 0x582, &D::VAVGSW }, + { 0x600, &D::VSUBUBS }, + { 0x604, &D::MFVSCR }, + { 0x608, &D::VSUM4UBS }, + { 0x640, &D::VSUBUHS }, + { 0x644, &D::MTVSCR }, + { 0x648, &D::VSUM4SHS }, + { 0x680, &D::VSUBUWS }, + { 0x688, &D::VSUM2SWS }, + { 0x700, &D::VSUBSBS }, + { 0x708, &D::VSUM4SBS }, + { 0x740, &D::VSUBSHS }, + { 0x780, &D::VSUBSWS }, + { 0x788, &D::VSUMSWS }, + }); + + // Group 0x13 opcodes (field 21..30) + fill_table(0x13, 10, 1, + { + { 0x000, &D::MCRF }, + { 0x010, &D::BCLR }, + { 0x021, &D::CRNOR }, + { 0x081, &D::CRANDC }, + { 0x096, &D::ISYNC }, + { 0x0c1, &D::CRXOR }, + { 0x0e1, &D::CRNAND }, + { 0x101, &D::CRAND }, + { 0x121, &D::CREQV }, + { 0x1a1, &D::CRORC }, + { 0x1c1, &D::CROR }, + { 0x210, &D::BCCTR }, + }); + + // Group 0x1e opcodes (field 27..30) + fill_table(0x1e, 4, 1, + { + { 0x0, &D::RLDICL }, + { 0x1, &D::RLDICL }, + { 0x2, &D::RLDICR }, + { 0x3, &D::RLDICR }, + { 0x4, &D::RLDIC }, + { 0x5, &D::RLDIC }, + { 0x6, &D::RLDIMI }, + { 0x7, &D::RLDIMI }, + { 0x8, &D::RLDCL }, + { 0x9, &D::RLDCR }, + }); + + // Group 0x1f opcodes (field 21..30) + fill_table(0x1f, 10, 1, + { + { 0x000, &D::CMP }, + { 0x004, &D::TW }, + { 0x006, &D::LVSL }, + { 0x007, &D::LVEBX }, + { 0x008, &D::SUBFC, 1 }, + { 0x009, &D::MULHDU }, + { 0x00a, &D::ADDC, 1 }, + { 0x00b, &D::MULHWU }, + { 0x013, &D::MFOCRF }, + { 0x014, &D::LWARX }, + { 0x015, &D::LDX }, + { 0x017, &D::LWZX }, + { 0x018, &D::SLW }, + { 0x01a, &D::CNTLZW }, + { 0x01b, &D::SLD }, + { 0x01c, &D::AND }, + { 0x020, &D::CMPL }, + { 0x026, &D::LVSR }, + { 0x027, &D::LVEHX }, + { 0x028, &D::SUBF, 1 }, + { 0x035, &D::LDUX }, + { 0x036, &D::DCBST }, + { 0x037, &D::LWZUX }, + { 0x03a, &D::CNTLZD }, + { 0x03c, &D::ANDC }, + { 0x044, &D::TD }, + { 0x047, &D::LVEWX }, + { 0x049, &D::MULHD }, + { 0x04b, &D::MULHW }, + { 0x054, &D::LDARX }, + { 0x056, &D::DCBF }, + { 0x057, &D::LBZX }, + { 0x067, &D::LVX }, + { 0x068, &D::NEG, 1 }, + { 0x077, &D::LBZUX }, + { 0x07c, &D::NOR }, + { 0x087, &D::STVEBX }, + { 0x088, &D::SUBFE, 1 }, + { 0x08a, &D::ADDE, 1 }, + { 0x090, &D::MTOCRF }, + { 0x095, &D::STDX }, + { 0x096, &D::STWCX }, + { 0x097, &D::STWX }, + { 0x0a7, &D::STVEHX }, + { 0x0b5, &D::STDUX }, + { 0x0b7, &D::STWUX }, + { 0x0c7, &D::STVEWX }, + { 0x0c8, &D::SUBFZE, 1 }, + { 0x0ca, &D::ADDZE, 1 }, + { 0x0d6, &D::STDCX }, + { 0x0d7, &D::STBX }, + { 0x0e7, &D::STVX }, + { 0x0e8, &D::SUBFME, 1 }, + { 0x0e9, &D::MULLD, 1 }, + { 0x0ea, &D::ADDME, 1 }, + { 0x0eb, &D::MULLW, 1 }, + { 0x0f6, &D::DCBTST }, + { 0x0f7, &D::STBUX }, + { 0x10a, &D::ADD, 1 }, + { 0x116, &D::DCBT }, + { 0x117, &D::LHZX }, + { 0x11c, &D::EQV }, + { 0x136, &D::ECIWX }, + { 0x137, &D::LHZUX }, + { 0x13c, &D::XOR }, + { 0x153, &D::MFSPR }, + { 0x155, &D::LWAX }, + { 0x156, &D::DST }, + { 0x157, &D::LHAX }, + { 0x167, &D::LVXL }, + { 0x173, &D::MFTB }, + { 0x175, &D::LWAUX }, + { 0x176, &D::DSTST }, + { 0x177, &D::LHAUX }, + { 0x197, &D::STHX }, + { 0x19c, &D::ORC }, + { 0x1b6, &D::ECOWX }, + { 0x1b7, &D::STHUX }, + { 0x1bc, &D::OR }, + { 0x1c9, &D::DIVDU, 1 }, + { 0x1cb, &D::DIVWU, 1 }, + { 0x1d3, &D::MTSPR }, + { 0x1d6, &D::DCBI }, + { 0x1dc, &D::NAND }, + { 0x1e7, &D::STVXL }, + { 0x1e9, &D::DIVD, 1 }, + { 0x1eb, &D::DIVW, 1 }, + { 0x207, &D::LVLX }, + { 0x214, &D::LDBRX }, + { 0x215, &D::LSWX }, + { 0x216, &D::LWBRX }, + { 0x217, &D::LFSX }, + { 0x218, &D::SRW }, + { 0x21b, &D::SRD }, + { 0x227, &D::LVRX }, + { 0x237, &D::LFSUX }, + { 0x255, &D::LSWI }, + { 0x256, &D::SYNC }, + { 0x257, &D::LFDX }, + { 0x277, &D::LFDUX }, + { 0x287, &D::STVLX }, + { 0x294, &D::STDBRX }, + { 0x295, &D::STSWX }, + { 0x296, &D::STWBRX }, + { 0x297, &D::STFSX }, + { 0x2a7, &D::STVRX }, + { 0x2b7, &D::STFSUX }, + { 0x2d5, &D::STSWI }, + { 0x2d7, &D::STFDX }, + { 0x2f7, &D::STFDUX }, + { 0x307, &D::LVLXL }, + { 0x316, &D::LHBRX }, + { 0x318, &D::SRAW }, + { 0x31a, &D::SRAD }, + { 0x327, &D::LVRXL }, + { 0x336, &D::DSS }, + { 0x338, &D::SRAWI }, + { 0x33a, &D::SRADI }, + { 0x33b, &D::SRADI }, + { 0x356, &D::EIEIO }, + { 0x387, &D::STVLXL }, + { 0x396, &D::STHBRX }, + { 0x39a, &D::EXTSH }, + { 0x3a7, &D::STVRXL }, + { 0x3ba, &D::EXTSB }, + { 0x3d7, &D::STFIWX }, + { 0x3da, &D::EXTSW }, + { 0x3d6, &D::ICBI }, + { 0x3f6, &D::DCBZ }, + }); + + // Group 0x3a opcodes (field 30..31) + fill_table(0x3a, 2, 0, + { + { 0x0, &D::LD }, + { 0x1, &D::LDU }, + { 0x2, &D::LWA }, + }); + + // Group 0x3b opcodes (field 21..30) + fill_table(0x3b, 10, 1, + { + { 0x12, &D::FDIVS, 5 }, + { 0x14, &D::FSUBS, 5 }, + { 0x15, &D::FADDS, 5 }, + { 0x16, &D::FSQRTS, 5 }, + { 0x18, &D::FRES, 5 }, + { 0x19, &D::FMULS, 5 }, + { 0x1c, &D::FMSUBS, 5 }, + { 0x1d, &D::FMADDS, 5 }, + { 0x1e, &D::FNMSUBS, 5 }, + { 0x1f, &D::FNMADDS, 5 }, + }); + + // Group 0x3e opcodes (field 30..31) + fill_table(0x3e, 2, 0, + { + { 0x0, &D::STD }, + { 0x1, &D::STDU }, + }); + + // Group 0x3f opcodes (field 21..30) + fill_table(0x3f, 10, 1, + { + { 0x026, &D::MTFSB1 }, + { 0x040, &D::MCRFS }, + { 0x046, &D::MTFSB0 }, + { 0x086, &D::MTFSFI }, + { 0x247, &D::MFFS }, + { 0x2c7, &D::MTFSF }, + + { 0x000, &D::FCMPU }, + { 0x00c, &D::FRSP }, + { 0x00e, &D::FCTIW }, + { 0x00f, &D::FCTIWZ }, + + { 0x012, &D::FDIV, 5 }, + { 0x014, &D::FSUB, 5 }, + { 0x015, &D::FADD, 5 }, + { 0x016, &D::FSQRT, 5 }, + { 0x017, &D::FSEL, 5 }, + { 0x019, &D::FMUL, 5 }, + { 0x01a, &D::FRSQRTE, 5 }, + { 0x01c, &D::FMSUB, 5 }, + { 0x01d, &D::FMADD, 5 }, + { 0x01e, &D::FNMSUB, 5 }, + { 0x01f, &D::FNMADD, 5 }, + + { 0x020, &D::FCMPO }, + { 0x028, &D::FNEG }, + { 0x048, &D::FMR }, + { 0x088, &D::FNABS }, + { 0x108, &D::FABS }, + { 0x32e, &D::FCTID }, + { 0x32f, &D::FCTIDZ }, + { 0x34e, &D::FCFID }, + }); + } + + const std::array& get_table() const + { + return m_table; + } + + T decode(u32 inst) const + { + return m_table[ppu_decode(inst)]; + } }; + +namespace ppu_instructions +{ + namespace fields + { + enum + { + r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, + r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, + r22, r23, r24, r25, r26, r27, r28, r29, r30, r31, + }; + } + + using namespace fields; + + inline u32 ADDI(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x0eu << 26 }; op.rd = rt; op.ra = ra; op.simm16 = si; return op.opcode; } + inline u32 ADDIS(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x0fu << 26 }; op.rd = rt; op.ra = ra; op.simm16 = si; return op.opcode; } + inline u32 ORI(u32 rt, u32 ra, u32 ui) { ppu_opcode_t op{ 0x18u << 26 }; op.rd = rt; op.ra = ra; op.uimm16 = ui; return op.opcode; } + inline u32 ORIS(u32 rt, u32 ra, u32 ui) { ppu_opcode_t op{ 0x19u << 26 }; op.rd = rt; op.ra = ra; op.uimm16 = ui; return op.opcode; } + inline u32 OR(u32 ra, u32 rs, u32 rb, bool rc = false) { ppu_opcode_t op{ 0x1fu << 26 | 0x1bcu << 1 }; op.rs = rs; op.ra = ra; op.rb = rb; op.rc = rc; return op.opcode; } + inline u32 SC(u32 lev) { ppu_opcode_t op{ 0x11u << 26 }; op.lev = lev; return op.opcode; } + inline u32 B(s32 li, bool aa = false, bool lk = false) { ppu_opcode_t op{ 0x12u << 26 }; op.ll = li; op.aa = aa; op.lk = lk; return op.opcode; } + inline u32 BC(u32 bo, u32 bi, s32 bd, bool aa = false, bool lk = false) { ppu_opcode_t op{ 0x10u << 26 }; op.bo = bo; op.bi = bi; op.ds = bd / 4; op.aa = aa; op.lk = lk; return op.opcode; } + inline u32 BCLR(u32 bo, u32 bi, u32 bh, bool lk = false) { ppu_opcode_t op{ 0x13u << 26 | 0x10u << 1 }; op.bo = bo; op.bi = bi; op.bh = bh; op.lk = lk; return op.opcode; } + inline u32 BCCTR(u32 bo, u32 bi, u32 bh, bool lk = false) { ppu_opcode_t op{ 0x13u << 26 | 0x210u << 1 }; op.bo = bo; op.bi = bi; op.bh = bh; op.lk = lk; return op.opcode; } + inline u32 MFSPR(u32 rt, u32 spr) { ppu_opcode_t op{ 0x1fu << 26 | 0x153u << 1 }; op.rd = rt; op.spr = spr; return op.opcode; } + inline u32 MTSPR(u32 spr, u32 rs) { ppu_opcode_t op{ 0x1fu << 26 | 0x1d3u << 1 }; op.rs = rs; op.spr = spr; return op.opcode; } + inline u32 LWZ(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x20u << 26 }; op.rd = rt; op.ra = ra; op.simm16 = si; return op.opcode; } + inline u32 STD(u32 rs, u32 ra, s32 si) { ppu_opcode_t op{ 0x3eu << 26 }; op.rs = rs; op.ra = ra; op.ds = si / 4; return op.opcode; } + inline u32 STDU(u32 rs, u32 ra, s32 si) { ppu_opcode_t op{ 0x3eu << 26 | 1 }; op.rs = rs; op.ra = ra; op.ds = si / 4; return op.opcode; } + inline u32 LD(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x3au << 26 }; op.rd = rt; op.ra = ra; op.ds = si / 4; return op.opcode; } + inline u32 LDU(u32 rt, u32 ra, s32 si) { ppu_opcode_t op{ 0x3au << 26 | 1 }; op.rd = rt; op.ra = ra; op.ds = si / 4; return op.opcode; } + //inline u32 CMPI(u32 bf, u32 l, u32 ra, u32 ui) { ppu_opcode_t op{ 0xbu << 26 }; op.crfd = bf; op.l10 = l; op.ra = ra; op.uimm16 = ui; return op.opcode; } + //inline u32 CMPLI(u32 bf, u32 l, u32 ra, u32 ui) { ppu_opcode_t op{ 0xau << 26 }; op.crfd = bf; op.l10 = l; op.ra = ra; op.uimm16 = ui; return op.opcode; } + inline u32 RLDICL(u32 ra, u32 rs, u32 sh, u32 mb, bool rc = false) { ppu_opcode_t op{ 30 << 26 }; op.ra = ra; op.rs = rs; op.sh64 = sh; op.mbe64 = mb; op.rc = rc; return op.opcode; } + + namespace implicts + { + inline u32 HACK(u32 index) { return 0x01 << 26 | index; } + inline u32 NOP() { return ORI(r0, r0, 0); } + inline u32 MR(u32 rt, u32 ra) { return OR(rt, ra, ra, false); } + inline u32 LI(u32 rt, u32 imm) { return ADDI(rt, r0, imm); } + inline u32 LIS(u32 rt, u32 imm) { return ADDIS(rt, r0, imm); } + + inline u32 BLR() { return BCLR(0x10 | 0x04, 0, 0); } + inline u32 BCTR() { return BCCTR(0x10 | 0x04, 0, 0); } + inline u32 BCTRL() { return BCCTR(0x10 | 0x04, 0, 0, true); } + inline u32 MFCTR(u32 reg) { return MFSPR(reg, 9 << 5); } + inline u32 MTCTR(u32 reg) { return MTSPR(9 << 5, reg); } + inline u32 MFLR(u32 reg) { return MFSPR(reg, 8 << 5); } + inline u32 MTLR(u32 reg) { return MTSPR(8 << 5, reg); } + + //inline u32 BNE(u32 cr, s32 imm) { return BC(4, 2 | cr << 2, imm); } + //inline u32 BEQ(u32 cr, s32 imm) { return BC(12, 2 | cr << 2, imm); } + //inline u32 BGT(u32 cr, s32 imm) { return BC(12, 1 | cr << 2, imm); } + //inline u32 BNE(s32 imm) { return BNE(cr0, imm); } + //inline u32 BEQ(s32 imm) { return BEQ(cr0, imm); } + //inline u32 BGT(s32 imm) { return BGT(cr0, imm); } + + //inline u32 CMPDI(u32 cr, u32 reg, u32 imm) { return CMPI(cr, 1, reg, imm); } + //inline u32 CMPDI(u32 reg, u32 imm) { return CMPDI(cr0, reg, imm); } + //inline u32 CMPWI(u32 cr, u32 reg, u32 imm) { return CMPI(cr, 0, reg, imm); } + //inline u32 CMPWI(u32 reg, u32 imm) { return CMPWI(cr0, reg, imm); } + //inline u32 CMPLDI(u32 cr, u32 reg, u32 imm) { return CMPLI(cr, 1, reg, imm); } + //inline u32 CMPLDI(u32 reg, u32 imm) { return CMPLDI(cr0, reg, imm); } + //inline u32 CMPLWI(u32 cr, u32 reg, u32 imm) { return CMPLI(cr, 0, reg, imm); } + //inline u32 CMPLWI(u32 reg, u32 imm) { return CMPLWI(cr0, reg, imm); } + + inline u32 EXTRDI(u32 x, u32 y, u32 n, u32 b) { return RLDICL(x, y, b + n, 64 - b, false); } + inline u32 SRDI(u32 x, u32 y, u32 n) { return RLDICL(x, y, 64 - n, n, false); } + inline u32 CLRLDI(u32 x, u32 y, u32 n) { return RLDICL(x, y, 0, n, false); } + } + + using namespace implicts; +} diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 58be498031..ccce38e9e6 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -1,108 +1,62 @@ #include "stdafx.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/state.h" #include "Emu/IdManager.h" -#include "Emu/Cell/PPUThread.h" -#include "Emu/Cell/PPUDecoder.h" -#include "Emu/Cell/PPUInterpreter.h" -#include "Emu/Cell/PPUInterpreter2.h" -#include "Emu/Cell/PPULLVMRecompiler.h" -//#include "Emu/Cell/PPURecompiler.h" -#include "Utilities/VirtualMemory.h" +#include "PPUThread.h" +#include "PPUInterpreter.h" +#include "PPUModule.h" -#ifdef _WIN32 -#include -#else -#include -#include -#endif - -u64 rotate_mask[64][64]; - -extern u32 ppu_get_tls(u32 thread); -extern void ppu_free_tls(u32 thread); - -//thread_local const std::weak_ptr g_tls_ppu_decoder_cache = fxm::get(); -thread_local const ppu_decoder_cache_t* g_tls_ppu_decoder_cache = nullptr; // temporarily, because thread_local is not fully available - -ppu_decoder_cache_t::ppu_decoder_cache_t() - : pointer(static_cast(memory_helper::reserve_memory(0x200000000))) +enum class ppu_decoder_type { -} + precise, + fast, + llvm, +}; -ppu_decoder_cache_t::~ppu_decoder_cache_t() +cfg::map_entry g_cfg_ppu_decoder(cfg::root.core, "PPU Decoder", 1, { - memory_helper::free_reserved_memory(pointer, 0x200000000); -} + { "Interpreter (precise)", ppu_decoder_type::precise }, + { "Interpreter (fast)", ppu_decoder_type::fast }, + { "Recompiler (LLVM)", ppu_decoder_type::llvm }, +}); -void ppu_decoder_cache_t::initialize(u32 addr, u32 size) -{ - memory_helper::commit_page_memory(pointer + addr / 4, size * 2); - - PPUInterpreter2* inter; - PPUDecoder dec(inter = new PPUInterpreter2); - - for (u32 pos = addr; pos < addr + size; pos += 4) - { - inter->func = ppu_interpreter::NULL_OP; - - // decode PPU opcode - dec.Decode(vm::ps3::read32(pos)); - - // store function address - pointer[pos / 4] = inter->func; - } -} - -PPUThread::PPUThread(const std::string& name) - : CPUThread(CPU_THREAD_PPU, name) -{ - InitRotateMask(); -} - -PPUThread::~PPUThread() -{ - close_stack(); - ppu_free_tls(m_id); -} +const ppu_decoder s_ppu_interpreter_precise; +const ppu_decoder s_ppu_interpreter_fast; std::string PPUThread::get_name() const { - return fmt::format("PPU Thread[0x%x] (%s)[0x%08x]", m_id, CPUThread::get_name(), PC); + return fmt::format("PPU[0x%x] Thread (%s)", id, name); } -void PPUThread::dump_info() const +std::string PPUThread::dump() const { - extern std::string get_ps3_function_name(u64 fid); + std::string ret = "Registers:\n=========\n"; - if (~hle_code < 1024) - { - LOG_SUCCESS(HLE, "Last syscall: %lld (%s)", ~hle_code, get_ps3_function_name(hle_code)); - } - else if (hle_code) - { - LOG_SUCCESS(HLE, "Last function: %s (0x%llx)", get_ps3_function_name(hle_code), hle_code); - } + for (uint i = 0; i<32; ++i) ret += fmt::format("GPR[%d] = 0x%llx\n", i, GPR[i]); + for (uint i = 0; i<32; ++i) ret += fmt::format("FPR[%d] = %.6G\n", i, FPR[i]); + for (uint i = 0; i<32; ++i) ret += fmt::format("VR[%d] = 0x%s [%s]\n", i, VR[i].to_hex().c_str(), VR[i].to_xyzw().c_str()); + ret += fmt::format("CR = 0x%08x\n", GetCR()); + ret += fmt::format("LR = 0x%llx\n", LR); + ret += fmt::format("CTR = 0x%llx\n", CTR); + ret += fmt::format("XER = [CA=%u | OV=%u | SO=%u | CNT=%u]\n", u32{ CA }, u32{ OV }, u32{ SO }, u32{ XCNT }); + //ret += fmt::format("FPSCR = 0x%x " + // "[RN=%d | NI=%d | XE=%d | ZE=%d | UE=%d | OE=%d | VE=%d | " + // "VXCVI=%d | VXSQRT=%d | VXSOFT=%d | FPRF=%d | " + // "FI=%d | FR=%d | VXVC=%d | VXIMZ=%d | " + // "VXZDZ=%d | VXIDI=%d | VXISI=%d | VXSNAN=%d | " + // "XX=%d | ZX=%d | UX=%d | OX=%d | VX=%d | FEX=%d | FX=%d]\n", + // FPSCR.FPSCR, + // u32{ FPSCR.RN }, + // u32{ FPSCR.NI }, u32{ FPSCR.XE }, u32{ FPSCR.ZE }, u32{ FPSCR.UE }, u32{ FPSCR.OE }, u32{ FPSCR.VE }, + // u32{ FPSCR.VXCVI }, u32{ FPSCR.VXSQRT }, u32{ FPSCR.VXSOFT }, u32{ FPSCR.FPRF }, + // u32{ FPSCR.FI }, u32{ FPSCR.FR }, u32{ FPSCR.VXVC }, u32{ FPSCR.VXIMZ }, + // u32{ FPSCR.VXZDZ }, u32{ FPSCR.VXIDI }, u32{ FPSCR.VXISI }, u32{ FPSCR.VXSNAN }, + // u32{ FPSCR.XX }, u32{ FPSCR.ZX }, u32{ FPSCR.UX }, u32{ FPSCR.OX }, u32{ FPSCR.VX }, u32{ FPSCR.FEX }, u32{ FPSCR.FX }); - CPUThread::dump_info(); + return ret; } -void PPUThread::init_regs() -{ - GPR[1] = align(stack_addr + stack_size, 0x200) - 0x200; - GPR[13] = ppu_get_tls(m_id) + 0x7000; // 0x7000 is subtracted from r13 to access first TLS element - - LR = 0; - CTR = PC; - CR.CR = 0x22000082; - VSCR.NJ = 1; - TB = 0; - - //m_state |= CPU_STATE_INTR; -} - -void PPUThread::init_stack() +void PPUThread::cpu_init() { if (!stack_addr) { @@ -118,14 +72,70 @@ void PPUThread::init_stack() throw EXCEPTION("Out of stack memory"); } } + + GPR[1] = align(stack_addr + stack_size, 0x200) - 0x200; } -void PPUThread::close_stack() +void PPUThread::cpu_task() { - if (stack_addr) + //SetHostRoundingMode(FPSCR_RN_NEAR); + + if (custom_task) { - vm::dealloc_verbose_nothrow(stack_addr, vm::stack); - stack_addr = 0; + if (check_status()) return; + + return custom_task(*this); + } + + _log::g_tls_make_prefix = [](const auto&, auto, const auto&) + { + const auto cpu = static_cast(get_current_cpu_thread()); + + return fmt::format("%s [0x%08x]", cpu->get_name(), cpu->PC); + }; + + const auto base = vm::_ptr(0); + + // Select opcode table + const auto& table = *( + g_cfg_ppu_decoder.get() == ppu_decoder_type::precise ? &s_ppu_interpreter_precise.get_table() : + 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; + + while (true) + { + if (_pc == PC && !state.load()) + { + func0(*this, { op0 }); + + if ((_pc += 4) == (PC += 4) && !state.load()) + { + func1(*this, { op1 }); + + if ((_pc += 4) == (PC += 4)) + { + op0 = op2; + func0 = func2; + const auto ops = reinterpret_cast*>(base + _pc); + func1 = table[ppu_decode(op1 = ops[1])]; + func2 = table[ppu_decode(op2 = ops[2])]; + continue; + } + } + } + + // Reinitialize + _pc = PC; + const auto ops = reinterpret_cast*>(base + _pc); + func0 = table[ppu_decode(op0 = ops[0])]; + func1 = table[ppu_decode(op1 = ops[1])]; + func2 = table[ppu_decode(op2 = ops[2])]; + + if (check_status()) return; } } @@ -134,99 +144,28 @@ bool PPUThread::handle_interrupt() return false; } -void PPUThread::do_run() +PPUThread::~PPUThread() { - m_dec.reset(); - - switch (auto mode = rpcs3::state.config.core.ppu_decoder.value()) + if (stack_addr) { - case ppu_decoder_type::interpreter: // original interpreter - { - m_dec.reset(new PPUDecoder(new PPUInterpreter(*this))); - break; - } - - case ppu_decoder_type::interpreter2: // alternative interpreter - { - break; - } - - case ppu_decoder_type::recompiler_llvm: - { -#ifdef PPU_LLVM_RECOMPILER - m_dec.reset(new ppu_recompiler_llvm::CPUHybridDecoderRecompiler(*this)); -#else - LOG_ERROR(PPU, "This image does not include PPU JIT (LLVM)"); - Emu.Pause(); -#endif - break; - } - - //case 3: m_dec.reset(new PPURecompiler(*this)); break; - - default: - { - LOG_ERROR(PPU, "Invalid CPU decoder mode: %d", mode); - Emu.Pause(); - } + vm::dealloc_verbose_nothrow(stack_addr, vm::stack); } } -bool FPRdouble::IsINF(PPCdouble d) +be_t* PPUThread::get_stack_arg(s32 i, u64 align) { - return ((u64&)d & 0x7FFFFFFFFFFFFFFFULL) == 0x7FF0000000000000ULL; -} - -bool FPRdouble::IsNaN(PPCdouble d) -{ - return std::isnan((double)d) ? 1 : 0; -} - -bool FPRdouble::IsQNaN(PPCdouble d) -{ - return - ((u64&)d & 0x7FF0000000000000ULL) == 0x7FF0000000000000ULL && - ((u64&)d & 0x0007FFFFFFFFFFFULL) == 0ULL && - ((u64&)d & 0x000800000000000ULL) != 0ULL; -} - -bool FPRdouble::IsSNaN(PPCdouble d) -{ - return - ((u64&)d & 0x7FF0000000000000ULL) == 0x7FF0000000000000ULL && - ((u64&)d & 0x000FFFFFFFFFFFFFULL) != 0ULL && - ((u64&)d & 0x0008000000000000ULL) == 0ULL; -} - -int FPRdouble::Cmp(PPCdouble a, PPCdouble b) -{ - if(a < b) return CR_LT; - if(a > b) return CR_GT; - if(a == b) return CR_EQ; - - return CR_SO; -} - -u64 PPUThread::get_stack_arg(s32 i) -{ - return vm::ps3::read64(VM_CAST(GPR[1] + 0x70 + 0x8 * (i - 9))); + if (align != 1 && align != 2 && align != 4 && align != 8 && align != 16) throw fmt::exception("Unsupported alignment: 0x%llx" HERE, align); + return vm::_ptr(vm::cast((GPR[1] + 0x30 + 0x8 * (i - 1)) & (0 - align), HERE)); } void PPUThread::fast_call(u32 addr, u32 rtoc) { - if (!is_current()) - { - throw EXCEPTION("Called from the wrong thread"); - } - 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); - assert(!old_task || !custom_task); - PC = addr; GPR[2] = rtoc; LR = Emu.GetCPUThreadStop(); @@ -236,11 +175,13 @@ void PPUThread::fast_call(u32 addr, u32 rtoc) { cpu_task(); } - catch (CPUThreadReturn) + catch (cpu_state _s) { + state += _s; + if (_s != cpu_state::ret) throw; } - m_state &= ~CPU_STATE_RETURN; + state -= cpu_state::ret; PC = old_PC; @@ -253,135 +194,3 @@ void PPUThread::fast_call(u32 addr, u32 rtoc) LR = old_LR; custom_task = std::move(old_task); } - -void PPUThread::fast_stop() -{ - m_state |= CPU_STATE_RETURN; -} - -void PPUThread::cpu_task() -{ - SetHostRoundingMode(FPSCR_RN_NEAR); - - if (custom_task) - { - if (check_status()) return; - - return custom_task(*this); - } - - if (!g_tls_ppu_decoder_cache) - { - const auto decoder_cache = fxm::get(); - - if (!decoder_cache) - { - throw EXCEPTION("PPU Decoder Cache not initialized"); - } - - g_tls_ppu_decoder_cache = decoder_cache.get(); // unsafe (TODO) - } - - const auto exec_map = g_tls_ppu_decoder_cache->pointer; - - if (m_dec) - { - while (true) - { - if (m_state && check_status()) break; - - // decode instruction using specified decoder - m_dec->DecodeMemory(PC); - - // next instruction - PC += 4; - } - } - else - { - while (true) - { - // get cached interpreter function address - const auto func = exec_map[PC / 4]; - - // check status - if (!m_state) - { - // call interpreter function - func(*this, { vm::ps3::read32(PC) }); - - // next instruction - PC += 4; - - continue; - } - - if (check_status()) - { - break; - } - } - } -} - -ppu_thread::ppu_thread(u32 entry, const std::string& name, u32 stack_size, s32 prio) -{ - auto ppu = idm::make_ptr(name); - - if (entry) - { - ppu->PC = vm::ps3::read32(entry); - ppu->GPR[2] = vm::ps3::read32(entry + 4); // rtoc - } - - ppu->stack_size = stack_size ? stack_size : Emu.GetPrimaryStackSize(); - ppu->prio = prio ? prio : Emu.GetPrimaryPrio(); - - thread = std::move(ppu); - - argc = 0; -} - -cpu_thread& ppu_thread::args(std::initializer_list values) -{ - if (!values.size()) - return *this; - - assert(argc == 0); - - envp.set(vm::alloc(align(SIZE_32(*envp), stack_align), vm::main)); - *envp = 0; - argv.set(vm::alloc(SIZE_32(*argv) * (u32)values.size(), vm::main)); - - for (auto &arg : values) - { - const u32 arg_size = align(u32(arg.size() + 1), stack_align); - const u32 arg_addr = vm::alloc(arg_size, vm::main); - - std::memcpy(vm::base(arg_addr), arg.c_str(), arg.size() + 1); - - argv[argc++] = arg_addr; - } - - return *this; -} - -cpu_thread& ppu_thread::run() -{ - thread->run(); - - gpr(3, argc); - gpr(4, argv.addr()); - gpr(5, envp.addr()); - - return *this; -} - -ppu_thread& ppu_thread::gpr(uint index, u64 value) -{ - assert(index < 32); - - static_cast(*thread).GPR[index] = value; - - return *this; -} diff --git a/rpcs3/Emu/Cell/PPUThread.h b/rpcs3/Emu/Cell/PPUThread.h index 897864d611..4c007110e8 100644 --- a/rpcs3/Emu/Cell/PPUThread.h +++ b/rpcs3/Emu/Cell/PPUThread.h @@ -4,246 +4,32 @@ #include "Emu/CPU/CPUThread.h" #include "Emu/Memory/vm.h" -enum +class PPUThread final : public cpu_thread { - XER_SO = 0x80000000, - XER_OV = 0x40000000, - XER_CA = 0x20000000, -}; +public: + virtual std::string get_name() const override; + virtual std::string dump() const override; + virtual void cpu_init() override; + virtual void cpu_task() override; + virtual bool handle_interrupt() override; -enum -{ - CR_LT = 0x8, - CR_GT = 0x4, - CR_EQ = 0x2, - CR_SO = 0x1, -}; - -enum FPSCR_EXP -{ - FPSCR_FX = 0x80000000, - FPSCR_FEX = 0x40000000, - FPSCR_VX = 0x20000000, - FPSCR_OX = 0x10000000, - - FPSCR_UX = 0x08000000, - FPSCR_ZX = 0x04000000, - FPSCR_XX = 0x02000000, - FPSCR_VXSNAN = 0x01000000, - - FPSCR_VXISI = 0x00800000, - FPSCR_VXIDI = 0x00400000, - FPSCR_VXZDZ = 0x00200000, - FPSCR_VXIMZ = 0x00100000, - - FPSCR_VXVC = 0x00080000, - FPSCR_FR = 0x00040000, - FPSCR_FI = 0x00020000, - - FPSCR_VXSOFT = 0x00000400, - FPSCR_VXSQRT = 0x00000200, - FPSCR_VXCVI = 0x00000100, - - FPSCR_VX_ALL = FPSCR_VXSNAN | FPSCR_VXISI | FPSCR_VXIDI | FPSCR_VXZDZ | FPSCR_VXIMZ | FPSCR_VXVC | FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI, -}; - -static const u64 DOUBLE_SIGN = 0x8000000000000000ULL; -static const u64 DOUBLE_EXP = 0x7FF0000000000000ULL; -static const u64 DOUBLE_FRAC = 0x000FFFFFFFFFFFFFULL; -static const u64 DOUBLE_ZERO = 0x0000000000000000ULL; - -union FPSCRhdr -{ - struct + PPUThread(const std::string& name) + : cpu_thread(cpu_type::ppu, name) { - u32 RN :2; //Floating-point rounding control - u32 NI :1; //Floating-point non-IEEE mode - u32 XE :1; //Floating-point inexact exception enable - u32 ZE :1; //IEEE floating-point zero divide exception enable - u32 UE :1; //IEEE floating-point underflow exception enable - u32 OE :1; //IEEE floating-point overflow exception enable - u32 VE :1; //Floating-point invalid operation exception enable - u32 VXCVI :1; //Floating-point invalid operation exception for invalid integer convert - u32 VXSQRT :1; //Floating-point invalid operation exception for invalid square root - u32 VXSOFT :1; //Floating-point invalid operation exception for software request - u32 :1; //Reserved - u32 FPRF :5; //Floating-point result flags - u32 FI :1; //Floating-point fraction inexact - u32 FR :1; //Floating-point fraction rounded - u32 VXVC :1; //Floating-point invalid operation exception for invalid compare - u32 VXIMZ :1; //Floating-point invalid operation exception for * * 0 - u32 VXZDZ :1; //Floating-point invalid operation exception for 0 / 0 - u32 VXIDI :1; //Floating-point invalid operation exception for * + * - u32 VXISI :1; //Floating-point invalid operation exception for * - * - u32 VXSNAN :1; //Floating-point invalid operation exception for SNaN - u32 XX :1; //Floating-point inexact exception - u32 ZX :1; //Floating-point zero divide exception - u32 UX :1; //Floating-point underflow exception - u32 OX :1; //Floating-point overflow exception - u32 VX :1; //Floating-point invalid operation exception summary - u32 FEX :1; //Floating-point enabled exception summary - u32 FX :1; //Floating-point exception summary - }; + } - u32 FPSCR; -}; + virtual ~PPUThread() override; -union MSRhdr -{ - struct - { - //Little-endian mode enable - //0 The processor runs in big-endian mode. - //1 The processor runs in little-endian mode. - u64 LE : 1; + u64 GPR[32]{}; // General-Purpose Registers + f64 FPR[32]{}; // Floating Point Registers + v128 VR[32]{}; // Vector Registers + alignas(16) bool CR[32]{}; // Condition Registers + bool SO{}; // XER: Summary overflow + bool OV{}; // XER: Overflow + bool CA{}; // XER: Carry + u8 XCNT{}; // XER: 0..6 - //Recoverable exception (for system reset and machine check exceptions). - //0 Exception is not recoverable. - //1 Exception is recoverable. - u64 RI : 1; - - //Reserved - u64 : 2; - - //Data address translation - //0 Data address translation is disabled. - //1 Data address translation is enabled. - u64 DR : 1; - - //Instruction address translation - //0 Instruction address translation is disabled. - //1 Instruction address translation is enabled. - u64 IR : 1; - - //Exception prefix. The setting of this bit specifies whether an exception vector offset - //is prepended with Fs or 0s. In the following description, nnnnn is the offset of the - //exception. - //0 Exceptions are vectored to the physical address 0x0000_0000_000n_nnnn in 64-bit implementations. - //1 Exceptions are vectored to the physical address 0xFFFF_FFFF_FFFn_nnnn in 64-bit implementations. - u64 IP : 1; - - //Reserved - u64 : 1; - - //Floating-point exception mode 1 - u64 FE1 : 1; - - //Branch trace enable (Optional) - //0 The processor executes branch instructions normally. - //1 The processor generates a branch trace exception after completing the - //execution of a branch instruction, regardless of whether or not the branch was - //taken. - //Note: If the function is not implemented, this bit is treated as reserved. - u64 BE : 1; - - //Single-step trace enable (Optional) - //0 The processor executes instructions normally. - //1 The processor generates a single-step trace exception upon the successful - //execution of the next instruction. - //Note: If the function is not implemented, this bit is treated as reserved. - u64 SE : 1; - - //Floating-point exception mode 0 - u64 FE0 : 1; - - //Machine check enable - //0 Machine check exceptions are disabled. - //1 Machine check exceptions are enabled. - u64 ME : 1; - - //Floating-point available - //0 The processor prevents dispatch of floating-point instructions, including - //floating-point loads, stores, and moves. - //1 The processor can execute floating-point instructions. - u64 FP : 1; - - //Privilege level - //0 The processor can execute both user- and supervisor-level instructions. - //1 The processor can only execute user-level instructions. - u64 PR : 1; - - //External interrupt enable - //0 While the bit is cleared the processor delays recognition of external interrupts - //and decrementer exception conditions. - //1 The processor is enabled to take an external interrupt or the decrementer - //exception. - u64 EE : 1; - - //Exception little-endian mode. When an exception occurs, this bit is copied into - //MSR[LE] to select the endian mode for the context established by the exception - u64 ILE : 1; - - //Reserved - u64 : 1; - - //Power management enable - //0 Power management disabled (normal operation mode). - //1 Power management enabled (reduced power mode). - //Note: Power management functions are implementation-dependent. If the function - //is not implemented, this bit is treated as reserved. - u64 POW : 1; - - //Reserved - u64 : 44; - - //Sixty-four bit mode - //0 The 64-bit processor runs in 32-bit mode. - //1 The 64-bit processor runs in 64-bit mode. Note that this is the default setting. - u64 SF : 1; - }; - - u64 MSR; -}; - -union PVRhdr -{ - struct - { - u16 revision; - u16 version; - }; - - u32 PVR; -}; - -union CRhdr -{ - u32 CR; - - struct - { - u8 cr7 : 4; - u8 cr6 : 4; - u8 cr5 : 4; - u8 cr4 : 4; - u8 cr3 : 4; - u8 cr2 : 4; - u8 cr1 : 4; - u8 cr0 : 4; - }; -}; - -union XERhdr -{ - u64 XER; - - struct - { - u32 L : 29; - u32 CA : 1; - u32 OV : 1; - u32 SO : 1; - u32 : 32; - }; -}; - -union VSCRhdr -{ - u32 VSCR; - - struct - { - /* + /* Saturation. A sticky status bit indicating that some field in a saturating instruction saturated since the last time SAT was cleared. In other words when SAT = '1' it remains set to '1' until it is cleared to '0' by an mtvscr instruction. @@ -261,11 +47,10 @@ union VSCRhdr Vector Pack with Saturation (vpkuhus, vpkuwus, vpkshus, vpkswus, vpkshss, vpkswss) Vector Convert to Fixed-Point with Saturation (vctuxs, vctsxs) 0 Indicates no saturation occurred; mtvscr can explicitly clear this bit. - */ - u32 SAT : 1; - u32 X : 15; + */ + bool SAT{}; - /* + /* Non-Java. A mode control bit that determines whether vector floating-point operations will be performed in a Java-IEEE-C9X-compliant mode or a possibly faster non-Java/non-IEEE mode. 0 The Java-IEEE-C9X-compliant mode is selected. Denormalized values are handled as specified @@ -274,759 +59,162 @@ union VSCRhdr contains a denormalized value, the value '0' is used instead. If an instruction causes an underflow exception, the corresponding element in the target VR is cleared to '0'. In both cases, the '0' has the same sign as the denormalized or underflowing value. - */ - u32 NJ : 1; - u32 Y : 15; - }; -}; + */ + bool NJ{ true }; -enum FPRType -{ - //FPR_NORM, - //FPR_ZERO, - //FPR_SNAN, - //FPR_QNAN, - //FPR_INF, - FPR_PZ = 0x2, - FPR_PN = 0x4, - FPR_PINF = 0x5, - FPR_NN = 0x8, - FPR_NINF = 0x9, - FPR_QNAN = 0x11, - FPR_NZ = 0x12, - FPR_PD = 0x14, - FPR_ND = 0x18, -}; + bool FL{}; // FPSCR.FPCC.FL + bool FG{}; // FPSCR.FPCC.FG + bool FE{}; // FPSCR.FPCC.FE + bool FU{}; // FPSCR.FPCC.FU -static const u64 FPR_NAN_I = 0x7FF8000000000000ULL; -static const double& FPR_NAN = (double&)FPR_NAN_I; + u64 LR{}; // Link Register + u64 CTR{}; // Counter Register + u32 VRSAVE{}; + u32 PC{}; -struct PPCdouble -{ - union - { - double _double; - u64 _u64; - - struct - { - u64 frac : 52; - u64 exp : 11; - u64 sign : 1; - }; - - struct - { - u64 : 51; - u64 nan : 1; - u64 : 12; - }; - }; - - FPRType type; - - operator double&() { return _double; } - operator const double&() const { return _double; } - - PPCdouble& operator = (const PPCdouble& r) - { - _u64 = r._u64; - type = UpdateType(); - return *this; - } - - FPRType UpdateType() const - { - const int fpc = _fpclass(_double); - -#ifndef __GNUG__ - switch(fpc) - { - case _FPCLASS_SNAN:// return FPR_SNAN; - case _FPCLASS_QNAN: return FPR_QNAN; - case _FPCLASS_NINF: return FPR_NINF; - case _FPCLASS_NN: return FPR_NN; - case _FPCLASS_ND: return FPR_ND; - case _FPCLASS_NZ: return FPR_NZ; - case _FPCLASS_PZ: return FPR_PZ; - case _FPCLASS_PD: return FPR_PD; - case _FPCLASS_PN: return FPR_PN; - case _FPCLASS_PINF: return FPR_PINF; - default: throw EXCEPTION("Unknown fpclass (0x%04x)", fpc); - } -#else - switch (fpc) - { - case FP_NAN: return FPR_QNAN; - case FP_INFINITE: return std::signbit(_double) ? FPR_NINF : FPR_PINF; - case FP_SUBNORMAL: return std::signbit(_double) ? FPR_ND : FPR_PD; - case FP_ZERO: return std::signbit(_double) ? FPR_NZ : FPR_PZ; - default: return std::signbit(_double) ? FPR_NN : FPR_PN; - } -#endif - } - - FPRType GetType() const - { - return type; - } - - u32 To32() const - { - float res = (float)_double; - - return (u32&)res; - } - - u64 To64() const - { - return (u64&)_double; - } - - u32 GetZerosCount() const - { - u32 ret; - u32 dd = frac >> 32; - if(dd) - { - ret = 31; - } - else - { - dd = frac; - ret = 63; - } - - if(dd > 0xffff) - { - ret -= 16; - dd >>= 16; - } - if(dd > 0xff) - { - ret -= 8; - dd >>= 8; - } - if(dd & 0xf0) - { - ret -= 4; - dd >>= 4; - } - if(dd & 0xc) - { - ret -= 2; - dd >>= 2; - } - if(dd & 0x2) ret--; - - return ret; - } - - PPCdouble() : _u64(0) - { - type = UpdateType(); - } - - PPCdouble(double val) : _double(val) - { - type = UpdateType(); - } - - PPCdouble(u64 val) : _u64(val) - { - type = UpdateType(); - } - - PPCdouble(u32 val) : _u64(val) - { - type = UpdateType(); - } -}; - -struct FPRdouble -{ - static const u64 double_sign = 0x8000000000000000ULL; - static const u64 double_frac = 0x000FFFFFFFFFFFFFULL; - - static bool IsINF(PPCdouble d); - static bool IsNaN(PPCdouble d); - static bool IsQNaN(PPCdouble d); - static bool IsSNaN(PPCdouble d); - - static int Cmp(PPCdouble a, PPCdouble b); -}; - -class PPUThread final : public CPUThread -{ -public: - PPCdouble FPR[32]{}; //Floating Point Register - FPSCRhdr FPSCR{}; //Floating Point Status and Control Register - u64 GPR[32]{}; //General-Purpose Register - v128 VPR[32]{}; - u32 vpcr = 0; - - CRhdr CR{}; //Condition Register - //CR0 - // 0 : LT - Negative (is negative) - // : 0 - Result is not negative - // : 1 - Result is negative - // 1 : GT - Positive (is positive) - // : 0 - Result is not positive - // : 1 - Result is positive - // 2 : EQ - Zero (is zero) - // : 0 - Result is not equal to zero - // : 1 - Result is equal to zero - // 3 : SO - Summary overflow (copy of the final state XER[S0]) - // : 0 - No overflow occurred - // : 1 - Overflow occurred - - //CRn - // 0 : LT - Less than (rA > X) - // : 0 - rA is not less than - // : 1 - rA is less than - // 1 : GT - Greater than (rA < X) - // : 0 - rA is not greater than - // : 1 - rA is greater than - // 2 : EQ - Equal to (rA == X) - // : 0 - Result is not equal to zero - // : 1 - Result is equal to zero - // 3 : SO - Summary overflow (copy of the final state XER[S0]) - // : 0 - No overflow occurred - // : 1 - Overflow occurred - - //SPR : Special-Purpose Registers - - XERhdr XER{}; //SPR 0x001 : Fixed-Point Expection Register - // 0 : SO - Summary overflow - // : 0 - No overflow occurred - // : 1 - Overflow occurred - // 1 : OV - Overflow - // : 0 - No overflow occurred - // : 1 - Overflow occurred - // 2 : CA - Carry - // : 0 - Carry did not occur - // : 1 - Carry occured - // 3 - 24 : Reserved - // 25 - 31 : TBC - // Transfer-byte count - - MSRhdr MSR{}; //Machine State Register - PVRhdr PVR{}; //Processor Version Register - - VSCRhdr VSCR{}; // Vector Status and Control Register - - u64 LR = 0; //SPR 0x008 : Link Register - u64 CTR = 0; //SPR 0x009 : Count Register - - u32 VRSAVE = 0; //SPR 0x100: VR Save/Restore Register (32 bits) - - u64 SPRG[8]{}; //SPR 0x110 - 0x117 : SPR General-Purpose Registers - - //TBR : Time-Base Registers - u64 TB = 0; //TBR 0x10C - 0x10D - - u32 PC = 0; - s32 prio = 0; // thread priority - u32 stack_addr = 0; // stack address - u32 stack_size = 0; // stack size + s32 prio = 0; // Thread priority + u32 stack_addr = 0; // Stack address + u32 stack_size = 0; // Stack size bool is_joinable = true; bool is_joining = false; - u64 hle_code = 0; // current syscall (~0..~1023) or function id (1..UINT32_MAX) + std::function custom_task; - std::function custom_task; + // Function name can be stored here. Used to print the last called function. + const char* last_function = nullptr; // When a thread has met an exception, this variable is used to retro propagate it through stack call. std::exception_ptr pending_exception; -public: - PPUThread(const std::string& name); - virtual ~PPUThread() override; - - virtual std::string get_name() const override; - virtual void dump_info() const override; - virtual u32 get_pc() const override { return PC; } - virtual u32 get_offset() const override { return 0; } - virtual void do_run() override; - virtual void cpu_task() override; - - virtual void init_regs() override; - virtual void init_stack() override; - virtual void close_stack() override; - - virtual bool handle_interrupt() override; - - u8 GetCR(const u8 n) const + // Pack CR bits + u32 GetCR() const { - switch(n) + u32 result{}; + + for (u32 bit : CR) { - case 0: return CR.cr0; - case 1: return CR.cr1; - case 2: return CR.cr2; - case 3: return CR.cr3; - case 4: return CR.cr4; - case 5: return CR.cr5; - case 6: return CR.cr6; - case 7: return CR.cr7; + result = (result << 1) | bit; } - return 0; + return result; } - void SetCR(const u8 n, const u32 value) + // Unpack CR bits + void SetCR(u32 value) { - switch(n) + for (bool& b : CR) { - case 0: CR.cr0 = value; break; - case 1: CR.cr1 = value; break; - case 2: CR.cr2 = value; break; - case 3: CR.cr3 = value; break; - case 4: CR.cr4 = value; break; - case 5: CR.cr5 = value; break; - case 6: CR.cr6 = value; break; - case 7: CR.cr7 = value; break; + b = (value & 0x1) != 0; + value >>= 1; } } - void SetCRBit(const u8 n, const u32 bit, const bool value) + // Set CR field + void SetCR(u32 field, bool le, bool gt, bool eq, bool so) { - switch(n) - { - case 0: CR.cr0 = (value ? CR.cr0 | bit : CR.cr0 & ~bit); break; - case 1: CR.cr1 = (value ? CR.cr1 | bit : CR.cr1 & ~bit); break; - case 2: CR.cr2 = (value ? CR.cr2 | bit : CR.cr2 & ~bit); break; - case 3: CR.cr3 = (value ? CR.cr3 | bit : CR.cr3 & ~bit); break; - case 4: CR.cr4 = (value ? CR.cr4 | bit : CR.cr4 & ~bit); break; - case 5: CR.cr5 = (value ? CR.cr5 | bit : CR.cr5 & ~bit); break; - case 6: CR.cr6 = (value ? CR.cr6 | bit : CR.cr6 & ~bit); break; - case 7: CR.cr7 = (value ? CR.cr7 | bit : CR.cr7 & ~bit); break; - } + CR[field * 4 + 0] = le; + CR[field * 4 + 1] = gt; + CR[field * 4 + 2] = eq; + CR[field * 4 + 3] = so; } - void SetCR_EQ(const u8 n, const bool value) { SetCRBit(n, CR_EQ, value); } - void SetCR_GT(const u8 n, const bool value) { SetCRBit(n, CR_GT, value); } - void SetCR_LT(const u8 n, const bool value) { SetCRBit(n, CR_LT, value); } - void SetCR_SO(const u8 n, const bool value) { SetCRBit(n, CR_SO, value); } - - bool IsCR_EQ(const u8 n) const { return (GetCR(n) & CR_EQ) ? 1 : 0; } - bool IsCR_GT(const u8 n) const { return (GetCR(n) & CR_GT) ? 1 : 0; } - bool IsCR_LT(const u8 n) const { return (GetCR(n) & CR_LT) ? 1 : 0; } - - template void UpdateCRn(const u8 n, const T a, const T b) + // Set CR field for comparison + template + void SetCR(u32 field, const T& a, const T& b) { - if (a < b) SetCR(n, CR_LT); - else if (a > b) SetCR(n, CR_GT); - else if (a == b) SetCR(n, CR_EQ); - - SetCR_SO(n, XER.SO); + SetCR(field, a < b, a > b, a == b, SO); } - void UpdateCRnU(const u8 l, const u8 n, const u64 a, const u64 b) - { - if(l) - { - UpdateCRn(n, a, b); - } - else - { - UpdateCRn(n, (u32)a, (u32)b); - } - } - - void UpdateCRnS(const u8 l, const u8 n, const u64 a, const u64 b) - { - if(l) - { - UpdateCRn(n, (s64)a, (s64)b); - } - else - { - UpdateCRn(n, (s32)a, (s32)b); - } - } - - template void UpdateCR0(const T val) - { - UpdateCRn(0, val, 0); - } - - void UpdateCR1() - { - SetCR_LT(1, FPSCR.FX); - SetCR_GT(1, FPSCR.FEX); - SetCR_EQ(1, FPSCR.VX); - SetCR_SO(1, FPSCR.OX); - } - - const u8 GetCRBit(const u32 bit) const { return 1 << (3 - (bit % 4)); } - - void SetCRBit (const u32 bit, bool set) { SetCRBit(bit >> 2, GetCRBit(bit), set); } - void SetCRBit2(const u32 bit, bool set) { SetCRBit(bit >> 2, 0x8 >> (bit & 3), set); } - - const u8 IsCR(const u32 bit) const { return (GetCR(bit >> 2) & GetCRBit(bit)) ? 1 : 0; } - - bool IsCarry(const u64 a, const u64 b) { return (a + b) < a; } - bool IsCarry(const u64 a, const u64 b, const u64 c) { return IsCarry(a, b) || IsCarry(a + b, c); } - + // Set overflow bit void SetOV(const bool set) { - XER.OV = set; - XER.SO |= set; + OV = set; + SO |= set; } - void UpdateFPSCR_FEX() + u64 get_next_arg(u32& g_count) { - const u32 exceptions = (FPSCR.FPSCR >> 25) & 0x1F; - const u32 enabled = (FPSCR.FPSCR >> 3) & 0x1F; - if (exceptions & enabled) FPSCR.FEX = 1; - } - - void UpdateFPSCR_VX() - { - if (FPSCR.FPSCR & FPSCR_VX_ALL) FPSCR.VX = 1; - } - - void SetFPSCR(const u32 val) - { - FPSCR.FPSCR = val & ~(FPSCR_FEX | FPSCR_VX); - UpdateFPSCR_VX(); - UpdateFPSCR_FEX(); - } - - void SetFPSCRException(const FPSCR_EXP mask) - { - if ((FPSCR.FPSCR & mask) != mask) FPSCR.FX = 1; - FPSCR.FPSCR |= mask; - UpdateFPSCR_VX(); - UpdateFPSCR_FEX(); - } - - void SetFPSCR_FI(const u32 val) - { - if(val) SetFPSCRException(FPSCR_XX); - FPSCR.FI = val; - } - - virtual std::string RegsToString() const override - { - std::string ret = "Registers:\n=========\n"; - - for(uint i=0; i<32; ++i) ret += fmt::format("GPR[%d] = 0x%llx\n", i, GPR[i]); - for(uint i=0; i<32; ++i) ret += fmt::format("FPR[%d] = %.6G\n", i, (double)FPR[i]); - for(uint i=0; i<32; ++i) ret += fmt::format("VPR[%d] = 0x%s [%s]\n", i, VPR[i].to_hex().c_str(), VPR[i].to_xyzw().c_str()); - ret += fmt::format("CR = 0x%08x\n", CR.CR); - ret += fmt::format("LR = 0x%llx\n", LR); - ret += fmt::format("CTR = 0x%llx\n", CTR); - ret += fmt::format("XER = 0x%llx [CA=%lld | OV=%lld | SO=%lld]\n", XER.XER, u32{ XER.CA }, u32{ XER.OV }, u32{ XER.SO }); - ret += fmt::format("FPSCR = 0x%x " - "[RN=%d | NI=%d | XE=%d | ZE=%d | UE=%d | OE=%d | VE=%d | " - "VXCVI=%d | VXSQRT=%d | VXSOFT=%d | FPRF=%d | " - "FI=%d | FR=%d | VXVC=%d | VXIMZ=%d | " - "VXZDZ=%d | VXIDI=%d | VXISI=%d | VXSNAN=%d | " - "XX=%d | ZX=%d | UX=%d | OX=%d | VX=%d | FEX=%d | FX=%d]\n", - FPSCR.FPSCR, - u32{ FPSCR.RN }, - u32{ FPSCR.NI }, u32{ FPSCR.XE }, u32{ FPSCR.ZE }, u32{ FPSCR.UE }, u32{ FPSCR.OE }, u32{ FPSCR.VE }, - u32{ FPSCR.VXCVI }, u32{ FPSCR.VXSQRT }, u32{ FPSCR.VXSOFT }, u32{ FPSCR.FPRF }, - u32{ FPSCR.FI }, u32{ FPSCR.FR }, u32{ FPSCR.VXVC }, u32{ FPSCR.VXIMZ }, - u32{ FPSCR.VXZDZ }, u32{ FPSCR.VXIDI }, u32{ FPSCR.VXISI }, u32{ FPSCR.VXSNAN }, - u32{ FPSCR.XX }, u32{ FPSCR.ZX }, u32{ FPSCR.UX }, u32{ FPSCR.OX }, u32{ FPSCR.VX }, u32{ FPSCR.FEX }, u32{ FPSCR.FX }); - - return ret; - } - - virtual std::string ReadRegString(const std::string& reg) const override - { - std::string::size_type first_brk = reg.find('['); - if (first_brk != std::string::npos) - { - long reg_index = atol(reg.substr(first_brk+1,reg.length()-first_brk-2).c_str()); - if (reg.find("GPR")==0) return fmt::format("%016llx", GPR[reg_index]); - if (reg.find("FPR")==0) return fmt::format("%016llx", (double)FPR[reg_index]); - if (reg.find("VPR")==0) return fmt::format("%016llx%016llx", VPR[reg_index]._u64[1], VPR[reg_index]._u64[0]); - } - if (reg == "CR") return fmt::format("%08x", CR.CR); - if (reg == "LR") return fmt::format("%016llx", LR); - if (reg == "CTR") return fmt::format("%016llx", CTR); - if (reg == "XER") return fmt::format("%016llx", XER.XER); - if (reg == "FPSCR") return fmt::format("%08x", FPSCR.FPSCR); - - return ""; - } - - bool WriteRegString(const std::string& reg, std::string value) override - { - while (value.length() < 32) value = "0"+value; - std::string::size_type first_brk = reg.find('['); - try - { - if (first_brk != std::string::npos) - { - long reg_index = atol(reg.substr(first_brk + 1, reg.length() - first_brk - 2).c_str()); - if (reg.find("GPR")==0 || reg.find("FPR")==0 ) - { - unsigned long long reg_value; - reg_value = std::stoull(value.substr(16, 31),0,16); - if (reg.find("GPR")==0) GPR[reg_index] = (u64)reg_value; - if (reg.find("FPR")==0) FPR[reg_index] = (u64)reg_value; - return true; - } - if (reg.find("VPR")==0) - { - unsigned long long reg_value0; - unsigned long long reg_value1; - reg_value0 = std::stoull(value.substr(16, 31), 0, 16); - reg_value1 = std::stoull(value.substr(0, 15), 0, 16); - VPR[reg_index]._u64[0] = (u64)reg_value0; - VPR[reg_index]._u64[1] = (u64)reg_value1; - return true; - } - } - if (reg == "LR" || reg == "CTR" || reg == "XER") - { - unsigned long long reg_value; - reg_value = std::stoull(value.substr(16, 31), 0, 16); - if (reg == "LR") LR = (u64)reg_value; - if (reg == "CTR") CTR = (u64)reg_value; - if (reg == "XER") XER.XER = (u64)reg_value; - return true; - } - if (reg == "CR" || reg == "FPSCR") - { - unsigned long long reg_value; - reg_value = std::stoull(value.substr(24, 31), 0, 16); - if (reg == "CR") CR.CR = (u32)reg_value; - if (reg == "FPSCR") FPSCR.FPSCR = (u32)reg_value; - return true; - } - } - catch (std::invalid_argument&)//if any of the stoull conversion fail - { - return false; - } - return false; - } - - u64 get_next_gpr_arg(u32& g_count, u32& f_count, u32& v_count) - { - assert(!f_count && !v_count); // not supported - if (g_count < 8) { return GPR[g_count++ + 3]; } else { - return get_stack_arg(++g_count); + return *get_stack_arg(++g_count); } } -public: - u64 get_stack_arg(s32 i); + be_t* get_stack_arg(s32 i, u64 align = alignof(u64)); void fast_call(u32 addr, u32 rtoc); - void fast_stop(); }; -class ppu_thread : cpu_thread +template +struct ppu_gpr_cast_impl { - static const u32 stack_align = 0x10; - vm::_ptr_base> argv; - u32 argc; - vm::_ptr_base> envp; - -public: - ppu_thread(u32 entry, const std::string& name = "", u32 stack_size = 0, s32 prio = 0); - - cpu_thread& args(std::initializer_list values) override; - cpu_thread& run() override; - ppu_thread& gpr(uint index, u64 value); + static_assert(!sizeof(T), "Invalid type for ppu_gpr_cast<>"); }; -template::value> -struct cast_ppu_gpr +template +struct ppu_gpr_cast_impl::value || std::is_enum::value>> { - static_assert(is_enum, "Invalid type for cast_ppu_gpr"); + static_assert(sizeof(T) <= 8, "Too big integral type for ppu_gpr_cast<>()"); + static_assert(std::is_same::value == false, "bool type is deprecated in ppu_gpr_cast<>(), use b8 instead"); - force_inline static u64 to_gpr(const T& value) + static inline u64 to(const T& value) { - return cast_ppu_gpr>::to_gpr(static_cast>(value)); + return static_cast(value); } - force_inline static T from_gpr(const u64 reg) + static inline T from(const u64 reg) { - return static_cast(cast_ppu_gpr>::from_gpr(reg)); + return static_cast(reg); } }; template<> -struct cast_ppu_gpr +struct ppu_gpr_cast_impl { - force_inline static u64 to_gpr(const u8& value) + static inline u64 to(const b8& value) { return value; } - force_inline static u8 from_gpr(const u64 reg) - { - return static_cast(reg); - } -}; - -template<> -struct cast_ppu_gpr -{ - force_inline static u64 to_gpr(const u16& value) - { - return value; - } - - force_inline static u16 from_gpr(const u64 reg) - { - return static_cast(reg); - } -}; - -template<> -struct cast_ppu_gpr -{ - force_inline static u64 to_gpr(const u32& value) - { - return value; - } - - force_inline static u32 from_gpr(const u64 reg) - { - return static_cast(reg); - } -}; - -#ifdef __APPLE__ -template<> -struct cast_ppu_gpr -{ - force_inline static u64 to_gpr(const unsigned long& value) - { - return value; - } - - force_inline static unsigned long from_gpr(const u64 reg) - { - return static_cast(reg); - } -}; -#endif - -template<> -struct cast_ppu_gpr -{ - force_inline static u64 to_gpr(const u64& value) - { - return value; - } - - force_inline static u64 from_gpr(const u64 reg) - { - return reg; - } -}; - -template<> -struct cast_ppu_gpr -{ - force_inline static u64 to_gpr(const s8& value) - { - return value; - } - - force_inline static s8 from_gpr(const u64 reg) - { - return static_cast(reg); - } -}; - -template<> -struct cast_ppu_gpr -{ - force_inline static u64 to_gpr(const s16& value) - { - return value; - } - - force_inline static s16 from_gpr(const u64 reg) - { - return static_cast(reg); - } -}; - -template<> -struct cast_ppu_gpr -{ - force_inline static u64 to_gpr(const s32& value) - { - return value; - } - - force_inline static s32 from_gpr(const u64 reg) - { - return static_cast(reg); - } -}; - -template<> -struct cast_ppu_gpr -{ - force_inline static u64 to_gpr(const s64& value) - { - return value; - } - - force_inline static s64 from_gpr(const u64 reg) - { - return static_cast(reg); - } -}; - -template<> -struct cast_ppu_gpr -{ - force_inline static u64 to_gpr(const b8& value) - { - return value; - } - - force_inline static b8 from_gpr(const u64& reg) + static inline b8 from(const u64 reg) { return static_cast(reg) != 0; } }; -template -force_inline u64 cast_to_ppu_gpr(const T& value) +template +struct ppu_gpr_cast_impl, void> { - return cast_ppu_gpr::to_gpr(value); -} + static inline u64 to(const vm::_ptr_base& value) + { + return ppu_gpr_cast_impl::to(value.addr()); + } -template -force_inline T cast_from_ppu_gpr(const u64 reg) -{ - return cast_ppu_gpr::from_gpr(reg); -} - -// flags set in ModuleFunc -enum : u32 -{ - MFF_FORCED_HLE = (1 << 0), // always call HLE function - MFF_NO_RETURN = (1 << 1), // uses EIF_USE_BRANCH flag with LLE, ignored with MFF_FORCED_HLE - - MFF_PERFECT = /* 0 */ MFF_FORCED_HLE, // can be set for fully implemented functions with LLE compatibility + static inline vm::_ptr_base from(const u64 reg) + { + return{ ppu_gpr_cast_impl::from(reg), vm::addr }; + } }; -// flags passed with index -enum : u32 +template +struct ppu_gpr_cast_impl, void> { - EIF_SAVE_RTOC = (1 << 25), // save RTOC in [SP+0x28] before calling HLE/LLE function - EIF_PERFORM_BLR = (1 << 24), // do BLR after calling HLE/LLE function - EIF_USE_BRANCH = (1 << 23), // do only branch, LLE must be set, last_syscall must be zero + static inline u64 to(const vm::_ref_base& value) + { + return ppu_gpr_cast_impl::to(value.addr()); + } - EIF_FLAGS = 0x3800000, // all flags + static inline vm::_ref_base from(const u64 reg) + { + return{ ppu_gpr_cast_impl::from(reg), vm::addr }; + } }; + +template +inline To ppu_gpr_cast(const From& value) +{ + return ppu_gpr_cast_impl::from(ppu_gpr_cast_impl::to(value)); +} diff --git a/rpcs3/Emu/Cell/RawSPUThread.cpp b/rpcs3/Emu/Cell/RawSPUThread.cpp index f0c9c06f6a..facaa0fa3e 100644 --- a/rpcs3/Emu/Cell/RawSPUThread.cpp +++ b/rpcs3/Emu/Cell/RawSPUThread.cpp @@ -1,17 +1,27 @@ #include "stdafx.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/SysCalls/Callback.h" +#include "Emu/IdManager.h" +#include "Loader/ELF.h" #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, index, RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index) +void RawSPUThread::cpu_task() { - CHECK_ASSERTION(vm::falloc(offset, 0x40000) == offset); + // get next PC and SPU Interrupt status + pc = npc.exchange(0); + + set_interrupt_status((pc & 1) != 0); + + pc &= 0x3fffc; + + SPUThread::cpu_task(); + + // save next PC and current SPU Interrupt status + npc = pc | ((ch_event_stat & SPU_EVENT_INTR_ENABLED) != 0); } bool RawSPUThread::read_reg(const u32 addr, u32& value) @@ -81,7 +91,8 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value) } })) { - exec(); + state -= cpu_state::stop; + safe_notify(); } }; @@ -182,7 +193,7 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value) else if (value == SPU_RUNCNTL_STOP_REQUEST) { status &= ~SPU_STATUS_RUNNING; - stop(); + state += cpu_state::stop; } else { @@ -221,17 +232,19 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value) return false; } -void RawSPUThread::cpu_task() +template<> +void spu_exec_loader::load() const { - // get next PC and SPU Interrupt status - pc = npc.exchange(0); + auto spu = idm::make_ptr("TEST_SPU"); - set_interrupt_status((pc & 1) != 0); + for (const auto& prog : progs) + { + if (prog.p_type == 0x1 /* LOAD */ && prog.p_memsz) + { + std::memcpy(vm::base(spu->offset + prog.p_vaddr), prog.bin.data(), prog.p_filesz); + } + } - pc &= 0x3fffc; - - SPUThread::cpu_task(); - - // save next PC and current SPU Interrupt status - npc = pc | ((ch_event_stat & SPU_EVENT_INTR_ENABLED) != 0); + spu->cpu_init(); + spu->npc = header.e_entry; } diff --git a/rpcs3/Emu/Cell/RawSPUThread.h b/rpcs3/Emu/Cell/RawSPUThread.h index 32cf470052..c3a27aa46f 100644 --- a/rpcs3/Emu/Cell/RawSPUThread.h +++ b/rpcs3/Emu/Cell/RawSPUThread.h @@ -2,27 +2,36 @@ #include "SPUThread.h" -enum : u32 -{ - RAW_SPU_OFFSET = 0x00100000, - RAW_SPU_BASE_ADDR = 0xE0000000, - RAW_SPU_LS_OFFSET = 0x00000000, - RAW_SPU_PROB_OFFSET = 0x00040000, -}; - -force_inline static u32 GetRawSPURegAddrByNum(int num, int offset) -{ - return RAW_SPU_OFFSET * num + RAW_SPU_BASE_ADDR + RAW_SPU_PROB_OFFSET + offset; -} - class RawSPUThread final : public SPUThread { + void cpu_task() override; + public: - RawSPUThread(const std::string& name, u32 index); + /* IdManager setups */ + + using id_base = RawSPUThread; + + static constexpr u32 id_min = 0; + static constexpr u32 id_max = 4; + + void on_init() override + { + if (!offset) + { + // Install correct SPU index and LS address + const_cast(index) = id; + const_cast(offset) = vm::falloc(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index, 0x40000); + ASSERT(offset); + + SPUThread::on_init(); + } + } + + RawSPUThread(const std::string& name) + : SPUThread(name) + { + } bool read_reg(const u32 addr, u32& value); bool write_reg(const u32 addr, const u32 value); - -private: - virtual void cpu_task() override; }; diff --git a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp index 1f5f43f9c4..a20f92c4b0 100644 --- a/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp @@ -1,4 +1,5 @@ #include "stdafx.h" +#include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "SPUDisAsm.h" @@ -9,10 +10,6 @@ #define ASMJIT_STATIC #define ASMJIT_DEBUG -#ifdef _MSC_VER -#pragma comment(lib, "asmjit.lib") -#endif - #include "asmjit.h" #define SPU_OFF_128(x) asmjit::host::oword_ptr(*cpu, OFFSET_32(SPUThread, x)) @@ -21,6 +18,9 @@ #define SPU_OFF_16(x) asmjit::host::word_ptr(*cpu, OFFSET_32(SPUThread, x)) #define SPU_OFF_8(x) asmjit::host::byte_ptr(*cpu, OFFSET_32(SPUThread, x)) +const spu_decoder s_spu_interpreter; // TODO: remove +const spu_decoder s_spu_decoder; + spu_recompiler::spu_recompiler() : m_jit(std::make_shared()) { @@ -29,7 +29,7 @@ spu_recompiler::spu_recompiler() LOG_SUCCESS(SPU, "SPU Recompiler (ASMJIT) created..."); - fs::file(fs::get_config_dir() + "SPUJIT.log", fom::rewrite).write(fmt::format("SPU JIT initialization...\n\nTitle: %s\nTitle ID: %s\n\n", Emu.GetTitle().c_str(), Emu.GetTitleID().c_str())); + fs::file(fs::get_config_dir() + "SPUJIT.log", fs::rewrite).write(fmt::format("SPU JIT initialization...\n\nTitle: %s\nTitle ID: %s\n\n", Emu.GetTitle().c_str(), Emu.GetTitleID().c_str())); } void spu_recompiler::compile(spu_function_t& f) @@ -145,13 +145,13 @@ void spu_recompiler::compile(spu_function_t& f) // Disasm dis_asm.dump_pc = m_pos; - dis_asm.do_disasm(op); + dis_asm.disasm(m_pos); compiler.addComment(dis_asm.last_opcode.c_str()); log += dis_asm.last_opcode.c_str(); log += '\n'; // Recompiler function - (this->*spu_recompiler::opcodes[op])({ op }); + (this->*s_spu_decoder.decode(op))({ op }); // Collect allocated xmm vars for (u32 i = 0; i < vec_vars.size(); i++) @@ -214,7 +214,7 @@ void spu_recompiler::compile(spu_function_t& f) log += "\n\n\n"; // Append log file - fs::file(fs::get_config_dir() + "SPUJIT.log", fom::write | fom::append).write(log); + fs::file(fs::get_config_dir() + "SPUJIT.log", fs::write + fs::append).write(log); } spu_recompiler::XmmLink spu_recompiler::XmmAlloc() // get empty xmm register @@ -267,7 +267,7 @@ void spu_recompiler::InterpreterCall(spu_opcode_t op) const u32 old_pc = _spu->pc; - if (_spu->m_state && _spu->check_status()) + if (_spu->state.load() && _spu->check_status()) { return 0x2000000 | _spu->pc; } @@ -294,7 +294,7 @@ void spu_recompiler::InterpreterCall(spu_opcode_t op) asmjit::X86CallNode* call = c->call(asmjit::imm_ptr(asmjit_cast(gate)), asmjit::kFuncConvHost, asmjit::FuncBuilder3()); call->setArg(0, *cpu); call->setArg(1, asmjit::imm_u(op.opcode)); - call->setArg(2, asmjit::imm_ptr(asmjit_cast(spu_interpreter::fast::g_spu_opcode_table[op.opcode]))); + call->setArg(2, asmjit::imm_ptr(asmjit_cast(s_spu_interpreter.decode(op.opcode)))); call->setRet(0, *addr); // return immediately if an error occured @@ -338,21 +338,20 @@ void spu_recompiler::FunctionCall() LOG_ERROR(SPU, "Branch-to-self"); } - while (!_spu->m_state || !_spu->check_status()) + while (!_spu->state.load() || !_spu->check_status()) { - // Call override function directly since the type is known - static_cast(*_spu->m_dec).DecodeMemory(_spu->offset + _spu->pc); + // Proceed recursively + spu_recompiler_base::enter(*_spu); - if (_spu->m_state & CPU_STATE_RETURN) + if (_spu->state & cpu_state::ret) { break; } if (_spu->pc == link) { - // returned successfully _spu->recursion_level--; - return 0; + return 0; // Successfully returned } } @@ -2185,7 +2184,7 @@ void spu_recompiler::BR(spu_opcode_t op) c->mov(*addr, target | 0x2000000); //c->cmp(asmjit::host::dword_ptr(*ls, m_pos), 0x32); // compare instruction opcode with BR-to-self //c->je(labels[target / 4]); - c->lock().or_(SPU_OFF_64(m_state), CPU_STATE_RETURN | CPU_STATE_STOPPED); + c->lock().or_(SPU_OFF_32(state), (to_mset(cpu_state::stop) + cpu_state::ret)._value()); c->jmp(*end); c->unuse(*addr); return; @@ -2614,7 +2613,6 @@ void spu_recompiler::FMS(spu_opcode_t op) void spu_recompiler::UNK(spu_opcode_t op) { - throw EXCEPTION("Unknown/Illegal opcode (0x%08x)", op.opcode); + LOG_ERROR(SPU, "0x%05x: Unknown/Illegal opcode (0x%08x)", m_pos, op.opcode); + c->int3(); } - -const spu_opcode_table_t spu_recompiler::opcodes{ DEFINE_SPU_OPCODES(&spu_recompiler::), &spu_recompiler::UNK }; diff --git a/rpcs3/Emu/Cell/SPUASMJITRecompiler.h b/rpcs3/Emu/Cell/SPUASMJITRecompiler.h index 9655b19ce9..2055a778ca 100644 --- a/rpcs3/Emu/Cell/SPUASMJITRecompiler.h +++ b/rpcs3/Emu/Cell/SPUASMJITRecompiler.h @@ -13,7 +13,7 @@ namespace asmjit } // SPU ASMJIT Recompiler -class spu_recompiler : public SPURecompilerBase +class spu_recompiler : public spu_recompiler_base { const std::shared_ptr m_jit; @@ -75,7 +75,7 @@ private: asmjit::X86Mem XmmConst(__m128 data); asmjit::X86Mem XmmConst(__m128i data); -private: +public: void InterpreterCall(spu_opcode_t op); void FunctionCall(); @@ -280,6 +280,4 @@ private: void FMS(spu_opcode_t op); void UNK(spu_opcode_t op); - - static const spu_opcode_table_t opcodes; }; diff --git a/rpcs3/Emu/Cell/SPUAnalyser.cpp b/rpcs3/Emu/Cell/SPUAnalyser.cpp index d8e063c7b2..57cc2d4b14 100644 --- a/rpcs3/Emu/Cell/SPUAnalyser.cpp +++ b/rpcs3/Emu/Cell/SPUAnalyser.cpp @@ -4,7 +4,7 @@ #include "SPURecompiler.h" #include "SPUAnalyser.h" -const spu_opcode_table_t g_spu_itype{ DEFINE_SPU_OPCODES(spu_itype::), spu_itype::UNK }; +const spu_decoder s_spu_itype; std::shared_ptr SPUDatabase::find(const be_t* data, u64 key, u32 max_size) { @@ -83,7 +83,7 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en { const spu_opcode_t op{ ls[pos / 4] }; - const spu_itype_t type = g_spu_itype[op.opcode]; + const auto type = s_spu_itype.decode(op.opcode); using namespace spu_itype; @@ -172,15 +172,15 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en break; } - if (type == BI || type == IRET) // Branch Indirect + if (type == &type::BI || type == &type::IRET) // Branch Indirect { - if (type == IRET) LOG_ERROR(SPU, "[0x%05x] Interrupt Return", pos); + if (type == &type::IRET) LOG_ERROR(SPU, "[0x%05x] Interrupt Return", pos); blocks.emplace(start); start = pos + 4; } - else if (type == BR || type == BRA) // Branch Relative/Absolute + else if (type == &type::BR || type == &type::BRA) // Branch Relative/Absolute { - const u32 target = spu_branch_target(type == BR ? pos : 0, op.i16); + const u32 target = spu_branch_target(type == &type::BR ? pos : 0, op.i16); // Add adjacent function because it always could be adjacent.emplace(target); @@ -192,9 +192,9 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en blocks.emplace(start); start = pos + 4; } - else if (type == BRSL || type == BRASL) // Branch Relative/Absolute and Set Link + else if (type == &type::BRSL || type == &type::BRASL) // Branch Relative/Absolute and Set Link { - const u32 target = spu_branch_target(type == BRSL ? pos : 0, op.i16); + const u32 target = spu_branch_target(type == &type::BRSL ? pos : 0, op.i16); if (target == pos + 4) { @@ -215,11 +215,11 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en if (op.rt != 0) LOG_ERROR(SPU, "[0x%05x] Function call without $LR", pos); } } - else if (type == BISL || type == BISLED) // Branch Indirect and Set Link + else if (type == &type::BISL || type == &type::BISLED) // Branch Indirect and Set Link { if (op.rt != 0) LOG_ERROR(SPU, "[0x%05x] Indirect function call without $LR", pos); } - else if (type == BRNZ || type == BRZ || type == BRHNZ || type == BRHZ) // Branch Relative if (Not) Zero (Half)word + else if (type == &type::BRNZ || type == &type::BRZ || type == &type::BRHNZ || type == &type::BRHZ) // Branch Relative if (Not) Zero (Half)word { const u32 target = spu_branch_target(pos, op.i16); @@ -231,24 +231,24 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en blocks.emplace(target); } } - else if (type == BINZ || type == BIZ || type == BIHNZ || type == BIHZ) // Branch Indirect if (Not) Zero (Half)word + else if (type == &type::BINZ || type == &type::BIZ || type == &type::BIHNZ || type == &type::BIHZ) // Branch Indirect if (Not) Zero (Half)word { } - else if (type == HBR || type == HBRA || type == HBRR) // Hint for Branch + else if (type == &type::HBR || type == &type::HBRA || type == &type::HBRR) // Hint for Branch { } - else if (type == STQA || type == STQD || type == STQR || type == STQX || type == FSCRWR || type == MTSPR || type == WRCH) // Store + else if (type == &type::STQA || type == &type::STQD || type == &type::STQR || type == &type::STQX || type == &type::FSCRWR || type == &type::MTSPR || type == &type::WRCH) // Store { } - else if (type == HEQ || type == HEQI || type == HGT || type == HGTI || type == HLGT || type == HLGTI) // Halt + else if (type == &type::HEQ || type == &type::HEQI || type == &type::HGT || type == &type::HGTI || type == &type::HLGT || type == &type::HLGTI) // Halt { } - else if (type == STOP || type == STOPD || type == NOP || type == LNOP || type == SYNC || type == DSYNC) // Miscellaneous + else if (type == &type::STOP || type == &type::STOPD || type == &type::NOP || type == &type::LNOP || type == &type::SYNC || type == &type::DSYNC) // Miscellaneous { } else // Other instructions (writing rt reg) { - const u32 rt = type == SELB || type == SHUFB || type == MPYA || type == FNMS || type == FMA || type == FMS ? +op.rc : +op.rt; + const u32 rt = type == &type::SELB || type == &type::SHUFB || type == &type::MPYA || type == &type::FNMS || type == &type::FMA || type == &type::FMS ? +op.rc : +op.rt; // Analyse link register access if (rt == 0) @@ -258,7 +258,7 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en // Analyse stack pointer access if (rt == 1) { - if (type == ILA && pos < ila_sp_pos) + if (type == &type::ILA && pos < ila_sp_pos) { // set minimal ila $SP,* instruction position ila_sp_pos = pos; @@ -272,7 +272,7 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en { const spu_opcode_t op{ ls[pos / 4] }; - const spu_itype_t type = g_spu_itype[op.opcode]; + const auto type = s_spu_itype.decode(op.opcode); using namespace spu_itype; @@ -280,9 +280,9 @@ std::shared_ptr SPUDatabase::analyse(const be_t* ls, u32 en { break; } - else if (type == BRSL || type == BRASL) // Branch Relative/Absolute and Set Link + else if (type == &type::BRSL || type == &type::BRASL) // Branch Relative/Absolute and Set Link { - const u32 target = spu_branch_target(type == BRSL ? pos : 0, op.i16); + const u32 target = spu_branch_target(type == &type::BRSL ? pos : 0, op.i16); if (target != pos + 4 && target > entry && limit > target) { diff --git a/rpcs3/Emu/Cell/SPUAnalyser.h b/rpcs3/Emu/Cell/SPUAnalyser.h index c03429f134..1588d31c8a 100644 --- a/rpcs3/Emu/Cell/SPUAnalyser.h +++ b/rpcs3/Emu/Cell/SPUAnalyser.h @@ -3,250 +3,246 @@ #include "Emu/Cell/SPUOpcodes.h" #include "Utilities/SharedMutex.h" +#include + class SPUThread; // Type of the runtime functions generated by SPU recompiler using spu_jit_func_t = u32(*)(SPUThread* _spu, be_t* _ls); -// SPU instruction classification namespace +// SPU Instruction Classifier namespace spu_itype { - enum spu_itype_t : u32 + struct type { - UNK = 0, - - STOP, - LNOP, - SYNC, - DSYNC, - MFSPR, - RDCH, - RCHCNT, - SF, - OR, - BG, - SFH, - NOR, - ABSDB, - ROT, - ROTM, - ROTMA, - SHL, - ROTH, - ROTHM, - ROTMAH, - SHLH, - ROTI, - ROTMI, - ROTMAI, - SHLI, - ROTHI, - ROTHMI, - ROTMAHI, - SHLHI, - A, - AND, - CG, - AH, - NAND, - AVGB, - MTSPR, - WRCH, - BIZ, - BINZ, - BIHZ, - BIHNZ, - STOPD, - STQX, - BI, - BISL, - IRET, - BISLED, - HBR, - GB, - GBH, - GBB, - FSM, - FSMH, - FSMB, - FREST, - FRSQEST, - LQX, - ROTQBYBI, - ROTQMBYBI, - SHLQBYBI, - CBX, - CHX, - CWX, - CDX, - ROTQBI, - ROTQMBI, - SHLQBI, - ROTQBY, - ROTQMBY, - SHLQBY, - ORX, - CBD, - CHD, - CWD, - CDD, - ROTQBII, - ROTQMBII, - SHLQBII, - ROTQBYI, - ROTQMBYI, - SHLQBYI, - NOP, - CGT, - XOR, - CGTH, - EQV, - CGTB, - SUMB, - HGT, - CLZ, - XSWD, - XSHW, - CNTB, - XSBH, - CLGT, - ANDC, - FCGT, - DFCGT, - FA, - FS, - FM, - CLGTH, - ORC, - FCMGT, - DFCMGT, - DFA, - DFS, - DFM, - CLGTB, - HLGT, - DFMA, - DFMS, - DFNMS, - DFNMA, - CEQ, - MPYHHU, - ADDX, - SFX, - CGX, - BGX, - MPYHHA, - MPYHHAU, - FSCRRD, - FESD, - FRDS, - FSCRWR, - DFTSV, - FCEQ, - DFCEQ, - MPY, - MPYH, - MPYHH, - MPYS, - CEQH, - FCMEQ, - DFCMEQ, - MPYU, - CEQB, - FI, - HEQ, - CFLTS, - CFLTU, - CSFLT, - CUFLT, - BRZ, - STQA, - BRNZ, - BRHZ, - BRHNZ, - STQR, - BRA, - LQA, - BRASL, - BR, - FSMBI, - BRSL, - LQR, - IL, - ILHU, - ILH, - IOHL, - ORI, - ORHI, - ORBI, - SFI, - SFHI, - ANDI, - ANDHI, - ANDBI, - AI, - AHI, - STQD, - LQD, - XORI, - XORHI, - XORBI, - CGTI, - CGTHI, - CGTBI, - HGTI, - CLGTI, - CLGTHI, - CLGTBI, - HLGTI, - MPYI, - MPYUI, - CEQI, - CEQHI, - CEQBI, - HEQI, - HBRA, - HBRR, - ILA, - SELB, - SHUFB, - MPYA, - FNMS, - FMA, - FMS, + u32 UNK; + u32 STOP; + u32 LNOP; + u32 SYNC; + u32 DSYNC; + u32 MFSPR; + u32 RDCH; + u32 RCHCNT; + u32 SF; + u32 OR; + u32 BG; + u32 SFH; + u32 NOR; + u32 ABSDB; + u32 ROT; + u32 ROTM; + u32 ROTMA; + u32 SHL; + u32 ROTH; + u32 ROTHM; + u32 ROTMAH; + u32 SHLH; + u32 ROTI; + u32 ROTMI; + u32 ROTMAI; + u32 SHLI; + u32 ROTHI; + u32 ROTHMI; + u32 ROTMAHI; + u32 SHLHI; + u32 A; + u32 AND; + u32 CG; + u32 AH; + u32 NAND; + u32 AVGB; + u32 MTSPR; + u32 WRCH; + u32 BIZ; + u32 BINZ; + u32 BIHZ; + u32 BIHNZ; + u32 STOPD; + u32 STQX; + u32 BI; + u32 BISL; + u32 IRET; + u32 BISLED; + u32 HBR; + u32 GB; + u32 GBH; + u32 GBB; + u32 FSM; + u32 FSMH; + u32 FSMB; + u32 FREST; + u32 FRSQEST; + u32 LQX; + u32 ROTQBYBI; + u32 ROTQMBYBI; + u32 SHLQBYBI; + u32 CBX; + u32 CHX; + u32 CWX; + u32 CDX; + u32 ROTQBI; + u32 ROTQMBI; + u32 SHLQBI; + u32 ROTQBY; + u32 ROTQMBY; + u32 SHLQBY; + u32 ORX; + u32 CBD; + u32 CHD; + u32 CWD; + u32 CDD; + u32 ROTQBII; + u32 ROTQMBII; + u32 SHLQBII; + u32 ROTQBYI; + u32 ROTQMBYI; + u32 SHLQBYI; + u32 NOP; + u32 CGT; + u32 XOR; + u32 CGTH; + u32 EQV; + u32 CGTB; + u32 SUMB; + u32 HGT; + u32 CLZ; + u32 XSWD; + u32 XSHW; + u32 CNTB; + u32 XSBH; + u32 CLGT; + u32 ANDC; + u32 FCGT; + u32 DFCGT; + u32 FA; + u32 FS; + u32 FM; + u32 CLGTH; + u32 ORC; + u32 FCMGT; + u32 DFCMGT; + u32 DFA; + u32 DFS; + u32 DFM; + u32 CLGTB; + u32 HLGT; + u32 DFMA; + u32 DFMS; + u32 DFNMS; + u32 DFNMA; + u32 CEQ; + u32 MPYHHU; + u32 ADDX; + u32 SFX; + u32 CGX; + u32 BGX; + u32 MPYHHA; + u32 MPYHHAU; + u32 FSCRRD; + u32 FESD; + u32 FRDS; + u32 FSCRWR; + u32 DFTSV; + u32 FCEQ; + u32 DFCEQ; + u32 MPY; + u32 MPYH; + u32 MPYHH; + u32 MPYS; + u32 CEQH; + u32 FCMEQ; + u32 DFCMEQ; + u32 MPYU; + u32 CEQB; + u32 FI; + u32 HEQ; + u32 CFLTS; + u32 CFLTU; + u32 CSFLT; + u32 CUFLT; + u32 BRZ; + u32 STQA; + u32 BRNZ; + u32 BRHZ; + u32 BRHNZ; + u32 STQR; + u32 BRA; + u32 LQA; + u32 BRASL; + u32 BR; + u32 FSMBI; + u32 BRSL; + u32 LQR; + u32 IL; + u32 ILHU; + u32 ILH; + u32 IOHL; + u32 ORI; + u32 ORHI; + u32 ORBI; + u32 SFI; + u32 SFHI; + u32 ANDI; + u32 ANDHI; + u32 ANDBI; + u32 AI; + u32 AHI; + u32 STQD; + u32 LQD; + u32 XORI; + u32 XORHI; + u32 XORBI; + u32 CGTI; + u32 CGTHI; + u32 CGTBI; + u32 HGTI; + u32 CLGTI; + u32 CLGTHI; + u32 CLGTBI; + u32 HLGTI; + u32 MPYI; + u32 MPYUI; + u32 CEQI; + u32 CEQHI; + u32 CEQBI; + u32 HEQI; + u32 HBRA; + u32 HBRR; + u32 ILA; + u32 SELB; + u32 SHUFB; + u32 MPYA; + u32 FNMS; + u32 FMA; + u32 FMS; }; -} - -using spu_itype::spu_itype_t; - -// SPU Instruction Classification table -extern const spu_opcode_table_t g_spu_itype; +}; // SPU basic function information structure struct spu_function_t { - // entry point (LS address) + // Entry point (LS address) const u32 addr; - // function size (in bytes) + // Function size (in bytes) const u32 size; - // function contents (binary copy) + // Function contents (binary copy) std::vector> data; - // basic blocks (start addresses) + // Basic blocks (start addresses) std::set blocks; - // functions possibly called by this function (may not be available) + // Functions possibly called by this function (may not be available) std::set adjacent; - // jump table values (start addresses) + // Jump table values (start addresses) std::set jtable; - // whether ila $SP,* instruction found + // Whether ila $SP,* instruction found bool does_reset_stack; - // pointer to the compiled function + // Pointer to the compiled function spu_jit_func_t compiled = nullptr; spu_function_t(u32 addr, u32 size) diff --git a/rpcs3/Emu/Cell/SPUContext.h b/rpcs3/Emu/Cell/SPUContext.h deleted file mode 100644 index 9c408ffdd2..0000000000 --- a/rpcs3/Emu/Cell/SPUContext.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -struct spu_context_t -{ -}; diff --git a/rpcs3/Emu/Cell/SPUDisAsm.cpp b/rpcs3/Emu/Cell/SPUDisAsm.cpp new file mode 100644 index 0000000000..85b5eeb14e --- /dev/null +++ b/rpcs3/Emu/Cell/SPUDisAsm.cpp @@ -0,0 +1,11 @@ +#include "stdafx.h" +#include "SPUDisAsm.h" + +const spu_decoder s_spu_disasm; + +u32 SPUDisAsm::disasm(u32 pc) +{ + const u32 op = *(be_t*)(offset + pc); + (this->*(s_spu_disasm.decode(op)))({ op }); + return 4; +} diff --git a/rpcs3/Emu/Cell/SPUDisAsm.h b/rpcs3/Emu/Cell/SPUDisAsm.h index 0583d9fa04..69d10c4c8a 100644 --- a/rpcs3/Emu/Cell/SPUDisAsm.h +++ b/rpcs3/Emu/Cell/SPUDisAsm.h @@ -66,7 +66,7 @@ static const char* spu_ch_name[128] = "$ch121", "$ch122", "$ch123", "$ch124", "$ch125", "$ch126", "$ch127", }; -class SPUDisAsm : public PPCDisAsm +class SPUDisAsm final : public PPCDisAsm { public: SPUDisAsm(CPUDisAsmMode mode) : PPCDisAsm(mode) @@ -133,6 +133,10 @@ private: { Write(fmt::format("%s %s,%s,%s,%s", FixOp(op).c_str(), a1, a2, a3, a4)); } + +public: + u32 disasm(u32 pc) override; + //0 - 10 void STOP(spu_opcode_t op) { @@ -945,12 +949,4 @@ private: { Write(fmt::format("Unknown/Illegal opcode! (0x%08x)", op.opcode)); } - - static const spu_opcode_table_t opcodes; - -public: - void do_disasm(u32 opcode) - { - (this->*opcodes[opcode])({ opcode }); - } }; diff --git a/rpcs3/Emu/Cell/SPUInterpreter.cpp b/rpcs3/Emu/Cell/SPUInterpreter.cpp index 0c669c37ac..8af145cbe6 100644 --- a/rpcs3/Emu/Cell/SPUInterpreter.cpp +++ b/rpcs3/Emu/Cell/SPUInterpreter.cpp @@ -7,20 +7,7 @@ #include -namespace spu_interpreter -{ - namespace fast - { - const spu_opcode_table_t g_spu_opcode_table{ DEFINE_SPU_OPCODES(+), default_function }; - } - - namespace precise - { - const spu_opcode_table_t g_spu_opcode_table{ DEFINE_SPU_OPCODES(+), default_function }; - } -} - -void spu_interpreter::default_function(SPUThread& spu, spu_opcode_t op) +void spu_interpreter::UNK(SPUThread& spu, spu_opcode_t op) { throw EXCEPTION("Unknown/Illegal instruction (0x%08x)", op.opcode); } @@ -396,12 +383,12 @@ void spu_interpreter::FSMB(SPUThread& spu, spu_opcode_t op) spu.gpr[op.rt] = g_spu_imm.fsmb[spu.gpr[op.ra]._u32[3] & 0xffff]; } -void spu_interpreter::fast::FREST(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FREST(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].vf = _mm_rcp_ps(spu.gpr[op.ra].vf); } -void spu_interpreter::fast::FRSQEST(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FRSQEST(SPUThread& spu, spu_opcode_t op) { const auto mask = _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff)); spu.gpr[op.rt].vf = _mm_rsqrt_ps(_mm_and_ps(spu.gpr[op.ra].vf, mask)); @@ -687,7 +674,7 @@ void spu_interpreter::ANDC(SPUThread& spu, spu_opcode_t op) spu.gpr[op.rt] = v128::andnot(spu.gpr[op.rb], spu.gpr[op.ra]); } -void spu_interpreter::fast::FCGT(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FCGT(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].vf = _mm_cmplt_ps(spu.gpr[op.rb].vf, spu.gpr[op.ra].vf); } @@ -697,17 +684,17 @@ void spu_interpreter::DFCGT(SPUThread& spu, spu_opcode_t op) throw EXCEPTION("Unexpected instruction"); } -void spu_interpreter::fast::FA(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FA(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt] = v128::addfs(spu.gpr[op.ra], spu.gpr[op.rb]); } -void spu_interpreter::fast::FS(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FS(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt] = v128::subfs(spu.gpr[op.ra], spu.gpr[op.rb]); } -void spu_interpreter::fast::FM(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FM(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].vf = _mm_mul_ps(spu.gpr[op.ra].vf, spu.gpr[op.rb].vf); } @@ -722,7 +709,7 @@ void spu_interpreter::ORC(SPUThread& spu, spu_opcode_t op) spu.gpr[op.rt] = spu.gpr[op.ra] | ~spu.gpr[op.rb]; } -void spu_interpreter::fast::FCMGT(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FCMGT(SPUThread& spu, spu_opcode_t op) { const auto mask = _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff)); spu.gpr[op.rt].vf = _mm_cmplt_ps(_mm_and_ps(spu.gpr[op.rb].vf, mask), _mm_and_ps(spu.gpr[op.ra].vf, mask)); @@ -733,17 +720,17 @@ void spu_interpreter::DFCMGT(SPUThread& spu, spu_opcode_t op) throw EXCEPTION("Unexpected instruction"); } -void spu_interpreter::fast::DFA(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::DFA(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt] = v128::addfd(spu.gpr[op.ra], spu.gpr[op.rb]); } -void spu_interpreter::fast::DFS(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::DFS(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt] = v128::subfd(spu.gpr[op.ra], spu.gpr[op.rb]); } -void spu_interpreter::fast::DFM(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::DFM(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].vd = _mm_mul_pd(spu.gpr[op.ra].vd, spu.gpr[op.rb].vd); } @@ -761,22 +748,22 @@ void spu_interpreter::HLGT(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::fast::DFMA(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::DFMA(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].vd = _mm_add_pd(_mm_mul_pd(spu.gpr[op.ra].vd, spu.gpr[op.rb].vd), spu.gpr[op.rt].vd); } -void spu_interpreter::fast::DFMS(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::DFMS(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].vd = _mm_sub_pd(_mm_mul_pd(spu.gpr[op.ra].vd, spu.gpr[op.rb].vd), spu.gpr[op.rt].vd); } -void spu_interpreter::fast::DFNMS(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::DFNMS(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].vd = _mm_sub_pd(spu.gpr[op.rt].vd, _mm_mul_pd(spu.gpr[op.ra].vd, spu.gpr[op.rb].vd)); } -void spu_interpreter::fast::DFNMA(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::DFNMA(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].vd = _mm_sub_pd(_mm_set1_pd(0.0), _mm_add_pd(_mm_mul_pd(spu.gpr[op.ra].vd, spu.gpr[op.rb].vd), spu.gpr[op.rt].vd)); } @@ -833,24 +820,24 @@ void spu_interpreter::MPYHHAU(SPUThread& spu, spu_opcode_t op) spu.gpr[op.rt].vi = _mm_add_epi32(spu.gpr[op.rt].vi, _mm_or_si128(_mm_srli_epi32(_mm_mullo_epi16(a, b), 16), _mm_and_si128(_mm_mulhi_epu16(a, b), _mm_set1_epi32(0xffff0000)))); } -void spu_interpreter::fast::FSCRRD(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FSCRRD(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].clear(); } -void spu_interpreter::fast::FESD(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FESD(SPUThread& spu, spu_opcode_t op) { const auto a = spu.gpr[op.ra].vf; spu.gpr[op.rt].vd = _mm_cvtps_pd(_mm_shuffle_ps(a, a, 0x8d)); } -void spu_interpreter::fast::FRDS(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FRDS(SPUThread& spu, spu_opcode_t op) { const auto t = _mm_cvtpd_ps(spu.gpr[op.ra].vd); spu.gpr[op.rt].vf = _mm_shuffle_ps(t, t, 0x72); } -void spu_interpreter::fast::FSCRWR(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FSCRWR(SPUThread& spu, spu_opcode_t op) { } @@ -859,7 +846,7 @@ void spu_interpreter::DFTSV(SPUThread& spu, spu_opcode_t op) throw EXCEPTION("Unexpected instruction"); } -void spu_interpreter::fast::FCEQ(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FCEQ(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].vf = _mm_cmpeq_ps(spu.gpr[op.rb].vf, spu.gpr[op.ra].vf); } @@ -895,7 +882,7 @@ void spu_interpreter::CEQH(SPUThread& spu, spu_opcode_t op) spu.gpr[op.rt].vi = _mm_cmpeq_epi16(spu.gpr[op.ra].vi, spu.gpr[op.rb].vi); } -void spu_interpreter::fast::FCMEQ(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FCMEQ(SPUThread& spu, spu_opcode_t op) { const auto mask = _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff)); spu.gpr[op.rt].vf = _mm_cmpeq_ps(_mm_and_ps(spu.gpr[op.rb].vf, mask), _mm_and_ps(spu.gpr[op.ra].vf, mask)); @@ -918,7 +905,7 @@ void spu_interpreter::CEQB(SPUThread& spu, spu_opcode_t op) spu.gpr[op.rt].vi = _mm_cmpeq_epi8(spu.gpr[op.ra].vi, spu.gpr[op.rb].vi); } -void spu_interpreter::fast::FI(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FI(SPUThread& spu, spu_opcode_t op) { // TODO const auto mask_se = _mm_castsi128_ps(_mm_set1_epi32(0xff800000)); // sign and exponent mask @@ -940,25 +927,25 @@ void spu_interpreter::HEQ(SPUThread& spu, spu_opcode_t op) } -void spu_interpreter::fast::CFLTS(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::CFLTS(SPUThread& spu, spu_opcode_t op) { const auto scaled = _mm_mul_ps(spu.gpr[op.ra].vf, g_spu_imm.scale[173 - op.i8]); spu.gpr[op.rt].vi = _mm_xor_si128(_mm_cvttps_epi32(scaled), _mm_castps_si128(_mm_cmpge_ps(scaled, _mm_set1_ps(0x80000000)))); } -void spu_interpreter::fast::CFLTU(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::CFLTU(SPUThread& spu, spu_opcode_t op) { const auto scaled1 = _mm_max_ps(_mm_mul_ps(spu.gpr[op.ra].vf, g_spu_imm.scale[173 - op.i8]), _mm_set1_ps(0.0f)); const auto scaled2 = _mm_and_ps(_mm_sub_ps(scaled1, _mm_set1_ps(0x80000000)), _mm_cmpge_ps(scaled1, _mm_set1_ps(0x80000000))); spu.gpr[op.rt].vi = _mm_or_si128(_mm_or_si128(_mm_cvttps_epi32(scaled1), _mm_cvttps_epi32(scaled2)), _mm_castps_si128(_mm_cmpge_ps(scaled1, _mm_set1_ps(0x100000000)))); } -void spu_interpreter::fast::CSFLT(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::CSFLT(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt].vf = _mm_mul_ps(_mm_cvtepi32_ps(spu.gpr[op.ra].vi), g_spu_imm.scale[op.i8 - 155]); } -void spu_interpreter::fast::CUFLT(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::CUFLT(SPUThread& spu, spu_opcode_t op) { const auto a = spu.gpr[op.ra].vi; const auto fix = _mm_and_ps(_mm_castsi128_ps(_mm_srai_epi32(a, 31)), _mm_set1_ps(0x80000000)); @@ -1265,17 +1252,17 @@ void spu_interpreter::MPYA(SPUThread& spu, spu_opcode_t op) spu.gpr[op.rt4].vi = _mm_add_epi32(spu.gpr[op.rc].vi, _mm_madd_epi16(_mm_and_si128(spu.gpr[op.ra].vi, mask), _mm_and_si128(spu.gpr[op.rb].vi, mask))); } -void spu_interpreter::fast::FNMS(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FNMS(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt4].vf = _mm_sub_ps(spu.gpr[op.rc].vf, _mm_mul_ps(spu.gpr[op.ra].vf, spu.gpr[op.rb].vf)); } -void spu_interpreter::fast::FMA(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FMA(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt4].vf = _mm_add_ps(_mm_mul_ps(spu.gpr[op.ra].vf, spu.gpr[op.rb].vf), spu.gpr[op.rc].vf); } -void spu_interpreter::fast::FMS(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_fast::FMS(SPUThread& spu, spu_opcode_t op) { spu.gpr[op.rt4].vf = _mm_sub_ps(_mm_mul_ps(spu.gpr[op.ra].vf, spu.gpr[op.rb].vf), spu.gpr[op.rc].vf); } @@ -1360,7 +1347,7 @@ inline bool isdenormal(double x) #endif } -void spu_interpreter::precise::FREST(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FREST(SPUThread& spu, spu_opcode_t op) { SetHostRoundingMode(FPSCR_RN_ZERO); for (int i = 0; i < 4; i++) @@ -1380,7 +1367,7 @@ void spu_interpreter::precise::FREST(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::precise::FRSQEST(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FRSQEST(SPUThread& spu, spu_opcode_t op) { SetHostRoundingMode(FPSCR_RN_ZERO); for (int i = 0; i < 4; i++) @@ -1400,7 +1387,7 @@ void spu_interpreter::precise::FRSQEST(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::precise::FCGT(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FCGT(SPUThread& spu, spu_opcode_t op) { for (int i = 0; i < 4; i++) { @@ -1508,11 +1495,11 @@ static void FA_FS(SPUThread& spu, spu_opcode_t op, bool sub) } } -void spu_interpreter::precise::FA(SPUThread& spu, spu_opcode_t op) { FA_FS(spu, op, false); } +void spu_interpreter_precise::FA(SPUThread& spu, spu_opcode_t op) { FA_FS(spu, op, false); } -void spu_interpreter::precise::FS(SPUThread& spu, spu_opcode_t op) { FA_FS(spu, op, true); } +void spu_interpreter_precise::FS(SPUThread& spu, spu_opcode_t op) { FA_FS(spu, op, true); } -void spu_interpreter::precise::FM(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FM(SPUThread& spu, spu_opcode_t op) { SetHostRoundingMode(FPSCR_RN_ZERO); for (int w = 0; w < 4; w++) @@ -1585,7 +1572,7 @@ void spu_interpreter::precise::FM(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::precise::FCMGT(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FCMGT(SPUThread& spu, spu_opcode_t op) { for (int i = 0; i < 4; i++) { @@ -1666,11 +1653,11 @@ static void DFASM(SPUThread& spu, spu_opcode_t op, DoubleOp operation) } } -void spu_interpreter::precise::DFA(SPUThread& spu, spu_opcode_t op) { DFASM(spu, op, DFASM_A); } +void spu_interpreter_precise::DFA(SPUThread& spu, spu_opcode_t op) { DFASM(spu, op, DFASM_A); } -void spu_interpreter::precise::DFS(SPUThread& spu, spu_opcode_t op) { DFASM(spu, op, DFASM_S); } +void spu_interpreter_precise::DFS(SPUThread& spu, spu_opcode_t op) { DFASM(spu, op, DFASM_S); } -void spu_interpreter::precise::DFM(SPUThread& spu, spu_opcode_t op) { DFASM(spu, op, DFASM_M); } +void spu_interpreter_precise::DFM(SPUThread& spu, spu_opcode_t op) { DFASM(spu, op, DFASM_M); } static void DFMA(SPUThread& spu, spu_opcode_t op, bool neg, bool sub) { @@ -1727,20 +1714,20 @@ static void DFMA(SPUThread& spu, spu_opcode_t op, bool neg, bool sub) } } -void spu_interpreter::precise::DFMA(SPUThread& spu, spu_opcode_t op) { DFMA(spu, op, false, false); } +void spu_interpreter_precise::DFMA(SPUThread& spu, spu_opcode_t op) { ::DFMA(spu, op, false, false); } -void spu_interpreter::precise::DFMS(SPUThread& spu, spu_opcode_t op) { DFMA(spu, op, false, true); } +void spu_interpreter_precise::DFMS(SPUThread& spu, spu_opcode_t op) { ::DFMA(spu, op, false, true); } -void spu_interpreter::precise::DFNMS(SPUThread& spu, spu_opcode_t op) { DFMA(spu, op, true, true); } +void spu_interpreter_precise::DFNMS(SPUThread& spu, spu_opcode_t op) { ::DFMA(spu, op, true, true); } -void spu_interpreter::precise::DFNMA(SPUThread& spu, spu_opcode_t op) { DFMA(spu, op, true, false); } +void spu_interpreter_precise::DFNMA(SPUThread& spu, spu_opcode_t op) { ::DFMA(spu, op, true, false); } -void spu_interpreter::precise::FSCRRD(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FSCRRD(SPUThread& spu, spu_opcode_t op) { spu.fpscr.Read(spu.gpr[op.rt]); } -void spu_interpreter::precise::FESD(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FESD(SPUThread& spu, spu_opcode_t op) { for (int i = 0; i < 2; i++) { @@ -1764,7 +1751,7 @@ void spu_interpreter::precise::FESD(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::precise::FRDS(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FRDS(SPUThread& spu, spu_opcode_t op) { for (int i = 0; i < 2; i++) { @@ -1792,12 +1779,12 @@ void spu_interpreter::precise::FRDS(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::precise::FSCRWR(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FSCRWR(SPUThread& spu, spu_opcode_t op) { spu.fpscr.Write(spu.gpr[op.ra]); } -void spu_interpreter::precise::FCEQ(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FCEQ(SPUThread& spu, spu_opcode_t op) { for (int i = 0; i < 4; i++) { @@ -1812,7 +1799,7 @@ void spu_interpreter::precise::FCEQ(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::precise::FCMEQ(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FCMEQ(SPUThread& spu, spu_opcode_t op) { for (int i = 0; i < 4; i++) { @@ -1827,13 +1814,13 @@ void spu_interpreter::precise::FCMEQ(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::precise::FI(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::FI(SPUThread& spu, spu_opcode_t op) { // TODO spu.gpr[op.rt] = spu.gpr[op.rb]; } -void spu_interpreter::precise::CFLTS(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::CFLTS(SPUThread& spu, spu_opcode_t op) { const int scale = 173 - (op.i8 & 0xff); //unsigned immediate for (int i = 0; i < 4; i++) @@ -1855,7 +1842,7 @@ void spu_interpreter::precise::CFLTS(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::precise::CFLTU(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::CFLTU(SPUThread& spu, spu_opcode_t op) { const int scale = 173 - (op.i8 & 0xff); //unsigned immediate for (int i = 0; i < 4; i++) @@ -1877,7 +1864,7 @@ void spu_interpreter::precise::CFLTU(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::precise::CSFLT(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::CSFLT(SPUThread& spu, spu_opcode_t op) { SetHostRoundingMode(FPSCR_RN_ZERO); const int scale = 155 - (op.i8 & 0xff); //unsigned immediate @@ -1900,7 +1887,7 @@ void spu_interpreter::precise::CSFLT(SPUThread& spu, spu_opcode_t op) } } -void spu_interpreter::precise::CUFLT(SPUThread& spu, spu_opcode_t op) +void spu_interpreter_precise::CUFLT(SPUThread& spu, spu_opcode_t op) { SetHostRoundingMode(FPSCR_RN_ZERO); const int scale = 155 - (op.i8 & 0xff); //unsigned immediate @@ -2068,8 +2055,8 @@ static void FMA(SPUThread& spu, spu_opcode_t op, bool neg, bool sub) } } -void spu_interpreter::precise::FNMS(SPUThread& spu, spu_opcode_t op) { FMA(spu, op, true, true); } +void spu_interpreter_precise::FNMS(SPUThread& spu, spu_opcode_t op) { ::FMA(spu, op, true, true); } -void spu_interpreter::precise::FMA(SPUThread& spu, spu_opcode_t op) { FMA(spu, op, false, false); } +void spu_interpreter_precise::FMA(SPUThread& spu, spu_opcode_t op) { ::FMA(spu, op, false, false); } -void spu_interpreter::precise::FMS(SPUThread& spu, spu_opcode_t op) { FMA(spu, op, false, true); } +void spu_interpreter_precise::FMS(SPUThread& spu, spu_opcode_t op) { ::FMA(spu, op, false, true); } diff --git a/rpcs3/Emu/Cell/SPUInterpreter.h b/rpcs3/Emu/Cell/SPUInterpreter.h index 5b57cd671e..68c0d4f9f9 100644 --- a/rpcs3/Emu/Cell/SPUInterpreter.h +++ b/rpcs3/Emu/Cell/SPUInterpreter.h @@ -4,256 +4,246 @@ class SPUThread; -using spu_inter_func_t = void(*)(SPUThread& spu, spu_opcode_t opcode); +using spu_inter_func_t = void(*)(SPUThread& spu, spu_opcode_t op); -namespace spu_interpreter +struct spu_interpreter { - namespace fast - { - extern const spu_opcode_table_t g_spu_opcode_table; - } + static void UNK(SPUThread&, spu_opcode_t); + static void set_interrupt_status(SPUThread&, spu_opcode_t); - namespace precise - { - extern const spu_opcode_table_t g_spu_opcode_table; - } + static void STOP(SPUThread&, spu_opcode_t); + static void LNOP(SPUThread&, spu_opcode_t); + static void SYNC(SPUThread&, spu_opcode_t); + static void DSYNC(SPUThread&, spu_opcode_t); + static void MFSPR(SPUThread&, spu_opcode_t); + static void RDCH(SPUThread&, spu_opcode_t); + static void RCHCNT(SPUThread&, spu_opcode_t); + static void SF(SPUThread&, spu_opcode_t); + static void OR(SPUThread&, spu_opcode_t); + static void BG(SPUThread&, spu_opcode_t); + static void SFH(SPUThread&, spu_opcode_t); + static void NOR(SPUThread&, spu_opcode_t); + static void ABSDB(SPUThread&, spu_opcode_t); + static void ROT(SPUThread&, spu_opcode_t); + static void ROTM(SPUThread&, spu_opcode_t); + static void ROTMA(SPUThread&, spu_opcode_t); + static void SHL(SPUThread&, spu_opcode_t); + static void ROTH(SPUThread&, spu_opcode_t); + static void ROTHM(SPUThread&, spu_opcode_t); + static void ROTMAH(SPUThread&, spu_opcode_t); + static void SHLH(SPUThread&, spu_opcode_t); + static void ROTI(SPUThread&, spu_opcode_t); + static void ROTMI(SPUThread&, spu_opcode_t); + static void ROTMAI(SPUThread&, spu_opcode_t); + static void SHLI(SPUThread&, spu_opcode_t); + static void ROTHI(SPUThread&, spu_opcode_t); + static void ROTHMI(SPUThread&, spu_opcode_t); + static void ROTMAHI(SPUThread&, spu_opcode_t); + static void SHLHI(SPUThread&, spu_opcode_t); + static void A(SPUThread&, spu_opcode_t); + static void AND(SPUThread&, spu_opcode_t); + static void CG(SPUThread&, spu_opcode_t); + static void AH(SPUThread&, spu_opcode_t); + static void NAND(SPUThread&, spu_opcode_t); + static void AVGB(SPUThread&, spu_opcode_t); + static void MTSPR(SPUThread&, spu_opcode_t); + static void WRCH(SPUThread&, spu_opcode_t); + static void BIZ(SPUThread&, spu_opcode_t); + static void BINZ(SPUThread&, spu_opcode_t); + static void BIHZ(SPUThread&, spu_opcode_t); + static void BIHNZ(SPUThread&, spu_opcode_t); + static void STOPD(SPUThread&, spu_opcode_t); + static void STQX(SPUThread&, spu_opcode_t); + static void BI(SPUThread&, spu_opcode_t); + static void BISL(SPUThread&, spu_opcode_t); + static void IRET(SPUThread&, spu_opcode_t); + static void BISLED(SPUThread&, spu_opcode_t); + static void HBR(SPUThread&, spu_opcode_t); + static void GB(SPUThread&, spu_opcode_t); + static void GBH(SPUThread&, spu_opcode_t); + static void GBB(SPUThread&, spu_opcode_t); + static void FSM(SPUThread&, spu_opcode_t); + static void FSMH(SPUThread&, spu_opcode_t); + static void FSMB(SPUThread&, spu_opcode_t); + static void LQX(SPUThread&, spu_opcode_t); + static void ROTQBYBI(SPUThread&, spu_opcode_t); + static void ROTQMBYBI(SPUThread&, spu_opcode_t); + static void SHLQBYBI(SPUThread&, spu_opcode_t); + static void CBX(SPUThread&, spu_opcode_t); + static void CHX(SPUThread&, spu_opcode_t); + static void CWX(SPUThread&, spu_opcode_t); + static void CDX(SPUThread&, spu_opcode_t); + static void ROTQBI(SPUThread&, spu_opcode_t); + static void ROTQMBI(SPUThread&, spu_opcode_t); + static void SHLQBI(SPUThread&, spu_opcode_t); + static void ROTQBY(SPUThread&, spu_opcode_t); + static void ROTQMBY(SPUThread&, spu_opcode_t); + static void SHLQBY(SPUThread&, spu_opcode_t); + static void ORX(SPUThread&, spu_opcode_t); + static void CBD(SPUThread&, spu_opcode_t); + static void CHD(SPUThread&, spu_opcode_t); + static void CWD(SPUThread&, spu_opcode_t); + static void CDD(SPUThread&, spu_opcode_t); + static void ROTQBII(SPUThread&, spu_opcode_t); + static void ROTQMBII(SPUThread&, spu_opcode_t); + static void SHLQBII(SPUThread&, spu_opcode_t); + static void ROTQBYI(SPUThread&, spu_opcode_t); + static void ROTQMBYI(SPUThread&, spu_opcode_t); + static void SHLQBYI(SPUThread&, spu_opcode_t); + static void NOP(SPUThread&, spu_opcode_t); + static void CGT(SPUThread&, spu_opcode_t); + static void XOR(SPUThread&, spu_opcode_t); + static void CGTH(SPUThread&, spu_opcode_t); + static void EQV(SPUThread&, spu_opcode_t); + static void CGTB(SPUThread&, spu_opcode_t); + static void SUMB(SPUThread&, spu_opcode_t); + static void HGT(SPUThread&, spu_opcode_t); + static void CLZ(SPUThread&, spu_opcode_t); + static void XSWD(SPUThread&, spu_opcode_t); + static void XSHW(SPUThread&, spu_opcode_t); + static void CNTB(SPUThread&, spu_opcode_t); + static void XSBH(SPUThread&, spu_opcode_t); + static void CLGT(SPUThread&, spu_opcode_t); + static void ANDC(SPUThread&, spu_opcode_t); + static void CLGTH(SPUThread&, spu_opcode_t); + static void ORC(SPUThread&, spu_opcode_t); + static void CLGTB(SPUThread&, spu_opcode_t); + static void HLGT(SPUThread&, spu_opcode_t); + static void CEQ(SPUThread&, spu_opcode_t); + static void MPYHHU(SPUThread&, spu_opcode_t); + static void ADDX(SPUThread&, spu_opcode_t); + static void SFX(SPUThread&, spu_opcode_t); + static void CGX(SPUThread&, spu_opcode_t); + static void BGX(SPUThread&, spu_opcode_t); + static void MPYHHA(SPUThread&, spu_opcode_t); + static void MPYHHAU(SPUThread&, spu_opcode_t); + static void MPY(SPUThread&, spu_opcode_t); + static void MPYH(SPUThread&, spu_opcode_t); + static void MPYHH(SPUThread&, spu_opcode_t); + static void MPYS(SPUThread&, spu_opcode_t); + static void CEQH(SPUThread&, spu_opcode_t); + static void MPYU(SPUThread&, spu_opcode_t); + static void CEQB(SPUThread&, spu_opcode_t); + static void HEQ(SPUThread&, spu_opcode_t); + static void BRZ(SPUThread&, spu_opcode_t); + static void STQA(SPUThread&, spu_opcode_t); + static void BRNZ(SPUThread&, spu_opcode_t); + static void BRHZ(SPUThread&, spu_opcode_t); + static void BRHNZ(SPUThread&, spu_opcode_t); + static void STQR(SPUThread&, spu_opcode_t); + static void BRA(SPUThread&, spu_opcode_t); + static void LQA(SPUThread&, spu_opcode_t); + static void BRASL(SPUThread&, spu_opcode_t); + static void BR(SPUThread&, spu_opcode_t); + static void FSMBI(SPUThread&, spu_opcode_t); + static void BRSL(SPUThread&, spu_opcode_t); + static void LQR(SPUThread&, spu_opcode_t); + static void IL(SPUThread&, spu_opcode_t); + static void ILHU(SPUThread&, spu_opcode_t); + static void ILH(SPUThread&, spu_opcode_t); + static void IOHL(SPUThread&, spu_opcode_t); + static void ORI(SPUThread&, spu_opcode_t); + static void ORHI(SPUThread&, spu_opcode_t); + static void ORBI(SPUThread&, spu_opcode_t); + static void SFI(SPUThread&, spu_opcode_t); + static void SFHI(SPUThread&, spu_opcode_t); + static void ANDI(SPUThread&, spu_opcode_t); + static void ANDHI(SPUThread&, spu_opcode_t); + static void ANDBI(SPUThread&, spu_opcode_t); + static void AI(SPUThread&, spu_opcode_t); + static void AHI(SPUThread&, spu_opcode_t); + static void STQD(SPUThread&, spu_opcode_t); + static void LQD(SPUThread&, spu_opcode_t); + static void XORI(SPUThread&, spu_opcode_t); + static void XORHI(SPUThread&, spu_opcode_t); + static void XORBI(SPUThread&, spu_opcode_t); + static void CGTI(SPUThread&, spu_opcode_t); + static void CGTHI(SPUThread&, spu_opcode_t); + static void CGTBI(SPUThread&, spu_opcode_t); + static void HGTI(SPUThread&, spu_opcode_t); + static void CLGTI(SPUThread&, spu_opcode_t); + static void CLGTHI(SPUThread&, spu_opcode_t); + static void CLGTBI(SPUThread&, spu_opcode_t); + static void HLGTI(SPUThread&, spu_opcode_t); + static void MPYI(SPUThread&, spu_opcode_t); + static void MPYUI(SPUThread&, spu_opcode_t); + static void CEQI(SPUThread&, spu_opcode_t); + static void CEQHI(SPUThread&, spu_opcode_t); + static void CEQBI(SPUThread&, spu_opcode_t); + static void HEQI(SPUThread&, spu_opcode_t); + static void HBRA(SPUThread&, spu_opcode_t); + static void HBRR(SPUThread&, spu_opcode_t); + static void ILA(SPUThread&, spu_opcode_t); + static void SELB(SPUThread&, spu_opcode_t); + static void SHUFB(SPUThread&, spu_opcode_t); + static void MPYA(SPUThread&, spu_opcode_t); + static void DFCGT(SPUThread&, spu_opcode_t); + static void DFCMGT(SPUThread&, spu_opcode_t); + static void DFTSV(SPUThread&, spu_opcode_t); + static void DFCEQ(SPUThread&, spu_opcode_t); + static void DFCMEQ(SPUThread&, spu_opcode_t); +}; - void default_function(SPUThread& spu, spu_opcode_t op); - void set_interrupt_status(SPUThread& spu, spu_opcode_t op); +struct spu_interpreter_fast final : spu_interpreter +{ + static void FREST(SPUThread&, spu_opcode_t); + static void FRSQEST(SPUThread&, spu_opcode_t); + static void FCGT(SPUThread&, spu_opcode_t); + static void FA(SPUThread&, spu_opcode_t); + static void FS(SPUThread&, spu_opcode_t); + static void FM(SPUThread&, spu_opcode_t); + static void FCMGT(SPUThread&, spu_opcode_t); + static void DFA(SPUThread&, spu_opcode_t); + static void DFS(SPUThread&, spu_opcode_t); + static void DFM(SPUThread&, spu_opcode_t); + static void DFMA(SPUThread&, spu_opcode_t); + static void DFMS(SPUThread&, spu_opcode_t); + static void DFNMS(SPUThread&, spu_opcode_t); + static void DFNMA(SPUThread&, spu_opcode_t); + static void FSCRRD(SPUThread&, spu_opcode_t); + static void FESD(SPUThread&, spu_opcode_t); + static void FRDS(SPUThread&, spu_opcode_t); + static void FSCRWR(SPUThread&, spu_opcode_t); + static void FCEQ(SPUThread&, spu_opcode_t); + static void FCMEQ(SPUThread&, spu_opcode_t); + static void FI(SPUThread&, spu_opcode_t); + static void CFLTS(SPUThread&, spu_opcode_t); + static void CFLTU(SPUThread&, spu_opcode_t); + static void CSFLT(SPUThread&, spu_opcode_t); + static void CUFLT(SPUThread&, spu_opcode_t); + static void FNMS(SPUThread&, spu_opcode_t); + static void FMA(SPUThread&, spu_opcode_t); + static void FMS(SPUThread&, spu_opcode_t); +}; - void STOP(SPUThread& spu, spu_opcode_t op); - void LNOP(SPUThread& spu, spu_opcode_t op); - void SYNC(SPUThread& spu, spu_opcode_t op); - void DSYNC(SPUThread& spu, spu_opcode_t op); - void MFSPR(SPUThread& spu, spu_opcode_t op); - void RDCH(SPUThread& spu, spu_opcode_t op); - void RCHCNT(SPUThread& spu, spu_opcode_t op); - void SF(SPUThread& spu, spu_opcode_t op); - void OR(SPUThread& spu, spu_opcode_t op); - void BG(SPUThread& spu, spu_opcode_t op); - void SFH(SPUThread& spu, spu_opcode_t op); - void NOR(SPUThread& spu, spu_opcode_t op); - void ABSDB(SPUThread& spu, spu_opcode_t op); - void ROT(SPUThread& spu, spu_opcode_t op); - void ROTM(SPUThread& spu, spu_opcode_t op); - void ROTMA(SPUThread& spu, spu_opcode_t op); - void SHL(SPUThread& spu, spu_opcode_t op); - void ROTH(SPUThread& spu, spu_opcode_t op); - void ROTHM(SPUThread& spu, spu_opcode_t op); - void ROTMAH(SPUThread& spu, spu_opcode_t op); - void SHLH(SPUThread& spu, spu_opcode_t op); - void ROTI(SPUThread& spu, spu_opcode_t op); - void ROTMI(SPUThread& spu, spu_opcode_t op); - void ROTMAI(SPUThread& spu, spu_opcode_t op); - void SHLI(SPUThread& spu, spu_opcode_t op); - void ROTHI(SPUThread& spu, spu_opcode_t op); - void ROTHMI(SPUThread& spu, spu_opcode_t op); - void ROTMAHI(SPUThread& spu, spu_opcode_t op); - void SHLHI(SPUThread& spu, spu_opcode_t op); - void A(SPUThread& spu, spu_opcode_t op); - void AND(SPUThread& spu, spu_opcode_t op); - void CG(SPUThread& spu, spu_opcode_t op); - void AH(SPUThread& spu, spu_opcode_t op); - void NAND(SPUThread& spu, spu_opcode_t op); - void AVGB(SPUThread& spu, spu_opcode_t op); - void MTSPR(SPUThread& spu, spu_opcode_t op); - void WRCH(SPUThread& spu, spu_opcode_t op); - void BIZ(SPUThread& spu, spu_opcode_t op); - void BINZ(SPUThread& spu, spu_opcode_t op); - void BIHZ(SPUThread& spu, spu_opcode_t op); - void BIHNZ(SPUThread& spu, spu_opcode_t op); - void STOPD(SPUThread& spu, spu_opcode_t op); - void STQX(SPUThread& spu, spu_opcode_t op); - void BI(SPUThread& spu, spu_opcode_t op); - void BISL(SPUThread& spu, spu_opcode_t op); - void IRET(SPUThread& spu, spu_opcode_t op); - void BISLED(SPUThread& spu, spu_opcode_t op); - void HBR(SPUThread& spu, spu_opcode_t op); - void GB(SPUThread& spu, spu_opcode_t op); - void GBH(SPUThread& spu, spu_opcode_t op); - void GBB(SPUThread& spu, spu_opcode_t op); - void FSM(SPUThread& spu, spu_opcode_t op); - void FSMH(SPUThread& spu, spu_opcode_t op); - void FSMB(SPUThread& spu, spu_opcode_t op); - void LQX(SPUThread& spu, spu_opcode_t op); - void ROTQBYBI(SPUThread& spu, spu_opcode_t op); - void ROTQMBYBI(SPUThread& spu, spu_opcode_t op); - void SHLQBYBI(SPUThread& spu, spu_opcode_t op); - void CBX(SPUThread& spu, spu_opcode_t op); - void CHX(SPUThread& spu, spu_opcode_t op); - void CWX(SPUThread& spu, spu_opcode_t op); - void CDX(SPUThread& spu, spu_opcode_t op); - void ROTQBI(SPUThread& spu, spu_opcode_t op); - void ROTQMBI(SPUThread& spu, spu_opcode_t op); - void SHLQBI(SPUThread& spu, spu_opcode_t op); - void ROTQBY(SPUThread& spu, spu_opcode_t op); - void ROTQMBY(SPUThread& spu, spu_opcode_t op); - void SHLQBY(SPUThread& spu, spu_opcode_t op); - void ORX(SPUThread& spu, spu_opcode_t op); - void CBD(SPUThread& spu, spu_opcode_t op); - void CHD(SPUThread& spu, spu_opcode_t op); - void CWD(SPUThread& spu, spu_opcode_t op); - void CDD(SPUThread& spu, spu_opcode_t op); - void ROTQBII(SPUThread& spu, spu_opcode_t op); - void ROTQMBII(SPUThread& spu, spu_opcode_t op); - void SHLQBII(SPUThread& spu, spu_opcode_t op); - void ROTQBYI(SPUThread& spu, spu_opcode_t op); - void ROTQMBYI(SPUThread& spu, spu_opcode_t op); - void SHLQBYI(SPUThread& spu, spu_opcode_t op); - void NOP(SPUThread& spu, spu_opcode_t op); - void CGT(SPUThread& spu, spu_opcode_t op); - void XOR(SPUThread& spu, spu_opcode_t op); - void CGTH(SPUThread& spu, spu_opcode_t op); - void EQV(SPUThread& spu, spu_opcode_t op); - void CGTB(SPUThread& spu, spu_opcode_t op); - void SUMB(SPUThread& spu, spu_opcode_t op); - void HGT(SPUThread& spu, spu_opcode_t op); - void CLZ(SPUThread& spu, spu_opcode_t op); - void XSWD(SPUThread& spu, spu_opcode_t op); - void XSHW(SPUThread& spu, spu_opcode_t op); - void CNTB(SPUThread& spu, spu_opcode_t op); - void XSBH(SPUThread& spu, spu_opcode_t op); - void CLGT(SPUThread& spu, spu_opcode_t op); - void ANDC(SPUThread& spu, spu_opcode_t op); - void CLGTH(SPUThread& spu, spu_opcode_t op); - void ORC(SPUThread& spu, spu_opcode_t op); - void CLGTB(SPUThread& spu, spu_opcode_t op); - void HLGT(SPUThread& spu, spu_opcode_t op); - void CEQ(SPUThread& spu, spu_opcode_t op); - void MPYHHU(SPUThread& spu, spu_opcode_t op); - void ADDX(SPUThread& spu, spu_opcode_t op); - void SFX(SPUThread& spu, spu_opcode_t op); - void CGX(SPUThread& spu, spu_opcode_t op); - void BGX(SPUThread& spu, spu_opcode_t op); - void MPYHHA(SPUThread& spu, spu_opcode_t op); - void MPYHHAU(SPUThread& spu, spu_opcode_t op); - void MPY(SPUThread& spu, spu_opcode_t op); - void MPYH(SPUThread& spu, spu_opcode_t op); - void MPYHH(SPUThread& spu, spu_opcode_t op); - void MPYS(SPUThread& spu, spu_opcode_t op); - void CEQH(SPUThread& spu, spu_opcode_t op); - void MPYU(SPUThread& spu, spu_opcode_t op); - void CEQB(SPUThread& spu, spu_opcode_t op); - void HEQ(SPUThread& spu, spu_opcode_t op); - void BRZ(SPUThread& spu, spu_opcode_t op); - void STQA(SPUThread& spu, spu_opcode_t op); - void BRNZ(SPUThread& spu, spu_opcode_t op); - void BRHZ(SPUThread& spu, spu_opcode_t op); - void BRHNZ(SPUThread& spu, spu_opcode_t op); - void STQR(SPUThread& spu, spu_opcode_t op); - void BRA(SPUThread& spu, spu_opcode_t op); - void LQA(SPUThread& spu, spu_opcode_t op); - void BRASL(SPUThread& spu, spu_opcode_t op); - void BR(SPUThread& spu, spu_opcode_t op); - void FSMBI(SPUThread& spu, spu_opcode_t op); - void BRSL(SPUThread& spu, spu_opcode_t op); - void LQR(SPUThread& spu, spu_opcode_t op); - void IL(SPUThread& spu, spu_opcode_t op); - void ILHU(SPUThread& spu, spu_opcode_t op); - void ILH(SPUThread& spu, spu_opcode_t op); - void IOHL(SPUThread& spu, spu_opcode_t op); - void ORI(SPUThread& spu, spu_opcode_t op); - void ORHI(SPUThread& spu, spu_opcode_t op); - void ORBI(SPUThread& spu, spu_opcode_t op); - void SFI(SPUThread& spu, spu_opcode_t op); - void SFHI(SPUThread& spu, spu_opcode_t op); - void ANDI(SPUThread& spu, spu_opcode_t op); - void ANDHI(SPUThread& spu, spu_opcode_t op); - void ANDBI(SPUThread& spu, spu_opcode_t op); - void AI(SPUThread& spu, spu_opcode_t op); - void AHI(SPUThread& spu, spu_opcode_t op); - void STQD(SPUThread& spu, spu_opcode_t op); - void LQD(SPUThread& spu, spu_opcode_t op); - void XORI(SPUThread& spu, spu_opcode_t op); - void XORHI(SPUThread& spu, spu_opcode_t op); - void XORBI(SPUThread& spu, spu_opcode_t op); - void CGTI(SPUThread& spu, spu_opcode_t op); - void CGTHI(SPUThread& spu, spu_opcode_t op); - void CGTBI(SPUThread& spu, spu_opcode_t op); - void HGTI(SPUThread& spu, spu_opcode_t op); - void CLGTI(SPUThread& spu, spu_opcode_t op); - void CLGTHI(SPUThread& spu, spu_opcode_t op); - void CLGTBI(SPUThread& spu, spu_opcode_t op); - void HLGTI(SPUThread& spu, spu_opcode_t op); - void MPYI(SPUThread& spu, spu_opcode_t op); - void MPYUI(SPUThread& spu, spu_opcode_t op); - void CEQI(SPUThread& spu, spu_opcode_t op); - void CEQHI(SPUThread& spu, spu_opcode_t op); - void CEQBI(SPUThread& spu, spu_opcode_t op); - void HEQI(SPUThread& spu, spu_opcode_t op); - void HBRA(SPUThread& spu, spu_opcode_t op); - void HBRR(SPUThread& spu, spu_opcode_t op); - void ILA(SPUThread& spu, spu_opcode_t op); - void SELB(SPUThread& spu, spu_opcode_t op); - void SHUFB(SPUThread& spu, spu_opcode_t op); - void MPYA(SPUThread& spu, spu_opcode_t op); - void DFCGT(SPUThread& spu, spu_opcode_t op); - void DFCMGT(SPUThread& spu, spu_opcode_t op); - void DFTSV(SPUThread& spu, spu_opcode_t op); - void DFCEQ(SPUThread& spu, spu_opcode_t op); - void DFCMEQ(SPUThread& spu, spu_opcode_t op); - - namespace fast - { - void FREST(SPUThread& spu, spu_opcode_t op); - void FRSQEST(SPUThread& spu, spu_opcode_t op); - void FCGT(SPUThread& spu, spu_opcode_t op); - void FA(SPUThread& spu, spu_opcode_t op); - void FS(SPUThread& spu, spu_opcode_t op); - void FM(SPUThread& spu, spu_opcode_t op); - void FCMGT(SPUThread& spu, spu_opcode_t op); - void DFA(SPUThread& spu, spu_opcode_t op); - void DFS(SPUThread& spu, spu_opcode_t op); - void DFM(SPUThread& spu, spu_opcode_t op); - void DFMA(SPUThread& spu, spu_opcode_t op); - void DFMS(SPUThread& spu, spu_opcode_t op); - void DFNMS(SPUThread& spu, spu_opcode_t op); - void DFNMA(SPUThread& spu, spu_opcode_t op); - void FSCRRD(SPUThread& spu, spu_opcode_t op); - void FESD(SPUThread& spu, spu_opcode_t op); - void FRDS(SPUThread& spu, spu_opcode_t op); - void FSCRWR(SPUThread& spu, spu_opcode_t op); - void FCEQ(SPUThread& spu, spu_opcode_t op); - void FCMEQ(SPUThread& spu, spu_opcode_t op); - void FI(SPUThread& spu, spu_opcode_t op); - void CFLTS(SPUThread& spu, spu_opcode_t op); - void CFLTU(SPUThread& spu, spu_opcode_t op); - void CSFLT(SPUThread& spu, spu_opcode_t op); - void CUFLT(SPUThread& spu, spu_opcode_t op); - void FNMS(SPUThread& spu, spu_opcode_t op); - void FMA(SPUThread& spu, spu_opcode_t op); - void FMS(SPUThread& spu, spu_opcode_t op); - } - - namespace precise - { - void FREST(SPUThread& spu, spu_opcode_t op); - void FRSQEST(SPUThread& spu, spu_opcode_t op); - void FCGT(SPUThread& spu, spu_opcode_t op); - void FA(SPUThread& spu, spu_opcode_t op); - void FS(SPUThread& spu, spu_opcode_t op); - void FM(SPUThread& spu, spu_opcode_t op); - void FCMGT(SPUThread& spu, spu_opcode_t op); - void DFA(SPUThread& spu, spu_opcode_t op); - void DFS(SPUThread& spu, spu_opcode_t op); - void DFM(SPUThread& spu, spu_opcode_t op); - void DFMA(SPUThread& spu, spu_opcode_t op); - void DFMS(SPUThread& spu, spu_opcode_t op); - void DFNMS(SPUThread& spu, spu_opcode_t op); - void DFNMA(SPUThread& spu, spu_opcode_t op); - void FSCRRD(SPUThread& spu, spu_opcode_t op); - void FESD(SPUThread& spu, spu_opcode_t op); - void FRDS(SPUThread& spu, spu_opcode_t op); - void FSCRWR(SPUThread& spu, spu_opcode_t op); - void FCEQ(SPUThread& spu, spu_opcode_t op); - void FCMEQ(SPUThread& spu, spu_opcode_t op); - void FI(SPUThread& spu, spu_opcode_t op); - void CFLTS(SPUThread& spu, spu_opcode_t op); - void CFLTU(SPUThread& spu, spu_opcode_t op); - void CSFLT(SPUThread& spu, spu_opcode_t op); - void CUFLT(SPUThread& spu, spu_opcode_t op); - void FNMS(SPUThread& spu, spu_opcode_t op); - void FMA(SPUThread& spu, spu_opcode_t op); - void FMS(SPUThread& spu, spu_opcode_t op); - } -} +struct spu_interpreter_precise final : spu_interpreter +{ + static void FREST(SPUThread&, spu_opcode_t); + static void FRSQEST(SPUThread&, spu_opcode_t); + static void FCGT(SPUThread&, spu_opcode_t); + static void FA(SPUThread&, spu_opcode_t); + static void FS(SPUThread&, spu_opcode_t); + static void FM(SPUThread&, spu_opcode_t); + static void FCMGT(SPUThread&, spu_opcode_t); + static void DFA(SPUThread&, spu_opcode_t); + static void DFS(SPUThread&, spu_opcode_t); + static void DFM(SPUThread&, spu_opcode_t); + static void DFMA(SPUThread&, spu_opcode_t); + static void DFMS(SPUThread&, spu_opcode_t); + static void DFNMS(SPUThread&, spu_opcode_t); + static void DFNMA(SPUThread&, spu_opcode_t); + static void FSCRRD(SPUThread&, spu_opcode_t); + static void FESD(SPUThread&, spu_opcode_t); + static void FRDS(SPUThread&, spu_opcode_t); + static void FSCRWR(SPUThread&, spu_opcode_t); + static void FCEQ(SPUThread&, spu_opcode_t); + static void FCMEQ(SPUThread&, spu_opcode_t); + static void FI(SPUThread&, spu_opcode_t); + static void CFLTS(SPUThread&, spu_opcode_t); + static void CFLTU(SPUThread&, spu_opcode_t); + static void CSFLT(SPUThread&, spu_opcode_t); + static void CUFLT(SPUThread&, spu_opcode_t); + static void FNMS(SPUThread&, spu_opcode_t); + static void FMA(SPUThread&, spu_opcode_t); + static void FMS(SPUThread&, spu_opcode_t); +}; diff --git a/rpcs3/Emu/Cell/SPUOpcodes.h b/rpcs3/Emu/Cell/SPUOpcodes.h index 25c02fb604..e3f3618f71 100644 --- a/rpcs3/Emu/Cell/SPUOpcodes.h +++ b/rpcs3/Emu/Cell/SPUOpcodes.h @@ -1,5 +1,7 @@ #pragma once +#include "../../../Utilities/BitField.h" + union spu_opcode_t { u32 opcode; @@ -23,246 +25,6 @@ union spu_opcode_t bf_t i18; // 7..24 }; -#define DEFINE_SPU_OPCODES(ns) { \ - { 10, 0x0, ns STOP }, \ - { 10, 0x1, ns LNOP }, \ - { 10, 0x2, ns SYNC }, \ - { 10, 0x3, ns DSYNC }, \ - { 10, 0xc, ns MFSPR }, \ - { 10, 0xd, ns RDCH }, \ - { 10, 0xf, ns RCHCNT }, \ - { 10, 0x40, ns SF }, \ - { 10, 0x41, ns OR }, \ - { 10, 0x42, ns BG }, \ - { 10, 0x48, ns SFH }, \ - { 10, 0x49, ns NOR }, \ - { 10, 0x53, ns ABSDB }, \ - { 10, 0x58, ns ROT }, \ - { 10, 0x59, ns ROTM }, \ - { 10, 0x5a, ns ROTMA }, \ - { 10, 0x5b, ns SHL }, \ - { 10, 0x5c, ns ROTH }, \ - { 10, 0x5d, ns ROTHM }, \ - { 10, 0x5e, ns ROTMAH }, \ - { 10, 0x5f, ns SHLH }, \ - { 10, 0x78, ns ROTI }, \ - { 10, 0x79, ns ROTMI }, \ - { 10, 0x7a, ns ROTMAI }, \ - { 10, 0x7b, ns SHLI }, \ - { 10, 0x7c, ns ROTHI }, \ - { 10, 0x7d, ns ROTHMI }, \ - { 10, 0x7e, ns ROTMAHI }, \ - { 10, 0x7f, ns SHLHI }, \ - { 10, 0xc0, ns A }, \ - { 10, 0xc1, ns AND }, \ - { 10, 0xc2, ns CG }, \ - { 10, 0xc8, ns AH }, \ - { 10, 0xc9, ns NAND }, \ - { 10, 0xd3, ns AVGB }, \ - { 10, 0x10c, ns MTSPR }, \ - { 10, 0x10d, ns WRCH }, \ - { 10, 0x128, ns BIZ }, \ - { 10, 0x129, ns BINZ }, \ - { 10, 0x12a, ns BIHZ }, \ - { 10, 0x12b, ns BIHNZ }, \ - { 10, 0x140, ns STOPD }, \ - { 10, 0x144, ns STQX }, \ - { 10, 0x1a8, ns BI }, \ - { 10, 0x1a9, ns BISL }, \ - { 10, 0x1aa, ns IRET }, \ - { 10, 0x1ab, ns BISLED }, \ - { 10, 0x1ac, ns HBR }, \ - { 10, 0x1b0, ns GB }, \ - { 10, 0x1b1, ns GBH }, \ - { 10, 0x1b2, ns GBB }, \ - { 10, 0x1b4, ns FSM }, \ - { 10, 0x1b5, ns FSMH }, \ - { 10, 0x1b6, ns FSMB }, \ - { 10, 0x1b8, ns FREST }, \ - { 10, 0x1b9, ns FRSQEST }, \ - { 10, 0x1c4, ns LQX }, \ - { 10, 0x1cc, ns ROTQBYBI }, \ - { 10, 0x1cd, ns ROTQMBYBI }, \ - { 10, 0x1cf, ns SHLQBYBI }, \ - { 10, 0x1d4, ns CBX }, \ - { 10, 0x1d5, ns CHX }, \ - { 10, 0x1d6, ns CWX }, \ - { 10, 0x1d7, ns CDX }, \ - { 10, 0x1d8, ns ROTQBI }, \ - { 10, 0x1d9, ns ROTQMBI }, \ - { 10, 0x1db, ns SHLQBI }, \ - { 10, 0x1dc, ns ROTQBY }, \ - { 10, 0x1dd, ns ROTQMBY }, \ - { 10, 0x1df, ns SHLQBY }, \ - { 10, 0x1f0, ns ORX }, \ - { 10, 0x1f4, ns CBD }, \ - { 10, 0x1f5, ns CHD }, \ - { 10, 0x1f6, ns CWD }, \ - { 10, 0x1f7, ns CDD }, \ - { 10, 0x1f8, ns ROTQBII }, \ - { 10, 0x1f9, ns ROTQMBII }, \ - { 10, 0x1fb, ns SHLQBII }, \ - { 10, 0x1fc, ns ROTQBYI }, \ - { 10, 0x1fd, ns ROTQMBYI }, \ - { 10, 0x1ff, ns SHLQBYI }, \ - { 10, 0x201, ns NOP }, \ - { 10, 0x240, ns CGT }, \ - { 10, 0x241, ns XOR }, \ - { 10, 0x248, ns CGTH }, \ - { 10, 0x249, ns EQV }, \ - { 10, 0x250, ns CGTB }, \ - { 10, 0x253, ns SUMB }, \ - { 10, 0x258, ns HGT }, \ - { 10, 0x2a5, ns CLZ }, \ - { 10, 0x2a6, ns XSWD }, \ - { 10, 0x2ae, ns XSHW }, \ - { 10, 0x2b4, ns CNTB }, \ - { 10, 0x2b6, ns XSBH }, \ - { 10, 0x2c0, ns CLGT }, \ - { 10, 0x2c1, ns ANDC }, \ - { 10, 0x2c2, ns FCGT }, \ - { 10, 0x2c3, ns DFCGT }, \ - { 10, 0x2c4, ns FA }, \ - { 10, 0x2c5, ns FS }, \ - { 10, 0x2c6, ns FM }, \ - { 10, 0x2c8, ns CLGTH }, \ - { 10, 0x2c9, ns ORC }, \ - { 10, 0x2ca, ns FCMGT }, \ - { 10, 0x2cb, ns DFCMGT }, \ - { 10, 0x2cc, ns DFA }, \ - { 10, 0x2cd, ns DFS }, \ - { 10, 0x2ce, ns DFM }, \ - { 10, 0x2d0, ns CLGTB }, \ - { 10, 0x2d8, ns HLGT }, \ - { 10, 0x35c, ns DFMA }, \ - { 10, 0x35d, ns DFMS }, \ - { 10, 0x35e, ns DFNMS }, \ - { 10, 0x35f, ns DFNMA }, \ - { 10, 0x3c0, ns CEQ }, \ - { 10, 0x3ce, ns MPYHHU }, \ - { 10, 0x340, ns ADDX }, \ - { 10, 0x341, ns SFX }, \ - { 10, 0x342, ns CGX }, \ - { 10, 0x343, ns BGX }, \ - { 10, 0x346, ns MPYHHA }, \ - { 10, 0x34e, ns MPYHHAU }, \ - { 10, 0x398, ns FSCRRD }, \ - { 10, 0x3b8, ns FESD }, \ - { 10, 0x3b9, ns FRDS }, \ - { 10, 0x3ba, ns FSCRWR }, \ - { 10, 0x3bf, ns DFTSV }, \ - { 10, 0x3c2, ns FCEQ }, \ - { 10, 0x3c3, ns DFCEQ }, \ - { 10, 0x3c4, ns MPY }, \ - { 10, 0x3c5, ns MPYH }, \ - { 10, 0x3c6, ns MPYHH }, \ - { 10, 0x3c7, ns MPYS }, \ - { 10, 0x3c8, ns CEQH }, \ - { 10, 0x3ca, ns FCMEQ }, \ - { 10, 0x3cb, ns DFCMEQ }, \ - { 10, 0x3cc, ns MPYU }, \ - { 10, 0x3d0, ns CEQB }, \ - { 10, 0x3d4, ns FI }, \ - { 10, 0x3d8, ns HEQ }, \ - { 9, 0x1d8, ns CFLTS }, \ - { 9, 0x1d9, ns CFLTU }, \ - { 9, 0x1da, ns CSFLT }, \ - { 9, 0x1db, ns CUFLT }, \ - { 8, 0x40, ns BRZ }, \ - { 8, 0x41, ns STQA }, \ - { 8, 0x42, ns BRNZ }, \ - { 8, 0x44, ns BRHZ }, \ - { 8, 0x46, ns BRHNZ }, \ - { 8, 0x47, ns STQR }, \ - { 8, 0x60, ns BRA }, \ - { 8, 0x61, ns LQA }, \ - { 8, 0x62, ns BRASL }, \ - { 8, 0x64, ns BR }, \ - { 8, 0x65, ns FSMBI }, \ - { 8, 0x66, ns BRSL }, \ - { 8, 0x67, ns LQR }, \ - { 8, 0x81, ns IL }, \ - { 8, 0x82, ns ILHU }, \ - { 8, 0x83, ns ILH }, \ - { 8, 0xc1, ns IOHL }, \ - { 7, 0x4, ns ORI }, \ - { 7, 0x5, ns ORHI }, \ - { 7, 0x6, ns ORBI }, \ - { 7, 0xc, ns SFI }, \ - { 7, 0xd, ns SFHI }, \ - { 7, 0x14, ns ANDI }, \ - { 7, 0x15, ns ANDHI }, \ - { 7, 0x16, ns ANDBI }, \ - { 7, 0x1c, ns AI }, \ - { 7, 0x1d, ns AHI }, \ - { 7, 0x24, ns STQD }, \ - { 7, 0x34, ns LQD }, \ - { 7, 0x44, ns XORI }, \ - { 7, 0x45, ns XORHI }, \ - { 7, 0x46, ns XORBI }, \ - { 7, 0x4c, ns CGTI }, \ - { 7, 0x4d, ns CGTHI }, \ - { 7, 0x4e, ns CGTBI }, \ - { 7, 0x4f, ns HGTI }, \ - { 7, 0x5c, ns CLGTI }, \ - { 7, 0x5d, ns CLGTHI }, \ - { 7, 0x5e, ns CLGTBI }, \ - { 7, 0x5f, ns HLGTI }, \ - { 7, 0x74, ns MPYI }, \ - { 7, 0x75, ns MPYUI }, \ - { 7, 0x7c, ns CEQI }, \ - { 7, 0x7d, ns CEQHI }, \ - { 7, 0x7e, ns CEQBI }, \ - { 7, 0x7f, ns HEQI }, \ - { 6, 0x8, ns HBRA }, \ - { 6, 0x9, ns HBRR }, \ - { 6, 0x21, ns ILA }, \ - { 3, 0x8, ns SELB }, \ - { 3, 0xb, ns SHUFB }, \ - { 3, 0xc, ns MPYA }, \ - { 3, 0xd, ns FNMS }, \ - { 3, 0xe, ns FMA }, \ - { 3, 0xf, ns FMS }, \ -} - -template class spu_opcode_table_t -{ - std::array m_data; - - struct opcode_entry_t - { - u32 group; - u32 value; - T pointer; - }; - -public: - // opcode table initialization (TODO: optimize it a bit) - spu_opcode_table_t(std::initializer_list opcodes, T default_value = {}) - { - for (u32 i = 0; i < 2048; i++) - { - m_data[i] = default_value; - - for (auto& op : opcodes) - { - if (((i << 21) & (INT_MIN >> op.group)) == (op.value << (31 - op.group))) - { - m_data[i] = op.pointer; - break; - } - } - } - } - - // access opcode table - T operator [](u32 opcode_data) const - { - // the whole decoding process is shifting opcode data - return m_data[opcode_data >> 21]; - } -}; - inline u32 spu_branch_target(u32 pc, u32 imm = 0) { return (pc + (imm << 2)) & 0x3fffc; @@ -272,3 +34,250 @@ inline u32 spu_ls_target(u32 pc, u32 imm = 0) { return (pc + (imm << 2)) & 0x3fff0; } + +static u32 spu_decode(u32 inst) +{ + return inst >> 21; +} + +// SPU decoder object. D provides functions. T is function pointer type returned. +template +class spu_decoder +{ + // Fast lookup table + std::array m_table; + + struct instruction_info + { + u32 magn; // Count = 2 ^ magn + u32 value; + T pointer; + }; + +public: + spu_decoder() + { + const std::initializer_list instructions + { + { 0, 0x0, &D::STOP }, + { 0, 0x1, &D::LNOP }, + { 0, 0x2, &D::SYNC }, + { 0, 0x3, &D::DSYNC }, + { 0, 0xc, &D::MFSPR }, + { 0, 0xd, &D::RDCH }, + { 0, 0xf, &D::RCHCNT }, + { 0, 0x40, &D::SF }, + { 0, 0x41, &D::OR }, + { 0, 0x42, &D::BG }, + { 0, 0x48, &D::SFH }, + { 0, 0x49, &D::NOR }, + { 0, 0x53, &D::ABSDB }, + { 0, 0x58, &D::ROT }, + { 0, 0x59, &D::ROTM }, + { 0, 0x5a, &D::ROTMA }, + { 0, 0x5b, &D::SHL }, + { 0, 0x5c, &D::ROTH }, + { 0, 0x5d, &D::ROTHM }, + { 0, 0x5e, &D::ROTMAH }, + { 0, 0x5f, &D::SHLH }, + { 0, 0x78, &D::ROTI }, + { 0, 0x79, &D::ROTMI }, + { 0, 0x7a, &D::ROTMAI }, + { 0, 0x7b, &D::SHLI }, + { 0, 0x7c, &D::ROTHI }, + { 0, 0x7d, &D::ROTHMI }, + { 0, 0x7e, &D::ROTMAHI }, + { 0, 0x7f, &D::SHLHI }, + { 0, 0xc0, &D::A }, + { 0, 0xc1, &D::AND }, + { 0, 0xc2, &D::CG }, + { 0, 0xc8, &D::AH }, + { 0, 0xc9, &D::NAND }, + { 0, 0xd3, &D::AVGB }, + { 0, 0x10c, &D::MTSPR }, + { 0, 0x10d, &D::WRCH }, + { 0, 0x128, &D::BIZ }, + { 0, 0x129, &D::BINZ }, + { 0, 0x12a, &D::BIHZ }, + { 0, 0x12b, &D::BIHNZ }, + { 0, 0x140, &D::STOPD }, + { 0, 0x144, &D::STQX }, + { 0, 0x1a8, &D::BI }, + { 0, 0x1a9, &D::BISL }, + { 0, 0x1aa, &D::IRET }, + { 0, 0x1ab, &D::BISLED }, + { 0, 0x1ac, &D::HBR }, + { 0, 0x1b0, &D::GB }, + { 0, 0x1b1, &D::GBH }, + { 0, 0x1b2, &D::GBB }, + { 0, 0x1b4, &D::FSM }, + { 0, 0x1b5, &D::FSMH }, + { 0, 0x1b6, &D::FSMB }, + { 0, 0x1b8, &D::FREST }, + { 0, 0x1b9, &D::FRSQEST }, + { 0, 0x1c4, &D::LQX }, + { 0, 0x1cc, &D::ROTQBYBI }, + { 0, 0x1cd, &D::ROTQMBYBI }, + { 0, 0x1cf, &D::SHLQBYBI }, + { 0, 0x1d4, &D::CBX }, + { 0, 0x1d5, &D::CHX }, + { 0, 0x1d6, &D::CWX }, + { 0, 0x1d7, &D::CDX }, + { 0, 0x1d8, &D::ROTQBI }, + { 0, 0x1d9, &D::ROTQMBI }, + { 0, 0x1db, &D::SHLQBI }, + { 0, 0x1dc, &D::ROTQBY }, + { 0, 0x1dd, &D::ROTQMBY }, + { 0, 0x1df, &D::SHLQBY }, + { 0, 0x1f0, &D::ORX }, + { 0, 0x1f4, &D::CBD }, + { 0, 0x1f5, &D::CHD }, + { 0, 0x1f6, &D::CWD }, + { 0, 0x1f7, &D::CDD }, + { 0, 0x1f8, &D::ROTQBII }, + { 0, 0x1f9, &D::ROTQMBII }, + { 0, 0x1fb, &D::SHLQBII }, + { 0, 0x1fc, &D::ROTQBYI }, + { 0, 0x1fd, &D::ROTQMBYI }, + { 0, 0x1ff, &D::SHLQBYI }, + { 0, 0x201, &D::NOP }, + { 0, 0x240, &D::CGT }, + { 0, 0x241, &D::XOR }, + { 0, 0x248, &D::CGTH }, + { 0, 0x249, &D::EQV }, + { 0, 0x250, &D::CGTB }, + { 0, 0x253, &D::SUMB }, + { 0, 0x258, &D::HGT }, + { 0, 0x2a5, &D::CLZ }, + { 0, 0x2a6, &D::XSWD }, + { 0, 0x2ae, &D::XSHW }, + { 0, 0x2b4, &D::CNTB }, + { 0, 0x2b6, &D::XSBH }, + { 0, 0x2c0, &D::CLGT }, + { 0, 0x2c1, &D::ANDC }, + { 0, 0x2c2, &D::FCGT }, + { 0, 0x2c3, &D::DFCGT }, + { 0, 0x2c4, &D::FA }, + { 0, 0x2c5, &D::FS }, + { 0, 0x2c6, &D::FM }, + { 0, 0x2c8, &D::CLGTH }, + { 0, 0x2c9, &D::ORC }, + { 0, 0x2ca, &D::FCMGT }, + { 0, 0x2cb, &D::DFCMGT }, + { 0, 0x2cc, &D::DFA }, + { 0, 0x2cd, &D::DFS }, + { 0, 0x2ce, &D::DFM }, + { 0, 0x2d0, &D::CLGTB }, + { 0, 0x2d8, &D::HLGT }, + { 0, 0x35c, &D::DFMA }, + { 0, 0x35d, &D::DFMS }, + { 0, 0x35e, &D::DFNMS }, + { 0, 0x35f, &D::DFNMA }, + { 0, 0x3c0, &D::CEQ }, + { 0, 0x3ce, &D::MPYHHU }, + { 0, 0x340, &D::ADDX }, + { 0, 0x341, &D::SFX }, + { 0, 0x342, &D::CGX }, + { 0, 0x343, &D::BGX }, + { 0, 0x346, &D::MPYHHA }, + { 0, 0x34e, &D::MPYHHAU }, + { 0, 0x398, &D::FSCRRD }, + { 0, 0x3b8, &D::FESD }, + { 0, 0x3b9, &D::FRDS }, + { 0, 0x3ba, &D::FSCRWR }, + { 0, 0x3bf, &D::DFTSV }, + { 0, 0x3c2, &D::FCEQ }, + { 0, 0x3c3, &D::DFCEQ }, + { 0, 0x3c4, &D::MPY }, + { 0, 0x3c5, &D::MPYH }, + { 0, 0x3c6, &D::MPYHH }, + { 0, 0x3c7, &D::MPYS }, + { 0, 0x3c8, &D::CEQH }, + { 0, 0x3ca, &D::FCMEQ }, + { 0, 0x3cb, &D::DFCMEQ }, + { 0, 0x3cc, &D::MPYU }, + { 0, 0x3d0, &D::CEQB }, + { 0, 0x3d4, &D::FI }, + { 0, 0x3d8, &D::HEQ }, + { 1, 0x1d8, &D::CFLTS }, + { 1, 0x1d9, &D::CFLTU }, + { 1, 0x1da, &D::CSFLT }, + { 1, 0x1db, &D::CUFLT }, + { 2, 0x40, &D::BRZ }, + { 2, 0x41, &D::STQA }, + { 2, 0x42, &D::BRNZ }, + { 2, 0x44, &D::BRHZ }, + { 2, 0x46, &D::BRHNZ }, + { 2, 0x47, &D::STQR }, + { 2, 0x60, &D::BRA }, + { 2, 0x61, &D::LQA }, + { 2, 0x62, &D::BRASL }, + { 2, 0x64, &D::BR }, + { 2, 0x65, &D::FSMBI }, + { 2, 0x66, &D::BRSL }, + { 2, 0x67, &D::LQR }, + { 2, 0x81, &D::IL }, + { 2, 0x82, &D::ILHU }, + { 2, 0x83, &D::ILH }, + { 2, 0xc1, &D::IOHL }, + { 3, 0x4, &D::ORI }, + { 3, 0x5, &D::ORHI }, + { 3, 0x6, &D::ORBI }, + { 3, 0xc, &D::SFI }, + { 3, 0xd, &D::SFHI }, + { 3, 0x14, &D::ANDI }, + { 3, 0x15, &D::ANDHI }, + { 3, 0x16, &D::ANDBI }, + { 3, 0x1c, &D::AI }, + { 3, 0x1d, &D::AHI }, + { 3, 0x24, &D::STQD }, + { 3, 0x34, &D::LQD }, + { 3, 0x44, &D::XORI }, + { 3, 0x45, &D::XORHI }, + { 3, 0x46, &D::XORBI }, + { 3, 0x4c, &D::CGTI }, + { 3, 0x4d, &D::CGTHI }, + { 3, 0x4e, &D::CGTBI }, + { 3, 0x4f, &D::HGTI }, + { 3, 0x5c, &D::CLGTI }, + { 3, 0x5d, &D::CLGTHI }, + { 3, 0x5e, &D::CLGTBI }, + { 3, 0x5f, &D::HLGTI }, + { 3, 0x74, &D::MPYI }, + { 3, 0x75, &D::MPYUI }, + { 3, 0x7c, &D::CEQI }, + { 3, 0x7d, &D::CEQHI }, + { 3, 0x7e, &D::CEQBI }, + { 3, 0x7f, &D::HEQI }, + { 4, 0x8, &D::HBRA }, + { 4, 0x9, &D::HBRR }, + { 4, 0x21, &D::ILA }, + { 7, 0x8, &D::SELB }, + { 7, 0xb, &D::SHUFB }, + { 7, 0xc, &D::MPYA }, + { 7, 0xd, &D::FNMS }, + { 7, 0xe, &D::FMA }, + { 7, 0xf, &D::FMS }, + }; + + m_table.fill(&D::UNK); + + for (auto& entry : instructions) + { + for (u32 i = 0; i < 1u << entry.magn; i++) + { + m_table[entry.value << entry.magn | i] = entry.pointer; + } + } + } + + const std::array& get_table() const + { + return m_table; + } + + T decode(u32 inst) const + { + return m_table[spu_decode(inst)]; + } +}; diff --git a/rpcs3/Emu/Cell/SPURecompiler.cpp b/rpcs3/Emu/Cell/SPURecompiler.cpp index c490b187ea..b6e635bfb2 100644 --- a/rpcs3/Emu/Cell/SPURecompiler.cpp +++ b/rpcs3/Emu/Cell/SPURecompiler.cpp @@ -8,39 +8,36 @@ extern u64 get_system_time(); -SPURecompilerDecoder::SPURecompilerDecoder(SPUThread& spu) - : db(fxm::get_always()) - , rec(fxm::get_always()) - , spu(spu) +void spu_recompiler_base::enter(SPUThread& spu) { -} - -u32 SPURecompilerDecoder::DecodeMemory(const u32 address) -{ - if (spu.offset != address - spu.pc || spu.pc >= 0x40000 || spu.pc % 4) + if (spu.pc >= 0x40000 || spu.pc % 4) { - throw EXCEPTION("Invalid address or PC (address=0x%x, PC=0x%05x)", address, spu.pc); + throw fmt::exception("Invalid PC: 0x%05x", spu.pc); } - // get SPU LS pointer + // Get SPU LS pointer const auto _ls = vm::ps3::_ptr(spu.offset); - // always validate (TODO) - const auto func = db->analyse(_ls, spu.pc); + // Always validate (TODO) + const auto func = spu.spu_db->analyse(_ls, spu.pc); - // reset callstack if necessary + // Reset callstack if necessary if (func->does_reset_stack && spu.recursion_level) { - spu.m_state |= CPU_STATE_RETURN; - - return 0; + spu.state += cpu_state::ret; + return; } if (!func->compiled) { - rec->compile(*func); + if (!spu.spu_rec) + { + spu.spu_rec = fxm::get_always(); + } - if (!func->compiled) throw EXCEPTION("Compilation failed"); + spu.spu_rec->compile(*func); + + if (!func->compiled) throw std::runtime_error("Compilation failed" HERE); } const u32 res = func->compiled(&spu, _ls); @@ -64,7 +61,7 @@ u32 SPURecompilerDecoder::DecodeMemory(const u32 address) { if (res & 0x8000000) { - throw EXCEPTION("Undefined behaviour"); + throw std::logic_error("Invalid interrupt status set" HERE); } spu.set_interrupt_status(true); @@ -75,6 +72,4 @@ u32 SPURecompilerDecoder::DecodeMemory(const u32 address) } spu.pc = res & 0x3fffc; - - return 0; } diff --git a/rpcs3/Emu/Cell/SPURecompiler.h b/rpcs3/Emu/Cell/SPURecompiler.h index 5ef15efc55..ed9b9aae64 100644 --- a/rpcs3/Emu/Cell/SPURecompiler.h +++ b/rpcs3/Emu/Cell/SPURecompiler.h @@ -1,12 +1,9 @@ #pragma once -#include "Emu/CPU/CPUDecoder.h" #include "SPUAnalyser.h" -class SPUThread; - // SPU Recompiler instance base (must be global or PS3 process-local) -class SPURecompilerBase +class spu_recompiler_base { protected: std::mutex m_mutex; // must be locked in compile() @@ -16,21 +13,11 @@ protected: u32 m_pos; // current position public: - virtual void compile(spu_function_t& f) = 0; // compile specified function - virtual ~SPURecompilerBase() {}; -}; - -// SPU Decoder instance (created per SPU thread) -class SPURecompilerDecoder final : public CPUDecoder -{ -public: - const std::shared_ptr db; // associated SPU Analyser instance - - const std::shared_ptr rec; // assiciated SPU Recompiler instance - - SPUThread& spu; // associated SPU Thread - - SPURecompilerDecoder(SPUThread& spu); - - u32 DecodeMemory(const u32 address) override; // non-virtual override (to avoid virtual call whenever possible) + virtual ~spu_recompiler_base() = default; + + // Compile specified function + virtual void compile(spu_function_t& f) = 0; + + // Run + static void enter(class SPUThread&); }; diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 5c92fae5f5..9bb9fdc4b6 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -1,15 +1,15 @@ #include "stdafx.h" +#include "Utilities/Config.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" -#include "Emu/state.h" #include "Emu/IdManager.h" #include "Emu/Cell/PPUThread.h" -#include "Emu/SysCalls/ErrorCodes.h" -#include "Emu/SysCalls/lv2/sys_spu.h" -#include "Emu/SysCalls/lv2/sys_event_flag.h" -#include "Emu/SysCalls/lv2/sys_event.h" -#include "Emu/SysCalls/lv2/sys_interrupt.h" +#include "Emu/Cell/ErrorCodes.h" +#include "Emu/Cell/lv2/sys_spu.h" +#include "Emu/Cell/lv2/sys_event_flag.h" +#include "Emu/Cell/lv2/sys_event.h" +#include "Emu/Cell/lv2/sys_interrupt.h" #include "Emu/Cell/SPUDisAsm.h" #include "Emu/Cell/SPUThread.h" @@ -20,8 +20,24 @@ extern u64 get_timebased_time(); -// defined here since SPUDisAsm.cpp doesn't exist -const spu_opcode_table_t SPUDisAsm::opcodes{ DEFINE_SPU_OPCODES(&SPUDisAsm::), &SPUDisAsm::UNK }; +enum class spu_decoder_type +{ + precise, + fast, + asmjit, + llvm, +}; + +cfg::map_entry g_cfg_spu_decoder(cfg::root.core, "SPU Decoder", 2, +{ + { "Interpreter (precise)", spu_decoder_type::precise }, + { "Interpreter (fast)", spu_decoder_type::fast }, + { "Recompiler (ASMJIT)", spu_decoder_type::asmjit }, + { "Recompiler (LLVM)", spu_decoder_type::llvm }, +}); + +const spu_decoder s_spu_interpreter_precise; +const spu_decoder s_spu_interpreter_fast; thread_local bool spu_channel_t::notification_required; @@ -31,7 +47,7 @@ void spu_int_ctrl_t::set(u64 ints) ints &= mask; // notify if at least 1 bit was set - if (ints && ~stat._or(ints) & ints && tag) + if (ints && ~stat.fetch_or(ints) & ints && tag) { LV2_LOCK; @@ -44,112 +60,23 @@ void spu_int_ctrl_t::set(u64 ints) } } -void spu_int_ctrl_t::clear(u64 ints) -{ - stat &= ~ints; -} - const spu_imm_table_t g_spu_imm; -SPUThread::SPUThread(CPUThreadType type, const std::string& name, u32 index, u32 offset) - : CPUThread(type, name) - , index(index) - , offset(offset) -{ -} - -SPUThread::SPUThread(const std::string& name, u32 index) - : CPUThread(CPU_THREAD_SPU, name) - , index(index) - , offset(vm::alloc(0x40000, vm::main)) -{ - CHECK_ASSERTION(offset); -} - -SPUThread::~SPUThread() -{ - // Deallocate Local Storage - vm::dealloc_verbose_nothrow(offset); -} - -bool SPUThread::is_paused() const -{ - if (CPUThread::is_paused()) - { - return true; - } - - if (const auto group = tg.lock()) - { - if (group->state >= SPU_THREAD_GROUP_STATUS_WAITING && group->state <= SPU_THREAD_GROUP_STATUS_SUSPENDED) - { - return true; - } - } - - return false; -} - std::string SPUThread::get_name() const { - return fmt::format("%s[0x%x] Thread (%s)[0x%05x]", CPUThread::GetTypeString(), m_id, CPUThread::get_name(), pc); + return fmt::format("%sSPU[0x%x] Thread (%s)", offset > RAW_SPU_BASE_ADDR ? "Raw" : "", id, name); } -void SPUThread::dump_info() const +std::string SPUThread::dump() const { - CPUThread::dump_info(); + std::string ret = "Registers:\n=========\n"; + + for (uint i = 0; i<128; ++i) ret += fmt::format("GPR[%d] = 0x%s\n", i, gpr[i].to_hex().c_str()); + + return ret; } -void SPUThread::cpu_task() -{ - std::fesetround(FE_TOWARDZERO); - - if (!custom_task && !m_dec) - { - // Select opcode table (TODO) - const auto& table = rpcs3::state.config.core.spu_decoder.value() == spu_decoder_type::interpreter_precise ? spu_interpreter::precise::g_spu_opcode_table : spu_interpreter::fast::g_spu_opcode_table; - - // LS base address - const auto base = vm::_ptr(offset); - - while (true) - { - if (!m_state) - { - // read opcode - const u32 opcode = base[pc / 4]; - - // call interpreter function - table[opcode](*this, { opcode }); - - // next instruction - pc += 4; - - continue; - } - - if (check_status()) - { - return; - } - } - } - - if (custom_task) - { - if (check_status()) return; - - return custom_task(*this); - } - - while (!m_state || !check_status()) - { - // decode instruction using specified decoder - pc += m_dec->DecodeMemory(pc + offset); - } -} - -void SPUThread::init_regs() +void SPUThread::cpu_init() { gpr = {}; fpscr.Reset(); @@ -190,75 +117,96 @@ void SPUThread::init_regs() gpr[1]._u32[3] = 0x3FFF0; // initial stack frame pointer } -void SPUThread::init_stack() +void SPUThread::cpu_task() { - // nothing to do -} + std::fesetround(FE_TOWARDZERO); -void SPUThread::close_stack() -{ - // nothing to do here -} - -void SPUThread::do_run() -{ - m_dec.reset(); - - switch (auto mode = rpcs3::state.config.core.spu_decoder.value()) + if (custom_task) { - case spu_decoder_type::interpreter_precise: // Interpreter 1 (Precise) - case spu_decoder_type::interpreter_fast: // Interpreter 2 (Fast) - { - break; + if (check_status()) return; + + return custom_task(*this); } - case spu_decoder_type::recompiler_asmjit: + _log::g_tls_make_prefix = [](const auto&, auto, const auto&) { - m_dec.reset(new SPURecompilerDecoder(*this)); - break; + const auto cpu = static_cast(get_current_cpu_thread()); + + return fmt::format("%s [0x%05x]", cpu->get_name(), cpu->pc); + }; + + if (g_cfg_spu_decoder.get() == spu_decoder_type::asmjit) + { + if (!spu_db) spu_db = fxm::get_always(); + return spu_recompiler_base::enter(*this); } - default: + // Select opcode table + const auto& table = *( + g_cfg_spu_decoder.get() == spu_decoder_type::precise ? &s_spu_interpreter_precise.get_table() : + g_cfg_spu_decoder.get() == spu_decoder_type::fast ? &s_spu_interpreter_fast.get_table() : + throw std::logic_error("Invalid SPU decoder")); + + // LS base address + const auto base = vm::_ptr(offset); + + while (true) { - LOG_ERROR(SPU, "Invalid SPU decoder mode: %d", (u8)mode); - Emu.Pause(); - } + if (!state.load()) + { + // Read opcode + const u32 op = base[pc / 4]; + + // Call interpreter function + table[spu_decode(op)](*this, { op }); + + // Next instruction + pc += 4; + continue; + } + + if (check_status()) return; } } -void SPUThread::fast_call(u32 ls_addr) +SPUThread::SPUThread(const std::string & name, u32 index) + : cpu_thread(cpu_type::spu, name) + , index(index) + , offset(vm::alloc(0x40000, vm::main)) { - if (!is_current()) + Ensures(offset); +} + +SPUThread::~SPUThread() +{ + // Deallocate Local Storage + vm::dealloc_verbose_nothrow(offset); +} + +void SPUThread::push_snr(u32 number, u32 value) +{ + // get channel + const auto channel = + number == 0 ? &ch_snr1 : + number == 1 ? &ch_snr2 : throw EXCEPTION("Unexpected"); + + // check corresponding SNR register settings + if ((snr_config >> number) & 1) { - throw EXCEPTION("Called from the wrong thread"); + channel->push_or(value); + } + else + { + channel->push(value); } - // LS:0x0: this is originally the entry point of the interrupt handler, but interrupts are not implemented - _ref(0) = 0x00000002; // STOP 2 - - auto old_pc = pc; - auto old_lr = gpr[0]._u32[3]; - auto old_stack = gpr[1]._u32[3]; // only saved and restored (may be wrong) - auto old_task = std::move(custom_task); - - pc = ls_addr; - gpr[0]._u32[3] = 0x0; - custom_task = nullptr; - - try + if (channel->notification_required) { - cpu_task(); - } - catch (CPUThreadReturn) - { - } + // lock for reliable notification + std::lock_guard lock(mutex); - m_state &= ~CPU_STATE_RETURN; - - pc = old_pc; - gpr[0]._u32[3] = old_lr; - gpr[1]._u32[3] = old_stack; - custom_task = std::move(old_task); + cv.notify_one(); + } } void SPUThread::do_dma_transfer(u32 cmd, spu_mfc_arg_t args) @@ -268,9 +216,9 @@ void SPUThread::do_dma_transfer(u32 cmd, spu_mfc_arg_t args) _mm_mfence(); } - u32 eal = VM_CAST(args.ea); + u32 eal = vm::cast(args.ea, HERE); - if (eal >= SYS_SPU_THREAD_BASE_LOW && m_type == CPU_THREAD_SPU) // SPU Thread Group MMIO (LS and SNR) + if (eal >= SYS_SPU_THREAD_BASE_LOW && offset >= RAW_SPU_BASE_ADDR) // SPU Thread Group MMIO (LS and SNR) { 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 @@ -413,7 +361,7 @@ void SPUThread::process_mfc_cmd(u32 cmd) break; } - const u32 raddr = VM_CAST(ch_mfc_args.ea); + const u32 raddr = vm::cast(ch_mfc_args.ea, HERE); vm::reservation_acquire(vm::base(offset + ch_mfc_args.lsa), raddr, 128); @@ -434,7 +382,7 @@ void SPUThread::process_mfc_cmd(u32 cmd) break; } - if (vm::reservation_update(VM_CAST(ch_mfc_args.ea), vm::base(offset + ch_mfc_args.lsa), 128)) + if (vm::reservation_update(vm::cast(ch_mfc_args.ea, HERE), vm::base(offset + ch_mfc_args.lsa), 128)) { if (last_raddr == 0) { @@ -466,9 +414,9 @@ void SPUThread::process_mfc_cmd(u32 cmd) break; } - vm::reservation_op(VM_CAST(ch_mfc_args.ea), 128, [this]() + vm::reservation_op(vm::cast(ch_mfc_args.ea, HERE), 128, [this]() { - std::memcpy(vm::base_priv(VM_CAST(ch_mfc_args.ea)), vm::base(offset + ch_mfc_args.lsa), 128); + std::memcpy(vm::base_priv(vm::cast(ch_mfc_args.ea, HERE)), vm::base(offset + ch_mfc_args.lsa), 128); }); if (last_raddr != 0 && vm::g_tls_did_break_reservation) @@ -539,7 +487,7 @@ void SPUThread::set_events(u32 mask) } // set new events, get old event mask - const u32 old_stat = ch_event_stat._or(mask); + const u32 old_stat = ch_event_stat.fetch_or(mask); // notify if some events were set if (~old_stat & mask && old_stat & SPU_EVENT_WAITING) @@ -617,7 +565,10 @@ u32 SPUThread::get_ch_value(u32 ch) CHECK_EMU_STATUS; - if (is_stopped()) throw CPUThreadStop{}; + if (state & cpu_state::stop) + { + throw cpu_state::stop; + } if (!lock) { @@ -658,7 +609,10 @@ u32 SPUThread::get_ch_value(u32 ch) CHECK_EMU_STATUS; - if (is_stopped()) throw CPUThreadStop{}; + if (state & cpu_state::stop) + { + throw cpu_state::stop; + } if (!lock) { @@ -723,14 +677,14 @@ u32 SPUThread::get_ch_value(u32 ch) if (ch_event_mask & SPU_EVENT_LR) { // register waiter if polling reservation status is required - vm::wait_op(*this, last_raddr, 128, WRAP_EXPR(get_events(true) || is_stopped())); + vm::wait_op(*this, last_raddr, 128, WRAP_EXPR(get_events(true) || state & cpu_state::stop)); } else { lock.lock(); // simple waiting loop otherwise - while (!get_events(true) && !is_stopped()) + while (!get_events(true) && !(state & cpu_state::stop)) { CHECK_EMU_STATUS; @@ -740,7 +694,10 @@ u32 SPUThread::get_ch_value(u32 ch) ch_event_stat &= ~SPU_EVENT_WAITING; - if (is_stopped()) throw CPUThreadStop{}; + if (state & cpu_state::stop) + { + throw cpu_state::stop; + } return get_events(); } @@ -767,7 +724,7 @@ void SPUThread::set_ch_value(u32 ch, u32 value) // break; case SPU_WrOutIntrMbox: { - if (m_type == CPU_THREAD_RAW_SPU) + if (offset >= RAW_SPU_BASE_ADDR) { std::unique_lock lock(mutex, std::defer_lock); @@ -775,7 +732,10 @@ void SPUThread::set_ch_value(u32 ch, u32 value) { CHECK_EMU_STATUS; - if (is_stopped()) throw CPUThreadStop{}; + if (state & cpu_state::stop) + { + throw cpu_state::stop; + } if (!lock) { @@ -824,12 +784,12 @@ void SPUThread::set_ch_value(u32 ch, u32 value) return ch_in_mbox.set_values(1, CELL_ENOTCONN); // TODO: check error passing } - if (queue->events.size() >= queue->size) + if (queue->events() >= queue->size) { return ch_in_mbox.set_values(1, CELL_EBUSY); } - queue->push(lv2_lock, SYS_SPU_THREAD_EVENT_USER_KEY, m_id, ((u64)spup << 32) | (value & 0x00ffffff), data); + queue->push(lv2_lock, SYS_SPU_THREAD_EVENT_USER_KEY, id, ((u64)spup << 32) | (value & 0x00ffffff), data); return ch_in_mbox.set_values(1, CELL_OK); } @@ -861,13 +821,13 @@ void SPUThread::set_ch_value(u32 ch, u32 value) } // TODO: check passing spup value - if (queue->events.size() >= queue->size) + if (queue->events() >= queue->size) { LOG_WARNING(SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x) failed (queue is full)", spup, (value & 0x00ffffff), data); return; } - queue->push(lv2_lock, SYS_SPU_THREAD_EVENT_USER_KEY, m_id, ((u64)spup << 32) | (value & 0x00ffffff), data); + queue->push(lv2_lock, SYS_SPU_THREAD_EVENT_USER_KEY, id, ((u64)spup << 32) | (value & 0x00ffffff), data); return; } else if (code == 128) @@ -979,7 +939,10 @@ void SPUThread::set_ch_value(u32 ch, u32 value) { CHECK_EMU_STATUS; - if (is_stopped()) throw CPUThreadStop{}; + if (state & cpu_state::stop) + { + throw cpu_state::stop; + } if (!lock) { @@ -1136,7 +1099,7 @@ void SPUThread::stop_and_signal(u32 code) { LOG_TRACE(SPU, "stop_and_signal(code=0x%x)", code); - if (m_type == CPU_THREAD_RAW_SPU) + if (offset >= RAW_SPU_BASE_ADDR) { status.atomic_op([code](u32& status) { @@ -1146,8 +1109,7 @@ void SPUThread::stop_and_signal(u32 code) }); int_ctrl[2].set(SPU_INT2_STAT_SPU_STOP_AND_SIGNAL_INT); - - return stop(); + throw cpu_state::stop; } switch (code) @@ -1160,7 +1122,7 @@ void SPUThread::stop_and_signal(u32 code) case 0x002: { - m_state |= CPU_STATE_RETURN; + state += cpu_state::ret; return; } @@ -1241,7 +1203,10 @@ void SPUThread::stop_and_signal(u32 code) { CHECK_EMU_STATUS; - if (is_stopped()) throw CPUThreadStop{}; + if (state & cpu_state::stop) + { + throw cpu_state::stop; + } group->cv.wait_for(lv2_lock, std::chrono::milliseconds(1)); } @@ -1253,7 +1218,10 @@ void SPUThread::stop_and_signal(u32 code) for (auto& thread : group->threads) { - if (thread) thread->sleep(); // trigger status check + if (thread) + { + thread->state += cpu_state::suspend; + } } } else @@ -1261,24 +1229,25 @@ void SPUThread::stop_and_signal(u32 code) throw EXCEPTION("Unexpected SPU Thread Group state (%d)", group->state); } - if (queue->events.size()) + if (queue->events()) { - auto& event = queue->events.front(); + const auto event = queue->pop(lv2_lock); ch_in_mbox.set_values(4, CELL_OK, static_cast(std::get<1>(event)), static_cast(std::get<2>(event)), static_cast(std::get<3>(event))); - - queue->events.pop_front(); } else { // add waiter; protocol is ignored in current implementation - sleep_queue_entry_t waiter(*this, queue->sq); + sleep_entry waiter(queue->thread_queue(lv2_lock), *this); // wait on the event queue - while (!unsignal()) + while (!state.test_and_reset(cpu_state::signal)) { CHECK_EMU_STATUS; - if (is_stopped()) throw CPUThreadStop{}; + if (state & cpu_state::stop) + { + throw cpu_state::stop; + } cv.wait(lv2_lock); } @@ -1302,9 +1271,14 @@ void SPUThread::stop_and_signal(u32 code) for (auto& thread : group->threads) { - if (thread) thread->awake(); // untrigger status check + if (thread && thread.get() != this) + { + thread->state -= cpu_state::suspend; + thread->safe_notify(); + } } + state -= cpu_state::suspend; group->cv.notify_all(); return; @@ -1338,7 +1312,8 @@ void SPUThread::stop_and_signal(u32 code) { if (thread && thread.get() != this) { - thread->stop(); + thread->state += cpu_state::stop; + thread->safe_notify(); } } @@ -1347,7 +1322,7 @@ void SPUThread::stop_and_signal(u32 code) group->join_state |= SPU_TGJSF_GROUP_EXIT; group->cv.notify_one(); - return stop(); + throw cpu_state::stop; } case 0x102: @@ -1373,7 +1348,7 @@ void SPUThread::stop_and_signal(u32 code) status |= SPU_STATUS_STOPPED_BY_STOP; group->cv.notify_one(); - return stop(); + throw cpu_state::stop; } } @@ -1391,7 +1366,7 @@ void SPUThread::halt() { LOG_TRACE(SPU, "halt()"); - if (m_type == CPU_THREAD_RAW_SPU) + if (offset >= RAW_SPU_BASE_ADDR) { status.atomic_op([](u32& status) { @@ -1401,18 +1376,41 @@ void SPUThread::halt() int_ctrl[2].set(SPU_INT2_STAT_SPU_HALT_OR_STEP_INT); - return stop(); + throw cpu_state::stop; } status |= SPU_STATUS_STOPPED_BY_HALT; throw EXCEPTION("Halt"); } -spu_thread::spu_thread(u32 entry, const std::string& name, u32 stack_size, u32 prio) +void SPUThread::fast_call(u32 ls_addr) { - auto spu = idm::make_ptr(name, 0x13370666); + // LS:0x0: this is originally the entry point of the interrupt handler, but interrupts are not implemented + _ref(0) = 0x00000002; // STOP 2 - spu->pc = entry; + auto old_pc = pc; + auto old_lr = gpr[0]._u32[3]; + auto old_stack = gpr[1]._u32[3]; // only saved and restored (may be wrong) + auto old_task = std::move(custom_task); - thread = std::move(spu); + pc = ls_addr; + gpr[0]._u32[3] = 0x0; + custom_task = nullptr; + + try + { + cpu_task(); + } + catch (cpu_state _s) + { + state += _s; + if (_s != cpu_state::ret) throw; + } + + state -= cpu_state::ret; + + pc = old_pc; + gpr[0]._u32[3] = old_lr; + gpr[1]._u32[3] = old_stack; + custom_task = std::move(old_task); } diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index c16547f3d6..7da16bfc7a 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -2,10 +2,10 @@ #include "Emu/Cell/Common.h" #include "Emu/CPU/CPUThread.h" -#include "Emu/Cell/SPUContext.h" +#include "Emu/Cell/SPUInterpreter.h" #include "MFC.h" -struct lv2_event_queue_t; +class lv2_event_queue_t; struct lv2_spu_group_t; struct lv2_int_tag_t; @@ -135,12 +135,20 @@ enum SPU_RdSigNotify2_offs = 0x1C00C, }; +enum : u32 +{ + RAW_SPU_BASE_ADDR = 0xE0000000, + RAW_SPU_OFFSET = 0x00100000, + RAW_SPU_LS_OFFSET = 0x00000000, + RAW_SPU_PROB_OFFSET = 0x00040000, +}; + struct spu_channel_t { // set to true if SPU thread must be notified after SPU channel operation thread_local static bool notification_required; - struct sync_var_t + struct alignas(8) sync_var_t { bool count; // value available bool wait; // notification required @@ -153,7 +161,7 @@ public: // returns true on success bool try_push(u32 value) { - const auto old = data.atomic_op([=](sync_var_t& data) + const auto old = data.fetch_op([=](sync_var_t& data) { if ((data.wait = data.count) == false) { @@ -168,7 +176,7 @@ public: // push performing bitwise OR with previous value, may require notification void push_or(u32 value) { - const auto old = data.atomic_op([=](sync_var_t& data) + const auto old = data.fetch_op([=](sync_var_t& data) { data.count = true; data.wait = false; @@ -181,7 +189,7 @@ public: // push unconditionally (overwriting previous value), may require notification void push(u32 value) { - const auto old = data.atomic_op([=](sync_var_t& data) + const auto old = data.fetch_op([=](sync_var_t& data) { data.count = true; data.wait = false; @@ -194,7 +202,7 @@ public: // returns true on success and loaded value std::tuple try_pop() { - const auto old = data.atomic_op([](sync_var_t& data) + const auto old = data.fetch_op([](sync_var_t& data) { data.wait = !data.count; data.count = false; @@ -207,7 +215,7 @@ public: // pop unconditionally (loading last value), may require notification u32 pop() { - const auto old = data.atomic_op([](sync_var_t& data) + const auto old = data.fetch_op([](sync_var_t& data) { data.wait = false; data.count = false; @@ -237,7 +245,7 @@ public: struct spu_channel_4_t { - struct sync_var_t + struct alignas(16) sync_var_t { struct { @@ -256,7 +264,7 @@ struct spu_channel_4_t public: void clear() { - values = sync_var_t{}; + values.store({}); value3 = 0; } @@ -333,7 +341,10 @@ struct spu_int_ctrl_t void set(u64 ints); - void clear(u64 ints); + void clear(u64 ints) + { + stat &= ~ints; + } void clear() { @@ -526,12 +537,27 @@ public: } }; -class SPUThread : public CPUThread +class SPUThread : public cpu_thread { - friend class SPURecompilerDecoder; - friend class spu_recompiler; +public: + virtual std::string get_name() const override; + virtual std::string dump() const override; + virtual void cpu_init() override; + virtual void cpu_task() override; + +protected: + SPUThread(const std::string& name) + : cpu_thread(cpu_type::spu, name) + , index(0) + , offset(0) + { + } public: + SPUThread(const std::string& name, u32 index); + + virtual ~SPUThread() override; + std::array gpr; // General-Purpose Registers SPU_FPSCR fpscr; @@ -578,32 +604,14 @@ public: const u32 index; // SPU index const u32 offset; // SPU LS offset - void push_snr(u32 number, u32 value) - { - // get channel - const auto channel = - number == 0 ? &ch_snr1 : - number == 1 ? &ch_snr2 : throw EXCEPTION("Unexpected"); + std::function custom_task; + std::exception_ptr pending_exception; - // check corresponding SNR register settings - if ((snr_config >> number) & 1) - { - channel->push_or(value); - } - else - { - channel->push(value); - } - - if (channel->notification_required) - { - // lock for reliable notification - std::lock_guard lock(mutex); - - cv.notify_one(); - } - } + std::shared_ptr spu_db; + std::shared_ptr spu_rec; + u32 recursion_level = 0; + void push_snr(u32 number, u32 value); void do_dma_transfer(u32 cmd, spu_mfc_arg_t args); void do_dma_list_cmd(u32 cmd, spu_mfc_arg_t args); void process_mfc_cmd(u32 cmd); @@ -618,14 +626,18 @@ public: void stop_and_signal(u32 code); void halt(); + void fast_call(u32 ls_addr); + // Convert specified SPU LS address to a pointer of specified (possibly converted to BE) type - template inline to_be_t* _ptr(u32 lsa) + template + inline to_be_t* _ptr(u32 lsa) { return static_cast*>(vm::base(offset + lsa)); } // Convert specified SPU LS address to a reference of specified (possibly converted to BE) type - template inline to_be_t& _ref(u32 lsa) + template + inline to_be_t& _ref(u32 lsa) { return *_ptr(lsa); } @@ -655,100 +667,4 @@ public: } } } - - std::function custom_task; - std::exception_ptr pending_exception; - u32 recursion_level = 0; - -protected: - SPUThread(CPUThreadType type, const std::string& name, u32 index, u32 offset); - -public: - SPUThread(const std::string& name, u32 index); - virtual ~SPUThread() override; - - virtual bool is_paused() const override; - - virtual std::string get_name() const override; - virtual void dump_info() const override; - virtual u32 get_pc() const override { return pc; } - virtual u32 get_offset() const override { return offset; } - virtual void do_run() override; - virtual void cpu_task() override; - - virtual void init_regs() override; - virtual void init_stack() override; - virtual void close_stack() override; - - void fast_call(u32 ls_addr); - - virtual std::string RegsToString() const override - { - std::string ret = "Registers:\n=========\n"; - - for(uint i=0; i<128; ++i) ret += fmt::format("GPR[%d] = 0x%s\n", i, gpr[i].to_hex().c_str()); - - return ret; - } - - virtual std::string ReadRegString(const std::string& reg) const override - { - std::string::size_type first_brk = reg.find('['); - if (first_brk != std::string::npos) - { - long reg_index; - reg_index = atol(reg.substr(first_brk + 1, reg.length()-2).c_str()); - if (reg.find("GPR")==0) return fmt::format("%016llx%016llx", gpr[reg_index]._u64[1], gpr[reg_index]._u64[0]); - } - return ""; - } - - bool WriteRegString(const std::string& reg, std::string value) override - { - while (value.length() < 32) value = "0"+value; - std::string::size_type first_brk = reg.find('['); - if (first_brk != std::string::npos) - { - long reg_index; - reg_index = atol(reg.substr(first_brk + 1, reg.length() - 2).c_str()); - if (reg.find("GPR")==0) - { - unsigned long long reg_value0; - unsigned long long reg_value1; - try - { - reg_value0 = std::stoull(value.substr(16, 31), 0, 16); - reg_value1 = std::stoull(value.substr(0, 15), 0, 16); - } - catch (std::invalid_argument& /*e*/) - { - return false; - } - gpr[reg_index]._u64[0] = (u64)reg_value0; - gpr[reg_index]._u64[1] = (u64)reg_value1; - return true; - } - } - return false; - } -}; - -class spu_thread : cpu_thread -{ -public: - spu_thread(u32 entry, const std::string& name = "", u32 stack_size = 0, u32 prio = 0); - - cpu_thread& args(std::initializer_list values) override - { - return *this; - } - - cpu_thread& run() override - { - auto& spu = static_cast(*thread); - - spu.run(); - - return *this; - } };