mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-03-15 13:21:14 +00:00
Partial commit: Cell
This commit is contained in:
parent
42e1d4d752
commit
c4e99dbdb2
@ -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();
|
||||
};
|
2160
rpcs3/Emu/Cell/PPUDisAsm.cpp
Normal file
2160
rpcs3/Emu/Cell/PPUDisAsm.cpp
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
2379
rpcs3/Emu/Cell/PPUFunction.cpp
Normal file
2379
rpcs3/Emu/Cell/PPUFunction.cpp
Normal file
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
@ -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; }
|
||||
};
|
1152
rpcs3/Emu/Cell/PPUModule.cpp
Normal file
1152
rpcs3/Emu/Cell/PPUModule.cpp
Normal file
File diff suppressed because it is too large
Load Diff
255
rpcs3/Emu/Cell/PPUModule.h
Normal file
255
rpcs3/Emu/Cell/PPUModule.h
Normal 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
@ -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;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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 };
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
|
@ -1,5 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
struct spu_context_t
|
||||
{
|
||||
};
|
11
rpcs3/Emu/Cell/SPUDisAsm.cpp
Normal file
11
rpcs3/Emu/Cell/SPUDisAsm.cpp
Normal 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;
|
||||
}
|
@ -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 });
|
||||
}
|
||||
};
|
||||
|
@ -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); }
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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)];
|
||||
}
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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&);
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user