HLE: Variable Argument Lists support
This commit is contained in:
parent
4b53093acb
commit
e9dd0072de
|
@ -343,6 +343,7 @@
|
|||
<ClInclude Include="HLE\HLE.h" />
|
||||
<ClInclude Include="HLE\HLE_Misc.h" />
|
||||
<ClInclude Include="HLE\HLE_OS.h" />
|
||||
<ClInclude Include="HLE\HLE_VarArgs.h" />
|
||||
<ClInclude Include="Host.h" />
|
||||
<ClInclude Include="HotkeyManager.h" />
|
||||
<ClInclude Include="HW\AudioInterface.h" />
|
||||
|
|
|
@ -955,6 +955,9 @@
|
|||
<ClInclude Include="HLE\HLE_OS.h">
|
||||
<Filter>HLE</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HLE\HLE_VarArgs.h">
|
||||
<Filter>HLE</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PowerPC\CachedInterpreter\CachedInterpreter.h">
|
||||
<Filter>PowerPC\Cached Interpreter</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "Common/MsgHandler.h"
|
||||
#include "Common/StringUtil.h"
|
||||
#include "Core/HLE/HLE_OS.h"
|
||||
#include "Core/HLE/HLE_VarArgs.h"
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
|
||||
|
@ -89,14 +90,12 @@ void HLE_write_console()
|
|||
NOTICE_LOG(OSREPORT, "%08x->%08x| %s", LR, PC, SHIFTJISToUTF8(report_message).c_str());
|
||||
}
|
||||
|
||||
std::string GetStringVA(u32 strReg)
|
||||
std::string GetStringVA(u32 str_reg)
|
||||
{
|
||||
std::string ArgumentBuffer;
|
||||
u32 ParameterCounter = strReg + 1;
|
||||
u32 FloatingParameterCounter = 1;
|
||||
|
||||
std::string result;
|
||||
std::string string = PowerPC::HostGetString(GPR(strReg));
|
||||
std::string string = PowerPC::HostGetString(GPR(str_reg));
|
||||
HLE::VAList ap(GPR(1) + 0x8, str_reg + 1);
|
||||
|
||||
for (size_t i = 0; i < string.size(); i++)
|
||||
{
|
||||
|
@ -120,38 +119,13 @@ std::string GetStringVA(u32 strReg)
|
|||
|
||||
ArgumentBuffer += string[i];
|
||||
|
||||
u64 Parameter;
|
||||
if (ParameterCounter > 10)
|
||||
{
|
||||
Parameter = PowerPC::HostRead_U32(GPR(1) + 0x8 + ((ParameterCounter - 11) * 4));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (string[i - 1] == 'l' &&
|
||||
string[i - 2] == 'l') // hax, just seen this on sysmenu osreport
|
||||
{
|
||||
Parameter = GPR(++ParameterCounter);
|
||||
Parameter = (Parameter << 32) | GPR(++ParameterCounter);
|
||||
}
|
||||
else // normal, 32bit
|
||||
Parameter = GPR(ParameterCounter);
|
||||
}
|
||||
ParameterCounter++;
|
||||
|
||||
switch (string[i])
|
||||
{
|
||||
case 's':
|
||||
result += StringFromFormat(ArgumentBuffer.c_str(),
|
||||
PowerPC::HostGetString((u32)Parameter).c_str());
|
||||
PowerPC::HostGetString(ap.GetArgT<u32>()).c_str());
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
case 'i':
|
||||
{
|
||||
result += StringFromFormat(ArgumentBuffer.c_str(), Parameter);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'a':
|
||||
case 'A':
|
||||
case 'e':
|
||||
|
@ -160,25 +134,24 @@ std::string GetStringVA(u32 strReg)
|
|||
case 'F':
|
||||
case 'g':
|
||||
case 'G':
|
||||
{
|
||||
result += StringFromFormat(ArgumentBuffer.c_str(), rPS0(FloatingParameterCounter));
|
||||
FloatingParameterCounter++;
|
||||
ParameterCounter--;
|
||||
result += StringFromFormat(ArgumentBuffer.c_str(), ap.GetArgT<double>());
|
||||
break;
|
||||
}
|
||||
|
||||
case 'p':
|
||||
// Override, so 64bit Dolphin prints 32bit pointers, since the ppc is 32bit :)
|
||||
result += StringFromFormat("%x", (u32)Parameter);
|
||||
result += StringFromFormat("%x", ap.GetArgT<u32>());
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
PowerPC::HostWrite_U32(static_cast<u32>(result.size()), static_cast<u32>(Parameter));
|
||||
PowerPC::HostWrite_U32(static_cast<u32>(result.size()), ap.GetArgT<u32>());
|
||||
// %n doesn't output anything, so the result variable is untouched
|
||||
break;
|
||||
|
||||
default:
|
||||
result += StringFromFormat(ArgumentBuffer.c_str(), Parameter);
|
||||
if (string[i - 1] == 'l' && string[i - 2] == 'l')
|
||||
result += StringFromFormat(ArgumentBuffer.c_str(), ap.GetArgT<u64>());
|
||||
else
|
||||
result += StringFromFormat(ArgumentBuffer.c_str(), ap.GetArgT<u32>());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,138 @@
|
|||
// Copyright 2016 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common/Align.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace HLE
|
||||
{
|
||||
// See System V ABI (SVR4) for more details
|
||||
// -> 3-18 Parameter Passing
|
||||
// -> 3-21 Variable Argument Lists
|
||||
//
|
||||
// Source:
|
||||
// http://refspecs.linux-foundation.org/elf/elfspec_ppc.pdf
|
||||
class VAList
|
||||
{
|
||||
public:
|
||||
explicit VAList(u32 stack, u32 gpr = 3, u32 fpr = 1, u32 gpr_max = 10, u32 fpr_max = 8)
|
||||
: m_gpr(gpr), m_fpr(fpr), m_gpr_max(gpr_max), m_fpr_max(fpr_max), m_stack(stack)
|
||||
{
|
||||
}
|
||||
~VAList() = default;
|
||||
|
||||
// SFINAE
|
||||
template <typename T>
|
||||
constexpr bool IS_ARG_POINTER = std::is_union<T>() || std::is_class<T>();
|
||||
template <typename T>
|
||||
constexpr bool IS_WORD = std::is_pointer<T>() || (std::is_integral<T>() && sizeof(T) <= 4);
|
||||
template <typename T>
|
||||
constexpr bool IS_DOUBLE_WORD = std::is_integral<T>() && sizeof(T) == 8;
|
||||
template <typename T>
|
||||
constexpr bool IS_ARG_REAL = std::is_floating_point<T>();
|
||||
|
||||
// 0 - arg_ARGPOINTER
|
||||
template <typename T, typename std::enable_if_t<IS_ARG_POINTER<T>>* = nullptr>
|
||||
T GetArg()
|
||||
{
|
||||
T obj;
|
||||
u32 addr = GetArg<u32>();
|
||||
|
||||
for (size_t i = 0; i < sizeof(T); i += 1, addr += 1)
|
||||
{
|
||||
reinterpret_cast<u8*>(&obj)[i] = PowerPC::HostRead_U8(addr);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
// 1 - arg_WORD
|
||||
template <typename T, typename std::enable_if_t<IS_WORD<T>>* = nullptr>
|
||||
T GetArg()
|
||||
{
|
||||
static_assert(!std::is_pointer<T>(), "VAList doesn't support pointers");
|
||||
u64 value;
|
||||
|
||||
if (m_gpr <= m_gpr_max)
|
||||
{
|
||||
value = GPR(m_gpr);
|
||||
m_gpr += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_stack = Common::AlignUp(m_stack, 4);
|
||||
value = PowerPC::HostRead_U32(m_stack);
|
||||
m_stack += 4;
|
||||
}
|
||||
|
||||
return static_cast<T>(value);
|
||||
}
|
||||
|
||||
// 2 - arg_DOUBLEWORD
|
||||
template <typename T, typename std::enable_if_t<IS_DOUBLE_WORD<T>>* = nullptr>
|
||||
T GetArg()
|
||||
{
|
||||
u64 value;
|
||||
|
||||
if (m_gpr % 2 == 0)
|
||||
m_gpr += 1;
|
||||
if (m_gpr < m_gpr_max)
|
||||
{
|
||||
value = static_cast<u64>(GPR(m_gpr)) << 32 | GPR(m_gpr + 1);
|
||||
m_gpr += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_stack = Common::AlignUp(m_stack, 8);
|
||||
value = PowerPC::HostRead_U64(m_stack);
|
||||
m_stack += 8;
|
||||
}
|
||||
|
||||
return static_cast<T>(value);
|
||||
}
|
||||
|
||||
// 3 - arg_ARGREAL
|
||||
template <typename T, typename std::enable_if_t<IS_ARG_REAL<T>>* = nullptr>
|
||||
T GetArg()
|
||||
{
|
||||
double value;
|
||||
|
||||
if (m_fpr <= m_fpr_max)
|
||||
{
|
||||
value = rPS0(m_fpr);
|
||||
m_fpr += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_stack = Common::AlignUp(m_stack, 8);
|
||||
const u64 integral = PowerPC::HostRead_U64(m_stack);
|
||||
std::memcpy(&value, &integral, sizeof(double));
|
||||
m_stack += 8;
|
||||
}
|
||||
|
||||
return static_cast<T>(value);
|
||||
}
|
||||
|
||||
// Helper
|
||||
template <typename T>
|
||||
T GetArgT()
|
||||
{
|
||||
return static_cast<T>(GetArg<T>());
|
||||
}
|
||||
|
||||
private:
|
||||
u32 m_gpr = 3;
|
||||
u32 m_fpr = 1;
|
||||
const u32 m_gpr_max = 10;
|
||||
const u32 m_fpr_max = 8;
|
||||
u32 m_stack;
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue