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_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)
enum : s32
enum CellOk : s32
{
CELL_OK = 0,
CELL_OK = 0,
};
enum CellError : s32
{
CELL_EAGAIN = ERROR_CODE(0x80010001), // The resource is temporarily unavailable
CELL_EINVAL = ERROR_CODE(0x80010002), // An invalid argument value is specified
CELL_ENOSYS = ERROR_CODE(0x80010003), // The feature is not yet implemented
@@ -64,6 +67,146 @@ enum : s32
CELL_EOVERFLOW = ERROR_CODE(0x80010039),
CELL_ENOTMOUNTED = ERROR_CODE(0x8001003A),
CELL_ENOTSDATA = ERROR_CODE(0x8001003B),
CELL_UNKNOWN_ERROR = -1,
};
// Special return type signaling on errors
struct ppu_error_code
{
s32 value;
// Print error message, error code is returned
static s32 report(s32 error, const char* text);
// Must be specialized for specific tag type T
template<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/IdManager.h"
#include "Emu/Cell/PPUThread.h"
#include "Emu/ARMv7/ARMv7Thread.h"
#include "Callback.h"
#include "PPUThread.h"
#include "PPUCallback.h"
void CallbackManager::Register(check_cb_t func)
{
@@ -79,17 +78,14 @@ void CallbackManager::Init()
}
};
if (vm::get(vm::main)->addr == 0x10000)
{
auto thread = idm::make_ptr<PPUThread>("Callback Thread");
auto thread = idm::make_ptr<PPUThread>("Callback Thread");
thread->prio = 1001;
thread->stack_size = 0x10000;
thread->custom_task = task;
thread->run();
thread->prio = 1001;
thread->stack_size = 0x10000;
thread->custom_task = task;
thread->cpu_init();
m_cb_thread = thread;
}
m_cb_thread = thread;
}
void CallbackManager::Clear()
@@ -2,7 +2,7 @@
#include "Emu/Cell/PPUThread.h"
namespace cb_detail
namespace ppu_cb_detail
{
enum _func_arg_type
{
@@ -10,7 +10,7 @@ namespace cb_detail
ARG_FLOAT,
ARG_VECTOR,
ARG_STACK,
ARG_CONTEXT, // for compatibility with SC_FUNC and CALL_FUNC
ARG_CONTEXT,
ARG_UNKNOWN,
};
@@ -19,7 +19,7 @@ namespace cb_detail
// It's possible to calculate suitable stack frame size in template, but too complicated.
static const auto FIXED_STACK_FRAME_SIZE = 0x90;
template<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
{
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(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>
{
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);
}
};
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>
{
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>
{
static_assert(f_count <= 13, "TODO: Unsupported stack argument type (float)");
static_assert(v_count <= 12, "TODO: Unsupported stack argument type (vector)");
static_assert(sizeof(T) <= 8, "Invalid callback argument type for ARG_STACK");
static_assert(alignof(T) <= 16, "Unsupported callback argument type alignment for ARG_STACK");
force_inline static void set_value(PPUThread& CPU, const T& arg)
static inline void set_value(PPUThread& CPU, const T& arg)
{
const int stack_pos = (g_count - 9) * 8 - FIXED_STACK_FRAME_SIZE;
static_assert(stack_pos < 0, "TODO: Increase fixed stack frame size (arg count limit broken)");
vm::ps3::write64(CPU.GPR[1] + stack_pos, cast_to_ppu_gpr<T>(arg));
const s64 stack_pos = (g_count - 1) * 0x8 + 0x30 - FIXED_STACK_FRAME_SIZE;
static_assert(stack_pos < 0, "TODO: Increase FIXED_STACK_FRAME_SIZE (arg count limit broken)");
vm::ps3::write64(CPU.GPR[1] + stack_pos, ppu_gpr_cast(arg)); // TODO
}
};
template<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>
{
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)
{
// terminator
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)
{
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_general = !is_float && !is_vector && !is_context;
@@ -102,9 +100,9 @@ namespace cb_detail
is_context ? ARG_CONTEXT :
ARG_UNKNOWN;
const int g = g_count + is_general;
const int f = f_count + is_float;
const int v = v_count + is_vector;
const u32 g = g_count + (is_general || is_float ? 1 : is_vector ? ::align(g_count, 2) + 2 : 0);
const u32 f = f_count + is_float;
const u32 v = v_count + is_vector;
_func_arg<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)
{
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>
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)
{
return CPU.VPR[2];
return CPU.VR[2];
}
};
@@ -169,11 +167,9 @@ namespace cb_detail
force_inline static void call(PPUThread& CPU, u32 pc, u32 rtoc, T... args)
{
const bool stack = _bind_func_args<0, 0, 0, T...>(CPU, args...);
if (stack) CPU.GPR[1] -= FIXED_STACK_FRAME_SIZE;
CPU.GPR[1] -= 0x70; // create reserved area
CPU.GPR[1] -= stack ? FIXED_STACK_FRAME_SIZE : 0x30; // create reserved area
CPU.fast_call(pc, rtoc);
CPU.GPR[1] += 0x70;
if (stack) CPU.GPR[1] += FIXED_STACK_FRAME_SIZE;
CPU.GPR[1] += stack ? FIXED_STACK_FRAME_SIZE : 0x30;
}
};
}
@@ -183,15 +179,44 @@ namespace vm
template<typename AT, typename RT, typename... T>
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 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)
{
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
#include "Emu/Cell/PPUThread.h"
#include "PPUThread.h"
using ppu_func_caller = void(*)(PPUThread&);
using ppu_function_t = void(*)(PPUThread&);
#define BIND_FUNC(func) [](PPUThread& ppu){ ppu.last_function = #func; ppu_func_detail::do_call(ppu, func); }
struct ppu_va_args_t
{
u32 g_count;
u32 f_count;
u32 v_count;
u32 count; // Number of 64-bit args passed
};
namespace ppu_func_detail
@@ -16,12 +16,12 @@ namespace ppu_func_detail
// argument type classification
enum arg_class : u32
{
ARG_GENERAL, // argument is stored in GPR registers (from r3 to r10)
ARG_FLOAT, // argument is stored in FPR registers (from f1 to f13)
ARG_VECTOR, // argument is stored in VPR registers (from v2 to v13)
ARG_STACK, // argument is stored on the stack
ARG_GENERAL, // argument stored in GPR (from r3 to r10)
ARG_FLOAT, // argument stored in FPR (from f1 to f13)
ARG_VECTOR, // argument stored in VR (from v2 to v13)
ARG_STACK, // argument stored on the stack
ARG_CONTEXT, // PPUThread& passed, doesn't affect g/f/v_count
ARG_VARIADIC, // information about arg counts already passed, doesn't affect g/f/v_count
ARG_VARIADIC, // argument count at specific position, doesn't affect g/f/v_count
ARG_UNKNOWN,
};
@@ -33,9 +33,9 @@ namespace ppu_func_detail
static_assert(!std::is_reference<T>::value, "Invalid function argument type (reference)");
static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_GENERAL");
static force_inline T get_arg(PPUThread& ppu)
static inline T get_arg(PPUThread& ppu)
{
return cast_from_ppu_gpr<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 force_inline T get_arg(PPUThread& ppu)
static inline T get_arg(PPUThread& ppu)
{
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>
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)
{
return ppu.VPR[v_count + 1];
return ppu.VR[v_count + 1];
}
};
template<typename T, u32 g_count, u32 f_count, u32 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(v_count <= 12, "TODO: Unsupported stack argument type (vector)");
static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_STACK");
static_assert(alignof(T) <= 16, "Unsupported type alignment for ARG_STACK");
static force_inline T get_arg(PPUThread& ppu)
{
// TODO: check stack argument displacement
const u64 res = ppu.get_stack_arg(8 + std::max<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);
return ppu_gpr_cast<T, u64>(*ppu.get_stack_arg(g_count, alignof(T))); // TODO
}
};
@@ -94,7 +90,7 @@ namespace ppu_func_detail
static force_inline ppu_va_args_t get_arg(PPUThread& ppu)
{
return{ g_count, f_count, v_count };
return{ g_count };
}
};
@@ -106,7 +102,7 @@ namespace ppu_func_detail
static force_inline void put_result(PPUThread& ppu, const T& result)
{
ppu.GPR[3] = cast_to_ppu_gpr<T>(result);
ppu.GPR[3] = ppu_gpr_cast(result);
}
};
@@ -124,11 +120,11 @@ namespace ppu_func_detail
template<typename T>
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)
{
ppu.VPR[2] = result;
ppu.VR[2] = result;
}
};
@@ -176,9 +172,9 @@ namespace ppu_func_detail
// TODO: check calculations
const bool is_float = std::is_floating_point<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_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 arg_class t =
@@ -189,19 +185,20 @@ namespace ppu_func_detail
is_variadic ? ARG_VARIADIC :
ARG_UNKNOWN;
const u32 g = g_count + is_general;
const u32 g = g_count + (is_general || is_float ? 1 : is_vector ? ::align(g_count, 2) + 2 : 0);
const u32 f = f_count + is_float;
const u32 v = v_count + is_vector;
return call<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_reference<RT>::value, "Invalid function result type (reference)");
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);
};
@@ -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);
}
}
#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 "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/state.h"
#include "Emu/IdManager.h"
#include "Emu/Cell/PPUThread.h"
#include "Emu/Cell/PPUDecoder.h"
#include "Emu/Cell/PPUInterpreter.h"
#include "Emu/Cell/PPUInterpreter2.h"
#include "Emu/Cell/PPULLVMRecompiler.h"
//#include "Emu/Cell/PPURecompiler.h"
#include "Utilities/VirtualMemory.h"
#include "PPUThread.h"
#include "PPUInterpreter.h"
#include "PPUModule.h"
#ifdef _WIN32
#include <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)))
enum class ppu_decoder_type
{
}
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)
{
memory_helper::commit_page_memory(pointer + addr / 4, size * 2);
PPUInterpreter2* inter;
PPUDecoder dec(inter = new PPUInterpreter2);
for (u32 pos = addr; pos < addr + size; pos += 4)
{
inter->func = ppu_interpreter::NULL_OP;
// decode PPU opcode
dec.Decode(vm::ps3::read32(pos));
// store function address
pointer[pos / 4] = inter->func;
}
}
PPUThread::PPUThread(const std::string& name)
: CPUThread(CPU_THREAD_PPU, name)
{
InitRotateMask();
}
PPUThread::~PPUThread()
{
close_stack();
ppu_free_tls(m_id);
}
const ppu_decoder<ppu_interpreter_precise> s_ppu_interpreter_precise;
const ppu_decoder<ppu_interpreter_fast> s_ppu_interpreter_fast;
std::string PPUThread::get_name() const
{
return fmt::format("PPU Thread[0x%x] (%s)[0x%08x]", m_id, CPUThread::get_name(), PC);
return fmt::format("PPU[0x%x] Thread (%s)", id, name);
}
void PPUThread::dump_info() const
std::string PPUThread::dump() const
{
extern std::string get_ps3_function_name(u64 fid);
std::string ret = "Registers:\n=========\n";
if (~hle_code < 1024)
{
LOG_SUCCESS(HLE, "Last syscall: %lld (%s)", ~hle_code, get_ps3_function_name(hle_code));
}
else if (hle_code)
{
LOG_SUCCESS(HLE, "Last function: %s (0x%llx)", get_ps3_function_name(hle_code), hle_code);
}
for (uint i = 0; i<32; ++i) ret += fmt::format("GPR[%d] = 0x%llx\n", i, GPR[i]);
for (uint i = 0; i<32; ++i) ret += fmt::format("FPR[%d] = %.6G\n", i, FPR[i]);
for (uint i = 0; i<32; ++i) ret += fmt::format("VR[%d] = 0x%s [%s]\n", i, VR[i].to_hex().c_str(), VR[i].to_xyzw().c_str());
ret += fmt::format("CR = 0x%08x\n", GetCR());
ret += fmt::format("LR = 0x%llx\n", LR);
ret += fmt::format("CTR = 0x%llx\n", CTR);
ret += fmt::format("XER = [CA=%u | OV=%u | SO=%u | CNT=%u]\n", u32{ CA }, u32{ OV }, u32{ SO }, u32{ XCNT });
//ret += fmt::format("FPSCR = 0x%x "
// "[RN=%d | NI=%d | XE=%d | ZE=%d | UE=%d | OE=%d | VE=%d | "
// "VXCVI=%d | VXSQRT=%d | VXSOFT=%d | FPRF=%d | "
// "FI=%d | FR=%d | VXVC=%d | VXIMZ=%d | "
// "VXZDZ=%d | VXIDI=%d | VXISI=%d | VXSNAN=%d | "
// "XX=%d | ZX=%d | UX=%d | OX=%d | VX=%d | FEX=%d | FX=%d]\n",
// FPSCR.FPSCR,
// u32{ FPSCR.RN },
// u32{ FPSCR.NI }, u32{ FPSCR.XE }, u32{ FPSCR.ZE }, u32{ FPSCR.UE }, u32{ FPSCR.OE }, u32{ FPSCR.VE },
// u32{ FPSCR.VXCVI }, u32{ FPSCR.VXSQRT }, u32{ FPSCR.VXSOFT }, u32{ FPSCR.FPRF },
// u32{ FPSCR.FI }, u32{ FPSCR.FR }, u32{ FPSCR.VXVC }, u32{ FPSCR.VXIMZ },
// u32{ FPSCR.VXZDZ }, u32{ FPSCR.VXIDI }, u32{ FPSCR.VXISI }, u32{ FPSCR.VXSNAN },
// u32{ FPSCR.XX }, u32{ FPSCR.ZX }, u32{ FPSCR.UX }, u32{ FPSCR.OX }, u32{ FPSCR.VX }, u32{ FPSCR.FEX }, u32{ FPSCR.FX });
CPUThread::dump_info();
return ret;
}
void PPUThread::init_regs()
{
GPR[1] = align(stack_addr + stack_size, 0x200) - 0x200;
GPR[13] = ppu_get_tls(m_id) + 0x7000; // 0x7000 is subtracted from r13 to access first TLS element
LR = 0;
CTR = PC;
CR.CR = 0x22000082;
VSCR.NJ = 1;
TB = 0;
//m_state |= CPU_STATE_INTR;
}
void PPUThread::init_stack()
void PPUThread::cpu_init()
{
if (!stack_addr)
{
@@ -118,14 +72,70 @@ void PPUThread::init_stack()
throw EXCEPTION("Out of stack memory");
}
}
GPR[1] = align(stack_addr + stack_size, 0x200) - 0x200;
}
void PPUThread::close_stack()
void PPUThread::cpu_task()
{
if (stack_addr)
//SetHostRoundingMode(FPSCR_RN_NEAR);
if (custom_task)
{
vm::dealloc_verbose_nothrow(stack_addr, vm::stack);
stack_addr = 0;
if (check_status()) return;
return custom_task(*this);
}
_log::g_tls_make_prefix = [](const auto&, auto, const auto&)
{
const auto cpu = static_cast<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;
}
void PPUThread::do_run()
PPUThread::~PPUThread()
{
m_dec.reset();
switch (auto mode = rpcs3::state.config.core.ppu_decoder.value())
if (stack_addr)
{
case ppu_decoder_type::interpreter: // original interpreter
{
m_dec.reset(new PPUDecoder(new PPUInterpreter(*this)));
break;
}
case ppu_decoder_type::interpreter2: // alternative interpreter
{
break;
}
case ppu_decoder_type::recompiler_llvm:
{
#ifdef PPU_LLVM_RECOMPILER
m_dec.reset(new ppu_recompiler_llvm::CPUHybridDecoderRecompiler(*this));
#else
LOG_ERROR(PPU, "This image does not include PPU JIT (LLVM)");
Emu.Pause();
#endif
break;
}
//case 3: m_dec.reset(new PPURecompiler(*this)); break;
default:
{
LOG_ERROR(PPU, "Invalid CPU decoder mode: %d", mode);
Emu.Pause();
}
vm::dealloc_verbose_nothrow(stack_addr, vm::stack);
}
}
bool FPRdouble::IsINF(PPCdouble d)
be_t<u64>* PPUThread::get_stack_arg(s32 i, u64 align)
{
return ((u64&)d & 0x7FFFFFFFFFFFFFFFULL) == 0x7FF0000000000000ULL;
}
bool FPRdouble::IsNaN(PPCdouble d)
{
return std::isnan((double)d) ? 1 : 0;
}
bool FPRdouble::IsQNaN(PPCdouble d)
{
return
((u64&)d & 0x7FF0000000000000ULL) == 0x7FF0000000000000ULL &&
((u64&)d & 0x0007FFFFFFFFFFFULL) == 0ULL &&
((u64&)d & 0x000800000000000ULL) != 0ULL;
}
bool FPRdouble::IsSNaN(PPCdouble d)
{
return
((u64&)d & 0x7FF0000000000000ULL) == 0x7FF0000000000000ULL &&
((u64&)d & 0x000FFFFFFFFFFFFFULL) != 0ULL &&
((u64&)d & 0x0008000000000000ULL) == 0ULL;
}
int FPRdouble::Cmp(PPCdouble a, PPCdouble b)
{
if(a < b) return CR_LT;
if(a > b) return CR_GT;
if(a == b) return CR_EQ;
return CR_SO;
}
u64 PPUThread::get_stack_arg(s32 i)
{
return vm::ps3::read64(VM_CAST(GPR[1] + 0x70 + 0x8 * (i - 9)));
if (align != 1 && align != 2 && align != 4 && align != 8 && align != 16) throw fmt::exception("Unsupported alignment: 0x%llx" HERE, align);
return vm::_ptr<u64>(vm::cast((GPR[1] + 0x30 + 0x8 * (i - 1)) & (0 - align), HERE));
}
void PPUThread::fast_call(u32 addr, u32 rtoc)
{
if (!is_current())
{
throw EXCEPTION("Called from the wrong thread");
}
auto old_PC = PC;
auto old_stack = GPR[1];
auto old_rtoc = GPR[2];
auto old_LR = LR;
auto old_task = std::move(custom_task);
assert(!old_task || !custom_task);
PC = addr;
GPR[2] = rtoc;
LR = Emu.GetCPUThreadStop();
@@ -236,11 +175,13 @@ void PPUThread::fast_call(u32 addr, u32 rtoc)
{
cpu_task();
}
catch (CPUThreadReturn)
catch (cpu_state _s)
{
state += _s;
if (_s != cpu_state::ret) throw;
}
m_state &= ~CPU_STATE_RETURN;
state -= cpu_state::ret;
PC = old_PC;
@@ -253,135 +194,3 @@ void PPUThread::fast_call(u32 addr, u32 rtoc)
LR = old_LR;
custom_task = std::move(old_task);
}
void PPUThread::fast_stop()
{
m_state |= CPU_STATE_RETURN;
}
void PPUThread::cpu_task()
{
SetHostRoundingMode(FPSCR_RN_NEAR);
if (custom_task)
{
if (check_status()) return;
return custom_task(*this);
}
if (!g_tls_ppu_decoder_cache)
{
const auto decoder_cache = fxm::get<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 "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/SysCalls/Callback.h"
#include "Emu/IdManager.h"
#include "Loader/ELF.h"
#include "Emu/Cell/RawSPUThread.h"
// Originally, SPU MFC registers are accessed externally in a concurrent manner (don't mix with channels, SPU MFC channels are isolated)
thread_local spu_mfc_arg_t raw_spu_mfc[8] = {};
RawSPUThread::RawSPUThread(const std::string& name, u32 index)
: SPUThread(CPU_THREAD_RAW_SPU, name, index, RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index)
void RawSPUThread::cpu_task()
{
CHECK_ASSERTION(vm::falloc(offset, 0x40000) == offset);
// get next PC and SPU Interrupt status
pc = npc.exchange(0);
set_interrupt_status((pc & 1) != 0);
pc &= 0x3fffc;
SPUThread::cpu_task();
// save next PC and current SPU Interrupt status
npc = pc | ((ch_event_stat & SPU_EVENT_INTR_ENABLED) != 0);
}
bool RawSPUThread::read_reg(const u32 addr, u32& value)
@@ -81,7 +91,8 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value)
}
}))
{
exec();
state -= cpu_state::stop;
safe_notify();
}
};
@@ -182,7 +193,7 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value)
else if (value == SPU_RUNCNTL_STOP_REQUEST)
{
status &= ~SPU_STATUS_RUNNING;
stop();
state += cpu_state::stop;
}
else
{
@@ -221,17 +232,19 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value)
return false;
}
void RawSPUThread::cpu_task()
template<>
void spu_exec_loader::load() const
{
// get next PC and SPU Interrupt status
pc = npc.exchange(0);
auto spu = idm::make_ptr<RawSPUThread>("TEST_SPU");
set_interrupt_status((pc & 1) != 0);
for (const auto& prog : progs)
{
if (prog.p_type == 0x1 /* LOAD */ && prog.p_memsz)
{
std::memcpy(vm::base(spu->offset + prog.p_vaddr), prog.bin.data(), prog.p_filesz);
}
}
pc &= 0x3fffc;
SPUThread::cpu_task();
// save next PC and current SPU Interrupt status
npc = pc | ((ch_event_stat & SPU_EVENT_INTR_ENABLED) != 0);
spu->cpu_init();
spu->npc = header.e_entry;
}
+26 -17
View File
@@ -2,27 +2,36 @@
#include "SPUThread.h"
enum : u32
{
RAW_SPU_OFFSET = 0x00100000,
RAW_SPU_BASE_ADDR = 0xE0000000,
RAW_SPU_LS_OFFSET = 0x00000000,
RAW_SPU_PROB_OFFSET = 0x00040000,
};
force_inline static u32 GetRawSPURegAddrByNum(int num, int offset)
{
return RAW_SPU_OFFSET * num + RAW_SPU_BASE_ADDR + RAW_SPU_PROB_OFFSET + offset;
}
class RawSPUThread final : public SPUThread
{
void cpu_task() override;
public:
RawSPUThread(const std::string& name, u32 index);
/* IdManager setups */
using id_base = RawSPUThread;
static constexpr u32 id_min = 0;
static constexpr u32 id_max = 4;
void on_init() override
{
if (!offset)
{
// Install correct SPU index and LS address
const_cast<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 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 "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "SPUDisAsm.h"
@@ -9,10 +10,6 @@
#define ASMJIT_STATIC
#define ASMJIT_DEBUG
#ifdef _MSC_VER
#pragma comment(lib, "asmjit.lib")
#endif
#include "asmjit.h"
#define SPU_OFF_128(x) asmjit::host::oword_ptr(*cpu, OFFSET_32(SPUThread, x))
@@ -21,6 +18,9 @@
#define SPU_OFF_16(x) asmjit::host::word_ptr(*cpu, OFFSET_32(SPUThread, x))
#define SPU_OFF_8(x) asmjit::host::byte_ptr(*cpu, OFFSET_32(SPUThread, x))
const spu_decoder<spu_interpreter_fast> s_spu_interpreter; // TODO: remove
const spu_decoder<spu_recompiler> s_spu_decoder;
spu_recompiler::spu_recompiler()
: m_jit(std::make_shared<asmjit::JitRuntime>())
{
@@ -29,7 +29,7 @@ spu_recompiler::spu_recompiler()
LOG_SUCCESS(SPU, "SPU Recompiler (ASMJIT) created...");
fs::file(fs::get_config_dir() + "SPUJIT.log", fom::rewrite).write(fmt::format("SPU JIT initialization...\n\nTitle: %s\nTitle ID: %s\n\n", Emu.GetTitle().c_str(), Emu.GetTitleID().c_str()));
fs::file(fs::get_config_dir() + "SPUJIT.log", fs::rewrite).write(fmt::format("SPU JIT initialization...\n\nTitle: %s\nTitle ID: %s\n\n", Emu.GetTitle().c_str(), Emu.GetTitleID().c_str()));
}
void spu_recompiler::compile(spu_function_t& f)
@@ -145,13 +145,13 @@ void spu_recompiler::compile(spu_function_t& f)
// Disasm
dis_asm.dump_pc = m_pos;
dis_asm.do_disasm(op);
dis_asm.disasm(m_pos);
compiler.addComment(dis_asm.last_opcode.c_str());
log += dis_asm.last_opcode.c_str();
log += '\n';
// Recompiler function
(this->*spu_recompiler::opcodes[op])({ op });
(this->*s_spu_decoder.decode(op))({ op });
// Collect allocated xmm vars
for (u32 i = 0; i < vec_vars.size(); i++)
@@ -214,7 +214,7 @@ void spu_recompiler::compile(spu_function_t& f)
log += "\n\n\n";
// Append log file
fs::file(fs::get_config_dir() + "SPUJIT.log", fom::write | fom::append).write(log);
fs::file(fs::get_config_dir() + "SPUJIT.log", fs::write + fs::append).write(log);
}
spu_recompiler::XmmLink spu_recompiler::XmmAlloc() // get empty xmm register
@@ -267,7 +267,7 @@ void spu_recompiler::InterpreterCall(spu_opcode_t op)
const u32 old_pc = _spu->pc;
if (_spu->m_state && _spu->check_status())
if (_spu->state.load() && _spu->check_status())
{
return 0x2000000 | _spu->pc;
}
@@ -294,7 +294,7 @@ void spu_recompiler::InterpreterCall(spu_opcode_t op)
asmjit::X86CallNode* call = c->call(asmjit::imm_ptr(asmjit_cast<void*, u32(SPUThread*, u32, spu_inter_func_t)>(gate)), asmjit::kFuncConvHost, asmjit::FuncBuilder3<u32, void*, u32, void*>());
call->setArg(0, *cpu);
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);
// return immediately if an error occured
@@ -338,21 +338,20 @@ void spu_recompiler::FunctionCall()
LOG_ERROR(SPU, "Branch-to-self");
}
while (!_spu->m_state || !_spu->check_status())
while (!_spu->state.load() || !_spu->check_status())
{
// Call override function directly since the type is known
static_cast<SPURecompilerDecoder&>(*_spu->m_dec).DecodeMemory(_spu->offset + _spu->pc);
// Proceed recursively
spu_recompiler_base::enter(*_spu);
if (_spu->m_state & CPU_STATE_RETURN)
if (_spu->state & cpu_state::ret)
{
break;
}
if (_spu->pc == link)
{
// returned successfully
_spu->recursion_level--;
return 0;
return 0; // Successfully returned
}
}
@@ -2185,7 +2184,7 @@ void spu_recompiler::BR(spu_opcode_t op)
c->mov(*addr, target | 0x2000000);
//c->cmp(asmjit::host::dword_ptr(*ls, m_pos), 0x32); // compare instruction opcode with BR-to-self
//c->je(labels[target / 4]);
c->lock().or_(SPU_OFF_64(m_state), CPU_STATE_RETURN | CPU_STATE_STOPPED);
c->lock().or_(SPU_OFF_32(state), (to_mset(cpu_state::stop) + cpu_state::ret)._value());
c->jmp(*end);
c->unuse(*addr);
return;
@@ -2614,7 +2613,6 @@ void spu_recompiler::FMS(spu_opcode_t op)
void spu_recompiler::UNK(spu_opcode_t op)
{
throw EXCEPTION("Unknown/Illegal opcode (0x%08x)", op.opcode);
LOG_ERROR(SPU, "0x%05x: Unknown/Illegal opcode (0x%08x)", m_pos, op.opcode);
c->int3();
}
const spu_opcode_table_t<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
class spu_recompiler : public SPURecompilerBase
class spu_recompiler : public spu_recompiler_base
{
const std::shared_ptr<asmjit::JitRuntime> m_jit;
@@ -75,7 +75,7 @@ private:
asmjit::X86Mem XmmConst(__m128 data);
asmjit::X86Mem XmmConst(__m128i data);
private:
public:
void InterpreterCall(spu_opcode_t op);
void FunctionCall();
@@ -280,6 +280,4 @@ private:
void FMS(spu_opcode_t op);
void UNK(spu_opcode_t op);
static const spu_opcode_table_t<void(spu_recompiler::*)(spu_opcode_t)> opcodes;
};
+20 -20
View File
@@ -4,7 +4,7 @@
#include "SPURecompiler.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)
{
@@ -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_itype_t type = g_spu_itype[op.opcode];
const auto type = s_spu_itype.decode(op.opcode);
using namespace spu_itype;
@@ -172,15 +172,15 @@ std::shared_ptr<spu_function_t> SPUDatabase::analyse(const be_t<u32>* ls, u32 en
break;
}
if (type == BI || type == IRET) // Branch Indirect
if (type == &type::BI || type == &type::IRET) // Branch Indirect
{
if (type == IRET) LOG_ERROR(SPU, "[0x%05x] Interrupt Return", pos);
if (type == &type::IRET) LOG_ERROR(SPU, "[0x%05x] Interrupt Return", pos);
blocks.emplace(start); start = pos + 4;
}
else if (type == BR || type == BRA) // Branch Relative/Absolute
else if (type == &type::BR || type == &type::BRA) // Branch Relative/Absolute
{
const u32 target = spu_branch_target(type == BR ? pos : 0, op.i16);
const u32 target = spu_branch_target(type == &type::BR ? pos : 0, op.i16);
// Add adjacent function because it always could be
adjacent.emplace(target);
@@ -192,9 +192,9 @@ std::shared_ptr<spu_function_t> SPUDatabase::analyse(const be_t<u32>* ls, u32 en
blocks.emplace(start); start = pos + 4;
}
else if (type == BRSL || type == BRASL) // Branch Relative/Absolute and Set Link
else if (type == &type::BRSL || type == &type::BRASL) // Branch Relative/Absolute and Set Link
{
const u32 target = spu_branch_target(type == BRSL ? pos : 0, op.i16);
const u32 target = spu_branch_target(type == &type::BRSL ? pos : 0, op.i16);
if (target == pos + 4)
{
@@ -215,11 +215,11 @@ std::shared_ptr<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);
}
}
else if (type == BISL || type == BISLED) // Branch Indirect and Set Link
else if (type == &type::BISL || type == &type::BISLED) // Branch Indirect and Set Link
{
if (op.rt != 0) LOG_ERROR(SPU, "[0x%05x] Indirect function call without $LR", pos);
}
else if (type == BRNZ || type == BRZ || type == BRHNZ || type == BRHZ) // Branch Relative if (Not) Zero (Half)word
else if (type == &type::BRNZ || type == &type::BRZ || type == &type::BRHNZ || type == &type::BRHZ) // Branch Relative if (Not) Zero (Half)word
{
const u32 target = spu_branch_target(pos, op.i16);
@@ -231,24 +231,24 @@ std::shared_ptr<spu_function_t> SPUDatabase::analyse(const be_t<u32>* ls, u32 en
blocks.emplace(target);
}
}
else if (type == BINZ || type == BIZ || type == BIHNZ || type == BIHZ) // Branch Indirect if (Not) Zero (Half)word
else if (type == &type::BINZ || type == &type::BIZ || type == &type::BIHNZ || type == &type::BIHZ) // Branch Indirect if (Not) Zero (Half)word
{
}
else if (type == HBR || type == HBRA || type == HBRR) // Hint for Branch
else if (type == &type::HBR || type == &type::HBRA || type == &type::HBRR) // Hint for Branch
{
}
else if (type == STQA || type == STQD || type == STQR || type == STQX || type == FSCRWR || type == MTSPR || type == WRCH) // Store
else if (type == &type::STQA || type == &type::STQD || type == &type::STQR || type == &type::STQX || type == &type::FSCRWR || type == &type::MTSPR || type == &type::WRCH) // Store
{
}
else if (type == HEQ || type == HEQI || type == HGT || type == HGTI || type == HLGT || type == HLGTI) // Halt
else if (type == &type::HEQ || type == &type::HEQI || type == &type::HGT || type == &type::HGTI || type == &type::HLGT || type == &type::HLGTI) // Halt
{
}
else if (type == STOP || type == STOPD || type == NOP || type == LNOP || type == SYNC || type == DSYNC) // Miscellaneous
else if (type == &type::STOP || type == &type::STOPD || type == &type::NOP || type == &type::LNOP || type == &type::SYNC || type == &type::DSYNC) // Miscellaneous
{
}
else // Other instructions (writing rt reg)
{
const u32 rt = type == SELB || type == SHUFB || type == MPYA || type == FNMS || type == FMA || type == FMS ? +op.rc : +op.rt;
const u32 rt = type == &type::SELB || type == &type::SHUFB || type == &type::MPYA || type == &type::FNMS || type == &type::FMA || type == &type::FMS ? +op.rc : +op.rt;
// Analyse link register access
if (rt == 0)
@@ -258,7 +258,7 @@ std::shared_ptr<spu_function_t> SPUDatabase::analyse(const be_t<u32>* ls, u32 en
// Analyse stack pointer access
if (rt == 1)
{
if (type == ILA && pos < ila_sp_pos)
if (type == &type::ILA && pos < ila_sp_pos)
{
// set minimal ila $SP,* instruction position
ila_sp_pos = pos;
@@ -272,7 +272,7 @@ std::shared_ptr<spu_function_t> SPUDatabase::analyse(const be_t<u32>* ls, u32 en
{
const spu_opcode_t op{ ls[pos / 4] };
const spu_itype_t type = g_spu_itype[op.opcode];
const auto type = s_spu_itype.decode(op.opcode);
using namespace spu_itype;
@@ -280,9 +280,9 @@ std::shared_ptr<spu_function_t> SPUDatabase::analyse(const be_t<u32>* ls, u32 en
{
break;
}
else if (type == BRSL || type == BRASL) // Branch Relative/Absolute and Set Link
else if (type == &type::BRSL || type == &type::BRASL) // Branch Relative/Absolute and Set Link
{
const u32 target = spu_branch_target(type == BRSL ? pos : 0, op.i16);
const u32 target = spu_branch_target(type == &type::BRSL ? pos : 0, op.i16);
if (target != pos + 4 && target > entry && limit > target)
{
+213 -217
View File
@@ -3,250 +3,246 @@
#include "Emu/Cell/SPUOpcodes.h"
#include "Utilities/SharedMutex.h"
#include <set>
class SPUThread;
// Type of the runtime functions generated by SPU recompiler
using spu_jit_func_t = u32(*)(SPUThread* _spu, be_t<u32>* _ls);
// SPU instruction classification namespace
// SPU Instruction Classifier
namespace spu_itype
{
enum spu_itype_t : u32
struct type
{
UNK = 0,
STOP,
LNOP,
SYNC,
DSYNC,
MFSPR,
RDCH,
RCHCNT,
SF,
OR,
BG,
SFH,
NOR,
ABSDB,
ROT,
ROTM,
ROTMA,
SHL,
ROTH,
ROTHM,
ROTMAH,
SHLH,
ROTI,
ROTMI,
ROTMAI,
SHLI,
ROTHI,
ROTHMI,
ROTMAHI,
SHLHI,
A,
AND,
CG,
AH,
NAND,
AVGB,
MTSPR,
WRCH,
BIZ,
BINZ,
BIHZ,
BIHNZ,
STOPD,
STQX,
BI,
BISL,
IRET,
BISLED,
HBR,
GB,
GBH,
GBB,
FSM,
FSMH,
FSMB,
FREST,
FRSQEST,
LQX,
ROTQBYBI,
ROTQMBYBI,
SHLQBYBI,
CBX,
CHX,
CWX,
CDX,
ROTQBI,
ROTQMBI,
SHLQBI,
ROTQBY,
ROTQMBY,
SHLQBY,
ORX,
CBD,
CHD,
CWD,
CDD,
ROTQBII,
ROTQMBII,
SHLQBII,
ROTQBYI,
ROTQMBYI,
SHLQBYI,
NOP,
CGT,
XOR,
CGTH,
EQV,
CGTB,
SUMB,
HGT,
CLZ,
XSWD,
XSHW,
CNTB,
XSBH,
CLGT,
ANDC,
FCGT,
DFCGT,
FA,
FS,
FM,
CLGTH,
ORC,
FCMGT,
DFCMGT,
DFA,
DFS,
DFM,
CLGTB,
HLGT,
DFMA,
DFMS,
DFNMS,
DFNMA,
CEQ,
MPYHHU,
ADDX,
SFX,
CGX,
BGX,
MPYHHA,
MPYHHAU,
FSCRRD,
FESD,
FRDS,
FSCRWR,
DFTSV,
FCEQ,
DFCEQ,
MPY,
MPYH,
MPYHH,
MPYS,
CEQH,
FCMEQ,
DFCMEQ,
MPYU,
CEQB,
FI,
HEQ,
CFLTS,
CFLTU,
CSFLT,
CUFLT,
BRZ,
STQA,
BRNZ,
BRHZ,
BRHNZ,
STQR,
BRA,
LQA,
BRASL,
BR,
FSMBI,
BRSL,
LQR,
IL,
ILHU,
ILH,
IOHL,
ORI,
ORHI,
ORBI,
SFI,
SFHI,
ANDI,
ANDHI,
ANDBI,
AI,
AHI,
STQD,
LQD,
XORI,
XORHI,
XORBI,
CGTI,
CGTHI,
CGTBI,
HGTI,
CLGTI,
CLGTHI,
CLGTBI,
HLGTI,
MPYI,
MPYUI,
CEQI,
CEQHI,
CEQBI,
HEQI,
HBRA,
HBRR,
ILA,
SELB,
SHUFB,
MPYA,
FNMS,
FMA,
FMS,
u32 UNK;
u32 STOP;
u32 LNOP;
u32 SYNC;
u32 DSYNC;
u32 MFSPR;
u32 RDCH;
u32 RCHCNT;
u32 SF;
u32 OR;
u32 BG;
u32 SFH;
u32 NOR;
u32 ABSDB;
u32 ROT;
u32 ROTM;
u32 ROTMA;
u32 SHL;
u32 ROTH;
u32 ROTHM;
u32 ROTMAH;
u32 SHLH;
u32 ROTI;
u32 ROTMI;
u32 ROTMAI;
u32 SHLI;
u32 ROTHI;
u32 ROTHMI;
u32 ROTMAHI;
u32 SHLHI;
u32 A;
u32 AND;
u32 CG;
u32 AH;
u32 NAND;
u32 AVGB;
u32 MTSPR;
u32 WRCH;
u32 BIZ;
u32 BINZ;
u32 BIHZ;
u32 BIHNZ;
u32 STOPD;
u32 STQX;
u32 BI;
u32 BISL;
u32 IRET;
u32 BISLED;
u32 HBR;
u32 GB;
u32 GBH;
u32 GBB;
u32 FSM;
u32 FSMH;
u32 FSMB;
u32 FREST;
u32 FRSQEST;
u32 LQX;
u32 ROTQBYBI;
u32 ROTQMBYBI;
u32 SHLQBYBI;
u32 CBX;
u32 CHX;
u32 CWX;
u32 CDX;
u32 ROTQBI;
u32 ROTQMBI;
u32 SHLQBI;
u32 ROTQBY;
u32 ROTQMBY;
u32 SHLQBY;
u32 ORX;
u32 CBD;
u32 CHD;
u32 CWD;
u32 CDD;
u32 ROTQBII;
u32 ROTQMBII;
u32 SHLQBII;
u32 ROTQBYI;
u32 ROTQMBYI;
u32 SHLQBYI;
u32 NOP;
u32 CGT;
u32 XOR;
u32 CGTH;
u32 EQV;
u32 CGTB;
u32 SUMB;
u32 HGT;
u32 CLZ;
u32 XSWD;
u32 XSHW;
u32 CNTB;
u32 XSBH;
u32 CLGT;
u32 ANDC;
u32 FCGT;
u32 DFCGT;
u32 FA;
u32 FS;
u32 FM;
u32 CLGTH;
u32 ORC;
u32 FCMGT;
u32 DFCMGT;
u32 DFA;
u32 DFS;
u32 DFM;
u32 CLGTB;
u32 HLGT;
u32 DFMA;
u32 DFMS;
u32 DFNMS;
u32 DFNMA;
u32 CEQ;
u32 MPYHHU;
u32 ADDX;
u32 SFX;
u32 CGX;
u32 BGX;
u32 MPYHHA;
u32 MPYHHAU;
u32 FSCRRD;
u32 FESD;
u32 FRDS;
u32 FSCRWR;
u32 DFTSV;
u32 FCEQ;
u32 DFCEQ;
u32 MPY;
u32 MPYH;
u32 MPYHH;
u32 MPYS;
u32 CEQH;
u32 FCMEQ;
u32 DFCMEQ;
u32 MPYU;
u32 CEQB;
u32 FI;
u32 HEQ;
u32 CFLTS;
u32 CFLTU;
u32 CSFLT;
u32 CUFLT;
u32 BRZ;
u32 STQA;
u32 BRNZ;
u32 BRHZ;
u32 BRHNZ;
u32 STQR;
u32 BRA;
u32 LQA;
u32 BRASL;
u32 BR;
u32 FSMBI;
u32 BRSL;
u32 LQR;
u32 IL;
u32 ILHU;
u32 ILH;
u32 IOHL;
u32 ORI;
u32 ORHI;
u32 ORBI;
u32 SFI;
u32 SFHI;
u32 ANDI;
u32 ANDHI;
u32 ANDBI;
u32 AI;
u32 AHI;
u32 STQD;
u32 LQD;
u32 XORI;
u32 XORHI;
u32 XORBI;
u32 CGTI;
u32 CGTHI;
u32 CGTBI;
u32 HGTI;
u32 CLGTI;
u32 CLGTHI;
u32 CLGTBI;
u32 HLGTI;
u32 MPYI;
u32 MPYUI;
u32 CEQI;
u32 CEQHI;
u32 CEQBI;
u32 HEQI;
u32 HBRA;
u32 HBRR;
u32 ILA;
u32 SELB;
u32 SHUFB;
u32 MPYA;
u32 FNMS;
u32 FMA;
u32 FMS;
};
}
using spu_itype::spu_itype_t;
// SPU Instruction Classification table
extern const spu_opcode_table_t<spu_itype_t> g_spu_itype;
};
// SPU basic function information structure
struct spu_function_t
{
// entry point (LS address)
// Entry point (LS address)
const u32 addr;
// function size (in bytes)
// Function size (in bytes)
const u32 size;
// function contents (binary copy)
// Function contents (binary copy)
std::vector<be_t<u32>> data;
// basic blocks (start addresses)
// Basic blocks (start addresses)
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;
// jump table values (start addresses)
// Jump table values (start addresses)
std::set<u32> jtable;
// whether ila $SP,* instruction found
// Whether ila $SP,* instruction found
bool does_reset_stack;
// pointer to the compiled function
// Pointer to the compiled function
spu_jit_func_t compiled = nullptr;
spu_function_t(u32 addr, u32 size)
-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",
};
class SPUDisAsm : public PPCDisAsm
class SPUDisAsm final : public PPCDisAsm
{
public:
SPUDisAsm(CPUDisAsmMode mode) : PPCDisAsm(mode)
@@ -133,6 +133,10 @@ private:
{
Write(fmt::format("%s %s,%s,%s,%s", FixOp(op).c_str(), a1, a2, a3, a4));
}
public:
u32 disasm(u32 pc) override;
//0 - 10
void STOP(spu_opcode_t op)
{
@@ -945,12 +949,4 @@ private:
{
Write(fmt::format("Unknown/Illegal opcode! (0x%08x)", op.opcode));
}
static const spu_opcode_table_t<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>
namespace spu_interpreter
{
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)
void spu_interpreter::UNK(SPUThread& spu, spu_opcode_t op)
{
throw EXCEPTION("Unknown/Illegal instruction (0x%08x)", op.opcode);
}
@@ -396,12 +383,12 @@ void spu_interpreter::FSMB(SPUThread& spu, spu_opcode_t op)
spu.gpr[op.rt] = g_spu_imm.fsmb[spu.gpr[op.ra]._u32[3] & 0xffff];
}
void spu_interpreter::fast::FREST(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_fast::FREST(SPUThread& spu, spu_opcode_t op)
{
spu.gpr[op.rt].vf = _mm_rcp_ps(spu.gpr[op.ra].vf);
}
void spu_interpreter::fast::FRSQEST(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_fast::FRSQEST(SPUThread& spu, spu_opcode_t op)
{
const auto mask = _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff));
spu.gpr[op.rt].vf = _mm_rsqrt_ps(_mm_and_ps(spu.gpr[op.ra].vf, mask));
@@ -687,7 +674,7 @@ void spu_interpreter::ANDC(SPUThread& spu, spu_opcode_t op)
spu.gpr[op.rt] = v128::andnot(spu.gpr[op.rb], spu.gpr[op.ra]);
}
void spu_interpreter::fast::FCGT(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_fast::FCGT(SPUThread& spu, spu_opcode_t op)
{
spu.gpr[op.rt].vf = _mm_cmplt_ps(spu.gpr[op.rb].vf, spu.gpr[op.ra].vf);
}
@@ -697,17 +684,17 @@ void spu_interpreter::DFCGT(SPUThread& spu, spu_opcode_t op)
throw EXCEPTION("Unexpected instruction");
}
void spu_interpreter::fast::FA(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_fast::FA(SPUThread& spu, spu_opcode_t op)
{
spu.gpr[op.rt] = v128::addfs(spu.gpr[op.ra], spu.gpr[op.rb]);
}
void spu_interpreter::fast::FS(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_fast::FS(SPUThread& spu, spu_opcode_t op)
{
spu.gpr[op.rt] = v128::subfs(spu.gpr[op.ra], spu.gpr[op.rb]);
}
void spu_interpreter::fast::FM(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_fast::FM(SPUThread& spu, spu_opcode_t op)
{
spu.gpr[op.rt].vf = _mm_mul_ps(spu.gpr[op.ra].vf, spu.gpr[op.rb].vf);
}
@@ -722,7 +709,7 @@ void spu_interpreter::ORC(SPUThread& spu, spu_opcode_t op)
spu.gpr[op.rt] = spu.gpr[op.ra] | ~spu.gpr[op.rb];
}
void spu_interpreter::fast::FCMGT(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_fast::FCMGT(SPUThread& spu, spu_opcode_t op)
{
const auto mask = _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff));
spu.gpr[op.rt].vf = _mm_cmplt_ps(_mm_and_ps(spu.gpr[op.rb].vf, mask), _mm_and_ps(spu.gpr[op.ra].vf, mask));
@@ -733,17 +720,17 @@ void spu_interpreter::DFCMGT(SPUThread& spu, spu_opcode_t op)
throw EXCEPTION("Unexpected instruction");
}
void spu_interpreter::fast::DFA(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_fast::DFA(SPUThread& spu, spu_opcode_t op)
{
spu.gpr[op.rt] = v128::addfd(spu.gpr[op.ra], spu.gpr[op.rb]);
}
void spu_interpreter::fast::DFS(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_fast::DFS(SPUThread& spu, spu_opcode_t op)
{
spu.gpr[op.rt] = v128::subfd(spu.gpr[op.ra], spu.gpr[op.rb]);
}
void spu_interpreter::fast::DFM(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_fast::DFM(SPUThread& spu, spu_opcode_t op)
{
spu.gpr[op.rt].vd = _mm_mul_pd(spu.gpr[op.ra].vd, spu.gpr[op.rb].vd);
}
@@ -761,22 +748,22 @@ void spu_interpreter::HLGT(SPUThread& spu, spu_opcode_t op)
}
}
void spu_interpreter::fast::DFMA(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_fast::DFMA(SPUThread& spu, spu_opcode_t op)
{
spu.gpr[op.rt].vd = _mm_add_pd(_mm_mul_pd(spu.gpr[op.ra].vd, spu.gpr[op.rb].vd), spu.gpr[op.rt].vd);
}
void spu_interpreter::fast::DFMS(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_fast::DFMS(SPUThread& spu, spu_opcode_t op)
{
spu.gpr[op.rt].vd = _mm_sub_pd(_mm_mul_pd(spu.gpr[op.ra].vd, spu.gpr[op.rb].vd), spu.gpr[op.rt].vd);
}
void spu_interpreter::fast::DFNMS(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_fast::DFNMS(SPUThread& spu, spu_opcode_t op)
{
spu.gpr[op.rt].vd = _mm_sub_pd(spu.gpr[op.rt].vd, _mm_mul_pd(spu.gpr[op.ra].vd, spu.gpr[op.rb].vd));
}
void spu_interpreter::fast::DFNMA(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_fast::DFNMA(SPUThread& spu, spu_opcode_t op)
{
spu.gpr[op.rt].vd = _mm_sub_pd(_mm_set1_pd(0.0), _mm_add_pd(_mm_mul_pd(spu.gpr[op.ra].vd, spu.gpr[op.rb].vd), spu.gpr[op.rt].vd));
}
@@ -833,24 +820,24 @@ void spu_interpreter::MPYHHAU(SPUThread& spu, spu_opcode_t op)
spu.gpr[op.rt].vi = _mm_add_epi32(spu.gpr[op.rt].vi, _mm_or_si128(_mm_srli_epi32(_mm_mullo_epi16(a, b), 16), _mm_and_si128(_mm_mulhi_epu16(a, b), _mm_set1_epi32(0xffff0000))));
}
void spu_interpreter::fast::FSCRRD(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_fast::FSCRRD(SPUThread& spu, spu_opcode_t op)
{
spu.gpr[op.rt].clear();
}
void spu_interpreter::fast::FESD(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_fast::FESD(SPUThread& spu, spu_opcode_t op)
{
const auto a = spu.gpr[op.ra].vf;
spu.gpr[op.rt].vd = _mm_cvtps_pd(_mm_shuffle_ps(a, a, 0x8d));
}
void spu_interpreter::fast::FRDS(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_fast::FRDS(SPUThread& spu, spu_opcode_t op)
{
const auto t = _mm_cvtpd_ps(spu.gpr[op.ra].vd);
spu.gpr[op.rt].vf = _mm_shuffle_ps(t, t, 0x72);
}
void spu_interpreter::fast::FSCRWR(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_fast::FSCRWR(SPUThread& spu, spu_opcode_t op)
{
}
@@ -859,7 +846,7 @@ void spu_interpreter::DFTSV(SPUThread& spu, spu_opcode_t op)
throw EXCEPTION("Unexpected instruction");
}
void spu_interpreter::fast::FCEQ(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_fast::FCEQ(SPUThread& spu, spu_opcode_t op)
{
spu.gpr[op.rt].vf = _mm_cmpeq_ps(spu.gpr[op.rb].vf, spu.gpr[op.ra].vf);
}
@@ -895,7 +882,7 @@ void spu_interpreter::CEQH(SPUThread& spu, spu_opcode_t op)
spu.gpr[op.rt].vi = _mm_cmpeq_epi16(spu.gpr[op.ra].vi, spu.gpr[op.rb].vi);
}
void spu_interpreter::fast::FCMEQ(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_fast::FCMEQ(SPUThread& spu, spu_opcode_t op)
{
const auto mask = _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff));
spu.gpr[op.rt].vf = _mm_cmpeq_ps(_mm_and_ps(spu.gpr[op.rb].vf, mask), _mm_and_ps(spu.gpr[op.ra].vf, mask));
@@ -918,7 +905,7 @@ void spu_interpreter::CEQB(SPUThread& spu, spu_opcode_t op)
spu.gpr[op.rt].vi = _mm_cmpeq_epi8(spu.gpr[op.ra].vi, spu.gpr[op.rb].vi);
}
void spu_interpreter::fast::FI(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_fast::FI(SPUThread& spu, spu_opcode_t op)
{
// TODO
const auto mask_se = _mm_castsi128_ps(_mm_set1_epi32(0xff800000)); // sign and exponent mask
@@ -940,25 +927,25 @@ void spu_interpreter::HEQ(SPUThread& spu, spu_opcode_t op)
}
void spu_interpreter::fast::CFLTS(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_fast::CFLTS(SPUThread& spu, spu_opcode_t op)
{
const auto scaled = _mm_mul_ps(spu.gpr[op.ra].vf, g_spu_imm.scale[173 - op.i8]);
spu.gpr[op.rt].vi = _mm_xor_si128(_mm_cvttps_epi32(scaled), _mm_castps_si128(_mm_cmpge_ps(scaled, _mm_set1_ps(0x80000000))));
}
void spu_interpreter::fast::CFLTU(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_fast::CFLTU(SPUThread& spu, spu_opcode_t op)
{
const auto scaled1 = _mm_max_ps(_mm_mul_ps(spu.gpr[op.ra].vf, g_spu_imm.scale[173 - op.i8]), _mm_set1_ps(0.0f));
const auto scaled2 = _mm_and_ps(_mm_sub_ps(scaled1, _mm_set1_ps(0x80000000)), _mm_cmpge_ps(scaled1, _mm_set1_ps(0x80000000)));
spu.gpr[op.rt].vi = _mm_or_si128(_mm_or_si128(_mm_cvttps_epi32(scaled1), _mm_cvttps_epi32(scaled2)), _mm_castps_si128(_mm_cmpge_ps(scaled1, _mm_set1_ps(0x100000000))));
}
void spu_interpreter::fast::CSFLT(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_fast::CSFLT(SPUThread& spu, spu_opcode_t op)
{
spu.gpr[op.rt].vf = _mm_mul_ps(_mm_cvtepi32_ps(spu.gpr[op.ra].vi), g_spu_imm.scale[op.i8 - 155]);
}
void spu_interpreter::fast::CUFLT(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_fast::CUFLT(SPUThread& spu, spu_opcode_t op)
{
const auto a = spu.gpr[op.ra].vi;
const auto fix = _mm_and_ps(_mm_castsi128_ps(_mm_srai_epi32(a, 31)), _mm_set1_ps(0x80000000));
@@ -1265,17 +1252,17 @@ void spu_interpreter::MPYA(SPUThread& spu, spu_opcode_t op)
spu.gpr[op.rt4].vi = _mm_add_epi32(spu.gpr[op.rc].vi, _mm_madd_epi16(_mm_and_si128(spu.gpr[op.ra].vi, mask), _mm_and_si128(spu.gpr[op.rb].vi, mask)));
}
void spu_interpreter::fast::FNMS(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_fast::FNMS(SPUThread& spu, spu_opcode_t op)
{
spu.gpr[op.rt4].vf = _mm_sub_ps(spu.gpr[op.rc].vf, _mm_mul_ps(spu.gpr[op.ra].vf, spu.gpr[op.rb].vf));
}
void spu_interpreter::fast::FMA(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_fast::FMA(SPUThread& spu, spu_opcode_t op)
{
spu.gpr[op.rt4].vf = _mm_add_ps(_mm_mul_ps(spu.gpr[op.ra].vf, spu.gpr[op.rb].vf), spu.gpr[op.rc].vf);
}
void spu_interpreter::fast::FMS(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_fast::FMS(SPUThread& spu, spu_opcode_t op)
{
spu.gpr[op.rt4].vf = _mm_sub_ps(_mm_mul_ps(spu.gpr[op.ra].vf, spu.gpr[op.rb].vf), spu.gpr[op.rc].vf);
}
@@ -1360,7 +1347,7 @@ inline bool isdenormal(double x)
#endif
}
void spu_interpreter::precise::FREST(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_precise::FREST(SPUThread& spu, spu_opcode_t op)
{
SetHostRoundingMode(FPSCR_RN_ZERO);
for (int i = 0; i < 4; i++)
@@ -1380,7 +1367,7 @@ void spu_interpreter::precise::FREST(SPUThread& spu, spu_opcode_t op)
}
}
void spu_interpreter::precise::FRSQEST(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_precise::FRSQEST(SPUThread& spu, spu_opcode_t op)
{
SetHostRoundingMode(FPSCR_RN_ZERO);
for (int i = 0; i < 4; i++)
@@ -1400,7 +1387,7 @@ void spu_interpreter::precise::FRSQEST(SPUThread& spu, spu_opcode_t op)
}
}
void spu_interpreter::precise::FCGT(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_precise::FCGT(SPUThread& spu, spu_opcode_t op)
{
for (int i = 0; i < 4; i++)
{
@@ -1508,11 +1495,11 @@ static void FA_FS(SPUThread& spu, spu_opcode_t op, bool sub)
}
}
void spu_interpreter::precise::FA(SPUThread& spu, spu_opcode_t op) { FA_FS(spu, op, false); }
void spu_interpreter_precise::FA(SPUThread& spu, spu_opcode_t op) { FA_FS(spu, op, false); }
void spu_interpreter::precise::FS(SPUThread& spu, spu_opcode_t op) { FA_FS(spu, op, true); }
void spu_interpreter_precise::FS(SPUThread& spu, spu_opcode_t op) { FA_FS(spu, op, true); }
void spu_interpreter::precise::FM(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_precise::FM(SPUThread& spu, spu_opcode_t op)
{
SetHostRoundingMode(FPSCR_RN_ZERO);
for (int w = 0; w < 4; w++)
@@ -1585,7 +1572,7 @@ void spu_interpreter::precise::FM(SPUThread& spu, spu_opcode_t op)
}
}
void spu_interpreter::precise::FCMGT(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_precise::FCMGT(SPUThread& spu, spu_opcode_t op)
{
for (int i = 0; i < 4; i++)
{
@@ -1666,11 +1653,11 @@ static void DFASM(SPUThread& spu, spu_opcode_t op, DoubleOp operation)
}
}
void spu_interpreter::precise::DFA(SPUThread& spu, spu_opcode_t op) { DFASM(spu, op, DFASM_A); }
void spu_interpreter_precise::DFA(SPUThread& spu, spu_opcode_t op) { DFASM(spu, op, DFASM_A); }
void spu_interpreter::precise::DFS(SPUThread& spu, spu_opcode_t op) { DFASM(spu, op, DFASM_S); }
void spu_interpreter_precise::DFS(SPUThread& spu, spu_opcode_t op) { DFASM(spu, op, DFASM_S); }
void spu_interpreter::precise::DFM(SPUThread& spu, spu_opcode_t op) { DFASM(spu, op, DFASM_M); }
void spu_interpreter_precise::DFM(SPUThread& spu, spu_opcode_t op) { DFASM(spu, op, DFASM_M); }
static void DFMA(SPUThread& spu, spu_opcode_t op, bool neg, bool sub)
{
@@ -1727,20 +1714,20 @@ static void DFMA(SPUThread& spu, spu_opcode_t op, bool neg, bool sub)
}
}
void spu_interpreter::precise::DFMA(SPUThread& spu, spu_opcode_t op) { DFMA(spu, op, false, false); }
void spu_interpreter_precise::DFMA(SPUThread& spu, spu_opcode_t op) { ::DFMA(spu, op, false, false); }
void spu_interpreter::precise::DFMS(SPUThread& spu, spu_opcode_t op) { DFMA(spu, op, false, true); }
void spu_interpreter_precise::DFMS(SPUThread& spu, spu_opcode_t op) { ::DFMA(spu, op, false, true); }
void spu_interpreter::precise::DFNMS(SPUThread& spu, spu_opcode_t op) { DFMA(spu, op, true, true); }
void spu_interpreter_precise::DFNMS(SPUThread& spu, spu_opcode_t op) { ::DFMA(spu, op, true, true); }
void spu_interpreter::precise::DFNMA(SPUThread& spu, spu_opcode_t op) { DFMA(spu, op, true, false); }
void spu_interpreter_precise::DFNMA(SPUThread& spu, spu_opcode_t op) { ::DFMA(spu, op, true, false); }
void spu_interpreter::precise::FSCRRD(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_precise::FSCRRD(SPUThread& spu, spu_opcode_t op)
{
spu.fpscr.Read(spu.gpr[op.rt]);
}
void spu_interpreter::precise::FESD(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_precise::FESD(SPUThread& spu, spu_opcode_t op)
{
for (int i = 0; i < 2; i++)
{
@@ -1764,7 +1751,7 @@ void spu_interpreter::precise::FESD(SPUThread& spu, spu_opcode_t op)
}
}
void spu_interpreter::precise::FRDS(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_precise::FRDS(SPUThread& spu, spu_opcode_t op)
{
for (int i = 0; i < 2; i++)
{
@@ -1792,12 +1779,12 @@ void spu_interpreter::precise::FRDS(SPUThread& spu, spu_opcode_t op)
}
}
void spu_interpreter::precise::FSCRWR(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_precise::FSCRWR(SPUThread& spu, spu_opcode_t op)
{
spu.fpscr.Write(spu.gpr[op.ra]);
}
void spu_interpreter::precise::FCEQ(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_precise::FCEQ(SPUThread& spu, spu_opcode_t op)
{
for (int i = 0; i < 4; i++)
{
@@ -1812,7 +1799,7 @@ void spu_interpreter::precise::FCEQ(SPUThread& spu, spu_opcode_t op)
}
}
void spu_interpreter::precise::FCMEQ(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_precise::FCMEQ(SPUThread& spu, spu_opcode_t op)
{
for (int i = 0; i < 4; i++)
{
@@ -1827,13 +1814,13 @@ void spu_interpreter::precise::FCMEQ(SPUThread& spu, spu_opcode_t op)
}
}
void spu_interpreter::precise::FI(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_precise::FI(SPUThread& spu, spu_opcode_t op)
{
// TODO
spu.gpr[op.rt] = spu.gpr[op.rb];
}
void spu_interpreter::precise::CFLTS(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_precise::CFLTS(SPUThread& spu, spu_opcode_t op)
{
const int scale = 173 - (op.i8 & 0xff); //unsigned immediate
for (int i = 0; i < 4; i++)
@@ -1855,7 +1842,7 @@ void spu_interpreter::precise::CFLTS(SPUThread& spu, spu_opcode_t op)
}
}
void spu_interpreter::precise::CFLTU(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_precise::CFLTU(SPUThread& spu, spu_opcode_t op)
{
const int scale = 173 - (op.i8 & 0xff); //unsigned immediate
for (int i = 0; i < 4; i++)
@@ -1877,7 +1864,7 @@ void spu_interpreter::precise::CFLTU(SPUThread& spu, spu_opcode_t op)
}
}
void spu_interpreter::precise::CSFLT(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_precise::CSFLT(SPUThread& spu, spu_opcode_t op)
{
SetHostRoundingMode(FPSCR_RN_ZERO);
const int scale = 155 - (op.i8 & 0xff); //unsigned immediate
@@ -1900,7 +1887,7 @@ void spu_interpreter::precise::CSFLT(SPUThread& spu, spu_opcode_t op)
}
}
void spu_interpreter::precise::CUFLT(SPUThread& spu, spu_opcode_t op)
void spu_interpreter_precise::CUFLT(SPUThread& spu, spu_opcode_t op)
{
SetHostRoundingMode(FPSCR_RN_ZERO);
const int scale = 155 - (op.i8 & 0xff); //unsigned immediate
@@ -2068,8 +2055,8 @@ static void FMA(SPUThread& spu, spu_opcode_t op, bool neg, bool sub)
}
}
void spu_interpreter::precise::FNMS(SPUThread& spu, spu_opcode_t op) { FMA(spu, op, true, true); }
void spu_interpreter_precise::FNMS(SPUThread& spu, spu_opcode_t op) { ::FMA(spu, op, true, true); }
void spu_interpreter::precise::FMA(SPUThread& spu, spu_opcode_t op) { FMA(spu, op, false, false); }
void spu_interpreter_precise::FMA(SPUThread& spu, spu_opcode_t op) { ::FMA(spu, op, false, false); }
void spu_interpreter::precise::FMS(SPUThread& spu, spu_opcode_t op) { FMA(spu, op, false, true); }
void spu_interpreter_precise::FMS(SPUThread& spu, spu_opcode_t op) { ::FMA(spu, op, false, true); }
+238 -248
View File
@@ -4,256 +4,246 @@
class SPUThread;
using spu_inter_func_t = void(*)(SPUThread& spu, spu_opcode_t opcode);
using spu_inter_func_t = void(*)(SPUThread& spu, spu_opcode_t op);
namespace spu_interpreter
struct spu_interpreter
{
namespace fast
{
extern const spu_opcode_table_t<spu_inter_func_t> g_spu_opcode_table;
}
static void UNK(SPUThread&, spu_opcode_t);
static void set_interrupt_status(SPUThread&, spu_opcode_t);
namespace precise
{
extern const spu_opcode_table_t<spu_inter_func_t> g_spu_opcode_table;
}
static void STOP(SPUThread&, spu_opcode_t);
static void LNOP(SPUThread&, spu_opcode_t);
static void SYNC(SPUThread&, spu_opcode_t);
static void DSYNC(SPUThread&, spu_opcode_t);
static void MFSPR(SPUThread&, spu_opcode_t);
static void RDCH(SPUThread&, spu_opcode_t);
static void RCHCNT(SPUThread&, spu_opcode_t);
static void SF(SPUThread&, spu_opcode_t);
static void OR(SPUThread&, spu_opcode_t);
static void BG(SPUThread&, spu_opcode_t);
static void SFH(SPUThread&, spu_opcode_t);
static void NOR(SPUThread&, spu_opcode_t);
static void ABSDB(SPUThread&, spu_opcode_t);
static void ROT(SPUThread&, spu_opcode_t);
static void ROTM(SPUThread&, spu_opcode_t);
static void ROTMA(SPUThread&, spu_opcode_t);
static void SHL(SPUThread&, spu_opcode_t);
static void ROTH(SPUThread&, spu_opcode_t);
static void ROTHM(SPUThread&, spu_opcode_t);
static void ROTMAH(SPUThread&, spu_opcode_t);
static void SHLH(SPUThread&, spu_opcode_t);
static void ROTI(SPUThread&, spu_opcode_t);
static void ROTMI(SPUThread&, spu_opcode_t);
static void ROTMAI(SPUThread&, spu_opcode_t);
static void SHLI(SPUThread&, spu_opcode_t);
static void ROTHI(SPUThread&, spu_opcode_t);
static void ROTHMI(SPUThread&, spu_opcode_t);
static void ROTMAHI(SPUThread&, spu_opcode_t);
static void SHLHI(SPUThread&, spu_opcode_t);
static void A(SPUThread&, spu_opcode_t);
static void AND(SPUThread&, spu_opcode_t);
static void CG(SPUThread&, spu_opcode_t);
static void AH(SPUThread&, spu_opcode_t);
static void NAND(SPUThread&, spu_opcode_t);
static void AVGB(SPUThread&, spu_opcode_t);
static void MTSPR(SPUThread&, spu_opcode_t);
static void WRCH(SPUThread&, spu_opcode_t);
static void BIZ(SPUThread&, spu_opcode_t);
static void BINZ(SPUThread&, spu_opcode_t);
static void BIHZ(SPUThread&, spu_opcode_t);
static void BIHNZ(SPUThread&, spu_opcode_t);
static void STOPD(SPUThread&, spu_opcode_t);
static void STQX(SPUThread&, spu_opcode_t);
static void BI(SPUThread&, spu_opcode_t);
static void BISL(SPUThread&, spu_opcode_t);
static void IRET(SPUThread&, spu_opcode_t);
static void BISLED(SPUThread&, spu_opcode_t);
static void HBR(SPUThread&, spu_opcode_t);
static void GB(SPUThread&, spu_opcode_t);
static void GBH(SPUThread&, spu_opcode_t);
static void GBB(SPUThread&, spu_opcode_t);
static void FSM(SPUThread&, spu_opcode_t);
static void FSMH(SPUThread&, spu_opcode_t);
static void FSMB(SPUThread&, spu_opcode_t);
static void LQX(SPUThread&, spu_opcode_t);
static void ROTQBYBI(SPUThread&, spu_opcode_t);
static void ROTQMBYBI(SPUThread&, spu_opcode_t);
static void SHLQBYBI(SPUThread&, spu_opcode_t);
static void CBX(SPUThread&, spu_opcode_t);
static void CHX(SPUThread&, spu_opcode_t);
static void CWX(SPUThread&, spu_opcode_t);
static void CDX(SPUThread&, spu_opcode_t);
static void ROTQBI(SPUThread&, spu_opcode_t);
static void ROTQMBI(SPUThread&, spu_opcode_t);
static void SHLQBI(SPUThread&, spu_opcode_t);
static void ROTQBY(SPUThread&, spu_opcode_t);
static void ROTQMBY(SPUThread&, spu_opcode_t);
static void SHLQBY(SPUThread&, spu_opcode_t);
static void ORX(SPUThread&, spu_opcode_t);
static void CBD(SPUThread&, spu_opcode_t);
static void CHD(SPUThread&, spu_opcode_t);
static void CWD(SPUThread&, spu_opcode_t);
static void CDD(SPUThread&, spu_opcode_t);
static void ROTQBII(SPUThread&, spu_opcode_t);
static void ROTQMBII(SPUThread&, spu_opcode_t);
static void SHLQBII(SPUThread&, spu_opcode_t);
static void ROTQBYI(SPUThread&, spu_opcode_t);
static void ROTQMBYI(SPUThread&, spu_opcode_t);
static void SHLQBYI(SPUThread&, spu_opcode_t);
static void NOP(SPUThread&, spu_opcode_t);
static void CGT(SPUThread&, spu_opcode_t);
static void XOR(SPUThread&, spu_opcode_t);
static void CGTH(SPUThread&, spu_opcode_t);
static void EQV(SPUThread&, spu_opcode_t);
static void CGTB(SPUThread&, spu_opcode_t);
static void SUMB(SPUThread&, spu_opcode_t);
static void HGT(SPUThread&, spu_opcode_t);
static void CLZ(SPUThread&, spu_opcode_t);
static void XSWD(SPUThread&, spu_opcode_t);
static void XSHW(SPUThread&, spu_opcode_t);
static void CNTB(SPUThread&, spu_opcode_t);
static void XSBH(SPUThread&, spu_opcode_t);
static void CLGT(SPUThread&, spu_opcode_t);
static void ANDC(SPUThread&, spu_opcode_t);
static void CLGTH(SPUThread&, spu_opcode_t);
static void ORC(SPUThread&, spu_opcode_t);
static void CLGTB(SPUThread&, spu_opcode_t);
static void HLGT(SPUThread&, spu_opcode_t);
static void CEQ(SPUThread&, spu_opcode_t);
static void MPYHHU(SPUThread&, spu_opcode_t);
static void ADDX(SPUThread&, spu_opcode_t);
static void SFX(SPUThread&, spu_opcode_t);
static void CGX(SPUThread&, spu_opcode_t);
static void BGX(SPUThread&, spu_opcode_t);
static void MPYHHA(SPUThread&, spu_opcode_t);
static void MPYHHAU(SPUThread&, spu_opcode_t);
static void MPY(SPUThread&, spu_opcode_t);
static void MPYH(SPUThread&, spu_opcode_t);
static void MPYHH(SPUThread&, spu_opcode_t);
static void MPYS(SPUThread&, spu_opcode_t);
static void CEQH(SPUThread&, spu_opcode_t);
static void MPYU(SPUThread&, spu_opcode_t);
static void CEQB(SPUThread&, spu_opcode_t);
static void HEQ(SPUThread&, spu_opcode_t);
static void BRZ(SPUThread&, spu_opcode_t);
static void STQA(SPUThread&, spu_opcode_t);
static void BRNZ(SPUThread&, spu_opcode_t);
static void BRHZ(SPUThread&, spu_opcode_t);
static void BRHNZ(SPUThread&, spu_opcode_t);
static void STQR(SPUThread&, spu_opcode_t);
static void BRA(SPUThread&, spu_opcode_t);
static void LQA(SPUThread&, spu_opcode_t);
static void BRASL(SPUThread&, spu_opcode_t);
static void BR(SPUThread&, spu_opcode_t);
static void FSMBI(SPUThread&, spu_opcode_t);
static void BRSL(SPUThread&, spu_opcode_t);
static void LQR(SPUThread&, spu_opcode_t);
static void IL(SPUThread&, spu_opcode_t);
static void ILHU(SPUThread&, spu_opcode_t);
static void ILH(SPUThread&, spu_opcode_t);
static void IOHL(SPUThread&, spu_opcode_t);
static void ORI(SPUThread&, spu_opcode_t);
static void ORHI(SPUThread&, spu_opcode_t);
static void ORBI(SPUThread&, spu_opcode_t);
static void SFI(SPUThread&, spu_opcode_t);
static void SFHI(SPUThread&, spu_opcode_t);
static void ANDI(SPUThread&, spu_opcode_t);
static void ANDHI(SPUThread&, spu_opcode_t);
static void ANDBI(SPUThread&, spu_opcode_t);
static void AI(SPUThread&, spu_opcode_t);
static void AHI(SPUThread&, spu_opcode_t);
static void STQD(SPUThread&, spu_opcode_t);
static void LQD(SPUThread&, spu_opcode_t);
static void XORI(SPUThread&, spu_opcode_t);
static void XORHI(SPUThread&, spu_opcode_t);
static void XORBI(SPUThread&, spu_opcode_t);
static void CGTI(SPUThread&, spu_opcode_t);
static void CGTHI(SPUThread&, spu_opcode_t);
static void CGTBI(SPUThread&, spu_opcode_t);
static void HGTI(SPUThread&, spu_opcode_t);
static void CLGTI(SPUThread&, spu_opcode_t);
static void CLGTHI(SPUThread&, spu_opcode_t);
static void CLGTBI(SPUThread&, spu_opcode_t);
static void HLGTI(SPUThread&, spu_opcode_t);
static void MPYI(SPUThread&, spu_opcode_t);
static void MPYUI(SPUThread&, spu_opcode_t);
static void CEQI(SPUThread&, spu_opcode_t);
static void CEQHI(SPUThread&, spu_opcode_t);
static void CEQBI(SPUThread&, spu_opcode_t);
static void HEQI(SPUThread&, spu_opcode_t);
static void HBRA(SPUThread&, spu_opcode_t);
static void HBRR(SPUThread&, spu_opcode_t);
static void ILA(SPUThread&, spu_opcode_t);
static void SELB(SPUThread&, spu_opcode_t);
static void SHUFB(SPUThread&, spu_opcode_t);
static void MPYA(SPUThread&, spu_opcode_t);
static void DFCGT(SPUThread&, spu_opcode_t);
static void DFCMGT(SPUThread&, spu_opcode_t);
static void DFTSV(SPUThread&, spu_opcode_t);
static void DFCEQ(SPUThread&, spu_opcode_t);
static void DFCMEQ(SPUThread&, spu_opcode_t);
};
void default_function(SPUThread& spu, spu_opcode_t op);
void set_interrupt_status(SPUThread& spu, spu_opcode_t op);
struct spu_interpreter_fast final : spu_interpreter
{
static void FREST(SPUThread&, spu_opcode_t);
static void FRSQEST(SPUThread&, spu_opcode_t);
static void FCGT(SPUThread&, spu_opcode_t);
static void FA(SPUThread&, spu_opcode_t);
static void FS(SPUThread&, spu_opcode_t);
static void FM(SPUThread&, spu_opcode_t);
static void FCMGT(SPUThread&, spu_opcode_t);
static void DFA(SPUThread&, spu_opcode_t);
static void DFS(SPUThread&, spu_opcode_t);
static void DFM(SPUThread&, spu_opcode_t);
static void DFMA(SPUThread&, spu_opcode_t);
static void DFMS(SPUThread&, spu_opcode_t);
static void DFNMS(SPUThread&, spu_opcode_t);
static void DFNMA(SPUThread&, spu_opcode_t);
static void FSCRRD(SPUThread&, spu_opcode_t);
static void FESD(SPUThread&, spu_opcode_t);
static void FRDS(SPUThread&, spu_opcode_t);
static void FSCRWR(SPUThread&, spu_opcode_t);
static void FCEQ(SPUThread&, spu_opcode_t);
static void FCMEQ(SPUThread&, spu_opcode_t);
static void FI(SPUThread&, spu_opcode_t);
static void CFLTS(SPUThread&, spu_opcode_t);
static void CFLTU(SPUThread&, spu_opcode_t);
static void CSFLT(SPUThread&, spu_opcode_t);
static void CUFLT(SPUThread&, spu_opcode_t);
static void FNMS(SPUThread&, spu_opcode_t);
static void FMA(SPUThread&, spu_opcode_t);
static void FMS(SPUThread&, spu_opcode_t);
};
void STOP(SPUThread& spu, spu_opcode_t op);
void LNOP(SPUThread& spu, spu_opcode_t op);
void SYNC(SPUThread& spu, spu_opcode_t op);
void DSYNC(SPUThread& spu, spu_opcode_t op);
void MFSPR(SPUThread& spu, spu_opcode_t op);
void RDCH(SPUThread& spu, spu_opcode_t op);
void RCHCNT(SPUThread& spu, spu_opcode_t op);
void SF(SPUThread& spu, spu_opcode_t op);
void OR(SPUThread& spu, spu_opcode_t op);
void BG(SPUThread& spu, spu_opcode_t op);
void SFH(SPUThread& spu, spu_opcode_t op);
void NOR(SPUThread& spu, spu_opcode_t op);
void ABSDB(SPUThread& spu, spu_opcode_t op);
void ROT(SPUThread& spu, spu_opcode_t op);
void ROTM(SPUThread& spu, spu_opcode_t op);
void ROTMA(SPUThread& spu, spu_opcode_t op);
void SHL(SPUThread& spu, spu_opcode_t op);
void ROTH(SPUThread& spu, spu_opcode_t op);
void ROTHM(SPUThread& spu, spu_opcode_t op);
void ROTMAH(SPUThread& spu, spu_opcode_t op);
void SHLH(SPUThread& spu, spu_opcode_t op);
void ROTI(SPUThread& spu, spu_opcode_t op);
void ROTMI(SPUThread& spu, spu_opcode_t op);
void ROTMAI(SPUThread& spu, spu_opcode_t op);
void SHLI(SPUThread& spu, spu_opcode_t op);
void ROTHI(SPUThread& spu, spu_opcode_t op);
void ROTHMI(SPUThread& spu, spu_opcode_t op);
void ROTMAHI(SPUThread& spu, spu_opcode_t op);
void SHLHI(SPUThread& spu, spu_opcode_t op);
void A(SPUThread& spu, spu_opcode_t op);
void AND(SPUThread& spu, spu_opcode_t op);
void CG(SPUThread& spu, spu_opcode_t op);
void AH(SPUThread& spu, spu_opcode_t op);
void NAND(SPUThread& spu, spu_opcode_t op);
void AVGB(SPUThread& spu, spu_opcode_t op);
void MTSPR(SPUThread& spu, spu_opcode_t op);
void WRCH(SPUThread& spu, spu_opcode_t op);
void BIZ(SPUThread& spu, spu_opcode_t op);
void BINZ(SPUThread& spu, spu_opcode_t op);
void BIHZ(SPUThread& spu, spu_opcode_t op);
void BIHNZ(SPUThread& spu, spu_opcode_t op);
void STOPD(SPUThread& spu, spu_opcode_t op);
void STQX(SPUThread& spu, spu_opcode_t op);
void BI(SPUThread& spu, spu_opcode_t op);
void BISL(SPUThread& spu, spu_opcode_t op);
void IRET(SPUThread& spu, spu_opcode_t op);
void BISLED(SPUThread& spu, spu_opcode_t op);
void HBR(SPUThread& spu, spu_opcode_t op);
void GB(SPUThread& spu, spu_opcode_t op);
void GBH(SPUThread& spu, spu_opcode_t op);
void GBB(SPUThread& spu, spu_opcode_t op);
void FSM(SPUThread& spu, spu_opcode_t op);
void FSMH(SPUThread& spu, spu_opcode_t op);
void FSMB(SPUThread& spu, spu_opcode_t op);
void LQX(SPUThread& spu, spu_opcode_t op);
void ROTQBYBI(SPUThread& spu, spu_opcode_t op);
void ROTQMBYBI(SPUThread& spu, spu_opcode_t op);
void SHLQBYBI(SPUThread& spu, spu_opcode_t op);
void CBX(SPUThread& spu, spu_opcode_t op);
void CHX(SPUThread& spu, spu_opcode_t op);
void CWX(SPUThread& spu, spu_opcode_t op);
void CDX(SPUThread& spu, spu_opcode_t op);
void ROTQBI(SPUThread& spu, spu_opcode_t op);
void ROTQMBI(SPUThread& spu, spu_opcode_t op);
void SHLQBI(SPUThread& spu, spu_opcode_t op);
void ROTQBY(SPUThread& spu, spu_opcode_t op);
void ROTQMBY(SPUThread& spu, spu_opcode_t op);
void SHLQBY(SPUThread& spu, spu_opcode_t op);
void ORX(SPUThread& spu, spu_opcode_t op);
void CBD(SPUThread& spu, spu_opcode_t op);
void CHD(SPUThread& spu, spu_opcode_t op);
void CWD(SPUThread& spu, spu_opcode_t op);
void CDD(SPUThread& spu, spu_opcode_t op);
void ROTQBII(SPUThread& spu, spu_opcode_t op);
void ROTQMBII(SPUThread& spu, spu_opcode_t op);
void SHLQBII(SPUThread& spu, spu_opcode_t op);
void ROTQBYI(SPUThread& spu, spu_opcode_t op);
void ROTQMBYI(SPUThread& spu, spu_opcode_t op);
void SHLQBYI(SPUThread& spu, spu_opcode_t op);
void NOP(SPUThread& spu, spu_opcode_t op);
void CGT(SPUThread& spu, spu_opcode_t op);
void XOR(SPUThread& spu, spu_opcode_t op);
void CGTH(SPUThread& spu, spu_opcode_t op);
void EQV(SPUThread& spu, spu_opcode_t op);
void CGTB(SPUThread& spu, spu_opcode_t op);
void SUMB(SPUThread& spu, spu_opcode_t op);
void HGT(SPUThread& spu, spu_opcode_t op);
void CLZ(SPUThread& spu, spu_opcode_t op);
void XSWD(SPUThread& spu, spu_opcode_t op);
void XSHW(SPUThread& spu, spu_opcode_t op);
void CNTB(SPUThread& spu, spu_opcode_t op);
void XSBH(SPUThread& spu, spu_opcode_t op);
void CLGT(SPUThread& spu, spu_opcode_t op);
void ANDC(SPUThread& spu, spu_opcode_t op);
void CLGTH(SPUThread& spu, spu_opcode_t op);
void ORC(SPUThread& spu, spu_opcode_t op);
void CLGTB(SPUThread& spu, spu_opcode_t op);
void HLGT(SPUThread& spu, spu_opcode_t op);
void CEQ(SPUThread& spu, spu_opcode_t op);
void MPYHHU(SPUThread& spu, spu_opcode_t op);
void ADDX(SPUThread& spu, spu_opcode_t op);
void SFX(SPUThread& spu, spu_opcode_t op);
void CGX(SPUThread& spu, spu_opcode_t op);
void BGX(SPUThread& spu, spu_opcode_t op);
void MPYHHA(SPUThread& spu, spu_opcode_t op);
void MPYHHAU(SPUThread& spu, spu_opcode_t op);
void MPY(SPUThread& spu, spu_opcode_t op);
void MPYH(SPUThread& spu, spu_opcode_t op);
void MPYHH(SPUThread& spu, spu_opcode_t op);
void MPYS(SPUThread& spu, spu_opcode_t op);
void CEQH(SPUThread& spu, spu_opcode_t op);
void MPYU(SPUThread& spu, spu_opcode_t op);
void CEQB(SPUThread& spu, spu_opcode_t op);
void HEQ(SPUThread& spu, spu_opcode_t op);
void BRZ(SPUThread& spu, spu_opcode_t op);
void STQA(SPUThread& spu, spu_opcode_t op);
void BRNZ(SPUThread& spu, spu_opcode_t op);
void BRHZ(SPUThread& spu, spu_opcode_t op);
void BRHNZ(SPUThread& spu, spu_opcode_t op);
void STQR(SPUThread& spu, spu_opcode_t op);
void BRA(SPUThread& spu, spu_opcode_t op);
void LQA(SPUThread& spu, spu_opcode_t op);
void BRASL(SPUThread& spu, spu_opcode_t op);
void BR(SPUThread& spu, spu_opcode_t op);
void FSMBI(SPUThread& spu, spu_opcode_t op);
void BRSL(SPUThread& spu, spu_opcode_t op);
void LQR(SPUThread& spu, spu_opcode_t op);
void IL(SPUThread& spu, spu_opcode_t op);
void ILHU(SPUThread& spu, spu_opcode_t op);
void ILH(SPUThread& spu, spu_opcode_t op);
void IOHL(SPUThread& spu, spu_opcode_t op);
void ORI(SPUThread& spu, spu_opcode_t op);
void ORHI(SPUThread& spu, spu_opcode_t op);
void ORBI(SPUThread& spu, spu_opcode_t op);
void SFI(SPUThread& spu, spu_opcode_t op);
void SFHI(SPUThread& spu, spu_opcode_t op);
void ANDI(SPUThread& spu, spu_opcode_t op);
void ANDHI(SPUThread& spu, spu_opcode_t op);
void ANDBI(SPUThread& spu, spu_opcode_t op);
void AI(SPUThread& spu, spu_opcode_t op);
void AHI(SPUThread& spu, spu_opcode_t op);
void STQD(SPUThread& spu, spu_opcode_t op);
void LQD(SPUThread& spu, spu_opcode_t op);
void XORI(SPUThread& spu, spu_opcode_t op);
void XORHI(SPUThread& spu, spu_opcode_t op);
void XORBI(SPUThread& spu, spu_opcode_t op);
void CGTI(SPUThread& spu, spu_opcode_t op);
void CGTHI(SPUThread& spu, spu_opcode_t op);
void CGTBI(SPUThread& spu, spu_opcode_t op);
void HGTI(SPUThread& spu, spu_opcode_t op);
void CLGTI(SPUThread& spu, spu_opcode_t op);
void CLGTHI(SPUThread& spu, spu_opcode_t op);
void CLGTBI(SPUThread& spu, spu_opcode_t op);
void HLGTI(SPUThread& spu, spu_opcode_t op);
void MPYI(SPUThread& spu, spu_opcode_t op);
void MPYUI(SPUThread& spu, spu_opcode_t op);
void CEQI(SPUThread& spu, spu_opcode_t op);
void CEQHI(SPUThread& spu, spu_opcode_t op);
void CEQBI(SPUThread& spu, spu_opcode_t op);
void HEQI(SPUThread& spu, spu_opcode_t op);
void HBRA(SPUThread& spu, spu_opcode_t op);
void HBRR(SPUThread& spu, spu_opcode_t op);
void ILA(SPUThread& spu, spu_opcode_t op);
void SELB(SPUThread& spu, spu_opcode_t op);
void SHUFB(SPUThread& spu, spu_opcode_t op);
void MPYA(SPUThread& spu, spu_opcode_t op);
void DFCGT(SPUThread& spu, spu_opcode_t op);
void DFCMGT(SPUThread& spu, spu_opcode_t op);
void DFTSV(SPUThread& spu, spu_opcode_t op);
void DFCEQ(SPUThread& spu, spu_opcode_t op);
void DFCMEQ(SPUThread& spu, spu_opcode_t op);
namespace fast
{
void FREST(SPUThread& spu, spu_opcode_t op);
void FRSQEST(SPUThread& spu, spu_opcode_t op);
void FCGT(SPUThread& spu, spu_opcode_t op);
void FA(SPUThread& spu, spu_opcode_t op);
void FS(SPUThread& spu, spu_opcode_t op);
void FM(SPUThread& spu, spu_opcode_t op);
void FCMGT(SPUThread& spu, spu_opcode_t op);
void DFA(SPUThread& spu, spu_opcode_t op);
void DFS(SPUThread& spu, spu_opcode_t op);
void DFM(SPUThread& spu, spu_opcode_t op);
void DFMA(SPUThread& spu, spu_opcode_t op);
void DFMS(SPUThread& spu, spu_opcode_t op);
void DFNMS(SPUThread& spu, spu_opcode_t op);
void DFNMA(SPUThread& spu, spu_opcode_t op);
void FSCRRD(SPUThread& spu, spu_opcode_t op);
void FESD(SPUThread& spu, spu_opcode_t op);
void FRDS(SPUThread& spu, spu_opcode_t op);
void FSCRWR(SPUThread& spu, spu_opcode_t op);
void FCEQ(SPUThread& spu, spu_opcode_t op);
void FCMEQ(SPUThread& spu, spu_opcode_t op);
void FI(SPUThread& spu, spu_opcode_t op);
void CFLTS(SPUThread& spu, spu_opcode_t op);
void CFLTU(SPUThread& spu, spu_opcode_t op);
void CSFLT(SPUThread& spu, spu_opcode_t op);
void CUFLT(SPUThread& spu, spu_opcode_t op);
void FNMS(SPUThread& spu, spu_opcode_t op);
void FMA(SPUThread& spu, spu_opcode_t op);
void FMS(SPUThread& spu, spu_opcode_t op);
}
namespace precise
{
void FREST(SPUThread& spu, spu_opcode_t op);
void FRSQEST(SPUThread& spu, spu_opcode_t op);
void FCGT(SPUThread& spu, spu_opcode_t op);
void FA(SPUThread& spu, spu_opcode_t op);
void FS(SPUThread& spu, spu_opcode_t op);
void FM(SPUThread& spu, spu_opcode_t op);
void FCMGT(SPUThread& spu, spu_opcode_t op);
void DFA(SPUThread& spu, spu_opcode_t op);
void DFS(SPUThread& spu, spu_opcode_t op);
void DFM(SPUThread& spu, spu_opcode_t op);
void DFMA(SPUThread& spu, spu_opcode_t op);
void DFMS(SPUThread& spu, spu_opcode_t op);
void DFNMS(SPUThread& spu, spu_opcode_t op);
void DFNMA(SPUThread& spu, spu_opcode_t op);
void FSCRRD(SPUThread& spu, spu_opcode_t op);
void FESD(SPUThread& spu, spu_opcode_t op);
void FRDS(SPUThread& spu, spu_opcode_t op);
void FSCRWR(SPUThread& spu, spu_opcode_t op);
void FCEQ(SPUThread& spu, spu_opcode_t op);
void FCMEQ(SPUThread& spu, spu_opcode_t op);
void FI(SPUThread& spu, spu_opcode_t op);
void CFLTS(SPUThread& spu, spu_opcode_t op);
void CFLTU(SPUThread& spu, spu_opcode_t op);
void CSFLT(SPUThread& spu, spu_opcode_t op);
void CUFLT(SPUThread& spu, spu_opcode_t op);
void FNMS(SPUThread& spu, spu_opcode_t op);
void FMA(SPUThread& spu, spu_opcode_t op);
void FMS(SPUThread& spu, spu_opcode_t op);
}
}
struct spu_interpreter_precise final : spu_interpreter
{
static void FREST(SPUThread&, spu_opcode_t);
static void FRSQEST(SPUThread&, spu_opcode_t);
static void FCGT(SPUThread&, spu_opcode_t);
static void FA(SPUThread&, spu_opcode_t);
static void FS(SPUThread&, spu_opcode_t);
static void FM(SPUThread&, spu_opcode_t);
static void FCMGT(SPUThread&, spu_opcode_t);
static void DFA(SPUThread&, spu_opcode_t);
static void DFS(SPUThread&, spu_opcode_t);
static void DFM(SPUThread&, spu_opcode_t);
static void DFMA(SPUThread&, spu_opcode_t);
static void DFMS(SPUThread&, spu_opcode_t);
static void DFNMS(SPUThread&, spu_opcode_t);
static void DFNMA(SPUThread&, spu_opcode_t);
static void FSCRRD(SPUThread&, spu_opcode_t);
static void FESD(SPUThread&, spu_opcode_t);
static void FRDS(SPUThread&, spu_opcode_t);
static void FSCRWR(SPUThread&, spu_opcode_t);
static void FCEQ(SPUThread&, spu_opcode_t);
static void FCMEQ(SPUThread&, spu_opcode_t);
static void FI(SPUThread&, spu_opcode_t);
static void CFLTS(SPUThread&, spu_opcode_t);
static void CFLTU(SPUThread&, spu_opcode_t);
static void CSFLT(SPUThread&, spu_opcode_t);
static void CUFLT(SPUThread&, spu_opcode_t);
static void FNMS(SPUThread&, spu_opcode_t);
static void FMA(SPUThread&, spu_opcode_t);
static void FMS(SPUThread&, spu_opcode_t);
};
+249 -240
View File
@@ -1,5 +1,7 @@
#pragma once
#include "../../../Utilities/BitField.h"
union spu_opcode_t
{
u32 opcode;
@@ -23,246 +25,6 @@ union spu_opcode_t
bf_t<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)
{
return (pc + (imm << 2)) & 0x3fffc;
@@ -272,3 +34,250 @@ inline u32 spu_ls_target(u32 pc, u32 imm = 0)
{
return (pc + (imm << 2)) & 0x3fff0;
}
static u32 spu_decode(u32 inst)
{
return inst >> 21;
}
// SPU decoder object. D provides functions. T is function pointer type returned.
template<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();
SPURecompilerDecoder::SPURecompilerDecoder(SPUThread& spu)
: db(fxm::get_always<SPUDatabase>())
, rec(fxm::get_always<spu_recompiler>())
, spu(spu)
void spu_recompiler_base::enter(SPUThread& spu)
{
}
u32 SPURecompilerDecoder::DecodeMemory(const u32 address)
{
if (spu.offset != address - spu.pc || spu.pc >= 0x40000 || spu.pc % 4)
if (spu.pc >= 0x40000 || spu.pc % 4)
{
throw EXCEPTION("Invalid address or PC (address=0x%x, PC=0x%05x)", address, spu.pc);
throw fmt::exception("Invalid PC: 0x%05x", spu.pc);
}
// get SPU LS pointer
// Get SPU LS pointer
const auto _ls = vm::ps3::_ptr<u32>(spu.offset);
// always validate (TODO)
const auto func = db->analyse(_ls, spu.pc);
// Always validate (TODO)
const auto func = spu.spu_db->analyse(_ls, spu.pc);
// reset callstack if necessary
// Reset callstack if necessary
if (func->does_reset_stack && spu.recursion_level)
{
spu.m_state |= CPU_STATE_RETURN;
return 0;
spu.state += cpu_state::ret;
return;
}
if (!func->compiled)
{
rec->compile(*func);
if (!spu.spu_rec)
{
spu.spu_rec = fxm::get_always<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);
@@ -64,7 +61,7 @@ u32 SPURecompilerDecoder::DecodeMemory(const u32 address)
{
if (res & 0x8000000)
{
throw EXCEPTION("Undefined behaviour");
throw std::logic_error("Invalid interrupt status set" HERE);
}
spu.set_interrupt_status(true);
@@ -75,6 +72,4 @@ u32 SPURecompilerDecoder::DecodeMemory(const u32 address)
}
spu.pc = res & 0x3fffc;
return 0;
}
+8 -21
View File
@@ -1,12 +1,9 @@
#pragma once
#include "Emu/CPU/CPUDecoder.h"
#include "SPUAnalyser.h"
class SPUThread;
// SPU Recompiler instance base (must be global or PS3 process-local)
class SPURecompilerBase
class spu_recompiler_base
{
protected:
std::mutex m_mutex; // must be locked in compile()
@@ -16,21 +13,11 @@ protected:
u32 m_pos; // current position
public:
virtual void compile(spu_function_t& f) = 0; // compile specified function
virtual ~SPURecompilerBase() {};
};
// SPU Decoder instance (created per SPU thread)
class SPURecompilerDecoder final : public CPUDecoder
{
public:
const std::shared_ptr<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)
virtual ~spu_recompiler_base() = default;
// Compile specified function
virtual void compile(spu_function_t& f) = 0;
// Run
static void enter(class SPUThread&);
};
+197 -199
View File
@@ -1,15 +1,15 @@
#include "stdafx.h"
#include "Utilities/Config.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/state.h"
#include "Emu/IdManager.h"
#include "Emu/Cell/PPUThread.h"
#include "Emu/SysCalls/ErrorCodes.h"
#include "Emu/SysCalls/lv2/sys_spu.h"
#include "Emu/SysCalls/lv2/sys_event_flag.h"
#include "Emu/SysCalls/lv2/sys_event.h"
#include "Emu/SysCalls/lv2/sys_interrupt.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/Cell/lv2/sys_spu.h"
#include "Emu/Cell/lv2/sys_event_flag.h"
#include "Emu/Cell/lv2/sys_event.h"
#include "Emu/Cell/lv2/sys_interrupt.h"
#include "Emu/Cell/SPUDisAsm.h"
#include "Emu/Cell/SPUThread.h"
@@ -20,8 +20,24 @@
extern u64 get_timebased_time();
// defined here since SPUDisAsm.cpp doesn't exist
const spu_opcode_table_t<void(SPUDisAsm::*)(spu_opcode_t)> SPUDisAsm::opcodes{ DEFINE_SPU_OPCODES(&SPUDisAsm::), &SPUDisAsm::UNK };
enum class spu_decoder_type
{
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;
@@ -31,7 +47,7 @@ void spu_int_ctrl_t::set(u64 ints)
ints &= mask;
// notify if at least 1 bit was set
if (ints && ~stat._or(ints) & ints && tag)
if (ints && ~stat.fetch_or(ints) & ints && tag)
{
LV2_LOCK;
@@ -44,112 +60,23 @@ void spu_int_ctrl_t::set(u64 ints)
}
}
void spu_int_ctrl_t::clear(u64 ints)
{
stat &= ~ints;
}
const spu_imm_table_t g_spu_imm;
SPUThread::SPUThread(CPUThreadType type, const std::string& name, u32 index, u32 offset)
: CPUThread(type, name)
, index(index)
, offset(offset)
{
}
SPUThread::SPUThread(const std::string& name, u32 index)
: CPUThread(CPU_THREAD_SPU, name)
, index(index)
, offset(vm::alloc(0x40000, vm::main))
{
CHECK_ASSERTION(offset);
}
SPUThread::~SPUThread()
{
// Deallocate Local Storage
vm::dealloc_verbose_nothrow(offset);
}
bool SPUThread::is_paused() const
{
if (CPUThread::is_paused())
{
return true;
}
if (const auto group = tg.lock())
{
if (group->state >= SPU_THREAD_GROUP_STATUS_WAITING && group->state <= SPU_THREAD_GROUP_STATUS_SUSPENDED)
{
return true;
}
}
return false;
}
std::string SPUThread::get_name() const
{
return fmt::format("%s[0x%x] Thread (%s)[0x%05x]", CPUThread::GetTypeString(), m_id, CPUThread::get_name(), pc);
return fmt::format("%sSPU[0x%x] Thread (%s)", offset > RAW_SPU_BASE_ADDR ? "Raw" : "", id, name);
}
void SPUThread::dump_info() const
std::string SPUThread::dump() const
{
CPUThread::dump_info();
std::string ret = "Registers:\n=========\n";
for (uint i = 0; i<128; ++i) ret += fmt::format("GPR[%d] = 0x%s\n", i, gpr[i].to_hex().c_str());
return ret;
}
void SPUThread::cpu_task()
{
std::fesetround(FE_TOWARDZERO);
if (!custom_task && !m_dec)
{
// Select opcode table (TODO)
const auto& table = rpcs3::state.config.core.spu_decoder.value() == spu_decoder_type::interpreter_precise ? spu_interpreter::precise::g_spu_opcode_table : spu_interpreter::fast::g_spu_opcode_table;
// LS base address
const auto base = vm::_ptr<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()
void SPUThread::cpu_init()
{
gpr = {};
fpscr.Reset();
@@ -190,75 +117,96 @@ void SPUThread::init_regs()
gpr[1]._u32[3] = 0x3FFF0; // initial stack frame pointer
}
void SPUThread::init_stack()
void SPUThread::cpu_task()
{
// nothing to do
}
std::fesetround(FE_TOWARDZERO);
void SPUThread::close_stack()
{
// nothing to do here
}
void SPUThread::do_run()
{
m_dec.reset();
switch (auto mode = rpcs3::state.config.core.spu_decoder.value())
if (custom_task)
{
case spu_decoder_type::interpreter_precise: // Interpreter 1 (Precise)
case spu_decoder_type::interpreter_fast: // Interpreter 2 (Fast)
{
break;
if (check_status()) return;
return custom_task(*this);
}
case spu_decoder_type::recompiler_asmjit:
_log::g_tls_make_prefix = [](const auto&, auto, const auto&)
{
m_dec.reset(new SPURecompilerDecoder(*this));
break;
const auto cpu = static_cast<SPUThread*>(get_current_cpu_thread());
return fmt::format("%s [0x%05x]", cpu->get_name(), cpu->pc);
};
if (g_cfg_spu_decoder.get() == spu_decoder_type::asmjit)
{
if (!spu_db) spu_db = fxm::get_always<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);
Emu.Pause();
}
if (!state.load())
{
// Read opcode
const u32 op = base[pc / 4];
// Call interpreter function
table[spu_decode(op)](*this, { op });
// Next instruction
pc += 4;
continue;
}
if (check_status()) return;
}
}
void SPUThread::fast_call(u32 ls_addr)
SPUThread::SPUThread(const std::string & name, u32 index)
: cpu_thread(cpu_type::spu, name)
, index(index)
, offset(vm::alloc(0x40000, vm::main))
{
if (!is_current())
Ensures(offset);
}
SPUThread::~SPUThread()
{
// Deallocate Local Storage
vm::dealloc_verbose_nothrow(offset);
}
void SPUThread::push_snr(u32 number, u32 value)
{
// get channel
const auto channel =
number == 0 ? &ch_snr1 :
number == 1 ? &ch_snr2 : throw EXCEPTION("Unexpected");
// check corresponding SNR register settings
if ((snr_config >> number) & 1)
{
throw EXCEPTION("Called from the wrong thread");
channel->push_or(value);
}
else
{
channel->push(value);
}
// LS:0x0: this is originally the entry point of the interrupt handler, but interrupts are not implemented
_ref<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
if (channel->notification_required)
{
cpu_task();
}
catch (CPUThreadReturn)
{
}
// lock for reliable notification
std::lock_guard<std::mutex> lock(mutex);
m_state &= ~CPU_STATE_RETURN;
pc = old_pc;
gpr[0]._u32[3] = old_lr;
gpr[1]._u32[3] = old_stack;
custom_task = std::move(old_task);
cv.notify_one();
}
}
void SPUThread::do_dma_transfer(u32 cmd, spu_mfc_arg_t args)
@@ -268,9 +216,9 @@ void SPUThread::do_dma_transfer(u32 cmd, spu_mfc_arg_t args)
_mm_mfence();
}
u32 eal = VM_CAST(args.ea);
u32 eal = vm::cast(args.ea, HERE);
if (eal >= SYS_SPU_THREAD_BASE_LOW && m_type == CPU_THREAD_SPU) // SPU Thread Group MMIO (LS and SNR)
if (eal >= SYS_SPU_THREAD_BASE_LOW && offset >= RAW_SPU_BASE_ADDR) // SPU Thread Group MMIO (LS and SNR)
{
const u32 index = (eal - SYS_SPU_THREAD_BASE_LOW) / SYS_SPU_THREAD_OFFSET; // thread number in group
const u32 offset = (eal - SYS_SPU_THREAD_BASE_LOW) % SYS_SPU_THREAD_OFFSET; // LS offset or MMIO register
@@ -413,7 +361,7 @@ void SPUThread::process_mfc_cmd(u32 cmd)
break;
}
const u32 raddr = VM_CAST(ch_mfc_args.ea);
const u32 raddr = vm::cast(ch_mfc_args.ea, HERE);
vm::reservation_acquire(vm::base(offset + ch_mfc_args.lsa), raddr, 128);
@@ -434,7 +382,7 @@ void SPUThread::process_mfc_cmd(u32 cmd)
break;
}
if (vm::reservation_update(VM_CAST(ch_mfc_args.ea), vm::base(offset + ch_mfc_args.lsa), 128))
if (vm::reservation_update(vm::cast(ch_mfc_args.ea, HERE), vm::base(offset + ch_mfc_args.lsa), 128))
{
if (last_raddr == 0)
{
@@ -466,9 +414,9 @@ void SPUThread::process_mfc_cmd(u32 cmd)
break;
}
vm::reservation_op(VM_CAST(ch_mfc_args.ea), 128, [this]()
vm::reservation_op(vm::cast(ch_mfc_args.ea, HERE), 128, [this]()
{
std::memcpy(vm::base_priv(VM_CAST(ch_mfc_args.ea)), vm::base(offset + ch_mfc_args.lsa), 128);
std::memcpy(vm::base_priv(vm::cast(ch_mfc_args.ea, HERE)), vm::base(offset + ch_mfc_args.lsa), 128);
});
if (last_raddr != 0 && vm::g_tls_did_break_reservation)
@@ -539,7 +487,7 @@ void SPUThread::set_events(u32 mask)
}
// set new events, get old event mask
const u32 old_stat = ch_event_stat._or(mask);
const u32 old_stat = ch_event_stat.fetch_or(mask);
// notify if some events were set
if (~old_stat & mask && old_stat & SPU_EVENT_WAITING)
@@ -617,7 +565,10 @@ u32 SPUThread::get_ch_value(u32 ch)
CHECK_EMU_STATUS;
if (is_stopped()) throw CPUThreadStop{};
if (state & cpu_state::stop)
{
throw cpu_state::stop;
}
if (!lock)
{
@@ -658,7 +609,10 @@ u32 SPUThread::get_ch_value(u32 ch)
CHECK_EMU_STATUS;
if (is_stopped()) throw CPUThreadStop{};
if (state & cpu_state::stop)
{
throw cpu_state::stop;
}
if (!lock)
{
@@ -723,14 +677,14 @@ u32 SPUThread::get_ch_value(u32 ch)
if (ch_event_mask & SPU_EVENT_LR)
{
// register waiter if polling reservation status is required
vm::wait_op(*this, last_raddr, 128, WRAP_EXPR(get_events(true) || is_stopped()));
vm::wait_op(*this, last_raddr, 128, WRAP_EXPR(get_events(true) || state & cpu_state::stop));
}
else
{
lock.lock();
// simple waiting loop otherwise
while (!get_events(true) && !is_stopped())
while (!get_events(true) && !(state & cpu_state::stop))
{
CHECK_EMU_STATUS;
@@ -740,7 +694,10 @@ u32 SPUThread::get_ch_value(u32 ch)
ch_event_stat &= ~SPU_EVENT_WAITING;
if (is_stopped()) throw CPUThreadStop{};
if (state & cpu_state::stop)
{
throw cpu_state::stop;
}
return get_events();
}
@@ -767,7 +724,7 @@ void SPUThread::set_ch_value(u32 ch, u32 value)
// break;
case SPU_WrOutIntrMbox:
{
if (m_type == CPU_THREAD_RAW_SPU)
if (offset >= RAW_SPU_BASE_ADDR)
{
std::unique_lock<std::mutex> lock(mutex, std::defer_lock);
@@ -775,7 +732,10 @@ void SPUThread::set_ch_value(u32 ch, u32 value)
{
CHECK_EMU_STATUS;
if (is_stopped()) throw CPUThreadStop{};
if (state & cpu_state::stop)
{
throw cpu_state::stop;
}
if (!lock)
{
@@ -824,12 +784,12 @@ void SPUThread::set_ch_value(u32 ch, u32 value)
return ch_in_mbox.set_values(1, CELL_ENOTCONN); // TODO: check error passing
}
if (queue->events.size() >= queue->size)
if (queue->events() >= queue->size)
{
return ch_in_mbox.set_values(1, CELL_EBUSY);
}
queue->push(lv2_lock, SYS_SPU_THREAD_EVENT_USER_KEY, m_id, ((u64)spup << 32) | (value & 0x00ffffff), data);
queue->push(lv2_lock, SYS_SPU_THREAD_EVENT_USER_KEY, id, ((u64)spup << 32) | (value & 0x00ffffff), data);
return ch_in_mbox.set_values(1, CELL_OK);
}
@@ -861,13 +821,13 @@ void SPUThread::set_ch_value(u32 ch, u32 value)
}
// TODO: check passing spup value
if (queue->events.size() >= queue->size)
if (queue->events() >= queue->size)
{
LOG_WARNING(SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x) failed (queue is full)", spup, (value & 0x00ffffff), data);
return;
}
queue->push(lv2_lock, SYS_SPU_THREAD_EVENT_USER_KEY, m_id, ((u64)spup << 32) | (value & 0x00ffffff), data);
queue->push(lv2_lock, SYS_SPU_THREAD_EVENT_USER_KEY, id, ((u64)spup << 32) | (value & 0x00ffffff), data);
return;
}
else if (code == 128)
@@ -979,7 +939,10 @@ void SPUThread::set_ch_value(u32 ch, u32 value)
{
CHECK_EMU_STATUS;
if (is_stopped()) throw CPUThreadStop{};
if (state & cpu_state::stop)
{
throw cpu_state::stop;
}
if (!lock)
{
@@ -1136,7 +1099,7 @@ void SPUThread::stop_and_signal(u32 code)
{
LOG_TRACE(SPU, "stop_and_signal(code=0x%x)", code);
if (m_type == CPU_THREAD_RAW_SPU)
if (offset >= RAW_SPU_BASE_ADDR)
{
status.atomic_op([code](u32& status)
{
@@ -1146,8 +1109,7 @@ void SPUThread::stop_and_signal(u32 code)
});
int_ctrl[2].set(SPU_INT2_STAT_SPU_STOP_AND_SIGNAL_INT);
return stop();
throw cpu_state::stop;
}
switch (code)
@@ -1160,7 +1122,7 @@ void SPUThread::stop_and_signal(u32 code)
case 0x002:
{
m_state |= CPU_STATE_RETURN;
state += cpu_state::ret;
return;
}
@@ -1241,7 +1203,10 @@ void SPUThread::stop_and_signal(u32 code)
{
CHECK_EMU_STATUS;
if (is_stopped()) throw CPUThreadStop{};
if (state & cpu_state::stop)
{
throw cpu_state::stop;
}
group->cv.wait_for(lv2_lock, std::chrono::milliseconds(1));
}
@@ -1253,7 +1218,10 @@ void SPUThread::stop_and_signal(u32 code)
for (auto& thread : group->threads)
{
if (thread) thread->sleep(); // trigger status check
if (thread)
{
thread->state += cpu_state::suspend;
}
}
}
else
@@ -1261,24 +1229,25 @@ void SPUThread::stop_and_signal(u32 code)
throw EXCEPTION("Unexpected SPU Thread Group state (%d)", group->state);
}
if (queue->events.size())
if (queue->events())
{
auto& event = queue->events.front();
const auto event = queue->pop(lv2_lock);
ch_in_mbox.set_values(4, CELL_OK, static_cast<u32>(std::get<1>(event)), static_cast<u32>(std::get<2>(event)), static_cast<u32>(std::get<3>(event)));
queue->events.pop_front();
}
else
{
// add waiter; protocol is ignored in current implementation
sleep_queue_entry_t waiter(*this, queue->sq);
sleep_entry<cpu_thread> waiter(queue->thread_queue(lv2_lock), *this);
// wait on the event queue
while (!unsignal())
while (!state.test_and_reset(cpu_state::signal))
{
CHECK_EMU_STATUS;
if (is_stopped()) throw CPUThreadStop{};
if (state & cpu_state::stop)
{
throw cpu_state::stop;
}
cv.wait(lv2_lock);
}
@@ -1302,9 +1271,14 @@ void SPUThread::stop_and_signal(u32 code)
for (auto& thread : group->threads)
{
if (thread) thread->awake(); // untrigger status check
if (thread && thread.get() != this)
{
thread->state -= cpu_state::suspend;
thread->safe_notify();
}
}
state -= cpu_state::suspend;
group->cv.notify_all();
return;
@@ -1338,7 +1312,8 @@ void SPUThread::stop_and_signal(u32 code)
{
if (thread && thread.get() != this)
{
thread->stop();
thread->state += cpu_state::stop;
thread->safe_notify();
}
}
@@ -1347,7 +1322,7 @@ void SPUThread::stop_and_signal(u32 code)
group->join_state |= SPU_TGJSF_GROUP_EXIT;
group->cv.notify_one();
return stop();
throw cpu_state::stop;
}
case 0x102:
@@ -1373,7 +1348,7 @@ void SPUThread::stop_and_signal(u32 code)
status |= SPU_STATUS_STOPPED_BY_STOP;
group->cv.notify_one();
return stop();
throw cpu_state::stop;
}
}
@@ -1391,7 +1366,7 @@ void SPUThread::halt()
{
LOG_TRACE(SPU, "halt()");
if (m_type == CPU_THREAD_RAW_SPU)
if (offset >= RAW_SPU_BASE_ADDR)
{
status.atomic_op([](u32& status)
{
@@ -1401,18 +1376,41 @@ void SPUThread::halt()
int_ctrl[2].set(SPU_INT2_STAT_SPU_HALT_OR_STEP_INT);
return stop();
throw cpu_state::stop;
}
status |= SPU_STATUS_STOPPED_BY_HALT;
throw EXCEPTION("Halt");
}
spu_thread::spu_thread(u32 entry, const std::string& name, u32 stack_size, u32 prio)
void SPUThread::fast_call(u32 ls_addr)
{
auto spu = idm::make_ptr<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/CPU/CPUThread.h"
#include "Emu/Cell/SPUContext.h"
#include "Emu/Cell/SPUInterpreter.h"
#include "MFC.h"
struct lv2_event_queue_t;
class lv2_event_queue_t;
struct lv2_spu_group_t;
struct lv2_int_tag_t;
@@ -135,12 +135,20 @@ enum
SPU_RdSigNotify2_offs = 0x1C00C,
};
enum : u32
{
RAW_SPU_BASE_ADDR = 0xE0000000,
RAW_SPU_OFFSET = 0x00100000,
RAW_SPU_LS_OFFSET = 0x00000000,
RAW_SPU_PROB_OFFSET = 0x00040000,
};
struct spu_channel_t
{
// set to true if SPU thread must be notified after SPU channel operation
thread_local static bool notification_required;
struct sync_var_t
struct alignas(8) sync_var_t
{
bool count; // value available
bool wait; // notification required
@@ -153,7 +161,7 @@ public:
// returns true on success
bool try_push(u32 value)
{
const auto old = data.atomic_op([=](sync_var_t& data)
const auto old = data.fetch_op([=](sync_var_t& data)
{
if ((data.wait = data.count) == false)
{
@@ -168,7 +176,7 @@ public:
// push performing bitwise OR with previous value, may require notification
void push_or(u32 value)
{
const auto old = data.atomic_op([=](sync_var_t& data)
const auto old = data.fetch_op([=](sync_var_t& data)
{
data.count = true;
data.wait = false;
@@ -181,7 +189,7 @@ public:
// push unconditionally (overwriting previous value), may require notification
void push(u32 value)
{
const auto old = data.atomic_op([=](sync_var_t& data)
const auto old = data.fetch_op([=](sync_var_t& data)
{
data.count = true;
data.wait = false;
@@ -194,7 +202,7 @@ public:
// returns true on success and loaded value
std::tuple<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.count = false;
@@ -207,7 +215,7 @@ public:
// pop unconditionally (loading last value), may require notification
u32 pop()
{
const auto old = data.atomic_op([](sync_var_t& data)
const auto old = data.fetch_op([](sync_var_t& data)
{
data.wait = false;
data.count = false;
@@ -237,7 +245,7 @@ public:
struct spu_channel_4_t
{
struct sync_var_t
struct alignas(16) sync_var_t
{
struct
{
@@ -256,7 +264,7 @@ struct spu_channel_4_t
public:
void clear()
{
values = sync_var_t{};
values.store({});
value3 = 0;
}
@@ -333,7 +341,10 @@ struct spu_int_ctrl_t
void set(u64 ints);
void clear(u64 ints);
void clear(u64 ints)
{
stat &= ~ints;
}
void clear()
{
@@ -526,12 +537,27 @@ public:
}
};
class SPUThread : public CPUThread
class SPUThread : public cpu_thread
{
friend class SPURecompilerDecoder;
friend class spu_recompiler;
public:
virtual std::string get_name() const override;
virtual std::string dump() const override;
virtual void cpu_init() override;
virtual void cpu_task() override;
protected:
SPUThread(const std::string& name)
: cpu_thread(cpu_type::spu, name)
, index(0)
, offset(0)
{
}
public:
SPUThread(const std::string& name, u32 index);
virtual ~SPUThread() override;
std::array<v128, 128> gpr; // General-Purpose Registers
SPU_FPSCR fpscr;
@@ -578,32 +604,14 @@ public:
const u32 index; // SPU index
const u32 offset; // SPU LS offset
void push_snr(u32 number, u32 value)
{
// get channel
const auto channel =
number == 0 ? &ch_snr1 :
number == 1 ? &ch_snr2 : throw EXCEPTION("Unexpected");
std::function<void(SPUThread&)> custom_task;
std::exception_ptr pending_exception;
// check corresponding SNR register settings
if ((snr_config >> number) & 1)
{
channel->push_or(value);
}
else
{
channel->push(value);
}
if (channel->notification_required)
{
// lock for reliable notification
std::lock_guard<std::mutex> lock(mutex);
cv.notify_one();
}
}
std::shared_ptr<class SPUDatabase> spu_db;
std::shared_ptr<class spu_recompiler_base> spu_rec;
u32 recursion_level = 0;
void push_snr(u32 number, u32 value);
void do_dma_transfer(u32 cmd, spu_mfc_arg_t args);
void do_dma_list_cmd(u32 cmd, spu_mfc_arg_t args);
void process_mfc_cmd(u32 cmd);
@@ -618,14 +626,18 @@ public:
void stop_and_signal(u32 code);
void halt();
void fast_call(u32 ls_addr);
// Convert specified SPU LS address to a pointer of specified (possibly converted to BE) type
template<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));
}
// 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);
}
@@ -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;
}
};