#pragma once #include "Emu/Cell/PPUThread.h" class func_caller { public: virtual void operator()(PPUThread& CPU) = 0; virtual ~func_caller(){}; }; namespace ppu_func_detail { enum bind_arg_type { ARG_GENERAL, ARG_FLOAT, ARG_VECTOR, ARG_STACK, }; template struct bind_arg; template struct bind_arg { static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_GENERAL"); static __forceinline T func(PPUThread& CPU) { return cast_from_ppu_gpr(CPU.GPR[g_count + 2]); } }; template struct bind_arg { static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_FLOAT"); static __forceinline T func(PPUThread& CPU) { return static_cast(CPU.FPR[f_count]); } }; template struct bind_arg { static_assert(std::is_same::value, "Invalid function argument type for ARG_VECTOR"); static __forceinline T func(PPUThread& CPU) { return CPU.VPR[v_count + 1]; } }; template struct bind_arg { static_assert(f_count <= 13, "TODO: Unsupported stack argument type (float)"); static_assert(v_count <= 12, "TODO: Unsupported stack argument type (vector)"); static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_STACK"); static __forceinline T func(PPUThread& CPU) { // TODO: check stack argument displacement const u64 res = CPU.GetStackArg(8 + std::max(g_count - 8, 0) + std::max(f_count - 13, 0) + std::max(v_count - 12, 0)); return cast_from_ppu_gpr(res); } }; template struct bind_result { static_assert(type == ARG_GENERAL, "Wrong use of bind_result template"); static_assert(sizeof(T) <= 8, "Invalid function result type for ARG_GENERAL"); static __forceinline void func(PPUThread& CPU, const T& result) { CPU.GPR[3] = cast_to_ppu_gpr(result); } }; template struct bind_result { static_assert(sizeof(T) <= 8, "Invalid function result type for ARG_FLOAT"); static __forceinline void func(PPUThread& CPU, const T& result) { CPU.FPR[1] = static_cast(result); } }; template struct bind_result { static_assert(std::is_same::value, "Invalid function result type for ARG_VECTOR"); static __forceinline void func(PPUThread& CPU, const T& result) { CPU.VPR[2] = result; } }; template struct call_impl { static __forceinline RT call(F f, Tuple && t) { return call_impl::call(f, std::forward(t)); } }; template struct call_impl { static __forceinline RT call(F f, Tuple && t) { return f(std::get(std::forward(t))...); } }; template __forceinline RT call(F f, Tuple && t) { typedef typename std::decay::type ttype; return ppu_func_detail::call_impl::value, std::tuple_size::value>::call(f, std::forward(t)); } template __forceinline std::tuple<> iterate(PPUThread& CPU) { // terminator return std::tuple<>(); } template __forceinline std::tuple iterate(PPUThread& CPU) { static_assert(!std::is_pointer::value, "Invalid function argument type (pointer)"); static_assert(!std::is_reference::value, "Invalid function argument type (reference)"); // TODO: check calculations const bool is_float = std::is_floating_point::value; const bool is_vector = std::is_same::value; const bind_arg_type t = is_float ? ((f_count >= 13) ? ARG_STACK : ARG_FLOAT) : (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); return std::tuple_cat(std::tuple(bind_arg::func(CPU)), iterate(CPU)); } template struct result_type { static_assert(!std::is_pointer::value, "Invalid function result type (pointer)"); static_assert(!std::is_reference::value, "Invalid function result type (reference)"); static const bool is_float = std::is_floating_point::value; static const bool is_vector = std::is_same::value; static const bind_arg_type value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL); }; template class func_binder; template class func_binder : public func_caller { typedef void(*func_t)(T...); const func_t m_call; public: func_binder(func_t call) : func_caller() , m_call(call) { } virtual void operator()(PPUThread& CPU) { call(m_call, iterate<0, 0, 0, T...>(CPU)); } }; template class func_binder : public func_caller { typedef void(*func_t)(PPUThread&, T...); const func_t m_call; public: func_binder(func_t call) : func_caller() , m_call(call) { } virtual void operator()(PPUThread& CPU) { call(m_call, std::tuple_cat(std::tuple(CPU), iterate<0, 0, 0, T...>(CPU))); } }; template class func_binder : public func_caller { typedef RT(*func_t)(T...); const func_t m_call; public: func_binder(func_t call) : func_caller() , m_call(call) { } virtual void operator()(PPUThread& CPU) { bind_result::value>::func(CPU, call(m_call, iterate<0, 0, 0, T...>(CPU))); } }; template class func_binder : public func_caller { typedef RT(*func_t)(PPUThread&, T...); const func_t m_call; public: func_binder(func_t call) : func_caller() , m_call(call) { } virtual void operator()(PPUThread& CPU) { bind_result::value>::func(CPU, call(m_call, std::tuple_cat(std::tuple(CPU), iterate<0, 0, 0, T...>(CPU)))); } }; } template func_caller* bind_func(RT(*call)(T...)) { return new ppu_func_detail::func_binder(call); }