Merge pull request #1024 from Nekotekina/master

HLE binding improvements
This commit is contained in:
Hykem 2015-02-25 17:25:01 +00:00
commit 9b2907dc64
14 changed files with 223 additions and 156 deletions

View file

@ -9,22 +9,7 @@ u32 add_psv_func(psv_func data)
{ {
for (auto& f : g_psv_func_list) for (auto& f : g_psv_func_list)
{ {
if (f.nid == data.nid) assert(f.nid != data.nid || (&f - g_psv_func_list.data()) < SFI_MAX);
{
const u32 index = (u32)(&f - g_psv_func_list.data());
if (index < SFI_MAX)
{
continue;
}
if (data.func)
{
f.func = data.func;
}
return index;
}
} }
g_psv_func_list.push_back(data); g_psv_func_list.push_back(data);

View file

@ -38,7 +38,7 @@ typedef void(*psv_func_caller)(ARMv7Context&);
// Utilities for binding ARMv7Context to C++ function arguments received by HLE functions or sent to callbacks // Utilities for binding ARMv7Context to C++ function arguments received by HLE functions or sent to callbacks
namespace psv_func_detail namespace psv_func_detail
{ {
enum bind_arg_type enum arg_class
{ {
ARG_GENERAL, ARG_GENERAL,
ARG_FLOAT, ARG_FLOAT,
@ -48,7 +48,7 @@ namespace psv_func_detail
static const auto FIXED_STACK_FRAME_SIZE = 0x100; // described in CB_FUNC.h static const auto FIXED_STACK_FRAME_SIZE = 0x100; // described in CB_FUNC.h
template<typename T, bind_arg_type type, int g_count, int f_count, int v_count> template<typename T, arg_class type, int g_count, int f_count, int v_count>
struct bind_arg; struct bind_arg;
template<typename T, int g_count, int f_count, int v_count> template<typename T, int g_count, int f_count, int v_count>
@ -191,7 +191,7 @@ namespace psv_func_detail
} }
}; };
template<typename T, bind_arg_type type> template<typename T, arg_class type>
struct bind_result struct bind_result
{ {
static_assert(type != ARG_FLOAT, "TODO: Unsupported funcion result type (float)"); static_assert(type != ARG_FLOAT, "TODO: Unsupported funcion result type (float)");
@ -265,7 +265,7 @@ namespace psv_func_detail
static_assert(!std::is_reference<RT>::value, "Invalid function result type (reference)"); 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_float = std::is_floating_point<RT>::value;
static const bool is_vector = std::is_same<RT, u128>::value; static const bool is_vector = std::is_same<RT, u128>::value;
static const bind_arg_type value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL); static const arg_class value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL);
}; };
template<typename T, int g_count, int f_count, int v_count> template<typename T, int g_count, int f_count, int v_count>
@ -281,7 +281,7 @@ namespace psv_func_detail
static const int g_next = g_pos + g_align - 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 f_value = !is_float ? f_count : f_count + 1;
static const int v_value = !is_vector ? v_count : v_count + 1; static const int v_value = !is_vector ? v_count : v_count + 1;
static const bind_arg_type value = is_float static const arg_class value = is_float
? ((f_value > 9000) ? ARG_STACK : ARG_FLOAT) ? ((f_value > 9000) ? ARG_STACK : ARG_FLOAT)
: (is_vector ? ((v_value > 9000) ? ARG_STACK : ARG_VECTOR) : ((g_pos > 4) ? ARG_STACK : ARG_GENERAL)); : (is_vector ? ((v_value > 9000) ? ARG_STACK : ARG_VECTOR) : ((g_pos > 4) ? ARG_STACK : ARG_GENERAL));
}; };
@ -322,7 +322,7 @@ namespace psv_func_detail
__forceinline std::tuple<T, A...> get_func_args(ARMv7Context& context) __forceinline std::tuple<T, A...> get_func_args(ARMv7Context& context)
{ {
typedef arg_type<T, g_count, f_count, v_count> type; typedef arg_type<T, g_count, f_count, v_count> type;
const bind_arg_type t = type::value; const arg_class t = type::value;
const int g0 = type::g_pos; const int g0 = type::g_pos;
const int g1 = type::g_next; const int g1 = type::g_next;
const int f = type::f_value; const int f = type::f_value;
@ -342,7 +342,7 @@ namespace psv_func_detail
__forceinline static bool put_func_args(ARMv7Context& context, T1 arg, T... args) __forceinline static bool put_func_args(ARMv7Context& context, T1 arg, T... args)
{ {
typedef arg_type<T1, g_count, f_count, v_count> type; typedef arg_type<T1, g_count, f_count, v_count> type;
const bind_arg_type t = type::value; const arg_class t = type::value;
const int g0 = type::g_pos; const int g0 = type::g_pos;
const int g1 = type::g_next; const int g1 = type::g_next;
const int f = type::f_value; const int f = type::f_value;
@ -435,9 +435,23 @@ namespace psv_func_detail
struct psv_func struct psv_func
{ {
u32 nid; // Unique function ID (should be generated individually for each elf loaded) u32 nid; // Unique function ID (should be generated individually for each elf loaded)
u32 flags;
const char* name; // Function name for information const char* name; // Function name for information
psv_func_caller func; // Function caller psv_func_caller func; // Function caller
psv_log_base* module; // Module for information 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)
: nid(nid)
, flags(flags)
, name(name)
, func(func)
, module(module)
{
}
}; };
enum psv_special_function_index : u16 enum psv_special_function_index : u16
@ -450,23 +464,12 @@ enum psv_special_function_index : u16
// Do not call directly // Do not call directly
u32 add_psv_func(psv_func data); u32 add_psv_func(psv_func data);
// Do not call directly // Do not call directly
__forceinline static u32 add_psv_func(u32 nid, psv_log_base* module, const char* name, psv_func_caller func)
{
psv_func f;
f.nid = nid;
f.name = name;
f.func = func;
f.module = module;
return add_psv_func(f);
}
// Do not call directly
template<typename RT, typename... T> __forceinline void call_psv_func(ARMv7Context& context, RT(*func)(T...)) template<typename RT, typename... T> __forceinline void call_psv_func(ARMv7Context& context, RT(*func)(T...))
{ {
psv_func_detail::func_binder<RT, T...>::do_call(context, func); psv_func_detail::func_binder<RT, T...>::do_call(context, func);
} }
#define reg_psv_func(nid, module, name, func) add_psv_func(nid, module, name, [](ARMv7Context& context){ call_psv_func(context, func); }) #define reg_psv_func(nid, module, name, func) add_psv_func(psv_func(nid, 0, module, name, [](ARMv7Context& context){ call_psv_func(context, func); }))
// Find registered HLE function by NID // Find registered HLE function by NID
psv_func* get_psv_func_by_nid(u32 nid, u32* out_index = nullptr); psv_func* get_psv_func_by_nid(u32 nid, u32* out_index = nullptr);

View file

@ -18,10 +18,6 @@
#include <fenv.h> #include <fenv.h>
#if 0//def _DEBUG
#define HLE_CALL_DEBUG
#endif
extern u64 rotate_mask[64][64]; // defined in PPUThread.cpp, static didn't work correctly in GCC 4.9 for some reason extern u64 rotate_mask[64][64]; // defined in PPUThread.cpp, static didn't work correctly in GCC 4.9 for some reason
inline void InitRotateMask() inline void InitRotateMask()
{ {
@ -107,28 +103,6 @@ private:
if (fetestexcept(FE_OVERFLOW)) CPU.SetFPSCRException(FPSCR_OX); if (fetestexcept(FE_OVERFLOW)) CPU.SetFPSCRException(FPSCR_OX);
} }
void Exit() {}
void SysCall()
{
const u64 sc = CPU.GPR[11];
const u64 old_sc = CPU.m_last_syscall;
CPU.m_last_syscall = sc;
SysCalls::DoSyscall(CPU, (u32)sc);
if(Ini.HLELogging.GetValue())
{
LOG_WARNING(PPU, "SysCall[0x%llx ('%s')] done with code [0x%llx]! #pc: 0x%x",
sc, SysCalls::GetHLEFuncName((u32)sc).c_str(), CPU.GPR[3], CPU.PC);
}
#ifdef HLE_CALL_DEBUG
LOG_NOTICE(PPU, "SysCall[%lld] done with code [0x%llx]! #pc: 0x%x", sc, CPU.GPR[3], CPU.PC);
#endif
CPU.m_last_syscall = old_sc;
}
void NULL_OP() void NULL_OP()
{ {
throw "Null operation"; throw "Null operation";
@ -2260,7 +2234,7 @@ private:
{ {
switch (lev) switch (lev)
{ {
case 0x0: SysCall(); break; case 0x0: SysCalls::DoSyscall(CPU, CPU.GPR[11]); break;
case 0x1: throw "SC(): HyperCall LV1"; case 0x1: throw "SC(): HyperCall LV1";
case 0x3: CPU.FastStop(); break; case 0x3: CPU.FastStop(); break;
default: throw fmt::Format("SC(): unknown level (0x%x)", lev); default: throw fmt::Format("SC(): unknown level (0x%x)", lev);

View file

@ -91,10 +91,6 @@ public:
} }
private: private:
void SysCall()
{
}
//0 - 10 //0 - 10
void STOP(u32 code) void STOP(u32 code)
{ {
@ -1096,7 +1092,7 @@ private:
} }
else if (result == 0.0f) else if (result == 0.0f)
{ {
if (a != 0.0f & b != 0.0f) if (a != 0.0f && b != 0.0f)
CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SUNF | FPSCR_SDIFF); CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SUNF | FPSCR_SDIFF);
result = +0.0f; result = +0.0f;
} }

View file

@ -163,7 +163,6 @@ static const g_module_list[] =
{ 0xf053, "cellAdecAt3multi", nullptr }, { 0xf053, "cellAdecAt3multi", nullptr },
{ 0xf054, "cellLibatrac3multi", nullptr }, { 0xf054, "cellLibatrac3multi", nullptr },
{ -1, "cellSync", &cellSync },
{ -1, "cellSysmodule", &cellSysmodule }, { -1, "cellSysmodule", &cellSysmodule },
{ -1, "libmixer", &libmixer }, { -1, "libmixer", &libmixer },
{ -1, "sysPrxForUser", &sysPrxForUser }, { -1, "sysPrxForUser", &sysPrxForUser },

View file

@ -17,22 +17,7 @@ u32 add_ppu_func(ModuleFunc func)
{ {
for (auto& f : g_ppu_func_list) for (auto& f : g_ppu_func_list)
{ {
if (f.id == func.id) assert(f.id != func.id);
{
// partial update
if (func.func)
{
f.func = func.func;
}
if (func.lle_func)
{
f.lle_func = func.lle_func;
}
return (u32)(&f - g_ppu_func_list.data());
}
} }
g_ppu_func_list.push_back(func); g_ppu_func_list.push_back(func);
@ -48,7 +33,7 @@ u32 add_ppu_func_sub(StaticFunc func)
u32 add_ppu_func_sub(const char group[8], const u64 ops[], const char* name, Module* module, ppu_func_caller func) u32 add_ppu_func_sub(const char group[8], const u64 ops[], const char* name, Module* module, ppu_func_caller func)
{ {
StaticFunc sf; StaticFunc sf;
sf.index = add_ppu_func(ModuleFunc(get_function_id(name), module, func)); sf.index = add_ppu_func(ModuleFunc(get_function_id(name), 0, module, func));
sf.name = name; sf.name = name;
sf.group = *(u64*)group; sf.group = *(u64*)group;
sf.found = 0; sf.found = 0;
@ -86,6 +71,8 @@ ModuleFunc* get_ppu_func_by_nid(u32 nid, u32* out_index)
ModuleFunc* get_ppu_func_by_index(u32 index) ModuleFunc* get_ppu_func_by_index(u32 index)
{ {
index &= ~EIF_FLAGS;
if (index >= g_ppu_func_list.size()) if (index >= g_ppu_func_list.size())
{ {
return nullptr; return nullptr;
@ -98,26 +85,57 @@ void execute_ppu_func_by_index(PPUThread& CPU, u32 index)
{ {
if (auto func = get_ppu_func_by_index(index)) if (auto func = get_ppu_func_by_index(index))
{ {
// save RTOC
vm::write64(vm::cast(CPU.GPR[1] + 0x28), CPU.GPR[2]);
auto old_last_syscall = CPU.m_last_syscall; auto old_last_syscall = CPU.m_last_syscall;
CPU.m_last_syscall = func->id; CPU.m_last_syscall = func->id;
if (func->lle_func) if (index & EIF_SAVE_RTOC)
{ {
// save RTOC if necessary
vm::write64(vm::cast(CPU.GPR[1] + 0x28), CPU.GPR[2]);
}
if (func->lle_func && !(func->flags & MFF_FORCED_HLE))
{
// call LLE function if available
if (Ini.HLELogging.GetValue())
{
LOG_NOTICE(HLE, "LLE function called: %s", SysCalls::GetHLEFuncName(func->id));
}
func->lle_func(CPU); func->lle_func(CPU);
if (Ini.HLELogging.GetValue())
{
LOG_NOTICE(HLE, "LLE function finished: %s -> 0x%llx", SysCalls::GetHLEFuncName(func->id), CPU.GPR[3]);
}
} }
else if (func->func) else if (func->func)
{ {
if (Ini.HLELogging.GetValue())
{
LOG_NOTICE(HLE, "HLE function called: %s", SysCalls::GetHLEFuncName(func->id));
}
func->func(CPU); func->func(CPU);
if (Ini.HLELogging.GetValue())
{
LOG_NOTICE(HLE, "HLE function finished: %s -> 0x%llx", SysCalls::GetHLEFuncName(func->id), CPU.GPR[3]);
}
} }
else else
{ {
LOG_ERROR(HLE, "Unimplemented function %s", SysCalls::GetHLEFuncName(func->id)); LOG_ERROR(HLE, "Unimplemented function: %s -> CELL_OK", SysCalls::GetHLEFuncName(func->id));
CPU.GPR[3] = 0; CPU.GPR[3] = 0;
} }
if (index & EIF_PERFORM_BLR)
{
// return if necessary
CPU.SetBranch(vm::cast(CPU.LR & ~3), true);
}
CPU.m_last_syscall = old_last_syscall; CPU.m_last_syscall = old_last_syscall;
} }
else else
@ -228,9 +246,7 @@ void hook_ppu_funcs(u32* base, u32 size)
{ {
LOG_NOTICE(LOADER, "Function '%s' hooked (addr=0x%x)", g_ppu_func_subs[j].name, vm::get_addr(base + i * 4)); LOG_NOTICE(LOADER, "Function '%s' hooked (addr=0x%x)", g_ppu_func_subs[j].name, vm::get_addr(base + i * 4));
g_ppu_func_subs[j].found++; g_ppu_func_subs[j].found++;
base[i + 0] = re32(0x04000000 | g_ppu_func_subs[j].index); // hack base[i] = re32(0x04000000 | g_ppu_func_subs[j].index | EIF_PERFORM_BLR); // hack
base[i + 1] = se32(0x4e800020); // blr
i += 1; // skip modified code
} }
} }
} }

View file

@ -6,15 +6,36 @@
class Module; class Module;
// flags set in ModuleFunc
enum : u32
{
MFF_FORCED_HLE = (1 << 0), // always call HLE function
};
// flags passed with index
enum : u32
{
EIF_SAVE_RTOC = (1 << 25), // save RTOC in [SP+0x28] before calling HLE/LLE function
EIF_PERFORM_BLR = (1 << 24), // do BLR after calling HLE/LLE function
EIF_FLAGS = 0x3000000, // all flags
};
struct ModuleFunc struct ModuleFunc
{ {
u32 id; u32 id;
u32 flags;
Module* module; Module* module;
ppu_func_caller func; ppu_func_caller func;
vm::ptr<void()> lle_func; vm::ptr<void()> lle_func;
ModuleFunc(u32 id, Module* module, ppu_func_caller func, vm::ptr<void()> lle_func = vm::ptr<void()>::make(0)) ModuleFunc()
{
}
ModuleFunc(u32 id, u32 flags, Module* module, ppu_func_caller func, vm::ptr<void()> lle_func = vm::ptr<void()>::make(0))
: id(id) : id(id)
, flags(flags)
, module(module) , module(module)
, func(func) , func(func)
, lle_func(lle_func) , lle_func(lle_func)
@ -121,9 +142,10 @@ u32 add_ppu_func_sub(const char group[8], const u64 ops[], const char* name, Mod
void hook_ppu_funcs(u32* base, u32 size); void hook_ppu_funcs(u32* base, u32 size);
#define REG_FUNC(module, name) add_ppu_func(ModuleFunc(get_function_id(#name), &module, bind_func(name))) #define REG_FUNC(module, name) add_ppu_func(ModuleFunc(get_function_id(#name), 0, &module, bind_func(name)))
#define REG_FUNC_FH(module, name) add_ppu_func(ModuleFunc(get_function_id(#name), MFF_FORCED_HLE, &module, bind_func(name)))
#define REG_UNNAMED(module, nid) add_ppu_func(ModuleFunc(0x##nid, &module, bind_func(_nid_##nid))) #define REG_UNNAMED(module, nid) add_ppu_func(ModuleFunc(0x##nid, 0, &module, bind_func(_nid_##nid)))
#define REG_SUB(module, group, name, ...) \ #define REG_SUB(module, group, name, ...) \
static const u64 name ## _table[] = {__VA_ARGS__ , 0}; \ static const u64 name ## _table[] = {__VA_ARGS__ , 0}; \

View file

@ -1081,7 +1081,7 @@ s32 syncLFQueueGetPushPointer(vm::ptr<CellSyncLFQueue> queue, s32& pointer, u32
s32 _cellSyncLFQueueGetPushPointer(vm::ptr<CellSyncLFQueue> queue, vm::ptr<u32> pointer, u32 isBlocking, u32 useEventQueue) s32 _cellSyncLFQueueGetPushPointer(vm::ptr<CellSyncLFQueue> queue, vm::ptr<u32> pointer, u32 isBlocking, u32 useEventQueue)
{ {
cellSync.Todo("_cellSyncLFQueueGetPushPointer(queue_addr=0x%x, pointer_addr=0x%x, isBlocking=%d, useEventQueue=%d)", cellSync.Warning("_cellSyncLFQueueGetPushPointer(queue_addr=0x%x, pointer_addr=0x%x, isBlocking=%d, useEventQueue=%d)",
queue.addr(), pointer.addr(), isBlocking, useEventQueue); queue.addr(), pointer.addr(), isBlocking, useEventQueue);
s32 pointer_value; s32 pointer_value;
@ -1243,7 +1243,7 @@ s32 syncLFQueueCompletePushPointer(vm::ptr<CellSyncLFQueue> queue, s32 pointer,
s32 _cellSyncLFQueueCompletePushPointer(vm::ptr<CellSyncLFQueue> queue, s32 pointer, vm::ptr<s32(u32 addr, u32 arg)> fpSendSignal) s32 _cellSyncLFQueueCompletePushPointer(vm::ptr<CellSyncLFQueue> queue, s32 pointer, vm::ptr<s32(u32 addr, u32 arg)> fpSendSignal)
{ {
cellSync.Todo("_cellSyncLFQueueCompletePushPointer(queue_addr=0x%x, pointer=%d, fpSendSignal_addr=0x%x)", cellSync.Warning("_cellSyncLFQueueCompletePushPointer(queue_addr=0x%x, pointer=%d, fpSendSignal_addr=0x%x)",
queue.addr(), pointer, fpSendSignal.addr()); queue.addr(), pointer, fpSendSignal.addr());
return syncLFQueueCompletePushPointer(queue, pointer, fpSendSignal); return syncLFQueueCompletePushPointer(queue, pointer, fpSendSignal);
@ -1432,7 +1432,7 @@ s32 syncLFQueueGetPopPointer(vm::ptr<CellSyncLFQueue> queue, s32& pointer, u32 i
s32 _cellSyncLFQueueGetPopPointer(vm::ptr<CellSyncLFQueue> queue, vm::ptr<u32> pointer, u32 isBlocking, u32 arg4, u32 useEventQueue) s32 _cellSyncLFQueueGetPopPointer(vm::ptr<CellSyncLFQueue> queue, vm::ptr<u32> pointer, u32 isBlocking, u32 arg4, u32 useEventQueue)
{ {
cellSync.Todo("_cellSyncLFQueueGetPopPointer(queue_addr=0x%x, pointer_addr=0x%x, isBlocking=%d, arg4=%d, useEventQueue=%d)", cellSync.Warning("_cellSyncLFQueueGetPopPointer(queue_addr=0x%x, pointer_addr=0x%x, isBlocking=%d, arg4=%d, useEventQueue=%d)",
queue.addr(), pointer.addr(), isBlocking, arg4, useEventQueue); queue.addr(), pointer.addr(), isBlocking, arg4, useEventQueue);
s32 pointer_value; s32 pointer_value;
@ -1594,7 +1594,7 @@ s32 syncLFQueueCompletePopPointer(vm::ptr<CellSyncLFQueue> queue, s32 pointer, c
s32 _cellSyncLFQueueCompletePopPointer(vm::ptr<CellSyncLFQueue> queue, s32 pointer, vm::ptr<s32(u32 addr, u32 arg)> fpSendSignal, u32 noQueueFull) s32 _cellSyncLFQueueCompletePopPointer(vm::ptr<CellSyncLFQueue> queue, s32 pointer, vm::ptr<s32(u32 addr, u32 arg)> fpSendSignal, u32 noQueueFull)
{ {
// arguments copied from _cellSyncLFQueueCompletePushPointer + unknown argument (noQueueFull taken from LFQueue2CompletePopPointer) // arguments copied from _cellSyncLFQueueCompletePushPointer + unknown argument (noQueueFull taken from LFQueue2CompletePopPointer)
cellSync.Todo("_cellSyncLFQueueCompletePopPointer(queue_addr=0x%x, pointer=%d, fpSendSignal_addr=0x%x, noQueueFull=%d)", cellSync.Warning("_cellSyncLFQueueCompletePopPointer(queue_addr=0x%x, pointer=%d, fpSendSignal_addr=0x%x, noQueueFull=%d)",
queue.addr(), pointer, fpSendSignal.addr(), noQueueFull); queue.addr(), pointer, fpSendSignal.addr(), noQueueFull);
return syncLFQueueCompletePopPointer(queue, pointer, fpSendSignal, noQueueFull); return syncLFQueueCompletePopPointer(queue, pointer, fpSendSignal, noQueueFull);

View file

@ -504,7 +504,7 @@ s32 sys_net_free_thread_context()
} }
// define additional macro for specific namespace // define additional macro for specific namespace
#define REG_FUNC_(name) add_ppu_func(ModuleFunc(get_function_id(#name), &sys_net, bind_func(sys_net_func::name))) #define REG_FUNC_(name) add_ppu_func(ModuleFunc(get_function_id(#name), 0, &sys_net, bind_func(sys_net_func::name)))
Module sys_net("sys_net", []() Module sys_net("sys_net", []()
{ {

View file

@ -5,7 +5,7 @@ typedef void(*ppu_func_caller)(PPUThread&);
namespace ppu_func_detail namespace ppu_func_detail
{ {
enum bind_arg_type enum arg_class : u8
{ {
ARG_GENERAL, ARG_GENERAL,
ARG_FLOAT, ARG_FLOAT,
@ -13,50 +13,50 @@ namespace ppu_func_detail
ARG_STACK, ARG_STACK,
}; };
template<typename T, bind_arg_type type, int g_count, int f_count, int v_count> template<typename T, arg_class type, u8 g_count, u8 f_count, u8 v_count>
struct bind_arg; struct bind_arg;
template<typename T, int g_count, int f_count, int v_count> template<typename T, u8 g_count, u8 f_count, u8 v_count>
struct bind_arg<T, ARG_GENERAL, g_count, f_count, v_count> struct bind_arg<T, ARG_GENERAL, g_count, f_count, v_count>
{ {
static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_GENERAL"); static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_GENERAL");
static __forceinline T func(PPUThread& CPU) static __forceinline T get_arg(PPUThread& CPU)
{ {
return cast_from_ppu_gpr<T>(CPU.GPR[g_count + 2]); return cast_from_ppu_gpr<T>(CPU.GPR[g_count + 2]);
} }
}; };
template<typename T, int g_count, int f_count, int v_count> template<typename T, u8 g_count, u8 f_count, u8 v_count>
struct bind_arg<T, ARG_FLOAT, g_count, f_count, v_count> struct bind_arg<T, ARG_FLOAT, g_count, f_count, v_count>
{ {
static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_FLOAT"); static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_FLOAT");
static __forceinline T func(PPUThread& CPU) static __forceinline T get_arg(PPUThread& CPU)
{ {
return static_cast<T>(CPU.FPR[f_count]); return static_cast<T>(CPU.FPR[f_count]);
} }
}; };
template<typename T, int g_count, int f_count, int v_count> template<typename T, u8 g_count, u8 f_count, u8 v_count>
struct bind_arg<T, ARG_VECTOR, g_count, f_count, v_count> struct bind_arg<T, ARG_VECTOR, g_count, f_count, v_count>
{ {
static_assert(std::is_same<T, u128>::value, "Invalid function argument type for ARG_VECTOR"); static_assert(std::is_same<T, u128>::value, "Invalid function argument type for ARG_VECTOR");
static __forceinline T func(PPUThread& CPU) static __forceinline T get_arg(PPUThread& CPU)
{ {
return CPU.VPR[v_count + 1]; return CPU.VPR[v_count + 1];
} }
}; };
template<typename T, int g_count, int f_count, int v_count> template<typename T, u8 g_count, u8 f_count, u8 v_count>
struct bind_arg<T, ARG_STACK, g_count, f_count, 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(f_count <= 13, "TODO: Unsupported stack argument type (float)");
static_assert(v_count <= 12, "TODO: Unsupported stack argument type (vector)"); 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(sizeof(T) <= 8, "Invalid function argument type for ARG_STACK");
static __forceinline T func(PPUThread& CPU) static __forceinline T get_arg(PPUThread& CPU)
{ {
// TODO: check stack argument displacement // 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)); const u64 res = CPU.GetStackArg(8 + std::max(g_count - 8, 0) + std::max(f_count - 13, 0) + std::max(v_count - 12, 0));
@ -64,13 +64,13 @@ namespace ppu_func_detail
} }
}; };
template<typename T, bind_arg_type type> template<typename T, arg_class type>
struct bind_result struct bind_result
{ {
static_assert(type == ARG_GENERAL, "Wrong use of bind_result template"); static_assert(type == ARG_GENERAL, "Wrong use of bind_result template");
static_assert(sizeof(T) <= 8, "Invalid function result type for ARG_GENERAL"); static_assert(sizeof(T) <= 8, "Invalid function result type for ARG_GENERAL");
static __forceinline void func(PPUThread& CPU, const T& result) static __forceinline void put_result(PPUThread& CPU, const T& result)
{ {
CPU.GPR[3] = cast_to_ppu_gpr<T>(result); CPU.GPR[3] = cast_to_ppu_gpr<T>(result);
} }
@ -81,7 +81,7 @@ namespace ppu_func_detail
{ {
static_assert(sizeof(T) <= 8, "Invalid function result type for ARG_FLOAT"); static_assert(sizeof(T) <= 8, "Invalid function result type for ARG_FLOAT");
static __forceinline void func(PPUThread& CPU, const T& result) static __forceinline void put_result(PPUThread& CPU, const T& result)
{ {
CPU.FPR[1] = static_cast<T>(result); CPU.FPR[1] = static_cast<T>(result);
} }
@ -92,12 +92,29 @@ namespace ppu_func_detail
{ {
static_assert(std::is_same<T, u128>::value, "Invalid function result type for ARG_VECTOR"); static_assert(std::is_same<T, u128>::value, "Invalid function result type for ARG_VECTOR");
static __forceinline void func(PPUThread& CPU, const T& result) static __forceinline void put_result(PPUThread& CPU, const T& result)
{ {
CPU.VPR[2] = result; CPU.VPR[2] = result;
} }
}; };
struct arg_type_pack
{
arg_class type;
u8 g_count;
u8 f_count;
u8 v_count;
};
template<typename T, u32 type_pack>
struct bind_arg_packed
{
static __forceinline T get_arg(PPUThread& CPU)
{
return bind_arg<T, type_pack, (type_pack >> 8), (type_pack >> 16), (type_pack >> 24)>::get_arg(CPU);
}
};
template <typename RT, typename F, typename Tuple, bool Done, int Total, int... N> template <typename RT, typename F, typename Tuple, bool Done, int Total, int... N>
struct call_impl struct call_impl
{ {
@ -123,14 +140,14 @@ namespace ppu_func_detail
return ppu_func_detail::call_impl<RT, F, Tuple, 0 == std::tuple_size<ttype>::value, std::tuple_size<ttype>::value>::call(f, std::forward<Tuple>(t)); return ppu_func_detail::call_impl<RT, F, Tuple, 0 == std::tuple_size<ttype>::value, std::tuple_size<ttype>::value>::call(f, std::forward<Tuple>(t));
} }
template<int g_count, int f_count, int v_count> template<u32 g_count, u32 f_count, u32 v_count>
__forceinline std::tuple<> iterate(PPUThread& CPU) __forceinline std::tuple<> iterate(PPUThread& CPU)
{ {
// terminator // terminator
return std::tuple<>(); return std::tuple<>();
} }
template<int g_count, int f_count, int v_count, typename T, typename... A> template<u32 g_count, u32 f_count, u32 v_count, typename T, typename... A>
__forceinline std::tuple<T, A...> iterate(PPUThread& CPU) __forceinline std::tuple<T, A...> iterate(PPUThread& CPU)
{ {
static_assert(!std::is_pointer<T>::value, "Invalid function argument type (pointer)"); static_assert(!std::is_pointer<T>::value, "Invalid function argument type (pointer)");
@ -138,14 +155,14 @@ namespace ppu_func_detail
// TODO: check calculations // TODO: check calculations
const bool is_float = std::is_floating_point<T>::value; const bool is_float = std::is_floating_point<T>::value;
const bool is_vector = std::is_same<T, u128>::value; const bool is_vector = std::is_same<T, u128>::value;
const bind_arg_type t = is_float const arg_class t = is_float
? ((f_count >= 13) ? ARG_STACK : ARG_FLOAT) ? ((f_count >= 13) ? ARG_STACK : ARG_FLOAT)
: (is_vector ? ((v_count >= 12) ? ARG_STACK : ARG_VECTOR) : ((g_count >= 8) ? ARG_STACK : ARG_GENERAL)); : (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 u32 g = g_count + (is_float || is_vector ? 0 : 1);
const int f = f_count + (is_float ? 1 : 0); const u32 f = f_count + (is_float ? 1 : 0);
const int v = v_count + (is_vector ? 1 : 0); const u32 v = v_count + (is_vector ? 1 : 0);
return std::tuple_cat(std::tuple<T>(bind_arg<T, t, g, f, v>::func(CPU)), iterate<g, f, v, A...>(CPU)); return std::tuple_cat(std::tuple<T>(bind_arg<T, t, g, f, v>::get_arg(CPU)), iterate<g, f, v, A...>(CPU));
} }
template<typename RT> template<typename RT>
@ -155,7 +172,7 @@ namespace ppu_func_detail
static_assert(!std::is_reference<RT>::value, "Invalid function result type (reference)"); 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_float = std::is_floating_point<RT>::value;
static const bool is_vector = std::is_same<RT, u128>::value; static const bool is_vector = std::is_same<RT, u128>::value;
static const bind_arg_type value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL); static const arg_class value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL);
}; };
template<typename RT, typename... T> template<typename RT, typename... T>
@ -166,9 +183,9 @@ namespace ppu_func_detail
{ {
typedef void(*func_t)(PPUThread&, T...); typedef void(*func_t)(PPUThread&, T...);
static void do_call(PPUThread& CPU, func_t _func) static void do_call(PPUThread& CPU, func_t func)
{ {
call<void>(_func, std::tuple_cat(std::tuple<PPUThread&>(CPU), iterate<0, 0, 0, T...>(CPU))); call<void>(func, std::tuple_cat(std::tuple<PPUThread&>(CPU), iterate<0, 0, 0, T...>(CPU)));
} }
}; };
@ -177,9 +194,9 @@ namespace ppu_func_detail
{ {
typedef void(*func_t)(T...); typedef void(*func_t)(T...);
static void do_call(PPUThread& CPU, func_t _func) static void do_call(PPUThread& CPU, func_t func)
{ {
call<void>(_func, iterate<0, 0, 0, T...>(CPU)); call<void>(func, iterate<0, 0, 0, T...>(CPU));
} }
}; };
@ -188,9 +205,9 @@ namespace ppu_func_detail
{ {
typedef RT(*func_t)(PPUThread&, T...); typedef RT(*func_t)(PPUThread&, T...);
static void do_call(PPUThread& CPU, func_t _func) static void do_call(PPUThread& CPU, func_t func)
{ {
bind_result<RT, result_type<RT>::value>::func(CPU, call<RT>(_func, std::tuple_cat(std::tuple<PPUThread&>(CPU), iterate<0, 0, 0, T...>(CPU)))); bind_result<RT, result_type<RT>::value>::put_result(CPU, call<RT>(func, std::tuple_cat(std::tuple<PPUThread&>(CPU), iterate<0, 0, 0, T...>(CPU))));
} }
}; };
@ -199,9 +216,9 @@ namespace ppu_func_detail
{ {
typedef RT(*func_t)(T...); typedef RT(*func_t)(T...);
static void do_call(PPUThread& CPU, func_t _func) static void do_call(PPUThread& CPU, func_t func)
{ {
bind_result<RT, result_type<RT>::value>::func(CPU, call<RT>(_func, iterate<0, 0, 0, T...>(CPU))); bind_result<RT, result_type<RT>::value>::put_result(CPU, call<RT>(func, iterate<0, 0, 0, T...>(CPU)));
} }
}; };
} }

View file

@ -921,23 +921,37 @@ void null_func(PPUThread& CPU)
return; return;
} }
LOG_ERROR(HLE, "Unknown syscall: %d - %08x", code, code); LOG_ERROR(HLE, "Unknown syscall: %d - %08x -> CELL_OK", code, code);
CPU.GPR[3] = 0; CPU.GPR[3] = 0;
return; return;
} }
void SysCalls::DoSyscall(PPUThread& CPU, u32 code) void SysCalls::DoSyscall(PPUThread& CPU, u64 code)
{ {
auto old_last_syscall = CPU.m_last_syscall;
CPU.m_last_syscall = code;
if (code >= 1024)
{
throw "Invalid syscall number";
}
//Auto Pause using simple singleton. //Auto Pause using simple singleton.
Debug::AutoPause::getInstance().TryPause(code); Debug::AutoPause::getInstance().TryPause(code);
if(code < 1024) if (Ini.HLELogging.GetValue())
{ {
sc_table[code](CPU); LOG_NOTICE(PPU, "SysCall called: %s [0x%llx]", "unknown", code);
return;
} }
throw "Invalid syscall number"; sc_table[code](CPU);
if (Ini.HLELogging.GetValue())
{
LOG_NOTICE(PPU, "SysCall finished: %s [0x%llx] -> 0x%llx", "unknown", code, CPU.GPR[3]);
}
CPU.m_last_syscall = old_last_syscall;
} }
IdManager& SysCallBase::GetIdManager() const IdManager& SysCallBase::GetIdManager() const

View file

@ -66,6 +66,6 @@ class PPUThread;
class SysCalls class SysCalls
{ {
public: public:
static void DoSyscall(PPUThread& CPU, u32 code); static void DoSyscall(PPUThread& CPU, u64 code);
static std::string GetHLEFuncName(const u32 fid); static std::string GetHLEFuncName(const u32 fid);
}; };

View file

@ -245,16 +245,11 @@ namespace loader
{ {
LOG_ERROR(LOADER, "Unknown function 0x%08x (addr=0x%x)", nid, addr); LOG_ERROR(LOADER, "Unknown function 0x%08x (addr=0x%x)", nid, addr);
psv_func unimplemented; // TODO: set correct name if possible
unimplemented.nid = nid; index = add_psv_func(psv_func(nid, 0, nullptr, "UNKNOWN", nullptr));
unimplemented.module = nullptr;
unimplemented.name = "UNKNOWN"; // TODO: set correct name if possible
unimplemented.func = nullptr;
index = add_psv_func(unimplemented);
} }
vm::psv::write32(addr + 0, 0xe0700090 | (index & 0xfff0) << 4 | (index & 0xf)); // HACK instruction (ARM) vm::psv::write32(addr, 0xe0700090 | (index & 0xfff0) << 4 | (index & 0xf)); // HACK instruction (ARM)
code_end = std::min<u32>(addr, code_end); code_end = std::min<u32>(addr, code_end);
} }

View file

@ -274,8 +274,26 @@ namespace loader
} }
} }
assert(e.second != stub);
e.second = stub; e.second = stub;
} }
for (auto &i : m.second.imports)
{
u32 stub = i.second;
for (auto &s : info.segments)
{
if (stub >= s.initial_addr.addr() && stub < s.initial_addr.addr() + s.size_file)
{
stub += s.begin.addr() - s.initial_addr.addr();
break;
}
}
assert(i.second != stub);
i.second = stub;
}
} }
return ok; return ok;
@ -398,13 +416,41 @@ namespace loader
for (auto& f : m.second.exports) for (auto& f : m.second.exports)
{ {
add_ppu_func(ModuleFunc(f.first, module, nullptr, vm::ptr<void()>::make(f.second))); const u32 nid = f.first;
const u32 addr = f.second;
u32 index;
auto func = get_ppu_func_by_nid(nid, &index);
if (!func)
{
index = add_ppu_func(ModuleFunc(nid, 0, module, nullptr, vm::ptr<void()>::make(addr)));
}
else
{
func->lle_func.set(addr);
if (func->flags & MFF_FORCED_HLE)
{
u32 i_addr = 0;
if (!vm::check_addr(addr, 8) || !vm::check_addr(i_addr = vm::read32(addr), 4))
{
LOG_ERROR(LOADER, "Failed to inject code for exported function '%s' (opd=0x%x, 0x%x)", SysCalls::GetHLEFuncName(nid), addr, i_addr);
}
else
{
vm::write32(i_addr, HACK(index | EIF_PERFORM_BLR));
}
}
}
} }
for (auto& f : m.second.imports) for (auto& f : m.second.imports)
{ {
const u32 nid = f.first; const u32 nid = f.first;
const u32 addr = f.second + info.segments[0].begin.addr(); const u32 addr = f.second;
u32 index; u32 index;
@ -414,21 +460,20 @@ namespace loader
{ {
LOG_ERROR(LOADER, "Unimplemented function '%s' (0x%x)", SysCalls::GetHLEFuncName(nid), addr); LOG_ERROR(LOADER, "Unimplemented function '%s' (0x%x)", SysCalls::GetHLEFuncName(nid), addr);
index = add_ppu_func(ModuleFunc(nid, module, nullptr)); index = add_ppu_func(ModuleFunc(nid, 0, module, nullptr));
} }
else else
{ {
LOG_NOTICE(LOADER, "Imported function '%s' (0x%x)", SysCalls::GetHLEFuncName(nid), addr); LOG_NOTICE(LOADER, "Imported function '%s' (0x%x)", SysCalls::GetHLEFuncName(nid), addr);
} }
if (!vm::check_addr(addr, 8)) if (!vm::check_addr(addr, 4))
{ {
LOG_ERROR(LOADER, "Failed to inject code for function '%s' (0x%x)", SysCalls::GetHLEFuncName(nid), addr); LOG_ERROR(LOADER, "Failed to inject code for function '%s' (0x%x)", SysCalls::GetHLEFuncName(nid), addr);
} }
else else
{ {
vm::write32(addr + 0, HACK(index)); vm::write32(addr, HACK(index | EIF_SAVE_RTOC | EIF_PERFORM_BLR));
vm::write32(addr + 4, BLR());
} }
} }
} }
@ -635,15 +680,16 @@ namespace loader
{ {
LOG_ERROR(LOADER, "Unimplemented function '%s' in '%s' module (0x%x)", SysCalls::GetHLEFuncName(nid), module_name, addr); LOG_ERROR(LOADER, "Unimplemented function '%s' in '%s' module (0x%x)", SysCalls::GetHLEFuncName(nid), module_name, addr);
index = add_ppu_func(ModuleFunc(nid, module, nullptr)); index = add_ppu_func(ModuleFunc(nid, 0, module, nullptr));
} }
else else
{ {
LOG_NOTICE(LOADER, "Imported %sfunction '%s' in '%s' module (0x%x)", func->lle_func ? "LLE " : "", SysCalls::GetHLEFuncName(nid), module_name, addr); const bool is_lle = func->lle_func && !(func->flags & MFF_FORCED_HLE);
LOG_NOTICE(LOADER, "Imported %sfunction '%s' in '%s' module (0x%x)", is_lle ? "LLE " : "", SysCalls::GetHLEFuncName(nid), module_name, addr);
} }
vm::write32(addr + 0, HACK(index)); vm::write32(addr, HACK(index | EIF_SAVE_RTOC | EIF_PERFORM_BLR));
vm::write32(addr + 4, BLR());
//if (!func || !func->lle_func) //if (!func || !func->lle_func)
//{ //{