diff --git a/.gitmodules b/.gitmodules
index fb181e64b1..6a79e8891c 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -12,3 +12,6 @@
path = llvm
url = https://github.com/llvm-mirror/llvm.git
branch = release_35
+[submodule "minidx9"]
+ path = minidx9
+ url = https://github.com/hrydgard/minidx9.git
diff --git a/.travis.yml b/.travis.yml
index 5b47d8dd7a..8fef9bddc8 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,6 +4,10 @@ compiler:
- clang
- gcc
+env:
+ global:
+ - secure: "jA29KvTCTR7q4BMzPPUBGazjJwrIWa7k4fo5ZSMlyxh2NbztZTKQYwodgDcXBoptCd1KJ9H3FXwBnNdMNVnTkvoPL9uWnN4K/3D1D20FCag1kmlBwnaVqVei5cRiZ9TOMuaxhjkdg8pcrQLTlXEEdMZf6A2OW0VgoBGDVSX9nYc="
+
branches:
only:
- master
@@ -37,6 +41,15 @@ before_script:
- cd build
- cmake ..
-script:
- - make -j 4
+addons:
+ coverity_scan:
+ project:
+ name: "DHrpcs3/rpcs3"
+ description: "PS3 emulator/debugger"
+ notification_email: raul.tambre@gmail.com
+ build_command_prepend: ""
+ build_command: "make -j 4"
+ branch_pattern: coverity_scan
+script:
+ - if [ ${COVERITY_SCAN_BRANCH} != 1 ]; then make -j 4; fi
diff --git a/README.md b/README.md
index 6b034b3ed4..b63652fffb 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,10 @@ RPCS3
=====
[](https://travis-ci.org/DHrpcs3/rpcs3)
+
+
+
An open-source PlayStation 3 emulator/debugger written in C++.
diff --git a/Utilities/BEType.h b/Utilities/BEType.h
index 768e25770c..27997618bd 100644
--- a/Utilities/BEType.h
+++ b/Utilities/BEType.h
@@ -284,15 +284,9 @@ union _CRT_ALIGN(16) u128
_u64[1] = _u64[0] = 0;
}
- std::string to_hex() const
- {
- return fmt::Format("%016llx%016llx", _u64[1], _u64[0]);
- }
+ std::string to_hex() const;
- std::string to_xyzw() const
- {
- return fmt::Format("x: %g y: %g z: %g w: %g", _f[3], _f[2], _f[1], _f[0]);
- }
+ std::string to_xyzw() const;
static __forceinline u128 byteswap(const u128 val)
{
@@ -378,65 +372,97 @@ template struct se_t;
template struct se_t
{
- static __forceinline T func(const T src)
+ static __forceinline u8 to_be(const T& src)
{
- return src;
+ return (u8&)src;
+ }
+
+ static __forceinline T from_be(const u8 src)
+ {
+ return (T&)src;
}
};
template struct se_t
{
- static __forceinline T func(const T src)
+ static __forceinline u16 to_be(const T& src)
{
- const u16 res = _byteswap_ushort((u16&)src);
+ return _byteswap_ushort((u16&)src);
+ }
+
+ static __forceinline T from_be(const u16 src)
+ {
+ const u16 res = _byteswap_ushort(src);
return (T&)res;
}
};
template struct se_t
{
- static __forceinline T func(const T src)
+ static __forceinline u32 to_be(const T& src)
{
- const u32 res = _byteswap_ulong((u32&)src);
+ return _byteswap_ulong((u32&)src);
+ }
+
+ static __forceinline T from_be(const u32 src)
+ {
+ const u32 res = _byteswap_ulong(src);
return (T&)res;
}
};
template struct se_t
{
- static __forceinline T func(const T src)
+ static __forceinline u64 to_be(const T& src)
{
- const u64 res = _byteswap_uint64((u64&)src);
+ return _byteswap_uint64((u64&)src);
+ }
+
+ static __forceinline T from_be(const u64 src)
+ {
+ const u64 res = _byteswap_uint64(src);
return (T&)res;
}
};
-//template T re(const T val) { T res; se_t::func(res, val); return res; }
-//template void re(T1& dst, const T2 val) { se_t::func(dst, val); }
-
-template struct const_se_t;
-template struct const_se_t
+template struct se_t
{
- static const T value = (T)_value;
+ static __forceinline u128 to_be(const T& src)
+ {
+ return u128::byteswap((u128&)src);
+ }
+
+ static __forceinline T from_be(const u128& src)
+ {
+ const u128 res = u128::byteswap(src);
+ return (T&)res;
+ }
};
-template struct const_se_t
+template struct const_se_t;
+
+template struct const_se_t
{
- static const T value = ((_value >> 8) & 0xff) | ((_value << 8) & 0xff00);
+ static const u8 value = _value;
};
-template struct const_se_t
+template struct const_se_t
{
- static const T value =
+ static const u16 value = ((_value >> 8) & 0xff) | ((_value << 8) & 0xff00);
+};
+
+template struct const_se_t
+{
+ static const u32 value =
((_value >> 24) & 0x000000ff) |
((_value >> 8) & 0x0000ff00) |
((_value << 8) & 0x00ff0000) |
((_value << 24) & 0xff000000);
};
-template struct const_se_t
+template struct const_se_t
{
- static const T value =
+ static const u64 value =
((_value >> 56) & 0x00000000000000ff) |
((_value >> 40) & 0x000000000000ff00) |
((_value >> 24) & 0x0000000000ff0000) |
@@ -447,17 +473,53 @@ template struct const_se_t
((_value << 56) & 0xff00000000000000);
};
+template
+struct be_storage_t
+{
+ static_assert(!size, "Bad be_storage_t type");
+};
+
+template
+struct be_storage_t
+{
+ typedef u8 type;
+};
+
+template
+struct be_storage_t
+{
+ typedef u16 type;
+};
+
+template
+struct be_storage_t
+{
+ typedef u32 type;
+};
+
+template
+struct be_storage_t
+{
+ typedef u64 type;
+};
+
+template
+struct be_storage_t
+{
+ typedef u128 type;
+};
+
+#define IS_LE_MACHINE
+
template
class be_t
{
- static_assert(sizeof(T2) == 1 || sizeof(T2) == 2 || sizeof(T2) == 4 || sizeof(T2) == 8, "Bad be_t type");
-
public:
typedef typename std::remove_cv::type type;
- static const bool is_le_machine = true;
+ typedef typename be_storage_t::type stype;
private:
- type m_data;
+ stype m_data;
template
struct _convert
@@ -489,63 +551,68 @@ private:
}
};
-public:
- const type& ToBE() const
+ const stype& ToBE() const
{
return m_data;
}
type ToLE() const
{
- return se_t::func(m_data);
+ return se_t::from_be(m_data);
}
- void FromBE(const type& value)
+ void FromBE(const stype& value)
{
m_data = value;
}
void FromLE(const type& value)
{
- m_data = se_t::func(value);
+ m_data = se_t::to_be(value);
}
- static be_t MakeFromLE(const type value)
+public:
+ static be_t MakeFromLE(const type& value)
{
- type data = se_t::func(value);
+ stype data = se_t::to_be(value);
return (be_t&)data;
}
- static be_t MakeFromBE(const type value)
+ static be_t MakeFromBE(const stype& value)
{
return (be_t&)value;
}
//make be_t from current machine byte ordering
- static be_t make(const type value)
+ static be_t make(const type& value)
{
- return is_le_machine ? MakeFromLE(value) : MakeFromBE(value);
+#ifdef IS_LE_MACHINE
+ return MakeFromLE(value);
+#else
+ return MakeFromBE(value);
+#endif
}
//get value in current machine byte ordering
__forceinline type value() const
{
- return is_le_machine ? ToLE() : ToBE();
+#ifdef IS_LE_MACHINE
+ return ToLE();
+#else
+ return ToBE();
+#endif
}
- //be_t() = default;
- //be_t(const be_t& value) = default;
-
- //be_t(type value)
- //{
- // m_data = se_t::func(value);
- //}
+ const stype& data() const
+ {
+ return ToBE();
+ }
be_t& operator = (const be_t& value) = default;
- be_t& operator = (type value)
+ be_t& operator = (const type& value)
{
- m_data = se_t::func(value);
+ m_data = se_t::to_be(value);
return *this;
}
@@ -691,86 +758,86 @@ template struct _se, T1, value> : pub
#define se32(x) _se::value
#define se64(x) _se::value
-template __forceinline static u8 Read8(T& f)
+template __forceinline u8 Read8(T& f)
{
u8 ret;
f.Read(&ret, sizeof(ret));
return ret;
}
-template __forceinline static u16 Read16(T& f)
+template __forceinline u16 Read16(T& f)
{
be_t ret;
f.Read(&ret, sizeof(ret));
return ret;
}
-template __forceinline static u32 Read32(T& f)
+template __forceinline u32 Read32(T& f)
{
be_t ret;
f.Read(&ret, sizeof(ret));
return ret;
}
-template __forceinline static u64 Read64(T& f)
+template __forceinline u64 Read64(T& f)
{
be_t ret;
f.Read(&ret, sizeof(ret));
return ret;
}
-template __forceinline static u16 Read16LE(T& f)
+template __forceinline u16 Read16LE(T& f)
{
u16 ret;
f.Read(&ret, sizeof(ret));
return ret;
}
-template __forceinline static u32 Read32LE(T& f)
+template __forceinline u32 Read32LE(T& f)
{
u32 ret;
f.Read(&ret, sizeof(ret));
return ret;
}
-template __forceinline static u64 Read64LE(T& f)
+template __forceinline u64 Read64LE(T& f)
{
u64 ret;
f.Read(&ret, sizeof(ret));
return ret;
}
-template __forceinline static void Write8(T& f, const u8 data)
+template __forceinline void Write8(T& f, const u8 data)
{
f.Write(&data, sizeof(data));
}
-template __forceinline static void Write16LE(T& f, const u16 data)
+template __forceinline void Write16LE(T& f, const u16 data)
{
f.Write(&data, sizeof(data));
}
-template __forceinline static void Write32LE(T& f, const u32 data)
+template __forceinline void Write32LE(T& f, const u32 data)
{
f.Write(&data, sizeof(data));
}
-template __forceinline static void Write64LE(T& f, const u64 data)
+template __forceinline void Write64LE(T& f, const u64 data)
{
f.Write(&data, sizeof(data));
}
-template __forceinline static void Write16(T& f, const u16 data)
+template __forceinline void Write16(T& f, const u16 data)
{
Write16LE(f, re16(data));
}
-template __forceinline static void Write32(T& f, const u32 data)
+template __forceinline void Write32(T& f, const u32 data)
{
Write32LE(f, re32(data));
}
-template __forceinline static void Write64(T& f, const u64 data)
+template __forceinline void Write64(T& f, const u64 data)
{
Write64LE(f, re64(data));
}
@@ -821,4 +888,4 @@ template
__forceinline void convert_le_be(Tto& dst, Tfrom&& src)
{
dst = convert_le_be_t::func(src);
-}
\ No newline at end of file
+}
diff --git a/Utilities/GNU.h b/Utilities/GNU.h
index 91fc34ae50..b1988b4dfa 100644
--- a/Utilities/GNU.h
+++ b/Utilities/GNU.h
@@ -289,9 +289,7 @@ static __forceinline uint64_t InterlockedXor(volatile uint64_t* dest, uint64_t v
static __forceinline uint32_t cntlz32(uint32_t arg)
{
-#if defined(__GNUG__)
- return __builtin_clzl(arg);
-#else
+#if defined(_MSC_VER)
unsigned long res;
if (!_BitScanReverse(&res, arg))
{
@@ -301,14 +299,21 @@ static __forceinline uint32_t cntlz32(uint32_t arg)
{
return res ^ 31;
}
+#else
+ if (arg)
+ {
+ return __builtin_clzll((uint64_t)arg) - 32;
+ }
+ else
+ {
+ return 32;
+ }
#endif
}
static __forceinline uint64_t cntlz64(uint64_t arg)
{
-#if defined(__GNUG__)
- return __builtin_clzll(arg);
-#else
+#if defined(_MSC_VER)
unsigned long res;
if (!_BitScanReverse64(&res, arg))
{
@@ -318,6 +323,15 @@ static __forceinline uint64_t cntlz64(uint64_t arg)
{
return res ^ 63;
}
+#else
+ if (arg)
+ {
+ return __builtin_clzll(arg);
+ }
+ else
+ {
+ return 64;
+ }
#endif
}
diff --git a/Utilities/Log.cpp b/Utilities/Log.cpp
index 562be95d8a..44ed7dedf7 100644
--- a/Utilities/Log.cpp
+++ b/Utilities/Log.cpp
@@ -235,3 +235,17 @@ LogChannel &LogManager::getChannel(LogType type)
{
return mChannels[static_cast(type)];
}
+
+void log_message(Log::LogType type, Log::LogSeverity sev, const char* text)
+{
+ log_message(type, sev, std::string(text));
+}
+
+void log_message(Log::LogType type, Log::LogSeverity sev, std::string text)
+{
+ //another msvc bug makes this not work, uncomment this and delete everything else in this function when it's fixed
+ //Log::LogManager::getInstance().log({logType, severity, text})
+
+ Log::LogMessage msg{ type, sev, std::move(text) };
+ Log::LogManager::getInstance().log(msg);
+}
diff --git a/Utilities/Log.h b/Utilities/Log.h
index c40d2a82c6..d1710f05cf 100644
--- a/Utilities/Log.h
+++ b/Utilities/Log.h
@@ -126,18 +126,11 @@ static struct { inline operator Log::LogType() { return Log::LogType::SPU; } } S
static struct { inline operator Log::LogType() { return Log::LogType::ARMv7; } } ARMv7;
static struct { inline operator Log::LogType() { return Log::LogType::TTY; } } TTY;
-inline void log_message(Log::LogType type, Log::LogSeverity sev, const char* text)
-{
- //another msvc bug makes this not work, uncomment this and delete everything else in this function when it's fixed
- //Log::LogManager::getInstance().log({logType, severity, text})
+void log_message(Log::LogType type, Log::LogSeverity sev, const char* text);
+void log_message(Log::LogType type, Log::LogSeverity sev, std::string text);
- Log::LogMessage msg{type, sev, text};
- Log::LogManager::getInstance().log(msg);
+template
+__noinline void log_message(Log::LogType type, Log::LogSeverity sev, const char* fmt, Targs... args)
+{
+ log_message(type, sev, fmt::detail::format(fmt, strlen(fmt), fmt::do_unveil(args)...));
}
-
-template
-inline void log_message(Log::LogType type, Log::LogSeverity sev, const char* text, T arg, Ts... args)
-{
- Log::LogMessage msg{type, sev, fmt::Format(text, arg, args...)};
- Log::LogManager::getInstance().log(msg);
-}
\ No newline at end of file
diff --git a/Utilities/StrFmt.cpp b/Utilities/StrFmt.cpp
index 1d3e6144e0..4c8c43cdf2 100644
--- a/Utilities/StrFmt.cpp
+++ b/Utilities/StrFmt.cpp
@@ -1,7 +1,160 @@
#include "stdafx.h"
-#include "StrFmt.h"
#include
+std::string u128::to_hex() const
+{
+ return fmt::format("%016llx%016llx", _u64[1], _u64[0]);
+}
+
+std::string u128::to_xyzw() const
+{
+ return fmt::Format("x: %g y: %g z: %g w: %g", _f[3], _f[2], _f[1], _f[0]);
+}
+
+std::string fmt::to_hex(u64 value, size_t count)
+{
+ assert(count - 1 < 16);
+ count = std::max(count, 16 - cntlz64(value) / 4);
+
+ char res[16] = {};
+
+ for (size_t i = count - 1; ~i; i--, value /= 16)
+ {
+ res[i] = "0123456789abcdef"[value % 16];
+ }
+
+ return std::string(res, count);
+}
+
+std::string fmt::to_udec(u64 value)
+{
+ char res[20] = {};
+ size_t first = sizeof(res);
+
+ if (!value)
+ {
+ res[--first] = '0';
+ }
+
+ for (; value; value /= 10)
+ {
+ res[--first] = '0' + (value % 10);
+ }
+
+ return std::string(&res[first], sizeof(res) - first);
+}
+
+std::string fmt::to_sdec(s64 svalue)
+{
+ const bool sign = svalue < 0;
+ u64 value = sign ? -svalue : svalue;
+
+ char res[20] = {};
+ size_t first = sizeof(res);
+
+ if (!value)
+ {
+ res[--first] = '0';
+ }
+
+ for (; value; value /= 10)
+ {
+ res[--first] = '0' + (value % 10);
+ }
+
+ if (sign)
+ {
+ res[--first] = '-';
+ }
+
+ return std::string(&res[first], sizeof(res) - first);
+}
+
+size_t fmt::detail::get_fmt_start(const char* fmt, size_t len)
+{
+ for (size_t i = 0; i < len; i++)
+ {
+ if (fmt[i] == '%')
+ {
+ return i;
+ }
+ }
+
+ return len;
+}
+
+size_t fmt::detail::get_fmt_len(const char* fmt, size_t len)
+{
+ assert(len >= 2 && fmt[0] == '%');
+
+ size_t res = 2;
+
+ if (fmt[1] == '.' || fmt[1] == '0')
+ {
+ assert(len >= 4 && fmt[2] - '1' < 9);
+ res += 2;
+ fmt += 2;
+ len -= 2;
+
+ if (fmt[1] == '1')
+ {
+ assert(len >= 3 && fmt[2] - '0' < 7);
+ res++;
+ fmt++;
+ len--;
+ }
+ }
+
+ if (fmt[1] == 'l')
+ {
+ assert(len >= 3);
+ res++;
+ fmt++;
+ len--;
+ }
+
+ if (fmt[1] == 'l')
+ {
+ assert(len >= 3);
+ res++;
+ fmt++;
+ len--;
+ }
+
+ return res;
+}
+
+size_t fmt::detail::get_fmt_precision(const char* fmt, size_t len)
+{
+ assert(len >= 2);
+
+ if (fmt[1] == '.' || fmt[1] == '0')
+ {
+ assert(len >= 4 && fmt[2] - '1' < 9);
+
+ if (fmt[2] == '1')
+ {
+ assert(len >= 5 && fmt[3] - '0' < 7);
+ return 10 + fmt[3] - '0';
+ }
+
+ return fmt[2] - '0';
+ }
+
+ return 1;
+}
+
+std::string fmt::detail::format(const char* fmt, size_t len)
+{
+ const size_t fmt_start = get_fmt_start(fmt, len);
+ if (fmt_start != len)
+ {
+ throw "Excessive formatting: " + std::string(fmt, len);
+ }
+
+ return std::string(fmt, len);
+}
+
extern const std::string fmt::placeholder = "???";
std::string replace_first(const std::string& src, const std::string& from, const std::string& to)
diff --git a/Utilities/StrFmt.h b/Utilities/StrFmt.h
index 963bb8b1b8..36a1ee4abb 100644
--- a/Utilities/StrFmt.h
+++ b/Utilities/StrFmt.h
@@ -1,18 +1,16 @@
#pragma once
+
class wxString;
#if defined(_MSC_VER)
#define snprintf _snprintf
#endif
-namespace fmt{
- using std::string;
- using std::ostream;
- using std::ostringstream;
-
+namespace fmt
+{
struct empty_t{};
- extern const string placeholder;
+ extern const std::string placeholder;
template
std::string AfterLast(const std::string& source, T searchstr)
@@ -51,11 +49,11 @@ namespace fmt{
// `fmt::placeholder` after `pos` everything in `fmt` after pos is written
// to `os`. Then `arg` is written to `os` after appending a space character
template
- empty_t write(const string &fmt, ostream &os, string::size_type &pos, T &&arg)
+ empty_t write(const std::string &fmt, std::ostream &os, std::string::size_type &pos, T &&arg)
{
- string::size_type ins = fmt.find(placeholder, pos);
+ std::string::size_type ins = fmt.find(placeholder, pos);
- if (ins == string::npos)
+ if (ins == std::string::npos)
{
os.write(fmt.data() + pos, fmt.size() - pos);
os << ' ' << arg;
@@ -77,10 +75,10 @@ namespace fmt{
// inserted use `fmt::placeholder`. If there's not enough placeholders
// the rest of the arguments are appended at the end, seperated by spaces
template
- string SFormat(const string &fmt, Args&& ... parameters)
+ std::string SFormat(const std::string &fmt, Args&& ... parameters)
{
- ostringstream os;
- string::size_type pos = 0;
+ std::ostringstream os;
+ std::string::size_type pos = 0;
std::initializer_list { write(fmt, os, pos, parameters)... };
if (!fmt.empty())
@@ -88,7 +86,7 @@ namespace fmt{
os.write(fmt.data() + pos, fmt.size() - pos);
}
- string result = os.str();
+ std::string result = os.str();
return result;
}
@@ -98,10 +96,10 @@ namespace fmt{
//wrapper to deal with advance sprintf formating options with automatic length finding
template
- string Format(const char* fmt, Args ... parameters)
+ std::string Format(const char* fmt, Args ... parameters)
{
size_t length = 256;
- string str;
+ std::string str;
for (;;)
{
@@ -116,7 +114,7 @@ namespace fmt{
#endif
if (printlen < length)
{
- str = string(buffptr.data(), printlen);
+ str = std::string(buffptr.data(), printlen);
break;
}
length *= 2;
@@ -175,13 +173,480 @@ namespace fmt{
return src;
}
+ std::string to_hex(u64 value, size_t count = 1);
+ std::string to_udec(u64 value);
+ std::string to_sdec(s64 value);
+
+ namespace detail
+ {
+ size_t get_fmt_start(const char* fmt, size_t len);
+ size_t get_fmt_len(const char* fmt, size_t len);
+ size_t get_fmt_precision(const char* fmt, size_t len);
+
+ template
+ struct get_fmt
+ {
+ static_assert(!sizeof(T), "Unsupported fmt::format argument");
+ };
+
+ template<>
+ struct get_fmt
+ {
+ static std::string text(const char* fmt, size_t len, u8 arg)
+ {
+ if (fmt[len - 1] == 'x')
+ {
+ return to_hex(arg, get_fmt_precision(fmt, len));
+ }
+ else if (fmt[len - 1] == 'd')
+ {
+ return to_udec(arg);
+ }
+ else
+ {
+ throw "Invalid formatting (u8): " + std::string(fmt, len);
+ }
+
+ return{};
+ }
+ };
+
+ template<>
+ struct get_fmt
+ {
+ static std::string text(const char* fmt, size_t len, u16 arg)
+ {
+ if (fmt[len - 1] == 'x')
+ {
+ return to_hex(arg, get_fmt_precision(fmt, len));
+ }
+ else if (fmt[len - 1] == 'd')
+ {
+ return to_udec(arg);
+ }
+ else
+ {
+ throw "Invalid formatting (u16): " + std::string(fmt, len);
+ }
+
+ return{};
+ }
+ };
+
+ template<>
+ struct get_fmt
+ {
+ static std::string text(const char* fmt, size_t len, u32 arg)
+ {
+ if (fmt[len - 1] == 'x')
+ {
+ return to_hex(arg, get_fmt_precision(fmt, len));
+ }
+ else if (fmt[len - 1] == 'd')
+ {
+ return to_udec(arg);
+ }
+ else
+ {
+ throw "Invalid formatting (u32): " + std::string(fmt, len);
+ }
+
+ return{};
+ }
+ };
+
+ template<>
+ struct get_fmt
+ {
+ static std::string text(const char* fmt, size_t len, u64 arg)
+ {
+ if (fmt[len - 1] == 'x')
+ {
+ return to_hex(arg, get_fmt_precision(fmt, len));
+ }
+ else if (fmt[len - 1] == 'd')
+ {
+ return to_udec(arg);
+ }
+ else
+ {
+ throw "Invalid formatting (u64): " + std::string(fmt, len);
+ }
+
+ return{};
+ }
+ };
+
+ template<>
+ struct get_fmt
+ {
+ static std::string text(const char* fmt, size_t len, s8 arg)
+ {
+ if (fmt[len - 1] == 'x')
+ {
+ return to_hex((u8)arg, get_fmt_precision(fmt, len));
+ }
+ else if (fmt[len - 1] == 'd')
+ {
+ return to_sdec(arg);
+ }
+ else
+ {
+ throw "Invalid formatting (s8): " + std::string(fmt, len);
+ }
+
+ return{};
+ }
+ };
+
+ template<>
+ struct get_fmt
+ {
+ static std::string text(const char* fmt, size_t len, s16 arg)
+ {
+ if (fmt[len - 1] == 'x')
+ {
+ return to_hex((u16)arg, get_fmt_precision(fmt, len));
+ }
+ else if (fmt[len - 1] == 'd')
+ {
+ return to_sdec(arg);
+ }
+ else
+ {
+ throw "Invalid formatting (s16): " + std::string(fmt, len);
+ }
+
+ return{};
+ }
+ };
+
+ template<>
+ struct get_fmt
+ {
+ static std::string text(const char* fmt, size_t len, s32 arg)
+ {
+ if (fmt[len - 1] == 'x')
+ {
+ return to_hex((u32)arg, get_fmt_precision(fmt, len));
+ }
+ else if (fmt[len - 1] == 'd')
+ {
+ return to_sdec(arg);
+ }
+ else
+ {
+ throw "Invalid formatting (s32): " + std::string(fmt, len);
+ }
+
+ return{};
+ }
+ };
+
+ template<>
+ struct get_fmt
+ {
+ static std::string text(const char* fmt, size_t len, s64 arg)
+ {
+ if (fmt[len - 1] == 'x')
+ {
+ return to_hex((u64)arg, get_fmt_precision(fmt, len));
+ }
+ else if (fmt[len - 1] == 'd')
+ {
+ return to_sdec(arg);
+ }
+ else
+ {
+ throw "Invalid formatting (s64): " + std::string(fmt, len);
+ }
+
+ return{};
+ }
+ };
+
+ template<>
+ struct get_fmt
+ {
+ static std::string text(const char* fmt, size_t len, float arg)
+ {
+ if (fmt[len - 1] == 'x')
+ {
+ return to_hex((u32&)arg, get_fmt_precision(fmt, len));
+ }
+ else if (fmt[len - 1] == 'f')
+ {
+ return std::to_string(arg);
+ }
+ else
+ {
+ throw "Invalid formatting (float): " + std::string(fmt, len);
+ }
+
+ return{};
+ }
+ };
+
+ template<>
+ struct get_fmt
+ {
+ static std::string text(const char* fmt, size_t len, double arg)
+ {
+ if (fmt[len - 1] == 'x')
+ {
+ return to_hex((u64&)arg, get_fmt_precision(fmt, len));
+ }
+ else if (fmt[len - 1] == 'f')
+ {
+ return std::to_string(arg);
+ }
+ else
+ {
+ throw "Invalid formatting (double): " + std::string(fmt, len);
+ }
+
+ return{};
+ }
+ };
+
+ template<>
+ struct get_fmt
+ {
+ static std::string text(const char* fmt, size_t len, bool arg)
+ {
+ if (fmt[len - 1] == 'x')
+ {
+ return to_hex(arg, get_fmt_precision(fmt, len));
+ }
+ else if (fmt[len - 1] == 'd')
+ {
+ return arg ? "1" : "0";
+ }
+ else if (fmt[len - 1] == 's')
+ {
+ return arg ? "true" : "false";
+ }
+ else
+ {
+ throw "Invalid formatting (bool): " + std::string(fmt, len);
+ }
+
+ return{};
+ }
+ };
+
+ template<>
+ struct get_fmt
+ {
+ static std::string text(const char* fmt, size_t len, char* arg)
+ {
+ if (fmt[len - 1] == 's')
+ {
+ return arg;
+ }
+ else
+ {
+ throw "Invalid formatting (char*): " + std::string(fmt, len);
+ }
+
+ return{};
+ }
+ };
+
+ template<>
+ struct get_fmt
+ {
+ static std::string text(const char* fmt, size_t len, const char* arg)
+ {
+ if (fmt[len - 1] == 's')
+ {
+ return arg;
+ }
+ else
+ {
+ throw "Invalid formatting (const char*): " + std::string(fmt, len);
+ }
+
+ return{};
+ }
+ };
+
+ //template
+ //struct get_fmt
+ //{
+ // static std::string text(const char* fmt, size_t len, const char(&arg)[size])
+ // {
+ // if (fmt[len - 1] == 's')
+ // {
+ // return std::string(arg, size);
+ // }
+ // else
+ // {
+ // throw "Invalid formatting (char[size]): " + std::string(fmt, len);
+ // }
+
+ // return{};
+ // }
+ //};
+
+ //template
+ //struct get_fmt
+ //{
+ // static std::string text(const char* fmt, size_t len, const char(&arg)[size])
+ // {
+ // if (fmt[len - 1] == 's')
+ // {
+ // return std::string(arg, size);
+ // }
+ // else
+ // {
+ // throw "Invalid formatting (const char[size]): " + std::string(fmt, len);
+ // }
+
+ // return{};
+ // }
+ //};
+
+ template<>
+ struct get_fmt
+ {
+ static std::string text(const char* fmt, size_t len, const std::string& arg)
+ {
+ if (fmt[len - 1] == 's')
+ {
+ return arg;
+ }
+ else
+ {
+ throw "Invalid formatting (std::string): " + std::string(fmt, len);
+ }
+
+ return{};
+ }
+ };
+
+ std::string format(const char* fmt, size_t len); // terminator
+
+ template
+ std::string format(const char* fmt, size_t len, const T& arg, Args... args)
+ {
+ const size_t fmt_start = get_fmt_start(fmt, len);
+ const size_t fmt_len = get_fmt_len(fmt + fmt_start, len - fmt_start);
+ const size_t fmt_end = fmt_start + fmt_len;
+
+ return std::string(fmt, fmt_start) + get_fmt::text(fmt + fmt_start, fmt_len, arg) + format(fmt + fmt_end, len - fmt_end, args...);
+ }
+ };
+
+ template::value>
+ struct unveil
+ {
+ typedef T result_type;
+
+ __forceinline static result_type get_value(const T& arg)
+ {
+ return arg;
+ }
+ };
+
+ template
+ struct unveil
+ {
+ typedef const char* result_type;
+
+ __forceinline static result_type get_value(const char(&arg)[N])
+ {
+ return arg;
+ }
+ };
+
+ template<>
+ struct unveil
+ {
+ typedef const std::string& result_type;
+
+ __forceinline static result_type get_value(const std::string& arg)
+ {
+ return arg;
+ }
+ };
+
+ template
+ struct unveil
+ {
+ typedef typename std::underlying_type::type result_type;
+
+ __forceinline static result_type get_value(const T& arg)
+ {
+ return static_cast(arg);
+ }
+ };
+
+ template
+ struct unveil, false>
+ {
+ typedef typename unveil::result_type result_type;
+
+ __forceinline static result_type get_value(const be_t& arg)
+ {
+ return unveil::get_value(arg.value());
+ }
+ };
+
+ template
+ __forceinline typename unveil::result_type do_unveil(const T& arg)
+ {
+ return unveil::get_value(arg);
+ }
+
+ /*
+ fmt::format(const char* fmt, args...)
+
+ Formatting function with very limited functionality (compared to printf-like formatting) and be_t<> support
+
+ Supported types:
+
+ u8, s8 (%x, %d)
+ u16, s16 (%x, %d)
+ u32, s32 (%x, %d)
+ u64, s64 (%x, %d)
+ float (%x, %f)
+ double (%x, %f)
+ bool (%x, %d, %s)
+ char*, const char*, std::string (%s)
+
+ be_t<> of any appropriate type in this list (fmt::unveil)
+ enum of any appropriate type in this list (fmt::unveil)
+
+ External specializations (can be found in another headers):
+ vm::ps3::ptr (fmt::unveil) (vm_ptr.h) (with appropriate address type, using .addr() can be avoided)
+ vm::ps3::bptr (fmt::unveil) (vm_ptr.h)
+ vm::psv::ptr (fmt::unveil) (vm_ptr.h)
+ vm::ps3::ref (fmt::unveil) (vm_ref.h)
+ vm::ps3::bref (fmt::unveil) (vm_ref.h)
+ vm::psv::ref (fmt::unveil) (vm_ref.h)
+
+ Supported formatting:
+ %d - decimal; to_sdec() and to_udec()
+ %x - hexadecimal; to_hex(), %08x - hexadecimal with minimal length (from 02 to 016)
+ %s - string; generates "true" or "false" for bool
+ %f - floating point; only basic std::to_string() functionality
+
+ Other features are not supported.
+ */
+ template
+ __forceinline std::string format(const char* fmt, Args... args)
+ {
+ return detail::format(fmt, strlen(fmt), do_unveil(args)...);
+ }
+
//convert a wxString to a std::string encoded in utf8
//CAUTION, only use this to interface with wxWidgets classes
std::string ToUTF8(const wxString& right);
//convert a std::string encoded in utf8 to a wxString
//CAUTION, only use this to interface with wxWidgets classes
- wxString FromUTF8(const string& right);
+ wxString FromUTF8(const std::string& right);
//TODO: remove this after every snippet that uses it is gone
//WARNING: not fully compatible with CmpNoCase from wxString
diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp
index 6014c607bf..2539c791cd 100644
--- a/Utilities/Thread.cpp
+++ b/Utilities/Thread.cpp
@@ -1,16 +1,24 @@
#include "stdafx.h"
-#include "Emu/System.h"
#include "Log.h"
+#include "rpcs3/Ini.h"
+#include "Emu/System.h"
+#include "Emu/CPU/CPUThread.h"
+#include "Emu/SysCalls/SysCalls.h"
#include "Thread.h"
#ifdef _WIN32
#include
+#else
+#include
+#include
#endif
void SetCurrentThreadDebugName(const char* threadName)
{
-#ifdef _WIN32 // this is VS-specific way to set thread names for the debugger
+#if defined(_MSC_VER) // this is VS-specific way to set thread names for the debugger
+
#pragma pack(push,8)
+
struct THREADNAME_INFO
{
DWORD dwType;
@@ -18,6 +26,7 @@ void SetCurrentThreadDebugName(const char* threadName)
DWORD dwThreadID;
DWORD dwFlags;
} info;
+
#pragma pack(pop)
info.dwType = 0x1000;
@@ -32,9 +41,300 @@ void SetCurrentThreadDebugName(const char* threadName)
__except (EXCEPTION_EXECUTE_HANDLER)
{
}
+
#endif
}
+enum x64_reg_t : u32
+{
+ X64R_EAX,
+ X64R_ECX,
+ X64R_EDX,
+ X64R_EBX,
+ X64R_ESP,
+ X64R_EBP,
+ X64R_ESI,
+ X64R_EDI,
+ X64R_R8D,
+ X64R_R9D,
+ X64R_R10D,
+ X64R_R11D,
+ X64R_R12D,
+ X64R_R13D,
+ X64R_R14D,
+ X64R_R15D,
+ X64R32 = X64R_EAX,
+
+ X64_IMM32,
+};
+
+enum x64_op_t : u32
+{
+ X64OP_LOAD, // obtain and put the value into x64 register (from Memory.ReadMMIO32, for example)
+ X64OP_STORE, // take the value from x64 register or an immediate and use it (pass in Memory.WriteMMIO32, for example)
+ // example: add eax,[rax] -> X64OP_LOAD_ADD (add the value to x64 register)
+ // example: add [rax],eax -> X64OP_LOAD_ADD_STORE (this will probably never happen for MMIO registers)
+};
+
+void decode_x64_reg_op(const u8* code, x64_op_t& decoded_op, x64_reg_t& decoded_reg, size_t& decoded_size)
+{
+ // simple analysis of x64 code allows to reinterpret MOV or other instructions in any desired way
+ decoded_size = 0;
+
+ u8 rex = 0;
+ u8 reg = 0; // set to 8 by REX prefix
+ u8 pg2 = 0;
+
+ // check prefixes:
+ for (;; code++, decoded_size++)
+ {
+ switch (const u8 prefix = *code)
+ {
+ case 0xf0: throw fmt::format("decode_x64_reg_op(%016llxh): 0x%02x (LOCK prefix) found", (size_t)code - decoded_size, prefix); // group 1
+ case 0xf2: throw fmt::format("decode_x64_reg_op(%016llxh): 0x%02x (REPNE/REPNZ prefix) found", (size_t)code - decoded_size, prefix); // group 1
+ case 0xf3: throw fmt::format("decode_x64_reg_op(%016llxh): 0x%02x (REP/REPE/REPZ prefix) found", (size_t)code - decoded_size, prefix); // group 1
+
+ case 0x2e: // group 2
+ case 0x36:
+ case 0x3e:
+ case 0x26:
+ case 0x64:
+ case 0x65:
+ {
+ if (!pg2)
+ {
+ pg2 = prefix; // probably, segment register
+ continue;
+ }
+ else
+ {
+ throw fmt::format("decode_x64_reg_op(%016llxh): 0x%02x (group 2 prefix) found after 0x%02x", (size_t)code - decoded_size, prefix, pg2);
+ }
+ }
+
+ case 0x66: throw fmt::format("decode_x64_reg_op(%016llxh): 0x%02x (operand-size override prefix) found", (size_t)code - decoded_size, prefix); // group 3
+ case 0x67: throw fmt::format("decode_x64_reg_op(%016llxh): 0x%02x (address-size override prefix) found", (size_t)code - decoded_size, prefix); // group 4
+
+ default:
+ {
+ if ((prefix & 0xf0) == 0x40) // check REX prefix
+ {
+ if (rex)
+ {
+ throw fmt::format("decode_x64_reg_op(%016llxh): 0x%02x (REX prefix) found after 0x%02x", (size_t)code - decoded_size, prefix, rex);
+ }
+ if (prefix & 0x80) // check REX.W bit
+ {
+ throw fmt::format("decode_x64_reg_op(%016llxh): 0x%02x (REX.W bit) found", (size_t)code - decoded_size, prefix);
+ }
+ if (prefix & 0x04) // check REX.R bit
+ {
+ reg = 8;
+ }
+ rex = prefix;
+ continue;
+ }
+ }
+ }
+
+ break;
+ }
+
+ auto get_modRM_r32 = [](const u8* code, const u8 reg_base) -> x64_reg_t
+ {
+ return (x64_reg_t)((((*code & 0x38) >> 3) | reg_base) + X64R32);
+ };
+
+ auto get_modRM_size = [](const u8* code) -> size_t
+ {
+ switch (*code >> 6) // check Mod
+ {
+ case 0: return (*code & 0x07) == 4 ? 2 : 1; // check SIB
+ case 1: return (*code & 0x07) == 4 ? 3 : 2; // check SIB (disp8)
+ case 2: return (*code & 0x07) == 4 ? 6 : 5; // check SIB (disp32)
+ default: return 1;
+ }
+ };
+
+ decoded_size++;
+ switch (const u8 op1 = *code++)
+ {
+ case 0x89: // MOV r/m32, r32
+ {
+ decoded_op = X64OP_STORE;
+ decoded_reg = get_modRM_r32(code, reg);
+ decoded_size += get_modRM_size(code);
+ return;
+ }
+ case 0x8b: // MOV r32, r/m32
+ {
+ decoded_op = X64OP_LOAD;
+ decoded_reg = get_modRM_r32(code, reg);
+ decoded_size += get_modRM_size(code);
+ return;
+ }
+ case 0xc7:
+ {
+ if (get_modRM_r32(code, 0) == X64R_EAX) // MOV r/m32, imm32 (not tested)
+ {
+ decoded_op = X64OP_STORE;
+ decoded_reg = X64_IMM32;
+ decoded_size = get_modRM_size(code) + 4;
+ return;
+ }
+ }
+ default:
+ {
+ throw fmt::format("decode_x64_reg_op(%016llxh): unsupported opcode found (0x%02x, 0x%02x, 0x%02x)", (size_t)code - decoded_size, op1, code[0], code[1]);
+ }
+ }
+}
+
+#ifdef _WIN32
+
+typedef CONTEXT x64_context;
+
+#define RIP 16
+#define X64REG(context, reg) ((&context->Rax)[reg])
+
+#else
+
+typedef ucontext_t x64_context;
+typedef decltype(REG_RIP) reg_table_t;
+#define RIP 16
+
+static const reg_table_t reg_table[17] =
+{
+ REG_RAX, REG_RCX, REG_RDX, REG_RBX, REG_RSP, REG_RBP, REG_RSI, REG_RDI,
+ REG_R8, REG_R9, REG_R10, REG_R11, REG_R12, REG_R13, REG_R14, REG_R15, REG_RIP
+};
+
+#define X64REG(context, reg) (context->uc_mcontext.gregs[reg_table[reg]])
+
+#endif
+
+bool handle_access_violation(const u32 addr, x64_context* context)
+{
+ if (addr - RAW_SPU_BASE_ADDR < (6 * RAW_SPU_OFFSET) && (addr % RAW_SPU_OFFSET) >= RAW_SPU_PROB_OFFSET) // RawSPU MMIO registers
+ {
+ // one x64 instruction is manually decoded and interpreted
+ x64_op_t op;
+ x64_reg_t reg;
+ size_t size;
+ decode_x64_reg_op((const u8*)X64REG(context, RIP), op, reg, size);
+
+ // get x64 reg value (for store operations)
+ u64 reg_value;
+ if (reg - X64R32 < 16)
+ {
+ // load the value from x64 register
+ reg_value = (u32)X64REG(context, reg - X64R32);
+ }
+ else if (reg == X64_IMM32)
+ {
+ // load the immediate value (assuming it's at the end of the instruction)
+ reg_value = *(u32*)(X64REG(context, RIP) + size - 4);
+ }
+ else
+ {
+ assert(!"Invalid x64_reg_t value");
+ }
+
+ bool save_reg = false;
+
+ switch (op)
+ {
+ case X64OP_LOAD:
+ {
+ reg_value = re32(Memory.ReadMMIO32(addr));
+ save_reg = true;
+ break;
+ }
+ case X64OP_STORE:
+ {
+ Memory.WriteMMIO32(addr, re32((u32)reg_value));
+ break;
+ }
+ default: assert(!"Invalid x64_op_t value");
+ }
+
+ // save x64 reg value (for load operations)
+ if (save_reg)
+ {
+ if (reg - X64R32 < 16)
+ {
+ // store the value into x64 register
+ X64REG(context, reg - X64R32) = (u32)reg_value;
+ }
+ else
+ {
+ assert(!"Invalid x64_reg_t value (saving)");
+ }
+ }
+
+ // skip decoded instruction
+ X64REG(context, RIP) += size;
+ return true;
+ }
+
+ // TODO: allow recovering from a page fault as a feature of PS3 virtual memory
+ return false;
+}
+
+#ifdef _WIN32
+
+void _se_translator(unsigned int u, EXCEPTION_POINTERS* pExp)
+{
+ const u64 addr64 = (u64)pExp->ExceptionRecord->ExceptionInformation[1] - (u64)Memory.GetBaseAddr();
+ const bool is_writing = pExp->ExceptionRecord->ExceptionInformation[0] != 0;
+ if (u == EXCEPTION_ACCESS_VIOLATION && (u32)addr64 == addr64)
+ {
+ if (handle_access_violation((u32)addr64, pExp->ContextRecord))
+ {
+ // restore context (further code shouldn't be reached)
+ RtlRestoreContext(pExp->ContextRecord, nullptr);
+
+ // it's dangerous because destructors won't be executed
+ }
+
+ throw fmt::format("Access violation %s location 0x%llx", is_writing ? "writing" : "reading", addr64);
+ }
+
+ // else some fatal error (should crash)
+}
+
+#else
+
+void signal_handler(int sig, siginfo_t* info, void* uct)
+{
+ const u64 addr64 = (u64)info->si_addr - (u64)Memory.GetBaseAddr();
+ if ((u32)addr64 == addr64 && GetCurrentNamedThread())
+ {
+ if (handle_access_violation((u32)addr64, (ucontext_t*)uct))
+ {
+ return; // proceed execution
+ }
+
+ // TODO: this may be wrong
+ throw fmt::format("Access violation at location 0x%llx", addr64);
+ }
+
+ // else some fatal error
+ exit(EXIT_FAILURE);
+}
+
+const int sigaction_result = []() -> int
+{
+ struct sigaction sa;
+
+ sa.sa_flags = SA_SIGINFO;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_sigaction = signal_handler;
+ return sigaction(SIGSEGV, &sa, NULL);
+}();
+
+#endif
+
thread_local NamedThreadBase* g_tls_this_thread = nullptr;
std::atomic g_thread_count(0);
@@ -45,7 +345,7 @@ NamedThreadBase* GetCurrentNamedThread()
void SetCurrentNamedThread(NamedThreadBase* value)
{
- auto old_value = g_tls_this_thread;
+ const auto old_value = g_tls_this_thread;
if (old_value == value)
{
@@ -54,7 +354,7 @@ void SetCurrentNamedThread(NamedThreadBase* value)
if (value && value->m_tls_assigned.exchange(true))
{
- LOG_ERROR(GENERAL, "Thread '%s' was already assigned to g_tls_this_thread of another thread", value->GetThreadName().c_str());
+ LOG_ERROR(GENERAL, "Thread '%s' was already assigned to g_tls_this_thread of another thread", value->GetThreadName());
g_tls_this_thread = nullptr;
}
else
@@ -119,6 +419,12 @@ void ThreadBase::Start()
{
SetCurrentThreadDebugName(GetThreadName().c_str());
+#ifdef _WIN32
+ auto old_se_translator = _set_se_translator(_se_translator);
+#else
+ if (sigaction_result == -1) assert(!"sigaction() failed");
+#endif
+
SetCurrentNamedThread(this);
g_thread_count++;
@@ -138,6 +444,10 @@ void ThreadBase::Start()
m_alive = false;
SetCurrentNamedThread(nullptr);
g_thread_count--;
+
+#ifdef _WIN32
+ _set_se_translator(old_se_translator);
+#endif
});
}
@@ -187,31 +497,82 @@ bool ThreadBase::TestDestroy() const
return m_destroy;
}
-thread::thread(const std::string& name, std::function func) : m_name(name)
+thread_t::thread_t(const std::string& name, bool autojoin, std::function func)
+ : m_name(name)
+ , m_state(TS_NON_EXISTENT)
+ , m_autojoin(autojoin)
{
start(func);
}
-thread::thread(const std::string& name) : m_name(name)
+thread_t::thread_t(const std::string& name, std::function func)
+ : m_name(name)
+ , m_state(TS_NON_EXISTENT)
+ , m_autojoin(false)
+{
+ start(func);
+}
+
+thread_t::thread_t(const std::string& name)
+ : m_name(name)
+ , m_state(TS_NON_EXISTENT)
+ , m_autojoin(false)
{
}
-thread::thread()
+thread_t::thread_t()
+ : m_state(TS_NON_EXISTENT)
+ , m_autojoin(false)
{
}
-void thread::start(std::function func)
+void thread_t::set_name(const std::string& name)
{
+ m_name = name;
+}
+
+thread_t::~thread_t()
+{
+ if (m_state == TS_JOINABLE)
+ {
+ if (m_autojoin)
+ {
+ m_thr.join();
+ }
+ else
+ {
+ m_thr.detach();
+ }
+ }
+}
+
+void thread_t::start(std::function func)
+{
+ if (m_state.exchange(TS_NON_EXISTENT) == TS_JOINABLE)
+ {
+ m_thr.join(); // forcefully join previously created thread
+ }
+
std::string name = m_name;
-
m_thr = std::thread([func, name]()
{
SetCurrentThreadDebugName(name.c_str());
+#ifdef _WIN32
+ auto old_se_translator = _set_se_translator(_se_translator);
+#else
+ if (sigaction_result == -1) assert(!"sigaction() failed");
+#endif
+
NamedThreadBase info(name);
SetCurrentNamedThread(&info);
g_thread_count++;
+ if (Ini.HLELogging.GetValue())
+ {
+ LOG_NOTICE(HLE, name + " started");
+ }
+
try
{
func();
@@ -225,24 +586,57 @@ void thread::start(std::function func)
LOG_ERROR(GENERAL, "%s: %s", name.c_str(), e.c_str());
}
+ if (Emu.IsStopped())
+ {
+ LOG_NOTICE(HLE, name + " aborted");
+ }
+ else if (Ini.HLELogging.GetValue())
+ {
+ LOG_NOTICE(HLE, name + " ended");
+ }
+
SetCurrentNamedThread(nullptr);
g_thread_count--;
+
+#ifdef _WIN32
+ _set_se_translator(old_se_translator);
+#endif
});
+
+ if (m_state.exchange(TS_JOINABLE) == TS_JOINABLE)
+ {
+ assert(!"thread_t::start() failed"); // probably started from another thread
+ }
}
-void thread::detach()
+void thread_t::detach()
{
- m_thr.detach();
+ if (m_state.exchange(TS_NON_EXISTENT) == TS_JOINABLE)
+ {
+ m_thr.detach();
+ }
+ else
+ {
+ assert(!"thread_t::detach() failed"); // probably joined or detached
+ }
}
-void thread::join()
+void thread_t::join()
{
- m_thr.join();
+ if (m_state.exchange(TS_NON_EXISTENT) == TS_JOINABLE)
+ {
+ m_thr.join();
+ }
+ else
+ {
+ assert(!"thread_t::join() failed"); // probably joined or detached
+ }
}
-bool thread::joinable() const
+bool thread_t::joinable() const
{
- return m_thr.joinable();
+ //return m_thr.joinable();
+ return m_state == TS_JOINABLE;
}
bool waiter_map_t::is_stopped(u64 signal_id)
@@ -306,7 +700,10 @@ void waiter_map_t::notify(u64 signal_id)
}
}
-bool squeue_test_exit(const volatile bool* do_exit)
+const std::function SQUEUE_ALWAYS_EXIT = [](){ return true; };
+const std::function SQUEUE_NEVER_EXIT = [](){ return false; };
+
+bool squeue_test_exit()
{
- return Emu.IsStopped() || (do_exit && *do_exit);
+ return Emu.IsStopped();
}
diff --git a/Utilities/Thread.h b/Utilities/Thread.h
index 4b54317bec..4e51438636 100644
--- a/Utilities/Thread.h
+++ b/Utilities/Thread.h
@@ -54,18 +54,34 @@ public:
virtual void Task() = 0;
};
-class thread
+class thread_t
{
+ enum thread_state_t
+ {
+ TS_NON_EXISTENT,
+ TS_JOINABLE,
+ };
+
+ std::atomic m_state;
std::string m_name;
std::thread m_thr;
+ bool m_autojoin;
public:
- thread(const std::string& name, std::function func);
- thread(const std::string& name);
- thread();
+ thread_t(const std::string& name, bool autojoin, std::function func);
+ thread_t(const std::string& name, std::function func);
+ thread_t(const std::string& name);
+ thread_t();
+ ~thread_t();
+ thread_t(const thread_t& right) = delete;
+ thread_t(thread_t&& right) = delete;
+
+ thread_t& operator =(const thread_t& right) = delete;
+ thread_t& operator =(thread_t&& right) = delete;
public:
+ void set_name(const std::string& name);
void start(std::function func);
void detach();
void join();
@@ -148,7 +164,10 @@ public:
void notify(u64 signal_id);
};
-bool squeue_test_exit(const volatile bool* do_exit);
+extern const std::function SQUEUE_ALWAYS_EXIT;
+extern const std::function SQUEUE_NEVER_EXIT;
+
+bool squeue_test_exit();
template
class squeue_t
@@ -199,7 +218,7 @@ public:
return m_sync.read_relaxed().count == sq_size;
}
- bool push(const T& data, const volatile bool* do_exit = nullptr)
+ bool push(const T& data, const std::function& test_exit)
{
u32 pos = 0;
@@ -222,7 +241,7 @@ public:
return SQSVR_OK;
}))
{
- if (res == SQSVR_FAILED && squeue_test_exit(do_exit))
+ if (res == SQSVR_FAILED && (test_exit() || squeue_test_exit()))
{
return false;
}
@@ -247,14 +266,22 @@ public:
return true;
}
- bool try_push(const T& data)
+ bool push(const T& data, const volatile bool* do_exit)
{
- static const volatile bool no_wait = true;
-
- return push(data, &no_wait);
+ return push(data, [do_exit](){ return do_exit && *do_exit; });
}
- bool pop(T& data, const volatile bool* do_exit = nullptr)
+ __forceinline bool push(const T& data)
+ {
+ return push(data, SQUEUE_NEVER_EXIT);
+ }
+
+ __forceinline bool try_push(const T& data)
+ {
+ return push(data, SQUEUE_ALWAYS_EXIT);
+ }
+
+ bool pop(T& data, const std::function& test_exit)
{
u32 pos = 0;
@@ -277,7 +304,7 @@ public:
return SQSVR_OK;
}))
{
- if (res == SQSVR_FAILED && squeue_test_exit(do_exit))
+ if (res == SQSVR_FAILED && (test_exit() || squeue_test_exit()))
{
return false;
}
@@ -307,14 +334,22 @@ public:
return true;
}
- bool try_pop(T& data)
+ bool pop(T& data, const volatile bool* do_exit)
{
- static const volatile bool no_wait = true;
-
- return pop(data, &no_wait);
+ return pop(data, [do_exit](){ return do_exit && *do_exit; });
}
- bool peek(T& data, u32 start_pos = 0, const volatile bool* do_exit = nullptr)
+ __forceinline bool pop(T& data)
+ {
+ return pop(data, SQUEUE_NEVER_EXIT);
+ }
+
+ __forceinline bool try_pop(T& data)
+ {
+ return pop(data, SQUEUE_ALWAYS_EXIT);
+ }
+
+ bool peek(T& data, u32 start_pos, const std::function& test_exit)
{
assert(start_pos < sq_size);
u32 pos = 0;
@@ -332,13 +367,13 @@ public:
{
return SQSVR_LOCKED;
}
-
+
sync.pop_lock = 1;
pos = sync.position + start_pos;
return SQSVR_OK;
}))
{
- if (res == SQSVR_FAILED && squeue_test_exit(do_exit))
+ if (res == SQSVR_FAILED && (test_exit() || squeue_test_exit()))
{
return false;
}
@@ -361,11 +396,19 @@ public:
return true;
}
- bool try_peek(T& data, u32 start_pos = 0)
+ bool peek(T& data, u32 start_pos, const volatile bool* do_exit)
{
- static const volatile bool no_wait = true;
+ return peek(data, start_pos, [do_exit](){ return do_exit && *do_exit; });
+ }
- return peek(data, start_pos, &no_wait);
+ __forceinline bool peek(T& data, u32 start_pos = 0)
+ {
+ return peek(data, start_pos, SQUEUE_NEVER_EXIT);
+ }
+
+ __forceinline bool try_peek(T& data, u32 start_pos = 0)
+ {
+ return peek(data, start_pos, SQUEUE_ALWAYS_EXIT);
}
class squeue_data_t
diff --git a/Utilities/rFile.cpp b/Utilities/rFile.cpp
index 912452ef89..e6f657d39e 100644
--- a/Utilities/rFile.cpp
+++ b/Utilities/rFile.cpp
@@ -114,7 +114,7 @@ bool rRmdir(const std::string &dir)
if (int err = rmdir(dir.c_str()))
#endif
{
- LOG_ERROR(GENERAL, "Error deleting directory %s: %i", dir.c_str(), GET_API_ERROR);
+ LOG_ERROR(GENERAL, "Error deleting directory %s: 0x%llx", dir.c_str(), (u64)GET_API_ERROR);
return false;
}
return true;
@@ -149,7 +149,7 @@ bool rRemoveFile(const std::string &file)
if (int err = unlink(file.c_str()))
#endif
{
- LOG_ERROR(GENERAL, "Error deleting %s: %i", file.c_str(), GET_API_ERROR);
+ LOG_ERROR(GENERAL, "Error deleting file %s: 0x%llx", file.c_str(), (u64)GET_API_ERROR);
return false;
}
return true;
diff --git a/minidx9 b/minidx9
new file mode 160000
index 0000000000..ec19e64346
--- /dev/null
+++ b/minidx9
@@ -0,0 +1 @@
+Subproject commit ec19e643461c84dbb256f6faaaab02cba61d4edc
diff --git a/rpcs3/CMakeLists.txt b/rpcs3/CMakeLists.txt
index 9245ac9125..c5e6ebe4a0 100644
--- a/rpcs3/CMakeLists.txt
+++ b/rpcs3/CMakeLists.txt
@@ -5,6 +5,13 @@ include(cotire)
project(rpcs3)
+# Generate git-version.h at build time.
+add_custom_target(GitVersion ALL
+ DEPENDS something_that_never_exists)
+add_custom_command(OUTPUT something_that_never_exists
+ COMMAND ${CMAKE_COMMAND} -DSOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/git-version.cmake)
+
if (CMAKE_COMPILER_IS_GNUCXX)
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7.0)
message(FATAL_ERROR "GCC ${CMAKE_CXX_COMPILER_VERSION} is too old.")
diff --git a/rpcs3/Crypto/unedat.cpp b/rpcs3/Crypto/unedat.cpp
index 27ddbffb6a..f4d57c49d0 100644
--- a/rpcs3/Crypto/unedat.cpp
+++ b/rpcs3/Crypto/unedat.cpp
@@ -288,7 +288,7 @@ int decrypt_data(rFile *in, rFile *out, EDAT_HEADER *edat, NPD_HEADER *npd, unsi
if (!decrypt(hash_mode, crypto_mode, (npd->version == 4), enc_data, dec_data, length, key_result, iv, hash, hash_result))
{
if (verbose)
- LOG_WARNING(LOADER, "EDAT: Block at offset 0x%llx has invalid hash!", offset);
+ LOG_WARNING(LOADER, "EDAT: Block at offset 0x%llx has invalid hash!", (u64)offset);
return 1;
}
@@ -695,7 +695,7 @@ bool extract_data(rFile *input, rFile *output, const char* input_file_name, unsi
LOG_NOTICE(LOADER, "SDAT HEADER");
LOG_NOTICE(LOADER, "SDAT flags: 0x%08X", EDAT->flags);
LOG_NOTICE(LOADER, "SDAT block size: 0x%08X", EDAT->block_size);
- LOG_NOTICE(LOADER, "SDAT file size: 0x%08X", EDAT->file_size);
+ LOG_NOTICE(LOADER, "SDAT file size: 0x%08X", (u64)EDAT->file_size);
}
// Generate SDAT key.
@@ -708,7 +708,7 @@ bool extract_data(rFile *input, rFile *output, const char* input_file_name, unsi
LOG_NOTICE(LOADER, "EDAT HEADER");
LOG_NOTICE(LOADER, "EDAT flags: 0x%08X", EDAT->flags);
LOG_NOTICE(LOADER, "EDAT block size: 0x%08X", EDAT->block_size);
- LOG_NOTICE(LOADER, "EDAT file size: 0x%08X", EDAT->file_size);
+ LOG_NOTICE(LOADER, "EDAT file size: 0x%08X", (u64)EDAT->file_size);
}
// Perform header validation (EDAT only).
diff --git a/rpcs3/Crypto/unpkg.cpp b/rpcs3/Crypto/unpkg.cpp
index 5d7846046f..65e1d3e394 100644
--- a/rpcs3/Crypto/unpkg.cpp
+++ b/rpcs3/Crypto/unpkg.cpp
@@ -158,24 +158,31 @@ bool LoadEntries(rFile& dec_pkg_f, PKGHeader* m_header, PKGEntry *m_entries)
bool UnpackEntry(rFile& dec_pkg_f, const PKGEntry& entry, std::string dir)
{
- u8 buf[BUF_SIZE];
+ char buf[BUF_SIZE];
dec_pkg_f.Seek(entry.name_offset);
dec_pkg_f.Read(buf, entry.name_size);
buf[entry.name_size] = 0;
- switch (entry.type & (0xff))
+ switch (entry.type.data() >> 24)
{
- case PKG_FILE_ENTRY_NPDRM:
- case PKG_FILE_ENTRY_NPDRMEDAT:
- case PKG_FILE_ENTRY_SDAT:
- case PKG_FILE_ENTRY_REGULAR:
+ case PKG_FILE_ENTRY_NPDRM:
+ case PKG_FILE_ENTRY_NPDRMEDAT:
+ case PKG_FILE_ENTRY_SDAT:
+ case PKG_FILE_ENTRY_REGULAR:
+ {
+ rFile out;
+ auto path = dir + std::string(buf, entry.name_size);
+ if (rExists(path))
+ {
+ LOG_WARNING(LOADER, "PKG Loader: File is overwritten: %s", path.c_str());
+ }
+
+ if (out.Create(path, true /* overwriting */))
{
- rFile out;
- out.Create(dir + std::string(reinterpret_cast(buf), entry.name_size));
dec_pkg_f.Seek(entry.file_offset);
- for (u64 size = 0; size < entry.file_size; ) {
+ for (u64 size = 0; size < entry.file_size;) {
size += dec_pkg_f.Read(buf, BUF_SIZE);
if (size > entry.file_size)
out.Write(buf, BUF_SIZE - (size - entry.file_size));
@@ -183,14 +190,33 @@ bool UnpackEntry(rFile& dec_pkg_f, const PKGEntry& entry, std::string dir)
out.Write(buf, BUF_SIZE);
}
out.Close();
+ return true;
+ }
+ else
+ {
+ LOG_ERROR(LOADER, "PKG Loader: Could not create file: %s", path.c_str());
+ return false;
}
- break;
-
- case PKG_FILE_ENTRY_FOLDER:
- rMkdir(dir + std::string(reinterpret_cast(buf), entry.name_size));
- break;
}
- return true;
+
+ case PKG_FILE_ENTRY_FOLDER:
+ {
+ auto path = dir + std::string(buf, entry.name_size);
+ if (!rExists(path) && !rMkdir(path))
+ {
+ LOG_ERROR(LOADER, "PKG Loader: Could not create directory: %s", path.c_str());
+ return false;
+ }
+
+ return true;
+ }
+
+ default:
+ {
+ LOG_ERROR(LOADER, "PKG Loader: unknown PKG file entry: 0x%x", entry.type);
+ return false;
+ }
+ }
}
int Unpack(rFile& pkg_f, std::string src, std::string dst)
diff --git a/rpcs3/Emu/ARMv7/ARMv7Thread.h b/rpcs3/Emu/ARMv7/ARMv7Thread.h
index ce63376273..22e655188d 100644
--- a/rpcs3/Emu/ARMv7/ARMv7Thread.h
+++ b/rpcs3/Emu/ARMv7/ARMv7Thread.h
@@ -1,5 +1,4 @@
#pragma once
-
#include "Emu/CPU/CPUThread.h"
#include "Emu/Memory/Memory.h"
@@ -210,3 +209,131 @@ public:
return *this;
}
};
+
+template::value>
+struct cast_armv7_gpr
+{
+ static_assert(is_enum, "Invalid type for cast_armv7_gpr");
+
+ typedef typename std::underlying_type::type underlying_type;
+
+ __forceinline static u32 to_gpr(const T& value)
+ {
+ return cast_armv7_gpr::to_gpr(static_cast(value));
+ }
+
+ __forceinline static T from_gpr(const u32 reg)
+ {
+ return static_cast(cast_armv7_gpr::from_gpr(reg));
+ }
+};
+
+template<>
+struct cast_armv7_gpr
+{
+ __forceinline static u32 to_gpr(const u8& value)
+ {
+ return value;
+ }
+
+ __forceinline static u8 from_gpr(const u32 reg)
+ {
+ return static_cast(reg);
+ }
+};
+
+template<>
+struct cast_armv7_gpr
+{
+ __forceinline static u32 to_gpr(const u16& value)
+ {
+ return value;
+ }
+
+ __forceinline static u16 from_gpr(const u32 reg)
+ {
+ return static_cast(reg);
+ }
+};
+
+template<>
+struct cast_armv7_gpr
+{
+ __forceinline static u32 to_gpr(const u32& value)
+ {
+ return value;
+ }
+
+ __forceinline static u32 from_gpr(const u32 reg)
+ {
+ return reg;
+ }
+};
+
+template<>
+struct cast_armv7_gpr
+{
+ __forceinline static u32 to_gpr(const s8& value)
+ {
+ return value;
+ }
+
+ __forceinline static s8 from_gpr(const u32 reg)
+ {
+ return static_cast(reg);
+ }
+};
+
+template<>
+struct cast_armv7_gpr
+{
+ __forceinline static u32 to_gpr(const s16& value)
+ {
+ return value;
+ }
+
+ __forceinline static s16 from_gpr(const u32 reg)
+ {
+ return static_cast(reg);
+ }
+};
+
+template<>
+struct cast_armv7_gpr
+{
+ __forceinline static u32 to_gpr(const s32& value)
+ {
+ return value;
+ }
+
+ __forceinline static s32 from_gpr(const u32 reg)
+ {
+ return static_cast(reg);
+ }
+};
+
+template<>
+struct cast_armv7_gpr
+{
+ __forceinline static u32 to_gpr(const bool& value)
+ {
+ return value;
+ }
+
+ __forceinline static bool from_gpr(const u32 reg)
+ {
+ return reinterpret_cast(reg);
+ }
+};
+
+template
+__forceinline u32 cast_to_armv7_gpr(const T& value)
+{
+ return cast_armv7_gpr::to_gpr(value);
+}
+
+template
+__forceinline T cast_from_armv7_gpr(const u32 reg)
+{
+ return cast_armv7_gpr::from_gpr(reg);
+}
diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp
index 562193cb22..7ae9f6a2a6 100644
--- a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp
+++ b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp
@@ -95,20 +95,18 @@ s32 sceKernelCreateThread(
s32 cpuAffinityMask,
vm::psv::ptr pOptParam)
{
- sceLibKernel.Error("sceKernelCreateThread(pName_addr=0x%x ('%s'), entry_addr=0x%x, initPriority=%d, stackSize=0x%x, attr=0x%x, cpuAffinityMask=0x%x, pOptParam_addr=0x%x)",
- pName.addr(), pName.get_ptr(), entry.addr(), initPriority, stackSize, attr, cpuAffinityMask, pOptParam.addr());
+ sceLibKernel.Error("sceKernelCreateThread(pName=0x%x, entry=0x%x, initPriority=%d, stackSize=0x%x, attr=0x%x, cpuAffinityMask=0x%x, pOptParam=0x%x)",
+ pName, entry, initPriority, stackSize, attr, cpuAffinityMask, pOptParam);
- std::string name = pName.get_ptr();
-
- ARMv7Thread& new_thread = *(ARMv7Thread*)&Emu.GetCPU().AddThread(CPU_THREAD_ARMv7);
+ ARMv7Thread& new_thread = static_cast(Emu.GetCPU().AddThread(CPU_THREAD_ARMv7));
u32 id = new_thread.GetId();
new_thread.SetEntry(entry.addr() ^ 1);
new_thread.SetPrio(initPriority);
new_thread.SetStackSize(stackSize);
- new_thread.SetName(name);
+ new_thread.SetName(pName.get_ptr());
- sceLibKernel.Error("*** New ARMv7 Thread [%s] (entry=0x%x): id = %d", name.c_str(), entry, id);
+ sceLibKernel.Error("*** New ARMv7 Thread [%s] (entry=0x%x)^1: id = %d", pName.get_ptr(), entry, id);
new_thread.Run();
@@ -119,7 +117,7 @@ s32 sceKernelCreateThread(
s32 sceKernelStartThread(s32 threadId, u32 argSize, vm::psv::ptr pArgBlock)
{
- sceLibKernel.Error("sceKernelStartThread(threadId=%d, argSize=%d, pArgBlock_addr=0x%x)", threadId, argSize, pArgBlock.addr());
+ sceLibKernel.Error("sceKernelStartThread(threadId=%d, argSize=%d, pArgBlock=0x%x)", threadId, argSize, pArgBlock);
std::shared_ptr t = Emu.GetCPU().GetThread(threadId);
@@ -128,15 +126,17 @@ s32 sceKernelStartThread(s32 threadId, u32 argSize, vm::psv::ptr pAr
RETURN_ERROR(SCE_KERNEL_ERROR_INVALID_UID);
}
+ ARMv7Thread& thread = static_cast(*t);
+
// push arg block onto the stack
- u32 pos = (static_cast(t.get())->SP -= argSize);
+ const u32 pos = (thread.SP -= argSize);
memcpy(vm::get_ptr(pos), pArgBlock.get_ptr(), argSize);
// set SceKernelThreadEntry function arguments
- static_cast(t.get())->write_gpr(0, argSize);
- static_cast(t.get())->write_gpr(1, pos);
+ thread.write_gpr(0, argSize);
+ thread.write_gpr(1, pos);
- t->Exec();
+ thread.Exec();
return SCE_OK;
}
@@ -208,7 +208,7 @@ s32 sceKernelChangeCurrentThreadAttr(u32 clearAttr, u32 setAttr)
s32 sceKernelGetThreadExitStatus(s32 threadId, vm::psv::ptr pExitStatus)
{
- sceLibKernel.Todo("sceKernelGetThreadExitStatus(threadId=%d, pExitStatus_addr=0x%x)", threadId, pExitStatus.addr());
+ sceLibKernel.Todo("sceKernelGetThreadExitStatus(threadId=%d, pExitStatus=0x%x)", threadId, pExitStatus);
return SCE_OK;
}
@@ -229,21 +229,21 @@ s32 sceKernelCheckWaitableStatus()
s32 sceKernelGetThreadInfo(s32 threadId, vm::psv::ptr pInfo)
{
- sceLibKernel.Todo("sceKernelGetThreadInfo(threadId=%d, pInfo_addr=0x%x)", threadId, pInfo.addr());
+ sceLibKernel.Todo("sceKernelGetThreadInfo(threadId=%d, pInfo=0x%x)", threadId, pInfo);
return SCE_OK;
}
s32 sceKernelGetThreadRunStatus(vm::psv::ptr pStatus)
{
- sceLibKernel.Todo("sceKernelGetThreadRunStatus(pStatus_addr=0x%x)", pStatus.addr());
+ sceLibKernel.Todo("sceKernelGetThreadRunStatus(pStatus=0x%x)", pStatus);
return SCE_OK;
}
s32 sceKernelGetSystemInfo(vm::psv::ptr pInfo)
{
- sceLibKernel.Todo("sceKernelGetSystemInfo(pInfo_addr=0x%x)", pInfo.addr());
+ sceLibKernel.Todo("sceKernelGetSystemInfo(pInfo=0x%x)", pInfo);
return SCE_OK;
}
@@ -285,14 +285,14 @@ s32 sceKernelDelayThreadCB(u32 usec)
s32 sceKernelWaitThreadEnd(s32 threadId, vm::psv::ptr pExitStatus, vm::psv::ptr pTimeout)
{
- sceLibKernel.Todo("sceKernelWaitThreadEnd(threadId=%d, pExitStatus_addr=0x%x, pTimeout_addr=0x%x)", threadId, pExitStatus.addr(), pTimeout.addr());
+ sceLibKernel.Todo("sceKernelWaitThreadEnd(threadId=%d, pExitStatus=0x%x, pTimeout=0x%x)", threadId, pExitStatus, pTimeout);
return SCE_OK;
}
s32 sceKernelWaitThreadEndCB(s32 threadId, vm::psv::ptr pExitStatus, vm::psv::ptr pTimeout)
{
- sceLibKernel.Todo("sceKernelWaitThreadEndCB(threadId=%d, pExitStatus_addr=0x%x, pTimeout_addr=0x%x)", threadId, pExitStatus.addr(), pTimeout.addr());
+ sceLibKernel.Todo("sceKernelWaitThreadEndCB(threadId=%d, pExitStatus=0x%x, pTimeout=0x%x)", threadId, pExitStatus, pTimeout);
return SCE_OK;
}
diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp
index a9173350a1..9abcf593e4 100644
--- a/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp
+++ b/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp
@@ -26,9 +26,9 @@ namespace sce_libc_func
});
}
- void printf(vm::psv::ptr fmt)
+ void printf(vm::psv::ptr fmt) // va_args...
{
- sceLibc.Error("printf(fmt_addr=0x%x)", fmt.addr());
+ sceLibc.Error("printf(fmt=0x%x)", fmt);
LOG_NOTICE(TTY, "%s", fmt.get_ptr());
}
@@ -40,14 +40,14 @@ namespace sce_libc_func
void memcpy(vm::psv::ptr dst, vm::psv::ptr src, u32 size)
{
- sceLibc.Error("memcpy(dst_addr=0x%x, src_addr=0x%x, size=0x%x)", dst.addr(), src.addr(), size);
+ sceLibc.Error("memcpy(dst=0x%x, src=0x%x, size=0x%x)", dst, src, size);
::memcpy(dst.get_ptr(), src.get_ptr(), size);
}
void _Assert(vm::psv::ptr text, vm::psv::ptr func)
{
- sceLibc.Error("_Assert(text_addr=0x%x, func_addr=0x%x)", text.addr(), func.addr());
+ sceLibc.Error("_Assert(text=0x%x, func=0x%x)", text, func);
LOG_ERROR(TTY, "%s : %s", func.get_ptr(), text.get_ptr());
Emu.Pause();
diff --git a/rpcs3/Emu/ARMv7/PSVFuncList.cpp b/rpcs3/Emu/ARMv7/PSVFuncList.cpp
index d1d3d2b1a6..84262b3b0f 100644
--- a/rpcs3/Emu/ARMv7/PSVFuncList.cpp
+++ b/rpcs3/Emu/ARMv7/PSVFuncList.cpp
@@ -1,4 +1,5 @@
#include "stdafx.h"
+#include
#include "Utilities/Log.h"
#include "Emu/System.h"
#include "PSVFuncList.h"
@@ -7,29 +8,19 @@ std::vector g_psv_func_list;
void add_psv_func(psv_func& data)
{
+ // setup special functions (without NIDs)
if (!g_psv_func_list.size())
{
psv_func unimplemented;
- unimplemented.nid = 0x00000000; // must not be a valid id
- unimplemented.name = "INVALID FUNCTION (0x0)";
- unimplemented.func.reset(new psv_func_detail::func_binder([]() -> u32
- {
- LOG_ERROR(HLE, "Unimplemented function executed");
- Emu.Pause();
-
- return 0xffffffffu;
- }));
+ unimplemented.nid = 0;
+ unimplemented.name = "Special function (unimplemented stub)";
+ unimplemented.func.reset(new psv_func_detail::func_binder([](ARMv7Thread& CPU){ CPU.m_last_syscall = vm::psv::read32(CPU.PC + 4); throw "Unimplemented function executed"; }));
g_psv_func_list.push_back(unimplemented);
psv_func hle_return;
- hle_return.nid = 0x00000001; // must not be a valid id
- hle_return.name = "INVALID FUNCTION (0x1)";
- hle_return.func.reset(new psv_func_detail::func_binder([](ARMv7Thread& CPU)
- {
- CPU.FastStop();
-
- return;
- }));
+ hle_return.nid = 1;
+ hle_return.name = "Special function (return from HLE)";
+ hle_return.func.reset(new psv_func_detail::func_binder([](ARMv7Thread& CPU){ CPU.FastStop(); }));
g_psv_func_list.push_back(hle_return);
}
@@ -40,7 +31,7 @@ psv_func* get_psv_func_by_nid(u32 nid)
{
for (auto& f : g_psv_func_list)
{
- if (f.nid == nid)
+ if (f.nid == nid && &f - g_psv_func_list.data() >= 2 /* special functions count */)
{
return &f;
}
@@ -61,8 +52,13 @@ u32 get_psv_func_index(psv_func* func)
void execute_psv_func_by_index(ARMv7Thread& CPU, u32 index)
{
assert(index < g_psv_func_list.size());
+
+ auto old_last_syscall = CPU.m_last_syscall;
+ CPU.m_last_syscall = g_psv_func_list[index].nid;
(*g_psv_func_list[index].func)(CPU);
+
+ CPU.m_last_syscall = old_last_syscall;
}
extern psv_log_base sceLibc;
diff --git a/rpcs3/Emu/ARMv7/PSVFuncList.h b/rpcs3/Emu/ARMv7/PSVFuncList.h
index 998225799d..9fe75a647a 100644
--- a/rpcs3/Emu/ARMv7/PSVFuncList.h
+++ b/rpcs3/Emu/ARMv7/PSVFuncList.h
@@ -425,7 +425,7 @@ namespace psv_func_detail
static __forceinline T func(ARMv7Thread& CPU)
{
- return (T&)CPU.GPR[g_count - 1];
+ return cast_from_armv7_gpr(CPU.GPR[g_count - 1]);
}
};
@@ -444,7 +444,7 @@ namespace psv_func_detail
struct bind_arg
{
static_assert(v_count <= 0, "TODO: Unsupported argument type (vector)");
- static_assert(sizeof(T) == 16, "Invalid function argument type for ARG_VECTOR");
+ static_assert(std::is_same::value, "Invalid function argument type for ARG_VECTOR");
static __forceinline T func(ARMv7Thread& CPU)
{
@@ -460,8 +460,9 @@ namespace psv_func_detail
static __forceinline T func(ARMv7Thread& CPU)
{
+ // TODO: check
const u32 res = CPU.GetStackArg(g_count);
- return (T&)res;
+ return cast_from_armv7_gpr(res);
}
};
@@ -473,9 +474,9 @@ namespace psv_func_detail
static_assert(type == ARG_GENERAL, "Wrong use of bind_result template");
static_assert(sizeof(T) <= 4, "Invalid function result type for ARG_GENERAL");
- static __forceinline void func(ARMv7Thread& CPU, T result)
+ static __forceinline void func(ARMv7Thread& CPU, const T& result)
{
- (T&)CPU.GPR[0] = result;
+ CPU.GPR[0] = cast_to_armv7_gpr(result);
}
};
@@ -484,7 +485,7 @@ namespace psv_func_detail
//{
// static_assert(sizeof(T) <= 8, "Invalid function result type for ARG_FLOAT");
- // static __forceinline void func(ARMv7Thread& CPU, T result)
+ // static __forceinline void func(ARMv7Thread& CPU, const T& result)
// {
// }
//};
@@ -492,9 +493,9 @@ namespace psv_func_detail
//template
//struct bind_result
//{
- // static_assert(sizeof(T) == 16, "Invalid function result type for ARG_VECTOR");
+ // static_assert(std::is_same::value, "Invalid function result type for ARG_VECTOR");
- // static __forceinline void func(ARMv7Thread& CPU, const T result)
+ // static __forceinline void func(ARMv7Thread& CPU, const T& result)
// {
// }
//};
@@ -518,21 +519,21 @@ namespace psv_func_detail
};
template
- static __forceinline RT call(F f, Tuple && t)
+ __forceinline RT call(F f, Tuple && t)
{
typedef typename std::decay::type ttype;
return psv_func_detail::call_impl