diff --git a/rpcs3/Emu/ARMv7/Modules/sceDbg.cpp b/rpcs3/Emu/ARMv7/Modules/sceDbg.cpp index d20b8dc818..33d3ce6a31 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceDbg.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceDbg.cpp @@ -14,12 +14,12 @@ s32 sceDbgSetBreakOnErrorState(SceDbgBreakOnErrorState state) throw EXCEPTION(""); } -s32 sceDbgAssertionHandler(vm::cptr pFile, s32 line, bool stop, vm::cptr pComponent, vm::cptr pMessage) // va_args... +s32 sceDbgAssertionHandler(vm::cptr pFile, s32 line, bool stop, vm::cptr pComponent, vm::cptr pMessage, armv7_va_args_t va_args) { throw EXCEPTION(""); } -s32 sceDbgLoggingHandler(vm::cptr pFile, s32 line, s32 severity, vm::cptr pComponent, vm::cptr pMessage) // va_args... +s32 sceDbgLoggingHandler(vm::cptr pFile, s32 line, s32 severity, vm::cptr pComponent, vm::cptr pMessage, armv7_va_args_t va_args) { throw EXCEPTION(""); } diff --git a/rpcs3/Emu/ARMv7/Modules/sceFios.cpp b/rpcs3/Emu/ARMv7/Modules/sceFios.cpp index 7581e7ac7f..58ca7c3fa1 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceFios.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceFios.cpp @@ -119,7 +119,7 @@ s32 sceFiosPathncmp(vm::cptr pA, vm::cptr pB, u32 n) throw EXCEPTION(""); } -s32 sceFiosPrintf(vm::cptr pFormat) // va_args... +s32 sceFiosPrintf(vm::cptr pFormat, armv7_va_args_t va_args) { throw EXCEPTION(""); } diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp index c3bc0338f4..5bc3ddfabf 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp @@ -201,23 +201,23 @@ namespace sce_libc_func } } - void printf(ARMv7Context& context, vm::cptr fmt) // va_args... + void printf(ARMv7Context& context, vm::cptr fmt, armv7_va_args_t va_args) { sceLibc.Warning("printf(fmt=*0x%x)", fmt); sceLibc.Log("*** *fmt = '%s'", fmt.get_ptr()); - const std::string& result = armv7_fmt(context, fmt, 1, 0, 0); + const std::string& result = armv7_fmt(context, fmt, va_args.g_count, va_args.f_count, va_args.v_count); sceLibc.Log("*** -> '%s'", result); LOG_NOTICE(TTY, result); } - void sprintf(ARMv7Context& context, vm::ptr str, vm::cptr fmt) // va_args... + void sprintf(ARMv7Context& context, vm::ptr str, vm::cptr fmt, armv7_va_args_t va_args) { sceLibc.Warning("sprintf(str=*0x%x, fmt=*0x%x)", str, fmt); sceLibc.Log("*** *fmt = '%s'", fmt.get_ptr()); - const std::string& result = armv7_fmt(context, fmt, 2, 0, 0); + const std::string& result = armv7_fmt(context, fmt, va_args.g_count, va_args.f_count, va_args.v_count); sceLibc.Log("*** -> '%s'", result); ::memcpy(str.get_ptr(), result.c_str(), result.size() + 1); diff --git a/rpcs3/Emu/ARMv7/PSVFuncList.h b/rpcs3/Emu/ARMv7/PSVFuncList.h index 970c1548cd..c104585ebe 100644 --- a/rpcs3/Emu/ARMv7/PSVFuncList.h +++ b/rpcs3/Emu/ARMv7/PSVFuncList.h @@ -35,27 +35,37 @@ public: }; -typedef void(*psv_func_caller)(ARMv7Context&); +using armv7_func_caller = void(*)(ARMv7Context&); + +struct armv7_va_args_t +{ + u32 g_count; + u32 f_count; + u32 v_count; +}; // Utilities for binding ARMv7Context to C++ function arguments received by HLE functions or sent to callbacks namespace psv_func_detail { - enum arg_class + enum arg_class : u32 { ARG_GENERAL, ARG_FLOAT, ARG_VECTOR, ARG_STACK, + ARG_CONTEXT, + ARG_VARIADIC, + ARG_UNKNOWN, }; static const auto FIXED_STACK_FRAME_SIZE = 0x80; // described in CB_FUNC.h - template - struct bind_arg; - - template - struct bind_arg + template + struct bind_arg { + static_assert(type == ARG_GENERAL, "Unknown function argument type"); + static_assert(!std::is_pointer::value, "Invalid function argument type (pointer)"); + static_assert(!std::is_reference::value, "Invalid function argument type (reference)"); static_assert(sizeof(T) <= 4, "Invalid function argument type for ARG_GENERAL"); force_inline static T get_arg(ARMv7Context& context) @@ -69,40 +79,40 @@ namespace psv_func_detail } }; - template + template struct bind_arg { // first u64 argument is passed in r0-r1, second one is passed in r2-r3 (if g_count = 3) - static_assert(g_count == 1 || g_count == 3, "Wrong u64 argument position"); + static_assert(g_count == 2 || g_count == 4, "Wrong u64 argument position"); force_inline static u64 get_arg(ARMv7Context& context) { - return context.GPR_D[g_count >> 1]; + return context.GPR_D[(g_count - 1) >> 1]; } force_inline static void put_arg(ARMv7Context& context, u64 arg) { - context.GPR_D[g_count >> 1] = arg; + context.GPR_D[(g_count - 1) >> 1] = arg; } }; - template + template struct bind_arg { - static_assert(g_count == 1 || g_count == 3, "Wrong s64 argument position"); + static_assert(g_count == 2 || g_count == 4, "Wrong s64 argument position"); force_inline static s64 get_arg(ARMv7Context& context) { - return context.GPR_D[g_count >> 1]; + return context.GPR_D[(g_count - 1) >> 1]; } force_inline static void put_arg(ARMv7Context& context, s64 arg) { - context.GPR_D[g_count >> 1] = arg; + context.GPR_D[(g_count - 1) >> 1] = arg; } }; - template + template struct bind_arg { static_assert(f_count <= 0, "TODO: Unsupported argument type (float)"); @@ -117,11 +127,11 @@ namespace psv_func_detail } }; - template + template struct bind_arg { static_assert(v_count <= 0, "TODO: Unsupported argument type (vector)"); - static_assert(std::is_same::value, "Invalid function argument type for ARG_VECTOR"); + static_assert(std::is_same, u128>::value, "Invalid function argument type for ARG_VECTOR"); force_inline static T get_arg(ARMv7Context& context) { @@ -132,7 +142,7 @@ namespace psv_func_detail } }; - template + template struct bind_arg { static_assert(f_count <= 0, "TODO: Unsupported stack argument type (float)"); @@ -155,44 +165,70 @@ namespace psv_func_detail } }; - template + template struct bind_arg { force_inline static u64 get_arg(ARMv7Context& context) { // TODO: check - return vm::read64(context.SP + sizeof(u32) * (g_count - 5)); + return vm::read64(context.SP + sizeof(u32) * (g_count - 6)); } force_inline static void put_arg(ARMv7Context& context, u64 arg) { // TODO: check - const int stack_pos = (g_count - 5) * 4 - FIXED_STACK_FRAME_SIZE; + const int stack_pos = (g_count - 6) * 4 - FIXED_STACK_FRAME_SIZE; static_assert(stack_pos < -4, "TODO: Increase fixed stack frame size (arg count limit broken)"); vm::write64(context.SP + stack_pos, arg); } }; - template + template struct bind_arg { force_inline static s64 get_arg(ARMv7Context& context) { // TODO: check - return vm::read64(context.SP + sizeof(u32) * (g_count - 5)); + return vm::read64(context.SP + sizeof(u32) * (g_count - 6)); } force_inline static void put_arg(ARMv7Context& context, s64 arg) { // TODO: check - const int stack_pos = (g_count - 5) * 4 - FIXED_STACK_FRAME_SIZE; + const int stack_pos = (g_count - 6) * 4 - FIXED_STACK_FRAME_SIZE; static_assert(stack_pos < -4, "TODO: Increase fixed stack frame size (arg count limit broken)"); vm::write64(context.SP + stack_pos, arg); } }; + template + struct bind_arg + { + static_assert(std::is_same::value, "Invalid function argument type for ARG_CONTEXT"); + + force_inline static ARMv7Context& get_arg(ARMv7Context& context) + { + return context; + } + + force_inline static void put_arg(ARMv7Context& context, ARMv7Context& arg) + { + } + }; + + template + struct bind_arg + { + static_assert(std::is_same, armv7_va_args_t>::value, "Invalid function argument type for ARG_VARIADIC"); + + force_inline static armv7_va_args_t get_arg(ARMv7Context& context) + { + return{ g_count, f_count, v_count }; + } + }; + template struct bind_result { @@ -253,7 +289,7 @@ namespace psv_func_detail //template //struct bind_result //{ - // static_assert(std::is_same::value, "Invalid function result type for ARG_VECTOR"); + // static_assert(std::is_same, u128>::value, "Invalid function result type for ARG_VECTOR"); // static force_inline void put_result(ARMv7Context& context, const T& result) // { @@ -266,94 +302,105 @@ namespace psv_func_detail 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 bool is_vector = std::is_same, u128>::value; static const arg_class value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL); }; - template + template struct arg_type { - 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 static const bool is_float = std::is_floating_point::value; - static const bool is_vector = std::is_same::value; - static const int g_align = __alignof(T) > 4 ? __alignof(T) >> 2 : 1; - static const int g_pos = (is_float || is_vector) ? g_count : ((g_count + (g_align - 1)) & ~(g_align - 1)) + 1; - static const int g_next = g_pos + g_align - 1; - static const int f_value = !is_float ? f_count : f_count + 1; - static const int v_value = !is_vector ? v_count : v_count + 1; - static const arg_class value = is_float - ? ((f_value > 9000) ? ARG_STACK : ARG_FLOAT) - : (is_vector ? ((v_value > 9000) ? ARG_STACK : ARG_VECTOR) : ((g_pos > 4) ? ARG_STACK : ARG_GENERAL)); + static const bool is_vector = std::is_same, u128>::value; + static const bool is_context = std::is_same::value; + static const bool is_variadic = std::is_same, armv7_va_args_t>::value; + static const bool is_general = !is_float && !is_vector && !is_context && !is_variadic; + + static const u32 g_align = alignof32(T) > 4 ? alignof32(T) >> 2 : 1; + static const u32 g_value = is_general ? ((g_count + (g_align - 1)) & ~(g_align - 1)) + (g_align) : g_count; + static const u32 f_value = f_count + is_float; + static const u32 v_value = v_count + is_vector; + + static const arg_class value = + is_general ? (g_value > 4 ? ARG_STACK : ARG_GENERAL) : + is_float ? (f_value > 9000 ? ARG_STACK : ARG_FLOAT) : + is_vector ? (v_value > 9000 ? ARG_STACK : ARG_VECTOR) : + is_context ? ARG_CONTEXT : + is_variadic ? ARG_VARIADIC : + ARG_UNKNOWN; }; - template - struct call_impl + // wrapper for variadic argument info list, each value contains packed argument type and counts of GENERAL, FLOAT and VECTOR arguments + template struct arg_info_pack_t; + + template struct arg_info_pack_t { - static force_inline RT call(F f, Tuple && t) + static const u32 last_value = arg_info_pack_t::last_value; + }; + + template struct arg_info_pack_t + { + static const u32 last_value = First; + }; + + template<> struct arg_info_pack_t<> + { + static const u32 last_value = 0; + }; + + // argument type + g/f/v_count unpacker + template struct bind_arg_packed + { + force_inline static T get_arg(ARMv7Context& context) { - return call_impl::call(f, std::forward(t)); + return bind_arg(type_pack & 0xff), (type_pack >> 8) & 0xff, (type_pack >> 16) & 0xff, (type_pack >> 24)>::get_arg(context); } }; - template - struct call_impl + template + force_inline RT call(ARMv7Context& context, RT(*func)(Args...), arg_info_pack_t info) { - static force_inline RT call(F f, Tuple && t) - { - return f(std::get(std::forward(t))...); - } - }; - - template - force_inline RT call(F f, Tuple && t) - { - using ttype = std::decay_t; - return psv_func_detail::call_impl::value, std::tuple_size::value>::call(f, std::forward(t)); + // do the actual function call when all arguments are prepared (simultaneous unpacking of Args... and Info...) + return func(bind_arg_packed::get_arg(context)...); } - template - force_inline std::tuple<> get_func_args(ARMv7Context& context) + template + force_inline RT call(ARMv7Context& context, RT(*func)(Args...), arg_info_pack_t info) { - // terminator - return std::tuple<>(); - } + // unpack previous type counts (0/0/0 for the first time) + const u32 g_count = (info.last_value >> 8) & 0xff; + const u32 f_count = (info.last_value >> 16) & 0xff; + const u32 v_count = (info.last_value >> 24); - template - force_inline std::tuple get_func_args(ARMv7Context& context) - { - typedef arg_type type; + using type = arg_type; const arg_class t = type::value; - const int g0 = type::g_pos; - const int g1 = type::g_next; - const int f = type::f_value; - const int v = type::v_value; + const u32 g = type::g_value; + const u32 f = type::f_value; + const u32 v = type::v_value; - return std::tuple_cat(std::tuple(bind_arg::get_arg(context)), get_func_args(context)); + return call(context, func, arg_info_pack_t{}); } - template + template force_inline static bool put_func_args(ARMv7Context& context) { // terminator return false; } - template + template force_inline static bool put_func_args(ARMv7Context& context, T1 arg, T... args) { - typedef arg_type type; + using type = arg_type; const arg_class t = type::value; - const int g0 = type::g_pos; - const int g1 = type::g_next; - const int f = type::f_value; - const int v = type::v_value; + const u32 g = type::g_value; + const u32 f = type::f_value; + const u32 v = type::v_value; - bind_arg::put_arg(context, arg); + bind_arg::put_arg(context, arg); // return true if stack was used - return put_func_args(context, args...) || (t == ARG_STACK); + return put_func_args(context, args...) || (t == ARG_STACK); } template @@ -362,44 +409,22 @@ namespace psv_func_detail template struct func_binder { - typedef void(*func_t)(T...); + using func_t = void(*)(T...); - static void do_call(ARMv7Context& context, func_t _func) + static void do_call(ARMv7Context& context, func_t func) { - call(_func, get_func_args<0, 0, 0, T...>(context)); - } - }; - - template - struct func_binder - { - typedef void(*func_t)(ARMv7Context&, T...); - - static void do_call(ARMv7Context& context, func_t _func) - { - call(_func, std::tuple_cat(std::tuple(context), get_func_args<0, 0, 0, T...>(context))); + call(context, func, arg_info_pack_t<>{}); } }; template struct func_binder { - typedef RT(*func_t)(T...); + using func_t = RT(*)(T...); - static void do_call(ARMv7Context& context, func_t _func) + static void do_call(ARMv7Context& context, func_t func) { - bind_result::value>::put_result(context, call(_func, get_func_args<0, 0, 0, T...>(context))); - } - }; - - template - struct func_binder - { - typedef RT(*func_t)(ARMv7Context&, T...); - - static void do_call(ARMv7Context& context, func_t _func) - { - bind_result::value>::put_result(context, call(_func, std::tuple_cat(std::tuple(context), get_func_args<0, 0, 0, T...>(context)))); + bind_result::value>::put_result(context, call(context, func, arg_info_pack_t<>{})); } }; @@ -439,14 +464,14 @@ struct psv_func u32 nid; // Unique function ID (should be generated individually for each elf loaded) u32 flags; const char* name; // Function name for information - psv_func_caller func; // Function caller + armv7_func_caller func; // Function caller psv_log_base* module; // Module for information psv_func() { } - psv_func(u32 nid, u32 flags, psv_log_base* module, const char* name, psv_func_caller func) + psv_func(u32 nid, u32 flags, psv_log_base* module, const char* name, armv7_func_caller func) : nid(nid) , flags(flags) , name(name) diff --git a/rpcs3/Emu/Cell/PPUThread.h b/rpcs3/Emu/Cell/PPUThread.h index 276da10924..d49cb1086e 100644 --- a/rpcs3/Emu/Cell/PPUThread.h +++ b/rpcs3/Emu/Cell/PPUThread.h @@ -1,4 +1,5 @@ #pragma once + #include "Emu/Cell/Common.h" #include "Emu/CPU/CPUThread.h" #include "Emu/Memory/vm.h" diff --git a/rpcs3/Emu/SysCalls/CB_FUNC.h b/rpcs3/Emu/SysCalls/CB_FUNC.h index 88d5343c4a..c68ea8dbcb 100644 --- a/rpcs3/Emu/SysCalls/CB_FUNC.h +++ b/rpcs3/Emu/SysCalls/CB_FUNC.h @@ -10,6 +10,8 @@ namespace cb_detail ARG_FLOAT, ARG_VECTOR, ARG_STACK, + ARG_CONTEXT, // for compatibility with SC_FUNC and CALL_FUNC + ARG_UNKNOWN, }; // Current implementation can handle only fixed amount of stack arguments. @@ -18,11 +20,11 @@ namespace cb_detail static const auto FIXED_STACK_FRAME_SIZE = 0x90; template - struct _func_arg; - - template - struct _func_arg + struct _func_arg { + static_assert(type == ARG_GENERAL, "Unknown callback argument type"); + static_assert(!std::is_pointer::value, "Invalid callback argument type (pointer)"); + static_assert(!std::is_reference::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) @@ -45,7 +47,7 @@ namespace cb_detail template struct _func_arg { - static_assert(std::is_same::value, "Invalid callback argument type for ARG_VECTOR"); + static_assert(std::is_same, u128>::value, "Invalid callback argument type for ARG_VECTOR"); force_inline static void set_value(PPUThread& CPU, const T& arg) { @@ -68,6 +70,16 @@ namespace cb_detail } }; + template + struct _func_arg + { + static_assert(std::is_same::value, "Invalid callback argument type for ARG_CONTEXT"); + + force_inline static void set_value(PPUThread& CPU, const T& arg) + { + } + }; + template force_inline static bool _bind_func_args(PPUThread& CPU) { @@ -78,18 +90,24 @@ namespace cb_detail template force_inline static bool _bind_func_args(PPUThread& CPU, T1 arg1, T... args) { - static_assert(!std::is_pointer::value, "Invalid callback argument type (pointer)"); - static_assert(!std::is_reference::value, "Invalid callback argument type (reference)"); const bool is_float = std::is_floating_point::value; - const bool is_vector = std::is_same::value; - const _func_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); + const bool is_vector = std::is_same, u128>::value; + const bool is_context = std::is_same::value; + const bool is_general = !is_float && !is_vector && !is_context; + + const _func_arg_type t = + is_general ? (g_count >= 8 ? ARG_STACK : ARG_GENERAL) : + is_float ? (f_count >= 13 ? ARG_STACK : ARG_FLOAT) : + is_vector ? (v_count >= 12 ? ARG_STACK : ARG_VECTOR) : + 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; _func_arg::set_value(CPU, arg1); + // return true if stack was used return _bind_func_args(CPU, args...) || (t == ARG_STACK); } @@ -97,7 +115,7 @@ namespace cb_detail template struct _func_res { - static_assert(type == ARG_GENERAL, "Wrong use of _func_res template"); + static_assert(type == ARG_GENERAL, "Unknown callback result type"); static_assert(sizeof(T) <= 8, "Invalid callback result type for ARG_GENERAL"); force_inline static T get_value(const PPUThread& CPU) @@ -120,7 +138,7 @@ namespace cb_detail template struct _func_res { - static_assert(std::is_same::value, "Invalid callback result type for ARG_VECTOR"); + static_assert(std::is_same, u128>::value, "Invalid callback result type for ARG_VECTOR"); force_inline static T get_value(const PPUThread& CPU) { @@ -138,7 +156,7 @@ namespace cb_detail static_assert(!std::is_pointer::value, "Invalid callback result type (pointer)"); static_assert(!std::is_reference::value, "Invalid callback result type (reference)"); const bool is_float = std::is_floating_point::value; - const bool is_vector = std::is_same::value; + const bool is_vector = std::is_same, u128>::value; const _func_arg_type t = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL); return _func_res::get_value(CPU); diff --git a/rpcs3/Emu/SysCalls/Modules.h b/rpcs3/Emu/SysCalls/Modules.h index 70f78090c9..10203a49bc 100644 --- a/rpcs3/Emu/SysCalls/Modules.h +++ b/rpcs3/Emu/SysCalls/Modules.h @@ -125,20 +125,8 @@ void hook_ppu_funcs(vm::ptr base, u32 size); bool patch_ppu_import(u32 addr, u32 index); -// don't use directly -template inline auto _call_ppu(RT(*func)(PPUThread&, T...), PPUThread& CPU, Args&&... args) -> decltype(func(CPU, args...)) -{ - return func(CPU, args...); -} - -// don't use directly -template inline auto _call_ppu(RT(*func)(T...), PPUThread& CPU, Args&&... args) -> decltype(func(args...)) -{ - return func(args...); -} - // call specified function directly if LLE is not available, call LLE equivalent in callback style otherwise -template inline auto hle_call_func(T func, u32 index, PPUThread& CPU, Args... args) -> decltype(_call_ppu(func, CPU, args...)) +template inline auto hle_call_func(PPUThread& CPU, T func, u32 index, Args&&... args) -> decltype(func(std::forward(args)...)) { const auto mfunc = get_ppu_func_by_index(index); @@ -147,15 +135,15 @@ template inline auto hle_call_func(T func, u32 ind const u32 pc = vm::read32(mfunc->lle_func.addr()); const u32 rtoc = vm::read32(mfunc->lle_func.addr() + 4); - return cb_call(CPU, pc, rtoc, args...); + return cb_call(args)...)), Args...>(CPU, pc, rtoc, std::forward(args)...); } else { - return _call_ppu(func, CPU, args...); + return func(std::forward(args)...); } } -#define CALL_FUNC(func, ...) hle_call_func(func, g_ppu_func_index__##func, __VA_ARGS__) +#define CALL_FUNC(cpu, func, ...) hle_call_func(cpu, func, g_ppu_func_index__##func, __VA_ARGS__) #define REG_FUNC(module, name) add_ppu_func(ModuleFunc(get_function_id(#name), 0, &module, #name, bind_func(name))) #define REG_FUNC_FH(module, name) add_ppu_func(ModuleFunc(get_function_id(#name), MFF_FORCED_HLE, &module, #name, bind_func(name))) diff --git a/rpcs3/Emu/SysCalls/Modules/cellAvconfExt.cpp b/rpcs3/Emu/SysCalls/Modules/cellAvconfExt.cpp index 1b77bb9b05..5499ac05b4 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAvconfExt.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAvconfExt.cpp @@ -8,7 +8,7 @@ namespace vm { using namespace ps3; } extern Module cellAvconfExt; -s32 cellVideoOutConvertCursorColor(PPUThread& CPU) +s32 cellVideoOutConvertCursorColor() { UNIMPLEMENTED_FUNC(cellAvconfExt); return CELL_OK; diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp b/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp index 7bf63df8c6..04d47eac5e 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp @@ -427,7 +427,7 @@ void spursHandlerWaitReady(PPUThread& CPU, vm::ptr spurs) { extern u32 g_ppu_func_index__sys_lwmutex_unlock; // test - if (s32 rc = CALL_FUNC(sys_lwmutex_unlock, CPU, spurs.of(&CellSpurs::mutex))) + if (s32 rc = CALL_FUNC(CPU, sys_lwmutex_unlock, CPU, spurs.of(&CellSpurs::mutex))) { throw EXCEPTION("sys_lwmutex_unlock() failed (0x%x)", rc); } diff --git a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp index 140241404c..0bfae70978 100644 --- a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp @@ -1141,11 +1141,11 @@ s32 _sys_free(u32 addr) return CELL_OK; } -s32 _sys_snprintf(PPUThread& CPU, vm::ptr dst, u32 count, vm::cptr fmt) // va_args... +s32 _sys_snprintf(PPUThread& CPU, vm::ptr dst, u32 count, vm::cptr fmt, ppu_va_args_t va_args) { sysPrxForUser.Warning("_sys_snprintf(dst=*0x%x, count=%d, fmt=*0x%x, ...)", dst, count, fmt); - std::string result = ps3_fmt(CPU, fmt, 3, 0, 0); + std::string result = ps3_fmt(CPU, fmt, va_args.g_count, va_args.f_count, va_args.v_count); sysPrxForUser.Warning("*** '%s' -> '%s'", fmt.get_ptr(), result); @@ -1163,7 +1163,7 @@ s32 _sys_snprintf(PPUThread& CPU, vm::ptr dst, u32 count, vm::cptr f } } -s32 _sys_printf(vm::cptr fmt) // va_args... +s32 _sys_printf(vm::cptr fmt, ppu_va_args_t va_args) { sysPrxForUser.Todo("_sys_printf(fmt=*0x%x, ...)", fmt); diff --git a/rpcs3/Emu/SysCalls/SC_FUNC.h b/rpcs3/Emu/SysCalls/SC_FUNC.h index 8d7eddaeaf..ac7690d807 100644 --- a/rpcs3/Emu/SysCalls/SC_FUNC.h +++ b/rpcs3/Emu/SysCalls/SC_FUNC.h @@ -4,22 +4,33 @@ using ppu_func_caller = void(*)(PPUThread&); +struct ppu_va_args_t +{ + u32 g_count; + u32 f_count; + u32 v_count; +}; + 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 f12) + 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, + ARG_STACK, // argument is 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_UNKNOWN, }; - template struct bind_arg; - - template - struct bind_arg + template + struct bind_arg { + static_assert(type == ARG_GENERAL, "Unknown function argument type"); + static_assert(!std::is_pointer::value, "Invalid function argument type (pointer)"); + static_assert(!std::is_reference::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& CPU) @@ -42,7 +53,7 @@ namespace ppu_func_detail template struct bind_arg { - static_assert(std::is_same::value, "Invalid function argument type for ARG_VECTOR"); + static_assert(std::is_same, u128>::value, "Invalid function argument type for ARG_VECTOR"); static force_inline T get_arg(PPUThread& CPU) { @@ -65,10 +76,32 @@ namespace ppu_func_detail } }; + template + struct bind_arg + { + static_assert(std::is_same::value, "Invalid function argument type for ARG_CONTEXT"); + + static force_inline PPUThread& get_arg(PPUThread& CPU) + { + return CPU; + } + }; + + template + struct bind_arg + { + static_assert(std::is_same::value, "Invalid function argument type for ARG_VARIADIC"); + + static force_inline ppu_va_args_t get_arg(PPUThread& CPU) + { + return{ g_count, f_count, v_count }; + } + }; + template struct bind_result { - static_assert(type == ARG_GENERAL, "Wrong use of bind_result template"); + static_assert(type == ARG_GENERAL, "Unknown function result type"); static_assert(sizeof(T) <= 8, "Invalid function result type for ARG_GENERAL"); static force_inline void put_result(PPUThread& CPU, const T& result) @@ -91,7 +124,7 @@ namespace ppu_func_detail template struct bind_result { - static_assert(std::is_same::value, "Invalid function result type for ARG_VECTOR"); + static_assert(std::is_same, u128>::value, "Invalid function result type for ARG_VECTOR"); static force_inline void put_result(PPUThread& CPU, const T& result) { @@ -117,7 +150,7 @@ namespace ppu_func_detail static const u32 last_value = 0; }; - // argument unpacker + // argument type + g/f/v_count unpacker template struct bind_arg_packed { static force_inline T get_arg(PPUThread& CPU) @@ -129,21 +162,13 @@ namespace ppu_func_detail template force_inline RT call(PPUThread& CPU, RT(*func)(Args...), arg_info_pack_t) { + // do the actual function call when all arguments are prepared (simultaneous unpacking of Args... and Info...) return func(bind_arg_packed::get_arg(CPU)...); } - template - force_inline RT call(PPUThread& CPU, RT(*func)(PPUThread&, Args...), arg_info_pack_t) - { - return func(CPU, bind_arg_packed::get_arg(CPU)...); - } - template force_inline RT call(PPUThread& CPU, RT(*func)(Args...), arg_info_pack_t info) { - static_assert(!std::is_pointer::value, "Invalid function argument type (pointer)"); - static_assert(!std::is_reference::value, "Invalid function argument type (reference)"); - // unpack previous type counts (0/0/0 for the first time) const u32 g_count = (info.last_value >> 8) & 0xff; const u32 f_count = (info.last_value >> 16) & 0xff; @@ -151,13 +176,22 @@ namespace ppu_func_detail // TODO: check calculations const bool is_float = std::is_floating_point::value; - const bool is_vector = std::is_same::value; - const arg_class 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 u32 g = g_count + (is_float || is_vector ? 0 : 1); - const u32 f = f_count + (is_float ? 1 : 0); - const u32 v = v_count + (is_vector ? 1 : 0); + const bool is_vector = std::is_same, u128>::value; + const bool is_context = std::is_same::value; + const bool is_variadic = std::is_same, ppu_va_args_t>::value; + const bool is_general = !is_float && !is_vector && !is_context && !is_variadic; + + const arg_class t = + is_general ? (g_count >= 8 ? ARG_STACK : ARG_GENERAL) : + is_float ? (f_count >= 13 ? ARG_STACK : ARG_FLOAT) : + is_vector ? (v_count >= 12 ? ARG_STACK : ARG_VECTOR) : + is_context ? ARG_CONTEXT : + is_variadic ? ARG_VARIADIC : + ARG_UNKNOWN; + + const u32 g = g_count + is_general; + const u32 f = f_count + is_float; + const u32 v = v_count + is_vector; return call(CPU, func, arg_info_pack_t{}); } @@ -167,23 +201,12 @@ namespace ppu_func_detail 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 bool is_vector = std::is_same, u128>::value; static const arg_class value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL); }; template struct func_binder; - template - struct func_binder - { - using func_t = void(*)(PPUThread&, T...); - - static force_inline void do_call(PPUThread& CPU, func_t func) - { - call(CPU, func, arg_info_pack_t<>{}); - } - }; - template struct func_binder { @@ -217,17 +240,6 @@ namespace ppu_func_detail } }; - template - struct func_binder - { - using func_t = RT(*)(PPUThread&, T...); - - static force_inline void do_call(PPUThread& CPU, func_t func) - { - bind_result::value>::put_result(CPU, call(CPU, func, arg_info_pack_t<>{})); - } - }; - template struct func_binder {