Partial commit: Cell

This commit is contained in:
Nekotekina
2016-04-14 02:09:41 +03:00
parent 42e1d4d752
commit c4e99dbdb2
32 changed files with 10685 additions and 12527 deletions
-13
View File
@@ -8,16 +8,3 @@ enum FPSCR_RN
FPSCR_RN_PINF = 2, FPSCR_RN_PINF = 2,
FPSCR_RN_MINF = 3, 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);
};
@@ -2,10 +2,13 @@
#define ERROR_CODE(code) static_cast<s32>(code) #define ERROR_CODE(code) static_cast<s32>(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_EAGAIN = ERROR_CODE(0x80010001), // The resource is temporarily unavailable
CELL_EINVAL = ERROR_CODE(0x80010002), // An invalid argument value is specified CELL_EINVAL = ERROR_CODE(0x80010002), // An invalid argument value is specified
CELL_ENOSYS = ERROR_CODE(0x80010003), // The feature is not yet implemented CELL_ENOSYS = ERROR_CODE(0x80010003), // The feature is not yet implemented
@@ -64,6 +67,146 @@ enum : s32
CELL_EOVERFLOW = ERROR_CODE(0x80010039), CELL_EOVERFLOW = ERROR_CODE(0x80010039),
CELL_ENOTMOUNTED = ERROR_CODE(0x8001003A), CELL_ENOTMOUNTED = ERROR_CODE(0x8001003A),
CELL_ENOTSDATA = ERROR_CODE(0x8001003B), 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<typename T>
static const char* print(T code)
{
return nullptr;
}
template<typename T>
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<typename T, typename = std::enable_if_t<std::is_enum<T>::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<s32>(value), std::nothrow }
template<typename T, typename>
struct ppu_gpr_cast_impl;
template<>
struct ppu_gpr_cast_impl<ppu_error_code, void>
{
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;
}
@@ -3,9 +3,8 @@
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/IdManager.h" #include "Emu/IdManager.h"
#include "Emu/Cell/PPUThread.h" #include "PPUThread.h"
#include "Emu/ARMv7/ARMv7Thread.h" #include "PPUCallback.h"
#include "Callback.h"
void CallbackManager::Register(check_cb_t func) 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<PPUThread>("Callback Thread");
{
auto thread = idm::make_ptr<PPUThread>("Callback Thread");
thread->prio = 1001; thread->prio = 1001;
thread->stack_size = 0x10000; thread->stack_size = 0x10000;
thread->custom_task = task; thread->custom_task = task;
thread->run(); thread->cpu_init();
m_cb_thread = thread; m_cb_thread = thread;
}
} }
void CallbackManager::Clear() void CallbackManager::Clear()
@@ -2,7 +2,7 @@
#include "Emu/Cell/PPUThread.h" #include "Emu/Cell/PPUThread.h"
namespace cb_detail namespace ppu_cb_detail
{ {
enum _func_arg_type enum _func_arg_type
{ {
@@ -10,7 +10,7 @@ namespace cb_detail
ARG_FLOAT, ARG_FLOAT,
ARG_VECTOR, ARG_VECTOR,
ARG_STACK, ARG_STACK,
ARG_CONTEXT, // for compatibility with SC_FUNC and CALL_FUNC ARG_CONTEXT,
ARG_UNKNOWN, ARG_UNKNOWN,
}; };
@@ -19,7 +19,7 @@ namespace cb_detail
// It's possible to calculate suitable stack frame size in template, but too complicated. // It's possible to calculate suitable stack frame size in template, but too complicated.
static const auto FIXED_STACK_FRAME_SIZE = 0x90; static const auto FIXED_STACK_FRAME_SIZE = 0x90;
template<typename T, _func_arg_type type, int g_count, int f_count, int v_count> template<typename T, _func_arg_type type, u32 g_count, u32 f_count, u32 v_count>
struct _func_arg struct _func_arg
{ {
static_assert(type == ARG_GENERAL, "Unknown callback argument type"); static_assert(type == ARG_GENERAL, "Unknown callback argument type");
@@ -27,50 +27,48 @@ namespace cb_detail
static_assert(!std::is_reference<T>::value, "Invalid callback argument type (reference)"); static_assert(!std::is_reference<T>::value, "Invalid callback argument type (reference)");
static_assert(sizeof(T) <= 8, "Invalid callback argument type for ARG_GENERAL"); 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<T>(arg); CPU.GPR[g_count + 2] = ppu_gpr_cast(arg);
} }
}; };
template<typename T, int g_count, int f_count, int v_count> template<typename T, u32 g_count, u32 f_count, u32 v_count>
struct _func_arg<T, ARG_FLOAT, g_count, f_count, v_count> struct _func_arg<T, ARG_FLOAT, g_count, f_count, v_count>
{ {
static_assert(sizeof(T) <= 8, "Invalid callback argument type for ARG_FLOAT"); 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<T>(arg); CPU.FPR[f_count] = static_cast<T>(arg);
} }
}; };
template<typename T, int g_count, int f_count, int v_count> template<typename T, u32 g_count, u32 f_count, u32 v_count>
struct _func_arg<T, ARG_VECTOR, g_count, f_count, v_count> struct _func_arg<T, ARG_VECTOR, g_count, f_count, v_count>
{ {
static_assert(std::is_same<std::remove_cv_t<T>, v128>::value, "Invalid callback argument type for ARG_VECTOR"); static_assert(std::is_same<CV T, CV v128>::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<typename T, int g_count, int f_count, int v_count> template<typename T, u32 g_count, u32 f_count, u32 v_count>
struct _func_arg<T, ARG_STACK, g_count, f_count, v_count> struct _func_arg<T, ARG_STACK, g_count, f_count, v_count>
{ {
static_assert(f_count <= 13, "TODO: Unsupported stack argument type (float)"); static_assert(alignof(T) <= 16, "Unsupported callback argument type alignment for ARG_STACK");
static_assert(v_count <= 12, "TODO: Unsupported stack argument type (vector)");
static_assert(sizeof(T) <= 8, "Invalid callback argument type 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; 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)"); 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<T>(arg)); vm::ps3::write64(CPU.GPR[1] + stack_pos, ppu_gpr_cast(arg)); // TODO
} }
}; };
template<typename T, int g_count, int f_count, int v_count> template<typename T, u32 g_count, u32 f_count, u32 v_count>
struct _func_arg<T, ARG_CONTEXT, g_count, f_count, v_count> struct _func_arg<T, ARG_CONTEXT, g_count, f_count, v_count>
{ {
static_assert(std::is_same<T, PPUThread&>::value, "Invalid callback argument type for ARG_CONTEXT"); static_assert(std::is_same<T, PPUThread&>::value, "Invalid callback argument type for ARG_CONTEXT");
@@ -80,18 +78,18 @@ namespace cb_detail
} }
}; };
template<int g_count, int f_count, int v_count> template<u32 g_count, u32 f_count, u32 v_count>
force_inline static bool _bind_func_args(PPUThread& CPU) force_inline static bool _bind_func_args(PPUThread& CPU)
{ {
// terminator // terminator
return false; return false;
} }
template<int g_count, int f_count, int v_count, typename T1, typename... T> template<u32 g_count, u32 f_count, u32 v_count, typename T1, typename... T>
force_inline static bool _bind_func_args(PPUThread& CPU, T1 arg1, T... args) force_inline static bool _bind_func_args(PPUThread& CPU, T1 arg1, T... args)
{ {
const bool is_float = std::is_floating_point<T1>::value; const bool is_float = std::is_floating_point<T1>::value;
const bool is_vector = std::is_same<std::remove_cv_t<T1>, v128>::value; const bool is_vector = std::is_same<CV T1, CV v128>::value;
const bool is_context = std::is_same<T1, PPUThread&>::value; const bool is_context = std::is_same<T1, PPUThread&>::value;
const bool is_general = !is_float && !is_vector && !is_context; const bool is_general = !is_float && !is_vector && !is_context;
@@ -102,9 +100,9 @@ namespace cb_detail
is_context ? ARG_CONTEXT : is_context ? ARG_CONTEXT :
ARG_UNKNOWN; ARG_UNKNOWN;
const int g = g_count + is_general; const u32 g = g_count + (is_general || is_float ? 1 : is_vector ? ::align(g_count, 2) + 2 : 0);
const int f = f_count + is_float; const u32 f = f_count + is_float;
const int v = v_count + is_vector; const u32 v = v_count + is_vector;
_func_arg<T1, t, g, f, v>::set_value(CPU, arg1); _func_arg<T1, t, g, f, v>::set_value(CPU, arg1);
@@ -120,7 +118,7 @@ namespace cb_detail
force_inline static T get_value(const PPUThread& CPU) force_inline static T get_value(const PPUThread& CPU)
{ {
return cast_from_ppu_gpr<T>(CPU.GPR[3]); return ppu_gpr_cast<T>(CPU.GPR[3]);
} }
}; };
@@ -138,11 +136,11 @@ namespace cb_detail
template<typename T> template<typename T>
struct _func_res<T, ARG_VECTOR> struct _func_res<T, ARG_VECTOR>
{ {
static_assert(std::is_same<std::remove_cv_t<T>, v128>::value, "Invalid callback result type for ARG_VECTOR"); static_assert(std::is_same<CV T, CV v128>::value, "Invalid callback result type for ARG_VECTOR");
force_inline static T get_value(const PPUThread& CPU) 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) 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...); const bool stack = _bind_func_args<0, 0, 0, T...>(CPU, args...);
if (stack) CPU.GPR[1] -= FIXED_STACK_FRAME_SIZE; CPU.GPR[1] -= stack ? FIXED_STACK_FRAME_SIZE : 0x30; // create reserved area
CPU.GPR[1] -= 0x70; // create reserved area
CPU.fast_call(pc, rtoc); CPU.fast_call(pc, rtoc);
CPU.GPR[1] += 0x70; CPU.GPR[1] += stack ? FIXED_STACK_FRAME_SIZE : 0x30;
if (stack) CPU.GPR[1] += FIXED_STACK_FRAME_SIZE;
} }
}; };
} }
@@ -183,15 +179,44 @@ namespace vm
template<typename AT, typename RT, typename... T> template<typename AT, typename RT, typename... T>
force_inline RT _ptr_base<RT(T...), AT>::operator()(PPUThread& CPU, T... args) const force_inline RT _ptr_base<RT(T...), AT>::operator()(PPUThread& CPU, T... args) const
{ {
const auto data = vm::ps3::_ptr<u32>(VM_CAST(m_addr)); const auto data = vm::ps3::_ptr<u32>(vm::cast(m_addr, HERE));
const u32 pc = data[0]; const u32 pc = data[0];
const u32 rtoc = data[1]; const u32 rtoc = data[1];
return cb_detail::_func_caller<RT, T...>::call(CPU, pc, rtoc, args...); return ppu_cb_detail::_func_caller<RT, T...>::call(CPU, pc, rtoc, args...);
} }
} }
template<typename RT, typename... T> inline RT cb_call(PPUThread& CPU, u32 pc, u32 rtoc, T... args) template<typename RT, typename... T> inline RT cb_call(PPUThread& CPU, u32 pc, u32 rtoc, T... args)
{ {
return cb_detail::_func_caller<RT, T...>::call(CPU, pc, rtoc, args...); return ppu_cb_detail::_func_caller<RT, T...>::call(CPU, pc, rtoc, args...);
} }
#include <queue>
class CallbackManager
{
using check_cb_t = std::function<s32(PPUThread&)>;
using async_cb_t = std::function<void(PPUThread&)>;
std::mutex m_mutex;
std::queue<check_cb_t> m_check_cb;
std::queue<async_cb_t> m_async_cb;
std::shared_ptr<PPUThread> 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();
};
File diff suppressed because it is too large Load Diff
+389 -1843
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,14 +1,14 @@
#pragma once #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 struct ppu_va_args_t
{ {
u32 g_count; u32 count; // Number of 64-bit args passed
u32 f_count;
u32 v_count;
}; };
namespace ppu_func_detail namespace ppu_func_detail
@@ -16,12 +16,12 @@ namespace ppu_func_detail
// argument type classification // argument type classification
enum arg_class : u32 enum arg_class : u32
{ {
ARG_GENERAL, // argument is stored in GPR registers (from r3 to r10) ARG_GENERAL, // argument stored in GPR (from r3 to r10)
ARG_FLOAT, // argument is stored in FPR registers (from f1 to f13) ARG_FLOAT, // argument stored in FPR (from f1 to f13)
ARG_VECTOR, // argument is stored in VPR registers (from v2 to v13) ARG_VECTOR, // argument stored in VR (from v2 to v13)
ARG_STACK, // argument is stored on the stack ARG_STACK, // argument stored on the stack
ARG_CONTEXT, // PPUThread& passed, doesn't affect g/f/v_count 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, ARG_UNKNOWN,
}; };
@@ -33,9 +33,9 @@ namespace ppu_func_detail
static_assert(!std::is_reference<T>::value, "Invalid function argument type (reference)"); static_assert(!std::is_reference<T>::value, "Invalid function argument type (reference)");
static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_GENERAL"); 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<T>(ppu.GPR[g_count + 2]); return ppu_gpr_cast<T>(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_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<T>(ppu.FPR[f_count]); return static_cast<T>(ppu.FPR[f_count]);
} }
@@ -53,26 +53,22 @@ namespace ppu_func_detail
template<typename T, u32 g_count, u32 f_count, u32 v_count> template<typename T, u32 g_count, u32 f_count, u32 v_count>
struct bind_arg<T, ARG_VECTOR, g_count, f_count, v_count> struct bind_arg<T, ARG_VECTOR, g_count, f_count, v_count>
{ {
static_assert(std::is_same<std::remove_cv_t<T>, v128>::value, "Invalid function argument type for ARG_VECTOR"); static_assert(std::is_same<CV T, CV v128>::value, "Invalid function argument type for ARG_VECTOR");
static force_inline T get_arg(PPUThread& ppu) static force_inline T get_arg(PPUThread& ppu)
{ {
return ppu.VPR[v_count + 1]; return ppu.VR[v_count + 1];
} }
}; };
template<typename T, u32 g_count, u32 f_count, u32 v_count> template<typename T, u32 g_count, u32 f_count, u32 v_count>
struct bind_arg<T, ARG_STACK, g_count, f_count, v_count> struct bind_arg<T, ARG_STACK, g_count, f_count, v_count>
{ {
static_assert(f_count <= 13, "TODO: Unsupported stack argument type (float)"); static_assert(alignof(T) <= 16, "Unsupported type alignment for ARG_STACK");
static_assert(v_count <= 12, "TODO: Unsupported stack argument type (vector)");
static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_STACK");
static force_inline T get_arg(PPUThread& ppu) static force_inline T get_arg(PPUThread& ppu)
{ {
// TODO: check stack argument displacement return ppu_gpr_cast<T, u64>(*ppu.get_stack_arg(g_count, alignof(T))); // TODO
const u64 res = ppu.get_stack_arg(8 + std::max<s32>(g_count - 8, 0) + std::max<s32>(f_count - 13, 0) + std::max<s32>(v_count - 12, 0));
return cast_from_ppu_gpr<T>(res);
} }
}; };
@@ -94,7 +90,7 @@ namespace ppu_func_detail
static force_inline ppu_va_args_t get_arg(PPUThread& ppu) 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) static force_inline void put_result(PPUThread& ppu, const T& result)
{ {
ppu.GPR[3] = cast_to_ppu_gpr<T>(result); ppu.GPR[3] = ppu_gpr_cast(result);
} }
}; };
@@ -124,11 +120,11 @@ namespace ppu_func_detail
template<typename T> template<typename T>
struct bind_result<T, ARG_VECTOR> struct bind_result<T, ARG_VECTOR>
{ {
static_assert(std::is_same<std::remove_cv_t<T>, v128>::value, "Invalid function result type for ARG_VECTOR"); static_assert(std::is_same<CV T, CV v128>::value, "Invalid function result type for ARG_VECTOR");
static force_inline void put_result(PPUThread& ppu, const T& result) 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 // TODO: check calculations
const bool is_float = std::is_floating_point<T>::value; const bool is_float = std::is_floating_point<T>::value;
const bool is_vector = std::is_same<std::remove_cv_t<T>, v128>::value; const bool is_vector = std::is_same<CV T, CV v128>::value;
const bool is_context = std::is_same<T, PPUThread&>::value; const bool is_context = std::is_same<T, PPUThread&>::value;
const bool is_variadic = std::is_same<std::remove_cv_t<T>, ppu_va_args_t>::value; const bool is_variadic = std::is_same<CV T, CV ppu_va_args_t>::value;
const bool is_general = !is_float && !is_vector && !is_context && !is_variadic; const bool is_general = !is_float && !is_vector && !is_context && !is_variadic;
const arg_class t = const arg_class t =
@@ -189,19 +185,20 @@ namespace ppu_func_detail
is_variadic ? ARG_VARIADIC : is_variadic ? ARG_VARIADIC :
ARG_UNKNOWN; 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 f = f_count + is_float;
const u32 v = v_count + is_vector; const u32 v = v_count + is_vector;
return call<Types...>(ppu, func, arg_info_pack_t<Info..., t | (g << 8) | (f << 16) | (v << 24)>{}); return call<Types...>(ppu, func, arg_info_pack_t<Info..., t | (g << 8) | (f << 16) | (v << 24)>{});
} }
template<typename RT> struct result_type template<typename RT>
struct result_type
{ {
static_assert(!std::is_pointer<RT>::value, "Invalid function result type (pointer)"); static_assert(!std::is_pointer<RT>::value, "Invalid function result type (pointer)");
static_assert(!std::is_reference<RT>::value, "Invalid function result type (reference)"); static_assert(!std::is_reference<RT>::value, "Invalid function result type (reference)");
static const bool is_float = std::is_floating_point<RT>::value; static const bool is_float = std::is_floating_point<RT>::value;
static const bool is_vector = std::is_same<std::remove_cv_t<RT>, v128>::value; static const bool is_vector = std::is_same<CV RT, CV v128>::value;
static const arg_class value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL); static const arg_class value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL);
}; };
@@ -229,10 +226,66 @@ namespace ppu_func_detail
} }
}; };
template<typename RT, typename... T> force_inline void do_call(PPUThread& ppu, RT(*func)(T...)) template<typename RT, typename... T>
force_inline void do_call(PPUThread& ppu, RT(*func)(T...))
{ {
func_binder<RT, T...>::do_call(ppu, func); func_binder<RT, T...>::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<typename T, T Func>
struct registered
{
static u32 index;
};
// Access global function list
static never_inline auto& access()
{
static std::vector<ppu_function_t> 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<typename T, T Func>
static inline u32 register_function(ppu_function_t func)
{
return registered<T, Func>::index = add_function(func);
}
// Get function index
template<typename T, T Func>
static inline u32 get_index()
{
return registered<T, Func>::index;
}
// Read all registered functions
static inline const auto& get()
{
return access();
}
};
template<typename T, T Func>
u32 ppu_function_manager::registered<T, Func>::index = 0;
#define FIND_FUNC(func) ppu_function_manager::get_index<decltype(&func), &func>()
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-870
View File
@@ -1,870 +0,0 @@
#pragma once
#include "PPUOpcodes.h"
class PPUThread;
union ppu_opcode_t
{
u32 opcode;
bf_t<u32, 32 - 1 - 30, 1> shh; // 30
bf_t<u32, 32 - 1 - 26, 1> mbmeh; // 26
bf_t<u32, 32 - 5 - 21, 5> mbmel; // 21..25
bf_t<u32, 32 - 5 - 16, 5> shl; // 16..20
bf_t<u32, 32 - 5 - 11, 5> vuimm; // 11..15
bf_t<u32, 32 - 5 - 6, 5> vs; // 6..10
bf_t<u32, 32 - 4 - 22, 4> vsh; // 22..25
bf_t<u32, 32 - 1 - 21, 1> oe; // 21
bf_t<u32, 32 - 10 - 11, 10> spr; // 11..20
bf_t<u32, 32 - 5 - 21, 5> vc; // 21..25
bf_t<u32, 32 - 5 - 16, 5> vb; // 16..20
bf_t<u32, 32 - 5 - 11, 5> va; // 11..15
bf_t<u32, 32 - 5 - 6, 5> vd; // 6..10
bf_t<u32, 32 - 1 - 31, 1> lk; // 31
bf_t<u32, 32 - 1 - 30, 1> aa; // 30
bf_t<u32, 32 - 5 - 16, 5> rb; // 16..20
bf_t<u32, 32 - 5 - 11, 5> ra; // 11..15
bf_t<u32, 32 - 5 - 6, 5> rd; // 6..10
bf_t<u32, 32 - 16 - 16, 16> uimm16; // 16..31
bf_t<u32, 32 - 1 - 11, 1> l11; // 11
bf_t<u32, 32 - 5 - 6, 5> rs; // 6..10
bf_t<s32, 32 - 16 - 16, 16> simm16; // 16..31, signed
bf_t<s32, 32 - 5 - 11, 5> vsimm; // 11..15, signed
bf_t<s32, 32 - 26 - 6, 26> ll; // 6..31, signed
bf_t<u32, 32 - 7 - 20, 7> lev; // 20..26
bf_t<u32, 32 - 4 - 16, 4> i; // 16..19
bf_t<u32, 32 - 3 - 11, 3> crfs; // 11..13
bf_t<u32, 32 - 1 - 10, 1> l10; // 10
bf_t<u32, 32 - 3 - 6, 3> crfd; // 6..8
bf_t<u32, 32 - 5 - 16, 5> crbb; // 16..20
bf_t<u32, 32 - 5 - 11, 5> crba; // 11..15
bf_t<u32, 32 - 5 - 6, 5> crbd; // 6..10
bf_t<u32, 32 - 1 - 31, 1> rc; // 31
bf_t<u32, 32 - 5 - 26, 5> me; // 26..30
bf_t<u32, 32 - 5 - 21, 5> mb; // 21..25
bf_t<u32, 32 - 5 - 16, 5> sh; // 16..20
bf_t<u32, 32 - 5 - 11, 5> bi; // 11..15
bf_t<u32, 32 - 5 - 6, 5> bo; // 6..10
bf_t<u32, 32 - 5 - 21, 5> frc; // 21..25
bf_t<u32, 32 - 5 - 16, 5> frb; // 16..20
bf_t<u32, 32 - 5 - 11, 5> fra; // 11..15
bf_t<u32, 32 - 5 - 6, 5> frd; // 6..10
bf_t<u32, 32 - 8 - 12, 8> crm; // 12..19
bf_t<u32, 32 - 5 - 6, 5> frs; // 6..10
bf_t<u32, 32 - 8 - 7, 8> 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; }
};
File diff suppressed because it is too large Load Diff
+255
View File
@@ -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<void>* 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<u32, ppu_static_function> functions;
std::unordered_map<u32, ppu_static_variable> 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<std::string, ppu_static_module*> 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<typename T, T Func>
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<T, Func>(func);
info.flags = flags;
}
template<typename T, T* Var>
static void register_static_variable(const char* module, const char* name, u32 vnid, void(*init)())
{
static_assert(std::is_same<CV u32, CV typename T::addr_type>::value, "Static variable registration: vm::gvar<T> expected");
auto& info = access_static_variable(module, vnid);
info.name = name;
info.var = reinterpret_cast<vm::gvar<void>*>(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<typename T, T Func, typename... Args, typename RT = std::result_of_t<T(Args...)>>
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>(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<decltype(&func), &func>(#func, ppu, __VA_ARGS__)
#define REG_FNID(module, nid, func, ...) ppu_module_manager::register_static_function<decltype(&func), &func>(#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<decltype(var), &var>(#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__)
File diff suppressed because it is too large Load Diff
+110 -301
View File
@@ -1,108 +1,62 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/state.h"
#include "Emu/IdManager.h" #include "Emu/IdManager.h"
#include "Emu/Cell/PPUThread.h" #include "PPUThread.h"
#include "Emu/Cell/PPUDecoder.h" #include "PPUInterpreter.h"
#include "Emu/Cell/PPUInterpreter.h" #include "PPUModule.h"
#include "Emu/Cell/PPUInterpreter2.h"
#include "Emu/Cell/PPULLVMRecompiler.h"
//#include "Emu/Cell/PPURecompiler.h"
#include "Utilities/VirtualMemory.h"
#ifdef _WIN32 enum class ppu_decoder_type
#include <Windows.h>
#else
#include <sys/mman.h>
#include <sys/stat.h>
#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<ppu_decoder_cache_t> g_tls_ppu_decoder_cache = fxm::get<ppu_decoder_cache_t>();
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<decltype(pointer)>(memory_helper::reserve_memory(0x200000000)))
{ {
} precise,
fast,
llvm,
};
ppu_decoder_cache_t::~ppu_decoder_cache_t() cfg::map_entry<ppu_decoder_type> 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) const ppu_decoder<ppu_interpreter_precise> s_ppu_interpreter_precise;
{ const ppu_decoder<ppu_interpreter_fast> s_ppu_interpreter_fast;
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);
}
std::string PPUThread::get_name() const 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) 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]);
LOG_SUCCESS(HLE, "Last syscall: %lld (%s)", ~hle_code, get_ps3_function_name(hle_code)); 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());
else if (hle_code) ret += fmt::format("LR = 0x%llx\n", LR);
{ ret += fmt::format("CTR = 0x%llx\n", CTR);
LOG_SUCCESS(HLE, "Last function: %s (0x%llx)", get_ps3_function_name(hle_code), hle_code); 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() void PPUThread::cpu_init()
{
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()
{ {
if (!stack_addr) if (!stack_addr)
{ {
@@ -118,14 +72,70 @@ void PPUThread::init_stack()
throw EXCEPTION("Out of stack memory"); 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); if (check_status()) return;
stack_addr = 0;
return custom_task(*this);
}
_log::g_tls_make_prefix = [](const auto&, auto, const auto&)
{
const auto cpu = static_cast<PPUThread*>(get_current_cpu_thread());
return fmt::format("%s [0x%08x]", cpu->get_name(), cpu->PC);
};
const auto base = vm::_ptr<const u8>(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<const be_t<u32>*>(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<const be_t<u32>*>(base + _pc);
func0 = table[ppu_decode(op0 = ops[0])];
func1 = table[ppu_decode(op1 = ops[1])];
func2 = table[ppu_decode(op2 = ops[2])];
if (check_status()) return;
} }
} }
@@ -134,99 +144,28 @@ bool PPUThread::handle_interrupt()
return false; return false;
} }
void PPUThread::do_run() PPUThread::~PPUThread()
{ {
m_dec.reset(); if (stack_addr)
switch (auto mode = rpcs3::state.config.core.ppu_decoder.value())
{ {
case ppu_decoder_type::interpreter: // original interpreter vm::dealloc_verbose_nothrow(stack_addr, vm::stack);
{
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();
}
} }
} }
bool FPRdouble::IsINF(PPCdouble d) be_t<u64>* PPUThread::get_stack_arg(s32 i, u64 align)
{ {
return ((u64&)d & 0x7FFFFFFFFFFFFFFFULL) == 0x7FF0000000000000ULL; if (align != 1 && align != 2 && align != 4 && align != 8 && align != 16) throw fmt::exception("Unsupported alignment: 0x%llx" HERE, align);
} return vm::_ptr<u64>(vm::cast((GPR[1] + 0x30 + 0x8 * (i - 1)) & (0 - align), HERE));
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)));
} }
void PPUThread::fast_call(u32 addr, u32 rtoc) void PPUThread::fast_call(u32 addr, u32 rtoc)
{ {
if (!is_current())
{
throw EXCEPTION("Called from the wrong thread");
}
auto old_PC = PC; auto old_PC = PC;
auto old_stack = GPR[1]; auto old_stack = GPR[1];
auto old_rtoc = GPR[2]; auto old_rtoc = GPR[2];
auto old_LR = LR; auto old_LR = LR;
auto old_task = std::move(custom_task); auto old_task = std::move(custom_task);
assert(!old_task || !custom_task);
PC = addr; PC = addr;
GPR[2] = rtoc; GPR[2] = rtoc;
LR = Emu.GetCPUThreadStop(); LR = Emu.GetCPUThreadStop();
@@ -236,11 +175,13 @@ void PPUThread::fast_call(u32 addr, u32 rtoc)
{ {
cpu_task(); 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; PC = old_PC;
@@ -253,135 +194,3 @@ void PPUThread::fast_call(u32 addr, u32 rtoc)
LR = old_LR; LR = old_LR;
custom_task = std::move(old_task); 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<ppu_decoder_cache_t>();
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<PPUThread>(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<std::string> 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<PPUThread&>(*thread).GPR[index] = value;
return *this;
}
+107 -919
View File
File diff suppressed because it is too large Load Diff
+29 -16
View File
@@ -1,17 +1,27 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/Callback.h" #include "Emu/IdManager.h"
#include "Loader/ELF.h"
#include "Emu/Cell/RawSPUThread.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) // 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] = {}; thread_local spu_mfc_arg_t raw_spu_mfc[8] = {};
RawSPUThread::RawSPUThread(const std::string& name, u32 index) void RawSPUThread::cpu_task()
: SPUThread(CPU_THREAD_RAW_SPU, name, index, RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index)
{ {
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) 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) else if (value == SPU_RUNCNTL_STOP_REQUEST)
{ {
status &= ~SPU_STATUS_RUNNING; status &= ~SPU_STATUS_RUNNING;
stop(); state += cpu_state::stop;
} }
else else
{ {
@@ -221,17 +232,19 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value)
return false; return false;
} }
void RawSPUThread::cpu_task() template<>
void spu_exec_loader::load() const
{ {
// get next PC and SPU Interrupt status auto spu = idm::make_ptr<RawSPUThread>("TEST_SPU");
pc = npc.exchange(0);
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; spu->cpu_init();
spu->npc = header.e_entry;
SPUThread::cpu_task();
// save next PC and current SPU Interrupt status
npc = pc | ((ch_event_stat & SPU_EVENT_INTR_ENABLED) != 0);
} }
+26 -17
View File
@@ -2,27 +2,36 @@
#include "SPUThread.h" #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 class RawSPUThread final : public SPUThread
{ {
void cpu_task() override;
public: 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<u32&>(index) = id;
const_cast<u32&>(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 read_reg(const u32 addr, u32& value);
bool write_reg(const u32 addr, const u32 value); bool write_reg(const u32 addr, const u32 value);
private:
virtual void cpu_task() override;
}; };
+18 -20
View File
@@ -1,4 +1,5 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "SPUDisAsm.h" #include "SPUDisAsm.h"
@@ -9,10 +10,6 @@
#define ASMJIT_STATIC #define ASMJIT_STATIC
#define ASMJIT_DEBUG #define ASMJIT_DEBUG
#ifdef _MSC_VER
#pragma comment(lib, "asmjit.lib")
#endif
#include "asmjit.h" #include "asmjit.h"
#define SPU_OFF_128(x) asmjit::host::oword_ptr(*cpu, OFFSET_32(SPUThread, x)) #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_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)) #define SPU_OFF_8(x) asmjit::host::byte_ptr(*cpu, OFFSET_32(SPUThread, x))
const spu_decoder<spu_interpreter_fast> s_spu_interpreter; // TODO: remove
const spu_decoder<spu_recompiler> s_spu_decoder;
spu_recompiler::spu_recompiler() spu_recompiler::spu_recompiler()
: m_jit(std::make_shared<asmjit::JitRuntime>()) : m_jit(std::make_shared<asmjit::JitRuntime>())
{ {
@@ -29,7 +29,7 @@ spu_recompiler::spu_recompiler()
LOG_SUCCESS(SPU, "SPU Recompiler (ASMJIT) created..."); 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) void spu_recompiler::compile(spu_function_t& f)
@@ -145,13 +145,13 @@ void spu_recompiler::compile(spu_function_t& f)
// Disasm // Disasm
dis_asm.dump_pc = m_pos; dis_asm.dump_pc = m_pos;
dis_asm.do_disasm(op); dis_asm.disasm(m_pos);
compiler.addComment(dis_asm.last_opcode.c_str()); compiler.addComment(dis_asm.last_opcode.c_str());
log += dis_asm.last_opcode.c_str(); log += dis_asm.last_opcode.c_str();
log += '\n'; log += '\n';
// Recompiler function // Recompiler function
(this->*spu_recompiler::opcodes[op])({ op }); (this->*s_spu_decoder.decode(op))({ op });
// Collect allocated xmm vars // Collect allocated xmm vars
for (u32 i = 0; i < vec_vars.size(); i++) 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"; log += "\n\n\n";
// Append log file // 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 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; const u32 old_pc = _spu->pc;
if (_spu->m_state && _spu->check_status()) if (_spu->state.load() && _spu->check_status())
{ {
return 0x2000000 | _spu->pc; 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<void*, u32(SPUThread*, u32, spu_inter_func_t)>(gate)), asmjit::kFuncConvHost, asmjit::FuncBuilder3<u32, void*, u32, void*>()); asmjit::X86CallNode* call = c->call(asmjit::imm_ptr(asmjit_cast<void*, u32(SPUThread*, u32, spu_inter_func_t)>(gate)), asmjit::kFuncConvHost, asmjit::FuncBuilder3<u32, void*, u32, void*>());
call->setArg(0, *cpu); call->setArg(0, *cpu);
call->setArg(1, asmjit::imm_u(op.opcode)); call->setArg(1, asmjit::imm_u(op.opcode));
call->setArg(2, asmjit::imm_ptr(asmjit_cast<void*>(spu_interpreter::fast::g_spu_opcode_table[op.opcode]))); call->setArg(2, asmjit::imm_ptr(asmjit_cast<void*>(s_spu_interpreter.decode(op.opcode))));
call->setRet(0, *addr); call->setRet(0, *addr);
// return immediately if an error occured // return immediately if an error occured
@@ -338,21 +338,20 @@ void spu_recompiler::FunctionCall()
LOG_ERROR(SPU, "Branch-to-self"); 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 // Proceed recursively
static_cast<SPURecompilerDecoder&>(*_spu->m_dec).DecodeMemory(_spu->offset + _spu->pc); spu_recompiler_base::enter(*_spu);
if (_spu->m_state & CPU_STATE_RETURN) if (_spu->state & cpu_state::ret)
{ {
break; break;
} }
if (_spu->pc == link) if (_spu->pc == link)
{ {
// returned successfully
_spu->recursion_level--; _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->mov(*addr, target | 0x2000000);
//c->cmp(asmjit::host::dword_ptr(*ls, m_pos), 0x32); // compare instruction opcode with BR-to-self //c->cmp(asmjit::host::dword_ptr(*ls, m_pos), 0x32); // compare instruction opcode with BR-to-self
//c->je(labels[target / 4]); //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->jmp(*end);
c->unuse(*addr); c->unuse(*addr);
return; return;
@@ -2614,7 +2613,6 @@ void spu_recompiler::FMS(spu_opcode_t op)
void spu_recompiler::UNK(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<void(spu_recompiler::*)(spu_opcode_t)> spu_recompiler::opcodes{ DEFINE_SPU_OPCODES(&spu_recompiler::), &spu_recompiler::UNK };
+2 -4
View File
@@ -13,7 +13,7 @@ namespace asmjit
} }
// SPU ASMJIT Recompiler // SPU ASMJIT Recompiler
class spu_recompiler : public SPURecompilerBase class spu_recompiler : public spu_recompiler_base
{ {
const std::shared_ptr<asmjit::JitRuntime> m_jit; const std::shared_ptr<asmjit::JitRuntime> m_jit;
@@ -75,7 +75,7 @@ private:
asmjit::X86Mem XmmConst(__m128 data); asmjit::X86Mem XmmConst(__m128 data);
asmjit::X86Mem XmmConst(__m128i data); asmjit::X86Mem XmmConst(__m128i data);
private: public:
void InterpreterCall(spu_opcode_t op); void InterpreterCall(spu_opcode_t op);
void FunctionCall(); void FunctionCall();
@@ -280,6 +280,4 @@ private:
void FMS(spu_opcode_t op); void FMS(spu_opcode_t op);
void UNK(spu_opcode_t op); void UNK(spu_opcode_t op);
static const spu_opcode_table_t<void(spu_recompiler::*)(spu_opcode_t)> opcodes;
}; };
+20 -20
View File
@@ -4,7 +4,7 @@
#include "SPURecompiler.h" #include "SPURecompiler.h"
#include "SPUAnalyser.h" #include "SPUAnalyser.h"
const spu_opcode_table_t<spu_itype_t> g_spu_itype{ DEFINE_SPU_OPCODES(spu_itype::), spu_itype::UNK }; const spu_decoder<spu_itype::type> s_spu_itype;
std::shared_ptr<spu_function_t> SPUDatabase::find(const be_t<u32>* data, u64 key, u32 max_size) std::shared_ptr<spu_function_t> SPUDatabase::find(const be_t<u32>* data, u64 key, u32 max_size)
{ {
@@ -83,7 +83,7 @@ std::shared_ptr<spu_function_t> SPUDatabase::analyse(const be_t<u32>* ls, u32 en
{ {
const spu_opcode_t op{ ls[pos / 4] }; 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; using namespace spu_itype;
@@ -172,15 +172,15 @@ std::shared_ptr<spu_function_t> SPUDatabase::analyse(const be_t<u32>* ls, u32 en
break; 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; 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 // Add adjacent function because it always could be
adjacent.emplace(target); adjacent.emplace(target);
@@ -192,9 +192,9 @@ std::shared_ptr<spu_function_t> SPUDatabase::analyse(const be_t<u32>* ls, u32 en
blocks.emplace(start); start = pos + 4; 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) if (target == pos + 4)
{ {
@@ -215,11 +215,11 @@ std::shared_ptr<spu_function_t> SPUDatabase::analyse(const be_t<u32>* ls, u32 en
if (op.rt != 0) LOG_ERROR(SPU, "[0x%05x] Function call without $LR", pos); 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); 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); const u32 target = spu_branch_target(pos, op.i16);
@@ -231,24 +231,24 @@ std::shared_ptr<spu_function_t> SPUDatabase::analyse(const be_t<u32>* ls, u32 en
blocks.emplace(target); 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) 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 // Analyse link register access
if (rt == 0) if (rt == 0)
@@ -258,7 +258,7 @@ std::shared_ptr<spu_function_t> SPUDatabase::analyse(const be_t<u32>* ls, u32 en
// Analyse stack pointer access // Analyse stack pointer access
if (rt == 1) if (rt == 1)
{ {
if (type == ILA && pos < ila_sp_pos) if (type == &type::ILA && pos < ila_sp_pos)
{ {
// set minimal ila $SP,* instruction position // set minimal ila $SP,* instruction position
ila_sp_pos = pos; ila_sp_pos = pos;
@@ -272,7 +272,7 @@ std::shared_ptr<spu_function_t> SPUDatabase::analyse(const be_t<u32>* ls, u32 en
{ {
const spu_opcode_t op{ ls[pos / 4] }; 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; using namespace spu_itype;
@@ -280,9 +280,9 @@ std::shared_ptr<spu_function_t> SPUDatabase::analyse(const be_t<u32>* ls, u32 en
{ {
break; 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) if (target != pos + 4 && target > entry && limit > target)
{ {
+213 -217
View File
@@ -3,250 +3,246 @@
#include "Emu/Cell/SPUOpcodes.h" #include "Emu/Cell/SPUOpcodes.h"
#include "Utilities/SharedMutex.h" #include "Utilities/SharedMutex.h"
#include <set>
class SPUThread; class SPUThread;
// Type of the runtime functions generated by SPU recompiler // Type of the runtime functions generated by SPU recompiler
using spu_jit_func_t = u32(*)(SPUThread* _spu, be_t<u32>* _ls); using spu_jit_func_t = u32(*)(SPUThread* _spu, be_t<u32>* _ls);
// SPU instruction classification namespace // SPU Instruction Classifier
namespace spu_itype namespace spu_itype
{ {
enum spu_itype_t : u32 struct type
{ {
UNK = 0, u32 UNK;
u32 STOP;
STOP, u32 LNOP;
LNOP, u32 SYNC;
SYNC, u32 DSYNC;
DSYNC, u32 MFSPR;
MFSPR, u32 RDCH;
RDCH, u32 RCHCNT;
RCHCNT, u32 SF;
SF, u32 OR;
OR, u32 BG;
BG, u32 SFH;
SFH, u32 NOR;
NOR, u32 ABSDB;
ABSDB, u32 ROT;
ROT, u32 ROTM;
ROTM, u32 ROTMA;
ROTMA, u32 SHL;
SHL, u32 ROTH;
ROTH, u32 ROTHM;
ROTHM, u32 ROTMAH;
ROTMAH, u32 SHLH;
SHLH, u32 ROTI;
ROTI, u32 ROTMI;
ROTMI, u32 ROTMAI;
ROTMAI, u32 SHLI;
SHLI, u32 ROTHI;
ROTHI, u32 ROTHMI;
ROTHMI, u32 ROTMAHI;
ROTMAHI, u32 SHLHI;
SHLHI, u32 A;
A, u32 AND;
AND, u32 CG;
CG, u32 AH;
AH, u32 NAND;
NAND, u32 AVGB;
AVGB, u32 MTSPR;
MTSPR, u32 WRCH;
WRCH, u32 BIZ;
BIZ, u32 BINZ;
BINZ, u32 BIHZ;
BIHZ, u32 BIHNZ;
BIHNZ, u32 STOPD;
STOPD, u32 STQX;
STQX, u32 BI;
BI, u32 BISL;
BISL, u32 IRET;
IRET, u32 BISLED;
BISLED, u32 HBR;
HBR, u32 GB;
GB, u32 GBH;
GBH, u32 GBB;
GBB, u32 FSM;
FSM, u32 FSMH;
FSMH, u32 FSMB;
FSMB, u32 FREST;
FREST, u32 FRSQEST;
FRSQEST, u32 LQX;
LQX, u32 ROTQBYBI;
ROTQBYBI, u32 ROTQMBYBI;
ROTQMBYBI, u32 SHLQBYBI;
SHLQBYBI, u32 CBX;
CBX, u32 CHX;
CHX, u32 CWX;
CWX, u32 CDX;
CDX, u32 ROTQBI;
ROTQBI, u32 ROTQMBI;
ROTQMBI, u32 SHLQBI;
SHLQBI, u32 ROTQBY;
ROTQBY, u32 ROTQMBY;
ROTQMBY, u32 SHLQBY;
SHLQBY, u32 ORX;
ORX, u32 CBD;
CBD, u32 CHD;
CHD, u32 CWD;
CWD, u32 CDD;
CDD, u32 ROTQBII;
ROTQBII, u32 ROTQMBII;
ROTQMBII, u32 SHLQBII;
SHLQBII, u32 ROTQBYI;
ROTQBYI, u32 ROTQMBYI;
ROTQMBYI, u32 SHLQBYI;
SHLQBYI, u32 NOP;
NOP, u32 CGT;
CGT, u32 XOR;
XOR, u32 CGTH;
CGTH, u32 EQV;
EQV, u32 CGTB;
CGTB, u32 SUMB;
SUMB, u32 HGT;
HGT, u32 CLZ;
CLZ, u32 XSWD;
XSWD, u32 XSHW;
XSHW, u32 CNTB;
CNTB, u32 XSBH;
XSBH, u32 CLGT;
CLGT, u32 ANDC;
ANDC, u32 FCGT;
FCGT, u32 DFCGT;
DFCGT, u32 FA;
FA, u32 FS;
FS, u32 FM;
FM, u32 CLGTH;
CLGTH, u32 ORC;
ORC, u32 FCMGT;
FCMGT, u32 DFCMGT;
DFCMGT, u32 DFA;
DFA, u32 DFS;
DFS, u32 DFM;
DFM, u32 CLGTB;
CLGTB, u32 HLGT;
HLGT, u32 DFMA;
DFMA, u32 DFMS;
DFMS, u32 DFNMS;
DFNMS, u32 DFNMA;
DFNMA, u32 CEQ;
CEQ, u32 MPYHHU;
MPYHHU, u32 ADDX;
ADDX, u32 SFX;
SFX, u32 CGX;
CGX, u32 BGX;
BGX, u32 MPYHHA;
MPYHHA, u32 MPYHHAU;
MPYHHAU, u32 FSCRRD;
FSCRRD, u32 FESD;
FESD, u32 FRDS;
FRDS, u32 FSCRWR;
FSCRWR, u32 DFTSV;
DFTSV, u32 FCEQ;
FCEQ, u32 DFCEQ;
DFCEQ, u32 MPY;
MPY, u32 MPYH;
MPYH, u32 MPYHH;
MPYHH, u32 MPYS;
MPYS, u32 CEQH;
CEQH, u32 FCMEQ;
FCMEQ, u32 DFCMEQ;
DFCMEQ, u32 MPYU;
MPYU, u32 CEQB;
CEQB, u32 FI;
FI, u32 HEQ;
HEQ, u32 CFLTS;
CFLTS, u32 CFLTU;
CFLTU, u32 CSFLT;
CSFLT, u32 CUFLT;
CUFLT, u32 BRZ;
BRZ, u32 STQA;
STQA, u32 BRNZ;
BRNZ, u32 BRHZ;
BRHZ, u32 BRHNZ;
BRHNZ, u32 STQR;
STQR, u32 BRA;
BRA, u32 LQA;
LQA, u32 BRASL;
BRASL, u32 BR;
BR, u32 FSMBI;
FSMBI, u32 BRSL;
BRSL, u32 LQR;
LQR, u32 IL;
IL, u32 ILHU;
ILHU, u32 ILH;
ILH, u32 IOHL;
IOHL, u32 ORI;
ORI, u32 ORHI;
ORHI, u32 ORBI;
ORBI, u32 SFI;
SFI, u32 SFHI;
SFHI, u32 ANDI;
ANDI, u32 ANDHI;
ANDHI, u32 ANDBI;
ANDBI, u32 AI;
AI, u32 AHI;
AHI, u32 STQD;
STQD, u32 LQD;
LQD, u32 XORI;
XORI, u32 XORHI;
XORHI, u32 XORBI;
XORBI, u32 CGTI;
CGTI, u32 CGTHI;
CGTHI, u32 CGTBI;
CGTBI, u32 HGTI;
HGTI, u32 CLGTI;
CLGTI, u32 CLGTHI;
CLGTHI, u32 CLGTBI;
CLGTBI, u32 HLGTI;
HLGTI, u32 MPYI;
MPYI, u32 MPYUI;
MPYUI, u32 CEQI;
CEQI, u32 CEQHI;
CEQHI, u32 CEQBI;
CEQBI, u32 HEQI;
HEQI, u32 HBRA;
HBRA, u32 HBRR;
HBRR, u32 ILA;
ILA, u32 SELB;
SELB, u32 SHUFB;
SHUFB, u32 MPYA;
MPYA, u32 FNMS;
FNMS, u32 FMA;
FMA, u32 FMS;
FMS,
}; };
} };
using spu_itype::spu_itype_t;
// SPU Instruction Classification table
extern const spu_opcode_table_t<spu_itype_t> g_spu_itype;
// SPU basic function information structure // SPU basic function information structure
struct spu_function_t struct spu_function_t
{ {
// entry point (LS address) // Entry point (LS address)
const u32 addr; const u32 addr;
// function size (in bytes) // Function size (in bytes)
const u32 size; const u32 size;
// function contents (binary copy) // Function contents (binary copy)
std::vector<be_t<u32>> data; std::vector<be_t<u32>> data;
// basic blocks (start addresses) // Basic blocks (start addresses)
std::set<u32> blocks; std::set<u32> blocks;
// functions possibly called by this function (may not be available) // Functions possibly called by this function (may not be available)
std::set<u32> adjacent; std::set<u32> adjacent;
// jump table values (start addresses) // Jump table values (start addresses)
std::set<u32> jtable; std::set<u32> jtable;
// whether ila $SP,* instruction found // Whether ila $SP,* instruction found
bool does_reset_stack; bool does_reset_stack;
// pointer to the compiled function // Pointer to the compiled function
spu_jit_func_t compiled = nullptr; spu_jit_func_t compiled = nullptr;
spu_function_t(u32 addr, u32 size) spu_function_t(u32 addr, u32 size)
-5
View File
@@ -1,5 +0,0 @@
#pragma once
struct spu_context_t
{
};
+11
View File
@@ -0,0 +1,11 @@
#include "stdafx.h"
#include "SPUDisAsm.h"
const spu_decoder<SPUDisAsm> s_spu_disasm;
u32 SPUDisAsm::disasm(u32 pc)
{
const u32 op = *(be_t<u32>*)(offset + pc);
(this->*(s_spu_disasm.decode(op)))({ op });
return 4;
}
+5 -9
View File
@@ -66,7 +66,7 @@ static const char* spu_ch_name[128] =
"$ch121", "$ch122", "$ch123", "$ch124", "$ch125", "$ch126", "$ch127", "$ch121", "$ch122", "$ch123", "$ch124", "$ch125", "$ch126", "$ch127",
}; };
class SPUDisAsm : public PPCDisAsm class SPUDisAsm final : public PPCDisAsm
{ {
public: public:
SPUDisAsm(CPUDisAsmMode mode) : PPCDisAsm(mode) 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)); Write(fmt::format("%s %s,%s,%s,%s", FixOp(op).c_str(), a1, a2, a3, a4));
} }
public:
u32 disasm(u32 pc) override;
//0 - 10 //0 - 10
void STOP(spu_opcode_t op) void STOP(spu_opcode_t op)
{ {
@@ -945,12 +949,4 @@ private:
{ {
Write(fmt::format("Unknown/Illegal opcode! (0x%08x)", op.opcode)); Write(fmt::format("Unknown/Illegal opcode! (0x%08x)", op.opcode));
} }
static const spu_opcode_table_t<void(SPUDisAsm::*)(spu_opcode_t)> opcodes;
public:
void do_disasm(u32 opcode)
{
(this->*opcodes[opcode])({ opcode });
}
}; };
+57 -70
View File
@@ -7,20 +7,7 @@
#include <fenv.h> #include <fenv.h>
namespace spu_interpreter void spu_interpreter::UNK(SPUThread& spu, spu_opcode_t op)
{
namespace fast
{
const spu_opcode_table_t<spu_inter_func_t> g_spu_opcode_table{ DEFINE_SPU_OPCODES(+), default_function };
}
namespace precise
{
const spu_opcode_table_t<spu_inter_func_t> g_spu_opcode_table{ DEFINE_SPU_OPCODES(+), default_function };
}
}
void spu_interpreter::default_function(SPUThread& spu, spu_opcode_t op)
{ {
throw EXCEPTION("Unknown/Illegal instruction (0x%08x)", op.opcode); 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]; 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); 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)); 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)); 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]); 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); 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"); 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]); 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]); 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); 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]; 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)); 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)); 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"); 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]); 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]); 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); 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); 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); 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)); 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)); 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)))); 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(); 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; const auto a = spu.gpr[op.ra].vf;
spu.gpr[op.rt].vd = _mm_cvtps_pd(_mm_shuffle_ps(a, a, 0x8d)); 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); const auto t = _mm_cvtpd_ps(spu.gpr[op.ra].vd);
spu.gpr[op.rt].vf = _mm_shuffle_ps(t, t, 0x72); 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"); 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); 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); 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)); 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)); 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); 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 // TODO
const auto mask_se = _mm_castsi128_ps(_mm_set1_epi32(0xff800000)); // sign and exponent mask 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]); 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)))); 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 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))); 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)))); 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]); 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 a = spu.gpr[op.ra].vi;
const auto fix = _mm_and_ps(_mm_castsi128_ps(_mm_srai_epi32(a, 31)), _mm_set1_ps(0x80000000)); 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))); 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)); 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); 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); 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 #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); SetHostRoundingMode(FPSCR_RN_ZERO);
for (int i = 0; i < 4; i++) 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); SetHostRoundingMode(FPSCR_RN_ZERO);
for (int i = 0; i < 4; i++) 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++) 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); SetHostRoundingMode(FPSCR_RN_ZERO);
for (int w = 0; w < 4; w++) 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++) 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) 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]); 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++) 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++) 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]); 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++) 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++) 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 // TODO
spu.gpr[op.rt] = spu.gpr[op.rb]; 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 const int scale = 173 - (op.i8 & 0xff); //unsigned immediate
for (int i = 0; i < 4; i++) 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 const int scale = 173 - (op.i8 & 0xff); //unsigned immediate
for (int i = 0; i < 4; i++) 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); SetHostRoundingMode(FPSCR_RN_ZERO);
const int scale = 155 - (op.i8 & 0xff); //unsigned immediate 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); SetHostRoundingMode(FPSCR_RN_ZERO);
const int scale = 155 - (op.i8 & 0xff); //unsigned immediate 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); }
+238 -248
View File
@@ -4,256 +4,246 @@
class SPUThread; 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 static void UNK(SPUThread&, spu_opcode_t);
{ static void set_interrupt_status(SPUThread&, spu_opcode_t);
extern const spu_opcode_table_t<spu_inter_func_t> g_spu_opcode_table;
}
namespace precise static void STOP(SPUThread&, spu_opcode_t);
{ static void LNOP(SPUThread&, spu_opcode_t);
extern const spu_opcode_table_t<spu_inter_func_t> g_spu_opcode_table; 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); struct spu_interpreter_fast final : spu_interpreter
void set_interrupt_status(SPUThread& spu, spu_opcode_t op); {
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); struct spu_interpreter_precise final : spu_interpreter
void LNOP(SPUThread& spu, spu_opcode_t op); {
void SYNC(SPUThread& spu, spu_opcode_t op); static void FREST(SPUThread&, spu_opcode_t);
void DSYNC(SPUThread& spu, spu_opcode_t op); static void FRSQEST(SPUThread&, spu_opcode_t);
void MFSPR(SPUThread& spu, spu_opcode_t op); static void FCGT(SPUThread&, spu_opcode_t);
void RDCH(SPUThread& spu, spu_opcode_t op); static void FA(SPUThread&, spu_opcode_t);
void RCHCNT(SPUThread& spu, spu_opcode_t op); static void FS(SPUThread&, spu_opcode_t);
void SF(SPUThread& spu, spu_opcode_t op); static void FM(SPUThread&, spu_opcode_t);
void OR(SPUThread& spu, spu_opcode_t op); static void FCMGT(SPUThread&, spu_opcode_t);
void BG(SPUThread& spu, spu_opcode_t op); static void DFA(SPUThread&, spu_opcode_t);
void SFH(SPUThread& spu, spu_opcode_t op); static void DFS(SPUThread&, spu_opcode_t);
void NOR(SPUThread& spu, spu_opcode_t op); static void DFM(SPUThread&, spu_opcode_t);
void ABSDB(SPUThread& spu, spu_opcode_t op); static void DFMA(SPUThread&, spu_opcode_t);
void ROT(SPUThread& spu, spu_opcode_t op); static void DFMS(SPUThread&, spu_opcode_t);
void ROTM(SPUThread& spu, spu_opcode_t op); static void DFNMS(SPUThread&, spu_opcode_t);
void ROTMA(SPUThread& spu, spu_opcode_t op); static void DFNMA(SPUThread&, spu_opcode_t);
void SHL(SPUThread& spu, spu_opcode_t op); static void FSCRRD(SPUThread&, spu_opcode_t);
void ROTH(SPUThread& spu, spu_opcode_t op); static void FESD(SPUThread&, spu_opcode_t);
void ROTHM(SPUThread& spu, spu_opcode_t op); static void FRDS(SPUThread&, spu_opcode_t);
void ROTMAH(SPUThread& spu, spu_opcode_t op); static void FSCRWR(SPUThread&, spu_opcode_t);
void SHLH(SPUThread& spu, spu_opcode_t op); static void FCEQ(SPUThread&, spu_opcode_t);
void ROTI(SPUThread& spu, spu_opcode_t op); static void FCMEQ(SPUThread&, spu_opcode_t);
void ROTMI(SPUThread& spu, spu_opcode_t op); static void FI(SPUThread&, spu_opcode_t);
void ROTMAI(SPUThread& spu, spu_opcode_t op); static void CFLTS(SPUThread&, spu_opcode_t);
void SHLI(SPUThread& spu, spu_opcode_t op); static void CFLTU(SPUThread&, spu_opcode_t);
void ROTHI(SPUThread& spu, spu_opcode_t op); static void CSFLT(SPUThread&, spu_opcode_t);
void ROTHMI(SPUThread& spu, spu_opcode_t op); static void CUFLT(SPUThread&, spu_opcode_t);
void ROTMAHI(SPUThread& spu, spu_opcode_t op); static void FNMS(SPUThread&, spu_opcode_t);
void SHLHI(SPUThread& spu, spu_opcode_t op); static void FMA(SPUThread&, spu_opcode_t);
void A(SPUThread& spu, spu_opcode_t op); static void FMS(SPUThread&, spu_opcode_t);
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);
}
}
+249 -240
View File
@@ -1,5 +1,7 @@
#pragma once #pragma once
#include "../../../Utilities/BitField.h"
union spu_opcode_t union spu_opcode_t
{ {
u32 opcode; u32 opcode;
@@ -23,246 +25,6 @@ union spu_opcode_t
bf_t<u32, 7, 18> i18; // 7..24 bf_t<u32, 7, 18> 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<typename T> class spu_opcode_table_t
{
std::array<T, 2048> 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<opcode_entry_t> 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) inline u32 spu_branch_target(u32 pc, u32 imm = 0)
{ {
return (pc + (imm << 2)) & 0x3fffc; return (pc + (imm << 2)) & 0x3fffc;
@@ -272,3 +34,250 @@ inline u32 spu_ls_target(u32 pc, u32 imm = 0)
{ {
return (pc + (imm << 2)) & 0x3fff0; 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<typename D, typename T = decltype(&D::UNK)>
class spu_decoder
{
// Fast lookup table
std::array<T, 2048> m_table;
struct instruction_info
{
u32 magn; // Count = 2 ^ magn
u32 value;
T pointer;
};
public:
spu_decoder()
{
const std::initializer_list<instruction_info> 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<T, 2048>& get_table() const
{
return m_table;
}
T decode(u32 inst) const
{
return m_table[spu_decode(inst)];
}
};
+17 -22
View File
@@ -8,39 +8,36 @@
extern u64 get_system_time(); extern u64 get_system_time();
SPURecompilerDecoder::SPURecompilerDecoder(SPUThread& spu) void spu_recompiler_base::enter(SPUThread& spu)
: db(fxm::get_always<SPUDatabase>())
, rec(fxm::get_always<spu_recompiler>())
, spu(spu)
{ {
} if (spu.pc >= 0x40000 || spu.pc % 4)
u32 SPURecompilerDecoder::DecodeMemory(const u32 address)
{
if (spu.offset != address - spu.pc || 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<u32>(spu.offset); const auto _ls = vm::ps3::_ptr<u32>(spu.offset);
// always validate (TODO) // Always validate (TODO)
const auto func = db->analyse(_ls, spu.pc); 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) if (func->does_reset_stack && spu.recursion_level)
{ {
spu.m_state |= CPU_STATE_RETURN; spu.state += cpu_state::ret;
return;
return 0;
} }
if (!func->compiled) if (!func->compiled)
{ {
rec->compile(*func); if (!spu.spu_rec)
{
spu.spu_rec = fxm::get_always<spu_recompiler>();
}
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); const u32 res = func->compiled(&spu, _ls);
@@ -64,7 +61,7 @@ u32 SPURecompilerDecoder::DecodeMemory(const u32 address)
{ {
if (res & 0x8000000) if (res & 0x8000000)
{ {
throw EXCEPTION("Undefined behaviour"); throw std::logic_error("Invalid interrupt status set" HERE);
} }
spu.set_interrupt_status(true); spu.set_interrupt_status(true);
@@ -75,6 +72,4 @@ u32 SPURecompilerDecoder::DecodeMemory(const u32 address)
} }
spu.pc = res & 0x3fffc; spu.pc = res & 0x3fffc;
return 0;
} }
+8 -21
View File
@@ -1,12 +1,9 @@
#pragma once #pragma once
#include "Emu/CPU/CPUDecoder.h"
#include "SPUAnalyser.h" #include "SPUAnalyser.h"
class SPUThread;
// SPU Recompiler instance base (must be global or PS3 process-local) // SPU Recompiler instance base (must be global or PS3 process-local)
class SPURecompilerBase class spu_recompiler_base
{ {
protected: protected:
std::mutex m_mutex; // must be locked in compile() std::mutex m_mutex; // must be locked in compile()
@@ -16,21 +13,11 @@ protected:
u32 m_pos; // current position u32 m_pos; // current position
public: public:
virtual void compile(spu_function_t& f) = 0; // compile specified function virtual ~spu_recompiler_base() = default;
virtual ~SPURecompilerBase() {};
}; // Compile specified function
virtual void compile(spu_function_t& f) = 0;
// SPU Decoder instance (created per SPU thread)
class SPURecompilerDecoder final : public CPUDecoder // Run
{ static void enter(class SPUThread&);
public:
const std::shared_ptr<SPUDatabase> db; // associated SPU Analyser instance
const std::shared_ptr<SPURecompilerBase> 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)
}; };
+197 -199
View File
@@ -1,15 +1,15 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/state.h"
#include "Emu/IdManager.h" #include "Emu/IdManager.h"
#include "Emu/Cell/PPUThread.h" #include "Emu/Cell/PPUThread.h"
#include "Emu/SysCalls/ErrorCodes.h" #include "Emu/Cell/ErrorCodes.h"
#include "Emu/SysCalls/lv2/sys_spu.h" #include "Emu/Cell/lv2/sys_spu.h"
#include "Emu/SysCalls/lv2/sys_event_flag.h" #include "Emu/Cell/lv2/sys_event_flag.h"
#include "Emu/SysCalls/lv2/sys_event.h" #include "Emu/Cell/lv2/sys_event.h"
#include "Emu/SysCalls/lv2/sys_interrupt.h" #include "Emu/Cell/lv2/sys_interrupt.h"
#include "Emu/Cell/SPUDisAsm.h" #include "Emu/Cell/SPUDisAsm.h"
#include "Emu/Cell/SPUThread.h" #include "Emu/Cell/SPUThread.h"
@@ -20,8 +20,24 @@
extern u64 get_timebased_time(); extern u64 get_timebased_time();
// defined here since SPUDisAsm.cpp doesn't exist enum class spu_decoder_type
const spu_opcode_table_t<void(SPUDisAsm::*)(spu_opcode_t)> SPUDisAsm::opcodes{ DEFINE_SPU_OPCODES(&SPUDisAsm::), &SPUDisAsm::UNK }; {
precise,
fast,
asmjit,
llvm,
};
cfg::map_entry<spu_decoder_type> 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<spu_interpreter_precise> s_spu_interpreter_precise;
const spu_decoder<spu_interpreter_fast> s_spu_interpreter_fast;
thread_local bool spu_channel_t::notification_required; thread_local bool spu_channel_t::notification_required;
@@ -31,7 +47,7 @@ void spu_int_ctrl_t::set(u64 ints)
ints &= mask; ints &= mask;
// notify if at least 1 bit was set // 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; 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; 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 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() void SPUThread::cpu_init()
{
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<const u32>(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()
{ {
gpr = {}; gpr = {};
fpscr.Reset(); fpscr.Reset();
@@ -190,75 +117,96 @@ void SPUThread::init_regs()
gpr[1]._u32[3] = 0x3FFF0; // initial stack frame pointer 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() if (custom_task)
{
// nothing to do here
}
void SPUThread::do_run()
{
m_dec.reset();
switch (auto mode = rpcs3::state.config.core.spu_decoder.value())
{ {
case spu_decoder_type::interpreter_precise: // Interpreter 1 (Precise) if (check_status()) return;
case spu_decoder_type::interpreter_fast: // Interpreter 2 (Fast)
{ return custom_task(*this);
break;
} }
case spu_decoder_type::recompiler_asmjit: _log::g_tls_make_prefix = [](const auto&, auto, const auto&)
{ {
m_dec.reset(new SPURecompilerDecoder(*this)); const auto cpu = static_cast<SPUThread*>(get_current_cpu_thread());
break;
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<SPUDatabase>();
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<const u32>(offset);
while (true)
{ {
LOG_ERROR(SPU, "Invalid SPU decoder mode: %d", (u8)mode); if (!state.load())
Emu.Pause(); {
} // 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 if (channel->notification_required)
_ref<u32>(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
{ {
cpu_task(); // lock for reliable notification
} std::lock_guard<std::mutex> lock(mutex);
catch (CPUThreadReturn)
{
}
m_state &= ~CPU_STATE_RETURN; cv.notify_one();
}
pc = old_pc;
gpr[0]._u32[3] = old_lr;
gpr[1]._u32[3] = old_stack;
custom_task = std::move(old_task);
} }
void SPUThread::do_dma_transfer(u32 cmd, spu_mfc_arg_t args) 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(); _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 index = (eal - SYS_SPU_THREAD_BASE_LOW) / SYS_SPU_THREAD_OFFSET; // thread number in group
const u32 offset = (eal - SYS_SPU_THREAD_BASE_LOW) % SYS_SPU_THREAD_OFFSET; // LS offset or MMIO register const 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; 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); vm::reservation_acquire(vm::base(offset + ch_mfc_args.lsa), raddr, 128);
@@ -434,7 +382,7 @@ void SPUThread::process_mfc_cmd(u32 cmd)
break; 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) if (last_raddr == 0)
{ {
@@ -466,9 +414,9 @@ void SPUThread::process_mfc_cmd(u32 cmd)
break; 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) 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 // 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 // notify if some events were set
if (~old_stat & mask && old_stat & SPU_EVENT_WAITING) if (~old_stat & mask && old_stat & SPU_EVENT_WAITING)
@@ -617,7 +565,10 @@ u32 SPUThread::get_ch_value(u32 ch)
CHECK_EMU_STATUS; CHECK_EMU_STATUS;
if (is_stopped()) throw CPUThreadStop{}; if (state & cpu_state::stop)
{
throw cpu_state::stop;
}
if (!lock) if (!lock)
{ {
@@ -658,7 +609,10 @@ u32 SPUThread::get_ch_value(u32 ch)
CHECK_EMU_STATUS; CHECK_EMU_STATUS;
if (is_stopped()) throw CPUThreadStop{}; if (state & cpu_state::stop)
{
throw cpu_state::stop;
}
if (!lock) if (!lock)
{ {
@@ -723,14 +677,14 @@ u32 SPUThread::get_ch_value(u32 ch)
if (ch_event_mask & SPU_EVENT_LR) if (ch_event_mask & SPU_EVENT_LR)
{ {
// register waiter if polling reservation status is required // 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 else
{ {
lock.lock(); lock.lock();
// simple waiting loop otherwise // simple waiting loop otherwise
while (!get_events(true) && !is_stopped()) while (!get_events(true) && !(state & cpu_state::stop))
{ {
CHECK_EMU_STATUS; CHECK_EMU_STATUS;
@@ -740,7 +694,10 @@ u32 SPUThread::get_ch_value(u32 ch)
ch_event_stat &= ~SPU_EVENT_WAITING; ch_event_stat &= ~SPU_EVENT_WAITING;
if (is_stopped()) throw CPUThreadStop{}; if (state & cpu_state::stop)
{
throw cpu_state::stop;
}
return get_events(); return get_events();
} }
@@ -767,7 +724,7 @@ void SPUThread::set_ch_value(u32 ch, u32 value)
// break; // break;
case SPU_WrOutIntrMbox: case SPU_WrOutIntrMbox:
{ {
if (m_type == CPU_THREAD_RAW_SPU) if (offset >= RAW_SPU_BASE_ADDR)
{ {
std::unique_lock<std::mutex> lock(mutex, std::defer_lock); std::unique_lock<std::mutex> lock(mutex, std::defer_lock);
@@ -775,7 +732,10 @@ void SPUThread::set_ch_value(u32 ch, u32 value)
{ {
CHECK_EMU_STATUS; CHECK_EMU_STATUS;
if (is_stopped()) throw CPUThreadStop{}; if (state & cpu_state::stop)
{
throw cpu_state::stop;
}
if (!lock) 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 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); 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); 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 // 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); 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; 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; return;
} }
else if (code == 128) else if (code == 128)
@@ -979,7 +939,10 @@ void SPUThread::set_ch_value(u32 ch, u32 value)
{ {
CHECK_EMU_STATUS; CHECK_EMU_STATUS;
if (is_stopped()) throw CPUThreadStop{}; if (state & cpu_state::stop)
{
throw cpu_state::stop;
}
if (!lock) if (!lock)
{ {
@@ -1136,7 +1099,7 @@ void SPUThread::stop_and_signal(u32 code)
{ {
LOG_TRACE(SPU, "stop_and_signal(code=0x%x)", 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) 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); int_ctrl[2].set(SPU_INT2_STAT_SPU_STOP_AND_SIGNAL_INT);
throw cpu_state::stop;
return stop();
} }
switch (code) switch (code)
@@ -1160,7 +1122,7 @@ void SPUThread::stop_and_signal(u32 code)
case 0x002: case 0x002:
{ {
m_state |= CPU_STATE_RETURN; state += cpu_state::ret;
return; return;
} }
@@ -1241,7 +1203,10 @@ void SPUThread::stop_and_signal(u32 code)
{ {
CHECK_EMU_STATUS; 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)); 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) for (auto& thread : group->threads)
{ {
if (thread) thread->sleep(); // trigger status check if (thread)
{
thread->state += cpu_state::suspend;
}
} }
} }
else else
@@ -1261,24 +1229,25 @@ void SPUThread::stop_and_signal(u32 code)
throw EXCEPTION("Unexpected SPU Thread Group state (%d)", group->state); 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<u32>(std::get<1>(event)), static_cast<u32>(std::get<2>(event)), static_cast<u32>(std::get<3>(event))); ch_in_mbox.set_values(4, CELL_OK, static_cast<u32>(std::get<1>(event)), static_cast<u32>(std::get<2>(event)), static_cast<u32>(std::get<3>(event)));
queue->events.pop_front();
} }
else else
{ {
// add waiter; protocol is ignored in current implementation // add waiter; protocol is ignored in current implementation
sleep_queue_entry_t waiter(*this, queue->sq); sleep_entry<cpu_thread> waiter(queue->thread_queue(lv2_lock), *this);
// wait on the event queue // wait on the event queue
while (!unsignal()) while (!state.test_and_reset(cpu_state::signal))
{ {
CHECK_EMU_STATUS; CHECK_EMU_STATUS;
if (is_stopped()) throw CPUThreadStop{}; if (state & cpu_state::stop)
{
throw cpu_state::stop;
}
cv.wait(lv2_lock); cv.wait(lv2_lock);
} }
@@ -1302,9 +1271,14 @@ void SPUThread::stop_and_signal(u32 code)
for (auto& thread : group->threads) 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(); group->cv.notify_all();
return; return;
@@ -1338,7 +1312,8 @@ void SPUThread::stop_and_signal(u32 code)
{ {
if (thread && thread.get() != this) 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->join_state |= SPU_TGJSF_GROUP_EXIT;
group->cv.notify_one(); group->cv.notify_one();
return stop(); throw cpu_state::stop;
} }
case 0x102: case 0x102:
@@ -1373,7 +1348,7 @@ void SPUThread::stop_and_signal(u32 code)
status |= SPU_STATUS_STOPPED_BY_STOP; status |= SPU_STATUS_STOPPED_BY_STOP;
group->cv.notify_one(); group->cv.notify_one();
return stop(); throw cpu_state::stop;
} }
} }
@@ -1391,7 +1366,7 @@ void SPUThread::halt()
{ {
LOG_TRACE(SPU, "halt()"); LOG_TRACE(SPU, "halt()");
if (m_type == CPU_THREAD_RAW_SPU) if (offset >= RAW_SPU_BASE_ADDR)
{ {
status.atomic_op([](u32& status) status.atomic_op([](u32& status)
{ {
@@ -1401,18 +1376,41 @@ void SPUThread::halt()
int_ctrl[2].set(SPU_INT2_STAT_SPU_HALT_OR_STEP_INT); int_ctrl[2].set(SPU_INT2_STAT_SPU_HALT_OR_STEP_INT);
return stop(); throw cpu_state::stop;
} }
status |= SPU_STATUS_STOPPED_BY_HALT; status |= SPU_STATUS_STOPPED_BY_HALT;
throw EXCEPTION("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<SPUThread>(name, 0x13370666); // LS:0x0: this is originally the entry point of the interrupt handler, but interrupts are not implemented
_ref<u32>(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);
} }
+52 -136
View File
@@ -2,10 +2,10 @@
#include "Emu/Cell/Common.h" #include "Emu/Cell/Common.h"
#include "Emu/CPU/CPUThread.h" #include "Emu/CPU/CPUThread.h"
#include "Emu/Cell/SPUContext.h" #include "Emu/Cell/SPUInterpreter.h"
#include "MFC.h" #include "MFC.h"
struct lv2_event_queue_t; class lv2_event_queue_t;
struct lv2_spu_group_t; struct lv2_spu_group_t;
struct lv2_int_tag_t; struct lv2_int_tag_t;
@@ -135,12 +135,20 @@ enum
SPU_RdSigNotify2_offs = 0x1C00C, 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 struct spu_channel_t
{ {
// set to true if SPU thread must be notified after SPU channel operation // set to true if SPU thread must be notified after SPU channel operation
thread_local static bool notification_required; thread_local static bool notification_required;
struct sync_var_t struct alignas(8) sync_var_t
{ {
bool count; // value available bool count; // value available
bool wait; // notification required bool wait; // notification required
@@ -153,7 +161,7 @@ public:
// returns true on success // returns true on success
bool try_push(u32 value) 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) if ((data.wait = data.count) == false)
{ {
@@ -168,7 +176,7 @@ public:
// push performing bitwise OR with previous value, may require notification // push performing bitwise OR with previous value, may require notification
void push_or(u32 value) 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.count = true;
data.wait = false; data.wait = false;
@@ -181,7 +189,7 @@ public:
// push unconditionally (overwriting previous value), may require notification // push unconditionally (overwriting previous value), may require notification
void push(u32 value) 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.count = true;
data.wait = false; data.wait = false;
@@ -194,7 +202,7 @@ public:
// returns true on success and loaded value // returns true on success and loaded value
std::tuple<bool, u32> try_pop() std::tuple<bool, u32> 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.wait = !data.count;
data.count = false; data.count = false;
@@ -207,7 +215,7 @@ public:
// pop unconditionally (loading last value), may require notification // pop unconditionally (loading last value), may require notification
u32 pop() 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.wait = false;
data.count = false; data.count = false;
@@ -237,7 +245,7 @@ public:
struct spu_channel_4_t struct spu_channel_4_t
{ {
struct sync_var_t struct alignas(16) sync_var_t
{ {
struct struct
{ {
@@ -256,7 +264,7 @@ struct spu_channel_4_t
public: public:
void clear() void clear()
{ {
values = sync_var_t{}; values.store({});
value3 = 0; value3 = 0;
} }
@@ -333,7 +341,10 @@ struct spu_int_ctrl_t
void set(u64 ints); void set(u64 ints);
void clear(u64 ints); void clear(u64 ints)
{
stat &= ~ints;
}
void clear() void clear()
{ {
@@ -526,12 +537,27 @@ public:
} }
}; };
class SPUThread : public CPUThread class SPUThread : public cpu_thread
{ {
friend class SPURecompilerDecoder; public:
friend class spu_recompiler; 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: public:
SPUThread(const std::string& name, u32 index);
virtual ~SPUThread() override;
std::array<v128, 128> gpr; // General-Purpose Registers std::array<v128, 128> gpr; // General-Purpose Registers
SPU_FPSCR fpscr; SPU_FPSCR fpscr;
@@ -578,32 +604,14 @@ public:
const u32 index; // SPU index const u32 index; // SPU index
const u32 offset; // SPU LS offset const u32 offset; // SPU LS offset
void push_snr(u32 number, u32 value) std::function<void(SPUThread&)> custom_task;
{ std::exception_ptr pending_exception;
// get channel
const auto channel =
number == 0 ? &ch_snr1 :
number == 1 ? &ch_snr2 : throw EXCEPTION("Unexpected");
// check corresponding SNR register settings std::shared_ptr<class SPUDatabase> spu_db;
if ((snr_config >> number) & 1) std::shared_ptr<class spu_recompiler_base> spu_rec;
{ u32 recursion_level = 0;
channel->push_or(value);
}
else
{
channel->push(value);
}
if (channel->notification_required)
{
// lock for reliable notification
std::lock_guard<std::mutex> lock(mutex);
cv.notify_one();
}
}
void push_snr(u32 number, u32 value);
void do_dma_transfer(u32 cmd, spu_mfc_arg_t args); void do_dma_transfer(u32 cmd, spu_mfc_arg_t args);
void do_dma_list_cmd(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); void process_mfc_cmd(u32 cmd);
@@ -618,14 +626,18 @@ public:
void stop_and_signal(u32 code); void stop_and_signal(u32 code);
void halt(); void halt();
void fast_call(u32 ls_addr);
// Convert specified SPU LS address to a pointer of specified (possibly converted to BE) type // Convert specified SPU LS address to a pointer of specified (possibly converted to BE) type
template<typename T> inline to_be_t<T>* _ptr(u32 lsa) template<typename T>
inline to_be_t<T>* _ptr(u32 lsa)
{ {
return static_cast<to_be_t<T>*>(vm::base(offset + lsa)); return static_cast<to_be_t<T>*>(vm::base(offset + lsa));
} }
// Convert specified SPU LS address to a reference of specified (possibly converted to BE) type // Convert specified SPU LS address to a reference of specified (possibly converted to BE) type
template<typename T> inline to_be_t<T>& _ref(u32 lsa) template<typename T>
inline to_be_t<T>& _ref(u32 lsa)
{ {
return *_ptr<T>(lsa); return *_ptr<T>(lsa);
} }
@@ -655,100 +667,4 @@ public:
} }
} }
} }
std::function<void(SPUThread&)> 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<std::string> values) override
{
return *this;
}
cpu_thread& run() override
{
auto& spu = static_cast<SPUThread&>(*thread);
spu.run();
return *this;
}
}; };