rpcsx/rpcs3/Emu/Cell/PPUCallback.h

204 lines
6.2 KiB
C
Raw Normal View History

2020-12-05 13:08:24 +01:00
#pragma once
2014-09-11 21:33:20 +02:00
#include "Emu/Cell/PPUThread.h"
2014-09-11 21:18:19 +02:00
#include "util/v128.hpp"
struct ppu_func_opd_t;
2016-04-14 01:09:41 +02:00
namespace ppu_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,
2016-04-14 01:09:41 +02:00
ARG_CONTEXT,
ARG_UNKNOWN,
2014-09-12 15:08:24 +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;
2016-04-14 01:09:41 +02:00
template<typename T, _func_arg_type type, u32 g_count, u32 f_count, u32 v_count>
struct _func_arg
2014-09-12 15:08:24 +02:00
{
static_assert(type == ARG_GENERAL, "Unknown callback argument type");
static_assert(!std::is_pointer<T>::value, "Invalid callback argument type (pointer)");
static_assert(!std::is_reference<T>::value, "Invalid callback argument type (reference)");
2014-09-12 15:08:24 +02:00
static_assert(sizeof(T) <= 8, "Invalid callback argument type for ARG_GENERAL");
2018-02-09 15:49:37 +01:00
static inline void set_value(ppu_thread& CPU, const T& arg)
2014-09-12 15:08:24 +02:00
{
CPU.gpr[g_count + 2] = ppu_gpr_cast(arg);
2014-09-12 15:08:24 +02:00
}
};
2016-04-14 01:09:41 +02:00
template<typename T, u32 g_count, u32 f_count, u32 v_count>
2014-09-12 15:08:24 +02:00
struct _func_arg<T, ARG_FLOAT, g_count, f_count, v_count>
{
static_assert(sizeof(T) <= 8, "Invalid callback argument type for ARG_FLOAT");
static inline void set_value(ppu_thread& CPU, const T& arg)
2014-09-12 15:08:24 +02: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
2016-04-14 01:09:41 +02:00
template<typename T, u32 g_count, u32 f_count, u32 v_count>
2014-09-12 15:08:24 +02:00
struct _func_arg<T, ARG_VECTOR, g_count, f_count, v_count>
{
2016-08-12 18:24:29 +02:00
static_assert(std::is_same<std::decay_t<T>, v128>::value, "Invalid callback argument type for ARG_VECTOR");
2014-09-11 21:18:19 +02:00
static inline void set_value(ppu_thread& CPU, const T& arg)
2014-09-11 21:18:19 +02:00
{
CPU.vr[v_count + 1] = arg;
2014-09-11 21:18:19 +02:00
}
};
2016-04-14 01:09:41 +02:00
template<typename T, u32 g_count, u32 f_count, u32 v_count>
2014-09-12 15:08:24 +02:00
struct _func_arg<T, ARG_STACK, g_count, f_count, v_count>
{
2016-04-14 01:09:41 +02:00
static_assert(alignof(T) <= 16, "Unsupported callback argument type alignment for ARG_STACK");
2014-09-12 15:08:24 +02:00
static inline void set_value(ppu_thread& CPU, const T& arg)
2014-09-12 15:08:24 +02:00
{
2016-04-14 01:09:41 +02:00
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)");
2018-02-09 15:49:37 +01:00
vm::write64(CPU.gpr[1] + stack_pos, ppu_gpr_cast(arg)); // TODO
2014-09-12 15:08:24 +02:00
}
};
2016-04-14 01:09:41 +02:00
template<typename T, u32 g_count, u32 f_count, u32 v_count>
struct _func_arg<T, ARG_CONTEXT, g_count, f_count, v_count>
{
2016-08-12 18:24:29 +02:00
static_assert(std::is_same<std::decay_t<T>, ppu_thread>::value, "Invalid callback argument type for ARG_CONTEXT");
FORCE_INLINE static void set_value(ppu_thread& CPU, const T& arg)
{
}
};
2016-04-14 01:09:41 +02:00
template<u32 g_count, u32 f_count, u32 v_count>
FORCE_INLINE static bool _bind_func_args(ppu_thread& CPU)
2014-09-12 15:08:24 +02:00
{
// terminator
return false;
2014-09-12 15:08:24 +02:00
}
2016-04-14 01:09:41 +02:00
template<u32 g_count, u32 f_count, u32 v_count, typename T1, typename... T>
FORCE_INLINE static bool _bind_func_args(ppu_thread& CPU, T1 arg1, T... args)
2014-09-12 15:08:24 +02:00
{
const bool is_float = std::is_floating_point<T1>::value;
2016-08-12 18:24:29 +02:00
const bool is_vector = std::is_same<std::decay_t<T1>, v128>::value;
const bool is_context = std::is_same<std::decay_t<T1>, ppu_thread>::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 u32 g = g_count + (is_general || is_float ? 1 : is_vector ? (g_count & 1) + 2 : 0);
2016-04-14 01:09:41 +02:00
const u32 f = f_count + is_float;
const u32 v = v_count + is_vector;
2018-02-09 15:49:37 +01:00
2014-09-12 15:08:24 +02:00
_func_arg<T1, t, g, f, v>::set_value(CPU, arg1);
// 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
{
static_assert(type == ARG_GENERAL, "Unknown callback result type");
2014-09-16 15:56:27 +02:00
static_assert(sizeof(T) <= 8, "Invalid callback result type for ARG_GENERAL");
2014-09-11 21:18:19 +02:00
FORCE_INLINE static T get_value(const ppu_thread& CPU)
2014-09-12 15:08:24 +02:00
{
return ppu_gpr_cast<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
FORCE_INLINE static T get_value(const ppu_thread& CPU)
2014-09-11 22:46:11 +02: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
{
2016-08-12 18:24:29 +02:00
static_assert(std::is_same<std::decay_t<T>, v128>::value, "Invalid callback result type for ARG_VECTOR");
2014-09-16 15:56:27 +02:00
FORCE_INLINE static T get_value(const ppu_thread& CPU)
2014-09-11 22:46:11 +02:00
{
return CPU.vr[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
{
FORCE_INLINE static RT call(ppu_thread& 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;
2016-08-12 18:24:29 +02:00
const bool is_vector = std::is_same<std::decay_t<RT>, v128>::value;
2014-09-16 15:56:27 +02:00
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
}
};
template<typename... T>
struct _func_caller<void, T...>
{
FORCE_INLINE static void call(ppu_thread& CPU, u32 pc, u32 rtoc, T... args)
{
const bool stack = _bind_func_args<0, 0, 0, T...>(CPU, args...);
CPU.gpr[1] -= stack ? FIXED_STACK_FRAME_SIZE : 0x70; // create reserved area
2015-07-19 13:36:32 +02:00
CPU.fast_call(pc, rtoc);
CPU.gpr[1] += stack ? FIXED_STACK_FRAME_SIZE : 0x70;
}
};
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>
FORCE_INLINE RT _ptr_base<RT(T...), AT>::operator()(ppu_thread& CPU, T... args) const
2014-09-12 15:08:24 +02:00
{
const auto data = vm::_ptr<ppu_func_opd_t>(vm::cast(m_addr));
const u32 pc = data->addr;
const u32 rtoc = data->rtoc;
2014-09-12 15:08:24 +02:00
2016-04-14 01:09:41 +02:00
return ppu_cb_detail::_func_caller<RT, T...>::call(CPU, pc, rtoc, args...);
2014-09-12 15:08:24 +02:00
}
template<typename AT, typename RT, typename... T>
FORCE_INLINE const ppu_func_opd_t& _ptr_base<RT(T...), AT>::opd() const
{
return vm::_ref<ppu_func_opd_t>(vm::cast(m_addr));
}
2014-09-12 21:27:33 +02:00
}
template<typename RT, typename... T> inline RT cb_call(ppu_thread& CPU, u32 pc, u32 rtoc, T... args)
{
2016-04-14 01:09:41 +02:00
return ppu_cb_detail::_func_caller<RT, T...>::call(CPU, pc, rtoc, args...);
}