2014-09-11 21:18:19 +02:00
|
|
|
#pragma once
|
2014-09-11 21:33:20 +02:00
|
|
|
#include "Emu/Cell/PPUThread.h"
|
2014-09-11 21:18:19 +02:00
|
|
|
|
2014-09-12 21:27:33 +02:00
|
|
|
namespace cb_detail
|
2014-09-11 21:18:19 +02:00
|
|
|
{
|
2014-09-12 15:08:24 +02:00
|
|
|
enum _func_arg_type
|
2014-09-11 21:18:19 +02:00
|
|
|
{
|
2014-09-12 15:08:24 +02:00
|
|
|
ARG_GENERAL,
|
|
|
|
|
ARG_FLOAT,
|
|
|
|
|
ARG_VECTOR,
|
|
|
|
|
ARG_STACK,
|
|
|
|
|
};
|
|
|
|
|
|
2014-09-15 17:04:09 +02:00
|
|
|
// Current implementation can handle only fixed amount of stack arguments.
|
|
|
|
|
// This constant can be increased if necessary.
|
|
|
|
|
// It's possible to calculate suitable stack frame size in template, but too complicated.
|
2015-04-18 02:25:26 +02:00
|
|
|
static const auto FIXED_STACK_FRAME_SIZE = 0x90;
|
2014-09-15 17:04:09 +02:00
|
|
|
|
2014-09-12 15:08:24 +02:00
|
|
|
template<typename T, _func_arg_type type, int g_count, int f_count, int v_count>
|
|
|
|
|
struct _func_arg;
|
|
|
|
|
|
|
|
|
|
template<typename T, int g_count, int f_count, int v_count>
|
|
|
|
|
struct _func_arg<T, ARG_GENERAL, g_count, f_count, v_count>
|
|
|
|
|
{
|
|
|
|
|
static_assert(sizeof(T) <= 8, "Invalid callback argument type for ARG_GENERAL");
|
|
|
|
|
|
2015-05-28 17:14:22 +02:00
|
|
|
force_inline static void set_value(PPUThread& CPU, const T& arg)
|
2014-09-12 15:08:24 +02:00
|
|
|
{
|
2015-01-14 20:45:36 +01:00
|
|
|
CPU.GPR[g_count + 2] = cast_to_ppu_gpr<T>(arg);
|
2014-09-12 15:08:24 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<typename T, int g_count, int f_count, int 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");
|
|
|
|
|
|
2015-05-28 17:14:22 +02:00
|
|
|
force_inline static void set_value(PPUThread& CPU, const T& arg)
|
2014-09-12 15:08:24 +02:00
|
|
|
{
|
2015-01-19 15:16:31 +01:00
|
|
|
CPU.FPR[f_count] = static_cast<T>(arg);
|
2014-09-12 15:08:24 +02:00
|
|
|
}
|
|
|
|
|
};
|
2014-09-11 21:18:19 +02:00
|
|
|
|
2014-09-12 15:08:24 +02:00
|
|
|
template<typename T, int g_count, int f_count, int v_count>
|
|
|
|
|
struct _func_arg<T, ARG_VECTOR, g_count, f_count, v_count>
|
|
|
|
|
{
|
|
|
|
|
static_assert(std::is_same<T, u128>::value, "Invalid callback argument type for ARG_VECTOR");
|
2014-09-11 21:18:19 +02:00
|
|
|
|
2015-05-28 17:14:22 +02:00
|
|
|
force_inline static void set_value(PPUThread& CPU, const T& arg)
|
2014-09-11 21:18:19 +02:00
|
|
|
{
|
2015-01-07 17:44:47 +01:00
|
|
|
CPU.VPR[v_count + 1] = arg;
|
2014-09-11 21:18:19 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2014-09-12 15:08:24 +02:00
|
|
|
template<typename T, int g_count, int f_count, int v_count>
|
|
|
|
|
struct _func_arg<T, ARG_STACK, g_count, f_count, v_count>
|
|
|
|
|
{
|
2014-09-23 16:27:18 +02:00
|
|
|
static_assert(f_count <= 13, "TODO: Unsupported stack argument type (float)");
|
2014-09-12 15:08:24 +02:00
|
|
|
static_assert(v_count <= 12, "TODO: Unsupported stack argument type (vector)");
|
|
|
|
|
static_assert(sizeof(T) <= 8, "Invalid callback argument type for ARG_STACK");
|
|
|
|
|
|
2015-05-28 17:14:22 +02:00
|
|
|
force_inline static void set_value(PPUThread& CPU, const T& arg)
|
2014-09-12 15:08:24 +02:00
|
|
|
{
|
2015-04-18 02:25:26 +02:00
|
|
|
const int stack_pos = (g_count - 9) * 8 - FIXED_STACK_FRAME_SIZE;
|
2014-09-15 17:04:09 +02:00
|
|
|
static_assert(stack_pos < 0, "TODO: Increase fixed stack frame size (arg count limit broken)");
|
2015-06-19 18:53:52 +02:00
|
|
|
vm::ps3::write64(CPU.GPR[1] + stack_pos, cast_to_ppu_gpr<T>(arg));
|
2014-09-12 15:08:24 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<int g_count, int f_count, int v_count>
|
2015-05-28 17:14:22 +02:00
|
|
|
force_inline static bool _bind_func_args(PPUThread& CPU)
|
2014-09-12 15:08:24 +02:00
|
|
|
{
|
|
|
|
|
// terminator
|
2014-09-15 17:04:09 +02:00
|
|
|
return false;
|
2014-09-12 15:08:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<int g_count, int f_count, int v_count, typename T1, typename... T>
|
2015-05-28 17:14:22 +02:00
|
|
|
force_inline static bool _bind_func_args(PPUThread& CPU, T1 arg1, T... args)
|
2014-09-12 15:08:24 +02:00
|
|
|
{
|
|
|
|
|
static_assert(!std::is_pointer<T1>::value, "Invalid callback argument type (pointer)");
|
|
|
|
|
static_assert(!std::is_reference<T1>::value, "Invalid callback argument type (reference)");
|
|
|
|
|
const bool is_float = std::is_floating_point<T1>::value;
|
|
|
|
|
const bool is_vector = std::is_same<T1, u128>::value;
|
|
|
|
|
const _func_arg_type t = is_float
|
2014-09-23 16:27:18 +02:00
|
|
|
? ((f_count >= 13) ? ARG_STACK : ARG_FLOAT)
|
2014-09-12 15:08:24 +02:00
|
|
|
: (is_vector ? ((v_count >= 12) ? ARG_STACK : ARG_VECTOR) : ((g_count >= 8) ? ARG_STACK : ARG_GENERAL));
|
|
|
|
|
const int g = g_count + (is_float || is_vector ? 0 : 1);
|
|
|
|
|
const int f = f_count + (is_float ? 1 : 0);
|
|
|
|
|
const int v = v_count + (is_vector ? 1 : 0);
|
|
|
|
|
|
|
|
|
|
_func_arg<T1, t, g, f, v>::set_value(CPU, arg1);
|
2014-09-15 17:04:09 +02:00
|
|
|
// return true if stack was used
|
|
|
|
|
return _bind_func_args<g, f, v>(CPU, args...) || (t == ARG_STACK);
|
2014-09-12 15:08:24 +02:00
|
|
|
}
|
|
|
|
|
|
2014-09-16 15:56:27 +02:00
|
|
|
template<typename T, _func_arg_type type>
|
2014-09-11 22:46:11 +02:00
|
|
|
struct _func_res
|
2014-09-11 21:18:19 +02:00
|
|
|
{
|
2014-09-16 15:56:27 +02:00
|
|
|
static_assert(type == ARG_GENERAL, "Wrong use of _func_res template");
|
|
|
|
|
static_assert(sizeof(T) <= 8, "Invalid callback result type for ARG_GENERAL");
|
2014-09-11 21:18:19 +02:00
|
|
|
|
2015-05-28 17:14:22 +02:00
|
|
|
force_inline static T get_value(const PPUThread& CPU)
|
2014-09-12 15:08:24 +02:00
|
|
|
{
|
2015-01-19 15:16:31 +01:00
|
|
|
return cast_from_ppu_gpr<T>(CPU.GPR[3]);
|
2014-09-12 15:08:24 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2014-09-16 15:56:27 +02:00
|
|
|
template<typename T>
|
|
|
|
|
struct _func_res<T, ARG_FLOAT>
|
2014-09-12 15:08:24 +02:00
|
|
|
{
|
2014-09-16 15:56:27 +02:00
|
|
|
static_assert(sizeof(T) <= 8, "Invalid callback result type for ARG_FLOAT");
|
2014-09-15 00:17:24 +02:00
|
|
|
|
2015-05-28 17:14:22 +02:00
|
|
|
force_inline static T get_value(const PPUThread& CPU)
|
2014-09-11 22:46:11 +02:00
|
|
|
{
|
2015-01-19 15:16:31 +01:00
|
|
|
return static_cast<T>(CPU.FPR[1]);
|
2014-09-11 22:46:11 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2014-09-16 15:56:27 +02:00
|
|
|
template<typename T>
|
|
|
|
|
struct _func_res<T, ARG_VECTOR>
|
2014-09-11 22:46:11 +02:00
|
|
|
{
|
2015-01-07 17:44:47 +01:00
|
|
|
static_assert(std::is_same<T, u128>::value, "Invalid callback result type for ARG_VECTOR");
|
2014-09-16 15:56:27 +02:00
|
|
|
|
2015-05-28 17:14:22 +02:00
|
|
|
force_inline static T get_value(const PPUThread& CPU)
|
2014-09-11 22:46:11 +02:00
|
|
|
{
|
2015-01-07 17:44:47 +01:00
|
|
|
return CPU.VPR[2];
|
2014-09-11 22:46:11 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2014-09-12 15:08:24 +02:00
|
|
|
template<typename RT, typename... T>
|
|
|
|
|
struct _func_caller
|
|
|
|
|
{
|
2015-05-28 17:14:22 +02:00
|
|
|
force_inline static RT call(PPUThread& CPU, u32 pc, u32 rtoc, T... args)
|
2014-09-12 15:08:24 +02:00
|
|
|
{
|
2015-04-18 03:35:58 +02:00
|
|
|
_func_caller<void, T...>::call(CPU, pc, rtoc, args...);
|
2014-09-16 15:56:27 +02:00
|
|
|
|
|
|
|
|
static_assert(!std::is_pointer<RT>::value, "Invalid callback result type (pointer)");
|
|
|
|
|
static_assert(!std::is_reference<RT>::value, "Invalid callback result type (reference)");
|
|
|
|
|
const bool is_float = std::is_floating_point<RT>::value;
|
|
|
|
|
const bool is_vector = std::is_same<RT, u128>::value;
|
|
|
|
|
const _func_arg_type t = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL);
|
|
|
|
|
|
|
|
|
|
return _func_res<RT, t>::get_value(CPU);
|
2014-09-12 15:08:24 +02:00
|
|
|
}
|
|
|
|
|
};
|
2014-09-16 13:23:58 +02:00
|
|
|
|
|
|
|
|
template<typename... T>
|
|
|
|
|
struct _func_caller<void, T...>
|
|
|
|
|
{
|
2015-05-28 17:14:22 +02:00
|
|
|
force_inline static void call(PPUThread& CPU, u32 pc, u32 rtoc, T... args)
|
2014-09-16 13:23:58 +02:00
|
|
|
{
|
|
|
|
|
const bool stack = _bind_func_args<0, 0, 0, T...>(CPU, args...);
|
|
|
|
|
if (stack) CPU.GPR[1] -= FIXED_STACK_FRAME_SIZE;
|
2015-04-18 03:35:58 +02:00
|
|
|
CPU.GPR[1] -= 0x70; // create reserved area
|
2014-09-16 13:23:58 +02:00
|
|
|
CPU.FastCall2(pc, rtoc);
|
2015-04-18 03:35:58 +02:00
|
|
|
CPU.GPR[1] += 0x70;
|
2014-09-16 13:23:58 +02:00
|
|
|
if (stack) CPU.GPR[1] += FIXED_STACK_FRAME_SIZE;
|
|
|
|
|
}
|
|
|
|
|
};
|
2014-09-12 21:27:33 +02:00
|
|
|
}
|
2014-09-12 15:08:24 +02:00
|
|
|
|
2014-09-12 21:27:33 +02:00
|
|
|
namespace vm
|
|
|
|
|
{
|
2014-09-12 15:08:24 +02:00
|
|
|
template<typename AT, typename RT, typename... T>
|
2015-06-14 23:52:22 +02:00
|
|
|
force_inline RT _ptr_base<RT(T...), AT>::operator()(PPUThread& CPU, T... args) const
|
2014-09-12 15:08:24 +02:00
|
|
|
{
|
2015-07-03 01:11:44 +02:00
|
|
|
const auto data = vm::get_ptr<be_t<u32>>(VM_CAST(m_addr));
|
2015-01-14 14:57:19 +01:00
|
|
|
const u32 pc = data[0];
|
|
|
|
|
const u32 rtoc = data[1];
|
2014-09-12 15:08:24 +02:00
|
|
|
|
2015-04-18 19:18:23 +02:00
|
|
|
return cb_detail::_func_caller<RT, T...>::call(CPU, pc, rtoc, args...);
|
2014-09-12 15:08:24 +02:00
|
|
|
}
|
2014-09-12 21:27:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename RT, typename... T>
|
2015-05-28 17:14:22 +02:00
|
|
|
force_inline RT cb_call(PPUThread& CPU, u32 pc, u32 rtoc, T... args)
|
2014-09-16 13:23:58 +02:00
|
|
|
{
|
|
|
|
|
return cb_detail::_func_caller<RT, T...>::call(CPU, pc, rtoc, args...);
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-28 13:59:16 +01:00
|
|
|
// Something is wrong with it (but cb_call<void, ...>() should work anyway)
|
2015-01-18 23:54:56 +01:00
|
|
|
//template<typename... T>
|
|
|
|
|
//void cb_call(PPUThread& CPU, u32 pc, u32 rtoc, T... args)
|
|
|
|
|
//{
|
|
|
|
|
// cb_detail::_func_caller<void, T...>::call(CPU, pc, rtoc, args...);
|
|
|
|
|
//}
|