Merge pull request #1521 from Nekotekina/master

RPCS3 0.0.0.9 (caution: LLVM recompiler removed)
This commit is contained in:
Ivan 2016-04-16 11:10:34 +03:00
commit fe1e7a1bdb
677 changed files with 42493 additions and 71015 deletions

View file

@ -53,7 +53,7 @@ before_install:
fi; fi;
before_script: before_script:
- git submodule update --init asmjit 3rdparty/ffmpeg 3rdparty/pugixml 3rdparty/GSL 3rdparty/libpng Vulkan/glslang Vulkan/Vulkan-LoaderAndValidationLayers - git submodule update --init asmjit 3rdparty/ffmpeg 3rdparty/pugixml 3rdparty/GSL 3rdparty/libpng Vulkan/glslang Vulkan/Vulkan-LoaderAndValidationLayers Utilities/yaml-cpp
- mkdir build - mkdir build
- cd build - cd build
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then cmake ..; else cmake .. -DLLVM_DIR=/usr/local/opt/llvm36/lib/llvm-3.6/share/llvm/cmake; fi - if [ "$TRAVIS_OS_NAME" = "linux" ]; then cmake ..; else cmake .. -DLLVM_DIR=/usr/local/opt/llvm36/lib/llvm-3.6/share/llvm/cmake; fi

View file

@ -37,9 +37,11 @@ __Mac OSX__
### Building ### Building
To initialize the repository don't forget to execute `git submodule update --init` to pull the wxWidgets source. To initialize the repository don't forget to execute `git submodule update --init` to pull the submodules.
* __Windows__: * __Windows__:
Open the *.SLN* file, and press *Build* > *Clean Solution*, then *Build Solution*. *Rebuild* may not work correctly. 1) Open the *.SLN* file.
2) Build the projects in *__BUILD_BEFORE* folder: right-click on every project > *Build*.
3) Press *BUILD* > *Build Solution* or *Rebuild Solution*.
* __Linux & Mac OSX__: * __Linux & Mac OSX__:
If you want to build with LLVM, then LLVM 3.6.2 is required. If you want to build with LLVM, then LLVM 3.6.2 is required.
`cd rpcs3 && cmake CMakeLists.txt && make && cd ../` then run with `cd bin && ./rpcs3`. `cd rpcs3 && cmake CMakeLists.txt && make && cd ../` then run with `cd bin && ./rpcs3`.

File diff suppressed because it is too large Load diff

View file

@ -1,57 +1,29 @@
#include "stdafx.h" #include "stdafx.h"
#include "AutoPause.h" #include "Config.h"
#include "Utilities/Log.h"
#include "Utilities/File.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/state.h" #include "AutoPause.h"
using namespace Debug; cfg::bool_entry g_cfg_debug_autopause_syscall(cfg::root.misc, "Auto Pause at System Call");
cfg::bool_entry g_cfg_debug_autopause_func_call(cfg::root.misc, "Auto Pause at Function Call");
std::unique_ptr<AutoPause> g_autopause; debug::autopause& debug::autopause::get_instance()
AutoPause& AutoPause::getInstance(void)
{ {
if (!g_autopause) // Use magic static
static autopause instance;
return instance;
}
// Load Auto Pause Configuration from file "pause.bin"
void debug::autopause::reload(void)
{
auto& instance = get_instance();
instance.m_pause_function.clear();
instance.m_pause_syscall.clear();
// TODO: better format, possibly a config entry
if (fs::file list{ fs::get_config_dir() + "pause.bin" })
{ {
g_autopause.reset(new AutoPause);
}
return *g_autopause;
}
//Still use binary format. Default Setting should be "disable all auto pause".
AutoPause::AutoPause(void)
{
m_pause_function.reserve(16);
m_pause_syscall.reserve(16);
initialized = false;
//Reload(false, false);
Reload();
}
//Notice: I would not allow to write the binary to file in this command.
AutoPause::~AutoPause(void)
{
initialized = false;
m_pause_function.clear();
m_pause_syscall.clear();
m_pause_function_enable = false;
m_pause_syscall_enable = false;
}
//Load Auto Pause Configuration from file "pause.bin"
//This would be able to create in a GUI window.
void AutoPause::Reload(void)
{
if (fs::is_file(fs::get_config_dir() + "pause.bin"))
{
m_pause_function.clear();
m_pause_function.reserve(16);
m_pause_syscall.clear();
m_pause_syscall.reserve(16);
fs::file list(fs::get_config_dir() + "pause.bin");
//System calls ID and Function calls ID are all u32 iirc.
u32 num; u32 num;
size_t fmax = list.size(); size_t fmax = list.size();
size_t fcur = 0; size_t fcur = 0;
@ -64,60 +36,38 @@ void AutoPause::Reload(void)
if (num < 1024) if (num < 1024)
{ {
//Less than 1024 - be regarded as a system call. instance.m_pause_syscall.emplace(num);
//emplace_back may not cause reductant move/copy operation. LOG_WARNING(HLE, "Set autopause at syscall %lld", num);
m_pause_syscall.emplace_back(num);
LOG_WARNING(HLE, "Auto Pause: Find System Call ID 0x%x", num);
} }
else else
{ {
m_pause_function.emplace_back(num); instance.m_pause_function.emplace(num);
LOG_WARNING(HLE, "Auto Pause: Find Function Call ID 0x%x", num); LOG_WARNING(HLE, "Set autopause at function 0x%08x", num);
} }
} }
} }
m_pause_syscall_enable = rpcs3::config.misc.debug.auto_pause_syscall.value();
m_pause_function_enable = rpcs3::config.misc.debug.auto_pause_func_call.value();
initialized = true;
} }
void AutoPause::TryPause(u32 code) bool debug::autopause::pause_syscall(u64 code)
{ {
if (code < 1024) if (g_cfg_debug_autopause_syscall && get_instance().m_pause_syscall.count(code) != 0)
{ {
//Would first check Enable setting. Then the list length. Emu.Pause();
if ((!m_pause_syscall_enable) LOG_SUCCESS(HLE, "Autopause triggered at syscall %lld", code);
|| (m_pause_syscall.size() <= 0)) return true;
{
return;
}
for (u32 i = 0; i < m_pause_syscall.size(); ++i)
{
if (code == m_pause_syscall[i])
{
Emu.Pause();
LOG_ERROR(HLE, "Auto Pause Triggered: System call 0x%x", code); // Used Error
}
}
} }
else
{
//Well similiar.. Seperate the list caused by possible setting difference.
if ((!m_pause_function_enable)
|| (m_pause_function.size() <= 0))
{
return;
}
for (u32 i = 0; i < m_pause_function.size(); ++i) return false;
{ }
if (code == m_pause_function[i])
{ bool debug::autopause::pause_function(u32 code)
Emu.Pause(); {
LOG_ERROR(HLE, "Auto Pause Triggered: Function call 0x%x", code); // Used Error if (g_cfg_debug_autopause_func_call && get_instance().m_pause_function.count(code) != 0)
} {
} Emu.Pause();
} LOG_SUCCESS(HLE, "Autopause triggered at function 0x%08x", code);
return true;
}
return false;
} }

View file

@ -1,24 +1,20 @@
#pragma once #pragma once
//Regarded as a Debugger Enchantment // Regarded as a Debugger Enchantment
namespace Debug { namespace debug
//To store the pause function/call id, and let those pause there. {
//Would be with a GUI to configure those. // To store the pause function/call id, and let those pause there.
struct AutoPause // Would be with a GUI to configure those.
class autopause
{ {
std::vector<u32> m_pause_syscall; std::unordered_set<u64> m_pause_syscall;
std::vector<u32> m_pause_function; std::unordered_set<u32> m_pause_function;
bool initialized;
bool m_pause_syscall_enable;
bool m_pause_function_enable;
AutoPause(); static autopause& get_instance();
~AutoPause();
public: public:
static AutoPause& getInstance(void);
void Reload(void); static void reload();
static bool pause_syscall(u64 code);
void TryPause(u32 code); static bool pause_function(u32 code);
}; };
} }

View file

@ -1,16 +1,14 @@
#pragma once #pragma once
#ifdef _MSC_VER #include "types.h"
#include <intrin.h> #include "Platform.h"
#else
#include <x86intrin.h>
#endif
#define IS_LE_MACHINE // only draft union alignas(16) v128
union v128
{ {
template<typename T, std::size_t N, std::size_t M> class masked_array_t // array type accessed as (index ^ M) char _bytes[16];
template<typename T, std::size_t N, std::size_t M>
struct masked_array_t // array type accessed as (index ^ M)
{ {
T m_data[N]; T m_data[N];
@ -24,24 +22,11 @@ union v128
{ {
return m_data[index ^ M]; return m_data[index ^ M];
} }
T& at(std::size_t index)
{
return (index ^ M) < N ? m_data[index ^ M] : throw std::out_of_range(__FUNCTION__);
}
const T& at(std::size_t index) const
{
return (index ^ M) < N ? m_data[index ^ M] : throw std::out_of_range(__FUNCTION__);
}
}; };
#ifdef IS_LE_MACHINE #if IS_LE_MACHINE == 1
template<typename T, std::size_t N = 16 / sizeof(T)> using normal_array_t = masked_array_t<T, N, 0>; template<typename T, std::size_t N = 16 / sizeof(T)> using normal_array_t = masked_array_t<T, N, 0>;
template<typename T, std::size_t N = 16 / sizeof(T)> using reversed_array_t = masked_array_t<T, N, N - 1>; template<typename T, std::size_t N = 16 / sizeof(T)> using reversed_array_t = masked_array_t<T, N, N - 1>;
#else
template<typename T, std::size_t N = 16 / sizeof(T)> using normal_array_t = masked_array_t<T, N, N - 1>;
template<typename T, std::size_t N = 16 / sizeof(T)> using reversed_array_t = masked_array_t<T, N, 0>;
#endif #endif
normal_array_t<u64> _u64; normal_array_t<u64> _u64;
@ -73,7 +58,7 @@ union v128
__m128i vi; __m128i vi;
__m128d vd; __m128d vd;
class bit_array_128 struct bit_array_128
{ {
u64 m_data[2]; u64 m_data[2];
@ -125,36 +110,18 @@ union v128
// Index 0 returns the MSB and index 127 returns the LSB // Index 0 returns the MSB and index 127 returns the LSB
bit_element operator [](u32 index) bit_element operator [](u32 index)
{ {
#ifdef IS_LE_MACHINE #if IS_LE_MACHINE == 1
return bit_element(m_data[1 - (index >> 6)], 0x8000000000000000ull >> (index & 0x3F)); return bit_element(m_data[1 - (index >> 6)], 0x8000000000000000ull >> (index & 0x3F));
#else
return bit_element(m_data[index >> 6], 0x8000000000000000ull >> (index & 0x3F));
#endif #endif
} }
// Index 0 returns the MSB and index 127 returns the LSB // Index 0 returns the MSB and index 127 returns the LSB
bool operator [](u32 index) const bool operator [](u32 index) const
{ {
#ifdef IS_LE_MACHINE #if IS_LE_MACHINE == 1
return (m_data[1 - (index >> 6)] & (0x8000000000000000ull >> (index & 0x3F))) != 0; return (m_data[1 - (index >> 6)] & (0x8000000000000000ull >> (index & 0x3F))) != 0;
#else
return (m_data[index >> 6] & (0x8000000000000000ull >> (index & 0x3F))) != 0;
#endif #endif
} }
bit_element at(u32 index)
{
if (index >= 128) throw std::out_of_range(__FUNCTION__);
return operator[](index);
}
bool at(u32 index) const
{
if (index >= 128) throw std::out_of_range(__FUNCTION__);
return operator[](index);
}
} }
_bit; _bit;
@ -320,16 +287,6 @@ union v128
return _u64[0] != right._u64[0] || _u64[1] != right._u64[1]; return _u64[0] != right._u64[0] || _u64[1] != right._u64[1];
} }
bool is_any_1() const // check if any bit is 1
{
return _u64[0] || _u64[1];
}
bool is_any_0() const // check if any bit is 0
{
return ~_u64[0] || ~_u64[1];
}
// result = (~left) & (right) // result = (~left) & (right)
static inline v128 andnot(const v128& left, const v128& right) static inline v128 andnot(const v128& left, const v128& right)
{ {
@ -345,15 +302,8 @@ union v128
std::string to_hex() const; std::string to_hex() const;
std::string to_xyzw() const; std::string to_xyzw() const;
static inline v128 byteswap(const v128 val)
{
return fromV(_mm_shuffle_epi8(val.vi, _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)));
}
}; };
CHECK_SIZE_ALIGN(v128, 16, 16);
inline v128 operator |(const v128& left, const v128& right) inline v128 operator |(const v128& left, const v128& right)
{ {
return v128::fromV(_mm_or_si128(left.vi, right.vi)); return v128::fromV(_mm_or_si128(left.vi, right.vi));
@ -374,21 +324,21 @@ inline v128 operator ~(const v128& other)
return v128::from64(~other._u64[0], ~other._u64[1]); return v128::from64(~other._u64[0], ~other._u64[1]);
} }
template<typename T, std::size_t Size = sizeof(T)> struct se_storage #define IS_INTEGER(t) (std::is_integral<t>::value || std::is_enum<t>::value)
#define IS_BINARY_COMPARABLE(t1, t2) (IS_INTEGER(t1) && IS_INTEGER(t2) && sizeof(t1) == sizeof(t2))
template<typename T, std::size_t Size = sizeof(T)>
struct se_storage
{ {
static_assert(!Size, "Bad se_storage<> type"); static_assert(!Size, "Bad se_storage<> type");
}; };
template<typename T> struct se_storage<T, 2> template<typename T>
struct se_storage<T, 2>
{ {
using type = u16; using type = u16;
[[deprecated]] static constexpr u16 _swap(u16 src) // for reference static constexpr u16 swap(u16 src)
{
return (src >> 8) | (src << 8);
}
static inline u16 swap(u16 src)
{ {
#if defined(__GNUG__) #if defined(__GNUG__)
return __builtin_bswap16(src); return __builtin_bswap16(src);
@ -409,16 +359,12 @@ template<typename T> struct se_storage<T, 2>
} }
}; };
template<typename T> struct se_storage<T, 4> template<typename T>
struct se_storage<T, 4>
{ {
using type = u32; using type = u32;
[[deprecated]] static constexpr u32 _swap(u32 src) // for reference static constexpr u32 swap(u32 src)
{
return (src >> 24) | (src << 24) | ((src >> 8) & 0x0000ff00) | ((src << 8) & 0x00ff0000);
}
static inline u32 swap(u32 src)
{ {
#if defined(__GNUG__) #if defined(__GNUG__)
return __builtin_bswap32(src); return __builtin_bswap32(src);
@ -439,22 +385,12 @@ template<typename T> struct se_storage<T, 4>
} }
}; };
template<typename T> struct se_storage<T, 8> template<typename T>
struct se_storage<T, 8>
{ {
using type = u64; using type = u64;
[[deprecated]] static constexpr u64 _swap(u64 src) // for reference static constexpr u64 swap(u64 src)
{
return (src >> 56) | (src << 56) |
((src >> 40) & 0x000000000000ff00) |
((src >> 24) & 0x0000000000ff0000) |
((src >> 8) & 0x00000000ff000000) |
((src << 8) & 0x000000ff00000000) |
((src << 24) & 0x0000ff0000000000) |
((src << 40) & 0x00ff000000000000);
}
static inline u64 swap(u64 src)
{ {
#if defined(__GNUG__) #if defined(__GNUG__)
return __builtin_bswap64(src); return __builtin_bswap64(src);
@ -475,25 +411,32 @@ template<typename T> struct se_storage<T, 8>
} }
}; };
template<typename T> struct se_storage<T, 16> template<typename T>
struct se_storage<T, 16>
{ {
using type = v128; using type = v128;
static inline v128 swap(const v128& src)
{
return v128::fromV(_mm_shuffle_epi8(src.vi, _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)));
}
static inline v128 to(const T& src) static inline v128 to(const T& src)
{ {
return v128::byteswap(reinterpret_cast<const v128&>(src)); return swap(reinterpret_cast<const v128&>(src));
} }
static inline T from(const v128& src) static inline T from(const v128& src)
{ {
const v128 result = v128::byteswap(src); const v128 result = swap(src);
return reinterpret_cast<const T&>(result); return reinterpret_cast<const T&>(result);
} }
}; };
template<typename T> using se_storage_t = typename se_storage<T>::type; template<typename T> using se_storage_t = typename se_storage<T>::type;
template<typename T1, typename T2> struct se_convert template<typename T1, typename T2>
struct se_convert
{ {
using type_from = std::remove_cv_t<T1>; using type_from = std::remove_cv_t<T1>;
using type_to = std::remove_cv_t<T2>; using type_to = std::remove_cv_t<T2>;
@ -515,10 +458,12 @@ template<typename T1, typename T2> struct se_convert
static struct se_raw_tag_t {} constexpr se_raw{}; static struct se_raw_tag_t {} constexpr se_raw{};
template<typename T, bool Se = true> class se_t; template<typename T, bool Se = true>
class se_t;
// se_t with switched endianness // Switched endianness
template<typename T> class se_t<T, true> template<typename T>
class se_t<T, true>
{ {
using type = typename std::remove_cv<T>::type; using type = typename std::remove_cv<T>::type;
using stype = se_storage_t<type>; using stype = se_storage_t<type>;
@ -526,14 +471,13 @@ template<typename T> class se_t<T, true>
stype m_data; stype m_data;
static_assert(!std::is_union<type>::value && !std::is_class<type>::value || std::is_same<type, v128>::value || std::is_same<type, u128>::value, "se_t<> error: invalid type (struct or union)");
static_assert(!std::is_pointer<type>::value, "se_t<> error: invalid type (pointer)"); static_assert(!std::is_pointer<type>::value, "se_t<> error: invalid type (pointer)");
static_assert(!std::is_reference<type>::value, "se_t<> error: invalid type (reference)"); static_assert(!std::is_reference<type>::value, "se_t<> error: invalid type (reference)");
static_assert(!std::is_array<type>::value, "se_t<> error: invalid type (array)"); static_assert(!std::is_array<type>::value, "se_t<> error: invalid type (array)");
//static_assert(!std::is_enum<type>::value, "se_t<> error: invalid type (enumeration), use integral type instead"); static_assert(sizeof(type) == alignof(type), "se_t<> error: unexpected alignment");
static_assert(alignof(type) == alignof(stype), "se_t<> error: unexpected alignment");
template<typename T2, typename = void> struct bool_converter template<typename T2, typename = void>
struct bool_converter
{ {
static inline bool to_bool(const se_t<T2>& value) static inline bool to_bool(const se_t<T2>& value)
{ {
@ -541,7 +485,8 @@ template<typename T> class se_t<T, true>
} }
}; };
template<typename T2> struct bool_converter<T2, std::enable_if_t<std::is_integral<T2>::value>> template<typename T2>
struct bool_converter<T2, std::enable_if_t<std::is_integral<T2>::value>>
{ {
static inline bool to_bool(const se_t<T2>& value) static inline bool to_bool(const se_t<T2>& value)
{ {
@ -559,7 +504,7 @@ public:
{ {
} }
// construct directly from raw data (don't use) // Construct directly from raw data (don't use)
constexpr se_t(const stype& raw_value, const se_raw_tag_t&) constexpr se_t(const stype& raw_value, const se_raw_tag_t&)
: m_data(raw_value) : m_data(raw_value)
{ {
@ -570,7 +515,7 @@ public:
return storage::from(m_data); return storage::from(m_data);
} }
// access underlying raw data (don't use) // Access underlying raw data (don't use)
constexpr const stype& raw_data() const noexcept constexpr const stype& raw_data() const noexcept
{ {
return m_data; return m_data;
@ -583,78 +528,96 @@ public:
return m_data = storage::to(value), *this; return m_data = storage::to(value), *this;
} }
using simple_type = simple_t<T>;
operator type() const operator type() const
{ {
return storage::from(m_data); return storage::from(m_data);
} }
// optimization // Optimization
explicit operator bool() const explicit operator bool() const
{ {
return bool_converter<type>::to_bool(*this); return bool_converter<type>::to_bool(*this);
} }
// optimization // Optimization
template<typename T2> std::enable_if_t<IS_BINARY_COMPARABLE(T, T2), se_t&> operator &=(const se_t<T2>& right) template<typename T2>
std::enable_if_t<IS_BINARY_COMPARABLE(T, T2), se_t&> operator &=(const se_t<T2>& right)
{ {
return m_data &= right.raw_data(), *this; return m_data &= right.raw_data(), *this;
} }
// optimization // Optimization
template<typename CT> std::enable_if_t<IS_INTEGRAL(T) && std::is_convertible<CT, T>::value, se_t&> operator &=(CT right) template<typename CT>
std::enable_if_t<std::is_integral<T>::value && std::is_convertible<CT, T>::value, se_t&> operator &=(CT right)
{ {
return m_data &= storage::to(right), *this; return m_data &= storage::to(right), *this;
} }
// optimization // Optimization
template<typename T2> std::enable_if_t<IS_BINARY_COMPARABLE(T, T2), se_t&> operator |=(const se_t<T2>& right) template<typename T2>
std::enable_if_t<IS_BINARY_COMPARABLE(T, T2), se_t&> operator |=(const se_t<T2>& right)
{ {
return m_data |= right.raw_data(), *this; return m_data |= right.raw_data(), *this;
} }
// optimization // Optimization
template<typename CT> std::enable_if_t<IS_INTEGRAL(T) && std::is_convertible<CT, T>::value, se_t&> operator |=(CT right) template<typename CT>
std::enable_if_t<std::is_integral<T>::value && std::is_convertible<CT, T>::value, se_t&> operator |=(CT right)
{ {
return m_data |= storage::to(right), *this; return m_data |= storage::to(right), *this;
} }
// optimization // Optimization
template<typename T2> std::enable_if_t<IS_BINARY_COMPARABLE(T, T2), se_t&> operator ^=(const se_t<T2>& right) template<typename T2>
std::enable_if_t<IS_BINARY_COMPARABLE(T, T2), se_t&> operator ^=(const se_t<T2>& right)
{ {
return m_data ^= right.raw_data(), *this; return m_data ^= right.raw_data(), *this;
} }
// optimization // Optimization
template<typename CT> std::enable_if_t<IS_INTEGRAL(T) && std::is_convertible<CT, T>::value, se_t&> operator ^=(CT right) template<typename CT>
std::enable_if_t<std::is_integral<T>::value && std::is_convertible<CT, T>::value, se_t&> operator ^=(CT right)
{ {
return m_data ^= storage::to(right), *this; return m_data ^= storage::to(right), *this;
} }
}; };
// se_t with native endianness // Native endianness
template<typename T> class se_t<T, false> template<typename T>
class se_t<T, false>
{ {
using type = typename std::remove_cv<T>::type; using type = typename std::remove_cv<T>::type;
type m_data;
static_assert(!std::is_union<type>::value && !std::is_class<type>::value || std::is_same<type, v128>::value || std::is_same<type, u128>::value, "se_t<> error: invalid type (struct or union)");
static_assert(!std::is_pointer<type>::value, "se_t<> error: invalid type (pointer)"); static_assert(!std::is_pointer<type>::value, "se_t<> error: invalid type (pointer)");
static_assert(!std::is_reference<type>::value, "se_t<> error: invalid type (reference)"); static_assert(!std::is_reference<type>::value, "se_t<> error: invalid type (reference)");
static_assert(!std::is_array<type>::value, "se_t<> error: invalid type (array)"); static_assert(!std::is_array<type>::value, "se_t<> error: invalid type (array)");
//static_assert(!std::is_enum<type>::value, "se_t<> error: invalid type (enumeration), use integral type instead"); static_assert(sizeof(type) == alignof(type), "se_t<> error: unexpected alignment");
type m_data;
public: public:
se_t() = default; se_t() = default;
se_t(const se_t&) = default;
constexpr se_t(type value) constexpr se_t(type value)
: m_data(value) : m_data(value)
{ {
} }
type value() const // Construct directly from raw data (don't use)
constexpr se_t(const type& raw_value, const se_raw_tag_t&)
: m_data(raw_value)
{
}
constexpr type value() const
{
return m_data;
}
// Access underlying raw data (don't use)
constexpr const type& raw_data() const noexcept
{ {
return m_data; return m_data;
} }
@ -666,22 +629,27 @@ public:
return m_data = value, *this; return m_data = value, *this;
} }
operator type() const using simple_type = simple_t<T>;
constexpr operator type() const
{ {
return m_data; return m_data;
} }
template<typename CT> std::enable_if_t<IS_INTEGRAL(T) && std::is_convertible<CT, T>::value, se_t&> operator &=(const CT& right) template<typename CT>
std::enable_if_t<std::is_integral<T>::value && std::is_convertible<CT, T>::value, se_t&> operator &=(const CT& right)
{ {
return m_data &= right, *this; return m_data &= right, *this;
} }
template<typename CT> std::enable_if_t<IS_INTEGRAL(T) && std::is_convertible<CT, T>::value, se_t&> operator |=(const CT& right) template<typename CT>
std::enable_if_t<std::is_integral<T>::value && std::is_convertible<CT, T>::value, se_t&> operator |=(const CT& right)
{ {
return m_data |= right, *this; return m_data |= right, *this;
} }
template<typename CT> std::enable_if_t<IS_INTEGRAL(T) && std::is_convertible<CT, T>::value, se_t&> operator ^=(const CT& right) template<typename CT>
std::enable_if_t<std::is_integral<T>::value && std::is_convertible<CT, T>::value, se_t&> operator ^=(const CT& right)
{ {
return m_data ^= right, *this; return m_data ^= right, *this;
} }
@ -690,49 +658,57 @@ public:
// se_t with native endianness (alias) // se_t with native endianness (alias)
template<typename T> using nse_t = se_t<T, false>; template<typename T> using nse_t = se_t<T, false>;
template<typename T, bool Se, typename T1> inline se_t<T, Se>& operator +=(se_t<T, Se>& left, const T1& right) template<typename T, bool Se, typename T1>
inline se_t<T, Se>& operator +=(se_t<T, Se>& left, const T1& right)
{ {
auto value = left.value(); auto value = left.value();
return left = (value += right); return left = (value += right);
} }
template<typename T, bool Se, typename T1> inline se_t<T, Se>& operator -=(se_t<T, Se>& left, const T1& right) template<typename T, bool Se, typename T1>
inline se_t<T, Se>& operator -=(se_t<T, Se>& left, const T1& right)
{ {
auto value = left.value(); auto value = left.value();
return left = (value -= right); return left = (value -= right);
} }
template<typename T, bool Se, typename T1> inline se_t<T, Se>& operator *=(se_t<T, Se>& left, const T1& right) template<typename T, bool Se, typename T1>
inline se_t<T, Se>& operator *=(se_t<T, Se>& left, const T1& right)
{ {
auto value = left.value(); auto value = left.value();
return left = (value *= right); return left = (value *= right);
} }
template<typename T, bool Se, typename T1> inline se_t<T, Se>& operator /=(se_t<T, Se>& left, const T1& right) template<typename T, bool Se, typename T1>
inline se_t<T, Se>& operator /=(se_t<T, Se>& left, const T1& right)
{ {
auto value = left.value(); auto value = left.value();
return left = (value /= right); return left = (value /= right);
} }
template<typename T, bool Se, typename T1> inline se_t<T, Se>& operator %=(se_t<T, Se>& left, const T1& right) template<typename T, bool Se, typename T1>
inline se_t<T, Se>& operator %=(se_t<T, Se>& left, const T1& right)
{ {
auto value = left.value(); auto value = left.value();
return left = (value %= right); return left = (value %= right);
} }
template<typename T, bool Se, typename T1> inline se_t<T, Se>& operator <<=(se_t<T, Se>& left, const T1& right) template<typename T, bool Se, typename T1>
inline se_t<T, Se>& operator <<=(se_t<T, Se>& left, const T1& right)
{ {
auto value = left.value(); auto value = left.value();
return left = (value <<= right); return left = (value <<= right);
} }
template<typename T, bool Se, typename T1> inline se_t<T, Se>& operator >>=(se_t<T, Se>& left, const T1& right) template<typename T, bool Se, typename T1>
inline se_t<T, Se>& operator >>=(se_t<T, Se>& left, const T1& right)
{ {
auto value = left.value(); auto value = left.value();
return left = (value >>= right); return left = (value >>= right);
} }
template<typename T, bool Se> inline se_t<T, Se> operator ++(se_t<T, Se>& left, int) template<typename T, bool Se>
inline se_t<T, Se> operator ++(se_t<T, Se>& left, int)
{ {
auto value = left.value(); auto value = left.value();
auto result = value++; auto result = value++;
@ -740,7 +716,8 @@ template<typename T, bool Se> inline se_t<T, Se> operator ++(se_t<T, Se>& left,
return result; return result;
} }
template<typename T, bool Se> inline se_t<T, Se> operator --(se_t<T, Se>& left, int) template<typename T, bool Se>
inline se_t<T, Se> operator --(se_t<T, Se>& left, int)
{ {
auto value = left.value(); auto value = left.value();
auto result = value--; auto result = value--;
@ -748,193 +725,205 @@ template<typename T, bool Se> inline se_t<T, Se> operator --(se_t<T, Se>& left,
return result; return result;
} }
template<typename T, bool Se> inline se_t<T, Se>& operator ++(se_t<T, Se>& right) template<typename T, bool Se>
inline se_t<T, Se>& operator ++(se_t<T, Se>& right)
{ {
auto value = right.value(); auto value = right.value();
return right = ++value; return right = ++value;
} }
template<typename T, bool Se> inline se_t<T, Se>& operator --(se_t<T, Se>& right) template<typename T, bool Se>
inline se_t<T, Se>& operator --(se_t<T, Se>& right)
{ {
auto value = right.value(); auto value = right.value();
return right = --value; return right = --value;
} }
// optimization // Optimization
template<typename T1, typename T2> inline std::enable_if_t<IS_BINARY_COMPARABLE(T1, T2), bool> operator ==(const se_t<T1>& left, const se_t<T2>& right) template<typename T1, typename T2>
inline std::enable_if_t<IS_BINARY_COMPARABLE(T1, T2), bool> operator ==(const se_t<T1>& left, const se_t<T2>& right)
{ {
return left.raw_data() == right.raw_data(); return left.raw_data() == right.raw_data();
} }
// optimization // Optimization
template<typename T1, typename T2> inline std::enable_if_t<IS_INTEGRAL(T1) && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2), bool> operator ==(const se_t<T1>& left, T2 right) template<typename T1, typename T2>
inline std::enable_if_t<std::is_integral<T1>::value && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2), bool> operator ==(const se_t<T1>& left, T2 right)
{ {
return left.raw_data() == se_storage<T1>::to(right); return left.raw_data() == se_storage<T1>::to(right);
} }
// optimization // Optimization
template<typename T1, typename T2> inline std::enable_if_t<IS_INTEGER(T1) && IS_INTEGRAL(T2) && sizeof(T1) <= sizeof(T2), bool> operator ==(T1 left, const se_t<T2>& right) template<typename T1, typename T2>
inline std::enable_if_t<IS_INTEGER(T1) && std::is_integral<T2>::value && sizeof(T1) <= sizeof(T2), bool> operator ==(T1 left, const se_t<T2>& right)
{ {
return se_storage<T2>::to(left) == right.raw_data(); return se_storage<T2>::to(left) == right.raw_data();
} }
// optimization // Optimization
template<typename T1, typename T2> inline std::enable_if_t<IS_BINARY_COMPARABLE(T1, T2), bool> operator !=(const se_t<T1>& left, const se_t<T2>& right) template<typename T1, typename T2>
inline std::enable_if_t<IS_BINARY_COMPARABLE(T1, T2), bool> operator !=(const se_t<T1>& left, const se_t<T2>& right)
{ {
return left.raw_data() != right.raw_data(); return left.raw_data() != right.raw_data();
} }
// optimization // Optimization
template<typename T1, typename T2> inline std::enable_if_t<IS_INTEGRAL(T1) && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2), bool> operator !=(const se_t<T1>& left, T2 right) template<typename T1, typename T2>
inline std::enable_if_t<std::is_integral<T1>::value && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2), bool> operator !=(const se_t<T1>& left, T2 right)
{ {
return left.raw_data() != se_storage<T1>::to(right); return left.raw_data() != se_storage<T1>::to(right);
} }
// optimization // Optimization
template<typename T1, typename T2> inline std::enable_if_t<IS_INTEGER(T1) && IS_INTEGRAL(T2) && sizeof(T1) <= sizeof(T2), bool> operator !=(T1 left, const se_t<T2>& right) template<typename T1, typename T2>
inline std::enable_if_t<IS_INTEGER(T1) && std::is_integral<T2>::value && sizeof(T1) <= sizeof(T2), bool> operator !=(T1 left, const se_t<T2>& right)
{ {
return se_storage<T2>::to(left) != right.raw_data(); return se_storage<T2>::to(left) != right.raw_data();
} }
// optimization // Optimization
template<typename T1, typename T2> inline std::enable_if_t<IS_BINARY_COMPARABLE(T1, T2) && sizeof(T1) >= 4, se_t<decltype(T1() & T2())>> operator &(const se_t<T1>& left, const se_t<T2>& right) template<typename T1, typename T2>
inline std::enable_if_t<IS_BINARY_COMPARABLE(T1, T2) && sizeof(T1) >= 4, se_t<decltype(T1() & T2())>> operator &(const se_t<T1>& left, const se_t<T2>& right)
{ {
return{ left.raw_data() & right.raw_data(), se_raw }; return{ left.raw_data() & right.raw_data(), se_raw };
} }
// optimization // Optimization
template<typename T1, typename T2> inline std::enable_if_t<IS_INTEGRAL(T1) && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2) && sizeof(T1) >= 4, se_t<decltype(T1() & T2())>> operator &(const se_t<T1>& left, T2 right) template<typename T1, typename T2>
inline std::enable_if_t<std::is_integral<T1>::value && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2) && sizeof(T1) >= 4, se_t<decltype(T1() & T2())>> operator &(const se_t<T1>& left, T2 right)
{ {
return{ left.raw_data() & se_storage<T1>::to(right), se_raw }; return{ left.raw_data() & se_storage<T1>::to(right), se_raw };
} }
// optimization // Optimization
template<typename T1, typename T2> inline std::enable_if_t<IS_INTEGER(T1) && IS_INTEGRAL(T2) && sizeof(T1) <= sizeof(T2) && sizeof(T2) >= 4, se_t<decltype(T1() & T2())>> operator &(T1 left, const se_t<T2>& right) template<typename T1, typename T2>
inline std::enable_if_t<IS_INTEGER(T1) && std::is_integral<T2>::value && sizeof(T1) <= sizeof(T2) && sizeof(T2) >= 4, se_t<decltype(T1() & T2())>> operator &(T1 left, const se_t<T2>& right)
{ {
return{ se_storage<T2>::to(left) & right.raw_data(), se_raw }; return{ se_storage<T2>::to(left) & right.raw_data(), se_raw };
} }
// optimization // Optimization
template<typename T1, typename T2> inline std::enable_if_t<IS_BINARY_COMPARABLE(T1, T2) && sizeof(T1) >= 4, se_t<decltype(T1() | T2())>> operator |(const se_t<T1>& left, const se_t<T2>& right) template<typename T1, typename T2>
inline std::enable_if_t<IS_BINARY_COMPARABLE(T1, T2) && sizeof(T1) >= 4, se_t<decltype(T1() | T2())>> operator |(const se_t<T1>& left, const se_t<T2>& right)
{ {
return{ left.raw_data() | right.raw_data(), se_raw }; return{ left.raw_data() | right.raw_data(), se_raw };
} }
// optimization // Optimization
template<typename T1, typename T2> inline std::enable_if_t<IS_INTEGRAL(T1) && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2) && sizeof(T1) >= 4, se_t<decltype(T1() | T2())>> operator |(const se_t<T1>& left, T2 right) template<typename T1, typename T2>
inline std::enable_if_t<std::is_integral<T1>::value && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2) && sizeof(T1) >= 4, se_t<decltype(T1() | T2())>> operator |(const se_t<T1>& left, T2 right)
{ {
return{ left.raw_data() | se_storage<T1>::to(right), se_raw }; return{ left.raw_data() | se_storage<T1>::to(right), se_raw };
} }
// optimization // Optimization
template<typename T1, typename T2> inline std::enable_if_t<IS_INTEGER(T1) && IS_INTEGRAL(T2) && sizeof(T1) <= sizeof(T2) && sizeof(T2) >= 4, se_t<decltype(T1() | T2())>> operator |(T1 left, const se_t<T2>& right) template<typename T1, typename T2>
inline std::enable_if_t<IS_INTEGER(T1) && std::is_integral<T2>::value && sizeof(T1) <= sizeof(T2) && sizeof(T2) >= 4, se_t<decltype(T1() | T2())>> operator |(T1 left, const se_t<T2>& right)
{ {
return{ se_storage<T2>::to(left) | right.raw_data(), se_raw }; return{ se_storage<T2>::to(left) | right.raw_data(), se_raw };
} }
// optimization // Optimization
template<typename T1, typename T2> inline std::enable_if_t<IS_BINARY_COMPARABLE(T1, T2) && sizeof(T1) >= 4, se_t<decltype(T1() ^ T2())>> operator ^(const se_t<T1>& left, const se_t<T2>& right) template<typename T1, typename T2>
inline std::enable_if_t<IS_BINARY_COMPARABLE(T1, T2) && sizeof(T1) >= 4, se_t<decltype(T1() ^ T2())>> operator ^(const se_t<T1>& left, const se_t<T2>& right)
{ {
return{ left.raw_data() ^ right.raw_data(), se_raw }; return{ left.raw_data() ^ right.raw_data(), se_raw };
} }
// optimization // Optimization
template<typename T1, typename T2> inline std::enable_if_t<IS_INTEGRAL(T1) && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2) && sizeof(T1) >= 4, se_t<decltype(T1() ^ T2())>> operator ^(const se_t<T1>& left, T2 right) template<typename T1, typename T2>
inline std::enable_if_t<std::is_integral<T1>::value && IS_INTEGER(T2) && sizeof(T1) >= sizeof(T2) && sizeof(T1) >= 4, se_t<decltype(T1() ^ T2())>> operator ^(const se_t<T1>& left, T2 right)
{ {
return{ left.raw_data() ^ se_storage<T1>::to(right), se_raw }; return{ left.raw_data() ^ se_storage<T1>::to(right), se_raw };
} }
// optimization // Optimization
template<typename T1, typename T2> inline std::enable_if_t<IS_INTEGER(T1) && IS_INTEGRAL(T2) && sizeof(T1) <= sizeof(T2) && sizeof(T2) >= 4, se_t<decltype(T1() ^ T2())>> operator ^(T1 left, const se_t<T2>& right) template<typename T1, typename T2>
inline std::enable_if_t<IS_INTEGER(T1) && std::is_integral<T2>::value && sizeof(T1) <= sizeof(T2) && sizeof(T2) >= 4, se_t<decltype(T1() ^ T2())>> operator ^(T1 left, const se_t<T2>& right)
{ {
return{ se_storage<T2>::to(left) ^ right.raw_data(), se_raw }; return{ se_storage<T2>::to(left) ^ right.raw_data(), se_raw };
} }
// optimization // Optimization
template<typename T> inline std::enable_if_t<IS_INTEGRAL(T) && sizeof(T) >= 4, se_t<decltype(~T())>> operator ~(const se_t<T>& right) template<typename T>
inline std::enable_if_t<std::is_integral<T>::value && sizeof(T) >= 4, se_t<decltype(~T())>> operator ~(const se_t<T>& right)
{ {
return{ ~right.raw_data(), se_raw }; return{ ~right.raw_data(), se_raw };
} }
#ifdef IS_LE_MACHINE #if IS_LE_MACHINE == 1
template<typename T> using be_t = se_t<T, true>; template<typename T> using be_t = se_t<T, true>;
template<typename T> using le_t = se_t<T, false>; template<typename T> using le_t = se_t<T, false>;
#else
template<typename T> using be_t = se_t<T, false>;
template<typename T> using le_t = se_t<T, true>;
#endif #endif
// Type converter: converts native endianness arithmetic/enum types to appropriate se_t<> type
template<typename T, bool Se, typename = void> struct to_se template<typename T, bool Se, typename = void>
struct to_se
{ {
// Convert arithmetic and enum types
using type = typename std::conditional<std::is_arithmetic<T>::value || std::is_enum<T>::value, se_t<T, Se>, T>::type; using type = typename std::conditional<std::is_arithmetic<T>::value || std::is_enum<T>::value, se_t<T, Se>, T>::type;
}; };
template<typename T, bool Se> struct to_se<const T, Se, std::enable_if_t<!std::is_array<T>::value>> // move const qualifier
{
using type = const typename to_se<T, Se>::type;
};
template<typename T, bool Se> struct to_se<volatile T, Se, std::enable_if_t<!std::is_array<T>::value && !std::is_const<T>::value>> // move volatile qualifier
{
using type = volatile typename to_se<T, Se>::type;
};
template<typename T, bool Se> struct to_se<T[], Se>
{
using type = typename to_se<T, Se>::type[];
};
template<typename T, bool Se, std::size_t N> struct to_se<T[N], Se>
{
using type = typename to_se<T, Se>::type[N];
};
template<bool Se> struct to_se<u128, Se> { using type = se_t<u128, Se>; };
template<bool Se> struct to_se<v128, Se> { using type = se_t<v128, Se>; }; template<bool Se> struct to_se<v128, Se> { using type = se_t<v128, Se>; };
template<bool Se> struct to_se<bool, Se> { using type = bool; }; template<bool Se> struct to_se<bool, Se> { using type = bool; };
template<bool Se> struct to_se<char, Se> { using type = char; }; template<bool Se> struct to_se<char, Se> { using type = char; };
template<bool Se> struct to_se<u8, Se> { using type = u8; }; template<bool Se> struct to_se<u8, Se> { using type = u8; };
template<bool Se> struct to_se<s8, Se> { using type = s8; }; template<bool Se> struct to_se<s8, Se> { using type = s8; };
#ifdef IS_LE_MACHINE template<typename T, bool Se>
struct to_se<const T, Se, std::enable_if_t<!std::is_array<T>::value>>
{
// Move const qualifier
using type = const typename to_se<T, Se>::type;
};
template<typename T, bool Se>
struct to_se<volatile T, Se, std::enable_if_t<!std::is_array<T>::value && !std::is_const<T>::value>>
{
// Move volatile qualifier
using type = volatile typename to_se<T, Se>::type;
};
template<typename T, bool Se>
struct to_se<T[], Se>
{
// Move array qualifier
using type = typename to_se<T, Se>::type[];
};
template<typename T, bool Se, std::size_t N>
struct to_se<T[N], Se>
{
// Move array qualifier
using type = typename to_se<T, Se>::type[N];
};
// BE/LE aliases for to_se<>
#if IS_LE_MACHINE == 1
template<typename T> using to_be_t = typename to_se<T, true>::type; template<typename T> using to_be_t = typename to_se<T, true>::type;
template<typename T> using to_le_t = typename to_se<T, false>::type; template<typename T> using to_le_t = typename to_se<T, false>::type;
#else
template<typename T> using to_be_t = typename to_se<T, false>::type;
template<typename T> using to_le_t = typename to_se<T, true>::type;
#endif #endif
// BE/LE aliases for atomic_t
#if IS_LE_MACHINE == 1
template<typename T> using atomic_be_t = atomic_t<be_t<T>>;
template<typename T> using atomic_le_t = atomic_t<le_t<T>>;
#endif
template<typename T, typename = void> struct to_ne namespace fmt
{ {
using type = T; // Formatting for BE/LE data
}; template<typename T, bool Se>
struct unveil<se_t<T, Se>, void>
{
using result_type = typename unveil<T>::result_type;
template<typename T, bool Se> struct to_ne<se_t<T, Se>> static inline result_type get_value(const se_t<T, Se>& arg)
{ {
using type = typename std::remove_cv<T>::type; return unveil<T>::get_value(arg);
}; }
};
}
template<typename T> struct to_ne<const T, std::enable_if_t<!std::is_array<T>::value>> // move const qualifier #undef IS_BINARY_COMPARABLE
{ #undef IS_INTEGER
using type = const typename to_ne<T>::type;
};
template<typename T> struct to_ne<volatile T, std::enable_if_t<!std::is_array<T>::value && !std::is_const<T>::value>> // move volatile qualifier
{
using type = volatile typename to_ne<T>::type;
};
template<typename T> struct to_ne<T[]>
{
using type = typename to_ne<T>::type[];
};
template<typename T, std::size_t N> struct to_ne<T[N]>
{
using type = typename to_ne<T>::type[N];
};
// restore native endianness for T: returns T for be_t<T> or le_t<T>, T otherwise
template<typename T> using to_ne_t = typename to_ne<T>::type;

View file

@ -1,73 +1,106 @@
#pragma once #pragma once
// BitField access helper class (N bits from I position), intended to be put in union #include "types.h"
template<typename T, u32 I, u32 N> class bf_t
template<typename T, uint N>
struct bf_base
{ {
// Checks using type = T;
static_assert(I < sizeof(T) * 8, "bf_t<> error: I out of bounds"); using vtype = simple_t<type>;
static_assert(N < sizeof(T) * 8, "bf_t<> error: N out of bounds");
static_assert(I + N <= sizeof(T) * 8, "bf_t<> error: values out of bounds");
// Underlying data type // Datatype bitsize
using type = typename std::remove_cv<T>::type; static constexpr uint bitmax = sizeof(T) * CHAR_BIT; static_assert(N - 1 < bitmax, "bf_base<> error: N out of bounds");
// Field bitsize
static constexpr uint bitsize = N;
// Underlying value type (native endianness) // Value mask
using vtype = typename to_ne<type>::type; static constexpr vtype vmask = static_cast<vtype>(~std::make_unsigned_t<vtype>{} >> (bitmax - bitsize));
// Mask of size N protected:
constexpr static vtype s_mask = (static_cast<vtype>(1) << N) - 1;
// Underlying data member
type m_data; type m_data;
};
// Conversion operator helper (uses SFINAE) // Bitfield accessor (N bits from I position, 0 is LSB)
template<typename T2, typename = void> struct converter {}; template<typename T, uint I, uint N>
struct bf_t : bf_base<T, N>
{
using type = typename bf_t::type;
using vtype = typename bf_t::vtype;
template<typename T2> struct converter<T2, std::enable_if_t<std::is_unsigned<T2>::value>> // Field offset
static constexpr uint bitpos = I; static_assert(bitpos + N <= bf_t::bitmax, "bf_t<> error: I out of bounds");
// Get bitmask of size N, at I pos
static constexpr vtype data_mask()
{
return bf_t::vmask << bitpos;
}
// Bitfield extraction helper
template<typename T2, typename = void>
struct extract_impl
{
static_assert(!sizeof(T2), "bf_t<> error: Invalid type");
};
template<typename T2>
struct extract_impl<T2, std::enable_if_t<std::is_unsigned<T2>::value>>
{ {
// Load unsigned value // Load unsigned value
static inline T2 convert(const type& data) static constexpr T2 extract(const T& data)
{ {
return (data >> I) & s_mask; return (data >> bitpos) & bf_t::vmask;
} }
}; };
template<typename T2> struct converter<T2, std::enable_if_t<std::is_signed<T2>::value>> template<typename T2>
struct extract_impl<T2, std::enable_if_t<std::is_signed<T2>::value>>
{ {
// Load signed value (sign-extended) // Load signed value (sign-extended)
static inline T2 convert(const type& data) static constexpr T2 extract(const T& data)
{ {
return data << (sizeof(T) * 8 - I - N) >> (sizeof(T) * 8 - N); return data << (bf_t::bitmax - bitpos - N) >> (bf_t::bitmax - N);
} }
}; };
public: // Bitfield extraction
// Assignment operator (store bitfield value) static constexpr vtype extract(const T& data)
bf_t& operator =(vtype value)
{ {
m_data = (m_data & ~(s_mask << I)) | (value & s_mask) << I; return extract_impl<vtype>::extract(data);
return *this;
} }
// Conversion operator (load bitfield value) // Bitfield insertion
operator vtype() const static constexpr vtype insert(vtype value)
{ {
return converter<vtype>::convert(m_data); return (value & bf_t::vmask) << bitpos;
} }
// Get raw data with mask applied // Load bitfield value
type unshifted() const constexpr operator vtype() const
{ {
return (m_data & (s_mask << I)); return extract(this->m_data);
} }
// Optimized bool conversion // Load raw data with mask applied
explicit operator bool() const constexpr T unshifted() const
{
return this->m_data & data_mask();
}
// Optimized bool conversion (must be removed if inappropriate)
explicit constexpr operator bool() const
{ {
return unshifted() != 0; return unshifted() != 0;
} }
// Postfix increment operator // Store bitfield value
bf_t& operator =(vtype value)
{
this->m_data = (this->m_data & ~data_mask()) | insert(value);
return *this;
}
vtype operator ++(int) vtype operator ++(int)
{ {
vtype result = *this; vtype result = *this;
@ -75,13 +108,11 @@ public:
return result; return result;
} }
// Prefix increment operator
bf_t& operator ++() bf_t& operator ++()
{ {
return *this = *this + 1; return *this = *this + 1;
} }
// Postfix decrement operator
vtype operator --(int) vtype operator --(int)
{ {
vtype result = *this; vtype result = *this;
@ -89,52 +120,125 @@ public:
return result; return result;
} }
// Prefix decrement operator
bf_t& operator --() bf_t& operator --()
{ {
return *this = *this - 1; return *this = *this - 1;
} }
// Addition assignment operator
bf_t& operator +=(vtype right) bf_t& operator +=(vtype right)
{ {
return *this = *this + right; return *this = *this + right;
} }
// Subtraction assignment operator
bf_t& operator -=(vtype right) bf_t& operator -=(vtype right)
{ {
return *this = *this - right; return *this = *this - right;
} }
// Multiplication assignment operator
bf_t& operator *=(vtype right) bf_t& operator *=(vtype right)
{ {
return *this = *this * right; return *this = *this * right;
} }
// Bitwise AND assignment operator
bf_t& operator &=(vtype right) bf_t& operator &=(vtype right)
{ {
m_data &= (right & s_mask) << I; this->m_data &= (right & bf_t::vmask) << bitpos;
return *this; return *this;
} }
// Bitwise OR assignment operator
bf_t& operator |=(vtype right) bf_t& operator |=(vtype right)
{ {
m_data |= (right & s_mask) << I; this->m_data |= (right & bf_t::vmask) << bitpos;
return *this; return *this;
} }
// Bitwise XOR assignment operator
bf_t& operator ^=(vtype right) bf_t& operator ^=(vtype right)
{ {
m_data ^= (right & s_mask) << I; this->m_data ^= (right & bf_t::vmask) << bitpos;
return *this; return *this;
} }
}; };
template<typename T, u32 I, u32 N> using bf_be_t = bf_t<be_t<T>, I, N>; // Field pack (concatenated from left to right)
template<typename F = void, typename... Fields>
struct cf_t : bf_base<typename F::type, F::bitsize + cf_t<Fields...>::bitsize>
{
using type = typename cf_t::type;
using vtype = typename cf_t::vtype;
template<typename T, u32 I, u32 N> using bf_le_t = bf_t<le_t<T>, I, N>; // Get disjunction of all "data" masks of concatenated values
static constexpr vtype data_mask()
{
return F::data_mask() | cf_t<Fields...>::data_mask();
}
// Extract all bitfields and concatenate
static constexpr vtype extract(const type& data)
{
return F::extract(data) << cf_t<Fields...>::bitsize | cf_t<Fields...>::extract(data);
}
// Split bitfields and insert them
static constexpr vtype insert(vtype value)
{
return F::insert(value >> cf_t<Fields...>::bitsize) | cf_t<Fields...>::insert(value);
}
// Load value
constexpr operator vtype() const
{
return extract(this->m_data);
}
// Store value
cf_t& operator =(vtype value)
{
this->m_data = (this->m_data & ~data_mask()) | insert(value);
return *this;
}
};
// Empty field pack (recursion terminator)
template<>
struct cf_t<void>
{
static constexpr uint bitsize = 0;
static constexpr uint data_mask()
{
return 0;
}
template<typename T>
static constexpr auto extract(const T& data) -> decltype(+T())
{
return 0;
}
template<typename T>
static constexpr T insert(T value)
{
return 0;
}
};
// Fixed field (provides constant values in field pack)
template<typename T, T V, uint N>
struct ff_t : bf_base<T, N>
{
using type = typename ff_t::type;
using vtype = typename ff_t::vtype;
// Return constant value
static constexpr vtype extract(const type& data)
{
static_assert((V & ff_t::vmask) == V, "ff_t<> error: V out of bounds");
return V;
}
// Get value
operator vtype() const
{
return V;
}
};

203
Utilities/Config.cpp Normal file
View file

@ -0,0 +1,203 @@
#include "stdafx.h"
#include "Config.h"
#include "yaml-cpp/yaml.h"
namespace cfg
{
_log::channel cfg("CFG", _log::level::notice);
entry_base::entry_base(type _type)
: m_type(_type)
{
if (_type != type::node)
{
throw std::logic_error("Invalid root node");
}
}
entry_base::entry_base(type _type, node& owner, const std::string& name)
: m_type(_type)
{
if (!owner.m_nodes.emplace(name, this).second)
{
throw std::logic_error("Node already exists");
}
}
entry_base& entry_base::operator[](const std::string& name) const
{
if (m_type == type::node)
{
return *static_cast<const node&>(*this).m_nodes.at(name);
}
throw std::logic_error("Invalid node type");
}
entry_base& entry_base::operator[](const char* name) const
{
if (m_type == type::node)
{
return *static_cast<const node&>(*this).m_nodes.at(name);
}
throw std::logic_error("Invalid node type");
}
// Emit YAML
static void encode(YAML::Emitter& out, const class entry_base& rhs);
// Incrementally load config entries from YAML::Node.
// The config value is preserved if the corresponding YAML node doesn't exist.
static void decode(const YAML::Node& data, class entry_base& rhs);
}
bool cfg::try_to_int64(s64* out, const std::string& value, s64 min, s64 max)
{
// TODO: this could be rewritten without exceptions (but it should be as safe as possible and provide logs)
s64 result;
std::size_t pos;
try
{
result = std::stoll(value, &pos, 0 /* Auto-detect numeric base */);
}
catch (const std::exception& e)
{
if (out) cfg.error("cfg::try_to_int('%s'): exception: %s", value, e.what());
return false;
}
if (pos != value.size())
{
if (out) cfg.error("cfg::try_to_int('%s'): unexpected characters (pos=%zu)", value, pos);
return false;
}
if (result < min || result > max)
{
if (out) cfg.error("cfg::try_to_int('%s'): out of bounds (%lld..%lld)", value, min, max);
return false;
}
if (out) *out = result;
return true;
}
void cfg::encode(YAML::Emitter& out, const cfg::entry_base& rhs)
{
switch (rhs.get_type())
{
case type::node:
{
out << YAML::BeginMap;
for (const auto& np : static_cast<const node&>(rhs).get_nodes())
{
out << YAML::Key << np.first;
out << YAML::Value; encode(out, *np.second);
}
out << YAML::EndMap;
return;
}
case type::set:
{
out << YAML::BeginSeq;
for (const auto& str : static_cast<const set_entry&>(rhs).get_set())
{
out << str;
}
out << YAML::EndSeq;
return;
}
}
out << rhs.to_string();
}
void cfg::decode(const YAML::Node& data, cfg::entry_base& rhs)
{
switch (rhs.get_type())
{
case type::node:
{
if (data.IsScalar() || data.IsSequence())
{
return; // ???
}
for (const auto& pair : data)
{
if (!pair.first.IsScalar()) continue;
// Find the key among existing nodes
const auto name = pair.first.Scalar();
const auto found = static_cast<node&>(rhs).get_nodes().find(name);
if (found != static_cast<node&>(rhs).get_nodes().cend())
{
decode(pair.second, *found->second);
}
else
{
// ???
}
}
break;
}
case type::set:
{
std::vector<std::string> values;
if (YAML::convert<decltype(values)>::decode(data, values))
{
rhs.from_list(std::move(values));
}
break;
}
default:
{
std::string value;
if (YAML::convert<std::string>::decode(data, value))
{
rhs.from_string(value);
}
break; // ???
}
}
}
std::string cfg::node::to_string() const
{
YAML::Emitter out;
cfg::encode(out, *this);
return{ out.c_str(), out.size() };
}
bool cfg::node::from_string(const std::string& value)
{
cfg::decode(YAML::Load(value), *this);
return true;
}
void cfg::node::from_default()
{
for (auto& node : m_nodes)
{
node.second->from_default();
}
}
cfg::root_node& cfg::get_root()
{
// Magic static
static root_node root;
return root;
}

523
Utilities/Config.h Normal file
View file

@ -0,0 +1,523 @@
#pragma once
#include "Utilities/Atomic.h"
#include <set>
#include <map>
namespace cfg
{
// Convert string to signed integer
bool try_to_int64(s64* out, const std::string& value, s64 min, s64 max);
// Config tree entry type.
enum class type : uint
{
node = 0, // cfg::node type
boolean, // cfg::bool_entry type
fixed_map, // cfg::map_entry type
enumeration, // cfg::enum_entry type
integer, // cfg::int_entry type
string, // cfg::string_entry type
set, // cfg::set_entry type
};
// Config tree entry abstract base class
class entry_base
{
const type m_type;
protected:
// Ownerless entry constructor
entry_base(type _type);
// Owned entry constructor
entry_base(type _type, class node& owner, const std::string& name);
public:
// Disallow copy/move constructors and assignments
entry_base(const entry_base&) = delete;
// Get type
type get_type() const { return m_type; }
// Access child node (must exist)
entry_base& operator [](const std::string& name) const; entry_base& operator [](const char* name) const;
// Reset defaults
virtual void from_default() = 0;
// Convert to string (optional)
virtual std::string to_string() const
{
return{};
}
// Try to convert from string (optional)
virtual bool from_string(const std::string&)
{
throw std::logic_error("from_string() not specified");
}
// Get string list (optional)
virtual std::vector<std::string> to_list() const
{
return{};
}
// Set multiple values. Implementation-specific, optional.
virtual bool from_list(std::vector<std::string>&&)
{
throw std::logic_error("from_list() not specified");
}
};
// Config tree node which contains another nodes
class node : public entry_base
{
std::map<std::string, entry_base*> m_nodes;
friend class entry_base;
public:
// Root node constructor
node()
: entry_base(type::node)
{
}
// Registered node constructor
node(node& owner, const std::string& name)
: entry_base(type::node, owner, name)
{
}
// Get child nodes
const std::map<std::string, entry_base*>& get_nodes() const
{
return m_nodes;
}
// Serialize node
std::string to_string() const override;
// Deserialize node
bool from_string(const std::string& value) override;
// Set default values
void from_default() override;
};
struct bool_entry final : public entry_base
{
atomic_t<bool> value;
const bool def;
bool_entry(node& owner, const std::string& name, bool def = false)
: entry_base(type::boolean, owner, name)
, value(def)
, def(def)
{
}
explicit operator bool() const
{
return value.load();
}
bool_entry& operator =(bool value)
{
value = value;
return *this;
}
void from_default() override
{
value = def;
}
std::string to_string() const override
{
return value.load() ? "true" : "false";
}
bool from_string(const std::string& value) override
{
if (value == "false")
this->value = false;
else if (value == "true")
this->value = true;
else
return false;
return true;
}
};
// Value node with fixed set of possible values, each maps to a value of type T.
template<typename T>
struct map_entry final : public entry_base
{
using init_type = std::initializer_list<std::pair<std::string, T>>;
using map_type = std::unordered_map<std::string, T>;
using list_type = std::vector<std::string>;
using value_type = typename map_type::value_type;
static map_type make_map(init_type init)
{
map_type map(init.size());
for (const auto& v : init)
{
// Ensure elements are unique
ASSERT(map.emplace(v.first, v.second).second);
}
return map;
}
static list_type make_list(init_type init)
{
list_type list; list.reserve(init.size());
for (const auto& v : init)
{
list.emplace_back(v.first);
}
return list;
}
public:
const map_type map;
const list_type list; // Element list sorted in original order
const value_type& def; // Pointer to the default value
private:
atomic_t<const value_type*> m_value;
public:
map_entry(node& owner, const std::string& name, const std::string& def, init_type init)
: entry_base(type::fixed_map, owner, name)
, map(make_map(init))
, list(make_list(init))
, def(*map.find(def))
, m_value(&this->def)
{
}
map_entry(node& owner, const std::string& name, std::size_t def_index, init_type init)
: map_entry(owner, name, def_index < init.size() ? (init.begin() + def_index)->first : throw std::logic_error("Invalid default value index"), init)
{
}
map_entry(node& owner, const std::string& name, init_type init)
: map_entry(owner, name, 0, init)
{
}
const T& get() const
{
return m_value.load()->second;
}
void from_default() override
{
m_value = &def;
}
std::string to_string() const override
{
return m_value.load()->first;
}
bool from_string(const std::string& value) override
{
const auto found = map.find(value);
if (found == map.end())
{
return false;
}
else
{
m_value = &*found;
return true;
}
}
std::vector<std::string> to_list() const override
{
return list;
}
};
// Value node with fixed set of possible values, each maps to an enum value of type T.
template<typename T, bool External = false>
class enum_entry final : public entry_base
{
// Value or reference
std::conditional_t<External, atomic_t<T>&, atomic_t<T>> m_value;
public:
const T def;
enum_entry(node& owner, const std::string& name, std::conditional_t<External, atomic_t<T>&, T> value)
: entry_base(type::enumeration, owner, name)
, m_value(value)
, def(value)
{
}
operator T() const
{
return m_value.load();
}
enum_entry& operator =(T value)
{
m_value = value;
return *this;
}
void from_default() override
{
m_value = def;
}
std::string to_string() const override
{
for (const auto& pair : bijective<T, const char*>::map)
{
if (pair.first == m_value)
{
return pair.second;
}
}
return{}; // TODO: ???
}
bool from_string(const std::string& value) override
{
for (const auto& pair : bijective<T, const char*>::map)
{
if (pair.second == value)
{
m_value = pair.first;
return true;
}
}
return false;
}
std::vector<std::string> to_list() const override
{
std::vector<std::string> result;
for (const auto& pair : bijective<T, const char*>::map)
{
result.emplace_back(pair.second);
}
return result;
}
};
// Signed 32/64-bit integer entry with custom Min/Max range.
template<s64 Min, s64 Max>
class int_entry final : public entry_base
{
static_assert(Min < Max, "Invalid cfg::int_entry range");
// Prefer 32 bit type if possible
using int_type = std::conditional_t<Min >= INT32_MIN && Max <= INT32_MAX, s32, s64>;
atomic_t<int_type> m_value;
public:
const int_type def;
int_entry(node& owner, const std::string& name, int_type def = std::min<int_type>(Max, std::max<int_type>(Min, 0)))
: entry_base(type::integer, owner, name)
, m_value(def)
, def(def)
{
}
operator int_type() const
{
return m_value.load();
}
int_entry& operator =(int_type value)
{
if (value < Min || value > Max)
{
throw fmt::exception("Value out of the valid range: %lld" HERE, s64{ value });
}
m_value = value;
return *this;
}
void from_default() override
{
m_value = def;
}
std::string to_string() const override
{
return std::to_string(m_value.load());
}
bool from_string(const std::string& value) override
{
s64 result;
if (try_to_int64(&result, value, Min, Max))
{
m_value = static_cast<int_type>(result);
return true;
}
return false;
}
};
// Alias for 32 bit int
using int32_entry = int_entry<INT32_MIN, INT32_MAX>;
// Alias for 64 bit int
using int64_entry = int_entry<INT64_MIN, INT64_MAX>;
// Simple string entry with mutex
class string_entry final : public entry_base
{
mutable std::mutex m_mutex;
std::string m_value;
public:
const std::string def;
string_entry(node& owner, const std::string& name, const std::string& def = {})
: entry_base(type::string, owner, name)
, m_value(def)
, def(def)
{
}
operator std::string() const
{
std::lock_guard<std::mutex> lock(m_mutex);
return m_value;
}
std::string get() const
{
return *this;
}
string_entry& operator =(const std::string& value)
{
std::lock_guard<std::mutex> lock(m_mutex);
m_value = value;
return *this;
}
std::size_t size() const
{
std::lock_guard<std::mutex> lock(m_mutex);
return m_value.size();
}
void from_default() override
{
*this = def;
}
std::string to_string() const override
{
std::lock_guard<std::mutex> lock(m_mutex);
return m_value;
}
bool from_string(const std::string& value) override
{
*this = value;
return true;
}
};
// Simple set entry with mutex (TODO: template for various types)
class set_entry final : public entry_base
{
mutable std::mutex m_mutex;
std::set<std::string> m_set;
public:
// Default value is empty list in current implementation
set_entry(node& owner, const std::string& name)
: entry_base(type::set, owner, name)
{
}
std::set<std::string> get_set() const
{
std::lock_guard<std::mutex> lock(m_mutex);
return m_set;
}
void set_set(std::set<std::string>&& set)
{
std::lock_guard<std::mutex> lock(m_mutex);
m_set = std::move(set);
}
void from_default() override
{
std::lock_guard<std::mutex> lock(m_mutex);
m_set = {};
}
std::vector<std::string> to_list() const override
{
std::lock_guard<std::mutex> lock(m_mutex);
return{ m_set.begin(), m_set.end() };
}
bool from_list(std::vector<std::string>&& list) override
{
std::lock_guard<std::mutex> lock(m_mutex);
m_set = { std::make_move_iterator(list.begin()), std::make_move_iterator(list.end()) };
return true;
}
};
// Root type with some predefined nodes. Don't change it, this is not mandatory for adding nodes.
struct root_node : node
{
node core { *this, "Core" };
node vfs { *this, "VFS" };
node log { *this, "Log" };
node video { *this, "Video" };
node audio { *this, "Audio" };
node io { *this, "Input/Output" };
node sys { *this, "System" };
node net { *this, "Net" };
node misc { *this, "Miscellaneous" };
};
// Get global configuration root instance
extern root_node& get_root();
// Global configuration root instance (cached reference)
static root_node& root = get_root();
}
// Registered log channel
#define LOG_CHANNEL(name) _log::channel name(#name, _log::level::notice); namespace _log { cfg::enum_entry<_log::level, true> name(cfg::root.log, #name, ::name.enabled); }

File diff suppressed because it is too large Load diff

View file

@ -1,29 +1,47 @@
#pragma once #pragma once
namespace fom // file open mode #include <memory>
{ #include <string>
enum open_mode : u32 #include <vector>
{ #include <type_traits>
read = 1 << 0, // enable reading
write = 1 << 1, // enable writing
append = 1 << 2, // enable appending (always write to the end of file)
create = 1 << 3, // create file if it doesn't exist
trunc = 1 << 4, // clear opened file if it's not empty
excl = 1 << 5, // failure if the file already exists (used with `create`)
rewrite = write | create | trunc, #include "types.h"
};
};
namespace fs namespace fs
{ {
enum seek_mode : u32 // file seek mode // File open mode flags
enum struct open_mode : u32
{
read,
write,
append,
create,
trunc,
excl,
};
constexpr mset<open_mode> read = open_mode::read; // Enable reading
constexpr mset<open_mode> write = open_mode::write; // Enable writing
constexpr mset<open_mode> append = open_mode::append; // Always append to the end of the file
constexpr mset<open_mode> create = open_mode::create; // Create file if it doesn't exist
constexpr mset<open_mode> trunc = open_mode::trunc; // Clear opened file if it's not empty
constexpr mset<open_mode> excl = open_mode::excl; // Failure if the file already exists (used with `create`)
constexpr mset<open_mode> rewrite = write + create + trunc;
// File seek mode
enum class seek_mode : u32
{ {
seek_set, seek_set,
seek_cur, seek_cur,
seek_end, seek_end,
}; };
constexpr auto seek_set = seek_mode::seek_set; // From beginning
constexpr auto seek_cur = seek_mode::seek_cur; // From current position
constexpr auto seek_end = seek_mode::seek_end; // From end
// File attributes (TODO)
struct stat_t struct stat_t
{ {
bool is_directory; bool is_directory;
@ -34,7 +52,57 @@ namespace fs
s64 ctime; s64 ctime;
}; };
// Get parent directory for the path (returns empty string on failure) // File handle base
struct file_base
{
virtual ~file_base() = default;
virtual stat_t stat() = 0;
virtual bool trunc(u64 length) = 0;
virtual u64 read(void* buffer, u64 size) = 0;
virtual u64 write(const void* buffer, u64 size) = 0;
virtual u64 seek(s64 offset, seek_mode whence) = 0;
virtual u64 size() = 0;
};
// Directory entry (TODO)
struct dir_entry : stat_t
{
std::string name;
};
// Directory handle base
struct dir_base
{
virtual ~dir_base() = default;
virtual bool read(dir_entry&) = 0;
virtual void rewind() = 0;
};
// Virtual device
struct device_base
{
virtual ~device_base() = default;
virtual bool stat(const std::string& path, stat_t& info) = 0;
virtual bool remove_dir(const std::string& path) = 0;
virtual bool create_dir(const std::string& path) = 0;
virtual bool rename(const std::string& from, const std::string& to) = 0;
virtual bool remove(const std::string& path) = 0;
virtual bool trunc(const std::string& path, u64 length) = 0;
virtual std::unique_ptr<file_base> open(const std::string& path, mset<open_mode> mode) = 0;
virtual std::unique_ptr<dir_base> open_dir(const std::string& path) = 0;
};
// Get virtual device for specified path (nullptr for real path)
std::shared_ptr<device_base> get_virtual_device(const std::string& path);
// Set virtual device with specified name (nullptr for deletion)
std::shared_ptr<device_base> set_virtual_device(const std::string& root_name, const std::shared_ptr<device_base>&);
// Try to get parent directory (returns empty string on failure)
std::string get_parent_dir(const std::string& path); std::string get_parent_dir(const std::string& path);
// Get file information // Get file information
@ -72,77 +140,105 @@ namespace fs
class file final class file final
{ {
using handle_type = std::intptr_t; std::unique_ptr<file_base> m_file;
constexpr static handle_type null = -1; [[noreturn]] void xnull() const;
[[noreturn]] void xfail() const;
handle_type m_fd = null;
friend class file_read_map;
friend class file_write_map;
public: public:
// Default constructor
file() = default; file() = default;
explicit file(const std::string& path, u32 mode = fom::read) // Open file with specified mode
explicit file(const std::string& path, mset<open_mode> mode = ::fs::read)
{ {
open(path, mode); open(path, mode);
} }
file(file&& other) // Open file with specified mode
: m_fd(other.m_fd) bool open(const std::string& path, mset<open_mode> mode = ::fs::read);
{
other.m_fd = null;
}
file& operator =(file&& right) // Open memory for read
{ explicit file(const void* ptr, std::size_t size);
std::swap(m_fd, right.m_fd);
return *this;
}
~file(); // Open vector
explicit file(std::vector<char>& vec);
// Check whether the handle is valid (opened file)
bool is_opened() const
{
return m_fd != null;
}
// Check whether the handle is valid (opened file) // Check whether the handle is valid (opened file)
explicit operator bool() const explicit operator bool() const
{ {
return is_opened(); return m_file.operator bool();
} }
// Open specified file with specified mode // Close the file explicitly
bool open(const std::string& path, u32 mode = fom::read); void close()
{
m_file.reset();
}
void reset(std::unique_ptr<file_base>&& ptr)
{
m_file = std::move(ptr);
}
std::unique_ptr<file_base> release()
{
return std::move(m_file);
}
// Change file size (possibly appending zero bytes) // Change file size (possibly appending zero bytes)
bool trunc(u64 size) const; bool trunc(u64 length) const
{
if (!m_file) xnull();
return m_file->trunc(length);
}
// Get file information // Get file information
bool stat(stat_t& info) const; stat_t stat() const
{
// Close the file explicitly (destructor automatically closes the file) if (!m_file) xnull();
void close(); return m_file->stat();
}
// Read the data from the file and return the amount of data written in buffer // Read the data from the file and return the amount of data written in buffer
u64 read(void* buffer, u64 count) const; u64 read(void* buffer, u64 count) const
{
if (!m_file) xnull();
return m_file->read(buffer, count);
}
// Write the data to the file and return the amount of data actually written // Write the data to the file and return the amount of data actually written
u64 write(const void* buffer, u64 count) const; u64 write(const void* buffer, u64 count) const
{
if (!m_file) xnull();
return m_file->write(buffer, count);
}
// Move file pointer // Change current position, returns previous position
u64 seek(s64 offset, seek_mode whence = seek_set) const; u64 seek(s64 offset, seek_mode whence = seek_set) const
{
if (!m_file) xnull();
return m_file->seek(offset, whence);
}
// Get file size // Get file size
u64 size() const; u64 size() const
{
if (!m_file) xnull();
return m_file->size();
}
// Get current position
u64 pos() const
{
if (!m_file) xnull();
return m_file->seek(0, seek_cur);
}
// Write std::string unconditionally // Write std::string unconditionally
const file& write(const std::string& str) const const file& write(const std::string& str) const
{ {
CHECK_ASSERTION(write(str.data(), str.size()) == str.size()); if (write(str.data(), str.size()) != str.size()) xfail();
return *this; return *this;
} }
@ -150,7 +246,7 @@ namespace fs
template<typename T> template<typename T>
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, const file&> write(const T& data) const std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, const file&> write(const T& data) const
{ {
CHECK_ASSERTION(write(std::addressof(data), sizeof(T)) == sizeof(T)); if (write(std::addressof(data), sizeof(T)) != sizeof(T)) xfail();
return *this; return *this;
} }
@ -158,7 +254,7 @@ namespace fs
template<typename T> template<typename T>
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, const file&> write(const std::vector<T>& vec) const std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, const file&> write(const std::vector<T>& vec) const
{ {
CHECK_ASSERTION(write(vec.data(), vec.size() * sizeof(T)) == vec.size() * sizeof(T)); if (write(vec.data(), vec.size() * sizeof(T)) != vec.size() * sizeof(T)) xfail();
return *this; return *this;
} }
@ -187,7 +283,7 @@ namespace fs
std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, T> read() const std::enable_if_t<std::is_pod<T>::value && !std::is_pointer<T>::value, T> read() const
{ {
T result; T result;
CHECK_ASSERTION(read(result)); if (!read(result)) xfail();
return result; return result;
} }
@ -196,7 +292,7 @@ namespace fs
{ {
std::string result; std::string result;
result.resize(size()); result.resize(size());
CHECK_ASSERTION(seek(0) != -1 && read(result)); if (seek(0), !read(result)) xfail();
return result; return result;
} }
@ -206,164 +302,69 @@ namespace fs
{ {
std::vector<T> result; std::vector<T> result;
result.resize(size() / sizeof(T)); result.resize(size() / sizeof(T));
CHECK_ASSERTION(seek(0) != -1 && read(result)); if (seek(0), !read(result)) xfail();
return result; return result;
} }
}; };
// TODO
class file_read_map final
{
char* m_ptr = nullptr;
u64 m_size;
public:
file_read_map() = default;
file_read_map(file_read_map&& right)
: m_ptr(right.m_ptr)
, m_size(right.m_size)
{
right.m_ptr = 0;
}
file_read_map& operator =(file_read_map&& right)
{
std::swap(m_ptr, right.m_ptr);
std::swap(m_size, right.m_size);
return *this;
}
file_read_map(const file& f)
{
reset(f);
}
~file_read_map()
{
reset();
}
// Open file mapping
void reset(const file& f);
// Close file mapping
void reset();
// Get pointer
operator const char*() const
{
return m_ptr;
}
};
// TODO
class file_write_map final
{
char* m_ptr = nullptr;
u64 m_size;
public:
file_write_map() = default;
file_write_map(file_write_map&& right)
: m_ptr(right.m_ptr)
, m_size(right.m_size)
{
right.m_ptr = 0;
}
file_write_map& operator =(file_write_map&& right)
{
std::swap(m_ptr, right.m_ptr);
std::swap(m_size, right.m_size);
return *this;
}
file_write_map(const file& f)
{
reset(f);
}
~file_write_map()
{
reset();
}
// Open file mapping
void reset(const file& f);
// Close file mapping
void reset();
// Get pointer
operator char*() const
{
return m_ptr;
}
};
class dir final class dir final
{ {
std::unique_ptr<char[]> m_path; std::unique_ptr<dir_base> m_dir;
std::intptr_t m_dd; // handle (aux)
[[noreturn]] void xnull() const;
public: public:
dir() = default; dir() = default;
explicit dir(const std::string& dirname) // Open dir handle
explicit dir(const std::string& path)
{ {
open(dirname); open(path);
} }
dir(dir&& other) // Open specified directory
: m_dd(other.m_dd) bool open(const std::string& path);
, m_path(std::move(other.m_path))
{
}
dir& operator =(dir&& right)
{
std::swap(m_dd, right.m_dd);
std::swap(m_path, right.m_path);
return *this;
}
~dir();
// Check whether the handle is valid (opened directory)
bool is_opened() const
{
return m_path.operator bool();
}
// Check whether the handle is valid (opened directory) // Check whether the handle is valid (opened directory)
explicit operator bool() const explicit operator bool() const
{ {
return is_opened(); return m_dir.operator bool();
} }
// Open specified directory // Close the directory explicitly
bool open(const std::string& dirname); void close()
// Close the directory explicitly (destructor automatically closes the directory)
void close();
// Get next directory entry (UTF-8 name and file stat)
bool read(std::string& name, stat_t& info);
bool first(std::string& name, stat_t& info);
struct entry
{ {
std::string name; m_dir.reset();
stat_t info; }
};
void reset(std::unique_ptr<dir_base>&& ptr)
{
m_dir = std::move(ptr);
}
std::unique_ptr<dir_base> release()
{
return std::move(m_dir);
}
// Get next directory entry
bool read(dir_entry& out) const
{
if (!m_dir) xnull();
return m_dir->read(out);
}
// Reset to the beginning
void rewind() const
{
if (!m_dir) xnull();
return m_dir->rewind();
}
class iterator class iterator
{ {
entry m_entry;
dir* m_parent; dir* m_parent;
dir_entry m_entry;
public: public:
enum class mode enum class mode
@ -382,20 +383,16 @@ namespace fs
if (mode_ == mode::from_first) if (mode_ == mode::from_first)
{ {
m_parent->first(m_entry.name, m_entry.info); m_parent->rewind();
}
else
{
m_parent->read(m_entry.name, m_entry.info);
} }
if (m_entry.name.empty()) if (!m_parent->read(m_entry))
{ {
m_parent = nullptr; m_parent = nullptr;
} }
} }
entry& operator *() dir_entry& operator *()
{ {
return m_entry; return m_entry;
} }
@ -414,7 +411,7 @@ namespace fs
iterator begin() iterator begin()
{ {
return{ this }; return{ m_dir ? this : nullptr };
} }
iterator end() iterator end()
@ -428,4 +425,10 @@ namespace fs
// Get executable directory // Get executable directory
const std::string& get_executable_dir(); const std::string& get_executable_dir();
// Delete directory and all its contents recursively
void remove_all(const std::string& path);
// Get size of all files recursively
u64 get_dir_size(const std::string& path);
} }

View file

@ -1,26 +1,17 @@
#include "stdafx.h" #include "Log.h"
#include "Thread.h"
#include "File.h"
#include "Log.h"
#ifdef _WIN32
#include <Windows.h>
#endif
namespace _log namespace _log
{ {
logger& get_logger() static file_listener& get_logger()
{ {
// Use magic static for global logger instance // Use magic static
static logger instance; static file_listener logger("RPCS3.log");
return instance; return logger;
} }
file_listener g_log_file(_PRGNAME_ ".log");
file_writer g_tty_file("TTY.log"); file_writer g_tty_file("TTY.log");
channel GENERAL("", level::notice); channel GENERAL(nullptr, level::notice);
channel LOADER("LDR", level::notice); channel LOADER("LDR", level::notice);
channel MEMORY("MEM", level::notice); channel MEMORY("MEM", level::notice);
channel RSX("RSX", level::notice); channel RSX("RSX", level::notice);
@ -28,72 +19,29 @@ namespace _log
channel PPU("PPU", level::notice); channel PPU("PPU", level::notice);
channel SPU("SPU", level::notice); channel SPU("SPU", level::notice);
channel ARMv7("ARMv7"); channel ARMv7("ARMv7");
}
_log::listener::listener() thread_local std::string(*g_tls_make_prefix)(const channel&, level, const std::string&) = nullptr;
{
// Register self
get_logger().add_listener(this);
}
_log::listener::~listener()
{
// Unregister self
get_logger().remove_listener(this);
}
_log::channel::channel(const std::string& name, _log::level init_level)
: name{ name }
, enabled{ init_level }
{
// TODO: register config property "name" associated with "enabled" member
}
void _log::logger::add_listener(_log::listener* listener)
{
std::lock_guard<shared_mutex> lock(m_mutex);
m_listeners.emplace(listener);
}
void _log::logger::remove_listener(_log::listener* listener)
{
std::lock_guard<shared_mutex> lock(m_mutex);
m_listeners.erase(listener);
}
void _log::logger::broadcast(const _log::channel& ch, _log::level sev, const std::string& text) const
{
reader_lock lock(m_mutex);
for (auto listener : m_listeners)
{
listener->log(ch, sev, text);
}
} }
void _log::broadcast(const _log::channel& ch, _log::level sev, const std::string& text) void _log::broadcast(const _log::channel& ch, _log::level sev, const std::string& text)
{ {
get_logger().broadcast(ch, sev, text); get_logger().log(ch, sev, text);
} }
[[noreturn]] extern void catch_all_exceptions();
_log::file_writer::file_writer(const std::string& name) _log::file_writer::file_writer(const std::string& name)
{ {
try try
{ {
if (!m_file.open(fs::get_config_dir() + name, fom::rewrite | fom::append)) if (!m_file.open(fs::get_config_dir() + name, fs::rewrite + fs::append))
{ {
throw EXCEPTION("Can't create log file %s (error %d)", name, errno); throw fmt::exception("Can't create log file %s (error %d)", name, errno);
} }
} }
catch (const fmt::exception& e) catch (...)
{ {
#ifdef _WIN32 catch_all_exceptions();
MessageBoxA(0, e.what(), "_log::file_writer() failed", MB_ICONERROR);
#else
std::printf("_log::file_writer() failed: %s\n", e.what());
#endif
} }
} }
@ -104,7 +52,7 @@ void _log::file_writer::log(const std::string& text)
std::size_t _log::file_writer::size() const std::size_t _log::file_writer::size() const
{ {
return m_file.seek(0, fs::seek_cur); return m_file.pos();
} }
void _log::file_listener::log(const _log::channel& ch, _log::level sev, const std::string& text) void _log::file_listener::log(const _log::channel& ch, _log::level sev, const std::string& text)
@ -126,14 +74,14 @@ void _log::file_listener::log(const _log::channel& ch, _log::level sev, const st
// TODO: print time? // TODO: print time?
if (auto t = thread_ctrl::get_current()) if (auto func = g_tls_make_prefix)
{ {
msg += '{'; msg += '{';
msg += t->get_name(); msg += func(ch, sev, text);
msg += "} "; msg += "} ";
} }
if (ch.name.size()) if (ch.name)
{ {
msg += ch.name; msg += ch.name;
msg += sev == level::todo ? " TODO: " : ": "; msg += sev == level::todo ? " TODO: " : ": ";

View file

@ -1,6 +1,9 @@
#pragma once #pragma once
#include "SharedMutex.h" #include "types.h"
#include "Atomic.h"
#include "File.h"
#include "StrFmt.h"
namespace _log namespace _log
{ {
@ -19,40 +22,24 @@ namespace _log
struct channel; struct channel;
struct listener; struct listener;
// Log manager
class logger final
{
mutable shared_mutex m_mutex;
std::set<listener*> m_listeners;
public:
// Register listener
void add_listener(listener* listener);
// Unregister listener
void remove_listener(listener* listener);
// Send log message to all listeners
void broadcast(const channel& ch, level sev, const std::string& text) const;
};
// Send log message to global logger instance // Send log message to global logger instance
void broadcast(const channel& ch, level sev, const std::string& text); void broadcast(const channel& ch, level sev, const std::string& text);
// Log channel (source) // Log channel
struct channel struct channel
{ {
// Channel prefix (also used for identification) // Channel prefix (added to every log message)
const std::string name; const char* const name;
// The lowest logging level enabled for this channel (used for early filtering) // The lowest logging level enabled for this channel (used for early filtering)
std::atomic<level> enabled; atomic_t<level> enabled;
// Initialization (max level enabled by default) // Constant initialization: name and initial log level
channel(const std::string& name, level = level::trace); constexpr channel(const char* name, level enabled = level::trace)
: name{ name }
virtual ~channel() = default; , enabled{ enabled }
{
}
// Log without formatting // Log without formatting
force_inline void log(level sev, const std::string& text) const force_inline void log(level sev, const std::string& text) const
@ -71,7 +58,7 @@ namespace _log
#define GEN_LOG_METHOD(_sev)\ #define GEN_LOG_METHOD(_sev)\
template<typename... Args>\ template<typename... Args>\
force_inline void _sev(const char* fmt, const Args&... args)\ force_inline void _sev(const char* fmt, const Args&... args) const\
{\ {\
return format<Args...>(level::_sev, fmt, args...);\ return format<Args...>(level::_sev, fmt, args...);\
} }
@ -90,9 +77,9 @@ namespace _log
// Log listener (destination) // Log listener (destination)
struct listener struct listener
{ {
listener(); listener() = default;
virtual ~listener(); virtual ~listener() = default;
virtual void log(const channel& ch, level sev, const std::string& text) = 0; virtual void log(const channel& ch, level sev, const std::string& text) = 0;
}; };
@ -126,9 +113,6 @@ namespace _log
virtual void log(const channel& ch, level sev, const std::string& text) override; virtual void log(const channel& ch, level sev, const std::string& text) override;
}; };
// Global variable for RPCS3.log
extern file_listener g_log_file;
// Global variable for TTY.log // Global variable for TTY.log
extern file_writer g_tty_file; extern file_writer g_tty_file;
@ -142,8 +126,26 @@ namespace _log
extern channel PPU; extern channel PPU;
extern channel SPU; extern channel SPU;
extern channel ARMv7; extern channel ARMv7;
extern thread_local std::string(*g_tls_make_prefix)(const channel&, level, const std::string&);
} }
template<>
struct bijective<_log::level, const char*>
{
static constexpr std::pair<_log::level, const char*> map[]
{
{ _log::level::always, "Nothing" },
{ _log::level::fatal, "Fatal" },
{ _log::level::error, "Error" },
{ _log::level::todo, "TODO" },
{ _log::level::success, "Success" },
{ _log::level::warning, "Warning" },
{ _log::level::notice, "Notice" },
{ _log::level::trace, "Trace" },
};
};
// Legacy: // Legacy:
#define LOG_SUCCESS(ch, fmt, ...) _log::ch.success(fmt, ##__VA_ARGS__) #define LOG_SUCCESS(ch, fmt, ...) _log::ch.success(fmt, ##__VA_ARGS__)

79
Utilities/Macro.h Normal file
View file

@ -0,0 +1,79 @@
#pragma once
#include <cstdint>
#include <exception>
template<typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
constexpr T align(const T& value, std::uint64_t align)
{
return static_cast<T>((value + (align - 1)) & ~(align - 1));
}
template<typename To, typename From>
constexpr To narrow_impl(const To& result, const From& value, const char* message)
{
return static_cast<From>(result) != value ? throw std::runtime_error(message) : result;
}
// Narrow cast (similar to gsl::narrow) with fixed message
template<typename To, typename From>
constexpr auto narrow(const From& value, const char* fixed_msg = "::narrow() failed") -> decltype(static_cast<To>(static_cast<From>(std::declval<To>())))
{
return narrow_impl(static_cast<To>(value), value, fixed_msg);
}
// Return 32 bit .size() for container
template<typename CT>
constexpr auto size32(const CT& container, const char* fixed_msg = "::size32() failed") -> decltype(static_cast<std::uint32_t>(container.size()))
{
return narrow<std::uint32_t>(container.size(), fixed_msg);
}
// Return 32 bit size for an array
template<typename T, std::size_t Size>
constexpr std::uint32_t size32(const T(&)[Size])
{
static_assert(Size <= UINT32_MAX, "size32() error: too big");
return static_cast<std::uint32_t>(Size);
}
#define CHECK_SIZE(type, size) static_assert(sizeof(type) == size, "Invalid " #type " type size")
#define CHECK_ALIGN(type, align) static_assert(alignof(type) == align, "Invalid " #type " type alignment")
#define CHECK_MAX_SIZE(type, size) static_assert(sizeof(type) <= size, #type " type size is too big")
#define CHECK_SIZE_ALIGN(type, size, align) CHECK_SIZE(type, size); CHECK_ALIGN(type, align)
// Return 32 bit sizeof() to avoid widening/narrowing conversions with size_t
#define SIZE_32(type) static_cast<std::uint32_t>(sizeof(type))
// Return 32 bit alignof() to avoid widening/narrowing conversions with size_t
#define ALIGN_32(type) static_cast<std::uint32_t>(alignof(type))
// Return 32 bit custom offsetof()
#define OFFSET_32(type, x) static_cast<std::uint32_t>(reinterpret_cast<std::uintptr_t>(&reinterpret_cast<const volatile char&>(reinterpret_cast<type*>(0ull)->x)))
// Sometimes to avoid writing std::remove_cv_t<>, example: std::is_same<CV T1, CV T2>
#define CV const volatile
#define CONCATENATE_DETAIL(x, y) x ## y
#define CONCATENATE(x, y) CONCATENATE_DETAIL(x, y)
#define STRINGIZE_DETAIL(x) #x
#define STRINGIZE(x) STRINGIZE_DETAIL(x)
// Macro set, allows to hide "return" in simple lambda expressions.
#define WRAP_EXPR(expr, ...) [&](__VA_ARGS__) { return expr; }
#define COPY_EXPR(expr, ...) [=](__VA_ARGS__) { return expr; }
#define PURE_EXPR(expr, ...) [] (__VA_ARGS__) { return expr; }
#define HERE "\n(in file " __FILE__ ":" STRINGIZE(__LINE__) ")"
// Ensure that the expression is evaluated to true. Always evaluated and allowed to have side effects (unlike assert() macro).
#define ASSERT(expr) if (!(expr)) throw std::runtime_error("Assertion failed: " #expr HERE)
// Expects() and Ensures() are intended to check function arguments and results.
// Expressions are not guaranteed to evaluate. Redefinition with ASSERT macro for better unification.
#define Expects ASSERT
#define Ensures ASSERT
#define DECLARE(static_member) decltype(static_member) static_member
#define STR_CASE(value) case value: return #value

View file

@ -1,4 +1,4 @@
#include "GNU.h" #include "Platform.h"
#ifdef __APPLE__ #ifdef __APPLE__
#include <sys/types.h> #include <sys/types.h>

View file

@ -1,17 +1,22 @@
#pragma once #pragma once
#include <cstdint>
#include <immintrin.h>
#include <emmintrin.h> #include <emmintrin.h>
#if defined(_MSC_VER) && _MSC_VER <= 1800 #define IS_LE_MACHINE 1
#define thread_local __declspec(thread) #define IS_BE_MACHINE 0
#elif __APPLE__
#define thread_local __thread #ifdef _MSC_VER
#include <intrin.h>
#else
#include <x86intrin.h>
#endif #endif
#if defined(_MSC_VER) // Some platforms don't support thread_local well yet.
#define never_inline __declspec(noinline) #ifndef _MSC_VER
#else #define thread_local __thread
#define never_inline __attribute__((noinline)) #define __assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)
#endif #endif
#if defined(_MSC_VER) #if defined(_MSC_VER)
@ -20,20 +25,21 @@
#define safe_buffers #define safe_buffers
#endif #endif
#if defined(_MSC_VER)
#define never_inline __declspec(noinline)
#else
#define never_inline __attribute__((noinline))
#endif
#if defined(_MSC_VER) #if defined(_MSC_VER)
#define force_inline __forceinline #define force_inline __forceinline
#else #else
#define force_inline __attribute__((always_inline)) inline #define force_inline __attribute__((always_inline)) inline
#endif #endif
#if defined(_MSC_VER) && _MSC_VER <= 1800
#define alignas(x) _CRT_ALIGN(x)
#endif
#if defined(__GNUG__) #if defined(__GNUG__)
#include <stdlib.h> #include <stdlib.h>
#include <cstdint>
#define _fpclass(x) std::fpclassify(x) #define _fpclass(x) std::fpclassify(x)
#define INFINITE 0xFFFFFFFF #define INFINITE 0xFFFFFFFF
@ -59,170 +65,6 @@ int clock_gettime(clockid_t clk_id, struct timespec *tp);
#endif /* __APPLE__ */ #endif /* __APPLE__ */
#endif /* __GNUG__ */ #endif /* __GNUG__ */
#if defined(_MSC_VER)
// Unsigned 128-bit integer implementation
struct alignas(16) u128
{
std::uint64_t lo, hi;
u128() = default;
u128(const u128&) = default;
u128(std::uint64_t l)
: lo(l)
, hi(0)
{
}
u128 operator +(const u128& r) const
{
u128 value;
_addcarry_u64(_addcarry_u64(0, r.lo, lo, &value.lo), r.hi, hi, &value.hi);
return value;
}
friend u128 operator +(const u128& l, std::uint64_t r)
{
u128 value;
_addcarry_u64(_addcarry_u64(0, r, l.lo, &value.lo), l.hi, 0, &value.hi);
return value;
}
friend u128 operator +(std::uint64_t l, const u128& r)
{
u128 value;
_addcarry_u64(_addcarry_u64(0, r.lo, l, &value.lo), 0, r.hi, &value.hi);
return value;
}
u128 operator -(const u128& r) const
{
u128 value;
_subborrow_u64(_subborrow_u64(0, r.lo, lo, &value.lo), r.hi, hi, &value.hi);
return value;
}
friend u128 operator -(const u128& l, std::uint64_t r)
{
u128 value;
_subborrow_u64(_subborrow_u64(0, r, l.lo, &value.lo), 0, l.hi, &value.hi);
return value;
}
friend u128 operator -(std::uint64_t l, const u128& r)
{
u128 value;
_subborrow_u64(_subborrow_u64(0, r.lo, l, &value.lo), r.hi, 0, &value.hi);
return value;
}
u128 operator +() const
{
return *this;
}
u128 operator -() const
{
u128 value;
_subborrow_u64(_subborrow_u64(0, lo, 0, &value.lo), hi, 0, &value.hi);
return value;
}
u128& operator ++()
{
_addcarry_u64(_addcarry_u64(0, 1, lo, &lo), 0, hi, &hi);
return *this;
}
u128 operator ++(int)
{
u128 value = *this;
_addcarry_u64(_addcarry_u64(0, 1, lo, &lo), 0, hi, &hi);
return value;
}
u128& operator --()
{
_subborrow_u64(_subborrow_u64(0, 1, lo, &lo), 0, hi, &hi);
return *this;
}
u128 operator --(int)
{
u128 value = *this;
_subborrow_u64(_subborrow_u64(0, 1, lo, &lo), 0, hi, &hi);
return value;
}
u128 operator ~() const
{
u128 value;
value.lo = ~lo;
value.hi = ~hi;
return value;
}
u128 operator &(const u128& r) const
{
u128 value;
value.lo = lo & r.lo;
value.hi = hi & r.hi;
return value;
}
u128 operator |(const u128& r) const
{
u128 value;
value.lo = lo | r.lo;
value.hi = hi | r.hi;
return value;
}
u128 operator ^(const u128& r) const
{
u128 value;
value.lo = lo ^ r.lo;
value.hi = hi ^ r.hi;
return value;
}
u128& operator +=(const u128& r)
{
_addcarry_u64(_addcarry_u64(0, r.lo, lo, &lo), r.hi, hi, &hi);
return *this;
}
u128& operator +=(uint64_t r)
{
_addcarry_u64(_addcarry_u64(0, r, lo, &lo), 0, hi, &hi);
return *this;
}
u128& operator &=(const u128& r)
{
lo &= r.lo;
hi &= r.hi;
return *this;
}
u128& operator |=(const u128& r)
{
lo |= r.lo;
hi |= r.hi;
return *this;
}
u128& operator ^=(const u128& r)
{
lo ^= r.lo;
hi ^= r.hi;
return *this;
}
};
#endif
inline std::uint32_t cntlz32(std::uint32_t arg) inline std::uint32_t cntlz32(std::uint32_t arg)
{ {
#if defined(_MSC_VER) #if defined(_MSC_VER)
@ -243,7 +85,67 @@ inline std::uint64_t cntlz64(std::uint64_t arg)
#endif #endif
} }
// compare 16 packed unsigned bytes (greater than) template<typename T>
struct add_flags_result_t
{
T result;
bool carry;
//bool overflow;
bool zero;
bool sign;
add_flags_result_t() = default;
// Straighforward ADD with flags
add_flags_result_t(T a, T b)
: result(a + b)
, carry(result < a)
//, overflow((result ^ ~(a ^ b)) >> (sizeof(T) * 8 - 1) != 0)
, zero(result == 0)
, sign(result >> (sizeof(T) * 8 - 1) != 0)
{
}
// Straighforward ADC with flags
add_flags_result_t(T a, T b, bool c)
: add_flags_result_t(a, b)
{
add_flags_result_t r(result, c);
result = r.result;
carry |= r.carry;
//overflow |= r.overflow;
zero = r.zero;
sign = r.sign;
}
};
inline add_flags_result_t<std::uint32_t> add32_flags(std::uint32_t a, std::uint32_t b)
{
//add_flags_result_t<std::uint32_t> r;
//r.carry = _addcarry_u32(0, a, b, &r.result) != 0;
//r.zero = r.result == 0;
//r.sign = r.result >> 31;
//return r;
return{ a, b };
}
inline add_flags_result_t<std::uint32_t> add32_flags(std::uint32_t a, std::uint32_t b, bool c)
{
return{ a, b, c };
}
inline add_flags_result_t<std::uint64_t> add64_flags(std::uint64_t a, std::uint64_t b)
{
return{ a, b };
}
inline add_flags_result_t<std::uint64_t> add64_flags(std::uint64_t a, std::uint64_t b, bool c)
{
return{ a, b, c };
}
// Compare 16 packed unsigned bytes (greater than)
inline __m128i sse_cmpgt_epu8(__m128i A, __m128i B) inline __m128i sse_cmpgt_epu8(__m128i A, __m128i B)
{ {
// (A xor 0x80) > (B xor 0x80) // (A xor 0x80) > (B xor 0x80)
@ -290,3 +192,36 @@ inline __m128 sse_log2_ps(__m128 A)
const auto x8 = _mm_cvtepi32_ps(_mm_sub_epi32(_mm_srli_epi32(_mm_castps_si128(x0), 23), _mm_set1_epi32(127))); const auto x8 = _mm_cvtepi32_ps(_mm_sub_epi32(_mm_srli_epi32(_mm_castps_si128(x0), 23), _mm_set1_epi32(127)));
return _mm_add_ps(_mm_mul_ps(_mm_mul_ps(_mm_mul_ps(_mm_mul_ps(x5, x6), x7), x4), _c), _mm_add_ps(_mm_mul_ps(x4, _c), x8)); return _mm_add_ps(_mm_mul_ps(_mm_mul_ps(_mm_mul_ps(_mm_mul_ps(x5, x6), x7), x4), _c), _mm_add_ps(_mm_mul_ps(x4, _c), x8));
} }
// Helper function, used by ""_u16, ""_u32, ""_u64
constexpr std::uint8_t to_u8(char c)
{
return static_cast<std::uint8_t>(c);
}
// Convert 2-byte string to u16 value like reinterpret_cast does
constexpr std::uint16_t operator""_u16(const char* s, std::size_t length)
{
return length != 2 ? throw s :
#if IS_LE_MACHINE == 1
to_u8(s[1]) << 8 | to_u8(s[0]);
#endif
}
// Convert 4-byte string to u32 value like reinterpret_cast does
constexpr std::uint32_t operator""_u32(const char* s, std::size_t length)
{
return length != 4 ? throw s :
#if IS_LE_MACHINE == 1
to_u8(s[3]) << 24 | to_u8(s[2]) << 16 | to_u8(s[1]) << 8 | to_u8(s[0]);
#endif
}
// Convert 8-byte string to u64 value like reinterpret_cast does
constexpr std::uint64_t operator""_u64(const char* s, std::size_t length)
{
return length != 8 ? throw s :
#if IS_LE_MACHINE == 1
static_cast<std::uint64_t>(to_u8(s[7]) << 24 | to_u8(s[6]) << 16 | to_u8(s[5]) << 8 | to_u8(s[4])) << 32 | to_u8(s[3]) << 24 | to_u8(s[2]) << 16 | to_u8(s[1]) << 8 | to_u8(s[0]);
#endif
}

View file

@ -10,7 +10,7 @@ bool semaphore_t::try_wait()
} }
// try to decrement m_value atomically // try to decrement m_value atomically
const auto old = m_var.atomic_op([](sync_var_t& var) const auto old = m_var.fetch_op([](sync_var_t& var)
{ {
if (var.value) if (var.value)
{ {
@ -36,7 +36,7 @@ bool semaphore_t::try_post()
} }
// try to increment m_value atomically // try to increment m_value atomically
const auto old = m_var.atomic_op([&](sync_var_t& var) const auto old = m_var.fetch_op([&](sync_var_t& var)
{ {
if (var.value < max_value) if (var.value < max_value)
{ {

View file

@ -8,7 +8,7 @@ class semaphore_t
// semaphore condition variable // semaphore condition variable
std::condition_variable m_cv; std::condition_variable m_cv;
struct sync_var_t struct alignas(8) sync_var_t
{ {
u32 value; // current semaphore value u32 value; // current semaphore value
u32 waiters; // current amount of waiters u32 waiters; // current amount of waiters

View file

@ -1,103 +0,0 @@
#include "stdafx.h"
#include "SharedMutex.h"
void shared_mutex::impl_lock_shared(u32 old_value)
{
// Throw if reader count breaks the "second" limit (it should be impossible)
CHECK_ASSERTION((old_value & SM_READER_COUNT) != SM_READER_COUNT);
std::unique_lock<std::mutex> lock(m_mutex);
// Notify non-zero reader queue size
m_ctrl |= SM_READER_QUEUE;
// Compensate incorrectly increased reader count
if ((--m_ctrl & SM_READER_COUNT) == 0 && m_wq_size)
{
// Notify current exclusive owner (condition passed)
m_ocv.notify_one();
}
CHECK_ASSERTION(++m_rq_size);
// Obtain the reader lock
while (!atomic_op(m_ctrl, op_lock_shared))
{
m_rcv.wait(lock);
}
CHECK_ASSERTION(m_rq_size--);
if (m_rq_size == 0)
{
m_ctrl &= ~SM_READER_QUEUE;
}
}
void shared_mutex::impl_unlock_shared(u32 new_value)
{
// Throw if reader count was zero
CHECK_ASSERTION((new_value & SM_READER_COUNT) != SM_READER_COUNT);
// Mutex cannot be unlocked before notification because m_ctrl has been changed outside
std::lock_guard<std::mutex> lock(m_mutex);
if (m_wq_size && (new_value & SM_READER_COUNT) == 0)
{
// Notify current exclusive owner that the latest reader is gone
m_ocv.notify_one();
}
else if (m_rq_size)
{
m_rcv.notify_one();
}
}
void shared_mutex::impl_lock_excl(u32 value)
{
std::unique_lock<std::mutex> lock(m_mutex);
// Notify non-zero writer queue size
m_ctrl |= SM_WRITER_QUEUE;
CHECK_ASSERTION(++m_wq_size);
// Obtain the writer lock
while (!atomic_op(m_ctrl, op_lock_excl))
{
m_wcv.wait(lock);
}
// Wait for remaining readers
while ((m_ctrl & SM_READER_COUNT) != 0)
{
m_ocv.wait(lock);
}
CHECK_ASSERTION(m_wq_size--);
if (m_wq_size == 0)
{
m_ctrl &= ~SM_WRITER_QUEUE;
}
}
void shared_mutex::impl_unlock_excl(u32 value)
{
// Throw if was not locked exclusively
CHECK_ASSERTION(value & SM_WRITER_LOCK);
// Mutex cannot be unlocked before notification because m_ctrl has been changed outside
std::lock_guard<std::mutex> lock(m_mutex);
if (m_wq_size)
{
// Notify next exclusive owner
m_wcv.notify_one();
}
else if (m_rq_size)
{
// Notify all readers
m_rcv.notify_all();
}
}

View file

@ -1,49 +1,156 @@
#pragma once #pragma once
#include <cstdint>
#include <exception>
#include <thread>
#include <mutex>
#include <condition_variable>
#include "Atomic.h"
//! An attempt to create effective implementation of "shared mutex", lock-free in optimistic case. //! An attempt to create effective implementation of "shared mutex", lock-free in optimistic case.
//! All locking and unlocking may be done by single LOCK XADD or LOCK CMPXCHG instructions. //! All locking and unlocking may be done by single LOCK XADD or LOCK CMPXCHG instructions.
//! MSVC implementation of std::shared_timed_mutex seems suboptimal. //! MSVC implementation of std::shared_timed_mutex seems suboptimal.
//! std::shared_mutex is not available until C++17. //! std::shared_mutex is not available until C++17.
class shared_mutex final class shared_mutex final
{ {
enum : u32 using ctrl_type = u32;
{
SM_WRITER_LOCK = 1u << 31, // Exclusive lock flag, must be MSB
SM_WRITER_QUEUE = 1u << 30, // Flag set if m_wq_size != 0
SM_READER_QUEUE = 1u << 29, // Flag set if m_rq_size != 0
SM_READER_COUNT = SM_READER_QUEUE - 1, // Valid reader count bit mask enum : ctrl_type
SM_READER_MAX = 1u << 24, // Max reader count {
SM_WRITER_LOCK = 1u << 31, // Exclusive lock flag, must be MSB
SM_WAITERS_BIT = 1u << 30, // Flag set if m_wq_size or m_rq_size is non-zero
SM_INVALID_BIT = 1u << 29, // Unreachable reader count bit (may be set by incorrect unlock_shared() call)
SM_READER_MASK = SM_WAITERS_BIT - 1, // Valid reader count bit mask
SM_READER_MAX = 1u << 24, // Max reader count
}; };
std::atomic<u32> m_ctrl{}; // Control atomic variable: reader count | SM_* flags atomic_t<ctrl_type> m_ctrl{}; // Control atomic variable: reader count | SM_* flags
std::thread::id m_owner{}; // Current exclusive owner (TODO: implement only for debug mode?)
std::mutex m_mutex; std::mutex m_mutex;
u32 m_rq_size{}; // Reader queue size (threads waiting on m_rcv) std::size_t m_rq_size{}; // Reader queue size (threads waiting on m_rcv)
u32 m_wq_size{}; // Writer queue size (threads waiting on m_wcv+m_ocv) std::size_t m_wq_size{}; // Writer queue size (threads waiting on m_wcv and m_ocv)
std::condition_variable m_rcv; // Reader queue std::condition_variable m_rcv; // Reader queue
std::condition_variable m_wcv; // Writer queue std::condition_variable m_wcv; // Writer queue
std::condition_variable m_ocv; // For current exclusive owner std::condition_variable m_ocv; // For current exclusive owner
static bool op_lock_shared(u32& ctrl) void lock_shared_hard()
{ {
// Check writer flags and reader limit std::unique_lock<std::mutex> lock(m_mutex);
return (ctrl & ~SM_READER_QUEUE) < SM_READER_MAX ? ctrl++, true : false;
// Validate
if ((m_ctrl & SM_INVALID_BIT) != 0) throw std::runtime_error("shared_mutex::lock_shared(): Invalid bit");
if ((m_ctrl & SM_READER_MASK) == 0) throw std::runtime_error("shared_mutex::lock_shared(): No readers");
// Notify non-zero reader queue size
m_ctrl |= SM_WAITERS_BIT, m_rq_size++;
// Fix excess reader count
if ((--m_ctrl & SM_READER_MASK) == 0 && m_wq_size)
{
// Notify exclusive owner
m_ocv.notify_one();
}
// Obtain the reader lock
while (true)
{
const auto ctrl = m_ctrl.load();
// Check writers and reader limit
if (m_wq_size || (ctrl & ~SM_WAITERS_BIT) >= SM_READER_MAX)
{
m_rcv.wait(lock);
continue;
}
if (m_ctrl.compare_and_swap_test(ctrl, ctrl + 1))
{
break;
}
}
if (!--m_rq_size && !m_wq_size)
{
m_ctrl &= ~SM_WAITERS_BIT;
}
} }
static bool op_lock_excl(u32& ctrl) void unlock_shared_notify()
{ {
// Test and set writer lock // Mutex is locked for reliable notification because m_ctrl has been changed outside
return (ctrl & SM_WRITER_LOCK) == 0 ? ctrl |= SM_WRITER_LOCK, true : false; std::lock_guard<std::mutex> lock(m_mutex);
if ((m_ctrl & SM_READER_MASK) == 0 && m_wq_size)
{
// Notify exclusive owner
m_ocv.notify_one();
}
else if (m_rq_size)
{
// Notify other readers
m_rcv.notify_one();
}
} }
void impl_lock_shared(u32 old_ctrl); void lock_hard()
void impl_unlock_shared(u32 new_ctrl); {
void impl_lock_excl(u32 ctrl); std::unique_lock<std::mutex> lock(m_mutex);
void impl_unlock_excl(u32 ctrl);
// Validate
if ((m_ctrl & SM_INVALID_BIT) != 0) throw std::runtime_error("shared_mutex::lock(): Invalid bit");
// Notify non-zero writer queue size
m_ctrl |= SM_WAITERS_BIT, m_wq_size++;
// Obtain the writer lock
while (true)
{
const auto ctrl = m_ctrl.load();
if (ctrl & SM_WRITER_LOCK)
{
m_wcv.wait(lock);
continue;
}
if (m_ctrl.compare_and_swap_test(ctrl, ctrl | SM_WRITER_LOCK))
{
break;
}
}
// Wait for remaining readers
while ((m_ctrl & SM_READER_MASK) != 0)
{
m_ocv.wait(lock);
}
if (!--m_wq_size && !m_rq_size)
{
m_ctrl &= ~SM_WAITERS_BIT;
}
}
void unlock_notify()
{
// Mutex is locked for reliable notification because m_ctrl has been changed outside
std::lock_guard<std::mutex> lock(m_mutex);
if (m_wq_size)
{
// Notify next exclusive owner
m_wcv.notify_one();
}
else if (m_rq_size)
{
// Notify all readers
m_rcv.notify_all();
}
}
public: public:
shared_mutex() = default; shared_mutex() = default;
@ -51,65 +158,49 @@ public:
// Lock in shared mode // Lock in shared mode
void lock_shared() void lock_shared()
{ {
const u32 old_ctrl = m_ctrl++; if (m_ctrl++ >= SM_READER_MAX)
// Check flags and reader limit
if (old_ctrl >= SM_READER_MAX)
{ {
impl_lock_shared(old_ctrl); lock_shared_hard();
} }
} }
// Try to lock in shared mode // Try to lock in shared mode
bool try_lock_shared() bool try_lock_shared()
{ {
return atomic_op(m_ctrl, [](u32& ctrl) auto ctrl = m_ctrl.load();
{
// Check flags and reader limit return ctrl < SM_READER_MAX && m_ctrl.compare_and_swap_test(ctrl, ctrl + 1);
return ctrl < SM_READER_MAX ? ctrl++, true : false;
});
} }
// Unlock in shared mode // Unlock in shared mode
void unlock_shared() void unlock_shared()
{ {
const u32 new_ctrl = --m_ctrl; if (m_ctrl-- >= SM_READER_MAX)
// Check if notification required
if (new_ctrl >= SM_READER_MAX)
{ {
impl_unlock_shared(new_ctrl); unlock_shared_notify();
}
}
// Lock exclusively
void lock()
{
u32 value = 0;
if (!m_ctrl.compare_exchange_strong(value, SM_WRITER_LOCK))
{
impl_lock_excl(value);
} }
} }
// Try to lock exclusively // Try to lock exclusively
bool try_lock() bool try_lock()
{ {
u32 value = 0; return m_ctrl.compare_and_swap_test(0, SM_WRITER_LOCK);
}
return m_ctrl.compare_exchange_strong(value, SM_WRITER_LOCK); // Lock exclusively
void lock()
{
if (m_ctrl.compare_and_swap_test(0, SM_WRITER_LOCK)) return;
lock_hard();
} }
// Unlock exclusively // Unlock exclusively
void unlock() void unlock()
{ {
const u32 value = m_ctrl.fetch_add(SM_WRITER_LOCK); if (m_ctrl.fetch_sub(SM_WRITER_LOCK) != SM_WRITER_LOCK)
// Check if notification required
if (value != SM_WRITER_LOCK)
{ {
impl_unlock_excl(value); unlock_notify();
} }
} }
}; };

View file

@ -1,55 +0,0 @@
#include "stdafx.h"
#include "Emu/CPU/CPUThread.h"
#include "SleepQueue.h"
void sleep_queue_entry_t::add_entry()
{
m_queue.emplace_back(std::static_pointer_cast<CPUThread>(m_thread.shared_from_this()));
}
void sleep_queue_entry_t::remove_entry()
{
for (auto it = m_queue.begin(); it != m_queue.end(); it++)
{
if (it->get() == &m_thread)
{
m_queue.erase(it);
return;
}
}
}
bool sleep_queue_entry_t::find() const
{
for (auto it = m_queue.begin(); it != m_queue.end(); it++)
{
if (it->get() == &m_thread)
{
return true;
}
}
return false;
}
sleep_queue_entry_t::sleep_queue_entry_t(sleep_entry_t& cpu, sleep_queue_t& queue)
: m_thread(cpu)
, m_queue(queue)
{
add_entry();
cpu.sleep();
}
sleep_queue_entry_t::sleep_queue_entry_t(sleep_entry_t& cpu, sleep_queue_t& queue, const defer_sleep_t&)
: m_thread(cpu)
, m_queue(queue)
{
cpu.sleep();
}
sleep_queue_entry_t::~sleep_queue_entry_t()
{
remove_entry();
m_thread.awake();
}

View file

@ -1,45 +1,75 @@
#pragma once #pragma once
using sleep_entry_t = class CPUThread; #include <deque>
using sleep_queue_t = std::deque<std::shared_ptr<sleep_entry_t>>;
static struct defer_sleep_t {} const defer_sleep{}; // Tag used in sleep_entry<> constructor
static struct defer_sleep_tag {} constexpr defer_sleep{};
// automatic object handling a thread entry in the sleep queue // Define sleep queue as std::deque with T* pointers, T - thread type
class sleep_queue_entry_t final template<typename T> using sleep_queue = std::deque<T*>;
// Automatic object handling a thread pointer (T*) in the sleep queue
// Sleep is called in the constructor (if not null)
// Awake is called in the destructor (if not null)
// Sleep queue is actually std::deque with pointers, be careful about the lifetime
template<typename T, void(T::*Sleep)() = &T::sleep, void(T::*Awake)() = &T::awake>
class sleep_entry final
{ {
sleep_entry_t& m_thread; sleep_queue<T>& m_queue;
sleep_queue_t& m_queue; T& m_thread;
void add_entry();
void remove_entry();
bool find() const;
public: public:
// add specified thread to the sleep queue // Constructor; enter() not called
sleep_queue_entry_t(sleep_entry_t& entry, sleep_queue_t& queue); sleep_entry(sleep_queue<T>& queue, T& entry, const defer_sleep_tag&)
: m_queue(queue)
, m_thread(entry)
{
if (Sleep) (m_thread.*Sleep)();
}
// don't add specified thread to the sleep queue // Constructor; calls enter()
sleep_queue_entry_t(sleep_entry_t& entry, sleep_queue_t& queue, const defer_sleep_t&); sleep_entry(sleep_queue<T>& queue, T& entry)
: sleep_entry(queue, entry, defer_sleep)
{
enter();
}
// removes specified thread from the sleep queue if added // Destructor; calls leave()
~sleep_queue_entry_t(); ~sleep_entry()
{
leave();
if (Awake) (m_thread.*Awake)();
}
// add thread to the sleep queue // Add thread to the sleep queue
void enter() void enter()
{ {
add_entry(); for (auto t : m_queue)
{
if (t == &m_thread)
{
// Already exists, is it an error?
return;
}
}
m_queue.emplace_back(&m_thread);
} }
// remove thread from the sleep queue // Remove thread from the sleep queue
void leave() void leave()
{ {
remove_entry(); auto it = std::find(m_queue.begin(), m_queue.end(), &m_thread);
if (it != m_queue.end())
{
m_queue.erase(it);
}
} }
// check whether the thread exists in the sleep queue // Check whether the thread exists in the sleep queue
explicit operator bool() const explicit operator bool() const
{ {
return find(); return std::find(m_queue.begin(), m_queue.end(), &m_thread) != m_queue.end();
} }
}; };

View file

@ -1,9 +1,5 @@
#include "stdafx.h" #include "StrFmt.h"
#pragma warning(push) #include "BEType.h"
#pragma message("TODO: remove wx dependency: <wx/string.h>")
#pragma warning(disable : 4996)
#include <wx/string.h>
#pragma warning(pop)
std::string v128::to_hex() const std::string v128::to_hex() const
{ {
@ -19,7 +15,7 @@ std::string fmt::to_hex(u64 value, u64 count)
{ {
if (count - 1 >= 16) if (count - 1 >= 16)
{ {
throw EXCEPTION("Invalid count: 0x%llx", count); throw exception("fmt::to_hex(): invalid count: 0x%llx", count);
} }
count = std::max<u64>(count, 16 - cntlz64(value) / 4); count = std::max<u64>(count, 16 - cntlz64(value) / 4);
@ -78,8 +74,6 @@ std::string fmt::to_sdec(s64 svalue)
return std::string(&res[first], sizeof(res) - first); return std::string(&res[first], sizeof(res) - first);
} }
//extern const std::string fmt::placeholder = "???";
std::string fmt::replace_first(const std::string& src, const std::string& from, const std::string& to) std::string fmt::replace_first(const std::string& src, const std::string& from, const std::string& to)
{ {
auto pos = src.find(from); auto pos = src.find(from);
@ -104,83 +98,6 @@ std::string fmt::replace_all(const std::string &src, const std::string& from, co
return target; return target;
} }
//TODO: move this wx Stuff somewhere else
//convert a wxString to a std::string encoded in utf8
//CAUTION, only use this to interface with wxWidgets classes
std::string fmt::ToUTF8(const wxString& right)
{
auto ret = std::string(((const char *)right.utf8_str()));
return ret;
}
//convert a std::string encoded in utf8 to a wxString
//CAUTION, only use this to interface with wxWidgets classes
wxString fmt::FromUTF8(const std::string& right)
{
auto ret = wxString::FromUTF8(right.c_str());
return ret;
}
//TODO: remove this after every snippet that uses it is gone
//WARNING: not fully compatible with CmpNoCase from wxString
int fmt::CmpNoCase(const std::string& a, const std::string& b)
{
if (a.length() != b.length())
{
return -1;
}
else
{
return std::equal(a.begin(),
a.end(),
b.begin(),
[](const char& a, const char& b){return ::tolower(a) == ::tolower(b); })
? 0 : -1;
}
}
//TODO: remove this after every snippet that uses it is gone
//WARNING: not fully compatible with CmpNoCase from wxString
void fmt::Replace(std::string &str, const std::string &searchterm, const std::string& replaceterm)
{
size_t cursor = 0;
do
{
cursor = str.find(searchterm, cursor);
if (cursor != std::string::npos)
{
str.replace(cursor, searchterm.size(), replaceterm);
cursor += replaceterm.size();
}
else
{
break;
}
} while (true);
}
std::vector<std::string> fmt::rSplit(const std::string& source, const std::string& delim)
{
std::vector<std::string> ret;
size_t cursor = 0;
do
{
size_t prevcurs = cursor;
cursor = source.find(delim, cursor);
if (cursor != std::string::npos)
{
ret.push_back(source.substr(prevcurs,cursor-prevcurs));
cursor += delim.size();
}
else
{
ret.push_back(source.substr(prevcurs));
break;
}
} while (true);
return ret;
}
std::vector<std::string> fmt::split(const std::string& source, std::initializer_list<std::string> separators, bool is_skip_empty) std::vector<std::string> fmt::split(const std::string& source, std::initializer_list<std::string> separators, bool is_skip_empty)
{ {
std::vector<std::string> result; std::vector<std::string> result;
@ -222,21 +139,7 @@ std::string fmt::trim(const std::string& source, const std::string& values)
return source.substr(begin, source.find_last_not_of(values) + 1); return source.substr(begin, source.find_last_not_of(values) + 1);
} }
std::string fmt::tolower(std::string source) std::string fmt::escape(const std::string& source, std::initializer_list<char> more)
{
std::transform(source.begin(), source.end(), source.begin(), ::tolower);
return source;
}
std::string fmt::toupper(std::string source)
{
std::transform(source.begin(), source.end(), source.begin(), ::toupper);
return source;
}
std::string fmt::escape(std::string source)
{ {
const std::pair<std::string, std::string> escape_list[] = const std::pair<std::string, std::string> escape_list[] =
{ {
@ -244,20 +147,66 @@ std::string fmt::escape(std::string source)
{ "\a", "\\a" }, { "\a", "\\a" },
{ "\b", "\\b" }, { "\b", "\\b" },
{ "\f", "\\f" }, { "\f", "\\f" },
{ "\n", "\\n\n" }, { "\n", "\\n" },
{ "\r", "\\r" }, { "\r", "\\r" },
{ "\t", "\\t" }, { "\t", "\\t" },
{ "\v", "\\v" }, { "\v", "\\v" },
}; };
source = fmt::replace_all(source, escape_list); std::string result = fmt::replace_all(source, escape_list);
for (char c = 0; c < 32; c++) for (char c = 0; c < 32; c++)
{ {
if (c != '\n') source = fmt::replace_all(source, std::string(1, c), fmt::format("\\x%02X", c)); result = fmt::replace_all(result, std::string(1, c), fmt::format("\\x%02X", c));
} }
return source; for (char c : more)
{
result = fmt::replace_all(result, std::string(1, c), fmt::format("\\x%02X", c));
}
return result;
}
std::string fmt::unescape(const std::string& source)
{
std::string result;
for (auto it = source.begin(); it != source.end();)
{
const char bs = *it++;
if (bs == '\\' && it != source.end())
{
switch (const char code = *it++)
{
case 'a': result += '\a'; break;
case 'b': result += '\b'; break;
case 'f': result += '\f'; break;
case 'n': result += '\n'; break;
case 'r': result += '\r'; break;
case 't': result += '\t'; break;
case 'v': result += '\v'; break;
case 'x':
{
// Detect hexadecimal character code (TODO)
if (source.end() - it >= 2)
{
result += std::stoi(std::string{ *it++, *it++ }, 0, 16);
}
}
// Octal/unicode not supported
default: result += code;
}
}
else
{
result += bs;
}
}
return result;
} }
bool fmt::match(const std::string &source, const std::string &mask) bool fmt::match(const std::string &source, const std::string &mask)

View file

@ -1,95 +1,38 @@
#pragma once #pragma once
class wxString; #include <array>
#include <string>
#include <vector>
#include <functional>
#include <memory>
#include "Platform.h"
#include "types.h"
#if defined(_MSC_VER) && _MSC_VER <= 1800 #if defined(_MSC_VER) && _MSC_VER <= 1800
#define snprintf _snprintf #define snprintf _snprintf
#endif #endif
// Copy null-terminated string from std::string to char array with truncation
template<std::size_t N>
inline void strcpy_trunc(char(&dst)[N], const std::string& src)
{
const std::size_t count = src.size() >= N ? N - 1 : src.size();
std::memcpy(dst, src.c_str(), count);
dst[count] = '\0';
}
// Copy null-terminated string from char array to another char array with truncation
template<std::size_t N, std::size_t N2>
inline void strcpy_trunc(char(&dst)[N], const char(&src)[N2])
{
const std::size_t count = N2 >= N ? N - 1 : N2;
std::memcpy(dst, src, count);
dst[count] = '\0';
}
namespace fmt namespace fmt
{ {
//struct empty_t{};
//extern const std::string placeholder;
template <typename T>
std::string AfterLast(const std::string& source, T searchstr)
{
size_t search_pos = source.rfind(searchstr);
search_pos = search_pos == std::string::npos ? 0 : search_pos;
return source.substr(search_pos);
}
template <typename T>
std::string BeforeLast(const std::string& source, T searchstr)
{
size_t search_pos = source.rfind(searchstr);
search_pos = search_pos == std::string::npos ? 0 : search_pos;
return source.substr(0, search_pos);
}
template <typename T>
std::string AfterFirst(const std::string& source, T searchstr)
{
size_t search_pos = source.find(searchstr);
search_pos = search_pos == std::string::npos ? 0 : search_pos;
return source.substr(search_pos);
}
template <typename T>
std::string BeforeFirst(const std::string& source, T searchstr)
{
size_t search_pos = source.find(searchstr);
search_pos = search_pos == std::string::npos ? 0 : search_pos;
return source.substr(0, search_pos);
}
// write `fmt` from `pos` to the first occurence of `fmt::placeholder` to
// the stream `os`. Then write `arg` to to the stream. If there's no
// `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<typename T>
//empty_t write(const std::string &fmt, std::ostream &os, std::string::size_type &pos, T &&arg)
//{
// std::string::size_type ins = fmt.find(placeholder, pos);
// if (ins == std::string::npos)
// {
// os.write(fmt.data() + pos, fmt.size() - pos);
// os << ' ' << arg;
// pos = fmt.size();
// }
// else
// {
// os.write(fmt.data() + pos, ins - pos);
// os << arg;
// pos = ins + placeholder.size();
// }
// return{};
//}
// typesafe version of a sprintf-like function. Returns the printed to
// string. To mark positions where the arguments are supposed to be
// inserted use `fmt::placeholder`. If there's not enough placeholders
// the rest of the arguments are appended at the end, seperated by spaces
//template<typename ... Args>
//std::string SFormat(const std::string &fmt, Args&& ... parameters)
//{
// std::ostringstream os;
// std::string::size_type pos = 0;
// std::initializer_list<empty_t> { write(fmt, os, pos, parameters)... };
// if (!fmt.empty())
// {
// os.write(fmt.data() + pos, fmt.size() - pos);
// }
// std::string result = os.str();
// return result;
//}
std::string replace_first(const std::string& src, const std::string& from, const std::string& to); std::string replace_first(const std::string& src, const std::string& from, const std::string& to);
std::string replace_all(const std::string &src, const std::string& from, const std::string& to); std::string replace_all(const std::string &src, const std::string& from, const std::string& to);
@ -145,7 +88,8 @@ namespace fmt
std::string to_udec(u64 value); std::string to_udec(u64 value);
std::string to_sdec(s64 value); std::string to_sdec(s64 value);
template<typename T, bool is_enum = std::is_enum<T>::value> struct unveil template<typename T, typename>
struct unveil
{ {
using result_type = T; using result_type = T;
@ -155,37 +99,41 @@ namespace fmt
} }
}; };
template<> struct unveil<const char*, false> template<>
struct unveil<const char*, void>
{ {
using result_type = const char* const; using result_type = const char* const;
force_inline static result_type get_value(const char* const& arg) static result_type get_value(const char* const& arg)
{ {
return arg; return arg;
} }
}; };
template<std::size_t N> struct unveil<char[N], false> template<std::size_t N>
struct unveil<char[N], void>
{ {
using result_type = const char* const; using result_type = const char* const;
force_inline static result_type get_value(const char(&arg)[N]) static result_type get_value(const char(&arg)[N])
{ {
return arg; return arg;
} }
}; };
template<> struct unveil<std::string, false> template<>
struct unveil<std::string, void>
{ {
using result_type = const char*; using result_type = const char*;
force_inline static result_type get_value(const std::string& arg) static result_type get_value(const std::string& arg)
{ {
return arg.c_str(); return arg.c_str();
} }
}; };
template<typename T> struct unveil<T, true> template<typename T>
struct unveil<T, std::enable_if_t<std::is_enum<T>::value>>
{ {
using result_type = std::underlying_type_t<T>; using result_type = std::underlying_type_t<T>;
@ -195,31 +143,13 @@ namespace fmt
} }
}; };
template<typename T, bool Se> struct unveil<se_t<T, Se>, false>
{
using result_type = typename unveil<T>::result_type;
force_inline static result_type get_value(const se_t<T, Se>& arg)
{
return unveil<T>::get_value(arg);
}
};
template<typename T> template<typename T>
force_inline typename unveil<T>::result_type do_unveil(const T& arg) force_inline typename unveil<T>::result_type do_unveil(const T& arg)
{ {
return unveil<T>::get_value(arg); return unveil<T>::get_value(arg);
} }
// Formatting function with special functionality: // Formatting function with special functionality (fmt::unveil)
//
// std::string is forced to .c_str()
// be_t<> is forced to .value() (fmt::do_unveil reverts byte order automatically)
//
// External specializations for fmt::do_unveil (can be found in another headers):
// vm::ptr, vm::bptr, ... (fmt::do_unveil) (vm_ptr.h) (with appropriate address type, using .addr() can be avoided)
// vm::ref, vm::bref, ... (fmt::do_unveil) (vm_ref.h)
//
template<typename... Args> template<typename... Args>
safe_buffers std::string format(const char* fmt, const Args&... args) safe_buffers std::string format(const char* fmt, const Args&... args)
{ {
@ -256,51 +186,28 @@ namespace fmt
} }
} }
struct exception : public std::exception // Create exception of type T (std::runtime_error by default) with formatting
template<typename T = std::runtime_error, typename... Args>
never_inline safe_buffers T exception(const char* fmt, const Args&... args) noexcept(noexcept(T{ fmt }))
{ {
std::unique_ptr<char[]> message; return T{ format(fmt, do_unveil(args)...).c_str() };
}
template<typename... Args> never_inline safe_buffers exception(const char* file, int line, const char* func, const char* text, Args... args) noexcept // Create exception of type T (std::runtime_error by default) without formatting
{ template<typename T = std::runtime_error>
const std::string data = format(text, args...) + format("\n(in file %s:%d, in function %s)", file, line, func); safe_buffers T exception(const char* msg) noexcept(noexcept(T{ msg }))
{
return T{ msg };
}
message.reset(new char[data.size() + 1]); // Narrow cast (similar to gsl::narrow) with exception message formatting
template<typename To, typename From, typename... Args>
std::memcpy(message.get(), data.c_str(), data.size() + 1); inline auto narrow(const char* format_str, const From& value, const Args&... args) -> decltype(static_cast<To>(static_cast<From>(std::declval<To>())))
} {
const auto result = static_cast<To>(value);
exception(const exception& other) noexcept if (static_cast<From>(result) != value) throw fmt::exception(format_str, fmt::do_unveil(value), fmt::do_unveil(args)...);
{ return result;
const std::size_t size = std::strlen(other.message.get()); }
message.reset(new char[size + 1]);
std::memcpy(message.get(), other.message.get(), size + 1);
}
virtual const char* what() const noexcept override
{
return message.get();
}
};
//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 std::string& right);
//TODO: remove this after every snippet that uses it is gone
//WARNING: not fully compatible with CmpNoCase from wxString
int CmpNoCase(const std::string& a, const std::string& b);
//TODO: remove this after every snippet that uses it is gone
//WARNING: not fully compatible with Replace from wxString
void Replace(std::string &str, const std::string &searchterm, const std::string& replaceterm);
std::vector<std::string> rSplit(const std::string& source, const std::string& delim);
std::vector<std::string> split(const std::string& source, std::initializer_list<std::string> separators, bool is_skip_empty = true); std::vector<std::string> split(const std::string& source, std::initializer_list<std::string> separators, bool is_skip_empty = true);
std::string trim(const std::string& source, const std::string& values = " \t"); std::string trim(const std::string& source, const std::string& values = " \t");
@ -352,8 +259,35 @@ namespace fmt
return result; return result;
} }
std::string tolower(std::string source); template<typename IT>
std::string toupper(std::string source); std::string to_lower(IT _begin, IT _end)
std::string escape(std::string source); {
std::string result; result.resize(_end - _begin);
std::transform(_begin, _end, result.begin(), ::tolower);
return result;
}
template<typename T>
std::string to_lower(const T& string)
{
return to_lower(std::begin(string), std::end(string));
}
template<typename IT>
std::string to_upper(IT _begin, IT _end)
{
std::string result; result.resize(_end - _begin);
std::transform(_begin, _end, result.begin(), ::toupper);
return result;
}
template<typename T>
std::string to_upper(const T& string)
{
return to_upper(std::begin(string), std::end(string));
}
std::string escape(const std::string& source, std::initializer_list<char> more = {});
std::string unescape(const std::string& source);
bool match(const std::string &source, const std::string &mask); bool match(const std::string &source, const std::string &mask);
} }

View file

@ -1,11 +1,8 @@
#include "stdafx.h" #include "stdafx.h"
#include "Log.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/state.h" #include "Emu/IdManager.h"
#include "Emu/CPU/CPUThreadManager.h"
#include "Emu/CPU/CPUThread.h"
#include "Emu/Cell/RawSPUThread.h" #include "Emu/Cell/RawSPUThread.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Thread.h" #include "Thread.h"
#ifdef _WIN32 #ifdef _WIN32
@ -21,10 +18,19 @@
static void report_fatal_error(const std::string& msg) static void report_fatal_error(const std::string& msg)
{ {
std::string _msg = msg + "\n"
"HOW TO REPORT ERRORS:\n"
"1) Check the FAQ, readme, other sources. Please ensure that your hardware and software configuration is compliant.\n"
"2) You must provide FULL information: how to reproduce the error (your actions), RPCS3.log file, other *.log files whenever requested.\n"
"3) Please ensure that your software (game) is 'Playable' or close. Please note that 'Non-playable' games will be ignored.\n"
"4) If the software (game) is not 'Playable', please ensure that this error is unexpected, i.e. it didn't happen before or similar.\n"
"Please, don't send incorrect reports. Thanks for understanding.\n";
#ifdef _WIN32 #ifdef _WIN32
MessageBoxA(0, msg.c_str(), "Fatal error", MB_ICONERROR); // TODO: unicode message _msg += "Press (Ctrl+C) to copy this message.";
MessageBoxA(0, _msg.c_str(), "Fatal error", MB_ICONERROR); // TODO: unicode message
#else #else
std::printf("Fatal error: %s\nPlease report this error to the developers.\n", msg.c_str()); std::printf("Fatal error: \n%s", _msg.c_str());
#endif #endif
} }
@ -34,9 +40,9 @@ static void report_fatal_error(const std::string& msg)
{ {
throw; throw;
} }
catch (const std::exception& ex) catch (const std::exception& e)
{ {
report_fatal_error("Unhandled exception: "s + ex.what()); report_fatal_error("Unhandled exception of type '"s + typeid(e).name() + "': "s + e.what());
} }
catch (...) catch (...)
{ {
@ -775,8 +781,7 @@ size_t get_x64_access_size(x64_context* context, x64_op_t op, x64_reg_t reg, siz
if (op == X64OP_CMPXCHG) if (op == X64OP_CMPXCHG)
{ {
// detect whether this instruction can't actually modify memory to avoid breaking reservation; // Detect whether the instruction can't actually modify memory to avoid breaking reservation
// this may theoretically cause endless loop, but it shouldn't be a problem if only load_sync() generates such instruction
u64 cmp, exch; u64 cmp, exch;
if (!get_x64_reg_value(context, reg, d_size, i_size, cmp) || !get_x64_reg_value(context, X64R_RAX, d_size, i_size, exch)) if (!get_x64_reg_value(context, reg, d_size, i_size, cmp) || !get_x64_reg_value(context, X64R_RAX, d_size, i_size, exch))
{ {
@ -843,7 +848,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
// check if address is RawSPU MMIO register // check if address is RawSPU MMIO register
if (addr - RAW_SPU_BASE_ADDR < (6 * RAW_SPU_OFFSET) && (addr % RAW_SPU_OFFSET) >= RAW_SPU_PROB_OFFSET) if (addr - RAW_SPU_BASE_ADDR < (6 * RAW_SPU_OFFSET) && (addr % RAW_SPU_OFFSET) >= RAW_SPU_PROB_OFFSET)
{ {
auto thread = Emu.GetCPU().GetRawSPUThread((addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET); auto thread = idm::get<RawSPUThread>((addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET);
if (!thread) if (!thread)
{ {
@ -1051,10 +1056,10 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
switch (d_size) switch (d_size)
{ {
case 1: reg_value = sync_lock_test_and_set((u8*)vm::base_priv(addr), (u8)reg_value); break; case 1: reg_value = ((atomic_t<u8>*)vm::base_priv(addr))->exchange((u8)reg_value); break;
case 2: reg_value = sync_lock_test_and_set((u16*)vm::base_priv(addr), (u16)reg_value); break; case 2: reg_value = ((atomic_t<u16>*)vm::base_priv(addr))->exchange((u16)reg_value); break;
case 4: reg_value = sync_lock_test_and_set((u32*)vm::base_priv(addr), (u32)reg_value); break; case 4: reg_value = ((atomic_t<u32>*)vm::base_priv(addr))->exchange((u32)reg_value); break;
case 8: reg_value = sync_lock_test_and_set((u64*)vm::base_priv(addr), (u64)reg_value); break; case 8: reg_value = ((atomic_t<u64>*)vm::base_priv(addr))->exchange((u64)reg_value); break;
default: return false; default: return false;
} }
@ -1074,10 +1079,10 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
switch (d_size) switch (d_size)
{ {
case 1: old_value = sync_val_compare_and_swap((u8*)vm::base_priv(addr), (u8)cmp_value, (u8)reg_value); break; case 1: old_value = ((atomic_t<u8>*)vm::base_priv(addr))->compare_and_swap((u8)cmp_value, (u8)reg_value); break;
case 2: old_value = sync_val_compare_and_swap((u16*)vm::base_priv(addr), (u16)cmp_value, (u16)reg_value); break; case 2: old_value = ((atomic_t<u16>*)vm::base_priv(addr))->compare_and_swap((u16)cmp_value, (u16)reg_value); break;
case 4: old_value = sync_val_compare_and_swap((u32*)vm::base_priv(addr), (u32)cmp_value, (u32)reg_value); break; case 4: old_value = ((atomic_t<u32>*)vm::base_priv(addr))->compare_and_swap((u32)cmp_value, (u32)reg_value); break;
case 8: old_value = sync_val_compare_and_swap((u64*)vm::base_priv(addr), (u64)cmp_value, (u64)reg_value); break; case 8: old_value = ((atomic_t<u64>*)vm::base_priv(addr))->compare_and_swap((u64)cmp_value, (u64)reg_value); break;
default: return false; default: return false;
} }
@ -1097,10 +1102,10 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
switch (d_size) switch (d_size)
{ {
case 1: value &= sync_fetch_and_and((u8*)vm::base_priv(addr), (u8)value); break; case 1: value = *(atomic_t<u8>*)vm::base_priv(addr) &= (u8)value; break;
case 2: value &= sync_fetch_and_and((u16*)vm::base_priv(addr), (u16)value); break; case 2: value = *(atomic_t<u16>*)vm::base_priv(addr) &= (u16)value; break;
case 4: value &= sync_fetch_and_and((u32*)vm::base_priv(addr), (u32)value); break; case 4: value = *(atomic_t<u32>*)vm::base_priv(addr) &= (u32)value; break;
case 8: value &= sync_fetch_and_and((u64*)vm::base_priv(addr), (u64)value); break; case 8: value = *(atomic_t<u64>*)vm::base_priv(addr) &= (u64)value; break;
default: return false; default: return false;
} }
@ -1126,14 +1131,14 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
// TODO: allow recovering from a page fault as a feature of PS3 virtual memory // TODO: allow recovering from a page fault as a feature of PS3 virtual memory
} }
// Throw virtual memory access violation exception [[noreturn]] static void throw_access_violation(const char* cause, u64 addr)
[[noreturn]] void throw_access_violation(const char* cause, u32 address) // Don't change function definition
{ {
throw EXCEPTION("Access violation %s location 0x%08x", cause, address); vm::throw_access_violation(addr, cause);
std::abort();
} }
// Modify context in order to convert hardware exception to C++ exception // Modify context in order to convert hardware exception to C++ exception
void prepare_throw_access_violation(x64_context* context, const char* cause, u32 address) static void prepare_throw_access_violation(x64_context* context, const char* cause, u32 address)
{ {
// Set throw_access_violation() call args (old register values are lost) // Set throw_access_violation() call args (old register values are lost)
ARG1(context) = (u64)cause; ARG1(context) = (u64)cause;
@ -1151,14 +1156,17 @@ static LONG exception_handler(PEXCEPTION_POINTERS pExp)
const u64 addr64 = pExp->ExceptionRecord->ExceptionInformation[1] - (u64)vm::base(0); const u64 addr64 = pExp->ExceptionRecord->ExceptionInformation[1] - (u64)vm::base(0);
const bool is_writing = pExp->ExceptionRecord->ExceptionInformation[0] != 0; const bool is_writing = pExp->ExceptionRecord->ExceptionInformation[0] != 0;
if (pExp->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && addr64 < 0x100000000ull && thread_ctrl::get_current() && handle_access_violation((u32)addr64, is_writing, pExp->ContextRecord)) if (pExp->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && addr64 < 0x100000000ull)
{ {
return EXCEPTION_CONTINUE_EXECUTION; vm::g_tls_fault_count++;
}
else if (thread_ctrl::get_current() && handle_access_violation((u32)addr64, is_writing, pExp->ContextRecord))
{ {
return EXCEPTION_CONTINUE_SEARCH; return EXCEPTION_CONTINUE_EXECUTION;
}
} }
return EXCEPTION_CONTINUE_SEARCH;
} }
static LONG exception_filter(PEXCEPTION_POINTERS pExp) static LONG exception_filter(PEXCEPTION_POINTERS pExp)
@ -1170,8 +1178,9 @@ static LONG exception_filter(PEXCEPTION_POINTERS pExp)
const u64 addr64 = pExp->ExceptionRecord->ExceptionInformation[1] - (u64)vm::base(0); const u64 addr64 = pExp->ExceptionRecord->ExceptionInformation[1] - (u64)vm::base(0);
const auto cause = pExp->ExceptionRecord->ExceptionInformation[0] != 0 ? "writing" : "reading"; const auto cause = pExp->ExceptionRecord->ExceptionInformation[0] != 0 ? "writing" : "reading";
if (addr64 < 0x100000000ull) if (!(vm::g_tls_fault_count & (1ull << 63)) && addr64 < 0x100000000ull)
{ {
vm::g_tls_fault_count |= (1ull << 63);
// Setup throw_access_violation() call on the context // Setup throw_access_violation() call on the context
prepare_throw_access_violation(pExp->ContextRecord, cause, (u32)addr64); prepare_throw_access_violation(pExp->ContextRecord, cause, (u32)addr64);
return EXCEPTION_CONTINUE_EXECUTION; return EXCEPTION_CONTINUE_EXECUTION;
@ -1190,33 +1199,23 @@ static LONG exception_filter(PEXCEPTION_POINTERS pExp)
} }
msg += fmt::format("Instruction address: %p.\n", pExp->ContextRecord->Rip); msg += fmt::format("Instruction address: %p.\n", pExp->ContextRecord->Rip);
msg += fmt::format("Image base: %p.", GetModuleHandle(NULL)); msg += fmt::format("Image base: %p.\n", GetModuleHandle(NULL));
if (pExp->ExceptionRecord->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION)
{
msg += "\n"
"Illegal instruction exception occured.\n"
"Note that your CPU must support SSSE3 extension.\n";
}
// TODO: print registers and the callstack // TODO: print registers and the callstack
// Exception specific messages
if (pExp->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
{
msg += "\n\nAn internal access violation has occured."
"\nPlease only report this error to the developers, if you're an advanced user and have obtained a stack trace.";
}
else if (pExp->ExceptionRecord->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION)
{
msg += "\n\nAn internal illegal instruction exception has occured."
"\nRPCS3 requires a modern x86-64 CPU that supports SSSE3 (and SSE4.1 for PPU LLVM recompiler)."
"\nPlease make sure that your CPU supports these extensions.";
}
else
{
msg += "\n\nAn unknown internal exception has occured. Please report this to the developers.\nYou can press (Ctrl+C) to copy this message.";
}
// Report fatal error // Report fatal error
report_fatal_error(msg); report_fatal_error(msg);
return EXCEPTION_CONTINUE_SEARCH; return EXCEPTION_CONTINUE_SEARCH;
} }
const bool g_exception_handler_set = []() -> bool const bool s_exception_handler_set = []() -> bool
{ {
if (!AddVectoredExceptionHandler(1, (PVECTORED_EXCEPTION_HANDLER)exception_handler)) if (!AddVectoredExceptionHandler(1, (PVECTORED_EXCEPTION_HANDLER)exception_handler))
{ {
@ -1248,12 +1247,12 @@ static void signal_handler(int sig, siginfo_t* info, void* uct)
const u64 addr64 = (u64)info->si_addr - (u64)vm::base(0); const u64 addr64 = (u64)info->si_addr - (u64)vm::base(0);
const auto cause = is_writing ? "writing" : "reading"; const auto cause = is_writing ? "writing" : "reading";
// TODO: Exception specific informative messages if (addr64 < 0x100000000ull)
if (addr64 < 0x100000000ull && thread_ctrl::get_current())
{ {
vm::g_tls_fault_count++;
// Try to process access violation // Try to process access violation
if (!handle_access_violation((u32)addr64, is_writing, context)) if (!thread_ctrl::get_current() || !handle_access_violation((u32)addr64, is_writing, context))
{ {
// Setup throw_access_violation() call on the context // Setup throw_access_violation() call on the context
prepare_throw_access_violation(context, cause, (u32)addr64); prepare_throw_access_violation(context, cause, (u32)addr64);
@ -1267,7 +1266,7 @@ static void signal_handler(int sig, siginfo_t* info, void* uct)
} }
} }
const bool g_exception_handler_set = []() -> bool const bool s_exception_handler_set = []() -> bool
{ {
struct ::sigaction sa; struct ::sigaction sa;
sa.sa_flags = SA_SIGINFO; sa.sa_flags = SA_SIGINFO;
@ -1285,17 +1284,33 @@ const bool g_exception_handler_set = []() -> bool
#endif #endif
thread_local thread_ctrl* thread_ctrl::g_tls_this_thread = nullptr; const bool s_self_test = []() -> bool
{
// Find ret instruction
if ((*(u8*)throw_access_violation & 0xF6) == 0xC2)
{
std::abort();
}
return true;
}();
thread_local DECLARE(thread_ctrl::g_tls_this_thread) = nullptr;
// TODO // TODO
std::atomic<u32> g_thread_count{ 0 }; atomic_t<u32> g_thread_count{ 0 };
void thread_ctrl::initialize() void thread_ctrl::initialize()
{ {
SetCurrentThreadDebugName(g_tls_this_thread->m_name().c_str()); SetCurrentThreadDebugName(g_tls_this_thread->m_name.c_str());
_log::g_tls_make_prefix = [](const auto&, auto, const auto&)
{
return g_tls_this_thread->m_name;
};
// TODO // TODO
g_thread_count++; ++g_thread_count;
} }
void thread_ctrl::finalize() noexcept void thread_ctrl::finalize() noexcept
@ -1304,79 +1319,36 @@ void thread_ctrl::finalize() noexcept
vm::reservation_free(); vm::reservation_free();
// TODO // TODO
g_thread_count--; --g_thread_count;
// Call atexit functions // Call atexit functions
for (const auto& func : decltype(m_atexit)(std::move(g_tls_this_thread->m_atexit))) g_tls_this_thread->m_atexit.exec();
{
func();
}
} }
thread_ctrl::~thread_ctrl() std::string named_thread::get_name() const
{
m_thread.detach();
if (m_future.valid())
{
try
{
m_future.get();
}
catch (...)
{
catch_all_exceptions();
}
}
}
std::string thread_ctrl::get_name() const
{
CHECK_ASSERTION(m_name);
return m_name();
}
std::string named_thread_t::get_name() const
{ {
return fmt::format("('%s') Unnamed Thread", typeid(*this).name()); return fmt::format("('%s') Unnamed Thread", typeid(*this).name());
} }
void named_thread_t::start() void named_thread::start()
{ {
CHECK_ASSERTION(!m_thread); Expects(!m_thread);
// Get shared_ptr instance (will throw if called from the constructor or the object has been created incorrectly) // Get shared_ptr instance (will throw if called from the constructor or the object has been created incorrectly)
auto ptr = shared_from_this(); auto&& ptr = shared_from_this();
// Make name getter
auto name = [wptr = std::weak_ptr<named_thread_t>(ptr), type = &typeid(*this)]()
{
// Return actual name if available
if (const auto ptr = wptr.lock())
{
return ptr->get_name();
}
else
{
return fmt::format("('%s') Deleted Thread", type->name());
}
};
// Run thread // Run thread
m_thread = thread_ctrl::spawn(std::move(name), [thread = std::move(ptr)]() m_thread = thread_ctrl::spawn(get_name(), [thread = std::move(ptr)]()
{ {
try try
{ {
LOG_TRACE(GENERAL, "Thread started"); LOG_TRACE(GENERAL, "Thread started");
thread->on_task(); thread->on_task();
LOG_TRACE(GENERAL, "Thread ended"); LOG_TRACE(GENERAL, "Thread ended");
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
LOG_FATAL(GENERAL, "Exception: %s", e.what()); LOG_FATAL(GENERAL, "%s thrown: %s", typeid(e).name(), e.what());
Emu.Pause(); Emu.Pause();
} }
catch (EmulationStopped) catch (EmulationStopped)
@ -1388,9 +1360,9 @@ void named_thread_t::start()
}); });
} }
void named_thread_t::join() void named_thread::join()
{ {
CHECK_ASSERTION(m_thread != nullptr); Expects(m_thread);
try try
{ {
@ -1403,11 +1375,3 @@ void named_thread_t::join()
throw; throw;
} }
} }
const std::function<bool()> SQUEUE_ALWAYS_EXIT = [](){ return true; };
const std::function<bool()> SQUEUE_NEVER_EXIT = [](){ return false; };
bool squeue_test_exit()
{
return Emu.IsStopped();
}

View file

@ -1,24 +1,96 @@
#pragma once #pragma once
#include <exception>
#include <string>
#include <memory>
#include <thread>
#include <mutex>
#include <condition_variable>
#include "Platform.h"
// Will report exception and call std::abort() if put in catch(...) // Will report exception and call std::abort() if put in catch(...)
[[noreturn]] void catch_all_exceptions(); [[noreturn]] void catch_all_exceptions();
// Simple list of void() functors
class task_stack
{
struct task_base
{
std::unique_ptr<task_base> next;
virtual ~task_base() = default;
virtual void exec()
{
if (next)
{
next->exec();
}
}
};
std::unique_ptr<task_base> m_stack;
never_inline void push(std::unique_ptr<task_base> task)
{
m_stack.swap(task->next);
m_stack.swap(task);
}
public:
template<typename F>
void push(F&& func)
{
struct task_t : task_base
{
std::remove_reference_t<F> func;
task_t(F&& func)
: func(std::forward<F>(func))
{
}
void exec() override
{
func();
task_base::exec();
}
};
return push(std::unique_ptr<task_base>{ new task_t(std::forward<F>(func)) });
}
void reset()
{
m_stack.reset();
}
void exec() const
{
if (m_stack)
{
m_stack->exec();
}
}
};
// Thread control class // Thread control class
class thread_ctrl final class thread_ctrl final
{ {
static thread_local thread_ctrl* g_tls_this_thread; static thread_local thread_ctrl* g_tls_this_thread;
// Name getter // Fixed name
std::function<std::string()> m_name; std::string m_name;
// Thread handle (be careful) // Thread handle (be careful)
std::thread m_thread; std::thread m_thread;
// Thread result // Thread result (exception)
std::future<void> m_future; std::exception_ptr m_exception;
// Functions scheduled at thread exit // Functions scheduled at thread exit
std::deque<std::function<void()>> m_atexit; task_stack m_atexit;
// Called at the thread start // Called at the thread start
static void initialize(); static void initialize();
@ -27,24 +99,41 @@ class thread_ctrl final
static void finalize() noexcept; static void finalize() noexcept;
public: public:
template<typename T> template<typename N>
thread_ctrl(T&& name) thread_ctrl(N&& name)
: m_name(std::forward<T>(name)) : m_name(std::forward<N>(name))
{ {
} }
// Disable copy/move constructors and operators // Disable copy/move constructors and operators
thread_ctrl(const thread_ctrl&) = delete; thread_ctrl(const thread_ctrl&) = delete;
~thread_ctrl(); ~thread_ctrl()
{
if (m_thread.joinable())
{
m_thread.detach();
}
}
// Get thread name // Get thread name
std::string get_name() const; const std::string& get_name() const
{
return m_name;
}
// Get future result (may throw) // Get thread result (may throw)
void join() void join()
{ {
return m_future.get(); if (m_thread.joinable())
{
m_thread.join();
}
if (auto&& e = std::move(m_exception))
{
std::rethrow_exception(e);
}
} }
// Get current thread (may be nullptr) // Get current thread (may be nullptr)
@ -54,12 +143,10 @@ public:
} }
// Register function at thread exit (for the current thread) // Register function at thread exit (for the current thread)
template<typename T> template<typename F>
static inline void at_exit(T&& func) static inline void at_exit(F&& func)
{ {
CHECK_ASSERTION(g_tls_this_thread); return g_tls_this_thread->m_atexit.push(std::forward<F>(func));
g_tls_this_thread->m_atexit.emplace_front(std::forward<T>(func));
} }
// Named thread factory // Named thread factory
@ -68,12 +155,9 @@ public:
{ {
auto ctrl = std::make_shared<thread_ctrl>(std::forward<N>(name)); auto ctrl = std::make_shared<thread_ctrl>(std::forward<N>(name));
std::promise<void> promise; ctrl->m_thread = std::thread([ctrl, task = std::forward<F>(func)]()
ctrl->m_future = promise.get_future();
ctrl->m_thread = std::thread([ctrl, task = std::forward<F>(func)](std::promise<void> promise)
{ {
// Initialize TLS variable
g_tls_this_thread = ctrl.get(); g_tls_this_thread = ctrl.get();
try try
@ -81,21 +165,21 @@ public:
initialize(); initialize();
task(); task();
finalize(); finalize();
promise.set_value();
} }
catch (...) catch (...)
{ {
finalize(); finalize();
promise.set_exception(std::current_exception());
}
}, std::move(promise)); // Set exception
ctrl->m_exception = std::current_exception();
}
});
return ctrl; return ctrl;
} }
}; };
class named_thread_t : public std::enable_shared_from_this<named_thread_t> class named_thread : public std::enable_shared_from_this<named_thread>
{ {
// Pointer to managed resource (shared with actual thread) // Pointer to managed resource (shared with actual thread)
std::shared_ptr<thread_ctrl> m_thread; std::shared_ptr<thread_ctrl> m_thread;
@ -107,6 +191,27 @@ public:
// Thread mutex for external use (can be used with `cv`) // Thread mutex for external use (can be used with `cv`)
std::mutex mutex; std::mutex mutex;
// Lock mutex, notify condition variable
void safe_notify()
{
// Lock for reliable notification, condition is assumed to be changed externally
std::unique_lock<std::mutex> lock(mutex);
cv.notify_one();
}
// ID initialization
virtual void on_init()
{
start();
}
// ID finalization
virtual void on_stop()
{
join();
}
protected: protected:
// Thread task (called in the thread) // Thread task (called in the thread)
virtual void on_task() = 0; virtual void on_task() = 0;
@ -114,19 +219,13 @@ protected:
// Thread finalization (called after on_task) // Thread finalization (called after on_task)
virtual void on_exit() {} virtual void on_exit() {}
// ID initialization (called through id_aux_initialize)
virtual void on_id_aux_initialize() { start(); }
// ID finalization (called through id_aux_finalize)
virtual void on_id_aux_finalize() { join(); }
public: public:
named_thread_t() = default; named_thread() = default;
virtual ~named_thread_t() = default; virtual ~named_thread() = default;
// Deleted copy/move constructors + copy/move operators // Deleted copy/move constructors + copy/move operators
named_thread_t(const named_thread_t&) = delete; named_thread(const named_thread&) = delete;
// Get thread name // Get thread name
virtual std::string get_name() const; virtual std::string get_name() const;
@ -134,377 +233,40 @@ public:
// Start thread (cannot be called from the constructor: should throw bad_weak_ptr in such case) // Start thread (cannot be called from the constructor: should throw bad_weak_ptr in such case)
void start(); void start();
// Join thread (get future result) // Join thread (get thread result)
void join(); void join();
// Check whether the thread is not in "empty state" // Get thread_ctrl
bool is_started() const { return m_thread.operator bool(); } const thread_ctrl* get_thread_ctrl() const
{
return m_thread.get();
}
// Compare with the current thread // Compare with the current thread
bool is_current() const { CHECK_ASSERTION(m_thread); return thread_ctrl::get_current() == m_thread.get(); } bool is_current() const
{
// Get thread_ctrl return m_thread && thread_ctrl::get_current() == m_thread.get();
const thread_ctrl* get_thread_ctrl() const { return m_thread.get(); } }
friend void id_aux_initialize(named_thread_t* ptr) { ptr->on_id_aux_initialize(); }
friend void id_aux_finalize(named_thread_t* ptr) { ptr->on_id_aux_finalize(); }
}; };
// Wrapper for named thread, joins automatically in the destructor, can only be used in function scope // Wrapper for named thread, joins automatically in the destructor, can only be used in function scope
class scope_thread_t final class scope_thread final
{ {
std::shared_ptr<thread_ctrl> m_thread; std::shared_ptr<thread_ctrl> m_thread;
public: public:
template<typename N, typename F> template<typename N, typename F>
scope_thread_t(N&& name, F&& func) scope_thread(N&& name, F&& func)
: m_thread(thread_ctrl::spawn(std::forward<N>(name), std::forward<F>(func))) : m_thread(thread_ctrl::spawn(std::forward<N>(name), std::forward<F>(func)))
{ {
} }
// Deleted copy/move constructors + copy/move operators // Deleted copy/move constructors + copy/move operators
scope_thread_t(const scope_thread_t&) = delete; scope_thread(const scope_thread&) = delete;
// Destructor with exceptions allowed // Destructor with exceptions allowed
~scope_thread_t() noexcept(false) ~scope_thread() noexcept(false)
{ {
m_thread->join(); m_thread->join();
} }
}; };
extern const std::function<bool()> SQUEUE_ALWAYS_EXIT;
extern const std::function<bool()> SQUEUE_NEVER_EXIT;
bool squeue_test_exit();
template<typename T, u32 sq_size = 256>
class squeue_t
{
struct squeue_sync_var_t
{
struct
{
u32 position : 31;
u32 pop_lock : 1;
};
struct
{
u32 count : 31;
u32 push_lock : 1;
};
};
atomic_t<squeue_sync_var_t> m_sync;
mutable std::mutex m_rcv_mutex;
mutable std::mutex m_wcv_mutex;
mutable std::condition_variable m_rcv;
mutable std::condition_variable m_wcv;
T m_data[sq_size];
enum squeue_sync_var_result : u32
{
SQSVR_OK = 0,
SQSVR_LOCKED = 1,
SQSVR_FAILED = 2,
};
public:
squeue_t()
: m_sync(squeue_sync_var_t{})
{
}
u32 get_max_size() const
{
return sq_size;
}
bool is_full() const
{
return m_sync.load().count == sq_size;
}
bool push(const T& data, const std::function<bool()>& test_exit)
{
u32 pos = 0;
while (u32 res = m_sync.atomic_op([&pos](squeue_sync_var_t& sync) -> u32
{
assert(sync.count <= sq_size);
assert(sync.position < sq_size);
if (sync.push_lock)
{
return SQSVR_LOCKED;
}
if (sync.count == sq_size)
{
return SQSVR_FAILED;
}
sync.push_lock = 1;
pos = sync.position + sync.count;
return SQSVR_OK;
}))
{
if (res == SQSVR_FAILED && (test_exit() || squeue_test_exit()))
{
return false;
}
std::unique_lock<std::mutex> wcv_lock(m_wcv_mutex);
m_wcv.wait_for(wcv_lock, std::chrono::milliseconds(1));
}
m_data[pos >= sq_size ? pos - sq_size : pos] = data;
m_sync.atomic_op([](squeue_sync_var_t& sync)
{
assert(sync.count <= sq_size);
assert(sync.position < sq_size);
assert(sync.push_lock);
sync.push_lock = 0;
sync.count++;
});
m_rcv.notify_one();
m_wcv.notify_one();
return true;
}
bool push(const T& data, const volatile bool* do_exit)
{
return push(data, [do_exit](){ return do_exit && *do_exit; });
}
force_inline bool push(const T& data)
{
return push(data, SQUEUE_NEVER_EXIT);
}
force_inline bool try_push(const T& data)
{
return push(data, SQUEUE_ALWAYS_EXIT);
}
bool pop(T& data, const std::function<bool()>& test_exit)
{
u32 pos = 0;
while (u32 res = m_sync.atomic_op([&pos](squeue_sync_var_t& sync) -> u32
{
assert(sync.count <= sq_size);
assert(sync.position < sq_size);
if (!sync.count)
{
return SQSVR_FAILED;
}
if (sync.pop_lock)
{
return SQSVR_LOCKED;
}
sync.pop_lock = 1;
pos = sync.position;
return SQSVR_OK;
}))
{
if (res == SQSVR_FAILED && (test_exit() || squeue_test_exit()))
{
return false;
}
std::unique_lock<std::mutex> rcv_lock(m_rcv_mutex);
m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1));
}
data = m_data[pos];
m_sync.atomic_op([](squeue_sync_var_t& sync)
{
assert(sync.count <= sq_size);
assert(sync.position < sq_size);
assert(sync.pop_lock);
sync.pop_lock = 0;
sync.position++;
sync.count--;
if (sync.position == sq_size)
{
sync.position = 0;
}
});
m_rcv.notify_one();
m_wcv.notify_one();
return true;
}
bool pop(T& data, const volatile bool* do_exit)
{
return pop(data, [do_exit](){ return do_exit && *do_exit; });
}
force_inline bool pop(T& data)
{
return pop(data, SQUEUE_NEVER_EXIT);
}
force_inline bool try_pop(T& data)
{
return pop(data, SQUEUE_ALWAYS_EXIT);
}
bool peek(T& data, u32 start_pos, const std::function<bool()>& test_exit)
{
assert(start_pos < sq_size);
u32 pos = 0;
while (u32 res = m_sync.atomic_op([&pos, start_pos](squeue_sync_var_t& sync) -> u32
{
assert(sync.count <= sq_size);
assert(sync.position < sq_size);
if (sync.count <= start_pos)
{
return SQSVR_FAILED;
}
if (sync.pop_lock)
{
return SQSVR_LOCKED;
}
sync.pop_lock = 1;
pos = sync.position + start_pos;
return SQSVR_OK;
}))
{
if (res == SQSVR_FAILED && (test_exit() || squeue_test_exit()))
{
return false;
}
std::unique_lock<std::mutex> rcv_lock(m_rcv_mutex);
m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1));
}
data = m_data[pos >= sq_size ? pos - sq_size : pos];
m_sync.atomic_op([](squeue_sync_var_t& sync)
{
assert(sync.count <= sq_size);
assert(sync.position < sq_size);
assert(sync.pop_lock);
sync.pop_lock = 0;
});
m_rcv.notify_one();
return true;
}
bool peek(T& data, u32 start_pos, const volatile bool* do_exit)
{
return peek(data, start_pos, [do_exit](){ return do_exit && *do_exit; });
}
force_inline bool peek(T& data, u32 start_pos = 0)
{
return peek(data, start_pos, SQUEUE_NEVER_EXIT);
}
force_inline bool try_peek(T& data, u32 start_pos = 0)
{
return peek(data, start_pos, SQUEUE_ALWAYS_EXIT);
}
class squeue_data_t
{
T* const m_data;
const u32 m_pos;
const u32 m_count;
squeue_data_t(T* data, u32 pos, u32 count)
: m_data(data)
, m_pos(pos)
, m_count(count)
{
}
public:
T& operator [] (u32 index)
{
assert(index < m_count);
index += m_pos;
index = index < sq_size ? index : index - sq_size;
return m_data[index];
}
};
void process(void(*proc)(squeue_data_t data))
{
u32 pos, count;
while (m_sync.atomic_op([&pos, &count](squeue_sync_var_t& sync) -> u32
{
assert(sync.count <= sq_size);
assert(sync.position < sq_size);
if (sync.pop_lock || sync.push_lock)
{
return SQSVR_LOCKED;
}
pos = sync.position;
count = sync.count;
sync.pop_lock = 1;
sync.push_lock = 1;
return SQSVR_OK;
}))
{
std::unique_lock<std::mutex> rcv_lock(m_rcv_mutex);
m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1));
}
proc(squeue_data_t(m_data, pos, count));
m_sync.atomic_op([](squeue_sync_var_t& sync)
{
assert(sync.count <= sq_size);
assert(sync.position < sq_size);
assert(sync.pop_lock && sync.push_lock);
sync.pop_lock = 0;
sync.push_lock = 0;
});
m_wcv.notify_one();
m_rcv.notify_one();
}
void clear()
{
while (m_sync.atomic_op([](squeue_sync_var_t& sync) -> u32
{
assert(sync.count <= sq_size);
assert(sync.position < sq_size);
if (sync.pop_lock || sync.push_lock)
{
return SQSVR_LOCKED;
}
sync.pop_lock = 1;
sync.push_lock = 1;
return SQSVR_OK;
}))
{
std::unique_lock<std::mutex> rcv_lock(m_rcv_mutex);
m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1));
}
m_sync.exchange({});
m_wcv.notify_one();
m_rcv.notify_one();
}
};

View file

@ -17,10 +17,10 @@ namespace memory_helper
{ {
#ifdef _WIN32 #ifdef _WIN32
void* ret = VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_NOACCESS); void* ret = VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_NOACCESS);
CHECK_ASSERTION(ret != NULL); Ensures(ret != NULL);
#else #else
void* ret = mmap(nullptr, size, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0); void* ret = mmap(nullptr, size, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0);
CHECK_ASSERTION(ret != 0); Ensures(ret != 0);
#endif #endif
return ret; return ret;
} }
@ -28,18 +28,18 @@ namespace memory_helper
void commit_page_memory(void* pointer, size_t page_size) void commit_page_memory(void* pointer, size_t page_size)
{ {
#ifdef _WIN32 #ifdef _WIN32
CHECK_ASSERTION(VirtualAlloc((u8*)pointer, page_size, MEM_COMMIT, PAGE_READWRITE) != NULL); ASSERT(VirtualAlloc((u8*)pointer, page_size, MEM_COMMIT, PAGE_READWRITE) != NULL);
#else #else
CHECK_ASSERTION(mprotect((u8*)pointer, page_size, PROT_READ | PROT_WRITE) != -1); ASSERT(mprotect((u8*)pointer, page_size, PROT_READ | PROT_WRITE) != -1);
#endif #endif
} }
void free_reserved_memory(void* pointer, size_t size) void free_reserved_memory(void* pointer, size_t size)
{ {
#ifdef _WIN32 #ifdef _WIN32
CHECK_ASSERTION(VirtualFree(pointer, 0, MEM_RELEASE) != 0); ASSERT(VirtualFree(pointer, 0, MEM_RELEASE) != 0);
#else #else
CHECK_ASSERTION(munmap(pointer, size) == 0); ASSERT(munmap(pointer, size) == 0);
#endif #endif
} }
} }

View file

@ -1,172 +0,0 @@
#include "stdafx.h"
#include "config_context.h"
#include "StrFmt.h"
#include <iostream>
#include <sstream>
void config_context_t::group::init()
{
if(!m_cfg->m_groups[full_name()])
m_cfg->m_groups[full_name()] = this;
}
config_context_t::group::group(config_context_t* cfg, const std::string& name)
: m_cfg(cfg)
, m_name(name)
, m_parent(nullptr)
{
init();
}
config_context_t::group::group(group* parent, const std::string& name)
: m_cfg(parent->m_cfg)
, m_name(name)
, m_parent(parent)
{
init();
}
void config_context_t::group::set_parent(config_context_t* cfg)
{
m_cfg = cfg;
init();
}
std::string config_context_t::group::name() const
{
return m_name;
}
std::string config_context_t::group::full_name() const
{
if (m_parent)
return m_parent->full_name() + "/" + m_name;
return m_name;
}
void config_context_t::assign(const config_context_t& rhs)
{
for (auto &rhs_g : rhs.m_groups)
{
auto g = m_groups.at(rhs_g.first);
for (auto rhs_e : rhs_g.second->entries)
{
if (g->entries[rhs_e.first])
g->entries[rhs_e.first]->value_from(rhs_e.second);
else
g->add_entry(rhs_e.first, rhs_e.second->string_value());
}
}
}
void config_context_t::deserialize(std::istream& stream)
{
set_defaults();
uint line_index = 0;
std::string line;
group *current_group = nullptr;
while (std::getline(stream, line))
{
++line_index;
line = fmt::trim(line);
if (line.empty())
continue;
if (line.front() == '[' && line.back() == ']')
{
std::string group_name = line.substr(1, line.length() - 2);
auto found = m_groups.find(group_name);
if (found == m_groups.end())
{
std::cerr << line_index << ": group '" << group_name << "' not exists. ignored" << std::endl;
current_group = nullptr;
continue;
}
current_group = found->second;
continue;
}
if (current_group == nullptr)
{
std::cerr << line_index << ": line '" << line << "' ignored, no group." << std::endl;
continue;
}
auto name_value = fmt::split(line, { "=" });
switch (name_value.size())
{
case 1:
{
if (current_group->entries[fmt::trim(name_value[0])])
current_group->entries[fmt::trim(name_value[0])]->string_value({});
else
current_group->add_entry(fmt::trim(name_value[0]), std::string{});
}
break;
default:
std::cerr << line_index << ": line '" << line << "' has more than one symbol '='. used only first" << std::endl;
case 2:
{
if (current_group->entries[fmt::trim(name_value[0])])
current_group->entries[fmt::trim(name_value[0])]->string_value(fmt::trim(name_value[1]));
else
current_group->add_entry(fmt::trim(name_value[0]), fmt::trim(name_value[1]));
}
break;
}
}
}
void config_context_t::serialize(std::ostream& stream) const
{
for (auto &g : m_groups)
{
stream << "[" + g.first + "]" << std::endl;
for (auto &e : g.second->entries)
{
stream << e.first << "=" << e.second->string_value() << std::endl;
}
stream << std::endl;
}
}
void config_context_t::set_defaults()
{
for (auto &g : m_groups)
{
for (auto &e : g.second->entries)
{
e.second->to_default();
}
}
}
std::string config_context_t::to_string() const
{
std::ostringstream result;
serialize(result);
return result.str();
}
void config_context_t::from_string(const std::string& str)
{
std::istringstream source(str);
deserialize(source);
}

View file

@ -1,164 +0,0 @@
#pragma once
#include <unordered_map>
#include <string>
#include "convert.h"
class config_context_t
{
public:
class entry_base;
protected:
class group
{
group* m_parent;
config_context_t* m_cfg;
std::string m_name;
std::vector<std::unique_ptr<entry_base>> m_entries;
void init();
public:
std::unordered_map<std::string, entry_base *> entries;
group(config_context_t* cfg, const std::string& name);
group(group* parent, const std::string& name);
void set_parent(config_context_t* cfg);
std::string name() const;
std::string full_name() const;
template<typename T>
void add_entry(const std::string& name, const T& def_value)
{
m_entries.emplace_back(std::make_unique<entry<T>>(this, name, def_value));
}
template<typename T>
T get_entry_value(const std::string& name, const T& def_value)
{
if (!entries[name])
add_entry(name, def_value);
return convert::to<T>(entries[name]->string_value());
}
template<typename T>
void set_entry_value(const std::string& name, const T& value)
{
if (entries[name])
entries[name]->string_value(convert::to<std::string>(value));
else
add_entry(name, value);
}
friend config_context_t;
};
public:
class entry_base
{
public:
virtual ~entry_base() = default;
virtual std::string name() = 0;
virtual void to_default() = 0;
virtual std::string string_value() = 0;
virtual void string_value(const std::string& value) = 0;
virtual void value_from(const entry_base* rhs) = 0;
};
template<typename T>
class entry : public entry_base
{
T m_default_value;
T m_value;
group* m_parent;
std::string m_name;
public:
entry(group* parent, const std::string& name, const T& default_value)
: m_parent(parent)
, m_name(name)
, m_default_value(default_value)
, m_value(default_value)
{
if(!parent->entries[name])
parent->entries[name] = this;
}
T default_value() const
{
return m_default_value;
}
T value() const
{
return m_value;
}
void value(const T& new_value)
{
m_value = new_value;
}
std::string name() override
{
return m_name;
}
void to_default() override
{
value(default_value());
}
std::string string_value() override
{
return convert::to<std::string>(value());
}
void string_value(const std::string &new_value) override
{
value(convert::to<T>(new_value));
}
void value_from(const entry_base* rhs) override
{
value(static_cast<const entry*>(rhs)->value());
}
entry& operator = (const T& new_value)
{
value(new_value);
return *this;
}
template<typename T2>
entry& operator = (const T2& new_value)
{
value(static_cast<T>(new_value));
return *this;
}
explicit operator const T&() const
{
return m_value;
}
};
private:
std::unordered_map<std::string, group*> m_groups;
public:
config_context_t() = default;
void assign(const config_context_t& rhs);
void serialize(std::ostream& stream) const;
void deserialize(std::istream& stream);
void set_defaults();
std::string to_string() const;
void from_string(const std::string&);
};

View file

@ -1,279 +0,0 @@
#pragma once
#include <string>
#include "types.h"
namespace convert
{
template<typename ReturnType, typename FromType>
struct to_impl_t;
template<typename Type>
struct to_impl_t<Type, Type>
{
static Type func(const Type& value)
{
return value;
}
};
template<>
struct to_impl_t<std::string, bool>
{
static std::string func(bool value)
{
return value ? "true" : "false";
}
};
template<>
struct to_impl_t<bool, std::string>
{
static bool func(const std::string& value)
{
return value == "true" ? true : value == "false" ? false : throw std::invalid_argument(__FUNCTION__);
}
};
template<>
struct to_impl_t<std::string, signed char>
{
static std::string func(signed char value)
{
return std::to_string(value);
}
};
template<>
struct to_impl_t<std::string, unsigned char>
{
static std::string func(unsigned char value)
{
return std::to_string(value);
}
};
template<>
struct to_impl_t<std::string, short>
{
static std::string func(short value)
{
return std::to_string(value);
}
};
template<>
struct to_impl_t<std::string, unsigned short>
{
static std::string func(unsigned short value)
{
return std::to_string(value);
}
};
template<>
struct to_impl_t<std::string, int>
{
static std::string func(int value)
{
return std::to_string(value);
}
};
template<>
struct to_impl_t<std::string, unsigned int>
{
static std::string func(unsigned int value)
{
return std::to_string(value);
}
};
template<>
struct to_impl_t<std::string, long>
{
static std::string func(long value)
{
return std::to_string(value);
}
};
template<>
struct to_impl_t<std::string, unsigned long>
{
static std::string func(unsigned long value)
{
return std::to_string(value);
}
};
template<>
struct to_impl_t<std::string, long long>
{
static std::string func(long long value)
{
return std::to_string(value);
}
};
template<>
struct to_impl_t<std::string, unsigned long long>
{
static std::string func(unsigned long long value)
{
return std::to_string(value);
}
};
template<>
struct to_impl_t<std::string, float>
{
static std::string func(float value)
{
return std::to_string(value);
}
};
template<>
struct to_impl_t<std::string, double>
{
static std::string func(double value)
{
return std::to_string(value);
}
};
template<>
struct to_impl_t<std::string, long double>
{
static std::string func(long double value)
{
return std::to_string(value);
}
};
template<>
struct to_impl_t<std::string, size2i>
{
static std::string func(size2i value)
{
return std::to_string(value.width) + "x" + std::to_string(value.height);
}
};
template<>
struct to_impl_t<std::string, position2i>
{
static std::string func(position2i value)
{
return std::to_string(value.x) + ":" + std::to_string(value.y);
}
};
template<>
struct to_impl_t<int, std::string>
{
static int func(const std::string& value)
{
return std::stoi(value);
}
};
template<>
struct to_impl_t<unsigned int, std::string>
{
static unsigned int func(const std::string& value)
{
return (unsigned long)std::stoul(value);
}
};
template<>
struct to_impl_t<long, std::string>
{
static long func(const std::string& value)
{
return std::stol(value);
}
};
template<>
struct to_impl_t<unsigned long, std::string>
{
static unsigned long func(const std::string& value)
{
return std::stoul(value);
}
};
template<>
struct to_impl_t<long long, std::string>
{
static long long func(const std::string& value)
{
return std::stoll(value);
}
};
template<>
struct to_impl_t<unsigned long long, std::string>
{
static unsigned long long func(const std::string& value)
{
return std::stoull(value);
}
};
template<>
struct to_impl_t<float, std::string>
{
static float func(const std::string& value)
{
return std::stof(value);
}
};
template<>
struct to_impl_t<double, std::string>
{
static double func(const std::string& value)
{
return std::stod(value);
}
};
template<>
struct to_impl_t<long double, std::string>
{
static long double func(const std::string& value)
{
return std::stold(value);
}
};
template<>
struct to_impl_t<size2i, std::string>
{
static size2i func(const std::string& value)
{
const auto& data = fmt::split(value, { "x" });
return { std::stoi(data[0]), std::stoi(data[1]) };
}
};
template<>
struct to_impl_t<position2i, std::string>
{
static position2i func(const std::string& value)
{
const auto& data = fmt::split(value, { ":" });
return { std::stoi(data[0]), std::stoi(data[1]) };
}
};
template<typename ReturnType, typename FromType>
ReturnType to(FromType value)
{
return to_impl_t<std::remove_all_extents_t<ReturnType>, std::remove_all_extents_t<FromType>>::func(value);
}
}

View file

@ -1,41 +0,0 @@
#include "stdafx.h"
#include "restore_new.h"
#include "Utilities/Log.h"
#pragma warning(push)
#pragma message("TODO: remove wx dependency: <wx/image.h>")
#pragma warning(disable : 4996)
#include <wx/image.h>
#pragma warning(pop)
#include "define_new_memleakdetect.h"
#ifndef _WIN32
#include <dirent.h>
#endif
#include "rPlatform.h"
rImage::rImage()
{
handle = static_cast<void*>(new wxImage());
}
rImage::~rImage()
{
delete static_cast<wxImage*>(handle);
}
void rImage::Create(int width, int height, void *data, void *alpha)
{
static_cast<wxImage*>(handle)->Create(width, height, static_cast<unsigned char*>(data), static_cast<unsigned char*>(alpha));
}
void rImage::SaveFile(const std::string& name, rImageType type)
{
if (type == rBITMAP_TYPE_PNG)
{
static_cast<wxImage*>(handle)->SaveFile(fmt::FromUTF8(name),wxBITMAP_TYPE_PNG);
}
else
{
throw EXCEPTION("unsupported type");
}
}

View file

@ -1,40 +0,0 @@
#pragma once
/**********************************************************************
*********** RSX Debugger
************************************************************************/
struct RSXDebuggerProgram
{
u32 id;
u32 vp_id;
u32 fp_id;
std::string vp_shader;
std::string fp_shader;
bool modified;
RSXDebuggerProgram()
: modified(false)
{
}
};
extern std::vector<RSXDebuggerProgram> m_debug_programs;
/**********************************************************************
*********** Image stuff
************************************************************************/
enum rImageType
{
rBITMAP_TYPE_PNG
};
struct rImage
{
rImage();
rImage(const rImage &) = delete;
~rImage();
void Create(int width , int height, void *data, void *alpha);
void SaveFile(const std::string& name, rImageType type);
void *handle;
};

View file

@ -1,235 +0,0 @@
#include "stdafx.h"
#include "rTime.h"
#pragma warning(push)
#pragma message("TODO: remove wx dependency: <wx/datetime.h>")
#pragma warning(disable : 4996)
#include <wx/datetime.h>
#pragma warning(pop)
std::string rDefaultDateTimeFormat = "%c";
rTimeSpan::rTimeSpan()
{
handle = static_cast<void *>(new wxTimeSpan());
}
rTimeSpan::~rTimeSpan()
{
delete static_cast<wxTimeSpan*>(handle);
}
rTimeSpan::rTimeSpan(const rTimeSpan& other)
{
handle = static_cast<void *>(new wxTimeSpan(*static_cast<wxTimeSpan*>(other.handle)));
}
rTimeSpan::rTimeSpan(int a, int b , int c, int d)
{
handle = static_cast<void *>(new wxTimeSpan(a,b,c,d));
}
rDateSpan::rDateSpan()
{
handle = static_cast<void *>(new wxDateSpan());
}
rDateSpan::~rDateSpan()
{
delete static_cast<wxDateSpan*>(handle);
}
rDateSpan::rDateSpan(const rDateSpan& other)
{
handle = static_cast<void *>(new wxDateSpan(*static_cast<wxDateSpan*>(other.handle)));
}
rDateSpan::rDateSpan(int a, int b, int c, int d)
{
handle = static_cast<void *>(new wxDateSpan(a,b,c,d));
}
rDateTime::rDateTime()
{
handle = static_cast<void *>(new wxDateTime());
}
rDateTime::~rDateTime()
{
delete static_cast<wxDateTime*>(handle);
}
rDateTime::rDateTime(const rDateTime& other)
{
handle = static_cast<void *>(new wxDateTime(*static_cast<wxDateTime*>(other.handle)));
}
rDateTime::rDateTime(const time_t& time)
{
handle = static_cast<void *>(new wxDateTime(time));
}
rDateTime::rDateTime(u16 day, rDateTime::Month month, u16 year, u16 hour, u16 minute, u16 second, u32 millisecond)
{
handle = static_cast<void *>(new wxDateTime(day,(wxDateTime::Month)month,year,hour,minute,second,millisecond));
}
rDateTime rDateTime::UNow()
{
rDateTime time;
delete static_cast<wxDateTime*>(time.handle);
time.handle = static_cast<void *>(new wxDateTime(wxDateTime::UNow()));
return time;
}
rDateTime rDateTime::FromUTC(bool val)
{
rDateTime time(*this);
void *temp = time.handle;
time.handle = static_cast<void *>(new wxDateTime(static_cast<wxDateTime*>(temp)->FromTimezone(wxDateTime::GMT0, val)));
delete static_cast<wxDateTime*>(temp);
return time;
}
rDateTime rDateTime::ToUTC(bool val)
{
rDateTime time(*this);
void *temp = time.handle;
time.handle = static_cast<void *>(new wxDateTime(static_cast<wxDateTime*>(temp)->ToTimezone(wxDateTime::GMT0, val)));
delete static_cast<wxDateTime*>(temp);
return time;
}
time_t rDateTime::GetTicks()
{
return static_cast<wxDateTime*>(handle)->GetTicks();
}
void rDateTime::Add(const rTimeSpan& span)
{
static_cast<wxDateTime*>(handle)->Add(*static_cast<wxTimeSpan*>(span.handle));
}
void rDateTime::Add(const rDateSpan& span)
{
static_cast<wxDateTime*>(handle)->Add(*static_cast<wxDateSpan*>(span.handle));
}
wxDateTime::TimeZone convertTZ(rDateTime::rTimeZone tz)
{
switch (tz)
{
case rDateTime::Local:
return wxDateTime::Local;
case rDateTime::GMT0:
return wxDateTime::GMT0;
case rDateTime::UTC:
return wxDateTime::UTC;
default:
throw EXCEPTION("WRONG DATETIME");
}
}
std::string rDateTime::Format(const std::string &format, const rTimeZone &tz) const
{
return fmt::ToUTF8(static_cast<wxDateTime*>(handle)->Format(fmt::FromUTF8(format),convertTZ(tz)));
}
void rDateTime::ParseDateTime(const char* format)
{
static_cast<wxDateTime*>(handle)->ParseDateTime(format);
}
u32 rDateTime::GetAsDOS()
{
return static_cast<wxDateTime*>(handle)->GetAsDOS();
}
rDateTime &rDateTime::SetFromDOS(u32 fromdos)
{
static_cast<wxDateTime*>(handle)->SetFromDOS(fromdos);
return *this;
}
bool rDateTime::IsLeapYear(int year, rDateTime::Calender cal)
{
if (cal == Gregorian)
{
return wxDateTime::IsLeapYear(year, wxDateTime::Gregorian);
}
else
{
return wxDateTime::IsLeapYear(year, wxDateTime::Julian);
}
}
int rDateTime::GetNumberOfDays(rDateTime::Month month, int year, rDateTime::Calender cal)
{
if (cal == Gregorian)
{
return wxDateTime::GetNumberOfDays(static_cast<wxDateTime::Month>(month), year, wxDateTime::Gregorian);
}
else
{
return wxDateTime::GetNumberOfDays(static_cast<wxDateTime::Month>(month), year, wxDateTime::Julian);
}
}
void rDateTime::SetToWeekDay(rDateTime::WeekDay day, int n, rDateTime::Month month, int year)
{
static_cast<wxDateTime*>(handle)->SetToWeekDay(
static_cast<wxDateTime::WeekDay>(day)
, n
, static_cast<wxDateTime::Month>(month)
, year
);
}
int rDateTime::GetWeekDay()
{
return static_cast<wxDateTime*>(handle)->GetWeekDay();
}
u16 rDateTime::GetYear(rDateTime::TZ timezone)
{
return static_cast<wxDateTime*>(handle)->GetYear(convertTZ(timezone));
}
u16 rDateTime::GetMonth(rDateTime::TZ timezone)
{
return static_cast<wxDateTime*>(handle)->GetMonth(convertTZ(timezone));
}
u16 rDateTime::GetDay(rDateTime::TZ timezone)
{
return static_cast<wxDateTime*>(handle)->GetDay(convertTZ(timezone));
}
u16 rDateTime::GetHour(rDateTime::TZ timezone)
{
return static_cast<wxDateTime*>(handle)->GetHour(convertTZ(timezone));
}
u16 rDateTime::GetMinute(rDateTime::TZ timezone)
{
return static_cast<wxDateTime*>(handle)->GetMinute(convertTZ(timezone));
}
u16 rDateTime::GetSecond(rDateTime::TZ timezone)
{
return static_cast<wxDateTime*>(handle)->GetSecond(convertTZ(timezone));
}
u32 rDateTime::GetMillisecond(rDateTime::TZ timezone)
{
return static_cast<wxDateTime*>(handle)->GetMillisecond(convertTZ(timezone));
}

View file

@ -1,102 +0,0 @@
#pragma once
extern std::string rDefaultDateTimeFormat;
struct rTimeSpan
{
rTimeSpan();
~rTimeSpan();
rTimeSpan(const rTimeSpan& other);
rTimeSpan(int, int, int, int);
void *handle;
};
struct rDateSpan
{
rDateSpan();
~rDateSpan();
rDateSpan(const rDateSpan& other);
rDateSpan(int, int, int, int);
void *handle;
};
struct rDateTime
{
enum TZ
{
Local, GMT0,UTC
};
enum Calender
{
Gregorian, Julian
};
using rTimeZone = TZ;
enum WeekDay
{
Sun = 0,
Mon,
Tue,
Wed,
Thu,
Fri,
Sat,
Inv_WeekDay
};
enum Month {
Jan = 0,
Feb = 1,
Mar = 2,
Apr = 3,
May = 4,
Jun = 5,
Jul = 6,
Aug = 7,
Sep = 8,
Oct = 9,
Nov = 10,
Dec = 11,
Inv_Month = 12
};
rDateTime();
~rDateTime();
rDateTime(const rDateTime& other);
rDateTime(const time_t &time);
rDateTime(u16 day, rDateTime::Month month, u16 year, u16 hour, u16 minute, u16 second, u32 millisecond);
static rDateTime UNow();
rDateTime FromUTC(bool val);
rDateTime ToUTC(bool val);
time_t GetTicks();
void Add(const rTimeSpan& span);
void Add(const rDateSpan& span);
void Close();
std::string Format(const std::string &format = rDefaultDateTimeFormat, const rTimeZone &tz = Local) const;
void ParseDateTime(const char* format);
u32 GetAsDOS();
rDateTime &SetFromDOS(u32 fromdos);
static bool IsLeapYear(int year, rDateTime::Calender cal);
static int GetNumberOfDays(rDateTime::Month month, int year, rDateTime::Calender cal);
void SetToWeekDay(rDateTime::WeekDay day, int n, rDateTime::Month month, int year);
int GetWeekDay();
u16 GetYear( rDateTime::TZ timezone);
u16 GetMonth(rDateTime::TZ timezone);
u16 GetDay(rDateTime::TZ timezone);
u16 GetHour(rDateTime::TZ timezone);
u16 GetMinute(rDateTime::TZ timezone);
u16 GetSecond(rDateTime::TZ timezone);
u32 GetMillisecond(rDateTime::TZ timezone);
void *handle;
};

View file

@ -1,16 +1,21 @@
#pragma once #pragma once
#include <new>
#include <typeinfo> #include <typeinfo>
#include <type_traits>
#include <exception>
#include <utility>
#include <cstdint> #include <cstdint>
#include <cmath> #include <cmath>
#include <algorithm>
#include "Platform.h"
using schar = signed char;
using uchar = unsigned char; using uchar = unsigned char;
using ushort = unsigned short; using ushort = unsigned short;
using uint = unsigned int; using uint = unsigned int;
using ulong = unsigned long; using ulong = unsigned long;
using ullong = unsigned long long; using ullong = unsigned long long;
using llong = long long; using llong = long long;
using u8 = std::uint8_t; using u8 = std::uint8_t;
@ -23,6 +28,350 @@ using s16 = std::int16_t;
using s32 = std::int32_t; using s32 = std::int32_t;
using s64 = std::int64_t; using s64 = std::int64_t;
// Specialization with static constexpr pair<T1, T2> map[] member expected
template<typename T1, typename T2>
struct bijective;
template<typename T, std::size_t Size = sizeof(T)>
struct atomic_storage;
template<typename T1, typename T2, typename = void>
struct atomic_add;
template<typename T1, typename T2, typename = void>
struct atomic_sub;
template<typename T1, typename T2, typename = void>
struct atomic_and;
template<typename T1, typename T2, typename = void>
struct atomic_or;
template<typename T1, typename T2, typename = void>
struct atomic_xor;
template<typename T, typename = void>
struct atomic_pre_inc;
template<typename T, typename = void>
struct atomic_post_inc;
template<typename T, typename = void>
struct atomic_pre_dec;
template<typename T, typename = void>
struct atomic_post_dec;
template<typename T1, typename T2, typename = void>
struct atomic_test_and_set;
template<typename T1, typename T2, typename = void>
struct atomic_test_and_reset;
template<typename T1, typename T2, typename = void>
struct atomic_test_and_complement;
template<typename T>
class atomic_t;
namespace fmt
{
template<typename T, typename = void>
struct unveil;
}
// TODO: replace with std::void_t when available
namespace void_details
{
template<class... >
struct make_void
{
using type = void;
};
}
template<class... T> using void_t = typename void_details::make_void<T...>::type;
// Extract T::simple_type if available, remove cv qualifiers
template<typename T, typename = void>
struct simple_type_helper
{
using type = typename std::remove_cv<T>::type;
};
template<typename T>
struct simple_type_helper<T, void_t<typename T::simple_type>>
{
using type = typename T::simple_type;
};
template<typename T> using simple_t = typename simple_type_helper<T>::type;
// Bool type equivalent
class b8
{
std::uint8_t m_value;
public:
b8() = default;
constexpr b8(bool value)
: m_value(value)
{
}
constexpr operator bool() const
{
return m_value != 0;
}
};
// Bool wrapper for restricting bool result conversions
struct explicit_bool_t
{
const bool value;
constexpr explicit_bool_t(bool value)
: value(value)
{
}
explicit constexpr operator bool() const
{
return value;
}
};
#ifndef _MSC_VER
using u128 = __uint128_t;
using s128 = __int128_t;
#else
#include "intrin.h"
// Unsigned 128-bit integer implementation (TODO)
struct alignas(16) u128
{
std::uint64_t lo, hi;
u128() = default;
constexpr u128(std::uint64_t l)
: lo(l)
, hi(0)
{
}
friend u128 operator +(const u128& l, const u128& r)
{
u128 value;
_addcarry_u64(_addcarry_u64(0, r.lo, l.lo, &value.lo), r.hi, l.hi, &value.hi);
return value;
}
friend u128 operator +(const u128& l, std::uint64_t r)
{
u128 value;
_addcarry_u64(_addcarry_u64(0, r, l.lo, &value.lo), l.hi, 0, &value.hi);
return value;
}
friend u128 operator +(std::uint64_t l, const u128& r)
{
u128 value;
_addcarry_u64(_addcarry_u64(0, r.lo, l, &value.lo), 0, r.hi, &value.hi);
return value;
}
friend u128 operator -(const u128& l, const u128& r)
{
u128 value;
_subborrow_u64(_subborrow_u64(0, r.lo, l.lo, &value.lo), r.hi, l.hi, &value.hi);
return value;
}
friend u128 operator -(const u128& l, std::uint64_t r)
{
u128 value;
_subborrow_u64(_subborrow_u64(0, r, l.lo, &value.lo), 0, l.hi, &value.hi);
return value;
}
friend u128 operator -(std::uint64_t l, const u128& r)
{
u128 value;
_subborrow_u64(_subborrow_u64(0, r.lo, l, &value.lo), r.hi, 0, &value.hi);
return value;
}
u128 operator +() const
{
return *this;
}
u128 operator -() const
{
u128 value;
_subborrow_u64(_subborrow_u64(0, lo, 0, &value.lo), hi, 0, &value.hi);
return value;
}
u128& operator ++()
{
_addcarry_u64(_addcarry_u64(0, 1, lo, &lo), 0, hi, &hi);
return *this;
}
u128 operator ++(int)
{
u128 value = *this;
_addcarry_u64(_addcarry_u64(0, 1, lo, &lo), 0, hi, &hi);
return value;
}
u128& operator --()
{
_subborrow_u64(_subborrow_u64(0, 1, lo, &lo), 0, hi, &hi);
return *this;
}
u128 operator --(int)
{
u128 value = *this;
_subborrow_u64(_subborrow_u64(0, 1, lo, &lo), 0, hi, &hi);
return value;
}
u128 operator ~() const
{
u128 value;
value.lo = ~lo;
value.hi = ~hi;
return value;
}
friend u128 operator &(const u128& l, const u128& r)
{
u128 value;
value.lo = l.lo & r.lo;
value.hi = l.hi & r.hi;
return value;
}
friend u128 operator |(const u128& l, const u128& r)
{
u128 value;
value.lo = l.lo | r.lo;
value.hi = l.hi | r.hi;
return value;
}
friend u128 operator ^(const u128& l, const u128& r)
{
u128 value;
value.lo = l.lo ^ r.lo;
value.hi = l.hi ^ r.hi;
return value;
}
u128& operator +=(const u128& r)
{
_addcarry_u64(_addcarry_u64(0, r.lo, lo, &lo), r.hi, hi, &hi);
return *this;
}
u128& operator +=(uint64_t r)
{
_addcarry_u64(_addcarry_u64(0, r, lo, &lo), 0, hi, &hi);
return *this;
}
u128& operator &=(const u128& r)
{
lo &= r.lo;
hi &= r.hi;
return *this;
}
u128& operator |=(const u128& r)
{
lo |= r.lo;
hi |= r.hi;
return *this;
}
u128& operator ^=(const u128& r)
{
lo ^= r.lo;
hi ^= r.hi;
return *this;
}
};
// Signed 128-bit integer implementation (TODO)
struct alignas(16) s128
{
std::uint64_t lo;
std::int64_t hi;
s128() = default;
constexpr s128(std::int64_t l)
: hi(l >> 63)
, lo(l)
{
}
constexpr s128(std::uint64_t l)
: hi(0)
, lo(l)
{
}
};
#endif
namespace std
{
/* Let's hack. */
template<>
struct is_integral<u128> : true_type
{
};
template<>
struct is_integral<s128> : true_type
{
};
template<>
struct make_unsigned<u128>
{
using type = u128;
};
template<>
struct make_unsigned<s128>
{
using type = u128;
};
template<>
struct make_signed<u128>
{
using type = s128;
};
template<>
struct make_signed<s128>
{
using type = s128;
};
}
static_assert(std::is_arithmetic<u128>::value && std::is_integral<u128>::value && alignof(u128) == 16 && sizeof(u128) == 16, "Wrong u128 implementation");
static_assert(std::is_arithmetic<s128>::value && std::is_integral<s128>::value && alignof(s128) == 16 && sizeof(s128) == 16, "Wrong s128 implementation");
union alignas(2) f16 union alignas(2) f16
{ {
u16 _u16; u16 _u16;
@ -55,6 +404,313 @@ struct ignore
} }
}; };
// Allows to define integer convertible to multiple enum types
template<typename T = void, typename... Ts>
struct multicast : multicast<Ts...>
{
static_assert(std::is_enum<T>::value, "multicast<> error: invalid conversion type (enum type expected)");
multicast() = default;
template<typename UT>
constexpr multicast(const UT& value)
: multicast<Ts...>(value)
, m_value{ value } // Forbid narrowing
{
}
constexpr operator T() const
{
// Cast to enum type
return static_cast<T>(m_value);
}
private:
std::underlying_type_t<T> m_value;
};
// Recursion terminator
template<>
struct multicast<void>
{
multicast() = default;
template<typename UT>
constexpr multicast(const UT& value)
{
}
};
// Small bitset for enum class types with available values [0, bitsize).
// T must be either enum type or convertible to (registered with via simple_t<T>).
// Internal representation is single value of type T.
template<typename T>
struct mset
{
using type = simple_t<T>;
using under = std::underlying_type_t<type>;
static constexpr auto bitsize = sizeof(type) * CHAR_BIT;
mset() = default;
constexpr mset(type _enum_const)
: m_value(static_cast<type>(shift(_enum_const)))
{
}
constexpr mset(under raw_value, const std::nothrow_t&)
: m_value(static_cast<T>(raw_value))
{
}
// Get underlying value
constexpr under _value() const
{
return static_cast<under>(m_value);
}
explicit constexpr operator bool() const
{
return _value() ? true : false;
}
mset& operator +=(mset rhs)
{
return *this = { _value() | rhs._value(), std::nothrow };
}
mset& operator -=(mset rhs)
{
return *this = { _value() & ~rhs._value(), std::nothrow };
}
mset& operator &=(mset rhs)
{
return *this = { _value() & rhs._value(), std::nothrow };
}
mset& operator ^=(mset rhs)
{
return *this = { _value() ^ rhs._value(), std::nothrow };
}
friend constexpr mset operator +(mset lhs, mset rhs)
{
return{ lhs._value() | rhs._value(), std::nothrow };
}
friend constexpr mset operator -(mset lhs, mset rhs)
{
return{ lhs._value() & ~rhs._value(), std::nothrow };
}
friend constexpr mset operator &(mset lhs, mset rhs)
{
return{ lhs._value() & rhs._value(), std::nothrow };
}
friend constexpr mset operator ^(mset lhs, mset rhs)
{
return{ lhs._value() ^ rhs._value(), std::nothrow };
}
bool test(mset rhs) const
{
const under v = _value();
const under s = rhs._value();
return (v & s) != 0;
}
bool test_and_set(mset rhs)
{
const under v = _value();
const under s = rhs._value();
*this = { v | s, std::nothrow };
return (v & s) != 0;
}
bool test_and_reset(mset rhs)
{
const under v = _value();
const under s = rhs._value();
*this = { v & ~s, std::nothrow };
return (v & s) != 0;
}
bool test_and_complement(mset rhs)
{
const under v = _value();
const under s = rhs._value();
*this = { v ^ s, std::nothrow };
return (v & s) != 0;
}
private:
[[noreturn]] static under xrange()
{
throw std::out_of_range("mset<>: bit out of range");
}
static constexpr under shift(const T& value)
{
return static_cast<under>(value) < bitsize ? static_cast<under>(1) << static_cast<under>(value) : xrange();
}
T m_value;
};
template<typename T, typename RT = T>
constexpr RT to_mset()
{
return RT{};
}
// Fold enum constants into mset<>
template<typename T = void, typename Arg, typename... Args, typename RT = std::conditional_t<std::is_void<T>::value, mset<Arg>, T>>
constexpr RT to_mset(Arg&& _enum_const, Args&&... args)
{
return RT{ std::forward<Arg>(_enum_const) } + to_mset<RT>(std::forward<Args>(args)...);
}
template<typename T, typename CT>
struct atomic_add<mset<T>, CT, std::enable_if_t<std::is_enum<T>::value>>
{
using under = typename mset<T>::under;
static force_inline mset<T> op1(mset<T>& left, mset<T> right)
{
return{ atomic_storage<under>::fetch_or(reinterpret_cast<under&>(left), right._value()), std::nothrow };
}
static constexpr auto fetch_op = &op1;
static force_inline mset<T> op2(mset<T>& left, mset<T> right)
{
return{ atomic_storage<under>::or_fetch(reinterpret_cast<under&>(left), right._value()), std::nothrow };
}
static constexpr auto op_fetch = &op2;
static constexpr auto atomic_op = &op2;
};
template<typename T, typename CT>
struct atomic_sub<mset<T>, CT, std::enable_if_t<std::is_enum<T>::value>>
{
using under = typename mset<T>::under;
static force_inline mset<T> op1(mset<T>& left, mset<T> right)
{
return{ atomic_storage<under>::fetch_and(reinterpret_cast<under&>(left), ~right._value()), std::nothrow };
}
static constexpr auto fetch_op = &op1;
static force_inline mset<T> op2(mset<T>& left, mset<T> right)
{
return{ atomic_storage<under>::and_fetch(reinterpret_cast<under&>(left), ~right._value()), std::nothrow };
}
static constexpr auto op_fetch = &op2;
static constexpr auto atomic_op = &op2;
};
template<typename T, typename CT>
struct atomic_and<mset<T>, CT, std::enable_if_t<std::is_enum<T>::value>>
{
using under = typename mset<T>::under;
static force_inline mset<T> op1(mset<T>& left, mset<T> right)
{
return{ atomic_storage<under>::fetch_and(reinterpret_cast<under&>(left), right._value()), std::nothrow };
}
static constexpr auto fetch_op = &op1;
static force_inline mset<T> op2(mset<T>& left, mset<T> right)
{
return{ atomic_storage<under>::and_fetch(reinterpret_cast<under&>(left), right._value()), std::nothrow };
}
static constexpr auto op_fetch = &op2;
static constexpr auto atomic_op = &op2;
};
template<typename T, typename CT>
struct atomic_xor<mset<T>, CT, std::enable_if_t<std::is_enum<T>::value>>
{
using under = typename mset<T>::under;
static force_inline mset<T> op1(mset<T>& left, mset<T> right)
{
return{ atomic_storage<under>::fetch_xor(reinterpret_cast<under&>(left), right._value()), std::nothrow };
}
static constexpr auto fetch_op = &op1;
static force_inline mset<T> op2(mset<T>& left, mset<T> right)
{
return{ atomic_storage<under>::xor_fetch(reinterpret_cast<under&>(left), right._value()), std::nothrow };
}
static constexpr auto op_fetch = &op2;
static constexpr auto atomic_op = &op2;
};
template<typename T>
struct atomic_test_and_set<mset<T>, T, std::enable_if_t<std::is_enum<T>::value>>
{
using under = typename mset<T>::under;
static force_inline bool _op(mset<T>& left, const T& value)
{
return atomic_storage<under>::bts(reinterpret_cast<under&>(left), static_cast<uint>(value));
}
static constexpr auto atomic_op = &_op;
};
template<typename T>
struct atomic_test_and_reset<mset<T>, T, std::enable_if_t<std::is_enum<T>::value>>
{
using under = typename mset<T>::under;
static force_inline bool _op(mset<T>& left, const T& value)
{
return atomic_storage<under>::btr(reinterpret_cast<under&>(left), static_cast<uint>(value));
}
static constexpr auto atomic_op = &_op;
};
template<typename T>
struct atomic_test_and_complement<mset<T>, T, std::enable_if_t<std::is_enum<T>::value>>
{
using under = typename mset<T>::under;
static force_inline bool _op(mset<T>& left, const T& value)
{
return atomic_storage<under>::btc(reinterpret_cast<under&>(left), static_cast<uint>(value));
}
static constexpr auto atomic_op = &_op;
};
template<typename T1, typename T2 = const char*, typename T = T1, typename DT = T2>
T2 bijective_find(const T& left, const DT& def = {})
{
for (const auto& pair : bijective<T1, T2>::map)
{
if (pair.first == left)
{
return pair.second;
}
}
return def;
}
template<typename T> template<typename T>
struct size2_base struct size2_base
{ {
@ -1088,15 +1744,3 @@ using color2d = color2_base<double>;
using color1i = color1_base<int>; using color1i = color1_base<int>;
using color1f = color1_base<float>; using color1f = color1_base<float>;
using color1d = color1_base<double>; using color1d = color1_base<double>;
namespace std
{
template<>
struct hash<::position2i>
{
size_t operator()(const ::position2i& position) const
{
return (static_cast<size_t>(position.x) << 32) | position.y;
}
};
}

View file

@ -300,7 +300,7 @@
// Recommended setting: 0 as the options below already provide a relatively // Recommended setting: 0 as the options below already provide a relatively
// good level of interoperability and changing this option arguably isn't worth // good level of interoperability and changing this option arguably isn't worth
// diverging from the official builds of the library. // diverging from the official builds of the library.
#define wxUSE_STL 0 #define wxUSE_STL 1
// This is not a real option but is used as the default value for // This is not a real option but is used as the default value for
// wxUSE_STD_IOSTREAM, wxUSE_STD_STRING and wxUSE_STD_CONTAINERS_COMPATIBLY. // wxUSE_STD_IOSTREAM, wxUSE_STD_STRING and wxUSE_STD_CONTAINERS_COMPATIBLY.

View file

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{FDC361C5-7734-493B-8CFB-037308B35122}</ProjectGuid>
<RootNamespace>yamlcpp</RootNamespace>
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
<PlatformToolset>v140</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\rpcs3_default.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="..\rpcs3_debug.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="..\rpcs3_release.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemGroup>
<ClCompile Include="yaml-cpp\src\binary.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\convert.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\directives.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\emit.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\emitfromevents.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\emitter.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\emitterstate.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\emitterutils.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\exp.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\memory.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\node.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\nodebuilder.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\nodeevents.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\node_data.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\null.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\ostream_wrapper.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\parse.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\parser.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\regex_yaml.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\scanner.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\scanscalar.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\scantag.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\scantoken.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\simplekey.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\singledocparser.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\stream.cpp">
</ClCompile>
<ClCompile Include="yaml-cpp\src\tag.cpp">
</ClCompile>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\binary.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\convert.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\directives.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\emit.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\emitfromevents.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\emitter.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\emitterstate.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\emitterutils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\exp.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\memory.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\node.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\node_data.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\nodebuilder.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\nodeevents.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\null.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\ostream_wrapper.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\parse.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\parser.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\regex_yaml.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\scanner.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\scanscalar.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\scantag.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\scantoken.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\simplekey.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\singledocparser.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\stream.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\tag.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View file

@ -14,7 +14,7 @@ branches:
before_build: before_build:
# until git for win 2.5 release with commit checkout # until git for win 2.5 release with commit checkout
- git submodule update --init 3rdparty/ffmpeg 3rdparty/pugixml asmjit rsx_program_decompiler 3rdparty/GSL 3rdparty/libpng Vulkan/glslang Vulkan/Vulkan-LoaderAndValidationLayers - git submodule update --init 3rdparty/ffmpeg 3rdparty/pugixml asmjit 3rdparty/GSL 3rdparty/libpng Vulkan/glslang Vulkan/Vulkan-LoaderAndValidationLayers Utilities/yaml-cpp
- 7z x wxWidgets.7z -aos -oC:\rpcs3\wxWidgets > null - 7z x wxWidgets.7z -aos -oC:\rpcs3\wxWidgets > null
- 7z x zlib.7z -aos -oC:\rpcs3\ > null - 7z x zlib.7z -aos -oC:\rpcs3\ > null
- if %configuration%==Release (cmake -G "Visual Studio 14 Win64" -DZLIB_ROOT=C:/rpcs3/zlib/) - if %configuration%==Release (cmake -G "Visual Studio 14 Win64" -DZLIB_ROOT=C:/rpcs3/zlib/)

243
rpcs3.sln
View file

@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14 # Visual Studio 14
VisualStudioVersion = 14.0.24720.0 VisualStudioVersion = 14.0.25123.0
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rpcs3", "rpcs3\rpcs3.vcxproj", "{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rpcs3", "rpcs3\rpcs3.vcxproj", "{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}"
ProjectSection(ProjectDependencies) = postProject ProjectSection(ProjectDependencies) = postProject
@ -161,11 +161,6 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "asmjit", "asmjit", "{E2A982F2-4B1A-48B1-8D77-A17A589C58D7}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "asmjit", "asmjit", "{E2A982F2-4B1A-48B1-8D77-A17A589C58D7}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "emucore", "rpcs3\emucore.vcxproj", "{C4A10229-4712-4BD2-B63E-50D93C67A038}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "emucore", "rpcs3\emucore.vcxproj", "{C4A10229-4712-4BD2-B63E-50D93C67A038}"
ProjectSection(ProjectDependencies) = postProject
{8BC303AB-25BE-4276-8E57-73F171B2D672} = {8BC303AB-25BE-4276-8E57-73F171B2D672}
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "llvm", "llvm", "{C8068CE9-D626-4FEA-BEE7-893F06A25BF3}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "llvm_build", "llvm_build\llvm_build.vcxproj", "{8BC303AB-25BE-4276-8E57-73F171B2D672}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "llvm_build", "llvm_build\llvm_build.vcxproj", "{8BC303AB-25BE-4276-8E57-73F171B2D672}"
EndProject EndProject
@ -209,8 +204,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "zlib", "zlib", "{F0C19EFA-E
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "3rdparty\libpng\projects\vstudio\zlib\zlib.vcxproj", "{60F89955-91C6-3A36-8000-13C592FEC2DF}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "3rdparty\libpng\projects\vstudio\zlib\zlib.vcxproj", "{60F89955-91C6-3A36-8000-13C592FEC2DF}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Vulkan", "Vulkan", "{09AD61F7-97FE-4FF8-8F7F-63FEA9B746F4}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Vulkan-build", "Vulkan\Vulkan-build\Vulkan-build.vcxproj", "{58B40697-B15E-429E-B325-D52C28AEBCBF}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Vulkan-build", "Vulkan\Vulkan-build\Vulkan-build.vcxproj", "{58B40697-B15E-429E-B325-D52C28AEBCBF}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "glslang-build", "Vulkan\glslang-build\glslang-build.vcxproj", "{8F85B6CC-250F-4ACA-A617-E820A74E3E3C}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "glslang-build", "Vulkan\glslang-build\glslang-build.vcxproj", "{8F85B6CC-250F-4ACA-A617-E820A74E3E3C}"
@ -221,17 +214,19 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "VKGSRender", "rpcs3\VKGSRen
{8F85B6CC-250F-4ACA-A617-E820A74E3E3C} = {8F85B6CC-250F-4ACA-A617-E820A74E3E3C} {8F85B6CC-250F-4ACA-A617-E820A74E3E3C} = {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}
EndProjectSection EndProjectSection
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PPULLVMRecompiler", "rpcs3\PPULLVMRecompiler.vcxproj", "{304A6E8B-A311-4EC5-8045-BFA8D08175CE}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "webview", "wxWidgets\build\msw\wx_webview.vcxproj", "{A8E8442A-078A-5FC5-B495-8D71BA77EE6E}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "webview", "wxWidgets\build\msw\wx_webview.vcxproj", "{A8E8442A-078A-5FC5-B495-8D71BA77EE6E}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "yaml-cpp", "yaml-cpp", "{DDF904CA-2771-441A-8629-5DF2EB922A79}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "__BUILD_BEFORE", "__BUILD_BEFORE", "{B0AC29FD-7B01-4B5E-9C8D-0A081E4C5668}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yaml-cpp", "Utilities\yaml-cpp.vcxproj", "{FDC361C5-7734-493B-8CFB-037308B35122}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug - LLVM|x64 = Debug - LLVM|x64 Debug - LLVM|x64 = Debug - LLVM|x64
Debug - MemLeak|x64 = Debug - MemLeak|x64 Debug - MemLeak|x64 = Debug - MemLeak|x64
Debug|x64 = Debug|x64 Debug|x64 = Debug|x64
DLL Debug|x64 = DLL Debug|x64
DLL Release|x64 = DLL Release|x64
Release - LLVM|x64 = Release - LLVM|x64 Release - LLVM|x64 = Release - LLVM|x64
Release|x64 = Release|x64 Release|x64 = Release|x64
EndGlobalSection EndGlobalSection
@ -242,10 +237,6 @@ Global
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64 {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug|x64.ActiveCfg = Debug|x64 {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug|x64.ActiveCfg = Debug|x64
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug|x64.Build.0 = Debug|x64 {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Debug|x64.Build.0 = Debug|x64
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.DLL Debug|x64.ActiveCfg = Debug|x64
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.DLL Debug|x64.Build.0 = Debug|x64
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.DLL Release|x64.ActiveCfg = Release|x64
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.DLL Release|x64.Build.0 = Release|x64
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64 {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Release - LLVM|x64.Build.0 = Release - LLVM|x64 {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Release - LLVM|x64.Build.0 = Release - LLVM|x64
{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Release|x64.ActiveCfg = Release|x64 {70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}.Release|x64.ActiveCfg = Release|x64
@ -256,10 +247,6 @@ Global
{24C45343-FD20-5C92-81C1-35A2AE841E79}.Debug - MemLeak|x64.Build.0 = Debug|x64 {24C45343-FD20-5C92-81C1-35A2AE841E79}.Debug - MemLeak|x64.Build.0 = Debug|x64
{24C45343-FD20-5C92-81C1-35A2AE841E79}.Debug|x64.ActiveCfg = Debug|x64 {24C45343-FD20-5C92-81C1-35A2AE841E79}.Debug|x64.ActiveCfg = Debug|x64
{24C45343-FD20-5C92-81C1-35A2AE841E79}.Debug|x64.Build.0 = Debug|x64 {24C45343-FD20-5C92-81C1-35A2AE841E79}.Debug|x64.Build.0 = Debug|x64
{24C45343-FD20-5C92-81C1-35A2AE841E79}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
{24C45343-FD20-5C92-81C1-35A2AE841E79}.DLL Debug|x64.Build.0 = DLL Debug|x64
{24C45343-FD20-5C92-81C1-35A2AE841E79}.DLL Release|x64.ActiveCfg = DLL Release|x64
{24C45343-FD20-5C92-81C1-35A2AE841E79}.DLL Release|x64.Build.0 = DLL Release|x64
{24C45343-FD20-5C92-81C1-35A2AE841E79}.Release - LLVM|x64.ActiveCfg = Release|x64 {24C45343-FD20-5C92-81C1-35A2AE841E79}.Release - LLVM|x64.ActiveCfg = Release|x64
{24C45343-FD20-5C92-81C1-35A2AE841E79}.Release - LLVM|x64.Build.0 = Release|x64 {24C45343-FD20-5C92-81C1-35A2AE841E79}.Release - LLVM|x64.Build.0 = Release|x64
{24C45343-FD20-5C92-81C1-35A2AE841E79}.Release|x64.ActiveCfg = Release|x64 {24C45343-FD20-5C92-81C1-35A2AE841E79}.Release|x64.ActiveCfg = Release|x64
@ -270,10 +257,6 @@ Global
{A16D3832-0F42-57CE-8F48-50E06649ADE8}.Debug - MemLeak|x64.Build.0 = Debug|x64 {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Debug - MemLeak|x64.Build.0 = Debug|x64
{A16D3832-0F42-57CE-8F48-50E06649ADE8}.Debug|x64.ActiveCfg = Debug|x64 {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Debug|x64.ActiveCfg = Debug|x64
{A16D3832-0F42-57CE-8F48-50E06649ADE8}.Debug|x64.Build.0 = Debug|x64 {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Debug|x64.Build.0 = Debug|x64
{A16D3832-0F42-57CE-8F48-50E06649ADE8}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
{A16D3832-0F42-57CE-8F48-50E06649ADE8}.DLL Debug|x64.Build.0 = DLL Debug|x64
{A16D3832-0F42-57CE-8F48-50E06649ADE8}.DLL Release|x64.ActiveCfg = DLL Release|x64
{A16D3832-0F42-57CE-8F48-50E06649ADE8}.DLL Release|x64.Build.0 = DLL Release|x64
{A16D3832-0F42-57CE-8F48-50E06649ADE8}.Release - LLVM|x64.ActiveCfg = Release|x64 {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Release - LLVM|x64.ActiveCfg = Release|x64
{A16D3832-0F42-57CE-8F48-50E06649ADE8}.Release - LLVM|x64.Build.0 = Release|x64 {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Release - LLVM|x64.Build.0 = Release|x64
{A16D3832-0F42-57CE-8F48-50E06649ADE8}.Release|x64.ActiveCfg = Release|x64 {A16D3832-0F42-57CE-8F48-50E06649ADE8}.Release|x64.ActiveCfg = Release|x64
@ -284,10 +267,6 @@ Global
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug - MemLeak|x64.Build.0 = Debug|x64 {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug - MemLeak|x64.Build.0 = Debug|x64
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug|x64.ActiveCfg = Debug|x64 {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug|x64.ActiveCfg = Debug|x64
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug|x64.Build.0 = Debug|x64 {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Debug|x64.Build.0 = Debug|x64
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.DLL Debug|x64.Build.0 = DLL Debug|x64
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.DLL Release|x64.ActiveCfg = DLL Release|x64
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.DLL Release|x64.Build.0 = DLL Release|x64
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release - LLVM|x64.ActiveCfg = Release|x64 {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release - LLVM|x64.ActiveCfg = Release|x64
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release - LLVM|x64.Build.0 = Release|x64 {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release - LLVM|x64.Build.0 = Release|x64
{3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release|x64.ActiveCfg = Release|x64 {3FCC50C2-81E9-5DB2-B8D8-2129427568B1}.Release|x64.ActiveCfg = Release|x64
@ -298,10 +277,6 @@ Global
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Debug - MemLeak|x64.Build.0 = Debug|x64 {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Debug - MemLeak|x64.Build.0 = Debug|x64
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Debug|x64.ActiveCfg = Debug|x64 {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Debug|x64.ActiveCfg = Debug|x64
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Debug|x64.Build.0 = Debug|x64 {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Debug|x64.Build.0 = Debug|x64
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.DLL Debug|x64.Build.0 = DLL Debug|x64
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.DLL Release|x64.ActiveCfg = DLL Release|x64
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.DLL Release|x64.Build.0 = DLL Release|x64
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Release - LLVM|x64.ActiveCfg = Release|x64 {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Release - LLVM|x64.ActiveCfg = Release|x64
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Release - LLVM|x64.Build.0 = Release|x64 {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Release - LLVM|x64.Build.0 = Release|x64
{6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Release|x64.ActiveCfg = Release|x64 {6744DAD8-9C70-574A-BFF2-9F8DDDB24A75}.Release|x64.ActiveCfg = Release|x64
@ -312,10 +287,6 @@ Global
{97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Debug - MemLeak|x64.Build.0 = Debug|x64 {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Debug - MemLeak|x64.Build.0 = Debug|x64
{97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Debug|x64.ActiveCfg = Debug|x64 {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Debug|x64.ActiveCfg = Debug|x64
{97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Debug|x64.Build.0 = Debug|x64 {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Debug|x64.Build.0 = Debug|x64
{97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
{97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.DLL Debug|x64.Build.0 = DLL Debug|x64
{97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.DLL Release|x64.ActiveCfg = DLL Release|x64
{97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.DLL Release|x64.Build.0 = DLL Release|x64
{97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Release - LLVM|x64.ActiveCfg = Release|x64 {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Release - LLVM|x64.ActiveCfg = Release|x64
{97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Release - LLVM|x64.Build.0 = Release|x64 {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Release - LLVM|x64.Build.0 = Release|x64
{97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Release|x64.ActiveCfg = Release|x64 {97FDAB45-9C58-5BC5-A2F4-EE42739EBC63}.Release|x64.ActiveCfg = Release|x64
@ -326,10 +297,6 @@ Global
{DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Debug - MemLeak|x64.Build.0 = Debug|x64 {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Debug - MemLeak|x64.Build.0 = Debug|x64
{DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Debug|x64.ActiveCfg = Debug|x64 {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Debug|x64.ActiveCfg = Debug|x64
{DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Debug|x64.Build.0 = Debug|x64 {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Debug|x64.Build.0 = Debug|x64
{DA8B15EF-6750-5928-BC0E-C748213CF9B2}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
{DA8B15EF-6750-5928-BC0E-C748213CF9B2}.DLL Debug|x64.Build.0 = DLL Debug|x64
{DA8B15EF-6750-5928-BC0E-C748213CF9B2}.DLL Release|x64.ActiveCfg = DLL Release|x64
{DA8B15EF-6750-5928-BC0E-C748213CF9B2}.DLL Release|x64.Build.0 = DLL Release|x64
{DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Release - LLVM|x64.ActiveCfg = Release|x64 {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Release - LLVM|x64.ActiveCfg = Release|x64
{DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Release - LLVM|x64.Build.0 = Release|x64 {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Release - LLVM|x64.Build.0 = Release|x64
{DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Release|x64.ActiveCfg = Release|x64 {DA8B15EF-6750-5928-BC0E-C748213CF9B2}.Release|x64.ActiveCfg = Release|x64
@ -338,13 +305,8 @@ Global
{33CC42F9-7756-5587-863C-8D4461B7C5DD}.Debug - LLVM|x64.Build.0 = Debug|x64 {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Debug - LLVM|x64.Build.0 = Debug|x64
{33CC42F9-7756-5587-863C-8D4461B7C5DD}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
{33CC42F9-7756-5587-863C-8D4461B7C5DD}.Debug - MemLeak|x64.Build.0 = Debug|x64 {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Debug - MemLeak|x64.Build.0 = Debug|x64
{33CC42F9-7756-5587-863C-8D4461B7C5DD}.Debug - MemLeak|x64.Deploy.0 = Debug|x64
{33CC42F9-7756-5587-863C-8D4461B7C5DD}.Debug|x64.ActiveCfg = Debug|x64 {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Debug|x64.ActiveCfg = Debug|x64
{33CC42F9-7756-5587-863C-8D4461B7C5DD}.Debug|x64.Build.0 = Debug|x64 {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Debug|x64.Build.0 = Debug|x64
{33CC42F9-7756-5587-863C-8D4461B7C5DD}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
{33CC42F9-7756-5587-863C-8D4461B7C5DD}.DLL Debug|x64.Build.0 = DLL Debug|x64
{33CC42F9-7756-5587-863C-8D4461B7C5DD}.DLL Release|x64.ActiveCfg = DLL Release|x64
{33CC42F9-7756-5587-863C-8D4461B7C5DD}.DLL Release|x64.Build.0 = DLL Release|x64
{33CC42F9-7756-5587-863C-8D4461B7C5DD}.Release - LLVM|x64.ActiveCfg = Release|x64 {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Release - LLVM|x64.ActiveCfg = Release|x64
{33CC42F9-7756-5587-863C-8D4461B7C5DD}.Release - LLVM|x64.Build.0 = Release|x64 {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Release - LLVM|x64.Build.0 = Release|x64
{33CC42F9-7756-5587-863C-8D4461B7C5DD}.Release|x64.ActiveCfg = Release|x64 {33CC42F9-7756-5587-863C-8D4461B7C5DD}.Release|x64.ActiveCfg = Release|x64
@ -355,10 +317,6 @@ Global
{8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Debug - MemLeak|x64.Build.0 = Debug|x64 {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Debug - MemLeak|x64.Build.0 = Debug|x64
{8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Debug|x64.ActiveCfg = Debug|x64 {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Debug|x64.ActiveCfg = Debug|x64
{8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Debug|x64.Build.0 = Debug|x64 {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Debug|x64.Build.0 = Debug|x64
{8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
{8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.DLL Debug|x64.Build.0 = DLL Debug|x64
{8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.DLL Release|x64.ActiveCfg = DLL Release|x64
{8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.DLL Release|x64.Build.0 = DLL Release|x64
{8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Release - LLVM|x64.ActiveCfg = Release|x64 {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Release - LLVM|x64.ActiveCfg = Release|x64
{8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Release - LLVM|x64.Build.0 = Release|x64 {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Release - LLVM|x64.Build.0 = Release|x64
{8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Release|x64.ActiveCfg = Release|x64 {8BD8F8D9-4275-5B42-A8F4-F1DB2970A550}.Release|x64.ActiveCfg = Release|x64
@ -369,10 +327,6 @@ Global
{69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Debug - MemLeak|x64.Build.0 = Debug|x64 {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Debug - MemLeak|x64.Build.0 = Debug|x64
{69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Debug|x64.ActiveCfg = Debug|x64 {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Debug|x64.ActiveCfg = Debug|x64
{69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Debug|x64.Build.0 = Debug|x64 {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Debug|x64.Build.0 = Debug|x64
{69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
{69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.DLL Debug|x64.Build.0 = DLL Debug|x64
{69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.DLL Release|x64.ActiveCfg = DLL Release|x64
{69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.DLL Release|x64.Build.0 = DLL Release|x64
{69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Release - LLVM|x64.ActiveCfg = Release|x64 {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Release - LLVM|x64.ActiveCfg = Release|x64
{69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Release - LLVM|x64.Build.0 = Release|x64 {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Release - LLVM|x64.Build.0 = Release|x64
{69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Release|x64.ActiveCfg = Release|x64 {69F2EDE4-7D21-5738-9BC0-F66F61C9AE00}.Release|x64.ActiveCfg = Release|x64
@ -383,10 +337,6 @@ Global
{E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Debug - MemLeak|x64.Build.0 = Debug|x64 {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Debug - MemLeak|x64.Build.0 = Debug|x64
{E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Debug|x64.ActiveCfg = Debug|x64 {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Debug|x64.ActiveCfg = Debug|x64
{E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Debug|x64.Build.0 = Debug|x64 {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Debug|x64.Build.0 = Debug|x64
{E21129E0-7C08-5936-9D8C-0D60B5319BA7}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
{E21129E0-7C08-5936-9D8C-0D60B5319BA7}.DLL Debug|x64.Build.0 = DLL Debug|x64
{E21129E0-7C08-5936-9D8C-0D60B5319BA7}.DLL Release|x64.ActiveCfg = DLL Release|x64
{E21129E0-7C08-5936-9D8C-0D60B5319BA7}.DLL Release|x64.Build.0 = DLL Release|x64
{E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Release - LLVM|x64.ActiveCfg = Release|x64 {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Release - LLVM|x64.ActiveCfg = Release|x64
{E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Release - LLVM|x64.Build.0 = Release|x64 {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Release - LLVM|x64.Build.0 = Release|x64
{E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Release|x64.ActiveCfg = Release|x64 {E21129E0-7C08-5936-9D8C-0D60B5319BA7}.Release|x64.ActiveCfg = Release|x64
@ -397,10 +347,6 @@ Global
{7FB0902D-8579-5DCE-B883-DAF66A885005}.Debug - MemLeak|x64.Build.0 = Debug|x64 {7FB0902D-8579-5DCE-B883-DAF66A885005}.Debug - MemLeak|x64.Build.0 = Debug|x64
{7FB0902D-8579-5DCE-B883-DAF66A885005}.Debug|x64.ActiveCfg = Debug|x64 {7FB0902D-8579-5DCE-B883-DAF66A885005}.Debug|x64.ActiveCfg = Debug|x64
{7FB0902D-8579-5DCE-B883-DAF66A885005}.Debug|x64.Build.0 = Debug|x64 {7FB0902D-8579-5DCE-B883-DAF66A885005}.Debug|x64.Build.0 = Debug|x64
{7FB0902D-8579-5DCE-B883-DAF66A885005}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
{7FB0902D-8579-5DCE-B883-DAF66A885005}.DLL Debug|x64.Build.0 = DLL Debug|x64
{7FB0902D-8579-5DCE-B883-DAF66A885005}.DLL Release|x64.ActiveCfg = DLL Release|x64
{7FB0902D-8579-5DCE-B883-DAF66A885005}.DLL Release|x64.Build.0 = DLL Release|x64
{7FB0902D-8579-5DCE-B883-DAF66A885005}.Release - LLVM|x64.ActiveCfg = Release|x64 {7FB0902D-8579-5DCE-B883-DAF66A885005}.Release - LLVM|x64.ActiveCfg = Release|x64
{7FB0902D-8579-5DCE-B883-DAF66A885005}.Release - LLVM|x64.Build.0 = Release|x64 {7FB0902D-8579-5DCE-B883-DAF66A885005}.Release - LLVM|x64.Build.0 = Release|x64
{7FB0902D-8579-5DCE-B883-DAF66A885005}.Release|x64.ActiveCfg = Release|x64 {7FB0902D-8579-5DCE-B883-DAF66A885005}.Release|x64.ActiveCfg = Release|x64
@ -411,10 +357,6 @@ Global
{A1A8355B-0988-528E-9CC2-B971D6266669}.Debug - MemLeak|x64.Build.0 = Debug|x64 {A1A8355B-0988-528E-9CC2-B971D6266669}.Debug - MemLeak|x64.Build.0 = Debug|x64
{A1A8355B-0988-528E-9CC2-B971D6266669}.Debug|x64.ActiveCfg = Debug|x64 {A1A8355B-0988-528E-9CC2-B971D6266669}.Debug|x64.ActiveCfg = Debug|x64
{A1A8355B-0988-528E-9CC2-B971D6266669}.Debug|x64.Build.0 = Debug|x64 {A1A8355B-0988-528E-9CC2-B971D6266669}.Debug|x64.Build.0 = Debug|x64
{A1A8355B-0988-528E-9CC2-B971D6266669}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
{A1A8355B-0988-528E-9CC2-B971D6266669}.DLL Debug|x64.Build.0 = DLL Debug|x64
{A1A8355B-0988-528E-9CC2-B971D6266669}.DLL Release|x64.ActiveCfg = DLL Release|x64
{A1A8355B-0988-528E-9CC2-B971D6266669}.DLL Release|x64.Build.0 = DLL Release|x64
{A1A8355B-0988-528E-9CC2-B971D6266669}.Release - LLVM|x64.ActiveCfg = Release|x64 {A1A8355B-0988-528E-9CC2-B971D6266669}.Release - LLVM|x64.ActiveCfg = Release|x64
{A1A8355B-0988-528E-9CC2-B971D6266669}.Release - LLVM|x64.Build.0 = Release|x64 {A1A8355B-0988-528E-9CC2-B971D6266669}.Release - LLVM|x64.Build.0 = Release|x64
{A1A8355B-0988-528E-9CC2-B971D6266669}.Release|x64.ActiveCfg = Release|x64 {A1A8355B-0988-528E-9CC2-B971D6266669}.Release|x64.ActiveCfg = Release|x64
@ -425,10 +367,6 @@ Global
{6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Debug - MemLeak|x64.Build.0 = Debug|x64 {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Debug - MemLeak|x64.Build.0 = Debug|x64
{6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Debug|x64.ActiveCfg = Debug|x64 {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Debug|x64.ActiveCfg = Debug|x64
{6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Debug|x64.Build.0 = Debug|x64 {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Debug|x64.Build.0 = Debug|x64
{6053CC38-CDEE-584C-8BC8-4B000D800FC7}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
{6053CC38-CDEE-584C-8BC8-4B000D800FC7}.DLL Debug|x64.Build.0 = DLL Debug|x64
{6053CC38-CDEE-584C-8BC8-4B000D800FC7}.DLL Release|x64.ActiveCfg = DLL Release|x64
{6053CC38-CDEE-584C-8BC8-4B000D800FC7}.DLL Release|x64.Build.0 = DLL Release|x64
{6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Release - LLVM|x64.ActiveCfg = Release|x64 {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Release - LLVM|x64.ActiveCfg = Release|x64
{6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Release - LLVM|x64.Build.0 = Release|x64 {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Release - LLVM|x64.Build.0 = Release|x64
{6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Release|x64.ActiveCfg = Release|x64 {6053CC38-CDEE-584C-8BC8-4B000D800FC7}.Release|x64.ActiveCfg = Release|x64
@ -439,10 +377,6 @@ Global
{8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Debug - MemLeak|x64.Build.0 = Debug|x64 {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Debug - MemLeak|x64.Build.0 = Debug|x64
{8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Debug|x64.ActiveCfg = Debug|x64 {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Debug|x64.ActiveCfg = Debug|x64
{8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Debug|x64.Build.0 = Debug|x64 {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Debug|x64.Build.0 = Debug|x64
{8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
{8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.DLL Debug|x64.Build.0 = DLL Debug|x64
{8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.DLL Release|x64.ActiveCfg = DLL Release|x64
{8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.DLL Release|x64.Build.0 = DLL Release|x64
{8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Release - LLVM|x64.ActiveCfg = Release|x64 {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Release - LLVM|x64.ActiveCfg = Release|x64
{8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Release - LLVM|x64.Build.0 = Release|x64 {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Release - LLVM|x64.Build.0 = Release|x64
{8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Release|x64.ActiveCfg = Release|x64 {8ACC122A-CA6A-5AA6-9C97-9CDD2E533DB0}.Release|x64.ActiveCfg = Release|x64
@ -453,10 +387,6 @@ Global
{56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Debug - MemLeak|x64.Build.0 = Debug|x64 {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Debug - MemLeak|x64.Build.0 = Debug|x64
{56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Debug|x64.ActiveCfg = Debug|x64 {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Debug|x64.ActiveCfg = Debug|x64
{56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Debug|x64.Build.0 = Debug|x64 {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Debug|x64.Build.0 = Debug|x64
{56A4B526-BB81-5D01-AAA9-16D23BBB169D}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
{56A4B526-BB81-5D01-AAA9-16D23BBB169D}.DLL Debug|x64.Build.0 = DLL Debug|x64
{56A4B526-BB81-5D01-AAA9-16D23BBB169D}.DLL Release|x64.ActiveCfg = DLL Release|x64
{56A4B526-BB81-5D01-AAA9-16D23BBB169D}.DLL Release|x64.Build.0 = DLL Release|x64
{56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Release - LLVM|x64.ActiveCfg = Release|x64 {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Release - LLVM|x64.ActiveCfg = Release|x64
{56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Release - LLVM|x64.Build.0 = Release|x64 {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Release - LLVM|x64.Build.0 = Release|x64
{56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Release|x64.ActiveCfg = Release|x64 {56A4B526-BB81-5D01-AAA9-16D23BBB169D}.Release|x64.ActiveCfg = Release|x64
@ -467,10 +397,6 @@ Global
{75596CE6-5AE7-55C9-B890-C07B0A657A83}.Debug - MemLeak|x64.Build.0 = Debug|x64 {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Debug - MemLeak|x64.Build.0 = Debug|x64
{75596CE6-5AE7-55C9-B890-C07B0A657A83}.Debug|x64.ActiveCfg = Debug|x64 {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Debug|x64.ActiveCfg = Debug|x64
{75596CE6-5AE7-55C9-B890-C07B0A657A83}.Debug|x64.Build.0 = Debug|x64 {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Debug|x64.Build.0 = Debug|x64
{75596CE6-5AE7-55C9-B890-C07B0A657A83}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
{75596CE6-5AE7-55C9-B890-C07B0A657A83}.DLL Debug|x64.Build.0 = DLL Debug|x64
{75596CE6-5AE7-55C9-B890-C07B0A657A83}.DLL Release|x64.ActiveCfg = DLL Release|x64
{75596CE6-5AE7-55C9-B890-C07B0A657A83}.DLL Release|x64.Build.0 = DLL Release|x64
{75596CE6-5AE7-55C9-B890-C07B0A657A83}.Release - LLVM|x64.ActiveCfg = Release|x64 {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Release - LLVM|x64.ActiveCfg = Release|x64
{75596CE6-5AE7-55C9-B890-C07B0A657A83}.Release - LLVM|x64.Build.0 = Release|x64 {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Release - LLVM|x64.Build.0 = Release|x64
{75596CE6-5AE7-55C9-B890-C07B0A657A83}.Release|x64.ActiveCfg = Release|x64 {75596CE6-5AE7-55C9-B890-C07B0A657A83}.Release|x64.ActiveCfg = Release|x64
@ -481,10 +407,6 @@ Global
{8B867186-A0B5-5479-B824-E176EDD27C40}.Debug - MemLeak|x64.Build.0 = Debug|x64 {8B867186-A0B5-5479-B824-E176EDD27C40}.Debug - MemLeak|x64.Build.0 = Debug|x64
{8B867186-A0B5-5479-B824-E176EDD27C40}.Debug|x64.ActiveCfg = Debug|x64 {8B867186-A0B5-5479-B824-E176EDD27C40}.Debug|x64.ActiveCfg = Debug|x64
{8B867186-A0B5-5479-B824-E176EDD27C40}.Debug|x64.Build.0 = Debug|x64 {8B867186-A0B5-5479-B824-E176EDD27C40}.Debug|x64.Build.0 = Debug|x64
{8B867186-A0B5-5479-B824-E176EDD27C40}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
{8B867186-A0B5-5479-B824-E176EDD27C40}.DLL Debug|x64.Build.0 = DLL Debug|x64
{8B867186-A0B5-5479-B824-E176EDD27C40}.DLL Release|x64.ActiveCfg = DLL Release|x64
{8B867186-A0B5-5479-B824-E176EDD27C40}.DLL Release|x64.Build.0 = DLL Release|x64
{8B867186-A0B5-5479-B824-E176EDD27C40}.Release - LLVM|x64.ActiveCfg = Release|x64 {8B867186-A0B5-5479-B824-E176EDD27C40}.Release - LLVM|x64.ActiveCfg = Release|x64
{8B867186-A0B5-5479-B824-E176EDD27C40}.Release - LLVM|x64.Build.0 = Release|x64 {8B867186-A0B5-5479-B824-E176EDD27C40}.Release - LLVM|x64.Build.0 = Release|x64
{8B867186-A0B5-5479-B824-E176EDD27C40}.Release|x64.ActiveCfg = Release|x64 {8B867186-A0B5-5479-B824-E176EDD27C40}.Release|x64.ActiveCfg = Release|x64
@ -495,10 +417,6 @@ Global
{3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Debug - MemLeak|x64.Build.0 = Debug|x64 {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Debug - MemLeak|x64.Build.0 = Debug|x64
{3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Debug|x64.ActiveCfg = Debug|x64 {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Debug|x64.ActiveCfg = Debug|x64
{3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Debug|x64.Build.0 = Debug|x64 {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Debug|x64.Build.0 = Debug|x64
{3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
{3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.DLL Debug|x64.Build.0 = DLL Debug|x64
{3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.DLL Release|x64.ActiveCfg = DLL Release|x64
{3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.DLL Release|x64.Build.0 = DLL Release|x64
{3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Release - LLVM|x64.ActiveCfg = Release|x64 {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Release - LLVM|x64.ActiveCfg = Release|x64
{3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Release - LLVM|x64.Build.0 = Release|x64 {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Release - LLVM|x64.Build.0 = Release|x64
{3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Release|x64.ActiveCfg = Release|x64 {3E6DCA27-5FA3-53EC-BBD6-2D42294B7AE6}.Release|x64.ActiveCfg = Release|x64
@ -509,10 +427,6 @@ Global
{09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Debug - MemLeak|x64.Build.0 = Debug|x64 {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Debug - MemLeak|x64.Build.0 = Debug|x64
{09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Debug|x64.ActiveCfg = Debug|x64 {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Debug|x64.ActiveCfg = Debug|x64
{09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Debug|x64.Build.0 = Debug|x64 {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Debug|x64.Build.0 = Debug|x64
{09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
{09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.DLL Debug|x64.Build.0 = DLL Debug|x64
{09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.DLL Release|x64.ActiveCfg = DLL Release|x64
{09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.DLL Release|x64.Build.0 = DLL Release|x64
{09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Release - LLVM|x64.ActiveCfg = Release|x64 {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Release - LLVM|x64.ActiveCfg = Release|x64
{09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Release - LLVM|x64.Build.0 = Release|x64 {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Release - LLVM|x64.Build.0 = Release|x64
{09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Release|x64.ActiveCfg = Release|x64 {09F2F96A-1CC6-5E43-AF1D-956EC2A4888D}.Release|x64.ActiveCfg = Release|x64
@ -523,10 +437,6 @@ Global
{87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Debug - MemLeak|x64.Build.0 = Debug|x64 {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Debug - MemLeak|x64.Build.0 = Debug|x64
{87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Debug|x64.ActiveCfg = Debug|x64 {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Debug|x64.ActiveCfg = Debug|x64
{87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Debug|x64.Build.0 = Debug|x64 {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Debug|x64.Build.0 = Debug|x64
{87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
{87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.DLL Debug|x64.Build.0 = DLL Debug|x64
{87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.DLL Release|x64.ActiveCfg = DLL Release|x64
{87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.DLL Release|x64.Build.0 = DLL Release|x64
{87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Release - LLVM|x64.ActiveCfg = Release|x64 {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Release - LLVM|x64.ActiveCfg = Release|x64
{87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Release - LLVM|x64.Build.0 = Release|x64 {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Release - LLVM|x64.Build.0 = Release|x64
{87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Release|x64.ActiveCfg = Release|x64 {87B42A9C-3F5C-53D7-9017-2B1CAE39457D}.Release|x64.ActiveCfg = Release|x64
@ -537,10 +447,6 @@ Global
{23E1C437-A951-5943-8639-A17F3CF2E606}.Debug - MemLeak|x64.Build.0 = Debug|x64 {23E1C437-A951-5943-8639-A17F3CF2E606}.Debug - MemLeak|x64.Build.0 = Debug|x64
{23E1C437-A951-5943-8639-A17F3CF2E606}.Debug|x64.ActiveCfg = Debug|x64 {23E1C437-A951-5943-8639-A17F3CF2E606}.Debug|x64.ActiveCfg = Debug|x64
{23E1C437-A951-5943-8639-A17F3CF2E606}.Debug|x64.Build.0 = Debug|x64 {23E1C437-A951-5943-8639-A17F3CF2E606}.Debug|x64.Build.0 = Debug|x64
{23E1C437-A951-5943-8639-A17F3CF2E606}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
{23E1C437-A951-5943-8639-A17F3CF2E606}.DLL Debug|x64.Build.0 = DLL Debug|x64
{23E1C437-A951-5943-8639-A17F3CF2E606}.DLL Release|x64.ActiveCfg = DLL Release|x64
{23E1C437-A951-5943-8639-A17F3CF2E606}.DLL Release|x64.Build.0 = DLL Release|x64
{23E1C437-A951-5943-8639-A17F3CF2E606}.Release - LLVM|x64.ActiveCfg = Release|x64 {23E1C437-A951-5943-8639-A17F3CF2E606}.Release - LLVM|x64.ActiveCfg = Release|x64
{23E1C437-A951-5943-8639-A17F3CF2E606}.Release - LLVM|x64.Build.0 = Release|x64 {23E1C437-A951-5943-8639-A17F3CF2E606}.Release - LLVM|x64.Build.0 = Release|x64
{23E1C437-A951-5943-8639-A17F3CF2E606}.Release|x64.ActiveCfg = Release|x64 {23E1C437-A951-5943-8639-A17F3CF2E606}.Release|x64.ActiveCfg = Release|x64
@ -551,10 +457,6 @@ Global
{74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Debug - MemLeak|x64.Build.0 = Debug|x64 {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Debug - MemLeak|x64.Build.0 = Debug|x64
{74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Debug|x64.ActiveCfg = Debug|x64 {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Debug|x64.ActiveCfg = Debug|x64
{74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Debug|x64.Build.0 = Debug|x64 {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Debug|x64.Build.0 = Debug|x64
{74827EBD-93DC-5110-BA95-3F2AB029B6B0}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
{74827EBD-93DC-5110-BA95-3F2AB029B6B0}.DLL Debug|x64.Build.0 = DLL Debug|x64
{74827EBD-93DC-5110-BA95-3F2AB029B6B0}.DLL Release|x64.ActiveCfg = DLL Release|x64
{74827EBD-93DC-5110-BA95-3F2AB029B6B0}.DLL Release|x64.Build.0 = DLL Release|x64
{74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Release - LLVM|x64.ActiveCfg = Release|x64 {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Release - LLVM|x64.ActiveCfg = Release|x64
{74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Release - LLVM|x64.Build.0 = Release|x64 {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Release - LLVM|x64.Build.0 = Release|x64
{74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Release|x64.ActiveCfg = Release|x64 {74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Release|x64.ActiveCfg = Release|x64
@ -565,10 +467,6 @@ Global
{AC40FF01-426E-4838-A317-66354CEFAE88}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64 {AC40FF01-426E-4838-A317-66354CEFAE88}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64
{AC40FF01-426E-4838-A317-66354CEFAE88}.Debug|x64.ActiveCfg = Debug|x64 {AC40FF01-426E-4838-A317-66354CEFAE88}.Debug|x64.ActiveCfg = Debug|x64
{AC40FF01-426E-4838-A317-66354CEFAE88}.Debug|x64.Build.0 = Debug|x64 {AC40FF01-426E-4838-A317-66354CEFAE88}.Debug|x64.Build.0 = Debug|x64
{AC40FF01-426E-4838-A317-66354CEFAE88}.DLL Debug|x64.ActiveCfg = Debug|x64
{AC40FF01-426E-4838-A317-66354CEFAE88}.DLL Debug|x64.Build.0 = Debug|x64
{AC40FF01-426E-4838-A317-66354CEFAE88}.DLL Release|x64.ActiveCfg = Release|x64
{AC40FF01-426E-4838-A317-66354CEFAE88}.DLL Release|x64.Build.0 = Release|x64
{AC40FF01-426E-4838-A317-66354CEFAE88}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64 {AC40FF01-426E-4838-A317-66354CEFAE88}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64
{AC40FF01-426E-4838-A317-66354CEFAE88}.Release - LLVM|x64.Build.0 = Release - LLVM|x64 {AC40FF01-426E-4838-A317-66354CEFAE88}.Release - LLVM|x64.Build.0 = Release - LLVM|x64
{AC40FF01-426E-4838-A317-66354CEFAE88}.Release|x64.ActiveCfg = Release|x64 {AC40FF01-426E-4838-A317-66354CEFAE88}.Release|x64.ActiveCfg = Release|x64
@ -579,24 +477,14 @@ Global
{C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64 {C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64
{C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug|x64.ActiveCfg = Debug|x64 {C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug|x64.ActiveCfg = Debug|x64
{C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug|x64.Build.0 = Debug|x64 {C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug|x64.Build.0 = Debug|x64
{C4A10229-4712-4BD2-B63E-50D93C67A038}.DLL Debug|x64.ActiveCfg = Debug|x64
{C4A10229-4712-4BD2-B63E-50D93C67A038}.DLL Debug|x64.Build.0 = Debug|x64
{C4A10229-4712-4BD2-B63E-50D93C67A038}.DLL Release|x64.ActiveCfg = Release|x64
{C4A10229-4712-4BD2-B63E-50D93C67A038}.DLL Release|x64.Build.0 = Release|x64
{C4A10229-4712-4BD2-B63E-50D93C67A038}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64 {C4A10229-4712-4BD2-B63E-50D93C67A038}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64
{C4A10229-4712-4BD2-B63E-50D93C67A038}.Release - LLVM|x64.Build.0 = Release - LLVM|x64 {C4A10229-4712-4BD2-B63E-50D93C67A038}.Release - LLVM|x64.Build.0 = Release - LLVM|x64
{C4A10229-4712-4BD2-B63E-50D93C67A038}.Release|x64.ActiveCfg = Release|x64 {C4A10229-4712-4BD2-B63E-50D93C67A038}.Release|x64.ActiveCfg = Release|x64
{C4A10229-4712-4BD2-B63E-50D93C67A038}.Release|x64.Build.0 = Release|x64 {C4A10229-4712-4BD2-B63E-50D93C67A038}.Release|x64.Build.0 = Release|x64
{8BC303AB-25BE-4276-8E57-73F171B2D672}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {8BC303AB-25BE-4276-8E57-73F171B2D672}.Debug - LLVM|x64.ActiveCfg = Debug|x64
{8BC303AB-25BE-4276-8E57-73F171B2D672}.Debug - LLVM|x64.Build.0 = Debug|x64
{8BC303AB-25BE-4276-8E57-73F171B2D672}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 {8BC303AB-25BE-4276-8E57-73F171B2D672}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
{8BC303AB-25BE-4276-8E57-73F171B2D672}.Debug|x64.ActiveCfg = Debug|x64 {8BC303AB-25BE-4276-8E57-73F171B2D672}.Debug|x64.ActiveCfg = Debug|x64
{8BC303AB-25BE-4276-8E57-73F171B2D672}.DLL Debug|x64.ActiveCfg = Debug|x64
{8BC303AB-25BE-4276-8E57-73F171B2D672}.DLL Debug|x64.Build.0 = Debug|x64
{8BC303AB-25BE-4276-8E57-73F171B2D672}.DLL Release|x64.ActiveCfg = Release|x64
{8BC303AB-25BE-4276-8E57-73F171B2D672}.DLL Release|x64.Build.0 = Release|x64
{8BC303AB-25BE-4276-8E57-73F171B2D672}.Release - LLVM|x64.ActiveCfg = Release|x64 {8BC303AB-25BE-4276-8E57-73F171B2D672}.Release - LLVM|x64.ActiveCfg = Release|x64
{8BC303AB-25BE-4276-8E57-73F171B2D672}.Release - LLVM|x64.Build.0 = Release|x64
{8BC303AB-25BE-4276-8E57-73F171B2D672}.Release|x64.ActiveCfg = Release|x64 {8BC303AB-25BE-4276-8E57-73F171B2D672}.Release|x64.ActiveCfg = Release|x64
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug - LLVM|x64.ActiveCfg = Debug|x64
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug - LLVM|x64.Build.0 = Debug|x64 {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug - LLVM|x64.Build.0 = Debug|x64
@ -604,10 +492,6 @@ Global
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug - MemLeak|x64.Build.0 = Debug|x64 {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug - MemLeak|x64.Build.0 = Debug|x64
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug|x64.ActiveCfg = Debug|x64 {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug|x64.ActiveCfg = Debug|x64
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug|x64.Build.0 = Debug|x64 {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Debug|x64.Build.0 = Debug|x64
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.DLL Debug|x64.Build.0 = DLL Debug|x64
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.DLL Release|x64.ActiveCfg = DLL Release|x64
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.DLL Release|x64.Build.0 = DLL Release|x64
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release - LLVM|x64.ActiveCfg = Release|x64 {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release - LLVM|x64.ActiveCfg = Release|x64
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release - LLVM|x64.Build.0 = Release|x64 {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release - LLVM|x64.Build.0 = Release|x64
{01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release|x64.ActiveCfg = Release|x64 {01F4CE10-2CFB-41A8-B41F-E54337868A1D}.Release|x64.ActiveCfg = Release|x64
@ -618,10 +502,6 @@ Global
{00D36322-6188-4A66-B514-3B3F183E998D}.Debug - MemLeak|x64.Build.0 = Debug|x64 {00D36322-6188-4A66-B514-3B3F183E998D}.Debug - MemLeak|x64.Build.0 = Debug|x64
{00D36322-6188-4A66-B514-3B3F183E998D}.Debug|x64.ActiveCfg = Debug|x64 {00D36322-6188-4A66-B514-3B3F183E998D}.Debug|x64.ActiveCfg = Debug|x64
{00D36322-6188-4A66-B514-3B3F183E998D}.Debug|x64.Build.0 = Debug|x64 {00D36322-6188-4A66-B514-3B3F183E998D}.Debug|x64.Build.0 = Debug|x64
{00D36322-6188-4A66-B514-3B3F183E998D}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
{00D36322-6188-4A66-B514-3B3F183E998D}.DLL Debug|x64.Build.0 = DLL Debug|x64
{00D36322-6188-4A66-B514-3B3F183E998D}.DLL Release|x64.ActiveCfg = DLL Release|x64
{00D36322-6188-4A66-B514-3B3F183E998D}.DLL Release|x64.Build.0 = DLL Release|x64
{00D36322-6188-4A66-B514-3B3F183E998D}.Release - LLVM|x64.ActiveCfg = Release|x64 {00D36322-6188-4A66-B514-3B3F183E998D}.Release - LLVM|x64.ActiveCfg = Release|x64
{00D36322-6188-4A66-B514-3B3F183E998D}.Release - LLVM|x64.Build.0 = Release|x64 {00D36322-6188-4A66-B514-3B3F183E998D}.Release - LLVM|x64.Build.0 = Release|x64
{00D36322-6188-4A66-B514-3B3F183E998D}.Release|x64.ActiveCfg = Release|x64 {00D36322-6188-4A66-B514-3B3F183E998D}.Release|x64.ActiveCfg = Release|x64
@ -632,24 +512,14 @@ Global
{FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64 {FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64
{FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.Debug|x64.ActiveCfg = Debug|x64 {FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.Debug|x64.ActiveCfg = Debug|x64
{FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.Debug|x64.Build.0 = Debug|x64 {FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.Debug|x64.Build.0 = Debug|x64
{FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.DLL Debug|x64.ActiveCfg = Debug|x64
{FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.DLL Debug|x64.Build.0 = Debug|x64
{FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.DLL Release|x64.ActiveCfg = Release|x64
{FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.DLL Release|x64.Build.0 = Release|x64
{FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64 {FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64
{FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.Release - LLVM|x64.Build.0 = Release - LLVM|x64 {FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.Release - LLVM|x64.Build.0 = Release - LLVM|x64
{FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.Release|x64.ActiveCfg = Release|x64 {FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.Release|x64.ActiveCfg = Release|x64
{FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.Release|x64.Build.0 = Release|x64 {FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078}.Release|x64.Build.0 = Release|x64
{AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Debug - LLVM|x64.ActiveCfg = Debug|x64
{AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Debug - LLVM|x64.Build.0 = Debug|x64
{AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 {AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
{AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Debug|x64.ActiveCfg = Debug|x64 {AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Debug|x64.ActiveCfg = Debug|x64
{AB222E8A-00CA-4ACF-A87E-5251C16C0587}.DLL Debug|x64.ActiveCfg = Debug|x64
{AB222E8A-00CA-4ACF-A87E-5251C16C0587}.DLL Debug|x64.Build.0 = Debug|x64
{AB222E8A-00CA-4ACF-A87E-5251C16C0587}.DLL Release|x64.ActiveCfg = Release|x64
{AB222E8A-00CA-4ACF-A87E-5251C16C0587}.DLL Release|x64.Build.0 = Release|x64
{AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Release - LLVM|x64.ActiveCfg = Release|x64 {AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Release - LLVM|x64.ActiveCfg = Release|x64
{AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Release - LLVM|x64.Build.0 = Release|x64
{AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Release|x64.ActiveCfg = Release|x64 {AB222E8A-00CA-4ACF-A87E-5251C16C0587}.Release|x64.ActiveCfg = Release|x64
{3384223A-6D97-4799-9862-359F85312892}.Debug - LLVM|x64.ActiveCfg = Debug - LLVM|x64 {3384223A-6D97-4799-9862-359F85312892}.Debug - LLVM|x64.ActiveCfg = Debug - LLVM|x64
{3384223A-6D97-4799-9862-359F85312892}.Debug - LLVM|x64.Build.0 = Debug - LLVM|x64 {3384223A-6D97-4799-9862-359F85312892}.Debug - LLVM|x64.Build.0 = Debug - LLVM|x64
@ -657,10 +527,6 @@ Global
{3384223A-6D97-4799-9862-359F85312892}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64 {3384223A-6D97-4799-9862-359F85312892}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64
{3384223A-6D97-4799-9862-359F85312892}.Debug|x64.ActiveCfg = Debug|x64 {3384223A-6D97-4799-9862-359F85312892}.Debug|x64.ActiveCfg = Debug|x64
{3384223A-6D97-4799-9862-359F85312892}.Debug|x64.Build.0 = Debug|x64 {3384223A-6D97-4799-9862-359F85312892}.Debug|x64.Build.0 = Debug|x64
{3384223A-6D97-4799-9862-359F85312892}.DLL Debug|x64.ActiveCfg = Debug|x64
{3384223A-6D97-4799-9862-359F85312892}.DLL Debug|x64.Build.0 = Debug|x64
{3384223A-6D97-4799-9862-359F85312892}.DLL Release|x64.ActiveCfg = Release|x64
{3384223A-6D97-4799-9862-359F85312892}.DLL Release|x64.Build.0 = Release|x64
{3384223A-6D97-4799-9862-359F85312892}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64 {3384223A-6D97-4799-9862-359F85312892}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64
{3384223A-6D97-4799-9862-359F85312892}.Release - LLVM|x64.Build.0 = Release - LLVM|x64 {3384223A-6D97-4799-9862-359F85312892}.Release - LLVM|x64.Build.0 = Release - LLVM|x64
{3384223A-6D97-4799-9862-359F85312892}.Release|x64.ActiveCfg = Release|x64 {3384223A-6D97-4799-9862-359F85312892}.Release|x64.ActiveCfg = Release|x64
@ -671,10 +537,6 @@ Global
{97E17077-A21F-45EF-9C3A-73A0BC092D7E}.Debug - MemLeak|x64.Build.0 = Debug|x64 {97E17077-A21F-45EF-9C3A-73A0BC092D7E}.Debug - MemLeak|x64.Build.0 = Debug|x64
{97E17077-A21F-45EF-9C3A-73A0BC092D7E}.Debug|x64.ActiveCfg = Debug|x64 {97E17077-A21F-45EF-9C3A-73A0BC092D7E}.Debug|x64.ActiveCfg = Debug|x64
{97E17077-A21F-45EF-9C3A-73A0BC092D7E}.Debug|x64.Build.0 = Debug|x64 {97E17077-A21F-45EF-9C3A-73A0BC092D7E}.Debug|x64.Build.0 = Debug|x64
{97E17077-A21F-45EF-9C3A-73A0BC092D7E}.DLL Debug|x64.ActiveCfg = Debug|x64
{97E17077-A21F-45EF-9C3A-73A0BC092D7E}.DLL Debug|x64.Build.0 = Debug|x64
{97E17077-A21F-45EF-9C3A-73A0BC092D7E}.DLL Release|x64.ActiveCfg = Release|x64
{97E17077-A21F-45EF-9C3A-73A0BC092D7E}.DLL Release|x64.Build.0 = Release|x64
{97E17077-A21F-45EF-9C3A-73A0BC092D7E}.Release - LLVM|x64.ActiveCfg = Release|x64 {97E17077-A21F-45EF-9C3A-73A0BC092D7E}.Release - LLVM|x64.ActiveCfg = Release|x64
{97E17077-A21F-45EF-9C3A-73A0BC092D7E}.Release - LLVM|x64.Build.0 = Release|x64 {97E17077-A21F-45EF-9C3A-73A0BC092D7E}.Release - LLVM|x64.Build.0 = Release|x64
{97E17077-A21F-45EF-9C3A-73A0BC092D7E}.Release|x64.ActiveCfg = Release|x64 {97E17077-A21F-45EF-9C3A-73A0BC092D7E}.Release|x64.ActiveCfg = Release|x64
@ -685,10 +547,6 @@ Global
{7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.Debug - MemLeak|x64.Build.0 = Debug|x64 {7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.Debug - MemLeak|x64.Build.0 = Debug|x64
{7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.Debug|x64.ActiveCfg = Debug|x64 {7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.Debug|x64.ActiveCfg = Debug|x64
{7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.Debug|x64.Build.0 = Debug|x64 {7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.Debug|x64.Build.0 = Debug|x64
{7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.DLL Debug|x64.ActiveCfg = Debug|x64
{7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.DLL Debug|x64.Build.0 = Debug|x64
{7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.DLL Release|x64.ActiveCfg = Release|x64
{7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.DLL Release|x64.Build.0 = Release|x64
{7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.Release - LLVM|x64.ActiveCfg = Release|x64 {7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.Release - LLVM|x64.ActiveCfg = Release|x64
{7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.Release - LLVM|x64.Build.0 = Release|x64 {7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.Release - LLVM|x64.Build.0 = Release|x64
{7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.Release|x64.ActiveCfg = Release|x64 {7D73447B-3D2D-4DFE-BF62-57E644C1D09F}.Release|x64.ActiveCfg = Release|x64
@ -699,10 +557,6 @@ Global
{78CB2F39-B809-4A06-8329-8C0A19119D3D}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64 {78CB2F39-B809-4A06-8329-8C0A19119D3D}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64
{78CB2F39-B809-4A06-8329-8C0A19119D3D}.Debug|x64.ActiveCfg = Debug|x64 {78CB2F39-B809-4A06-8329-8C0A19119D3D}.Debug|x64.ActiveCfg = Debug|x64
{78CB2F39-B809-4A06-8329-8C0A19119D3D}.Debug|x64.Build.0 = Debug|x64 {78CB2F39-B809-4A06-8329-8C0A19119D3D}.Debug|x64.Build.0 = Debug|x64
{78CB2F39-B809-4A06-8329-8C0A19119D3D}.DLL Debug|x64.ActiveCfg = Debug|x64
{78CB2F39-B809-4A06-8329-8C0A19119D3D}.DLL Debug|x64.Build.0 = Debug|x64
{78CB2F39-B809-4A06-8329-8C0A19119D3D}.DLL Release|x64.ActiveCfg = Release|x64
{78CB2F39-B809-4A06-8329-8C0A19119D3D}.DLL Release|x64.Build.0 = Release|x64
{78CB2F39-B809-4A06-8329-8C0A19119D3D}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64 {78CB2F39-B809-4A06-8329-8C0A19119D3D}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64
{78CB2F39-B809-4A06-8329-8C0A19119D3D}.Release - LLVM|x64.Build.0 = Release - LLVM|x64 {78CB2F39-B809-4A06-8329-8C0A19119D3D}.Release - LLVM|x64.Build.0 = Release - LLVM|x64
{78CB2F39-B809-4A06-8329-8C0A19119D3D}.Release|x64.ActiveCfg = Release|x64 {78CB2F39-B809-4A06-8329-8C0A19119D3D}.Release|x64.ActiveCfg = Release|x64
@ -713,10 +567,6 @@ Global
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64 {30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Debug|x64.ActiveCfg = Debug|x64 {30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Debug|x64.ActiveCfg = Debug|x64
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Debug|x64.Build.0 = Debug|x64 {30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Debug|x64.Build.0 = Debug|x64
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.DLL Debug|x64.ActiveCfg = Debug|x64
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.DLL Debug|x64.Build.0 = Debug|x64
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.DLL Release|x64.ActiveCfg = Release|x64
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.DLL Release|x64.Build.0 = Release|x64
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64 {30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Release - LLVM|x64.Build.0 = Release - LLVM|x64 {30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Release - LLVM|x64.Build.0 = Release - LLVM|x64
{30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Release|x64.ActiveCfg = Release|x64 {30A05C4D-F5FD-421C-A864-17A64BDEAA75}.Release|x64.ActiveCfg = Release|x64
@ -727,10 +577,6 @@ Global
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug - MemLeak|x64.Build.0 = Debug Library|x64 {D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug - MemLeak|x64.Build.0 = Debug Library|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|x64.ActiveCfg = Debug Library|x64 {D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|x64.ActiveCfg = Debug Library|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|x64.Build.0 = Debug Library|x64 {D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Debug|x64.Build.0 = Debug Library|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.DLL Debug|x64.ActiveCfg = Debug|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.DLL Debug|x64.Build.0 = Debug|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.DLL Release|x64.ActiveCfg = Release|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.DLL Release|x64.Build.0 = Release|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release - LLVM|x64.ActiveCfg = Release Library|x64 {D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release - LLVM|x64.ActiveCfg = Release Library|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release - LLVM|x64.Build.0 = Release Library|x64 {D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release - LLVM|x64.Build.0 = Release Library|x64
{D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release|x64.ActiveCfg = Release Library|x64 {D6973076-9317-4EF2-A0B8-B7A18AC0713E}.Release|x64.ActiveCfg = Release Library|x64
@ -741,84 +587,50 @@ Global
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug - MemLeak|x64.Build.0 = Debug Library|x64 {60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug - MemLeak|x64.Build.0 = Debug Library|x64
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug|x64.ActiveCfg = Debug Library|x64 {60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug|x64.ActiveCfg = Debug Library|x64
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug|x64.Build.0 = Debug Library|x64 {60F89955-91C6-3A36-8000-13C592FEC2DF}.Debug|x64.Build.0 = Debug Library|x64
{60F89955-91C6-3A36-8000-13C592FEC2DF}.DLL Debug|x64.ActiveCfg = Debug Library|x64
{60F89955-91C6-3A36-8000-13C592FEC2DF}.DLL Debug|x64.Build.0 = Debug Library|x64
{60F89955-91C6-3A36-8000-13C592FEC2DF}.DLL Release|x64.ActiveCfg = Release Library|x64
{60F89955-91C6-3A36-8000-13C592FEC2DF}.DLL Release|x64.Build.0 = Release Library|x64
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Release - LLVM|x64.ActiveCfg = Release Library|x64 {60F89955-91C6-3A36-8000-13C592FEC2DF}.Release - LLVM|x64.ActiveCfg = Release Library|x64
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Release - LLVM|x64.Build.0 = Release Library|x64 {60F89955-91C6-3A36-8000-13C592FEC2DF}.Release - LLVM|x64.Build.0 = Release Library|x64
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Release|x64.ActiveCfg = Release Library|x64 {60F89955-91C6-3A36-8000-13C592FEC2DF}.Release|x64.ActiveCfg = Release Library|x64
{60F89955-91C6-3A36-8000-13C592FEC2DF}.Release|x64.Build.0 = Release Library|x64 {60F89955-91C6-3A36-8000-13C592FEC2DF}.Release|x64.Build.0 = Release Library|x64
{58B40697-B15E-429E-B325-D52C28AEBCBF}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {58B40697-B15E-429E-B325-D52C28AEBCBF}.Debug - LLVM|x64.ActiveCfg = Debug|x64
{58B40697-B15E-429E-B325-D52C28AEBCBF}.Debug - LLVM|x64.Build.0 = Debug|x64
{58B40697-B15E-429E-B325-D52C28AEBCBF}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 {58B40697-B15E-429E-B325-D52C28AEBCBF}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
{58B40697-B15E-429E-B325-D52C28AEBCBF}.Debug - MemLeak|x64.Build.0 = Debug|x64
{58B40697-B15E-429E-B325-D52C28AEBCBF}.Debug|x64.ActiveCfg = Debug|x64 {58B40697-B15E-429E-B325-D52C28AEBCBF}.Debug|x64.ActiveCfg = Debug|x64
{58B40697-B15E-429E-B325-D52C28AEBCBF}.Debug|x64.Build.0 = Debug|x64
{58B40697-B15E-429E-B325-D52C28AEBCBF}.DLL Debug|x64.ActiveCfg = Debug|x64
{58B40697-B15E-429E-B325-D52C28AEBCBF}.DLL Debug|x64.Build.0 = Debug|x64
{58B40697-B15E-429E-B325-D52C28AEBCBF}.DLL Release|x64.ActiveCfg = Release|x64
{58B40697-B15E-429E-B325-D52C28AEBCBF}.DLL Release|x64.Build.0 = Release|x64
{58B40697-B15E-429E-B325-D52C28AEBCBF}.Release - LLVM|x64.ActiveCfg = Release|x64 {58B40697-B15E-429E-B325-D52C28AEBCBF}.Release - LLVM|x64.ActiveCfg = Release|x64
{58B40697-B15E-429E-B325-D52C28AEBCBF}.Release - LLVM|x64.Build.0 = Release|x64
{58B40697-B15E-429E-B325-D52C28AEBCBF}.Release|x64.ActiveCfg = Release|x64 {58B40697-B15E-429E-B325-D52C28AEBCBF}.Release|x64.ActiveCfg = Release|x64
{58B40697-B15E-429E-B325-D52C28AEBCBF}.Release|x64.Build.0 = Release|x64
{8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Debug - LLVM|x64.ActiveCfg = Debug|x64
{8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Debug - LLVM|x64.Build.0 = Debug|x64
{8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
{8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Debug - MemLeak|x64.Build.0 = Debug|x64
{8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Debug|x64.ActiveCfg = Debug|x64 {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Debug|x64.ActiveCfg = Debug|x64
{8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Debug|x64.Build.0 = Debug|x64
{8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.DLL Debug|x64.ActiveCfg = Debug|x64
{8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.DLL Debug|x64.Build.0 = Debug|x64
{8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.DLL Release|x64.ActiveCfg = Release|x64
{8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.DLL Release|x64.Build.0 = Release|x64
{8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Release - LLVM|x64.ActiveCfg = Release|x64 {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Release - LLVM|x64.ActiveCfg = Release|x64
{8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Release - LLVM|x64.Build.0 = Release|x64
{8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Release|x64.ActiveCfg = Release|x64 {8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Release|x64.ActiveCfg = Release|x64
{8F85B6CC-250F-4ACA-A617-E820A74E3E3C}.Release|x64.Build.0 = Release|x64 {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug - LLVM|x64.ActiveCfg = Debug - LLVM|x64
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug - LLVM|x64.Build.0 = Debug - LLVM|x64
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug - LLVM|x64.Build.0 = Debug|x64 {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug - MemLeak|x64.ActiveCfg = Debug - MemLeak|x64
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug - MemLeak|x64.Build.0 = Debug|x64
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug|x64.ActiveCfg = Debug|x64 {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug|x64.ActiveCfg = Debug|x64
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug|x64.Build.0 = Debug|x64 {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Debug|x64.Build.0 = Debug|x64
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.DLL Debug|x64.ActiveCfg = Debug|x64 {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.DLL Debug|x64.Build.0 = Debug|x64 {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Release - LLVM|x64.Build.0 = Release - LLVM|x64
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.DLL Release|x64.ActiveCfg = Release|x64
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.DLL Release|x64.Build.0 = Release|x64
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Release - LLVM|x64.ActiveCfg = Release|x64
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Release - LLVM|x64.Build.0 = Release|x64
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Release|x64.ActiveCfg = Release|x64 {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Release|x64.ActiveCfg = Release|x64
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Release|x64.Build.0 = Release|x64 {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}.Release|x64.Build.0 = Release|x64
{304A6E8B-A311-4EC5-8045-BFA8D08175CE}.Debug - LLVM|x64.ActiveCfg = Debug - LLVM|x64
{304A6E8B-A311-4EC5-8045-BFA8D08175CE}.Debug - LLVM|x64.Build.0 = Debug - LLVM|x64
{304A6E8B-A311-4EC5-8045-BFA8D08175CE}.Debug - MemLeak|x64.ActiveCfg = Debug - MemLeak|x64
{304A6E8B-A311-4EC5-8045-BFA8D08175CE}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64
{304A6E8B-A311-4EC5-8045-BFA8D08175CE}.Debug|x64.ActiveCfg = Debug|x64
{304A6E8B-A311-4EC5-8045-BFA8D08175CE}.Debug|x64.Build.0 = Debug|x64
{304A6E8B-A311-4EC5-8045-BFA8D08175CE}.DLL Debug|x64.ActiveCfg = Debug|x64
{304A6E8B-A311-4EC5-8045-BFA8D08175CE}.DLL Debug|x64.Build.0 = Debug|x64
{304A6E8B-A311-4EC5-8045-BFA8D08175CE}.DLL Release|x64.ActiveCfg = Release|x64
{304A6E8B-A311-4EC5-8045-BFA8D08175CE}.DLL Release|x64.Build.0 = Release|x64
{304A6E8B-A311-4EC5-8045-BFA8D08175CE}.Release - LLVM|x64.ActiveCfg = Release - LLVM|x64
{304A6E8B-A311-4EC5-8045-BFA8D08175CE}.Release - LLVM|x64.Build.0 = Release - LLVM|x64
{304A6E8B-A311-4EC5-8045-BFA8D08175CE}.Release|x64.ActiveCfg = Release|x64
{304A6E8B-A311-4EC5-8045-BFA8D08175CE}.Release|x64.Build.0 = Release|x64
{A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Debug - LLVM|x64.ActiveCfg = Debug|x64 {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Debug - LLVM|x64.ActiveCfg = Debug|x64
{A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Debug - LLVM|x64.Build.0 = Debug|x64 {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Debug - LLVM|x64.Build.0 = Debug|x64
{A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Debug - MemLeak|x64.ActiveCfg = Debug|x64 {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
{A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Debug - MemLeak|x64.Build.0 = Debug|x64 {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Debug - MemLeak|x64.Build.0 = Debug|x64
{A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Debug|x64.ActiveCfg = Debug|x64 {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Debug|x64.ActiveCfg = Debug|x64
{A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Debug|x64.Build.0 = Debug|x64 {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Debug|x64.Build.0 = Debug|x64
{A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.DLL Debug|x64.ActiveCfg = DLL Debug|x64
{A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.DLL Debug|x64.Build.0 = DLL Debug|x64
{A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.DLL Release|x64.ActiveCfg = DLL Release|x64
{A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.DLL Release|x64.Build.0 = DLL Release|x64
{A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Release - LLVM|x64.ActiveCfg = Release|x64 {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Release - LLVM|x64.ActiveCfg = Release|x64
{A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Release - LLVM|x64.Build.0 = Release|x64 {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Release - LLVM|x64.Build.0 = Release|x64
{A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Release|x64.ActiveCfg = Release|x64 {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Release|x64.ActiveCfg = Release|x64
{A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Release|x64.Build.0 = Release|x64 {A8E8442A-078A-5FC5-B495-8D71BA77EE6E}.Release|x64.Build.0 = Release|x64
{FDC361C5-7734-493B-8CFB-037308B35122}.Debug - LLVM|x64.ActiveCfg = Debug|x64
{FDC361C5-7734-493B-8CFB-037308B35122}.Debug - LLVM|x64.Build.0 = Debug|x64
{FDC361C5-7734-493B-8CFB-037308B35122}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
{FDC361C5-7734-493B-8CFB-037308B35122}.Debug - MemLeak|x64.Build.0 = Debug|x64
{FDC361C5-7734-493B-8CFB-037308B35122}.Debug|x64.ActiveCfg = Debug|x64
{FDC361C5-7734-493B-8CFB-037308B35122}.Debug|x64.Build.0 = Debug|x64
{FDC361C5-7734-493B-8CFB-037308B35122}.Release - LLVM|x64.ActiveCfg = Release|x64
{FDC361C5-7734-493B-8CFB-037308B35122}.Release - LLVM|x64.Build.0 = Release|x64
{FDC361C5-7734-493B-8CFB-037308B35122}.Release|x64.ActiveCfg = Release|x64
{FDC361C5-7734-493B-8CFB-037308B35122}.Release|x64.Build.0 = Release|x64
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -848,8 +660,7 @@ Global
{74827EBD-93DC-5110-BA95-3F2AB029B6B0} = {5812E712-6213-4372-B095-9EB9BAA1F2DF} {74827EBD-93DC-5110-BA95-3F2AB029B6B0} = {5812E712-6213-4372-B095-9EB9BAA1F2DF}
{AC40FF01-426E-4838-A317-66354CEFAE88} = {E2A982F2-4B1A-48B1-8D77-A17A589C58D7} {AC40FF01-426E-4838-A317-66354CEFAE88} = {E2A982F2-4B1A-48B1-8D77-A17A589C58D7}
{C4A10229-4712-4BD2-B63E-50D93C67A038} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2} {C4A10229-4712-4BD2-B63E-50D93C67A038} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2}
{C8068CE9-D626-4FEA-BEE7-893F06A25BF3} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2} {8BC303AB-25BE-4276-8E57-73F171B2D672} = {B0AC29FD-7B01-4B5E-9C8D-0A081E4C5668}
{8BC303AB-25BE-4276-8E57-73F171B2D672} = {C8068CE9-D626-4FEA-BEE7-893F06A25BF3}
{01F4CE10-2CFB-41A8-B41F-E54337868A1D} = {5812E712-6213-4372-B095-9EB9BAA1F2DF} {01F4CE10-2CFB-41A8-B41F-E54337868A1D} = {5812E712-6213-4372-B095-9EB9BAA1F2DF}
{00D36322-6188-4A66-B514-3B3F183E998D} = {5812E712-6213-4372-B095-9EB9BAA1F2DF} {00D36322-6188-4A66-B514-3B3F183E998D} = {5812E712-6213-4372-B095-9EB9BAA1F2DF}
{FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2} {FAC9B17B-F4B8-4B75-8AEB-C8C7CB92B078} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2}
@ -859,10 +670,10 @@ Global
{30A05C4D-F5FD-421C-A864-17A64BDEAA75} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2} {30A05C4D-F5FD-421C-A864-17A64BDEAA75} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2}
{D6973076-9317-4EF2-A0B8-B7A18AC0713E} = {A17D34F1-7E3E-4841-818D-3B7C6F5AF829} {D6973076-9317-4EF2-A0B8-B7A18AC0713E} = {A17D34F1-7E3E-4841-818D-3B7C6F5AF829}
{60F89955-91C6-3A36-8000-13C592FEC2DF} = {F0C19EFA-EDD0-43F2-97C1-18E865E96B4E} {60F89955-91C6-3A36-8000-13C592FEC2DF} = {F0C19EFA-EDD0-43F2-97C1-18E865E96B4E}
{58B40697-B15E-429E-B325-D52C28AEBCBF} = {09AD61F7-97FE-4FF8-8F7F-63FEA9B746F4} {58B40697-B15E-429E-B325-D52C28AEBCBF} = {B0AC29FD-7B01-4B5E-9C8D-0A081E4C5668}
{8F85B6CC-250F-4ACA-A617-E820A74E3E3C} = {09AD61F7-97FE-4FF8-8F7F-63FEA9B746F4} {8F85B6CC-250F-4ACA-A617-E820A74E3E3C} = {B0AC29FD-7B01-4B5E-9C8D-0A081E4C5668}
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2} {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2}
{304A6E8B-A311-4EC5-8045-BFA8D08175CE} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2}
{A8E8442A-078A-5FC5-B495-8D71BA77EE6E} = {5812E712-6213-4372-B095-9EB9BAA1F2DF} {A8E8442A-078A-5FC5-B495-8D71BA77EE6E} = {5812E712-6213-4372-B095-9EB9BAA1F2DF}
{FDC361C5-7734-493B-8CFB-037308B35122} = {DDF904CA-2771-441A-8629-5DF2EB922A79}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

View file

@ -0,0 +1,170 @@
#include "stdafx.h"
#include "stdafx_gui.h"
#include "rpcs3.h"
#include "BasicKeyboardHandler.h"
void BasicKeyboardHandler::Init(const u32 max_connect)
{
for (u32 i = 0; i<max_connect; i++)
{
m_keyboards.emplace_back(Keyboard());
}
LoadSettings();
memset(&m_info, 0, sizeof(KbInfo));
m_info.max_connect = max_connect;
m_info.now_connect = std::min<size_t>(m_keyboards.size(), max_connect);
m_info.info = 0; // Ownership of keyboard data: 0=Application, 1=System
m_info.status[0] = CELL_KB_STATUS_CONNECTED; // (TODO: Support for more keyboards)
}
BasicKeyboardHandler::BasicKeyboardHandler()
{
wxGetApp().Bind(wxEVT_KEY_DOWN, &BasicKeyboardHandler::KeyDown, this);
wxGetApp().Bind(wxEVT_KEY_UP, &BasicKeyboardHandler::KeyUp, this);
}
void BasicKeyboardHandler::KeyDown(wxKeyEvent& event)
{
Key(event.GetKeyCode(), 1);
event.Skip();
}
void BasicKeyboardHandler::KeyUp(wxKeyEvent& event)
{
Key(event.GetKeyCode(), 0);
event.Skip();
}
void BasicKeyboardHandler::LoadSettings()
{
// Meta Keys
m_keyboards[0].m_buttons.emplace_back(WXK_CONTROL, CELL_KB_MKEY_L_CTRL);
m_keyboards[0].m_buttons.emplace_back(WXK_SHIFT, CELL_KB_MKEY_L_SHIFT);
m_keyboards[0].m_buttons.emplace_back(WXK_ALT, CELL_KB_MKEY_L_ALT);
m_keyboards[0].m_buttons.emplace_back(WXK_WINDOWS_LEFT, CELL_KB_MKEY_L_WIN);
m_keyboards[0].m_buttons.emplace_back(WXK_COMMAND, CELL_KB_MKEY_L_WIN);
//m_keyboards[0].m_buttons.emplace_back(, CELL_KB_MKEY_R_CTRL);
//m_keyboards[0].m_buttons.emplace_back(, CELL_KB_MKEY_R_SHIFT);
//m_keyboards[0].m_buttons.emplace_back(, CELL_KB_MKEY_R_ALT);
m_keyboards[0].m_buttons.emplace_back(WXK_WINDOWS_RIGHT, CELL_KB_MKEY_R_WIN);
// CELL_KB_RAWDAT
//m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_NO_EVENT);
//m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_E_ROLLOVER);
//m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_E_POSTFAIL);
//m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_E_UNDEF);
m_keyboards[0].m_buttons.emplace_back(WXK_ESCAPE, CELL_KEYC_ESCAPE);
//m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_106_KANJI);
m_keyboards[0].m_buttons.emplace_back(WXK_CAPITAL, CELL_KEYC_CAPS_LOCK);
m_keyboards[0].m_buttons.emplace_back(WXK_F1, CELL_KEYC_F1);
m_keyboards[0].m_buttons.emplace_back(WXK_F2, CELL_KEYC_F2);
m_keyboards[0].m_buttons.emplace_back(WXK_F3, CELL_KEYC_F3);
m_keyboards[0].m_buttons.emplace_back(WXK_F4, CELL_KEYC_F4);
m_keyboards[0].m_buttons.emplace_back(WXK_F5, CELL_KEYC_F5);
m_keyboards[0].m_buttons.emplace_back(WXK_F6, CELL_KEYC_F6);
m_keyboards[0].m_buttons.emplace_back(WXK_F7, CELL_KEYC_F7);
m_keyboards[0].m_buttons.emplace_back(WXK_F8, CELL_KEYC_F8);
m_keyboards[0].m_buttons.emplace_back(WXK_F9, CELL_KEYC_F9);
m_keyboards[0].m_buttons.emplace_back(WXK_F10, CELL_KEYC_F10);
m_keyboards[0].m_buttons.emplace_back(WXK_F11, CELL_KEYC_F11);
m_keyboards[0].m_buttons.emplace_back(WXK_F12, CELL_KEYC_F12);
m_keyboards[0].m_buttons.emplace_back(WXK_PRINT, CELL_KEYC_PRINTSCREEN);
m_keyboards[0].m_buttons.emplace_back(WXK_SCROLL, CELL_KEYC_SCROLL_LOCK);
m_keyboards[0].m_buttons.emplace_back(WXK_PAUSE, CELL_KEYC_PAUSE);
m_keyboards[0].m_buttons.emplace_back(WXK_INSERT, CELL_KEYC_INSERT);
//m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_HOME);
m_keyboards[0].m_buttons.emplace_back(WXK_PAGEUP, CELL_KEYC_PAGE_UP);
m_keyboards[0].m_buttons.emplace_back(WXK_DELETE, CELL_KEYC_DELETE);
m_keyboards[0].m_buttons.emplace_back(WXK_END, CELL_KEYC_END);
m_keyboards[0].m_buttons.emplace_back(WXK_PAGEDOWN, CELL_KEYC_PAGE_DOWN);
m_keyboards[0].m_buttons.emplace_back(WXK_RIGHT, CELL_KEYC_RIGHT_ARROW);
m_keyboards[0].m_buttons.emplace_back(WXK_LEFT, CELL_KEYC_LEFT_ARROW);
m_keyboards[0].m_buttons.emplace_back(WXK_DOWN, CELL_KEYC_DOWN_ARROW);
m_keyboards[0].m_buttons.emplace_back(WXK_UP, CELL_KEYC_UP_ARROW);
//m_keyboards[0].m_buttons.emplace_back(WXK_NUMLOCK, CELL_KEYC_NUM_LOCK);
//m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_APPLICATION);
//m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_KANA);
//m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_HENKAN);
//m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_MUHENKAN);
// CELL_KB_KEYPAD
m_keyboards[0].m_buttons.emplace_back(WXK_NUMLOCK, CELL_KEYC_KPAD_NUMLOCK);
m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD_DIVIDE, CELL_KEYC_KPAD_SLASH);
m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD_MULTIPLY, CELL_KEYC_KPAD_ASTERISK);
m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD_SUBTRACT, CELL_KEYC_KPAD_MINUS);
m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD_ADD, CELL_KEYC_KPAD_PLUS);
m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD_ENTER, CELL_KEYC_KPAD_ENTER);
m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD1, CELL_KEYC_KPAD_1);
m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD2, CELL_KEYC_KPAD_2);
m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD3, CELL_KEYC_KPAD_3);
m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD4, CELL_KEYC_KPAD_4);
m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD5, CELL_KEYC_KPAD_5);
m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD6, CELL_KEYC_KPAD_6);
m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD7, CELL_KEYC_KPAD_7);
m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD8, CELL_KEYC_KPAD_8);
m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD9, CELL_KEYC_KPAD_9);
m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD0, CELL_KEYC_KPAD_0);
m_keyboards[0].m_buttons.emplace_back(WXK_NUMPAD_DELETE, CELL_KEYC_KPAD_PERIOD);
// ASCII Printable characters
m_keyboards[0].m_buttons.emplace_back('A', CELL_KEYC_A);
m_keyboards[0].m_buttons.emplace_back('B', CELL_KEYC_B);
m_keyboards[0].m_buttons.emplace_back('C', CELL_KEYC_C);
m_keyboards[0].m_buttons.emplace_back('D', CELL_KEYC_D);
m_keyboards[0].m_buttons.emplace_back('E', CELL_KEYC_E);
m_keyboards[0].m_buttons.emplace_back('F', CELL_KEYC_F);
m_keyboards[0].m_buttons.emplace_back('G', CELL_KEYC_G);
m_keyboards[0].m_buttons.emplace_back('H', CELL_KEYC_H);
m_keyboards[0].m_buttons.emplace_back('I', CELL_KEYC_I);
m_keyboards[0].m_buttons.emplace_back('J', CELL_KEYC_J);
m_keyboards[0].m_buttons.emplace_back('K', CELL_KEYC_K);
m_keyboards[0].m_buttons.emplace_back('L', CELL_KEYC_L);
m_keyboards[0].m_buttons.emplace_back('M', CELL_KEYC_M);
m_keyboards[0].m_buttons.emplace_back('N', CELL_KEYC_N);
m_keyboards[0].m_buttons.emplace_back('O', CELL_KEYC_O);
m_keyboards[0].m_buttons.emplace_back('P', CELL_KEYC_P);
m_keyboards[0].m_buttons.emplace_back('Q', CELL_KEYC_Q);
m_keyboards[0].m_buttons.emplace_back('R', CELL_KEYC_R);
m_keyboards[0].m_buttons.emplace_back('S', CELL_KEYC_S);
m_keyboards[0].m_buttons.emplace_back('T', CELL_KEYC_T);
m_keyboards[0].m_buttons.emplace_back('U', CELL_KEYC_U);
m_keyboards[0].m_buttons.emplace_back('V', CELL_KEYC_V);
m_keyboards[0].m_buttons.emplace_back('W', CELL_KEYC_W);
m_keyboards[0].m_buttons.emplace_back('X', CELL_KEYC_X);
m_keyboards[0].m_buttons.emplace_back('Y', CELL_KEYC_Y);
m_keyboards[0].m_buttons.emplace_back('Z', CELL_KEYC_Z);
m_keyboards[0].m_buttons.emplace_back('1', CELL_KEYC_1);
m_keyboards[0].m_buttons.emplace_back('2', CELL_KEYC_2);
m_keyboards[0].m_buttons.emplace_back('3', CELL_KEYC_3);
m_keyboards[0].m_buttons.emplace_back('4', CELL_KEYC_4);
m_keyboards[0].m_buttons.emplace_back('5', CELL_KEYC_5);
m_keyboards[0].m_buttons.emplace_back('6', CELL_KEYC_6);
m_keyboards[0].m_buttons.emplace_back('7', CELL_KEYC_7);
m_keyboards[0].m_buttons.emplace_back('8', CELL_KEYC_8);
m_keyboards[0].m_buttons.emplace_back('9', CELL_KEYC_9);
m_keyboards[0].m_buttons.emplace_back('0', CELL_KEYC_0);
m_keyboards[0].m_buttons.emplace_back(WXK_RETURN, CELL_KEYC_ENTER);
//m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_ESC);
m_keyboards[0].m_buttons.emplace_back(WXK_TAB, CELL_KEYC_TAB);
m_keyboards[0].m_buttons.emplace_back(WXK_SPACE, CELL_KEYC_SPACE);
m_keyboards[0].m_buttons.emplace_back(WXK_SUBTRACT, CELL_KEYC_MINUS);
m_keyboards[0].m_buttons.emplace_back('=', CELL_KEYC_EQUAL_101);
m_keyboards[0].m_buttons.emplace_back('^', CELL_KEYC_ACCENT_CIRCONFLEX_106);
//m_keyboards[0].m_buttons.emplace_back('(', CELL_KEYC_LEFT_BRACKET_101);
m_keyboards[0].m_buttons.emplace_back('@', CELL_KEYC_ATMARK_106);
//m_keyboards[0].m_buttons.emplace_back(')', CELL_KEYC_RIGHT_BRACKET_101);
m_keyboards[0].m_buttons.emplace_back('(', CELL_KEYC_LEFT_BRACKET_106);
//m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_BACKSLASH_101);
m_keyboards[0].m_buttons.emplace_back('(', CELL_KEYC_RIGHT_BRACKET_106);
m_keyboards[0].m_buttons.emplace_back(';', CELL_KEYC_SEMICOLON);
m_keyboards[0].m_buttons.emplace_back('"', CELL_KEYC_QUOTATION_101);
m_keyboards[0].m_buttons.emplace_back(':', CELL_KEYC_COLON_106);
m_keyboards[0].m_buttons.emplace_back(',', CELL_KEYC_COMMA);
m_keyboards[0].m_buttons.emplace_back('.', CELL_KEYC_PERIOD);
m_keyboards[0].m_buttons.emplace_back('/', CELL_KEYC_SLASH);
m_keyboards[0].m_buttons.emplace_back('\\', CELL_KEYC_BACKSLASH_106);
//m_keyboards[0].m_buttons.emplace_back(, CELL_KEYC_YEN_106);
}

View file

@ -0,0 +1,15 @@
#pragma once
#include "Emu/Io/KeyboardHandler.h"
class BasicKeyboardHandler final : public KeyboardHandlerBase, public wxWindow
{
public:
virtual void Init(const u32 max_connect) override;
BasicKeyboardHandler();
void KeyDown(wxKeyEvent& event);
void KeyUp(wxKeyEvent& event);
void LoadSettings();
};

View file

@ -0,0 +1,57 @@
#include "stdafx.h"
#include "stdafx_gui.h"
#include "rpcs3.h"
#include "BasicMouseHandler.h"
void BasicMouseHandler::Init(const u32 max_connect)
{
m_mice.emplace_back(Mouse());
memset(&m_info, 0, sizeof(MouseInfo));
m_info.max_connect = max_connect;
m_info.now_connect = std::min(m_mice.size(), (size_t)max_connect);
m_info.info = 0; // Ownership of mouse data: 0=Application, 1=System
m_info.status[0] = CELL_MOUSE_STATUS_CONNECTED; // (TODO: Support for more mice)
for (u32 i = 1; i<max_connect; i++) m_info.status[i] = CELL_MOUSE_STATUS_DISCONNECTED;
m_info.vendor_id[0] = 0x1234;
m_info.product_id[0] = 0x1234;
}
BasicMouseHandler::BasicMouseHandler()
{
wxGetApp().Bind(wxEVT_LEFT_DOWN, &BasicMouseHandler::MouseButtonDown, this);
wxGetApp().Bind(wxEVT_RIGHT_DOWN, &BasicMouseHandler::MouseButtonDown, this);
wxGetApp().Bind(wxEVT_MIDDLE_DOWN, &BasicMouseHandler::MouseButtonDown, this);
wxGetApp().Bind(wxEVT_LEFT_UP, &BasicMouseHandler::MouseButtonUp, this);
wxGetApp().Bind(wxEVT_RIGHT_UP, &BasicMouseHandler::MouseButtonUp, this);
wxGetApp().Bind(wxEVT_MIDDLE_UP, &BasicMouseHandler::MouseButtonUp, this);
wxGetApp().Bind(wxEVT_MOUSEWHEEL, &BasicMouseHandler::MouseScroll, this);
wxGetApp().Bind(wxEVT_MOTION, &BasicMouseHandler::MouseMove, this);
}
void BasicMouseHandler::MouseButtonDown(wxMouseEvent& event)
{
if (event.LeftDown()) MouseHandlerBase::Button(CELL_MOUSE_BUTTON_1, 1);
else if (event.RightDown()) MouseHandlerBase::Button(CELL_MOUSE_BUTTON_2, 1);
else if (event.MiddleDown()) MouseHandlerBase::Button(CELL_MOUSE_BUTTON_3, 1);
event.Skip();
}
void BasicMouseHandler::MouseButtonUp(wxMouseEvent& event)
{
if (event.LeftUp()) MouseHandlerBase::Button(CELL_MOUSE_BUTTON_1, 0);
else if (event.RightUp()) MouseHandlerBase::Button(CELL_MOUSE_BUTTON_2, 0);
else if (event.MiddleUp()) MouseHandlerBase::Button(CELL_MOUSE_BUTTON_3, 0);
event.Skip();
}
void BasicMouseHandler::MouseScroll(wxMouseEvent& event)
{
MouseHandlerBase::Scroll(event.GetWheelRotation());
event.Skip();
}
void BasicMouseHandler::MouseMove(wxMouseEvent& event)
{
MouseHandlerBase::Move(event.m_x, event.m_y);
event.Skip();
}

16
rpcs3/BasicMouseHandler.h Normal file
View file

@ -0,0 +1,16 @@
#pragma once
#include "Emu/Io/MouseHandler.h"
class BasicMouseHandler final : public MouseHandlerBase, public wxWindow
{
public:
virtual void Init(const u32 max_connect) override;
BasicMouseHandler();
void MouseButtonDown(wxMouseEvent& event);
void MouseButtonUp(wxMouseEvent& event);
void MouseScroll(wxMouseEvent& event);
void MouseMove(wxMouseEvent& event);
};

View file

@ -112,8 +112,8 @@ ${LLVM_INCLUDE_DIRS}
"${RPCS3_SRC_DIR}/Loader" "${RPCS3_SRC_DIR}/Loader"
"${RPCS3_SRC_DIR}/Crypto" "${RPCS3_SRC_DIR}/Crypto"
"${RPCS3_SRC_DIR}/.." "${RPCS3_SRC_DIR}/.."
"${RPCS3_SRC_DIR}/../Utilities/yaml-cpp/include"
"${RPCS3_SRC_DIR}/../asmjit/src/asmjit" "${RPCS3_SRC_DIR}/../asmjit/src/asmjit"
"${RPCS3_SRC_DIR}/../3rdparty/glm"
"${RPCS3_SRC_DIR}/../3rdparty/libpng" "${RPCS3_SRC_DIR}/../3rdparty/libpng"
"${RPCS3_SRC_DIR}/../3rdparty/GSL/include" "${RPCS3_SRC_DIR}/../3rdparty/GSL/include"
"${RPCS3_SRC_DIR}/../rsx_program_decompiler/rsx_decompiler" "${RPCS3_SRC_DIR}/../rsx_program_decompiler/rsx_decompiler"
@ -165,17 +165,10 @@ endforeach()
file( file(
GLOB_RECURSE GLOB_RECURSE
RPCS3_SRC RPCS3_SRC
"${RPCS3_SRC_DIR}/rpcs3.cpp" "${RPCS3_SRC_DIR}/*.cpp"
"${RPCS3_SRC_DIR}/config.cpp" "${RPCS3_SRC_DIR}/../Utilities/*.cpp"
"${RPCS3_SRC_DIR}/stb_image.cpp" "${RPCS3_SRC_DIR}/../rsx_program_decompiler/rsx_decompiler/*.cpp"
"${RPCS3_SRC_DIR}/../Utilities/GNU.cpp" "${RPCS3_SRC_DIR}/../rsx_program_decompiler/shader_code/*.cpp"
"${RPCS3_SRC_DIR}/Emu/*"
"${RPCS3_SRC_DIR}/Gui/*"
"${RPCS3_SRC_DIR}/Loader/*"
"${RPCS3_SRC_DIR}/Crypto/*"
"${RPCS3_SRC_DIR}/../Utilities/*"
"${RPCS3_SRC_DIR}/../rsx_program_decompiler/rsx_decompiler/*"
"${RPCS3_SRC_DIR}/../rsx_program_decompiler/shader_code/*"
) )
if(APPLE) if(APPLE)
@ -224,4 +217,4 @@ else()
endif() endif()
set_target_properties(rpcs3 PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "${RPCS3_SRC_DIR}/stdafx.h") set_target_properties(rpcs3 PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "${RPCS3_SRC_DIR}/stdafx.h")
cotire(rpcs3) cotire(rpcs3)

View file

@ -29,7 +29,6 @@
* http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf * http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
*/ */
#include "stdafx.h"
#include "aes.h" #include "aes.h"
/* /*
@ -972,4 +971,4 @@ void aes_cmac(aes_context *ctx, int length, unsigned char *input, unsigned char
for (i = 0; i < 16; i++) for (i = 0; i < 16; i++)
output[i] = X[i]; output[i] = X[i];
} }

View file

@ -2,7 +2,6 @@
// Licensed under the terms of the GNU GPL, version 2 // Licensed under the terms of the GNU GPL, version 2
// http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
#include "stdafx.h"
#include "utils.h" #include "utils.h"
void bn_print(char *name, u8 *a, u32 n) void bn_print(char *name, u8 *a, u32 n)
@ -545,4 +544,4 @@ int ecdsa_verify(u8 *hash, u8 *R, u8 *S)
void ecdsa_sign(u8 *hash, u8 *R, u8 *S) void ecdsa_sign(u8 *hash, u8 *R, u8 *S)
{ {
generate_ecdsa(R, S, ec_k, hash); generate_ecdsa(R, S, ec_k, hash);
} }

View file

@ -1,4 +1,3 @@
#include "stdafx.h"
#include "utils.h" #include "utils.h"
#include "aes.h" #include "aes.h"
#include "key_vault.h" #include "key_vault.h"

View file

@ -1,5 +1,8 @@
#pragma once #pragma once
#include <string>
#include <vector>
enum SELF_KEY_TYPE { enum SELF_KEY_TYPE {
KEY_LV0 = 1, KEY_LV0 = 1,
KEY_LV1, KEY_LV1,

View file

@ -281,4 +281,4 @@ int decompress(unsigned char *out, unsigned char *in, unsigned int size)
} }
delete[] tmp; delete[] tmp;
return result; return result;
} }

View file

@ -12,4 +12,4 @@ void decode_range(unsigned int *range, unsigned int *code, unsigned char **src);
int decode_bit(unsigned int *range, unsigned int *code, int *index, unsigned char **src, unsigned char *c); int decode_bit(unsigned int *range, unsigned int *code, int *index, unsigned char **src, unsigned char *c);
int decode_number(unsigned char *ptr, int index, int *bit_flag, unsigned int *range, unsigned int *code, unsigned char **src); int decode_number(unsigned char *ptr, int index, int *bit_flag, unsigned int *range, unsigned int *code, unsigned char **src);
int decode_word(unsigned char *ptr, int index, int *bit_flag, unsigned int *range, unsigned int *code, unsigned char **src); int decode_word(unsigned char *ptr, int index, int *bit_flag, unsigned int *range, unsigned int *code, unsigned char **src);
int decompress(unsigned char *out, unsigned char *in, unsigned int size); int decompress(unsigned char *out, unsigned char *in, unsigned int size);

View file

@ -28,7 +28,6 @@
* http://www.itl.nist.gov/fipspubs/fip180-1.htm * http://www.itl.nist.gov/fipspubs/fip180-1.htm
*/ */
#include "stdafx.h"
#include "sha1.h" #include "sha1.h"
/* /*
@ -394,4 +393,4 @@ void sha1_hmac( const unsigned char *key, size_t keylen,
sha1_hmac_finish( &ctx, output ); sha1_hmac_finish( &ctx, output );
memset( &ctx, 0, sizeof( sha1_context ) ); memset( &ctx, 0, sizeof( sha1_context ) );
} }

View file

@ -170,7 +170,7 @@ int decrypt_data(const fs::file* in, const fs::file* out, EDAT_HEADER *edat, NPD
{ {
metadata_sec_offset = metadata_offset + (unsigned long long) i * metadata_section_size; metadata_sec_offset = metadata_offset + (unsigned long long) i * metadata_section_size;
CHECK_ASSERTION(in->seek(metadata_sec_offset) != -1); in->seek(metadata_sec_offset);
unsigned char metadata[0x20]; unsigned char metadata[0x20];
memset(metadata, 0, 0x20); memset(metadata, 0, 0x20);
@ -199,7 +199,7 @@ int decrypt_data(const fs::file* in, const fs::file* out, EDAT_HEADER *edat, NPD
{ {
// If FLAG 0x20, the metadata precedes each data block. // If FLAG 0x20, the metadata precedes each data block.
metadata_sec_offset = metadata_offset + (unsigned long long) i * (metadata_section_size + length); metadata_sec_offset = metadata_offset + (unsigned long long) i * (metadata_section_size + length);
CHECK_ASSERTION(in->seek(metadata_sec_offset) != -1); in->seek(metadata_sec_offset);
unsigned char metadata[0x20]; unsigned char metadata[0x20];
memset(metadata, 0, 0x20); memset(metadata, 0, 0x20);
@ -220,7 +220,7 @@ int decrypt_data(const fs::file* in, const fs::file* out, EDAT_HEADER *edat, NPD
else else
{ {
metadata_sec_offset = metadata_offset + (unsigned long long) i * metadata_section_size; metadata_sec_offset = metadata_offset + (unsigned long long) i * metadata_section_size;
CHECK_ASSERTION(in->seek(metadata_sec_offset) != -1); in->seek(metadata_sec_offset);
in->read(hash_result, 0x10); in->read(hash_result, 0x10);
offset = metadata_offset + (unsigned long long) i * edat->block_size + (unsigned long long) block_num * metadata_section_size; offset = metadata_offset + (unsigned long long) i * edat->block_size + (unsigned long long) block_num * metadata_section_size;
@ -242,8 +242,7 @@ int decrypt_data(const fs::file* in, const fs::file* out, EDAT_HEADER *edat, NPD
memset(hash, 0, 0x10); memset(hash, 0, 0x10);
memset(key_result, 0, 0x10); memset(key_result, 0, 0x10);
CHECK_ASSERTION(in->seek(offset) != -1); in->seek(offset);
in->read(enc_data, length); in->read(enc_data, length);
// Generate a key for the current block. // Generate a key for the current block.
@ -347,7 +346,7 @@ int decrypt_data(const fs::file* in, const fs::file* out, EDAT_HEADER *edat, NPD
int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs::file* f, bool verbose) int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs::file* f, bool verbose)
{ {
CHECK_ASSERTION(f->seek(0) != -1); f->seek(0);
unsigned char header[0xA0]; unsigned char header[0xA0];
unsigned char empty_header[0xA0]; unsigned char empty_header[0xA0];
unsigned char header_hash[0x10]; unsigned char header_hash[0x10];
@ -392,8 +391,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
f->read(header, 0xA0); f->read(header, 0xA0);
// Read in the header and metadata section hashes. // Read in the header and metadata section hashes.
CHECK_ASSERTION(f->seek(0x90) != -1); f->seek(0x90);
f->read(metadata_hash, 0x10); f->read(metadata_hash, 0x10);
f->read(header_hash, 0x10); f->read(header_hash, 0x10);
@ -449,7 +447,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
while (bytes_to_read > 0) while (bytes_to_read > 0)
{ {
// Locate the metadata blocks. // Locate the metadata blocks.
CHECK_ASSERTION(f->seek(metadata_section_offset) != -1); f->seek(metadata_section_offset);
// Read in the metadata. // Read in the metadata.
f->read(metadata + bytes_read, metadata_section_size); f->read(metadata + bytes_read, metadata_section_size);
@ -496,9 +494,9 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
// Read in the metadata and header signatures. // Read in the metadata and header signatures.
CHECK_ASSERTION(f->seek(0xB0) != -1); f->seek(0xB0);
f->read(metadata_signature, 0x28); f->read(metadata_signature, 0x28);
CHECK_ASSERTION(f->seek(0xD8) != -1); f->seek(0xD8);
f->read(header_signature, 0x28); f->read(header_signature, 0x28);
// Checking metadata signature. // Checking metadata signature.
@ -514,7 +512,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
{ {
int metadata_buf_size = block_num * 0x10; int metadata_buf_size = block_num * 0x10;
unsigned char *metadata_buf = new unsigned char[metadata_buf_size]; unsigned char *metadata_buf = new unsigned char[metadata_buf_size];
CHECK_ASSERTION(f->seek(metadata_offset) != -1); f->seek(metadata_offset);
f->read(metadata_buf, metadata_buf_size); f->read(metadata_buf, metadata_buf_size);
sha1(metadata_buf, metadata_buf_size, signature_hash); sha1(metadata_buf, metadata_buf_size, signature_hash);
delete[] metadata_buf; delete[] metadata_buf;
@ -547,7 +545,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
// Setup header signature hash. // Setup header signature hash.
memset(signature_hash, 0, 20); memset(signature_hash, 0, 20);
unsigned char *header_buf = new unsigned char[0xD8]; unsigned char *header_buf = new unsigned char[0xD8];
CHECK_ASSERTION(f->seek(0x00) != -1); f->seek(0x00);
f->read(header_buf, 0xD8); f->read(header_buf, 0xD8);
sha1(header_buf, 0xD8, signature_hash ); sha1(header_buf, 0xD8, signature_hash );
delete[] header_buf; delete[] header_buf;
@ -819,7 +817,7 @@ int DecryptEDAT(const std::string& input_file_name, const std::string& output_fi
{ {
// Prepare the files. // Prepare the files.
fs::file input(input_file_name); fs::file input(input_file_name);
fs::file output(output_file_name, fom::rewrite); fs::file output(output_file_name, fs::rewrite);
// Set keys (RIF and DEVKLIC). // Set keys (RIF and DEVKLIC).
unsigned char rifkey[0x10]; unsigned char rifkey[0x10];
@ -893,7 +891,7 @@ int DecryptEDAT(const std::string& input_file_name, const std::string& output_fi
// Delete the bad output file if any errors arise. // Delete the bad output file if any errors arise.
if (extract_data(&input, &output, input_file_name.c_str(), devklic, rifkey, verbose)) if (extract_data(&input, &output, input_file_name.c_str(), devklic, rifkey, verbose))
{ {
output.close(); output.release();
fs::remove_file(output_file_name); fs::remove_file(output_file_name);
return -1; return -1;
} }

View file

@ -62,12 +62,12 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, volatile f64& pr
const std::size_t BUF_SIZE = 8192 * 1024; // 8 MB const std::size_t BUF_SIZE = 8192 * 1024; // 8 MB
// Save current file offset (probably zero) // Save current file offset (probably zero)
const u64 start_offset = pkg_f.seek(0, fs::seek_cur); const u64 start_offset = pkg_f.pos();
// Get basic PKG information // Get basic PKG information
PKGHeader header; PKGHeader header;
if (pkg_f.read(&header, sizeof(PKGHeader)) != sizeof(PKGHeader)) if (!pkg_f.read(header))
{ {
LOG_ERROR(LOADER, "PKG: Package file is too short!"); LOG_ERROR(LOADER, "PKG: Package file is too short!");
return false; return false;
@ -84,7 +84,7 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, volatile f64& pr
// Define decryption subfunction (`psp` arg selects the key for specific block) // Define decryption subfunction (`psp` arg selects the key for specific block)
auto decrypt = [&](u64 offset, u64 size, bool psp) -> u64 auto decrypt = [&](u64 offset, u64 size, bool psp) -> u64
{ {
CHECK_ASSERTION(pkg_f.seek(start_offset + header.data_offset + offset) != -1); pkg_f.seek(start_offset + header.data_offset + offset);
// Read the data and set available size // Read the data and set available size
const u64 read = pkg_f.read(buf.get(), size); const u64 read = pkg_f.read(buf.get(), size);
@ -175,7 +175,7 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, volatile f64& pr
const bool did_overwrite = fs::is_file(path); const bool did_overwrite = fs::is_file(path);
if (fs::file out{ path, fom::write | fom::create | fom::trunc }) if (fs::file out{ path, fs::rewrite })
{ {
for (u64 pos = 0; pos < entry.file_size; pos += BUF_SIZE) for (u64 pos = 0; pos < entry.file_size; pos += BUF_SIZE)
{ {

View file

@ -2,131 +2,90 @@
#include "aes.h" #include "aes.h"
#include "sha1.h" #include "sha1.h"
#include "utils.h" #include "utils.h"
#include "Emu/FS/vfsLocalFile.h"
#include "unself.h" #include "unself.h"
#pragma warning(push)
#pragma message("TODO: remove wx dependencies: See comment below.")
#pragma warning(disable : 4996)
// TODO: Still reliant on wxWidgets for zlib functions. Alternative solutions? // TODO: Still reliant on wxWidgets for zlib functions. Alternative solutions?
#include <zlib.h> #include <zlib.h>
#pragma warning(pop) force_inline u8 Read8(const fs::file& f)
force_inline u8 Read8(vfsStream& f)
{ {
u8 ret; u8 ret;
f.Read(&ret, sizeof(ret)); f.read(&ret, sizeof(ret));
return ret; return ret;
} }
force_inline u16 Read16(vfsStream& f) force_inline u16 Read16(const fs::file& f)
{ {
be_t<u16> ret; be_t<u16> ret;
f.Read(&ret, sizeof(ret)); f.read(&ret, sizeof(ret));
return ret; return ret;
} }
force_inline u32 Read32(vfsStream& f) force_inline u32 Read32(const fs::file& f)
{ {
be_t<u32> ret; be_t<u32> ret;
f.Read(&ret, sizeof(ret)); f.read(&ret, sizeof(ret));
return ret; return ret;
} }
force_inline u64 Read64(vfsStream& f) force_inline u64 Read64(const fs::file& f)
{ {
be_t<u64> ret; be_t<u64> ret;
f.Read(&ret, sizeof(ret)); f.read(&ret, sizeof(ret));
return ret; return ret;
} }
force_inline u16 Read16LE(vfsStream& f) force_inline u16 Read16LE(const fs::file& f)
{ {
u16 ret; u16 ret;
f.Read(&ret, sizeof(ret)); f.read(&ret, sizeof(ret));
return ret; return ret;
} }
force_inline u32 Read32LE(vfsStream& f) force_inline u32 Read32LE(const fs::file& f)
{ {
u32 ret; u32 ret;
f.Read(&ret, sizeof(ret)); f.read(&ret, sizeof(ret));
return ret; return ret;
} }
force_inline u64 Read64LE(vfsStream& f) force_inline u64 Read64LE(const fs::file& f)
{ {
u64 ret; u64 ret;
f.Read(&ret, sizeof(ret)); f.read(&ret, sizeof(ret));
return ret; return ret;
} }
force_inline void Write8(vfsStream& f, const u8 data)
{
f.Write(&data, sizeof(data));
}
force_inline void Write8(const fs::file& f, const u8 data) force_inline void Write8(const fs::file& f, const u8 data)
{ {
f.write(&data, sizeof(data)); f.write(&data, sizeof(data));
} }
force_inline void Write16LE(vfsStream& f, const u16 data)
{
f.Write(&data, sizeof(data));
}
force_inline void Write16LE(const fs::file& f, const u16 data) force_inline void Write16LE(const fs::file& f, const u16 data)
{ {
f.write(&data, sizeof(data)); f.write(&data, sizeof(data));
} }
force_inline void Write32LE(vfsStream& f, const u32 data)
{
f.Write(&data, sizeof(data));
}
force_inline void Write32LE(const fs::file& f, const u32 data) force_inline void Write32LE(const fs::file& f, const u32 data)
{ {
f.write(&data, sizeof(data)); f.write(&data, sizeof(data));
} }
force_inline void Write64LE(vfsStream& f, const u64 data)
{
f.Write(&data, sizeof(data));
}
force_inline void Write64LE(const fs::file& f, const u64 data) force_inline void Write64LE(const fs::file& f, const u64 data)
{ {
f.write(&data, sizeof(data)); f.write(&data, sizeof(data));
} }
force_inline void Write16(vfsStream& f, const be_t<u16> data)
{
f.Write(&data, sizeof(data));
}
force_inline void Write16(const fs::file& f, const be_t<u16> data) force_inline void Write16(const fs::file& f, const be_t<u16> data)
{ {
f.write(&data, sizeof(data)); f.write(&data, sizeof(data));
} }
force_inline void Write32(vfsStream& f, const be_t<u32> data)
{
f.Write(&data, sizeof(data));
}
force_inline void Write32(const fs::file& f, const be_t<u32> data) force_inline void Write32(const fs::file& f, const be_t<u32> data)
{ {
f.write(&data, sizeof(data)); f.write(&data, sizeof(data));
} }
force_inline void Write64(vfsStream& f, const be_t<u64> data)
{
f.Write(&data, sizeof(data));
}
force_inline void Write64(const fs::file& f, const be_t<u64> data) force_inline void Write64(const fs::file& f, const be_t<u64> data)
{ {
f.write(&data, sizeof(data)); f.write(&data, sizeof(data));
@ -231,7 +190,7 @@ void WriteShdr(const fs::file& f, Elf32_Shdr& shdr)
} }
void AppInfo::Load(vfsStream& f) void AppInfo::Load(const fs::file& f)
{ {
authid = Read64(f); authid = Read64(f);
vendor_id = Read32(f); vendor_id = Read32(f);
@ -248,7 +207,7 @@ void AppInfo::Show()
LOG_NOTICE(LOADER, "Version: 0x%llx", version); LOG_NOTICE(LOADER, "Version: 0x%llx", version);
} }
void SectionInfo::Load(vfsStream& f) void SectionInfo::Load(const fs::file& f)
{ {
offset = Read64(f); offset = Read64(f);
size = Read64(f); size = Read64(f);
@ -268,7 +227,7 @@ void SectionInfo::Show()
LOG_NOTICE(LOADER, "Encrypted: 0x%08x", encrypted); LOG_NOTICE(LOADER, "Encrypted: 0x%08x", encrypted);
} }
void SCEVersionInfo::Load(vfsStream& f) void SCEVersionInfo::Load(const fs::file& f)
{ {
subheader_type = Read32(f); subheader_type = Read32(f);
present = Read32(f); present = Read32(f);
@ -284,7 +243,7 @@ void SCEVersionInfo::Show()
LOG_NOTICE(LOADER, "Unknown: 0x%08x", unknown); LOG_NOTICE(LOADER, "Unknown: 0x%08x", unknown);
} }
void ControlInfo::Load(vfsStream& f) void ControlInfo::Load(const fs::file& f)
{ {
type = Read32(f); type = Read32(f);
size = Read32(f); size = Read32(f);
@ -305,13 +264,13 @@ void ControlInfo::Load(vfsStream& f)
{ {
if (size == 0x30) if (size == 0x30)
{ {
f.Read(file_digest_30.digest, 20); f.read(file_digest_30.digest, 20);
file_digest_30.unknown = Read64(f); file_digest_30.unknown = Read64(f);
} }
else if (size == 0x40) else if (size == 0x40)
{ {
f.Read(file_digest_40.digest1, 20); f.read(file_digest_40.digest1, 20);
f.Read(file_digest_40.digest2, 20); f.read(file_digest_40.digest2, 20);
file_digest_40.unknown = Read64(f); file_digest_40.unknown = Read64(f);
} }
} }
@ -321,10 +280,10 @@ void ControlInfo::Load(vfsStream& f)
npdrm.unknown1 = Read32(f); npdrm.unknown1 = Read32(f);
npdrm.license = Read32(f); npdrm.license = Read32(f);
npdrm.type = Read32(f); npdrm.type = Read32(f);
f.Read(npdrm.content_id, 48); f.read(npdrm.content_id, 48);
f.Read(npdrm.digest, 16); f.read(npdrm.digest, 16);
f.Read(npdrm.invdigest, 16); f.read(npdrm.invdigest, 16);
f.Read(npdrm.xordigest, 16); f.read(npdrm.xordigest, 16);
npdrm.unknown2 = Read64(f); npdrm.unknown2 = Read64(f);
npdrm.unknown3 = Read64(f); npdrm.unknown3 = Read64(f);
} }
@ -500,14 +459,14 @@ void MetadataSectionHeader::Show()
LOG_NOTICE(LOADER, "Compressed: 0x%08x", compressed); LOG_NOTICE(LOADER, "Compressed: 0x%08x", compressed);
} }
void SectionHash::Load(vfsStream& f) void SectionHash::Load(const fs::file& f)
{ {
f.Read(sha1, 20); f.read(sha1, 20);
f.Read(padding, 12); f.read(padding, 12);
f.Read(hmac_key, 64); f.read(hmac_key, 64);
} }
void CapabilitiesInfo::Load(vfsStream& f) void CapabilitiesInfo::Load(const fs::file& f)
{ {
type = Read32(f); type = Read32(f);
capabilities_size = Read32(f); capabilities_size = Read32(f);
@ -520,21 +479,21 @@ void CapabilitiesInfo::Load(vfsStream& f)
unknown5 = Read32(f); unknown5 = Read32(f);
} }
void Signature::Load(vfsStream& f) void Signature::Load(const fs::file& f)
{ {
f.Read(r, 21); f.read(r, 21);
f.Read(s, 21); f.read(s, 21);
f.Read(padding, 6); f.read(padding, 6);
} }
void SelfSection::Load(vfsStream& f) void SelfSection::Load(const fs::file& f)
{ {
*data = Read32(f); *data = Read32(f);
size = Read64(f); size = Read64(f);
offset = Read64(f); offset = Read64(f);
} }
void Elf32_Ehdr::Load(vfsStream& f) void Elf32_Ehdr::Load(const fs::file& f)
{ {
e_magic = Read32(f); e_magic = Read32(f);
e_class = Read8(f); e_class = Read8(f);
@ -578,7 +537,7 @@ void Elf32_Ehdr::Load(vfsStream& f)
} }
} }
void Elf32_Shdr::Load(vfsStream& f) void Elf32_Shdr::Load(const fs::file& f)
{ {
sh_name = Read32(f); sh_name = Read32(f);
sh_type = Read32(f); sh_type = Read32(f);
@ -592,12 +551,12 @@ void Elf32_Shdr::Load(vfsStream& f)
sh_entsize = Read32(f); sh_entsize = Read32(f);
} }
void Elf32_Shdr::LoadLE(vfsStream& f) void Elf32_Shdr::LoadLE(const fs::file& f)
{ {
f.Read(this, sizeof(*this)); f.read(this, sizeof(*this));
} }
void Elf32_Phdr::Load(vfsStream& f) void Elf32_Phdr::Load(const fs::file& f)
{ {
p_type = Read32(f); p_type = Read32(f);
p_offset = Read32(f); p_offset = Read32(f);
@ -609,12 +568,12 @@ void Elf32_Phdr::Load(vfsStream& f)
p_align = Read32(f); p_align = Read32(f);
} }
void Elf32_Phdr::LoadLE(vfsStream& f) void Elf32_Phdr::LoadLE(const fs::file& f)
{ {
f.Read(this, sizeof(*this)); f.read(this, sizeof(*this));
} }
void Elf64_Ehdr::Load(vfsStream& f) void Elf64_Ehdr::Load(const fs::file& f)
{ {
e_magic = Read32(f); e_magic = Read32(f);
e_class = Read8(f); e_class = Read8(f);
@ -637,7 +596,7 @@ void Elf64_Ehdr::Load(vfsStream& f)
e_shstrndx = Read16(f); e_shstrndx = Read16(f);
} }
void Elf64_Shdr::Load(vfsStream& f) void Elf64_Shdr::Load(const fs::file& f)
{ {
sh_name = Read32(f); sh_name = Read32(f);
sh_type = Read32(f); sh_type = Read32(f);
@ -651,7 +610,7 @@ void Elf64_Shdr::Load(vfsStream& f)
sh_entsize = Read64(f); sh_entsize = Read64(f);
} }
void Elf64_Phdr::Load(vfsStream& f) void Elf64_Phdr::Load(const fs::file& f)
{ {
p_type = Read32(f); p_type = Read32(f);
p_flags = Read32(f); p_flags = Read32(f);
@ -663,7 +622,7 @@ void Elf64_Phdr::Load(vfsStream& f)
p_align = Read64(f); p_align = Read64(f);
} }
void SceHeader::Load(vfsStream& f) void SceHeader::Load(const fs::file& f)
{ {
se_magic = Read32(f); se_magic = Read32(f);
se_hver = Read32(f); se_hver = Read32(f);
@ -674,7 +633,7 @@ void SceHeader::Load(vfsStream& f)
se_esize = Read64(f); se_esize = Read64(f);
} }
void SelfHeader::Load(vfsStream& f) void SelfHeader::Load(const fs::file& f)
{ {
se_htype = Read64(f); se_htype = Read64(f);
se_appinfooff = Read64(f); se_appinfooff = Read64(f);
@ -688,7 +647,7 @@ void SelfHeader::Load(vfsStream& f)
pad = Read64(f); pad = Read64(f);
} }
SELFDecrypter::SELFDecrypter(vfsStream& s) SELFDecrypter::SELFDecrypter(const fs::file& s)
: self_f(s) : self_f(s)
, key_v() , key_v()
, data_buf_length(0) , data_buf_length(0)
@ -698,7 +657,7 @@ SELFDecrypter::SELFDecrypter(vfsStream& s)
bool SELFDecrypter::LoadHeaders(bool isElf32) bool SELFDecrypter::LoadHeaders(bool isElf32)
{ {
// Read SCE header. // Read SCE header.
CHECK_ASSERTION(self_f.Seek(0) != -1); self_f.seek(0);
sce_hdr.Load(self_f); sce_hdr.Load(self_f);
// Check SCE magic. // Check SCE magic.
@ -712,11 +671,11 @@ bool SELFDecrypter::LoadHeaders(bool isElf32)
self_hdr.Load(self_f); self_hdr.Load(self_f);
// Read the APP INFO. // Read the APP INFO.
CHECK_ASSERTION(self_f.Seek(self_hdr.se_appinfooff) != -1); self_f.seek(self_hdr.se_appinfooff);
app_info.Load(self_f); app_info.Load(self_f);
// Read ELF header. // Read ELF header.
CHECK_ASSERTION(self_f.Seek(self_hdr.se_elfoff) != -1); self_f.seek(self_hdr.se_elfoff);
if (isElf32) if (isElf32)
elf32_hdr.Load(self_f); elf32_hdr.Load(self_f);
@ -732,7 +691,7 @@ bool SELFDecrypter::LoadHeaders(bool isElf32)
LOG_ERROR(LOADER, "SELF: ELF program header offset is null!"); LOG_ERROR(LOADER, "SELF: ELF program header offset is null!");
return false; return false;
} }
self_f.Seek(self_hdr.se_phdroff); self_f.seek(self_hdr.se_phdroff);
for(u32 i = 0; i < elf32_hdr.e_phnum; ++i) for(u32 i = 0; i < elf32_hdr.e_phnum; ++i)
{ {
phdr32_arr.emplace_back(); phdr32_arr.emplace_back();
@ -749,7 +708,7 @@ bool SELFDecrypter::LoadHeaders(bool isElf32)
return false; return false;
} }
CHECK_ASSERTION(self_f.Seek(self_hdr.se_phdroff) != -1); self_f.seek(self_hdr.se_phdroff);
for (u32 i = 0; i < elf64_hdr.e_phnum; ++i) for (u32 i = 0; i < elf64_hdr.e_phnum; ++i)
{ {
@ -761,7 +720,7 @@ bool SELFDecrypter::LoadHeaders(bool isElf32)
// Read section info. // Read section info.
secinfo_arr.clear(); secinfo_arr.clear();
CHECK_ASSERTION(self_f.Seek(self_hdr.se_secinfoff) != -1); self_f.seek(self_hdr.se_secinfoff);
for(u32 i = 0; i < ((isElf32) ? elf32_hdr.e_phnum : elf64_hdr.e_phnum); ++i) for(u32 i = 0; i < ((isElf32) ? elf32_hdr.e_phnum : elf64_hdr.e_phnum); ++i)
{ {
@ -770,12 +729,12 @@ bool SELFDecrypter::LoadHeaders(bool isElf32)
} }
// Read SCE version info. // Read SCE version info.
CHECK_ASSERTION(self_f.Seek(self_hdr.se_sceveroff) != -1); self_f.seek(self_hdr.se_sceveroff);
scev_info.Load(self_f); scev_info.Load(self_f);
// Read control info. // Read control info.
ctrlinfo_arr.clear(); ctrlinfo_arr.clear();
CHECK_ASSERTION(self_f.Seek(self_hdr.se_controloff) != -1); self_f.seek(self_hdr.se_controloff);
u32 i = 0; u32 i = 0;
while(i < self_hdr.se_controlsize) while(i < self_hdr.se_controlsize)
@ -797,7 +756,7 @@ bool SELFDecrypter::LoadHeaders(bool isElf32)
return true; return true;
} }
CHECK_ASSERTION(self_f.Seek(self_hdr.se_shdroff) != -1); self_f.seek(self_hdr.se_shdroff);
for(u32 i = 0; i < elf32_hdr.e_shnum; ++i) for(u32 i = 0; i < elf32_hdr.e_shnum; ++i)
{ {
@ -814,7 +773,7 @@ bool SELFDecrypter::LoadHeaders(bool isElf32)
return true; return true;
} }
CHECK_ASSERTION(self_f.Seek(self_hdr.se_shdroff) != -1); self_f.seek(self_hdr.se_shdroff);
for(u32 i = 0; i < elf64_hdr.e_shnum; ++i) for(u32 i = 0; i < elf64_hdr.e_shnum; ++i)
{ {
@ -950,12 +909,12 @@ bool SELFDecrypter::LoadMetadata()
u8 *metadata_headers = (u8 *)malloc(metadata_headers_size); u8 *metadata_headers = (u8 *)malloc(metadata_headers_size);
// Locate and read the encrypted metadata info. // Locate and read the encrypted metadata info.
CHECK_ASSERTION(self_f.Seek(sce_hdr.se_meta + sizeof(sce_hdr)) != -1); self_f.seek(sce_hdr.se_meta + sizeof(sce_hdr));
self_f.Read(metadata_info, metadata_info_size); self_f.read(metadata_info, metadata_info_size);
// Locate and read the encrypted metadata header and section header. // Locate and read the encrypted metadata header and section header.
CHECK_ASSERTION(self_f.Seek(sce_hdr.se_meta + sizeof(sce_hdr) + metadata_info_size) != -1); self_f.seek(sce_hdr.se_meta + sizeof(sce_hdr) + metadata_info_size);
self_f.Read(metadata_headers, metadata_headers_size); self_f.read(metadata_headers, metadata_headers_size);
// Find the right keyset from the key vault. // Find the right keyset from the key vault.
SELF_KEY keyset = key_v.FindSelfKey(app_info.self_type, sce_hdr.se_flags, app_info.version); SELF_KEY keyset = key_v.FindSelfKey(app_info.self_type, sce_hdr.se_flags, app_info.version);
@ -1057,8 +1016,8 @@ bool SELFDecrypter::DecryptData()
u8 *buf = (u8 *)malloc(meta_shdr[i].data_size); u8 *buf = (u8 *)malloc(meta_shdr[i].data_size);
// Seek to the section data offset and read the encrypted data. // Seek to the section data offset and read the encrypted data.
CHECK_ASSERTION(self_f.Seek(meta_shdr[i].data_offset) != -1); self_f.seek(meta_shdr[i].data_offset);
self_f.Read(buf, meta_shdr[i].data_size); self_f.read(buf, meta_shdr[i].data_size);
// Zero out our ctr nonce. // Zero out our ctr nonce.
memset(ctr_stream_block, 0, sizeof(ctr_stream_block)); memset(ctr_stream_block, 0, sizeof(ctr_stream_block));
@ -1085,7 +1044,7 @@ bool SELFDecrypter::DecryptData()
bool SELFDecrypter::MakeElf(const std::string& elf, bool isElf32) bool SELFDecrypter::MakeElf(const std::string& elf, bool isElf32)
{ {
// Create a new ELF file. // Create a new ELF file.
fs::file e(elf, fom::rewrite); fs::file e(elf, fs::rewrite);
if(!e) if(!e)
{ {
LOG_ERROR(LOADER, "Could not create ELF file! (%s)", elf.c_str()); LOG_ERROR(LOADER, "Could not create ELF file! (%s)", elf.c_str());
@ -1112,8 +1071,7 @@ bool SELFDecrypter::MakeElf(const std::string& elf, bool isElf32)
if (meta_shdr[i].type == 2) if (meta_shdr[i].type == 2)
{ {
// Seek to the program header data offset and write the data. // Seek to the program header data offset and write the data.
CHECK_ASSERTION(e.seek(phdr32_arr[meta_shdr[i].program_idx].p_offset) != -1); e.seek(phdr32_arr[meta_shdr[i].program_idx].p_offset);
e.write(data_buf + data_buf_offset, meta_shdr[i].data_size); e.write(data_buf + data_buf_offset, meta_shdr[i].data_size);
// Advance the data buffer offset by data size. // Advance the data buffer offset by data size.
@ -1124,7 +1082,7 @@ bool SELFDecrypter::MakeElf(const std::string& elf, bool isElf32)
// Write section headers. // Write section headers.
if (self_hdr.se_shdroff != 0) if (self_hdr.se_shdroff != 0)
{ {
CHECK_ASSERTION(e.seek(elf32_hdr.e_shoff) != -1); e.seek(elf32_hdr.e_shoff);
for (u32 i = 0; i < elf32_hdr.e_shnum; ++i) for (u32 i = 0; i < elf32_hdr.e_shnum; ++i)
{ {
@ -1180,15 +1138,13 @@ bool SELFDecrypter::MakeElf(const std::string& elf, bool isElf32)
} }
// Seek to the program header data offset and write the data. // Seek to the program header data offset and write the data.
CHECK_ASSERTION(e.seek(phdr64_arr[meta_shdr[i].program_idx].p_offset) != -1); e.seek(phdr64_arr[meta_shdr[i].program_idx].p_offset);
e.write(decomp_buf.get(), phdr64_arr[meta_shdr[i].program_idx].p_filesz); e.write(decomp_buf.get(), phdr64_arr[meta_shdr[i].program_idx].p_filesz);
} }
else else
{ {
// Seek to the program header data offset and write the data. // Seek to the program header data offset and write the data.
CHECK_ASSERTION(e.seek(phdr64_arr[meta_shdr[i].program_idx].p_offset) != -1); e.seek(phdr64_arr[meta_shdr[i].program_idx].p_offset);
e.write(data_buf + data_buf_offset, meta_shdr[i].data_size); e.write(data_buf + data_buf_offset, meta_shdr[i].data_size);
} }
@ -1200,7 +1156,7 @@ bool SELFDecrypter::MakeElf(const std::string& elf, bool isElf32)
// Write section headers. // Write section headers.
if (self_hdr.se_shdroff != 0) if (self_hdr.se_shdroff != 0)
{ {
CHECK_ASSERTION(e.seek(elf64_hdr.e_shoff) != -1); e.seek(elf64_hdr.e_shoff);
for (u32 i = 0; i < elf64_hdr.e_shnum; ++i) for (u32 i = 0; i < elf64_hdr.e_shnum; ++i)
{ {
@ -1250,10 +1206,9 @@ bool SELFDecrypter::GetKeyFromRap(u8 *content_id, u8 *npdrm_key)
bool IsSelf(const std::string& path) bool IsSelf(const std::string& path)
{ {
vfsLocalFile f(nullptr); fs::file f(path);
if(!f.Open(path)) if (!f) return false;
return false;
SceHeader hdr; SceHeader hdr;
hdr.Load(f); hdr.Load(f);
@ -1263,10 +1218,9 @@ bool IsSelf(const std::string& path)
bool IsSelfElf32(const std::string& path) bool IsSelfElf32(const std::string& path)
{ {
vfsLocalFile f(nullptr); fs::file f(path);
if(!f.Open(path)) if (!f) return false;
return false;
SceHeader hdr; SceHeader hdr;
SelfHeader sh; SelfHeader sh;
@ -1276,9 +1230,8 @@ bool IsSelfElf32(const std::string& path)
// Locate the class byte and check it. // Locate the class byte and check it.
u8 elf_class[0x8]; u8 elf_class[0x8];
CHECK_ASSERTION(f.Seek(sh.se_elfoff) != -1); f.seek(sh.se_elfoff);
f.read(elf_class, 0x8);
f.Read(elf_class, 0x8);
return (elf_class[4] == 1); return (elf_class[4] == 1);
} }
@ -1295,7 +1248,7 @@ bool CheckDebugSelf(const std::string& self, const std::string& elf)
} }
// Get the key version. // Get the key version.
CHECK_ASSERTION(s.seek(0x08) != -1); s.seek(0x08);
u16 key_version; u16 key_version;
s.read(&key_version, sizeof(key_version)); s.read(&key_version, sizeof(key_version));
@ -1306,7 +1259,7 @@ bool CheckDebugSelf(const std::string& self, const std::string& elf)
LOG_WARNING(LOADER, "Debug SELF detected! Removing fake header..."); LOG_WARNING(LOADER, "Debug SELF detected! Removing fake header...");
// Get the real elf offset. // Get the real elf offset.
CHECK_ASSERTION(s.seek(0x10) != -1); s.seek(0x10);
u64 elf_offset; u64 elf_offset;
s.read(&elf_offset, sizeof(elf_offset)); s.read(&elf_offset, sizeof(elf_offset));
@ -1314,10 +1267,10 @@ bool CheckDebugSelf(const std::string& self, const std::string& elf)
// Start at the real elf offset. // Start at the real elf offset.
elf_offset = swap64(elf_offset); elf_offset = swap64(elf_offset);
CHECK_ASSERTION(s.seek(elf_offset) != -1); s.seek(elf_offset);
// Write the real ELF file back. // Write the real ELF file back.
fs::file e(elf, fom::rewrite); fs::file e(elf, fs::rewrite);
if (!e) if (!e)
{ {
LOG_ERROR(LOADER, "Could not create ELF file! (%s)", elf.c_str()); LOG_ERROR(LOADER, "Could not create ELF file! (%s)", elf.c_str());
@ -1326,7 +1279,7 @@ bool CheckDebugSelf(const std::string& self, const std::string& elf)
// Copy the data. // Copy the data.
char buf[2048]; char buf[2048];
while (u64 size = s.read(buf, 2048)) // read returns u64. while (u64 size = s.read(buf, 2048))
{ {
e.write(buf, size); e.write(buf, size);
} }
@ -1346,9 +1299,9 @@ bool DecryptSelf(const std::string& elf, const std::string& self)
if (!CheckDebugSelf(self, elf)) if (!CheckDebugSelf(self, elf))
{ {
// Set a virtual pointer to the SELF file. // Set a virtual pointer to the SELF file.
vfsLocalFile self_vf(nullptr); fs::file self_vf(self);
if (!self_vf.Open(self)) if (!self_vf)
return false; return false;
// Check the ELF file class (32 or 64 bit). // Check the ELF file class (32 or 64 bit).

View file

@ -1,7 +1,6 @@
#pragma once #pragma once
#include "key_vault.h"
struct vfsStream; #include "key_vault.h"
struct AppInfo struct AppInfo
{ {
@ -11,7 +10,7 @@ struct AppInfo
u64 version; u64 version;
u64 padding; u64 padding;
void Load(vfsStream& f); void Load(const fs::file& f);
void Show(); void Show();
}; };
@ -24,7 +23,7 @@ struct SectionInfo
u32 unknown2; u32 unknown2;
u32 encrypted; u32 encrypted;
void Load(vfsStream& f); void Load(const fs::file& f);
void Show(); void Show();
}; };
@ -35,7 +34,7 @@ struct SCEVersionInfo
u32 size; u32 size;
u32 unknown; u32 unknown;
void Load(vfsStream& f); void Load(const fs::file& f);
void Show(); void Show();
}; };
@ -95,7 +94,7 @@ struct ControlInfo
} npdrm; } npdrm;
}; };
void Load(vfsStream& f); void Load(const fs::file& f);
void Show(); void Show();
}; };
@ -148,7 +147,7 @@ struct SectionHash
u8 padding[12]; u8 padding[12];
u8 hmac_key[64]; u8 hmac_key[64];
void Load(vfsStream& f); void Load(const fs::file& f);
}; };
struct CapabilitiesInfo struct CapabilitiesInfo
@ -163,7 +162,7 @@ struct CapabilitiesInfo
u32 unknown4; u32 unknown4;
u32 unknown5; u32 unknown5;
void Load(vfsStream& f); void Load(const fs::file& f);
}; };
struct Signature struct Signature
@ -172,7 +171,7 @@ struct Signature
u8 s[21]; u8 s[21];
u8 padding[6]; u8 padding[6];
void Load(vfsStream& f); void Load(const fs::file& f);
}; };
struct SelfSection struct SelfSection
@ -181,7 +180,7 @@ struct SelfSection
u64 size; u64 size;
u64 offset; u64 offset;
void Load(vfsStream& f); void Load(const fs::file& f);
}; };
struct Elf32_Ehdr struct Elf32_Ehdr
@ -206,7 +205,7 @@ struct Elf32_Ehdr
u16 e_shnum; u16 e_shnum;
u16 e_shstrndx; u16 e_shstrndx;
void Load(vfsStream& f); void Load(const fs::file& f);
void Show() {} void Show() {}
bool IsLittleEndian() const { return e_data == 1; } bool IsLittleEndian() const { return e_data == 1; }
bool CheckMagic() const { return e_magic == 0x7F454C46; } bool CheckMagic() const { return e_magic == 0x7F454C46; }
@ -226,8 +225,8 @@ struct Elf32_Shdr
u32 sh_addralign; u32 sh_addralign;
u32 sh_entsize; u32 sh_entsize;
void Load(vfsStream& f); void Load(const fs::file& f);
void LoadLE(vfsStream& f); void LoadLE(const fs::file& f);
void Show() {} void Show() {}
}; };
@ -242,8 +241,8 @@ struct Elf32_Phdr
u32 p_flags; u32 p_flags;
u32 p_align; u32 p_align;
void Load(vfsStream& f); void Load(const fs::file& f);
void LoadLE(vfsStream& f); void LoadLE(const fs::file& f);
void Show() {} void Show() {}
}; };
@ -269,7 +268,7 @@ struct Elf64_Ehdr
u16 e_shnum; u16 e_shnum;
u16 e_shstrndx; u16 e_shstrndx;
void Load(vfsStream& f); void Load(const fs::file& f);
void Show() {} void Show() {}
bool CheckMagic() const { return e_magic == 0x7F454C46; } bool CheckMagic() const { return e_magic == 0x7F454C46; }
u64 GetEntry() const { return e_entry; } u64 GetEntry() const { return e_entry; }
@ -288,7 +287,7 @@ struct Elf64_Shdr
u64 sh_addralign; u64 sh_addralign;
u64 sh_entsize; u64 sh_entsize;
void Load(vfsStream& f); void Load(const fs::file& f);
void Show(){} void Show(){}
}; };
@ -303,7 +302,7 @@ struct Elf64_Phdr
u64 p_memsz; u64 p_memsz;
u64 p_align; u64 p_align;
void Load(vfsStream& f); void Load(const fs::file& f);
void Show(){} void Show(){}
}; };
@ -317,7 +316,7 @@ struct SceHeader
u64 se_hsize; u64 se_hsize;
u64 se_esize; u64 se_esize;
void Load(vfsStream& f); void Load(const fs::file& f);
void Show(){} void Show(){}
bool CheckMagic() const { return se_magic == 0x53434500; } bool CheckMagic() const { return se_magic == 0x53434500; }
}; };
@ -335,14 +334,14 @@ struct SelfHeader
u64 se_controlsize; u64 se_controlsize;
u64 pad; u64 pad;
void Load(vfsStream& f); void Load(const fs::file& f);
void Show(){} void Show(){}
}; };
class SELFDecrypter class SELFDecrypter
{ {
// Main SELF file stream. // Main SELF file stream.
vfsStream& self_f; const fs::file& self_f;
// SCE, SELF and APP headers. // SCE, SELF and APP headers.
SceHeader sce_hdr; SceHeader sce_hdr;
@ -379,7 +378,7 @@ class SELFDecrypter
KeyVault key_v; KeyVault key_v;
public: public:
SELFDecrypter(vfsStream& s); SELFDecrypter(const fs::file& s);
bool MakeElf(const std::string& elf, bool isElf32); bool MakeElf(const std::string& elf, bool isElf32);
bool LoadHeaders(bool isElf32); bool LoadHeaders(bool isElf32);
void ShowHeaders(bool isElf32); void ShowHeaders(bool isElf32);

View file

@ -2,7 +2,6 @@
// Licensed under the terms of the GNU GPL, version 3 // Licensed under the terms of the GNU GPL, version 3
// http://www.gnu.org/licenses/gpl-3.0.txt // http://www.gnu.org/licenses/gpl-3.0.txt
#include "stdafx.h"
#include "utils.h" #include "utils.h"
#include <stdio.h> #include <stdio.h>
#include <time.h> #include <time.h>
@ -208,4 +207,4 @@ char* extract_file_name(const char* file_path, char real_file_name[MAX_PATH])
strncpy(real_file_name, p ? (p + 1) : file_path, file_path_len + 1); strncpy(real_file_name, p ? (p + 1) : file_path, file_path_len + 1);
return real_file_name; return real_file_name;
} }

View file

@ -4,6 +4,8 @@
// Licensed under the terms of the GNU GPL, version 3 // Licensed under the terms of the GNU GPL, version 3
// http://www.gnu.org/licenses/gpl-3.0.txt // http://www.gnu.org/licenses/gpl-3.0.txt
#include "../../Utilities/types.h"
#define MAX_PATH 4096 #define MAX_PATH 4096
#include <stdlib.h> #include <stdlib.h>
@ -32,4 +34,4 @@ void aesecb128_encrypt(unsigned char *key, unsigned char *in, unsigned char *out
bool hmac_hash_compare(unsigned char *key, int key_len, unsigned char *in, int in_len, unsigned char *hash, int hash_len); bool hmac_hash_compare(unsigned char *key, int key_len, unsigned char *in, int in_len, unsigned char *hash, int hash_len);
void hmac_hash_forge(unsigned char *key, int key_len, unsigned char *in, int in_len, unsigned char *hash); void hmac_hash_forge(unsigned char *key, int key_len, unsigned char *in, int in_len, unsigned char *hash);
bool cmac_hash_compare(unsigned char *key, int key_len, unsigned char *in, int in_len, unsigned char *hash, int hash_len); bool cmac_hash_compare(unsigned char *key, int key_len, unsigned char *in, int in_len, unsigned char *hash, int hash_len);
void cmac_hash_forge(unsigned char *key, int key_len, unsigned char *in, int in_len, unsigned char *hash); void cmac_hash_forge(unsigned char *key, int key_len, unsigned char *in, int in_len, unsigned char *hash);

View file

@ -61,11 +61,6 @@
<Import Project="..\rpcs3_llvm.props" /> <Import Project="..\rpcs3_llvm.props" />
</ImportGroup> </ImportGroup>
<PropertyGroup Label="UserMacros" /> <PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup>
<ClCompile>
<TreatWarningAsError>true</TreatWarningAsError>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="Emu\RSX\D3D12\D3D12Utils.h" /> <ClInclude Include="Emu\RSX\D3D12\D3D12Utils.h" />
<ClInclude Include="Emu\RSX\D3D12\D3D12CommonDecompiler.h" /> <ClInclude Include="Emu\RSX\D3D12\D3D12CommonDecompiler.h" />

View file

@ -1,17 +1,17 @@
#pragma once #pragma once
#include "Emu/Memory/Memory.h"
#include "Emu/ARMv7/PSVFuncList.h" #include "ARMv7Function.h"
namespace vm namespace vm
{ {
template<typename AT, typename RT, typename... T> template<typename AT, typename RT, typename... T>
force_inline RT _ptr_base<RT(T...), AT>::operator()(ARMv7Thread& context, T... args) const force_inline RT _ptr_base<RT(T...), AT>::operator()(ARMv7Thread& cpu, T... args) const
{ {
return psv_func_detail::func_caller<RT, T...>::call(context, VM_CAST(this->addr()), args...); return arm_func_detail::func_caller<RT, T...>::call(cpu, vm::cast(this->addr(), HERE), args...);
} }
} }
template<typename RT, typename... T> inline RT cb_call(ARMv7Thread& context, u32 addr, T... args) template<typename RT, typename... T> inline RT cb_call(ARMv7Thread& cpu, u32 addr, T... args)
{ {
return psv_func_detail::func_caller<RT, T...>::call(context, addr, args...); return arm_func_detail::func_caller<RT, T...>::call(cpu, addr, args...);
} }

View file

@ -1,324 +0,0 @@
#pragma once
#include "Emu/Memory/Memory.h"
enum ARMv7InstructionSet
{
ARM,
Thumb,
Jazelle,
ThumbEE
};
enum armv7_debug_flags : u32
{
DF_DISASM = 1 << 0,
DF_PRINT = 1 << 1,
DF_NO_EXE = 1 << 2,
};
struct ARMv7Context
{
union
{
u32 GPR[15];
struct
{
u32 pad[13];
union
{
u32 SP;
struct { u16 SP_main, SP_process; };
};
u32 LR;
union
{
struct
{
u32 reserved0 : 16;
u32 GE : 4;
u32 reserved1 : 4;
u32 dummy : 3;
u32 Q : 1; // Set to 1 if an SSAT or USAT instruction changes (saturates) the input value for the signed or unsigned range of the result
u32 V : 1; // Overflow condition code flag
u32 C : 1; // Carry condition code flag
u32 Z : 1; // Zero condition code flag
u32 N : 1; // Negative condition code flag
};
u32 APSR;
} APSR;
};
struct
{
u64 GPR_D[8];
};
};
union
{
struct
{
u32 dummy : 24;
u32 exception : 8;
};
u32 IPSR;
} IPSR;
ARMv7InstructionSet ISET;
union
{
struct
{
u8 shift_state : 5;
u8 cond_base : 3;
};
struct
{
u8 check_state : 4;
u8 condition : 4;
};
u8 IT;
u32 advance()
{
const u32 res = check_state ? condition : 0xe /* always true */;
shift_state <<= 1;
if (!check_state)
{
IT = 0; // clear
}
return res;
}
operator bool() const
{
return check_state != 0;
}
} ITSTATE;
u32 TLS;
struct perf_counter
{
u32 event;
u32 value;
};
std::array<perf_counter, 6> counters;
u32 PC;
s32 prio;
u32 stack_addr;
u32 stack_size;
u32 hle_func; // current function ID
u32 debug;
std::string debug_str;
void write_pc(u32 value, u32 size)
{
ISET = value & 1 ? Thumb : ARM;
PC = (value & ~1) - size;
}
u32 read_pc()
{
return ISET == ARM ? PC + 8 : PC + 4;
}
u32 get_stack_arg(u32 pos)
{
return vm::psv::read32(SP + sizeof(u32) * (pos - 5));
}
void fast_call(u32 addr);
void write_gpr(u32 n, u32 value, u32 size)
{
assert(n < 16);
if (n < 15)
{
GPR[n] = value;
}
else
{
write_pc(value, size);
}
}
u32 read_gpr(u32 n)
{
assert(n < 16);
if (n < 15)
{
return GPR[n];
}
return read_pc();
}
// function for processing va_args in printf-like functions
u32 get_next_gpr_arg(u32& g_count, u32& f_count, u32& v_count)
{
assert(!f_count && !v_count); // not supported
if (g_count < 4)
{
return GPR[g_count++];
}
else
{
return get_stack_arg(g_count++);
}
}
template<typename... T>
never_inline void fmt_debug_str(const char* fmt, T... args)
{
debug_str = fmt::format(fmt, args...);
}
};
template<typename T, bool is_enum = std::is_enum<T>::value>
struct cast_armv7_gpr
{
static_assert(is_enum, "Invalid type for cast_armv7_gpr");
force_inline static u32 to_gpr(const T& value)
{
return cast_armv7_gpr<std::underlying_type_t<T>>::to_gpr(static_cast<std::underlying_type_t<T>>(value));
}
force_inline static T from_gpr(const u32 reg)
{
return static_cast<T>(cast_armv7_gpr<std::underlying_type_t<T>>::from_gpr(reg));
}
};
template<>
struct cast_armv7_gpr<u8, false>
{
force_inline static u32 to_gpr(const u8& value)
{
return value;
}
force_inline static u8 from_gpr(const u32 reg)
{
return static_cast<u8>(reg);
}
};
template<>
struct cast_armv7_gpr<u16, false>
{
force_inline static u32 to_gpr(const u16& value)
{
return value;
}
force_inline static u16 from_gpr(const u32 reg)
{
return static_cast<u16>(reg);
}
};
template<>
struct cast_armv7_gpr<u32, false>
{
force_inline static u32 to_gpr(const u32& value)
{
return value;
}
force_inline static u32 from_gpr(const u32 reg)
{
return reg;
}
};
template<>
struct cast_armv7_gpr<s8, false>
{
force_inline static u32 to_gpr(const s8& value)
{
return value;
}
force_inline static s8 from_gpr(const u32 reg)
{
return static_cast<s8>(reg);
}
};
template<>
struct cast_armv7_gpr<s16, false>
{
force_inline static u32 to_gpr(const s16& value)
{
return value;
}
force_inline static s16 from_gpr(const u32 reg)
{
return static_cast<s16>(reg);
}
};
template<>
struct cast_armv7_gpr<s32, false>
{
force_inline static u32 to_gpr(const s32& value)
{
return value;
}
force_inline static s32 from_gpr(const u32 reg)
{
return static_cast<s32>(reg);
}
};
template<>
struct cast_armv7_gpr<b8, false>
{
force_inline static u32 to_gpr(const b8& value)
{
return value;
}
force_inline static b8 from_gpr(const u32& reg)
{
return reg != 0;
}
};
template<typename T>
force_inline u32 cast_to_armv7_gpr(const T& value)
{
return cast_armv7_gpr<T>::to_gpr(value);
}
template<typename T>
force_inline T cast_from_armv7_gpr(const u32 reg)
{
return cast_armv7_gpr<T>::from_gpr(reg);
}

File diff suppressed because it is too large Load diff

View file

@ -1,18 +0,0 @@
#pragma once
#include "Emu/CPU/CPUDecoder.h"
struct ARMv7Context;
class ARMv7Decoder : public CPUDecoder
{
ARMv7Context& m_ctx;
public:
ARMv7Decoder(ARMv7Context& context) : m_ctx(context)
{
}
virtual u32 DecodeMemory(const u32 address);
};
void armv7_decoder_initialize(u32 addr, u32 end_addr, bool dump = false);

File diff suppressed because it is too large Load diff

View file

@ -1,328 +1,459 @@
#pragma once #pragma once
#include "Emu/CPU/CPUDisAsm.h" #include "Emu/CPU/CPUDisAsm.h"
static const char* g_arm_cond_name[16] = enum class arm_encoding;
{
"eq", "ne", "cs", "cc",
"mi", "pl", "vs", "vc",
"hi", "ls", "ge", "lt",
"gt", "le", "al", "al",
};
static const char* g_arm_reg_name[16] = class ARMv7DisAsm final : public CPUDisAsm
{
"r0", "r1", "r2", "r3",
"r4", "r5", "r6", "r7",
"r8", "r9", "r10", "r11",
"r12", "sp", "lr", "pc",
};
class ARMv7DisAsm
: public CPUDisAsm
{ {
public: public:
ARMv7DisAsm() : CPUDisAsm(CPUDisAsm_InterpreterMode) ARMv7DisAsm(CPUDisAsmMode mode) : CPUDisAsm(mode)
{ {
} }
protected: protected:
virtual u32 DisAsmBranchTarget(const s32 imm) virtual u32 DisAsmBranchTarget(const s32 imm) override
{ {
return (u32)dump_pc + imm; // TODO: ARM
return dump_pc + (true ? 4 : 8) + imm;
} }
#if 0 virtual void Write(const std::string& value) override;
std::string GetRegsListString(u16 regs_list)
private:
template<typename... Args>
void write(const char* fmt, const Args&... args)
{ {
std::string regs_str; Write(fmt::format(fmt, args...));
for(u16 mask=0x1, i=0; mask; mask <<= 1, i++)
{
if(regs_list & mask)
{
if(!regs_str.empty())
{
regs_str += ", ";
}
regs_str += g_arm_reg_name[i];
}
}
return regs_str;
} }
virtual void UNK(const u32 data); public:
void UNK(const u32 op, const u32 cond);
virtual void NULL_OP(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void HACK(const u32, const u32);
template<arm_encoding type> void MRC_(const u32, const u32);
virtual void HACK(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void ADC_IMM(const u32, const u32);
template<arm_encoding type> void ADC_REG(const u32, const u32);
template<arm_encoding type> void ADC_RSR(const u32, const u32);
virtual void ADC_IMM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void ADD_IMM(const u32, const u32);
virtual void ADC_REG(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void ADD_REG(const u32, const u32);
virtual void ADC_RSR(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void ADD_RSR(const u32, const u32);
template<arm_encoding type> void ADD_SPI(const u32, const u32);
template<arm_encoding type> void ADD_SPR(const u32, const u32);
virtual void ADD_IMM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void ADR(const u32, const u32);
virtual void ADD_REG(const u32 data, const ARMv7_encoding type);
virtual void ADD_RSR(const u32 data, const ARMv7_encoding type);
virtual void ADD_SPI(const u32 data, const ARMv7_encoding type);
virtual void ADD_SPR(const u32 data, const ARMv7_encoding type);
virtual void ADR(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void AND_IMM(const u32, const u32);
template<arm_encoding type> void AND_REG(const u32, const u32);
template<arm_encoding type> void AND_RSR(const u32, const u32);
virtual void AND_IMM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void ASR_IMM(const u32, const u32);
virtual void AND_REG(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void ASR_REG(const u32, const u32);
virtual void AND_RSR(const u32 data, const ARMv7_encoding type);
virtual void ASR_IMM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void B(const u32, const u32);
virtual void ASR_REG(const u32 data, const ARMv7_encoding type);
virtual void B(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void BFC(const u32, const u32);
template<arm_encoding type> void BFI(const u32, const u32);
virtual void BFC(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void BIC_IMM(const u32, const u32);
virtual void BFI(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void BIC_REG(const u32, const u32);
template<arm_encoding type> void BIC_RSR(const u32, const u32);
virtual void BIC_IMM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void BKPT(const u32, const u32);
virtual void BIC_REG(const u32 data, const ARMv7_encoding type);
virtual void BIC_RSR(const u32 data, const ARMv7_encoding type);
virtual void BKPT(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void BL(const u32, const u32);
template<arm_encoding type> void BLX(const u32, const u32);
template<arm_encoding type> void BX(const u32, const u32);
virtual void BL(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void CB_Z(const u32, const u32);
virtual void BLX(const u32 data, const ARMv7_encoding type);
virtual void BX(const u32 data, const ARMv7_encoding type);
virtual void CB_Z(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void CLZ(const u32, const u32);
virtual void CLZ(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void CMN_IMM(const u32, const u32);
template<arm_encoding type> void CMN_REG(const u32, const u32);
template<arm_encoding type> void CMN_RSR(const u32, const u32);
virtual void CMN_IMM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void CMP_IMM(const u32, const u32);
virtual void CMN_REG(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void CMP_REG(const u32, const u32);
virtual void CMN_RSR(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void CMP_RSR(const u32, const u32);
virtual void CMP_IMM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void DBG(const u32, const u32);
virtual void CMP_REG(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void DMB(const u32, const u32);
virtual void CMP_RSR(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void DSB(const u32, const u32);
virtual void EOR_IMM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void EOR_IMM(const u32, const u32);
virtual void EOR_REG(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void EOR_REG(const u32, const u32);
virtual void EOR_RSR(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void EOR_RSR(const u32, const u32);
virtual void IT(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void IT(const u32, const u32);
virtual void LDM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void LDM(const u32, const u32);
virtual void LDMDA(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void LDMDA(const u32, const u32);
virtual void LDMDB(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void LDMDB(const u32, const u32);
virtual void LDMIB(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void LDMIB(const u32, const u32);
virtual void LDR_IMM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void LDR_IMM(const u32, const u32);
virtual void LDR_LIT(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void LDR_LIT(const u32, const u32);
virtual void LDR_REG(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void LDR_REG(const u32, const u32);
virtual void LDRB_IMM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void LDRB_IMM(const u32, const u32);
virtual void LDRB_LIT(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void LDRB_LIT(const u32, const u32);
virtual void LDRB_REG(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void LDRB_REG(const u32, const u32);
virtual void LDRD_IMM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void LDRD_IMM(const u32, const u32);
virtual void LDRD_LIT(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void LDRD_LIT(const u32, const u32);
virtual void LDRD_REG(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void LDRD_REG(const u32, const u32);
virtual void LDRH_IMM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void LDRH_IMM(const u32, const u32);
virtual void LDRH_LIT(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void LDRH_LIT(const u32, const u32);
virtual void LDRH_REG(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void LDRH_REG(const u32, const u32);
virtual void LDRSB_IMM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void LDRSB_IMM(const u32, const u32);
virtual void LDRSB_LIT(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void LDRSB_LIT(const u32, const u32);
virtual void LDRSB_REG(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void LDRSB_REG(const u32, const u32);
virtual void LDRSH_IMM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void LDRSH_IMM(const u32, const u32);
virtual void LDRSH_LIT(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void LDRSH_LIT(const u32, const u32);
virtual void LDRSH_REG(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void LDRSH_REG(const u32, const u32);
virtual void LSL_IMM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void LDREX(const u32, const u32);
virtual void LSL_REG(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void LDREXB(const u32, const u32);
template<arm_encoding type> void LDREXD(const u32, const u32);
template<arm_encoding type> void LDREXH(const u32, const u32);
virtual void LSR_IMM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void LSL_IMM(const u32, const u32);
virtual void LSR_REG(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void LSL_REG(const u32, const u32);
virtual void MLA(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void LSR_IMM(const u32, const u32);
virtual void MLS(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void LSR_REG(const u32, const u32);
virtual void MOV_IMM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void MLA(const u32, const u32);
virtual void MOV_REG(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void MLS(const u32, const u32);
virtual void MOVT(const u32 data, const ARMv7_encoding type);
virtual void MRS(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void MOV_IMM(const u32, const u32);
virtual void MSR_IMM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void MOV_REG(const u32, const u32);
virtual void MSR_REG(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void MOVT(const u32, const u32);
virtual void MUL(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void MRS(const u32, const u32);
template<arm_encoding type> void MSR_IMM(const u32, const u32);
template<arm_encoding type> void MSR_REG(const u32, const u32);
virtual void MVN_IMM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void MUL(const u32, const u32);
virtual void MVN_REG(const u32 data, const ARMv7_encoding type);
virtual void MVN_RSR(const u32 data, const ARMv7_encoding type);
virtual void NOP(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void MVN_IMM(const u32, const u32);
template<arm_encoding type> void MVN_REG(const u32, const u32);
template<arm_encoding type> void MVN_RSR(const u32, const u32);
virtual void ORN_IMM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void NOP(const u32, const u32);
virtual void ORN_REG(const u32 data, const ARMv7_encoding type);
virtual void ORR_IMM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void ORN_IMM(const u32, const u32);
virtual void ORR_REG(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void ORN_REG(const u32, const u32);
virtual void ORR_RSR(const u32 data, const ARMv7_encoding type);
virtual void PKH(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void ORR_IMM(const u32, const u32);
template<arm_encoding type> void ORR_REG(const u32, const u32);
template<arm_encoding type> void ORR_RSR(const u32, const u32);
virtual void POP(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void PKH(const u32, const u32);
virtual void PUSH(const u32 data, const ARMv7_encoding type);
virtual void QADD(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void POP(const u32, const u32);
virtual void QADD16(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void PUSH(const u32, const u32);
virtual void QADD8(const u32 data, const ARMv7_encoding type);
virtual void QASX(const u32 data, const ARMv7_encoding type);
virtual void QDADD(const u32 data, const ARMv7_encoding type);
virtual void QDSUB(const u32 data, const ARMv7_encoding type);
virtual void QSAX(const u32 data, const ARMv7_encoding type);
virtual void QSUB(const u32 data, const ARMv7_encoding type);
virtual void QSUB16(const u32 data, const ARMv7_encoding type);
virtual void QSUB8(const u32 data, const ARMv7_encoding type);
virtual void RBIT(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void QADD(const u32, const u32);
virtual void REV(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void QADD16(const u32, const u32);
virtual void REV16(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void QADD8(const u32, const u32);
virtual void REVSH(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void QASX(const u32, const u32);
template<arm_encoding type> void QDADD(const u32, const u32);
template<arm_encoding type> void QDSUB(const u32, const u32);
template<arm_encoding type> void QSAX(const u32, const u32);
template<arm_encoding type> void QSUB(const u32, const u32);
template<arm_encoding type> void QSUB16(const u32, const u32);
template<arm_encoding type> void QSUB8(const u32, const u32);
virtual void ROR_IMM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void RBIT(const u32, const u32);
virtual void ROR_REG(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void REV(const u32, const u32);
template<arm_encoding type> void REV16(const u32, const u32);
template<arm_encoding type> void REVSH(const u32, const u32);
virtual void RRX(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void ROR_IMM(const u32, const u32);
template<arm_encoding type> void ROR_REG(const u32, const u32);
virtual void RSB_IMM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void RRX(const u32, const u32);
virtual void RSB_REG(const u32 data, const ARMv7_encoding type);
virtual void RSB_RSR(const u32 data, const ARMv7_encoding type);
virtual void RSC_IMM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void RSB_IMM(const u32, const u32);
virtual void RSC_REG(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void RSB_REG(const u32, const u32);
virtual void RSC_RSR(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void RSB_RSR(const u32, const u32);
virtual void SADD16(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void RSC_IMM(const u32, const u32);
virtual void SADD8(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void RSC_REG(const u32, const u32);
virtual void SASX(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void RSC_RSR(const u32, const u32);
virtual void SBC_IMM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void SADD16(const u32, const u32);
virtual void SBC_REG(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void SADD8(const u32, const u32);
virtual void SBC_RSR(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void SASX(const u32, const u32);
virtual void SBFX(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void SBC_IMM(const u32, const u32);
template<arm_encoding type> void SBC_REG(const u32, const u32);
template<arm_encoding type> void SBC_RSR(const u32, const u32);
virtual void SDIV(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void SBFX(const u32, const u32);
virtual void SEL(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void SDIV(const u32, const u32);
virtual void SHADD16(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void SEL(const u32, const u32);
virtual void SHADD8(const u32 data, const ARMv7_encoding type);
virtual void SHASX(const u32 data, const ARMv7_encoding type);
virtual void SHSAX(const u32 data, const ARMv7_encoding type);
virtual void SHSUB16(const u32 data, const ARMv7_encoding type);
virtual void SHSUB8(const u32 data, const ARMv7_encoding type);
virtual void SMLA__(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void SHADD16(const u32, const u32);
virtual void SMLAD(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void SHADD8(const u32, const u32);
virtual void SMLAL(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void SHASX(const u32, const u32);
virtual void SMLAL__(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void SHSAX(const u32, const u32);
virtual void SMLALD(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void SHSUB16(const u32, const u32);
virtual void SMLAW_(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void SHSUB8(const u32, const u32);
virtual void SMLSD(const u32 data, const ARMv7_encoding type);
virtual void SMLSLD(const u32 data, const ARMv7_encoding type);
virtual void SMMLA(const u32 data, const ARMv7_encoding type);
virtual void SMMLS(const u32 data, const ARMv7_encoding type);
virtual void SMMUL(const u32 data, const ARMv7_encoding type);
virtual void SMUAD(const u32 data, const ARMv7_encoding type);
virtual void SMUL__(const u32 data, const ARMv7_encoding type);
virtual void SMULL(const u32 data, const ARMv7_encoding type);
virtual void SMULW_(const u32 data, const ARMv7_encoding type);
virtual void SMUSD(const u32 data, const ARMv7_encoding type);
virtual void SSAT(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void SMLA__(const u32, const u32);
virtual void SSAT16(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void SMLAD(const u32, const u32);
virtual void SSAX(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void SMLAL(const u32, const u32);
virtual void SSUB16(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void SMLAL__(const u32, const u32);
virtual void SSUB8(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void SMLALD(const u32, const u32);
template<arm_encoding type> void SMLAW_(const u32, const u32);
template<arm_encoding type> void SMLSD(const u32, const u32);
template<arm_encoding type> void SMLSLD(const u32, const u32);
template<arm_encoding type> void SMMLA(const u32, const u32);
template<arm_encoding type> void SMMLS(const u32, const u32);
template<arm_encoding type> void SMMUL(const u32, const u32);
template<arm_encoding type> void SMUAD(const u32, const u32);
template<arm_encoding type> void SMUL__(const u32, const u32);
template<arm_encoding type> void SMULL(const u32, const u32);
template<arm_encoding type> void SMULW_(const u32, const u32);
template<arm_encoding type> void SMUSD(const u32, const u32);
virtual void STM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void SSAT(const u32, const u32);
virtual void STMDA(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void SSAT16(const u32, const u32);
virtual void STMDB(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void SSAX(const u32, const u32);
virtual void STMIB(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void SSUB16(const u32, const u32);
template<arm_encoding type> void SSUB8(const u32, const u32);
virtual void STR_IMM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void STM(const u32, const u32);
virtual void STR_REG(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void STMDA(const u32, const u32);
template<arm_encoding type> void STMDB(const u32, const u32);
template<arm_encoding type> void STMIB(const u32, const u32);
virtual void STRB_IMM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void STR_IMM(const u32, const u32);
virtual void STRB_REG(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void STR_REG(const u32, const u32);
virtual void STRD_IMM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void STRB_IMM(const u32, const u32);
virtual void STRD_REG(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void STRB_REG(const u32, const u32);
virtual void STRH_IMM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void STRD_IMM(const u32, const u32);
virtual void STRH_REG(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void STRD_REG(const u32, const u32);
virtual void SUB_IMM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void STRH_IMM(const u32, const u32);
virtual void SUB_REG(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void STRH_REG(const u32, const u32);
virtual void SUB_RSR(const u32 data, const ARMv7_encoding type);
virtual void SUB_SPI(const u32 data, const ARMv7_encoding type);
virtual void SUB_SPR(const u32 data, const ARMv7_encoding type);
virtual void SVC(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void STREX(const u32, const u32);
template<arm_encoding type> void STREXB(const u32, const u32);
template<arm_encoding type> void STREXD(const u32, const u32);
template<arm_encoding type> void STREXH(const u32, const u32);
virtual void SXTAB(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void SUB_IMM(const u32, const u32);
virtual void SXTAB16(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void SUB_REG(const u32, const u32);
virtual void SXTAH(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void SUB_RSR(const u32, const u32);
virtual void SXTB(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void SUB_SPI(const u32, const u32);
virtual void SXTB16(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void SUB_SPR(const u32, const u32);
virtual void SXTH(const u32 data, const ARMv7_encoding type);
virtual void TB_(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void SVC(const u32, const u32);
virtual void TEQ_IMM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void SXTAB(const u32, const u32);
virtual void TEQ_REG(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void SXTAB16(const u32, const u32);
virtual void TEQ_RSR(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void SXTAH(const u32, const u32);
template<arm_encoding type> void SXTB(const u32, const u32);
template<arm_encoding type> void SXTB16(const u32, const u32);
template<arm_encoding type> void SXTH(const u32, const u32);
virtual void TST_IMM(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void TB_(const u32, const u32);
virtual void TST_REG(const u32 data, const ARMv7_encoding type);
virtual void TST_RSR(const u32 data, const ARMv7_encoding type);
virtual void UADD16(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void TEQ_IMM(const u32, const u32);
virtual void UADD8(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void TEQ_REG(const u32, const u32);
virtual void UASX(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void TEQ_RSR(const u32, const u32);
virtual void UBFX(const u32 data, const ARMv7_encoding type);
virtual void UDIV(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void TST_IMM(const u32, const u32);
virtual void UHADD16(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void TST_REG(const u32, const u32);
virtual void UHADD8(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void TST_RSR(const u32, const u32);
virtual void UHASX(const u32 data, const ARMv7_encoding type);
virtual void UHSAX(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void UADD16(const u32, const u32);
virtual void UHSUB16(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void UADD8(const u32, const u32);
virtual void UHSUB8(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void UASX(const u32, const u32);
virtual void UMAAL(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void UBFX(const u32, const u32);
virtual void UMLAL(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void UDIV(const u32, const u32);
virtual void UMULL(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void UHADD16(const u32, const u32);
virtual void UQADD16(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void UHADD8(const u32, const u32);
virtual void UQADD8(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void UHASX(const u32, const u32);
virtual void UQASX(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void UHSAX(const u32, const u32);
virtual void UQSAX(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void UHSUB16(const u32, const u32);
virtual void UQSUB16(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void UHSUB8(const u32, const u32);
virtual void UQSUB8(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void UMAAL(const u32, const u32);
virtual void USAD8(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void UMLAL(const u32, const u32);
virtual void USADA8(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void UMULL(const u32, const u32);
virtual void USAT(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void UQADD16(const u32, const u32);
virtual void USAT16(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void UQADD8(const u32, const u32);
virtual void USAX(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void UQASX(const u32, const u32);
virtual void USUB16(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void UQSAX(const u32, const u32);
virtual void USUB8(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void UQSUB16(const u32, const u32);
virtual void UXTAB(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void UQSUB8(const u32, const u32);
virtual void UXTAB16(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void USAD8(const u32, const u32);
virtual void UXTAH(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void USADA8(const u32, const u32);
virtual void UXTB(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void USAT(const u32, const u32);
virtual void UXTB16(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void USAT16(const u32, const u32);
virtual void UXTH(const u32 data, const ARMv7_encoding type); template<arm_encoding type> void USAX(const u32, const u32);
#endif template<arm_encoding type> void USUB16(const u32, const u32);
template<arm_encoding type> void USUB8(const u32, const u32);
template<arm_encoding type> void UXTAB(const u32, const u32);
template<arm_encoding type> void UXTAB16(const u32, const u32);
template<arm_encoding type> void UXTAH(const u32, const u32);
template<arm_encoding type> void UXTB(const u32, const u32);
template<arm_encoding type> void UXTB16(const u32, const u32);
template<arm_encoding type> void UXTH(const u32, const u32);
template<arm_encoding type> void VABA_(const u32, const u32);
template<arm_encoding type> void VABD_(const u32, const u32);
template<arm_encoding type> void VABD_FP(const u32, const u32);
template<arm_encoding type> void VABS(const u32, const u32);
template<arm_encoding type> void VAC__(const u32, const u32);
template<arm_encoding type> void VADD(const u32, const u32);
template<arm_encoding type> void VADD_FP(const u32, const u32);
template<arm_encoding type> void VADDHN(const u32, const u32);
template<arm_encoding type> void VADD_(const u32, const u32);
template<arm_encoding type> void VAND(const u32, const u32);
template<arm_encoding type> void VBIC_IMM(const u32, const u32);
template<arm_encoding type> void VBIC_REG(const u32, const u32);
template<arm_encoding type> void VB__(const u32, const u32);
template<arm_encoding type> void VCEQ_REG(const u32, const u32);
template<arm_encoding type> void VCEQ_ZERO(const u32, const u32);
template<arm_encoding type> void VCGE_REG(const u32, const u32);
template<arm_encoding type> void VCGE_ZERO(const u32, const u32);
template<arm_encoding type> void VCGT_REG(const u32, const u32);
template<arm_encoding type> void VCGT_ZERO(const u32, const u32);
template<arm_encoding type> void VCLE_ZERO(const u32, const u32);
template<arm_encoding type> void VCLS(const u32, const u32);
template<arm_encoding type> void VCLT_ZERO(const u32, const u32);
template<arm_encoding type> void VCLZ(const u32, const u32);
template<arm_encoding type> void VCMP_(const u32, const u32);
template<arm_encoding type> void VCNT(const u32, const u32);
template<arm_encoding type> void VCVT_FIA(const u32, const u32);
template<arm_encoding type> void VCVT_FIF(const u32, const u32);
template<arm_encoding type> void VCVT_FFA(const u32, const u32);
template<arm_encoding type> void VCVT_FFF(const u32, const u32);
template<arm_encoding type> void VCVT_DF(const u32, const u32);
template<arm_encoding type> void VCVT_HFA(const u32, const u32);
template<arm_encoding type> void VCVT_HFF(const u32, const u32);
template<arm_encoding type> void VDIV(const u32, const u32);
template<arm_encoding type> void VDUP_S(const u32, const u32);
template<arm_encoding type> void VDUP_R(const u32, const u32);
template<arm_encoding type> void VEOR(const u32, const u32);
template<arm_encoding type> void VEXT(const u32, const u32);
template<arm_encoding type> void VHADDSUB(const u32, const u32);
template<arm_encoding type> void VLD__MS(const u32, const u32);
template<arm_encoding type> void VLD1_SL(const u32, const u32);
template<arm_encoding type> void VLD1_SAL(const u32, const u32);
template<arm_encoding type> void VLD2_SL(const u32, const u32);
template<arm_encoding type> void VLD2_SAL(const u32, const u32);
template<arm_encoding type> void VLD3_SL(const u32, const u32);
template<arm_encoding type> void VLD3_SAL(const u32, const u32);
template<arm_encoding type> void VLD4_SL(const u32, const u32);
template<arm_encoding type> void VLD4_SAL(const u32, const u32);
template<arm_encoding type> void VLDM(const u32, const u32);
template<arm_encoding type> void VLDR(const u32, const u32);
template<arm_encoding type> void VMAXMIN(const u32, const u32);
template<arm_encoding type> void VMAXMIN_FP(const u32, const u32);
template<arm_encoding type> void VML__(const u32, const u32);
template<arm_encoding type> void VML__FP(const u32, const u32);
template<arm_encoding type> void VML__S(const u32, const u32);
template<arm_encoding type> void VMOV_IMM(const u32, const u32);
template<arm_encoding type> void VMOV_REG(const u32, const u32);
template<arm_encoding type> void VMOV_RS(const u32, const u32);
template<arm_encoding type> void VMOV_SR(const u32, const u32);
template<arm_encoding type> void VMOV_RF(const u32, const u32);
template<arm_encoding type> void VMOV_2RF(const u32, const u32);
template<arm_encoding type> void VMOV_2RD(const u32, const u32);
template<arm_encoding type> void VMOVL(const u32, const u32);
template<arm_encoding type> void VMOVN(const u32, const u32);
template<arm_encoding type> void VMRS(const u32, const u32);
template<arm_encoding type> void VMSR(const u32, const u32);
template<arm_encoding type> void VMUL_(const u32, const u32);
template<arm_encoding type> void VMUL_FP(const u32, const u32);
template<arm_encoding type> void VMUL_S(const u32, const u32);
template<arm_encoding type> void VMVN_IMM(const u32, const u32);
template<arm_encoding type> void VMVN_REG(const u32, const u32);
template<arm_encoding type> void VNEG(const u32, const u32);
template<arm_encoding type> void VNM__(const u32, const u32);
template<arm_encoding type> void VORN_REG(const u32, const u32);
template<arm_encoding type> void VORR_IMM(const u32, const u32);
template<arm_encoding type> void VORR_REG(const u32, const u32);
template<arm_encoding type> void VPADAL(const u32, const u32);
template<arm_encoding type> void VPADD(const u32, const u32);
template<arm_encoding type> void VPADD_FP(const u32, const u32);
template<arm_encoding type> void VPADDL(const u32, const u32);
template<arm_encoding type> void VPMAXMIN(const u32, const u32);
template<arm_encoding type> void VPMAXMIN_FP(const u32, const u32);
template<arm_encoding type> void VPOP(const u32, const u32);
template<arm_encoding type> void VPUSH(const u32, const u32);
template<arm_encoding type> void VQABS(const u32, const u32);
template<arm_encoding type> void VQADD(const u32, const u32);
template<arm_encoding type> void VQDML_L(const u32, const u32);
template<arm_encoding type> void VQDMULH(const u32, const u32);
template<arm_encoding type> void VQDMULL(const u32, const u32);
template<arm_encoding type> void VQMOV_N(const u32, const u32);
template<arm_encoding type> void VQNEG(const u32, const u32);
template<arm_encoding type> void VQRDMULH(const u32, const u32);
template<arm_encoding type> void VQRSHL(const u32, const u32);
template<arm_encoding type> void VQRSHR_N(const u32, const u32);
template<arm_encoding type> void VQSHL_REG(const u32, const u32);
template<arm_encoding type> void VQSHL_IMM(const u32, const u32);
template<arm_encoding type> void VQSHR_N(const u32, const u32);
template<arm_encoding type> void VQSUB(const u32, const u32);
template<arm_encoding type> void VRADDHN(const u32, const u32);
template<arm_encoding type> void VRECPE(const u32, const u32);
template<arm_encoding type> void VRECPS(const u32, const u32);
template<arm_encoding type> void VREV__(const u32, const u32);
template<arm_encoding type> void VRHADD(const u32, const u32);
template<arm_encoding type> void VRSHL(const u32, const u32);
template<arm_encoding type> void VRSHR(const u32, const u32);
template<arm_encoding type> void VRSHRN(const u32, const u32);
template<arm_encoding type> void VRSQRTE(const u32, const u32);
template<arm_encoding type> void VRSQRTS(const u32, const u32);
template<arm_encoding type> void VRSRA(const u32, const u32);
template<arm_encoding type> void VRSUBHN(const u32, const u32);
template<arm_encoding type> void VSHL_IMM(const u32, const u32);
template<arm_encoding type> void VSHL_REG(const u32, const u32);
template<arm_encoding type> void VSHLL(const u32, const u32);
template<arm_encoding type> void VSHR(const u32, const u32);
template<arm_encoding type> void VSHRN(const u32, const u32);
template<arm_encoding type> void VSLI(const u32, const u32);
template<arm_encoding type> void VSQRT(const u32, const u32);
template<arm_encoding type> void VSRA(const u32, const u32);
template<arm_encoding type> void VSRI(const u32, const u32);
template<arm_encoding type> void VST__MS(const u32, const u32);
template<arm_encoding type> void VST1_SL(const u32, const u32);
template<arm_encoding type> void VST2_SL(const u32, const u32);
template<arm_encoding type> void VST3_SL(const u32, const u32);
template<arm_encoding type> void VST4_SL(const u32, const u32);
template<arm_encoding type> void VSTM(const u32, const u32);
template<arm_encoding type> void VSTR(const u32, const u32);
template<arm_encoding type> void VSUB(const u32, const u32);
template<arm_encoding type> void VSUB_FP(const u32, const u32);
template<arm_encoding type> void VSUBHN(const u32, const u32);
template<arm_encoding type> void VSUB_(const u32, const u32);
template<arm_encoding type> void VSWP(const u32, const u32);
template<arm_encoding type> void VTB_(const u32, const u32);
template<arm_encoding type> void VTRN(const u32, const u32);
template<arm_encoding type> void VTST(const u32, const u32);
template<arm_encoding type> void VUZP(const u32, const u32);
template<arm_encoding type> void VZIP(const u32, const u32);
template<arm_encoding type> void WFE(const u32, const u32);
template<arm_encoding type> void WFI(const u32, const u32);
template<arm_encoding type> void YIELD(const u32, const u32);
public:
u32 disasm(u32 pc) override;
}; };

View file

@ -0,0 +1,59 @@
#include "stdafx.h"
#include "ARMv7Module.h"
// Get function name by FNID
extern std::string arm_get_function_name(const std::string& module, u32 fnid)
{
// Check registered functions
if (const auto sm = arm_module_manager::get_module(module))
{
const auto found = sm->functions.find(fnid);
if (found != sm->functions.end())
{
return found->second.name;
}
}
return fmt::format("0x%08X", fnid);
}
// Get variable name by VNID
extern std::string arm_get_variable_name(const std::string& module, u32 vnid)
{
// Check registered variables
if (const auto sm = arm_module_manager::get_module(module))
{
const auto found = sm->variables.find(vnid);
if (found != sm->variables.end())
{
return found->second.name;
}
}
return fmt::format("0x%08X", vnid);
}
s32 arm_error_code::report(s32 error, const char* text)
{
if (auto thread = get_current_cpu_thread())
{
if (thread->type == cpu_type::arm)
{
if (auto func = static_cast<ARMv7Thread*>(thread)->last_function)
{
LOG_ERROR(ARMv7, "Function '%s' failed with 0x%08x : %s", func, error, text);
}
else
{
LOG_ERROR(ARMv7, "Unknown function failed with 0x%08x : %s", error, text);
}
return error;
}
}
LOG_ERROR(ARMv7, "Illegal call to ppu_report_error(0x%x, '%s')!");
return error;
}

View file

@ -0,0 +1,487 @@
#pragma once
#include "ARMv7Thread.h"
using arm_function_t = void(*)(ARMv7Thread&);
#define BIND_FUNC(func) [](ARMv7Thread& cpu){ cpu.last_function = #func; arm_func_detail::do_call(cpu, func); }
struct arm_va_args_t
{
u32 count; // Number of 32-bit args passed
};
namespace arm_func_detail
{
enum arg_class : u32
{
ARG_GENERAL,
ARG_FLOAT,
ARG_VECTOR,
ARG_STACK,
ARG_CONTEXT,
ARG_VARIADIC,
ARG_UNKNOWN,
};
static const auto FIXED_STACK_FRAME_SIZE = 0x80;
template<typename T, arg_class type, u32 g_count, u32 f_count, u32 v_count>
struct bind_arg
{
static_assert(type == ARG_GENERAL, "Unknown function argument type");
static_assert(!std::is_pointer<T>::value, "Invalid function argument type (pointer)");
static_assert(!std::is_reference<T>::value, "Invalid function argument type (reference)");
static_assert(sizeof(T) <= 4, "Invalid function argument type for ARG_GENERAL");
force_inline static T get_arg(ARMv7Thread& cpu)
{
return arm_gpr_cast<T>(cpu.GPR[g_count - 1]);
}
force_inline static void put_arg(ARMv7Thread& cpu, const T& arg)
{
cpu.GPR[g_count - 1] = arm_gpr_cast(arg);
}
};
template<u32 g_count, u32 f_count, u32 v_count>
struct bind_arg<u64, ARG_GENERAL, g_count, f_count, v_count>
{
// first u64 argument is passed in r0-r1, second one is passed in r2-r3 (if g_count = 3)
static_assert(g_count == 2 || g_count == 4, "Wrong u64 argument position");
force_inline static u64 get_arg(ARMv7Thread& cpu)
{
return cpu.GPR_D[(g_count - 1) >> 1];
}
force_inline static void put_arg(ARMv7Thread& cpu, u64 arg)
{
cpu.GPR_D[(g_count - 1) >> 1] = arg;
}
};
template<u32 g_count, u32 f_count, u32 v_count>
struct bind_arg<s64, ARG_GENERAL, g_count, f_count, v_count>
{
static_assert(g_count == 2 || g_count == 4, "Wrong s64 argument position");
force_inline static s64 get_arg(ARMv7Thread& cpu)
{
return cpu.GPR_D[(g_count - 1) >> 1];
}
force_inline static void put_arg(ARMv7Thread& cpu, s64 arg)
{
cpu.GPR_D[(g_count - 1) >> 1] = arg;
}
};
template<typename T, u32 g_count, u32 f_count, u32 v_count>
struct bind_arg<T, ARG_FLOAT, g_count, f_count, v_count>
{
static_assert(f_count <= 0, "TODO: Unsupported argument type (float)");
static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_FLOAT");
force_inline static T get_arg(ARMv7Thread& cpu)
{
}
force_inline static void put_arg(ARMv7Thread& cpu, const T& arg)
{
}
};
template<typename T, u32 g_count, u32 f_count, u32 v_count>
struct bind_arg<T, ARG_VECTOR, g_count, f_count, v_count>
{
static_assert(v_count <= 0, "TODO: Unsupported argument type (vector)");
static_assert(std::is_same<CV T, CV v128>::value, "Invalid function argument type for ARG_VECTOR");
force_inline static T get_arg(ARMv7Thread& cpu)
{
}
force_inline static void put_arg(ARMv7Thread& cpu, const T& arg)
{
}
};
template<typename T, u32 g_count, u32 f_count, u32 v_count>
struct bind_arg<T, ARG_STACK, g_count, f_count, v_count>
{
static_assert(f_count <= 0, "TODO: Unsupported stack argument type (float)");
static_assert(v_count <= 0, "TODO: Unsupported stack argument type (vector)");
static_assert(sizeof(T) <= 4, "Invalid function argument type for ARG_STACK");
force_inline static T get_arg(ARMv7Thread& cpu)
{
// TODO: check
return arm_gpr_cast<T, u32>(vm::psv::read32(cpu.SP + sizeof(u32) * (g_count - 5)));
}
force_inline static void put_arg(ARMv7Thread& cpu, const T& arg)
{
// TODO: check
const int stack_pos = (g_count - 5) * 4 - FIXED_STACK_FRAME_SIZE;
static_assert(stack_pos < 0, "TODO: Increase fixed stack frame size (arg count limit broken)");
vm::psv::write32(cpu.SP + stack_pos, arm_gpr_cast(arg));
}
};
template<u32 g_count, u32 f_count, u32 v_count>
struct bind_arg<u64, ARG_STACK, g_count, f_count, v_count>
{
force_inline static u64 get_arg(ARMv7Thread& cpu)
{
// TODO: check
return vm::psv::read64(cpu.SP + sizeof(u32) * (g_count - 6));
}
force_inline static void put_arg(ARMv7Thread& cpu, u64 arg)
{
// TODO: check
const int stack_pos = (g_count - 6) * 4 - FIXED_STACK_FRAME_SIZE;
static_assert(stack_pos < -4, "TODO: Increase fixed stack frame size (arg count limit broken)");
vm::psv::write64(cpu.SP + stack_pos, arg);
}
};
template<u32 g_count, u32 f_count, u32 v_count>
struct bind_arg<s64, ARG_STACK, g_count, f_count, v_count>
{
force_inline static s64 get_arg(ARMv7Thread& cpu)
{
// TODO: check
return vm::psv::read64(cpu.SP + sizeof(u32) * (g_count - 6));
}
force_inline static void put_arg(ARMv7Thread& cpu, s64 arg)
{
// TODO: check
const int stack_pos = (g_count - 6) * 4 - FIXED_STACK_FRAME_SIZE;
static_assert(stack_pos < -4, "TODO: Increase fixed stack frame size (arg count limit broken)");
vm::psv::write64(cpu.SP + stack_pos, arg);
}
};
template<typename T, u32 g_count, u32 f_count, u32 v_count>
struct bind_arg<T, ARG_CONTEXT, g_count, f_count, v_count>
{
static_assert(std::is_same<T, ARMv7Thread&>::value, "Invalid function argument type for ARG_CONTEXT");
force_inline static ARMv7Thread& get_arg(ARMv7Thread& cpu)
{
return cpu;
}
force_inline static void put_arg(ARMv7Thread& cpu, ARMv7Thread& arg)
{
}
};
template<typename T, u32 g_count, u32 f_count, u32 v_count>
struct bind_arg<T, ARG_VARIADIC, g_count, f_count, v_count>
{
static_assert(std::is_same<CV T, CV arm_va_args_t>::value, "Invalid function argument type for ARG_VARIADIC");
force_inline static arm_va_args_t get_arg(ARMv7Thread& cpu)
{
return{ g_count };
}
};
template<typename T, arg_class type>
struct bind_result
{
static_assert(type != ARG_FLOAT, "TODO: Unsupported funcion result type (float)");
static_assert(type != ARG_VECTOR, "TODO: Unsupported funcion result type (vector)");
static_assert(type == ARG_GENERAL, "Wrong use of bind_result template");
static_assert(sizeof(T) <= 4, "Invalid function result type for ARG_GENERAL");
force_inline static T get_result(ARMv7Thread& cpu)
{
return arm_gpr_cast<T>(cpu.GPR[0]);
}
force_inline static void put_result(ARMv7Thread& cpu, const T& result)
{
cpu.GPR[0] = arm_gpr_cast(result);
}
};
template<>
struct bind_result<u64, ARG_GENERAL>
{
force_inline static u64 get_result(ARMv7Thread& cpu)
{
return cpu.GPR_D[0];
}
force_inline static void put_result(ARMv7Thread& cpu, u64 result)
{
cpu.GPR_D[0] = result;
}
};
template<>
struct bind_result<s64, ARG_GENERAL>
{
force_inline static s64 get_result(ARMv7Thread& cpu)
{
return cpu.GPR_D[0];
}
force_inline static void put_result(ARMv7Thread& cpu, s64 result)
{
cpu.GPR_D[0] = result;
}
};
//template<typename T>
//struct bind_result<T, ARG_FLOAT>
//{
// static_assert(sizeof(T) <= 8, "Invalid function result type for ARG_FLOAT");
// static force_inline void put_result(ARMv7Thread& cpu, const T& result)
// {
// }
//};
//template<typename T>
//struct bind_result<T, ARG_VECTOR>
//{
// static_assert(std::is_same<std::remove_cv_t<T>, v128>::value, "Invalid function result type for ARG_VECTOR");
// static force_inline void put_result(ARMv7Thread& cpu, const T& result)
// {
// }
//};
template<typename RT>
struct result_type
{
static_assert(!std::is_pointer<RT>::value, "Invalid function result type (pointer)");
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_vector = std::is_same<CV RT, CV v128>::value;
static const arg_class value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL);
};
template<typename T, u32 g_count, u32 f_count, u32 v_count>
struct arg_type
{
// TODO: check calculations
static const bool is_float = std::is_floating_point<T>::value;
static const bool is_vector = std::is_same<CV T, CV v128>::value;
static const bool is_context = std::is_same<T, ARMv7Thread&>::value;
static const bool is_variadic = std::is_same<CV T, CV arm_va_args_t>::value;
static const bool is_general = !is_float && !is_vector && !is_context && !is_variadic;
static const u32 g_align = ALIGN_32(T) > 4 ? ALIGN_32(T) >> 2 : 1;
static const u32 g_value = is_general ? ((g_count + (g_align - 1)) & ~(g_align - 1)) + (g_align) : g_count;
static const u32 f_value = f_count + is_float;
static const u32 v_value = v_count + is_vector;
static const arg_class value =
is_general ? (g_value > 4 ? ARG_STACK : ARG_GENERAL) :
is_float ? (f_value > 9000 ? ARG_STACK : ARG_FLOAT) :
is_vector ? (v_value > 9000 ? ARG_STACK : ARG_VECTOR) :
is_context ? ARG_CONTEXT :
is_variadic ? ARG_VARIADIC :
ARG_UNKNOWN;
};
// wrapper for variadic argument info list, each value contains packed argument type and counts of GENERAL, FLOAT and VECTOR arguments
template<u32... Values> struct arg_info_pack_t;
template<u32 First, u32... Values> struct arg_info_pack_t<First, Values...>
{
static const u32 last_value = arg_info_pack_t<Values...>::last_value;
};
template<u32 First> struct arg_info_pack_t<First>
{
static const u32 last_value = First;
};
template<> struct arg_info_pack_t<>
{
static const u32 last_value = 0;
};
// argument type + g/f/v_count unpacker
template<typename T, u32 type_pack> struct bind_arg_packed
{
force_inline static T get_arg(ARMv7Thread& cpu)
{
return bind_arg<T, static_cast<arg_class>(type_pack & 0xff), (type_pack >> 8) & 0xff, (type_pack >> 16) & 0xff, (type_pack >> 24)>::get_arg(cpu);
}
};
template<u32... Info, typename RT, typename... Args>
force_inline RT call(ARMv7Thread& cpu, RT(*func)(Args...), arg_info_pack_t<Info...> info)
{
// do the actual function call when all arguments are prepared (simultaneous unpacking of Args... and Info...)
return func(bind_arg_packed<Args, Info>::get_arg(cpu)...);
}
template<typename T, typename... Types, u32... Info, typename RT, typename... Args>
force_inline RT call(ARMv7Thread& cpu, RT(*func)(Args...), arg_info_pack_t<Info...> info)
{
// unpack previous type counts (0/0/0 for the first time)
const u32 g_count = (info.last_value >> 8) & 0xff;
const u32 f_count = (info.last_value >> 16) & 0xff;
const u32 v_count = (info.last_value >> 24);
using type = arg_type<T, g_count, f_count, v_count>;
const arg_class t = type::value;
const u32 g = type::g_value;
const u32 f = type::f_value;
const u32 v = type::v_value;
return call<Types...>(cpu, func, arg_info_pack_t<Info..., t | (g << 8) | (f << 16) | (v << 24)>{});
}
template<u32 g_count, u32 f_count, u32 v_count>
force_inline static bool put_func_args(ARMv7Thread& cpu)
{
// terminator
return false;
}
template<u32 g_count, u32 f_count, u32 v_count, typename T1, typename... T>
force_inline static bool put_func_args(ARMv7Thread& cpu, T1 arg, T... args)
{
using type = arg_type<T1, g_count, f_count, v_count>;
const arg_class t = type::value;
const u32 g = type::g_value;
const u32 f = type::f_value;
const u32 v = type::v_value;
bind_arg<T1, t, g, f, v>::put_arg(cpu, arg);
// return true if stack was used
return put_func_args<g, f, v>(cpu, args...) || (t == ARG_STACK);
}
template<typename RT, typename... T>
struct func_binder;
template<typename... T>
struct func_binder<void, T...>
{
using func_t = void(*)(T...);
static void do_call(ARMv7Thread& cpu, func_t func)
{
call<T...>(cpu, func, arg_info_pack_t<>{});
}
};
template<typename RT, typename... T>
struct func_binder
{
using func_t = RT(*)(T...);
static void do_call(ARMv7Thread& cpu, func_t func)
{
bind_result<RT, result_type<RT>::value>::put_result(cpu, call<T...>(cpu, func, arg_info_pack_t<>{}));
}
};
template<typename RT, typename... T>
struct func_caller
{
force_inline static RT call(ARMv7Thread& cpu, u32 addr, T... args)
{
func_caller<void, T...>::call(cpu, addr, args...);
return bind_result<RT, result_type<RT>::value>::get_result(cpu);
}
};
template<typename... T>
struct func_caller<void, T...>
{
force_inline static void call(ARMv7Thread& cpu, u32 addr, T... args)
{
if (put_func_args<0, 0, 0, T...>(cpu, args...))
{
cpu.SP -= FIXED_STACK_FRAME_SIZE;
cpu.fast_call(addr);
cpu.SP += FIXED_STACK_FRAME_SIZE;
}
else
{
cpu.fast_call(addr);
}
}
};
template<typename RT, typename... T> force_inline void do_call(ARMv7Thread& cpu, RT(*func)(T...))
{
func_binder<RT, T...>::do_call(cpu, func);
}
}
class arm_function_manager
{
// Global variable for each registered function
template<typename T, T Func>
struct registered
{
static u32 index;
};
// Access global function list
static never_inline auto& access()
{
static std::vector<arm_function_t> list
{
nullptr,
[](ARMv7Thread& cpu) { cpu.state += cpu_state::ret; },
};
return list;
}
static never_inline u32 add_function(arm_function_t function)
{
auto& list = access();
list.push_back(function);
return ::size32(list) - 1;
}
public:
// Register function (shall only be called during global initialization)
template<typename T, T Func>
static inline u32 register_function(arm_function_t func)
{
return registered<T, Func>::index = add_function(func);
}
// Get function index
template<typename T, T Func>
static inline u32 get_index()
{
return registered<T, Func>::index;
}
// Read all registered functions
static inline const auto& get()
{
return access();
}
};
template<typename T, T Func>
u32 arm_function_manager::registered<T, Func>::index = 0;
#define FIND_FUNC(func) arm_function_manager::get_index<decltype(&func), &func>()

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,578 @@
#include "stdafx.h"
#include "Loader/ELF.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/IdManager.h"
#include "ARMv7Thread.h"
#include "ARMv7Opcodes.h"
#include "ARMv7Function.h"
#include "ARMv7Module.h"
extern void armv7_init_tls();
extern std::string arm_get_function_name(const std::string& module, u32 fnid);
extern std::string arm_get_variable_name(const std::string& module, u32 vnid);
// Function lookup table. Not supposed to grow after emulation start.
std::vector<arm_function_t> g_arm_function_cache;
extern void arm_execute_function(ARMv7Thread& cpu, u32 index)
{
if (index < g_arm_function_cache.size())
{
if (const auto func = g_arm_function_cache[index])
{
const auto previous_function = cpu.last_function; // TODO: use gsl::finally or something
try
{
func(cpu);
}
catch (const std::exception&)
{
LOG_ERROR(ARMv7, "Function '%s' aborted", cpu.last_function);
cpu.last_function = previous_function;
throw;
}
catch (EmulationStopped)
{
LOG_WARNING(ARMv7, "Function '%s' aborted", cpu.last_function);
cpu.last_function = previous_function;
throw;
}
LOG_TRACE(ARMv7, "Function '%s' finished, r0=0x%x", cpu.last_function, cpu.GPR[0]);
cpu.last_function = previous_function;
return;
}
}
throw fmt::exception("Function not registered (%u)" HERE, index);
}
arm_static_module::arm_static_module(const char* name)
: name(name)
{
arm_module_manager::register_module(this);
}
static void arm_initialize_modules()
{
const std::initializer_list<const arm_static_module*> registered
{
&arm_module_manager::SceAppMgr,
&arm_module_manager::SceAppUtil,
&arm_module_manager::SceAudio,
&arm_module_manager::SceAudiodec,
&arm_module_manager::SceAudioenc,
&arm_module_manager::SceAudioIn,
&arm_module_manager::SceCamera,
&arm_module_manager::SceCodecEngine,
&arm_module_manager::SceCommonDialog,
&arm_module_manager::SceCpu,
&arm_module_manager::SceCtrl,
&arm_module_manager::SceDbg,
&arm_module_manager::SceDebugLed,
&arm_module_manager::SceDeci4p,
&arm_module_manager::SceDeflt,
&arm_module_manager::SceDipsw,
&arm_module_manager::SceDisplay,
&arm_module_manager::SceDisplayUser,
&arm_module_manager::SceFiber,
&arm_module_manager::SceFios,
&arm_module_manager::SceFpu,
&arm_module_manager::SceGxm,
&arm_module_manager::SceHttp,
&arm_module_manager::SceIme,
&arm_module_manager::SceIofilemgr,
&arm_module_manager::SceJpeg,
&arm_module_manager::SceJpegEnc,
&arm_module_manager::SceLibc,
&arm_module_manager::SceLibKernel,
&arm_module_manager::SceLibm,
&arm_module_manager::SceLibstdcxx,
&arm_module_manager::SceLibXml,
&arm_module_manager::SceLiveArea,
&arm_module_manager::SceLocation,
&arm_module_manager::SceMd5,
&arm_module_manager::SceModulemgr,
&arm_module_manager::SceMotion,
&arm_module_manager::SceMt19937,
&arm_module_manager::SceNet,
&arm_module_manager::SceNetCtl,
&arm_module_manager::SceNgs,
&arm_module_manager::SceNpBasic,
&arm_module_manager::SceNpCommon,
&arm_module_manager::SceNpManager,
&arm_module_manager::SceNpMatching,
&arm_module_manager::SceNpScore,
&arm_module_manager::SceNpUtility,
&arm_module_manager::ScePerf,
&arm_module_manager::ScePgf,
&arm_module_manager::ScePhotoExport,
&arm_module_manager::SceProcessmgr,
&arm_module_manager::SceRazorCapture,
&arm_module_manager::SceRtc,
&arm_module_manager::SceSas,
&arm_module_manager::SceScreenShot,
&arm_module_manager::SceSfmt,
&arm_module_manager::SceSha,
&arm_module_manager::SceSqlite,
&arm_module_manager::SceSsl,
&arm_module_manager::SceStdio,
&arm_module_manager::SceSulpha,
&arm_module_manager::SceSysmem,
&arm_module_manager::SceSysmodule,
&arm_module_manager::SceSystemGesture,
&arm_module_manager::SceThreadmgr,
&arm_module_manager::SceTouch,
&arm_module_manager::SceUlt,
&arm_module_manager::SceVideodec,
&arm_module_manager::SceVoice,
&arm_module_manager::SceVoiceQoS,
};
// Reinitialize function cache
g_arm_function_cache = arm_function_manager::get();
// "Use" all the modules for correct linkage
for (auto& module : registered)
{
LOG_TRACE(LOADER, "Registered static module: %s", module->name);
for (auto& function : module->functions)
{
LOG_TRACE(LOADER, "** 0x%08X: %s", function.first, function.second.name);
}
for (auto& variable : module->variables)
{
LOG_TRACE(LOADER, "** &0x%08X: %s (size=0x%x, align=0x%x)", variable.first, variable.second.name, variable.second.size, variable.second.align);
variable.second.var->set(0);
}
}
}
struct psv_moduleinfo_t
{
le_t<u16> attr; // ???
u8 major; // ???
u8 minor; // ???
char name[24]; // ???
le_t<u32> unk0;
le_t<u32> unk1;
le_t<u32> libent_top;
le_t<u32> libent_end;
le_t<u32> libstub_top;
le_t<u32> libstub_end;
le_t<u32> data[1]; // ...
};
struct psv_libent_t
{
le_t<u16> size; // ???
le_t<u16> unk0;
le_t<u16> unk1;
le_t<u16> fcount;
le_t<u16> vcount;
le_t<u16> unk2;
le_t<u32> unk3;
le_t<u32> data[1]; // ...
};
struct psv_libstub_t
{
le_t<u16> size; // 0x2C, 0x34
le_t<u16> unk0; // (usually 1, 5 for sceLibKernel)
le_t<u16> unk1; // (usually 0)
le_t<u16> fcount;
le_t<u16> vcount;
le_t<u16> unk2;
le_t<u32> unk3;
le_t<u32> data[1]; // ...
};
struct psv_libcparam_t
{
le_t<u32> size;
le_t<u32> unk0;
vm::lcptr<u32> sceLibcHeapSize;
vm::lcptr<u32> sceLibcHeapSizeDefault;
vm::lcptr<u32> sceLibcHeapExtendedAlloc;
vm::lcptr<u32> sceLibcHeapDelayedAlloc;
le_t<u32> unk1;
le_t<u32> unk2;
vm::lptr<u32> __sce_libcmallocreplace;
vm::lptr<u32> __sce_libcnewreplace;
};
struct psv_process_param_t
{
le_t<u32> size; // 0x00000030
nse_t<u32> ver; // 'PSP2'
le_t<u32> unk0; // 0x00000005
le_t<u32> unk1;
vm::lcptr<char> sceUserMainThreadName;
vm::lcptr<s32> sceUserMainThreadPriority;
vm::lcptr<u32> sceUserMainThreadStackSize;
vm::lcptr<u32> sceUserMainThreadAttribute;
vm::lcptr<char> sceProcessName;
vm::lcptr<u32> sce_process_preload_disabled;
vm::lcptr<u32> sceUserMainThreadCpuAffinityMask;
vm::lcptr<psv_libcparam_t> sce_libcparam;
};
static void arm_patch_refs(u32 refs, u32 addr)
{
auto ptr = vm::cptr<u32>::make(refs);
LOG_NOTICE(LOADER, "**** Processing refs at 0x%x:", ptr);
if (ptr[0] != 0xff || ptr[1] != addr)
{
LOG_ERROR(LOADER, "**** Unexpected ref format ([0]=0x%x, [1]=0x%x)", ptr[0], ptr[1]);
}
else for (ptr += 2; *ptr; ptr++)
{
switch (u32 code = *ptr)
{
case 0x0000002f: // movw r*,# instruction
{
const u32 raddr = *++ptr;
vm::write16(raddr + 0, vm::read16(raddr + 0) | (addr & 0x800) >> 1 | (addr & 0xf000) >> 12);
vm::write16(raddr + 2, vm::read16(raddr + 2) | (addr & 0x700) << 4 | (addr & 0xff));
LOG_NOTICE(LOADER, "**** MOVW written at *0x%x", raddr);
break;
}
case 0x00000030: // movt r*,# instruction
{
const u32 raddr = *++ptr;
vm::write16(raddr + 0, vm::read16(raddr + 0) | (addr & 0x8000000) >> 17 | (addr & 0xf0000000) >> 28);
vm::write16(raddr + 2, vm::read16(raddr + 2) | (addr & 0x7000000) >> 12 | (addr & 0xff0000) >> 16);
LOG_NOTICE(LOADER, "**** MOVT written at *0x%x", raddr);
break;
}
default:
{
LOG_ERROR(LOADER, "**** Unknown ref code found (0x%08x)", code);
}
}
}
}
template<>
void arm_exec_loader::load() const
{
arm_initialize_modules();
vm::cptr<psv_moduleinfo_t> module_info{};
vm::cptr<psv_libent_t> libent{};
vm::cptr<psv_libstub_t> libstub{};
vm::cptr<psv_process_param_t> proc_param{};
u32 entry_point{};
u32 start_addr{};
u32 arm_exidx{};
u32 arm_extab{};
u32 tls_faddr{};
u32 tls_fsize{};
u32 tls_vsize{};
for (const auto& prog : progs)
{
if (prog.p_type == 0x1 /* LOAD */ && prog.p_memsz)
{
if (!vm::falloc(prog.p_vaddr, prog.p_memsz, vm::main))
{
throw fmt::exception("vm::falloc() failed (addr=0x%x, size=0x%x)", prog.p_vaddr, prog.p_memsz);
}
if (prog.p_paddr)
{
module_info.set(prog.p_vaddr + (prog.p_paddr - prog.p_offset));
LOG_NOTICE(LOADER, "Found program with p_paddr=0x%x", prog.p_paddr);
}
if (!start_addr)
{
start_addr = prog.p_vaddr;
}
std::memcpy(vm::base(prog.p_vaddr), prog.bin.data(), prog.p_filesz);
}
}
if (!module_info) module_info.set(start_addr + header.e_entry);
if (!libent) libent.set(start_addr + module_info->libent_top);
if (!libstub) libstub.set(start_addr + module_info->libstub_top);
LOG_NOTICE(LOADER, "__sce_moduleinfo(*0x%x) analysis...", module_info);
if (module_info->data[2] == 0xffffffff)
{
arm_exidx = module_info->data[3];
arm_extab = module_info->data[4];
tls_faddr = module_info->data[5];
tls_fsize = module_info->data[6];
tls_vsize = module_info->data[7];
}
else if (module_info->data[5] == 0xffffffff)
{
tls_faddr = module_info->data[1]; // Guess
tls_fsize = module_info->data[2];
tls_vsize = module_info->data[3];
arm_exidx = module_info->data[6];
arm_extab = module_info->data[8];
}
else
{
LOG_ERROR(LOADER, "Failed to recognize __sce_moduleinfo format");
}
LOG_NOTICE(LOADER, "** arm_exidx=0x%x", arm_exidx);
LOG_NOTICE(LOADER, "** arm_extab=0x%x", arm_extab);
LOG_NOTICE(LOADER, "** tls_faddr=0x%x", tls_faddr);
LOG_NOTICE(LOADER, "** tls_fsize=0x%x", tls_fsize);
LOG_NOTICE(LOADER, "** tls_vsize=0x%x", tls_vsize);
Emu.SetTLSData(tls_faddr + start_addr, tls_fsize, tls_vsize);
// Process exports
while (libent.addr() < start_addr + module_info->libent_end)
{
const u32 size = libent->size;
// TODO: check addresses
if (size != 0x1c && size != 0x20)
{
LOG_ERROR(LOADER, "Unknown libent size (0x%x) at *0x%x", libent->size, libent);
}
else
{
LOG_NOTICE(LOADER, "Loading libent at *0x%x", libent);
LOG_NOTICE(LOADER, "** 0x%x, 0x%x", libent->unk0, libent->unk1);
LOG_NOTICE(LOADER, "** Functions: %u", libent->fcount);
LOG_NOTICE(LOADER, "** Variables: %u", libent->vcount);
LOG_NOTICE(LOADER, "** 0x%x, 0x%08x", libent->unk2, libent->unk3);
const auto export_nids = vm::cptr<u32>::make(libent->data[size == 0x20 ? 2 : 1]);
const auto export_data = vm::cptr<u32>::make(libent->data[size == 0x20 ? 3 : 2]);
for (u32 i = 0, count = export_data - export_nids; i < count; i++)
{
const u32 nid = export_nids[i];
const u32 addr = export_data[i];
// Known exports
switch (nid)
{
case 0x935cd196: // set entry point
{
entry_point = addr;
break;
}
case 0x6c2224ba: // __sce_moduleinfo
{
ASSERT(addr == module_info.addr());
break;
}
case 0x70fba1e7: // __sce_process_param
{
proc_param.set(addr);
break;
}
default:
{
LOG_ERROR(LOADER, "** Unknown export '0x%08X' (*0x%x)", nid, addr);
}
}
}
}
// Next entry
libent.set(libent.addr() + libent->size);
}
// Process imports
while (libstub.addr() < start_addr + module_info->libstub_end)
{
const u32 size = libstub->size;
// TODO: check addresses
if (size != 0x2c && size != 0x34)
{
LOG_ERROR(LOADER, "Unknown libstub size (0x%x) at *0x%x)", libstub->size, libstub);
}
else
{
const std::string module_name(vm::_ptr<char>(libstub->data[size == 0x34 ? 1 : 0]));
LOG_NOTICE(LOADER, "Loading libstub at 0x%x: %s", libstub, module_name);
const auto _sm = arm_module_manager::get_module(module_name);
if (!_sm)
{
LOG_ERROR(LOADER, "** Unknown module '%s'", module_name);
}
else
{
// Allocate HLE variables (TODO)
for (auto& var : _sm->variables)
{
var.second.var->set(vm::alloc(var.second.size, vm::main, std::max<u32>(var.second.align, 4096)));
LOG_WARNING(LOADER, "** Allocated variable '%s' in module '%s' at *0x%x", var.second.name, module_name, var.second.var->addr());
}
// Initialize HLE variables (TODO)
for (auto& var : _sm->variables)
{
var.second.init();
}
}
LOG_NOTICE(LOADER, "** 0x%x, 0x%x", libstub->unk0, libstub->unk1);
LOG_NOTICE(LOADER, "** Functions: %u", libstub->fcount);
LOG_NOTICE(LOADER, "** Variables: %u", libstub->vcount);
LOG_NOTICE(LOADER, "** 0x%x, 0x%08x", libstub->unk2, libstub->unk3);
const auto fnids = vm::cptr<u32>::make(libstub->data[size == 0x34 ? 3 : 1]);
const auto fstubs = vm::cptr<u32>::make(libstub->data[size == 0x34 ? 4 : 2]);
for (u32 j = 0; j < libstub->fcount; j++)
{
const u32 fnid = fnids[j];
const u32 faddr = fstubs[j];
u32 index = 0;
const auto fstub = vm::ptr<u32>::make(faddr);
const auto fname = arm_get_function_name(module_name, fnid);
if (_sm && _sm->functions.count(fnid))
{
index = _sm->functions.at(fnid).index;
LOG_NOTICE(LOADER, "** Imported function '%s' in module '%s' (*0x%x)", fname, module_name, faddr);
}
else
{
// TODO
index = ::size32(g_arm_function_cache);
g_arm_function_cache.emplace_back();
LOG_ERROR(LOADER, "** Unknown function '%s' in module '%s' (*0x%x) -> index %u", fname, module_name, faddr, index);
}
// Check import stub
if (fstub[2] != 0xE1A00000)
{
LOG_ERROR(LOADER, "**** Unexpected import function stub (*0x%x, [2]=0x%08x)", faddr, fstub[2]);
}
// Process refs
if (const u32 refs = fstub[3])
{
arm_patch_refs(refs, faddr);
}
// Install HACK instruction (ARM)
fstub[0] = 0xe0700090 | arm_code::hack<arm_encoding::A1>::index::insert(index);
}
const auto vnids = vm::cptr<u32>::make(libstub->data[size == 0x34 ? 5 : 3]);
const auto vstub = vm::cptr<u32>::make(libstub->data[size == 0x34 ? 6 : 4]);
for (u32 j = 0; j < libstub->vcount; j++)
{
const u32 vnid = vnids[j];
const u32 refs = vstub[j];
// Static variable
if (const auto _sv = _sm && _sm->variables.count(vnid) ? &_sm->variables.at(vnid) : nullptr)
{
LOG_NOTICE(LOADER, "** Imported variable '%s' in module '%s' (refs=*0x%x)", arm_get_variable_name(module_name, vnid), module_name, refs);
arm_patch_refs(refs, _sv->var->addr());
}
else
{
LOG_FATAL(LOADER, "** Unknown variable '%s' in module '%s' (refs=*0x%x)", arm_get_variable_name(module_name, vnid), module_name, refs);
}
}
}
// Next lib
libstub.set(libstub.addr() + size);
}
LOG_NOTICE(LOADER, "__sce_process_param(*0x%x) analysis...", proc_param);
ASSERT(proc_param->size >= sizeof(psv_process_param_t));
ASSERT(proc_param->ver == "PSP2"_u32);
LOG_NOTICE(LOADER, "*** size=0x%x; 0x%x, 0x%x, 0x%x", proc_param->size, proc_param->ver, proc_param->unk0, proc_param->unk1);
LOG_NOTICE(LOADER, "*** &sceUserMainThreadName = 0x%x", proc_param->sceUserMainThreadName);
LOG_NOTICE(LOADER, "*** &sceUserMainThreadPriority = 0x%x", proc_param->sceUserMainThreadPriority);
LOG_NOTICE(LOADER, "*** &sceUserMainThreadStackSize = 0x%x", proc_param->sceUserMainThreadStackSize);
LOG_NOTICE(LOADER, "*** &sceUserMainThreadAttribute = 0x%x", proc_param->sceUserMainThreadAttribute);
LOG_NOTICE(LOADER, "*** &sceProcessName = 0x%x", proc_param->sceProcessName);
LOG_NOTICE(LOADER, "*** &sce_process_preload_disabled = 0x%x", proc_param->sce_process_preload_disabled);
LOG_NOTICE(LOADER, "*** &sceUserMainThreadCpuAffinityMask = 0x%x", proc_param->sceUserMainThreadCpuAffinityMask);
const auto libc_param = proc_param->sce_libcparam;
LOG_NOTICE(LOADER, "__sce_libcparam(*0x%x) analysis...", libc_param);
ASSERT(libc_param->size >= 0x1c);
LOG_NOTICE(LOADER, "*** size=0x%x; 0x%x, 0x%x, 0x%x", libc_param->size, libc_param->unk0, libc_param->unk1, libc_param->unk2);
LOG_NOTICE(LOADER, "*** &sceLibcHeapSize = 0x%x", libc_param->sceLibcHeapSize);
LOG_NOTICE(LOADER, "*** &sceLibcHeapSizeDefault = 0x%x", libc_param->sceLibcHeapSizeDefault);
LOG_NOTICE(LOADER, "*** &sceLibcHeapExtendedAlloc = 0x%x", libc_param->sceLibcHeapExtendedAlloc);
LOG_NOTICE(LOADER, "*** &sceLibcHeapDelayedAlloc = 0x%x", libc_param->sceLibcHeapDelayedAlloc);
const auto stop_code = vm::ptr<u32>::make(vm::alloc(3 * 4, vm::main));
stop_code[0] = 0xf870; // HACK instruction (Thumb)
stop_code[1] = 1; // Predefined function index (HLE return)
Emu.SetCPUThreadStop(stop_code.addr());
armv7_init_tls();
const std::string& thread_name = proc_param->sceUserMainThreadName ? proc_param->sceUserMainThreadName.get_ptr() : "main_thread";
const u32 stack_size = proc_param->sceUserMainThreadStackSize ? proc_param->sceUserMainThreadStackSize->value() : 256 * 1024;
const u32 priority = proc_param->sceUserMainThreadPriority ? proc_param->sceUserMainThreadPriority->value() : 160;
auto thread = idm::make_ptr<ARMv7Thread>(thread_name);
thread->PC = entry_point;
thread->stack_size = stack_size;
thread->prio = priority;
thread->cpu_init();
// Initialize args
std::vector<char> argv_data;
for (const auto& arg : { Emu.GetPath(), "-emu"s })
{
argv_data.insert(argv_data.end(), arg.begin(), arg.end());
argv_data.insert(argv_data.end(), '\0');
thread->GPR[0]++; // argc
}
const u32 argv = vm::alloc(::size32(argv_data), vm::main);
std::memcpy(vm::base(argv), argv_data.data(), argv_data.size()); // copy arg list
thread->GPR[1] = argv;
}

View file

@ -0,0 +1,222 @@
#pragma once
#include "Utilities/Config.h"
#include "ARMv7Function.h"
#include "ARMv7Callback.h"
#include "ErrorCodes.h"
namespace vm { using namespace psv; }
// HLE function information
struct arm_static_function
{
const char* name;
u32 index; // Index for arm_function_manager
u32 flags;
};
// HLE variable information
struct arm_static_variable
{
const char* name;
vm::gvar<void>* var; // Pointer to variable address storage
void(*init)(); // Variable initialization function
u32 size;
u32 align;
};
// HLE module information
class arm_static_module final
{
public:
const std::string name;
task_stack on_load;
task_stack on_unload;
std::unordered_map<u32, arm_static_function> functions;
std::unordered_map<u32, arm_static_variable> variables;
public:
arm_static_module(const char* name);
arm_static_module(const char* name, void(*init)())
: arm_static_module(name)
{
init();
}
arm_static_module(const char* name, void(*init)(arm_static_module* _this))
: arm_static_module(name)
{
init(this);
}
};
class arm_module_manager final
{
friend class arm_static_module;
static never_inline auto& access()
{
static std::unordered_map<std::string, arm_static_module*> map;
return map;
}
static never_inline void register_module(arm_static_module* module)
{
access().emplace(module->name, module);
}
static never_inline auto& access_static_function(const char* module, u32 fnid)
{
return access().at(module)->functions[fnid];
}
static never_inline auto& access_static_variable(const char* module, u32 vnid)
{
return access().at(module)->variables[vnid];
}
public:
static never_inline const arm_static_module* get_module(const std::string& name)
{
const auto& map = access();
const auto found = map.find(name);
return found != map.end() ? found->second : nullptr;
}
template<typename T, T Func>
static void register_static_function(const char* module, const char* name, arm_function_t func, u32 fnid, u32 flags)
{
auto& info = access_static_function(module, fnid);
info.name = name;
info.index = arm_function_manager::register_function<T, Func>(func);
info.flags = flags;
}
template<typename T, T* Var>
static void register_static_variable(const char* module, const char* name, u32 vnid, void(*init)())
{
static_assert(std::is_same<u32, typename T::addr_type>::value, "Static variable registration: vm::gvar<T> expected");
auto& info = access_static_variable(module, vnid);
info.name = name;
info.var = reinterpret_cast<vm::gvar<void>*>(Var);
info.init = init ? init : [] {};
info.size = SIZE_32(typename T::type);
info.align = ALIGN_32(typename T::type);
}
static const arm_static_module SceAppMgr;
static const arm_static_module SceAppUtil;
static const arm_static_module SceAudio;
static const arm_static_module SceAudiodec;
static const arm_static_module SceAudioenc;
static const arm_static_module SceAudioIn;
static const arm_static_module SceCamera;
static const arm_static_module SceCodecEngine;
static const arm_static_module SceCommonDialog;
static const arm_static_module SceCpu;
static const arm_static_module SceCtrl;
static const arm_static_module SceDbg;
static const arm_static_module SceDebugLed;
static const arm_static_module SceDeci4p;
static const arm_static_module SceDeflt;
static const arm_static_module SceDipsw;
static const arm_static_module SceDisplay;
static const arm_static_module SceDisplayUser;
static const arm_static_module SceFiber;
static const arm_static_module SceFios;
static const arm_static_module SceFpu;
static const arm_static_module SceGxm;
static const arm_static_module SceHttp;
static const arm_static_module SceIme;
static const arm_static_module SceIofilemgr;
static const arm_static_module SceJpeg;
static const arm_static_module SceJpegEnc;
static const arm_static_module SceLibc;
static const arm_static_module SceLibKernel;
static const arm_static_module SceLibm;
static const arm_static_module SceLibstdcxx;
static const arm_static_module SceLibXml;
static const arm_static_module SceLiveArea;
static const arm_static_module SceLocation;
static const arm_static_module SceMd5;
static const arm_static_module SceModulemgr;
static const arm_static_module SceMotion;
static const arm_static_module SceMt19937;
static const arm_static_module SceNet;
static const arm_static_module SceNetCtl;
static const arm_static_module SceNgs;
static const arm_static_module SceNpBasic;
static const arm_static_module SceNpCommon;
static const arm_static_module SceNpManager;
static const arm_static_module SceNpMatching;
static const arm_static_module SceNpScore;
static const arm_static_module SceNpUtility;
static const arm_static_module ScePerf;
static const arm_static_module ScePgf;
static const arm_static_module ScePhotoExport;
static const arm_static_module SceProcessmgr;
static const arm_static_module SceRazorCapture;
static const arm_static_module SceRtc;
static const arm_static_module SceSas;
static const arm_static_module SceScreenShot;
static const arm_static_module SceSfmt;
static const arm_static_module SceSha;
static const arm_static_module SceSqlite;
static const arm_static_module SceSsl;
static const arm_static_module SceStdio;
static const arm_static_module SceSulpha;
static const arm_static_module SceSysmem;
static const arm_static_module SceSysmodule;
static const arm_static_module SceSystemGesture;
static const arm_static_module SceThreadmgr;
static const arm_static_module SceTouch;
static const arm_static_module SceUlt;
static const arm_static_module SceVideodec;
static const arm_static_module SceVoice;
static const arm_static_module SceVoiceQoS;
};
#define REG_FNID(module, nid, func, ...) arm_module_manager::register_static_function<decltype(&func), &func>(#module, #func, BIND_FUNC(func), nid, {__VA_ARGS__})
#define REG_VNID(module, nid, var, ...) arm_module_manager::register_static_variable<decltype(var), &var>(#module, #var, nid, {__VA_ARGS__})
struct SceDateTime
{
le_t<u16> year;
le_t<u16> month;
le_t<u16> day;
le_t<u16> hour;
le_t<u16> minute;
le_t<u16> second;
le_t<u32> microsecond;
};
struct SceFVector3
{
le_t<f32> x, y, z;
};
struct SceFQuaternion
{
le_t<f32> x, y, z, w;
};
union SceUMatrix4
{
struct
{
le_t<f32> f[4][4];
};
struct
{
le_t<s32> i[4][4];
};
};

File diff suppressed because it is too large Load diff

View file

@ -1,25 +1,20 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/state.h"
#include "Emu/IdManager.h"
#include "Emu/ARMv7/PSVFuncList.h"
#include "ARMv7Thread.h" #include "ARMv7Thread.h"
#include "ARMv7Decoder.h" #include "ARMv7Opcodes.h"
#include "ARMv7DisAsm.h"
#include "ARMv7Interpreter.h" #include "ARMv7Interpreter.h"
void ARMv7Context::fast_call(u32 addr) namespace vm { using namespace psv; }
{
return static_cast<ARMv7Thread*>(this)->fast_call(addr); const arm_decoder<arm_interpreter> s_arm_interpreter;
}
#define TLS_MAX 128 #define TLS_MAX 128
u32 g_armv7_tls_start; u32 g_armv7_tls_start;
std::array<std::atomic<u32>, TLS_MAX> g_armv7_tls_owners; std::array<atomic_t<u32>, TLS_MAX> g_armv7_tls_owners;
void armv7_init_tls() void armv7_init_tls()
{ {
@ -48,8 +43,7 @@ u32 armv7_get_tls(u32 thread)
for (u32 i = 0; i < TLS_MAX; i++) for (u32 i = 0; i < TLS_MAX; i++)
{ {
u32 old = 0; if (g_armv7_tls_owners[i].compare_and_swap_test(0, thread))
if (g_armv7_tls_owners[i].compare_exchange_strong(old, thread))
{ {
const u32 addr = g_armv7_tls_start + i * Emu.GetTLSMemsz(); // get TLS address const u32 addr = g_armv7_tls_start + i * Emu.GetTLSMemsz(); // get TLS address
std::memcpy(vm::base(addr), vm::base(Emu.GetTLSAddr()), Emu.GetTLSFilesz()); // initialize from TLS image std::memcpy(vm::base(addr), vm::base(Emu.GetTLSAddr()), Emu.GetTLSFilesz()); // initialize from TLS image
@ -70,57 +64,38 @@ void armv7_free_tls(u32 thread)
for (auto& v : g_armv7_tls_owners) for (auto& v : g_armv7_tls_owners)
{ {
u32 old = thread; if (v.compare_and_swap_test(thread, 0))
if (v.compare_exchange_strong(old, 0))
{ {
return; return;
} }
} }
} }
ARMv7Thread::ARMv7Thread(const std::string& name)
: CPUThread(CPU_THREAD_ARMv7, name)
, ARMv7Context({})
{
}
ARMv7Thread::~ARMv7Thread()
{
close_stack();
armv7_free_tls(m_id);
}
std::string ARMv7Thread::get_name() const std::string ARMv7Thread::get_name() const
{ {
return fmt::format("ARMv7 Thread[0x%x] (%s)[0x%08x]", m_id, CPUThread::get_name(), PC); return fmt::format("ARMv7[0x%x] Thread (%s)", id, name);
} }
void ARMv7Thread::dump_info() const std::string ARMv7Thread::dump() const
{ {
if (hle_func) std::string result = "Registers:\n=========\n";
for(int i=0; i<15; ++i)
{ {
const auto func = get_psv_func_by_nid(hle_func); result += fmt::format("r%u\t= 0x%08x\n", i, GPR[i]);
LOG_SUCCESS(HLE, "Last function: %s (0x%x)", func ? func->name : "?????????", hle_func);
} }
CPUThread::dump_info(); result += fmt::format("APSR\t= 0x%08x [N: %d, Z: %d, C: %d, V: %d, Q: %d]\n",
APSR.APSR,
u32{ APSR.N },
u32{ APSR.Z },
u32{ APSR.C },
u32{ APSR.V },
u32{ APSR.Q });
return result;
} }
void ARMv7Thread::init_regs() void ARMv7Thread::cpu_init()
{
memset(GPR, 0, sizeof(GPR));
APSR.APSR = 0;
IPSR.IPSR = 0;
ISET = PC & 1 ? Thumb : ARM; // select instruction set
PC = PC & ~1; // and fix PC
ITSTATE.IT = 0;
SP = stack_addr + stack_size;
TLS = armv7_get_tls(m_id);
debug = DF_DISASM | DF_PRINT;
}
void ARMv7Thread::init_stack()
{ {
if (!stack_addr) if (!stack_addr)
{ {
@ -136,60 +111,15 @@ void ARMv7Thread::init_stack()
throw EXCEPTION("Out of stack memory"); throw EXCEPTION("Out of stack memory");
} }
} }
}
void ARMv7Thread::close_stack() memset(GPR, 0, sizeof(GPR));
{ APSR.APSR = 0;
if (stack_addr) IPSR.IPSR = 0;
{ ISET = PC & 1 ? Thumb : ARM; // select instruction set
vm::dealloc_verbose_nothrow(stack_addr, vm::main); PC = PC & ~1; // and fix PC
stack_addr = 0; ITSTATE.IT = 0;
} SP = stack_addr + stack_size;
} TLS = armv7_get_tls(id);
std::string ARMv7Thread::RegsToString() const
{
std::string result = "Registers:\n=========\n";
for(int i=0; i<15; ++i)
{
result += fmt::format("%s\t= 0x%08x\n", g_arm_reg_name[i], GPR[i]);
}
result += fmt::format("APSR\t= 0x%08x [N: %d, Z: %d, C: %d, V: %d, Q: %d]\n",
APSR.APSR,
u32{ APSR.N },
u32{ APSR.Z },
u32{ APSR.C },
u32{ APSR.V },
u32{ APSR.Q });
return result;
}
std::string ARMv7Thread::ReadRegString(const std::string& reg) const
{
return "";
}
bool ARMv7Thread::WriteRegString(const std::string& reg, std::string value)
{
return true;
}
void ARMv7Thread::do_run()
{
m_dec.reset();
switch((int)rpcs3::state.config.core.ppu_decoder.value())
{
case 0:
case 1:
m_dec.reset(new ARMv7Decoder(*this));
break;
default:
LOG_ERROR(ARMv7, "Invalid CPU decoder mode: %d", (int)rpcs3::state.config.core.ppu_decoder.value());
Emu.Pause();
}
} }
void ARMv7Thread::cpu_task() void ARMv7Thread::cpu_task()
@ -201,10 +131,54 @@ void ARMv7Thread::cpu_task()
return custom_task(*this); return custom_task(*this);
} }
while (!m_state || !check_status()) _log::g_tls_make_prefix = [](const auto&, auto, const auto&)
{ {
// decode instruction using specified decoder const auto cpu = static_cast<ARMv7Thread*>(get_current_cpu_thread());
PC += m_dec->DecodeMemory(PC);
return fmt::format("%s [0x%08x]", cpu->get_name(), cpu->PC);
};
while (!state.load() || !check_status())
{
if (ISET == Thumb)
{
const u16 op16 = vm::read16(PC);
const u32 cond = ITSTATE.advance();
if (const auto func16 = s_arm_interpreter.decode_thumb(op16))
{
func16(*this, op16, cond);
PC += 2;
}
else
{
const u32 op32 = (op16 << 16) | vm::read16(PC + 2);
s_arm_interpreter.decode_thumb(op32)(*this, op32, cond);
PC += 4;
}
}
else if (ISET == ARM)
{
const u32 op = vm::read32(PC);
s_arm_interpreter.decode_arm(op)(*this, op, op >> 28);
PC += 4;
}
else
{
throw fmt::exception("Invalid instruction set" HERE);
}
}
}
ARMv7Thread::~ARMv7Thread()
{
armv7_free_tls(id);
if (stack_addr)
{
vm::dealloc_verbose_nothrow(stack_addr, vm::main);
} }
} }
@ -228,11 +202,13 @@ void ARMv7Thread::fast_call(u32 addr)
{ {
cpu_task(); cpu_task();
} }
catch (CPUThreadReturn) catch (cpu_state _s)
{ {
state += _s;
if (_s != cpu_state::ret) throw;
} }
m_state &= ~CPU_STATE_RETURN; state -= cpu_state::ret;
PC = old_PC; PC = old_PC;
@ -244,67 +220,3 @@ void ARMv7Thread::fast_call(u32 addr)
LR = old_LR; LR = old_LR;
custom_task = std::move(old_task); custom_task = std::move(old_task);
} }
void ARMv7Thread::fast_stop()
{
m_state |= CPU_STATE_RETURN;
}
armv7_thread::armv7_thread(u32 entry, const std::string& name, u32 stack_size, s32 prio)
{
std::shared_ptr<ARMv7Thread> armv7 = idm::make_ptr<ARMv7Thread>(name);
armv7->PC = entry;
armv7->stack_size = stack_size;
armv7->prio = prio;
thread = std::move(armv7);
argc = 0;
}
cpu_thread& armv7_thread::args(std::initializer_list<std::string> values)
{
assert(argc == 0);
if (!values.size())
{
return *this;
}
std::vector<char> argv_data;
u32 argv_size = 0;
for (auto& arg : values)
{
const u32 arg_size = arg.size(); // get arg size
for (char c : arg)
{
argv_data.push_back(c); // append characters
}
argv_data.push_back('\0'); // append null terminator
argv_size += arg_size + 1;
argc++;
}
argv = vm::alloc(argv_size, vm::main); // allocate arg list
std::memcpy(vm::base(argv), argv_data.data(), argv_size); // copy arg list
return *this;
}
cpu_thread& armv7_thread::run()
{
auto& armv7 = static_cast<ARMv7Thread&>(*thread);
armv7.run();
// set arguments
armv7.GPR[0] = argc;
armv7.GPR[1] = argv;
return *this;
}

View file

@ -1,44 +1,271 @@
#pragma once #pragma once
#include "Emu/CPU/CPUThread.h"
#include "ARMv7Context.h"
class ARMv7Thread final : public CPUThread, public ARMv7Context #include "Emu/CPU/CPUThread.h"
#include "Emu/Memory/vm.h"
enum ARMv7InstructionSet
{
ARM,
Thumb,
Jazelle,
ThumbEE
};
class ARMv7Thread final : public cpu_thread
{ {
public: public:
std::function<void(ARMv7Thread&)> custom_task;
public:
ARMv7Thread(const std::string& name);
virtual ~ARMv7Thread() override;
virtual std::string get_name() const override; virtual std::string get_name() const override;
virtual void dump_info() const override; virtual std::string dump() const override;
virtual u32 get_pc() const override { return PC; } virtual void cpu_init() override;
virtual u32 get_offset() const override { return 0; }
virtual void do_run() override;
virtual void cpu_task() override; virtual void cpu_task() override;
virtual void init_regs() override; ARMv7Thread(const std::string& name)
virtual void init_stack() override; : cpu_thread(cpu_type::arm, name)
virtual void close_stack() override; {
u32 get_stack_arg(u32 pos); }
virtual ~ARMv7Thread() override;
union
{
u32 GPR[15];
struct
{
u32 pad[13];
union
{
u32 SP;
struct { u16 SP_main, SP_process; };
};
u32 LR;
union
{
struct
{
u32 reserved0 : 16;
u32 GE : 4;
u32 reserved1 : 4;
u32 dummy : 3;
u32 Q : 1; // Set to 1 if an SSAT or USAT instruction changes (saturates) the input value for the signed or unsigned range of the result
u32 V : 1; // Overflow condition code flag
u32 C : 1; // Carry condition code flag
u32 Z : 1; // Zero condition code flag
u32 N : 1; // Negative condition code flag
};
u32 APSR;
} APSR;
};
struct
{
u64 GPR_D[8];
};
};
union
{
struct
{
u32 dummy : 24;
u32 exception : 8;
};
u32 IPSR;
} IPSR;
ARMv7InstructionSet ISET;
union
{
struct
{
u8 shift_state : 5;
u8 cond_base : 3;
};
struct
{
u8 check_state : 4;
u8 condition : 4;
};
u8 IT;
u32 advance()
{
// 0xf is "always true" and indicates that this instruction was not in IT block.
// 0xe is "always true" too and represents the AL condition of IT block.
// This makes a significant difference in some instructions.
const u32 res = check_state ? condition : 0xf;
shift_state <<= 1;
if (!check_state)
{
IT = 0; // clear
}
return res;
}
operator bool() const
{
return check_state != 0;
}
} ITSTATE;
u32 TLS = 0;
struct perf_counter
{
u32 event;
u32 value;
};
std::array<perf_counter, 6> counters{};
u32 PC = 0;
s32 prio = 0;
u32 stack_addr = 0;
u32 stack_size = 0;
std::function<void(ARMv7Thread&)> custom_task;
const char* last_function = nullptr;
void write_pc(u32 value, u32 size)
{
ISET = value & 1 ? Thumb : ARM;
PC = (value & ~1) - size;
}
u32 read_pc()
{
return ISET == ARM ? PC + 8 : PC + 4;
}
u32 get_stack_arg(u32 pos)
{
return vm::psv::read32(SP + sizeof(u32) * (pos - 5));
}
void write_gpr(u32 n, u32 value, u32 size)
{
Expects(n < 16);
if (n < 15)
{
GPR[n] = value;
}
else
{
write_pc(value, size);
}
}
u32 read_gpr(u32 n)
{
Expects(n < 16);
if (n < 15)
{
return GPR[n];
}
return read_pc();
}
// function for processing va_args in printf-like functions
u32 get_next_gpr_arg(u32& g_count)
{
if (g_count < 4)
{
return GPR[g_count++];
}
else
{
return get_stack_arg(g_count++);
}
}
void fast_call(u32 addr); void fast_call(u32 addr);
void fast_stop();
virtual std::string RegsToString() const override;
virtual std::string ReadRegString(const std::string& reg) const override;
virtual bool WriteRegString(const std::string& reg, std::string value) override;
}; };
class armv7_thread : cpu_thread template<typename T, typename = void>
struct arm_gpr_cast_impl
{ {
u32 argv; static_assert(!sizeof(T), "Invalid type for arm_gpr_cast<>");
u32 argc;
public:
armv7_thread(u32 entry, const std::string& name, u32 stack_size, s32 prio);
cpu_thread& args(std::initializer_list<std::string> values) override;
cpu_thread& run() override;
}; };
template<typename T>
struct arm_gpr_cast_impl<T, std::enable_if_t<std::is_integral<T>::value || std::is_enum<T>::value>>
{
static_assert(sizeof(T) <= 4, "Too big integral type for arm_gpr_cast<>()");
static_assert(std::is_same<const T, const bool>::value == false, "bool type is deprecated in arm_gpr_cast<>(), use b8 instead");
static inline u32 to(const T& value)
{
return static_cast<u32>(value);
}
static inline T from(const u32 reg)
{
return static_cast<T>(reg);
}
};
template<>
struct arm_gpr_cast_impl<b8, void>
{
static inline u32 to(const b8& value)
{
return value;
}
static inline b8 from(const u32 reg)
{
return reg != 0;
}
};
template<typename T, typename AT>
struct arm_gpr_cast_impl<vm::_ptr_base<T, AT>, void>
{
static inline u32 to(const vm::_ptr_base<T, AT>& value)
{
return arm_gpr_cast_impl<AT>::to(value.addr());
}
static inline vm::_ptr_base<T, AT> from(const u32 reg)
{
return{ arm_gpr_cast_impl<AT>::from(reg), vm::addr };
}
};
template<typename T, typename AT>
struct arm_gpr_cast_impl<vm::_ref_base<T, AT>, void>
{
static inline u32 to(const vm::_ref_base<T, AT>& value)
{
return arm_gpr_cast_impl<AT>::to(value.addr());
}
static inline vm::_ref_base<T, AT> from(const u32 reg)
{
return{ arm_gpr_cast_impl<AT>::from(reg), vm::addr };
}
};
template<typename To = u32, typename From>
inline To arm_gpr_cast(const From& value)
{
return arm_gpr_cast_impl<To>::from(arm_gpr_cast_impl<From>::to(value));
}

View file

@ -0,0 +1,350 @@
#pragma once
#define ERROR_CODE(code) static_cast<s32>(code)
enum SceOk : s32
{
SCE_OK = 0,
};
enum SceError : s32
{
SCE_ERROR_ERRNO_EPERM = ERROR_CODE(0x80010001),
SCE_ERROR_ERRNO_ENOENT = ERROR_CODE(0x80010002),
SCE_ERROR_ERRNO_ESRCH = ERROR_CODE(0x80010003),
SCE_ERROR_ERRNO_EINTR = ERROR_CODE(0x80010004),
SCE_ERROR_ERRNO_EIO = ERROR_CODE(0x80010005),
SCE_ERROR_ERRNO_ENXIO = ERROR_CODE(0x80010006),
SCE_ERROR_ERRNO_E2BIG = ERROR_CODE(0x80010007),
SCE_ERROR_ERRNO_ENOEXEC = ERROR_CODE(0x80010008),
SCE_ERROR_ERRNO_EBADF = ERROR_CODE(0x80010009),
SCE_ERROR_ERRNO_ECHILD = ERROR_CODE(0x8001000A),
SCE_ERROR_ERRNO_EAGAIN = ERROR_CODE(0x8001000B),
SCE_ERROR_ERRNO_ENOMEM = ERROR_CODE(0x8001000C),
SCE_ERROR_ERRNO_EACCES = ERROR_CODE(0x8001000D),
SCE_ERROR_ERRNO_EFAULT = ERROR_CODE(0x8001000E),
SCE_ERROR_ERRNO_ENOTBLK = ERROR_CODE(0x8001000F),
SCE_ERROR_ERRNO_EBUSY = ERROR_CODE(0x80010010),
SCE_ERROR_ERRNO_EEXIST = ERROR_CODE(0x80010011),
SCE_ERROR_ERRNO_EXDEV = ERROR_CODE(0x80010012),
SCE_ERROR_ERRNO_ENODEV = ERROR_CODE(0x80010013),
SCE_ERROR_ERRNO_ENOTDIR = ERROR_CODE(0x80010014),
SCE_ERROR_ERRNO_EISDIR = ERROR_CODE(0x80010015),
SCE_ERROR_ERRNO_EINVAL = ERROR_CODE(0x80010016),
SCE_ERROR_ERRNO_ENFILE = ERROR_CODE(0x80010017),
SCE_ERROR_ERRNO_EMFILE = ERROR_CODE(0x80010018),
SCE_ERROR_ERRNO_ENOTTY = ERROR_CODE(0x80010019),
SCE_ERROR_ERRNO_ETXTBSY = ERROR_CODE(0x8001001A),
SCE_ERROR_ERRNO_EFBIG = ERROR_CODE(0x8001001B),
SCE_ERROR_ERRNO_ENOSPC = ERROR_CODE(0x8001001C),
SCE_ERROR_ERRNO_ESPIPE = ERROR_CODE(0x8001001D),
SCE_ERROR_ERRNO_EROFS = ERROR_CODE(0x8001001E),
SCE_ERROR_ERRNO_EMLINK = ERROR_CODE(0x8001001F),
SCE_ERROR_ERRNO_EPIPE = ERROR_CODE(0x80010020),
SCE_ERROR_ERRNO_EDOM = ERROR_CODE(0x80010021),
SCE_ERROR_ERRNO_ERANGE = ERROR_CODE(0x80010022),
SCE_ERROR_ERRNO_ENOMSG = ERROR_CODE(0x80010023),
SCE_ERROR_ERRNO_EIDRM = ERROR_CODE(0x80010024),
SCE_ERROR_ERRNO_ECHRNG = ERROR_CODE(0x80010025),
SCE_ERROR_ERRNO_EL2NSYNC = ERROR_CODE(0x80010026),
SCE_ERROR_ERRNO_EL3HLT = ERROR_CODE(0x80010027),
SCE_ERROR_ERRNO_EL3RST = ERROR_CODE(0x80010028),
SCE_ERROR_ERRNO_ELNRNG = ERROR_CODE(0x80010029),
SCE_ERROR_ERRNO_EUNATCH = ERROR_CODE(0x8001002A),
SCE_ERROR_ERRNO_ENOCSI = ERROR_CODE(0x8001002B),
SCE_ERROR_ERRNO_EL2HLT = ERROR_CODE(0x8001002C),
SCE_ERROR_ERRNO_EDEADLK = ERROR_CODE(0x8001002D),
SCE_ERROR_ERRNO_ENOLCK = ERROR_CODE(0x8001002E),
SCE_ERROR_ERRNO_EFORMAT = ERROR_CODE(0x8001002F),
SCE_ERROR_ERRNO_EUNSUP = ERROR_CODE(0x80010030),
SCE_ERROR_ERRNO_EBADE = ERROR_CODE(0x80010032),
SCE_ERROR_ERRNO_EBADR = ERROR_CODE(0x80010033),
SCE_ERROR_ERRNO_EXFULL = ERROR_CODE(0x80010034),
SCE_ERROR_ERRNO_ENOANO = ERROR_CODE(0x80010035),
SCE_ERROR_ERRNO_EBADRQC = ERROR_CODE(0x80010036),
SCE_ERROR_ERRNO_EBADSLT = ERROR_CODE(0x80010037),
SCE_ERROR_ERRNO_EDEADLOCK = ERROR_CODE(0x80010038),
SCE_ERROR_ERRNO_EBFONT = ERROR_CODE(0x80010039),
SCE_ERROR_ERRNO_ENOSTR = ERROR_CODE(0x8001003C),
SCE_ERROR_ERRNO_ENODATA = ERROR_CODE(0x8001003D),
SCE_ERROR_ERRNO_ETIME = ERROR_CODE(0x8001003E),
SCE_ERROR_ERRNO_ENOSR = ERROR_CODE(0x8001003F),
SCE_ERROR_ERRNO_ENONET = ERROR_CODE(0x80010040),
SCE_ERROR_ERRNO_ENOPKG = ERROR_CODE(0x80010041),
SCE_ERROR_ERRNO_EREMOTE = ERROR_CODE(0x80010042),
SCE_ERROR_ERRNO_ENOLINK = ERROR_CODE(0x80010043),
SCE_ERROR_ERRNO_EADV = ERROR_CODE(0x80010044),
SCE_ERROR_ERRNO_ESRMNT = ERROR_CODE(0x80010045),
SCE_ERROR_ERRNO_ECOMM = ERROR_CODE(0x80010046),
SCE_ERROR_ERRNO_EPROTO = ERROR_CODE(0x80010047),
SCE_ERROR_ERRNO_EMULTIHOP = ERROR_CODE(0x8001004A),
SCE_ERROR_ERRNO_ELBIN = ERROR_CODE(0x8001004B),
SCE_ERROR_ERRNO_EDOTDOT = ERROR_CODE(0x8001004C),
SCE_ERROR_ERRNO_EBADMSG = ERROR_CODE(0x8001004D),
SCE_ERROR_ERRNO_EFTYPE = ERROR_CODE(0x8001004F),
SCE_ERROR_ERRNO_ENOTUNIQ = ERROR_CODE(0x80010050),
SCE_ERROR_ERRNO_EBADFD = ERROR_CODE(0x80010051),
SCE_ERROR_ERRNO_EREMCHG = ERROR_CODE(0x80010052),
SCE_ERROR_ERRNO_ELIBACC = ERROR_CODE(0x80010053),
SCE_ERROR_ERRNO_ELIBBAD = ERROR_CODE(0x80010054),
SCE_ERROR_ERRNO_ELIBSCN = ERROR_CODE(0x80010055),
SCE_ERROR_ERRNO_ELIBMAX = ERROR_CODE(0x80010056),
SCE_ERROR_ERRNO_ELIBEXEC = ERROR_CODE(0x80010057),
SCE_ERROR_ERRNO_ENOSYS = ERROR_CODE(0x80010058),
SCE_ERROR_ERRNO_ENMFILE = ERROR_CODE(0x80010059),
SCE_ERROR_ERRNO_ENOTEMPTY = ERROR_CODE(0x8001005A),
SCE_ERROR_ERRNO_ENAMETOOLONG = ERROR_CODE(0x8001005B),
SCE_ERROR_ERRNO_ELOOP = ERROR_CODE(0x8001005C),
SCE_ERROR_ERRNO_EOPNOTSUPP = ERROR_CODE(0x8001005F),
SCE_ERROR_ERRNO_EPFNOSUPPORT = ERROR_CODE(0x80010060),
SCE_ERROR_ERRNO_ECONNRESET = ERROR_CODE(0x80010068),
SCE_ERROR_ERRNO_ENOBUFS = ERROR_CODE(0x80010069),
SCE_ERROR_ERRNO_EAFNOSUPPORT = ERROR_CODE(0x8001006A),
SCE_ERROR_ERRNO_EPROTOTYPE = ERROR_CODE(0x8001006B),
SCE_ERROR_ERRNO_ENOTSOCK = ERROR_CODE(0x8001006C),
SCE_ERROR_ERRNO_ENOPROTOOPT = ERROR_CODE(0x8001006D),
SCE_ERROR_ERRNO_ESHUTDOWN = ERROR_CODE(0x8001006E),
SCE_ERROR_ERRNO_ECONNREFUSED = ERROR_CODE(0x8001006F),
SCE_ERROR_ERRNO_EADDRINUSE = ERROR_CODE(0x80010070),
SCE_ERROR_ERRNO_ECONNABORTED = ERROR_CODE(0x80010071),
SCE_ERROR_ERRNO_ENETUNREACH = ERROR_CODE(0x80010072),
SCE_ERROR_ERRNO_ENETDOWN = ERROR_CODE(0x80010073),
SCE_ERROR_ERRNO_ETIMEDOUT = ERROR_CODE(0x80010074),
SCE_ERROR_ERRNO_EHOSTDOWN = ERROR_CODE(0x80010075),
SCE_ERROR_ERRNO_EHOSTUNREACH = ERROR_CODE(0x80010076),
SCE_ERROR_ERRNO_EINPROGRESS = ERROR_CODE(0x80010077),
SCE_ERROR_ERRNO_EALREADY = ERROR_CODE(0x80010078),
SCE_ERROR_ERRNO_EDESTADDRREQ = ERROR_CODE(0x80010079),
SCE_ERROR_ERRNO_EMSGSIZE = ERROR_CODE(0x8001007A),
SCE_ERROR_ERRNO_EPROTONOSUPPORT = ERROR_CODE(0x8001007B),
SCE_ERROR_ERRNO_ESOCKTNOSUPPORT = ERROR_CODE(0x8001007C),
SCE_ERROR_ERRNO_EADDRNOTAVAIL = ERROR_CODE(0x8001007D),
SCE_ERROR_ERRNO_ENETRESET = ERROR_CODE(0x8001007E),
SCE_ERROR_ERRNO_EISCONN = ERROR_CODE(0x8001007F),
SCE_ERROR_ERRNO_ENOTCONN = ERROR_CODE(0x80010080),
SCE_ERROR_ERRNO_ETOOMANYREFS = ERROR_CODE(0x80010081),
SCE_ERROR_ERRNO_EPROCLIM = ERROR_CODE(0x80010082),
SCE_ERROR_ERRNO_EUSERS = ERROR_CODE(0x80010083),
SCE_ERROR_ERRNO_EDQUOT = ERROR_CODE(0x80010084),
SCE_ERROR_ERRNO_ESTALE = ERROR_CODE(0x80010085),
SCE_ERROR_ERRNO_ENOTSUP = ERROR_CODE(0x80010086),
SCE_ERROR_ERRNO_ENOMEDIUM = ERROR_CODE(0x80010087),
SCE_ERROR_ERRNO_ENOSHARE = ERROR_CODE(0x80010088),
SCE_ERROR_ERRNO_ECASECLASH = ERROR_CODE(0x80010089),
SCE_ERROR_ERRNO_EILSEQ = ERROR_CODE(0x8001008A),
SCE_ERROR_ERRNO_EOVERFLOW = ERROR_CODE(0x8001008B),
SCE_ERROR_ERRNO_ECANCELED = ERROR_CODE(0x8001008C),
SCE_ERROR_ERRNO_ENOTRECOVERABLE = ERROR_CODE(0x8001008D),
SCE_ERROR_ERRNO_EOWNERDEAD = ERROR_CODE(0x8001008E),
};
// Special return type signaling on errors
struct arm_error_code
{
s32 value;
// Print error message, error code is returned
static s32 report(s32 error, const char* text);
// Must be specialized for specific tag type T
template<typename T>
static const char* print(T code)
{
return nullptr;
}
template<typename T>
s32 error_check(T code)
{
if (const auto text = print(code))
{
return report(code, text);
}
return code;
}
arm_error_code() = default;
// General error check
template<typename T, typename = std::enable_if_t<std::is_enum<T>::value>>
arm_error_code(T value)
: value(error_check(value))
{
}
// Force error reporting with a message specified
arm_error_code(s32 value, const char* text)
: value(report(value, text))
{
}
// Silence any error
constexpr arm_error_code(s32 value, const std::nothrow_t&)
: value(value)
{
}
// Conversion
constexpr operator s32() const
{
return value;
}
};
// Helper macro for silencing possible error checks on returning arm_error_code values
#define NOT_AN_ERROR(value) { static_cast<s32>(value), std::nothrow }
template<typename T, typename>
struct arm_gpr_cast_impl;
template<>
struct arm_gpr_cast_impl<arm_error_code, void>
{
static inline u32 to(const arm_error_code& code)
{
return code;
}
static inline arm_error_code from(const u32 reg)
{
return NOT_AN_ERROR(reg);
}
};
template<>
inline const char* arm_error_code::print(SceError error)
{
switch (error)
{
STR_CASE(SCE_ERROR_ERRNO_EPERM);
STR_CASE(SCE_ERROR_ERRNO_ENOENT);
STR_CASE(SCE_ERROR_ERRNO_ESRCH);
STR_CASE(SCE_ERROR_ERRNO_EINTR);
STR_CASE(SCE_ERROR_ERRNO_EIO);
STR_CASE(SCE_ERROR_ERRNO_ENXIO);
STR_CASE(SCE_ERROR_ERRNO_E2BIG);
STR_CASE(SCE_ERROR_ERRNO_ENOEXEC);
STR_CASE(SCE_ERROR_ERRNO_EBADF);
STR_CASE(SCE_ERROR_ERRNO_ECHILD);
STR_CASE(SCE_ERROR_ERRNO_EAGAIN);
STR_CASE(SCE_ERROR_ERRNO_ENOMEM);
STR_CASE(SCE_ERROR_ERRNO_EACCES);
STR_CASE(SCE_ERROR_ERRNO_EFAULT);
STR_CASE(SCE_ERROR_ERRNO_ENOTBLK);
STR_CASE(SCE_ERROR_ERRNO_EBUSY);
STR_CASE(SCE_ERROR_ERRNO_EEXIST);
STR_CASE(SCE_ERROR_ERRNO_EXDEV);
STR_CASE(SCE_ERROR_ERRNO_ENODEV);
STR_CASE(SCE_ERROR_ERRNO_ENOTDIR);
STR_CASE(SCE_ERROR_ERRNO_EISDIR);
STR_CASE(SCE_ERROR_ERRNO_EINVAL);
STR_CASE(SCE_ERROR_ERRNO_ENFILE);
STR_CASE(SCE_ERROR_ERRNO_EMFILE);
STR_CASE(SCE_ERROR_ERRNO_ENOTTY);
STR_CASE(SCE_ERROR_ERRNO_ETXTBSY);
STR_CASE(SCE_ERROR_ERRNO_EFBIG);
STR_CASE(SCE_ERROR_ERRNO_ENOSPC);
STR_CASE(SCE_ERROR_ERRNO_ESPIPE);
STR_CASE(SCE_ERROR_ERRNO_EROFS);
STR_CASE(SCE_ERROR_ERRNO_EMLINK);
STR_CASE(SCE_ERROR_ERRNO_EPIPE);
STR_CASE(SCE_ERROR_ERRNO_EDOM);
STR_CASE(SCE_ERROR_ERRNO_ERANGE);
STR_CASE(SCE_ERROR_ERRNO_ENOMSG);
STR_CASE(SCE_ERROR_ERRNO_EIDRM);
STR_CASE(SCE_ERROR_ERRNO_ECHRNG);
STR_CASE(SCE_ERROR_ERRNO_EL2NSYNC);
STR_CASE(SCE_ERROR_ERRNO_EL3HLT);
STR_CASE(SCE_ERROR_ERRNO_EL3RST);
STR_CASE(SCE_ERROR_ERRNO_ELNRNG);
STR_CASE(SCE_ERROR_ERRNO_EUNATCH);
STR_CASE(SCE_ERROR_ERRNO_ENOCSI);
STR_CASE(SCE_ERROR_ERRNO_EL2HLT);
STR_CASE(SCE_ERROR_ERRNO_EDEADLK);
STR_CASE(SCE_ERROR_ERRNO_ENOLCK);
STR_CASE(SCE_ERROR_ERRNO_EFORMAT);
STR_CASE(SCE_ERROR_ERRNO_EUNSUP);
STR_CASE(SCE_ERROR_ERRNO_EBADE);
STR_CASE(SCE_ERROR_ERRNO_EBADR);
STR_CASE(SCE_ERROR_ERRNO_EXFULL);
STR_CASE(SCE_ERROR_ERRNO_ENOANO);
STR_CASE(SCE_ERROR_ERRNO_EBADRQC);
STR_CASE(SCE_ERROR_ERRNO_EBADSLT);
STR_CASE(SCE_ERROR_ERRNO_EDEADLOCK);
STR_CASE(SCE_ERROR_ERRNO_EBFONT);
STR_CASE(SCE_ERROR_ERRNO_ENOSTR);
STR_CASE(SCE_ERROR_ERRNO_ENODATA);
STR_CASE(SCE_ERROR_ERRNO_ETIME);
STR_CASE(SCE_ERROR_ERRNO_ENOSR);
STR_CASE(SCE_ERROR_ERRNO_ENONET);
STR_CASE(SCE_ERROR_ERRNO_ENOPKG);
STR_CASE(SCE_ERROR_ERRNO_EREMOTE);
STR_CASE(SCE_ERROR_ERRNO_ENOLINK);
STR_CASE(SCE_ERROR_ERRNO_EADV);
STR_CASE(SCE_ERROR_ERRNO_ESRMNT);
STR_CASE(SCE_ERROR_ERRNO_ECOMM);
STR_CASE(SCE_ERROR_ERRNO_EPROTO);
STR_CASE(SCE_ERROR_ERRNO_EMULTIHOP);
STR_CASE(SCE_ERROR_ERRNO_ELBIN);
STR_CASE(SCE_ERROR_ERRNO_EDOTDOT);
STR_CASE(SCE_ERROR_ERRNO_EBADMSG);
STR_CASE(SCE_ERROR_ERRNO_EFTYPE);
STR_CASE(SCE_ERROR_ERRNO_ENOTUNIQ);
STR_CASE(SCE_ERROR_ERRNO_EBADFD);
STR_CASE(SCE_ERROR_ERRNO_EREMCHG);
STR_CASE(SCE_ERROR_ERRNO_ELIBACC);
STR_CASE(SCE_ERROR_ERRNO_ELIBBAD);
STR_CASE(SCE_ERROR_ERRNO_ELIBSCN);
STR_CASE(SCE_ERROR_ERRNO_ELIBMAX);
STR_CASE(SCE_ERROR_ERRNO_ELIBEXEC);
STR_CASE(SCE_ERROR_ERRNO_ENOSYS);
STR_CASE(SCE_ERROR_ERRNO_ENMFILE);
STR_CASE(SCE_ERROR_ERRNO_ENOTEMPTY);
STR_CASE(SCE_ERROR_ERRNO_ENAMETOOLONG);
STR_CASE(SCE_ERROR_ERRNO_ELOOP);
STR_CASE(SCE_ERROR_ERRNO_EOPNOTSUPP);
STR_CASE(SCE_ERROR_ERRNO_EPFNOSUPPORT);
STR_CASE(SCE_ERROR_ERRNO_ECONNRESET);
STR_CASE(SCE_ERROR_ERRNO_ENOBUFS);
STR_CASE(SCE_ERROR_ERRNO_EAFNOSUPPORT);
STR_CASE(SCE_ERROR_ERRNO_EPROTOTYPE);
STR_CASE(SCE_ERROR_ERRNO_ENOTSOCK);
STR_CASE(SCE_ERROR_ERRNO_ENOPROTOOPT);
STR_CASE(SCE_ERROR_ERRNO_ESHUTDOWN);
STR_CASE(SCE_ERROR_ERRNO_ECONNREFUSED);
STR_CASE(SCE_ERROR_ERRNO_EADDRINUSE);
STR_CASE(SCE_ERROR_ERRNO_ECONNABORTED);
STR_CASE(SCE_ERROR_ERRNO_ENETUNREACH);
STR_CASE(SCE_ERROR_ERRNO_ENETDOWN);
STR_CASE(SCE_ERROR_ERRNO_ETIMEDOUT);
STR_CASE(SCE_ERROR_ERRNO_EHOSTDOWN);
STR_CASE(SCE_ERROR_ERRNO_EHOSTUNREACH);
STR_CASE(SCE_ERROR_ERRNO_EINPROGRESS);
STR_CASE(SCE_ERROR_ERRNO_EALREADY);
STR_CASE(SCE_ERROR_ERRNO_EDESTADDRREQ);
STR_CASE(SCE_ERROR_ERRNO_EMSGSIZE);
STR_CASE(SCE_ERROR_ERRNO_EPROTONOSUPPORT);
STR_CASE(SCE_ERROR_ERRNO_ESOCKTNOSUPPORT);
STR_CASE(SCE_ERROR_ERRNO_EADDRNOTAVAIL);
STR_CASE(SCE_ERROR_ERRNO_ENETRESET);
STR_CASE(SCE_ERROR_ERRNO_EISCONN);
STR_CASE(SCE_ERROR_ERRNO_ENOTCONN);
STR_CASE(SCE_ERROR_ERRNO_ETOOMANYREFS);
STR_CASE(SCE_ERROR_ERRNO_EPROCLIM);
STR_CASE(SCE_ERROR_ERRNO_EUSERS);
STR_CASE(SCE_ERROR_ERRNO_EDQUOT);
STR_CASE(SCE_ERROR_ERRNO_ESTALE);
STR_CASE(SCE_ERROR_ERRNO_ENOTSUP);
STR_CASE(SCE_ERROR_ERRNO_ENOMEDIUM);
STR_CASE(SCE_ERROR_ERRNO_ENOSHARE);
STR_CASE(SCE_ERROR_ERRNO_ECASECLASH);
STR_CASE(SCE_ERROR_ERRNO_EILSEQ);
STR_CASE(SCE_ERROR_ERRNO_EOVERFLOW);
STR_CASE(SCE_ERROR_ERRNO_ECANCELED);
STR_CASE(SCE_ERROR_ERRNO_ENOTRECOVERABLE);
STR_CASE(SCE_ERROR_ERRNO_EOWNERDEAD);
}
return nullptr;
}

View file

@ -1,9 +1,11 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/ARMv7/PSVFuncList.h" #include "Emu/ARMv7/ARMv7Module.h"
#include "sceAppMgr.h" #include "sceAppMgr.h"
LOG_CHANNEL(sceAppMgr);
s32 sceAppMgrReceiveEventNum(vm::ptr<s32> eventNum) s32 sceAppMgrReceiveEventNum(vm::ptr<s32> eventNum)
{ {
throw EXCEPTION(""); throw EXCEPTION("");
@ -25,15 +27,10 @@ s32 sceAppMgrReleaseBgmPort()
} }
#define REG_FUNC(nid, name) reg_psv_func(nid, &sceAppMgr, #name, name) #define REG_FUNC(nid, name) REG_FNID(SceAppMgrUser, nid, name)
psv_log_base sceAppMgr("SceAppMgr", []() DECLARE(arm_module_manager::SceAppMgr)("SceAppMgrUser", []()
{ {
sceAppMgr.on_load = nullptr;
sceAppMgr.on_unload = nullptr;
sceAppMgr.on_stop = nullptr;
sceAppMgr.on_error = nullptr;
REG_FUNC(0x47E5DD7D, sceAppMgrReceiveEventNum); REG_FUNC(0x47E5DD7D, sceAppMgrReceiveEventNum);
REG_FUNC(0xCFAD5A3A, sceAppMgrReceiveEvent); REG_FUNC(0xCFAD5A3A, sceAppMgrReceiveEvent);
REG_FUNC(0xF3D65520, sceAppMgrAcquireBgmPort); REG_FUNC(0xF3D65520, sceAppMgrAcquireBgmPort);

View file

@ -6,5 +6,3 @@ struct SceAppMgrEvent
le_t<s32> appId; le_t<s32> appId;
char param[56]; char param[56];
}; };
extern psv_log_base sceAppMgr;

View file

@ -1,9 +1,11 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/ARMv7/PSVFuncList.h" #include "Emu/ARMv7/ARMv7Module.h"
#include "sceAppUtil.h" #include "sceAppUtil.h"
LOG_CHANNEL(sceAppUtil);
s32 sceAppUtilInit(vm::cptr<SceAppUtilInitParam> initParam, vm::ptr<SceAppUtilBootParam> bootParam) s32 sceAppUtilInit(vm::cptr<SceAppUtilInitParam> initParam, vm::ptr<SceAppUtilBootParam> bootParam)
{ {
throw EXCEPTION(""); throw EXCEPTION("");
@ -70,15 +72,10 @@ s32 sceAppUtilLoadSafeMemory(vm::ptr<void> buf, u32 bufSize, s64 offset)
} }
#define REG_FUNC(nid, name) reg_psv_func(nid, &sceAppUtil, #name, name) #define REG_FUNC(nid, name) REG_FNID(SceAppUtil, nid, name)
psv_log_base sceAppUtil("SceAppUtil", []() DECLARE(arm_module_manager::SceAppUtil)("SceAppUtil", []()
{ {
sceAppUtil.on_load = nullptr;
sceAppUtil.on_unload = nullptr;
sceAppUtil.on_stop = nullptr;
sceAppUtil.on_error = nullptr;
REG_FUNC(0xDAFFE671, sceAppUtilInit); REG_FUNC(0xDAFFE671, sceAppUtilInit);
REG_FUNC(0xB220B00B, sceAppUtilShutdown); REG_FUNC(0xB220B00B, sceAppUtilShutdown);
REG_FUNC(0x7E8FE96A, sceAppUtilSaveDataSlotCreate); REG_FUNC(0x7E8FE96A, sceAppUtilSaveDataSlotCreate);

View file

@ -65,5 +65,3 @@ struct SceAppUtilSaveDataFileSlot
vm::lptr<SceAppUtilSaveDataSlotParam> slotParam; vm::lptr<SceAppUtilSaveDataSlotParam> slotParam;
char reserved[32]; char reserved[32];
}; };
extern psv_log_base sceAppUtil;

View file

@ -1,9 +1,11 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/ARMv7/PSVFuncList.h" #include "Emu/ARMv7/ARMv7Module.h"
#include "sceAudio.h" #include "sceAudio.h"
LOG_CHANNEL(sceAudio);
s32 sceAudioOutOpenPort(s32 portType, s32 len, s32 freq, s32 param) s32 sceAudioOutOpenPort(s32 portType, s32 len, s32 freq, s32 param)
{ {
throw EXCEPTION(""); throw EXCEPTION("");
@ -45,15 +47,10 @@ s32 sceAudioOutGetAdopt(s32 portType)
} }
#define REG_FUNC(nid, name) reg_psv_func(nid, &sceAudio, #name, name) #define REG_FUNC(nid, name) REG_FNID(SceAudio, nid, name)
psv_log_base sceAudio("SceAudio", []() DECLARE(arm_module_manager::SceAudio)("SceAudio", []()
{ {
sceAudio.on_load = nullptr;
sceAudio.on_unload = nullptr;
sceAudio.on_stop = nullptr;
sceAudio.on_error = nullptr;
REG_FUNC(0x5BC341E4, sceAudioOutOpenPort); REG_FUNC(0x5BC341E4, sceAudioOutOpenPort);
REG_FUNC(0x69E2E6B5, sceAudioOutReleasePort); REG_FUNC(0x69E2E6B5, sceAudioOutReleasePort);
REG_FUNC(0x02DB3F5F, sceAudioOutOutput); REG_FUNC(0x02DB3F5F, sceAudioOutOutput);

View file

@ -1,3 +1 @@
#pragma once #pragma once
extern psv_log_base sceAudio;

View file

@ -1,9 +1,11 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/ARMv7/PSVFuncList.h" #include "Emu/ARMv7/ARMv7Module.h"
#include "sceAudioIn.h" #include "sceAudioIn.h"
LOG_CHANNEL(sceAudioIn);
s32 sceAudioInOpenPort(s32 portType, s32 grain, s32 freq, s32 param) s32 sceAudioInOpenPort(s32 portType, s32 grain, s32 freq, s32 param)
{ {
throw EXCEPTION(""); throw EXCEPTION("");
@ -20,15 +22,10 @@ s32 sceAudioInInput(s32 port, vm::ptr<void> destPtr)
} }
#define REG_FUNC(nid, name) reg_psv_func(nid, &sceAudioIn, #name, name) #define REG_FUNC(nid, name) REG_FNID(SceAudioIn, nid, name)
psv_log_base sceAudioIn("SceAudioIn", []() DECLARE(arm_module_manager::SceAudioIn)("SceAudioIn", []()
{ {
sceAudioIn.on_load = nullptr;
sceAudioIn.on_unload = nullptr;
sceAudioIn.on_stop = nullptr;
sceAudioIn.on_error = nullptr;
REG_FUNC(0x638ADD2D, sceAudioInInput); REG_FUNC(0x638ADD2D, sceAudioInInput);
REG_FUNC(0x39B50DC1, sceAudioInOpenPort); REG_FUNC(0x39B50DC1, sceAudioInOpenPort);
REG_FUNC(0x3A61B8C4, sceAudioInReleasePort); REG_FUNC(0x3A61B8C4, sceAudioInReleasePort);

View file

@ -1,3 +1 @@
#pragma once #pragma once
extern psv_log_base sceAudioIn;

View file

@ -1,9 +1,11 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/ARMv7/PSVFuncList.h" #include "Emu/ARMv7/ARMv7Module.h"
#include "sceAudiodec.h" #include "sceAudiodec.h"
LOG_CHANNEL(sceAudiodec);
s32 sceAudiodecInitLibrary(u32 codecType, vm::ptr<SceAudiodecInitParam> pInitParam) s32 sceAudiodecInitLibrary(u32 codecType, vm::ptr<SceAudiodecInitParam> pInitParam)
{ {
throw EXCEPTION(""); throw EXCEPTION("");
@ -40,15 +42,10 @@ s32 sceAudiodecGetInternalError(vm::ptr<SceAudiodecCtrl> pCtrl, vm::ptr<s32> pIn
} }
#define REG_FUNC(nid, name) reg_psv_func(nid, &sceAudiodec, #name, name) #define REG_FUNC(nid, name) REG_FNID(SceAudiodecUser, nid, name)
psv_log_base sceAudiodec("SceAudiodec", []() DECLARE(arm_module_manager::SceAudiodec)("SceAudiodecUser", []()
{ {
sceAudiodec.on_load = nullptr;
sceAudiodec.on_unload = nullptr;
sceAudiodec.on_stop = nullptr;
sceAudiodec.on_error = nullptr;
REG_FUNC(0x445C2CEF, sceAudiodecInitLibrary); REG_FUNC(0x445C2CEF, sceAudiodecInitLibrary);
REG_FUNC(0x45719B9D, sceAudiodecTermLibrary); REG_FUNC(0x45719B9D, sceAudiodecTermLibrary);
REG_FUNC(0x4DFD3AAA, sceAudiodecCreateDecoder); REG_FUNC(0x4DFD3AAA, sceAudiodecCreateDecoder);

View file

@ -79,5 +79,3 @@ struct SceAudiodecCtrl
le_t<u32> wordLength; le_t<u32> wordLength;
vm::lptr<SceAudiodecInfo> pInfo; vm::lptr<SceAudiodecInfo> pInfo;
}; };
extern psv_log_base sceAudiodec;

View file

@ -1,9 +1,11 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/ARMv7/PSVFuncList.h" #include "Emu/ARMv7/ARMv7Module.h"
#include "sceAudioenc.h" #include "sceAudioenc.h"
LOG_CHANNEL(sceAudioenc);
s32 sceAudioencInitLibrary(u32 codecType, vm::ptr<SceAudioencInitParam> pInitParam) s32 sceAudioencInitLibrary(u32 codecType, vm::ptr<SceAudioencInitParam> pInitParam)
{ {
throw EXCEPTION(""); throw EXCEPTION("");
@ -45,15 +47,10 @@ s32 sceAudioencGetInternalError(vm::ptr<SceAudioencCtrl> pCtrl, vm::ptr<s32> pIn
} }
#define REG_FUNC(nid, name) reg_psv_func(nid, &sceAudioenc, #name, name) #define REG_FUNC(nid, name) REG_FNID(SceAudioencUser, nid, name)
psv_log_base sceAudioenc("SceAudioenc", []() DECLARE(arm_module_manager::SceAudioenc)("SceAudioencUser", []()
{ {
sceAudioenc.on_load = nullptr;
sceAudioenc.on_unload = nullptr;
sceAudioenc.on_stop = nullptr;
sceAudioenc.on_error = nullptr;
REG_FUNC(0x76EE4DC6, sceAudioencInitLibrary); REG_FUNC(0x76EE4DC6, sceAudioencInitLibrary);
REG_FUNC(0xAB32D022, sceAudioencTermLibrary); REG_FUNC(0xAB32D022, sceAudioencTermLibrary);
REG_FUNC(0x64C04AE8, sceAudioencCreateEncoder); REG_FUNC(0x64C04AE8, sceAudioencCreateEncoder);

View file

@ -55,5 +55,3 @@ struct SceAudioencCtrl
vm::lptr<SceAudioencInfo> pInfo; vm::lptr<SceAudioencInfo> pInfo;
vm::lptr<SceAudioencOptInfo> pOptInfo; vm::lptr<SceAudioencOptInfo> pOptInfo;
}; };
extern psv_log_base sceAudioenc;

View file

@ -1,9 +1,11 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/ARMv7/PSVFuncList.h" #include "Emu/ARMv7/ARMv7Module.h"
#include "sceCamera.h" #include "sceCamera.h"
LOG_CHANNEL(sceCamera);
s32 sceCameraOpen(s32 devnum, vm::ptr<SceCameraInfo> pInfo) s32 sceCameraOpen(s32 devnum, vm::ptr<SceCameraInfo> pInfo)
{ {
throw EXCEPTION(""); throw EXCEPTION("");
@ -210,15 +212,10 @@ void sceCameraUseCacheMemoryForTrial(s32 isCache)
} }
#define REG_FUNC(nid, name) reg_psv_func(nid, &sceCamera, #name, name) #define REG_FUNC(nid, name) REG_FNID(SceCamera, nid, name)
psv_log_base sceCamera("SceCamera", []() DECLARE(arm_module_manager::SceCamera)("SceCamera", []()
{ {
sceCamera.on_load = nullptr;
sceCamera.on_unload = nullptr;
sceCamera.on_stop = nullptr;
sceCamera.on_error = nullptr;
REG_FUNC(0xA462F801, sceCameraOpen); REG_FUNC(0xA462F801, sceCameraOpen);
REG_FUNC(0xCD6E1CFC, sceCameraClose); REG_FUNC(0xCD6E1CFC, sceCameraClose);
REG_FUNC(0xA8FEAE35, sceCameraStart); REG_FUNC(0xA8FEAE35, sceCameraStart);

View file

@ -36,5 +36,3 @@ struct SceCameraRead
vm::lptr<void> pvUBase; vm::lptr<void> pvUBase;
vm::lptr<void> pvVBase; vm::lptr<void> pvVBase;
}; };
extern psv_log_base sceCamera;

View file

@ -1,9 +1,11 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/ARMv7/PSVFuncList.h" #include "Emu/ARMv7/ARMv7Module.h"
#include "sceCodecEngine.h" #include "sceCodecEngine.h"
LOG_CHANNEL(sceCodecEngine);
s32 sceCodecEnginePmonStart() s32 sceCodecEnginePmonStart()
{ {
throw EXCEPTION(""); throw EXCEPTION("");
@ -25,15 +27,10 @@ s32 sceCodecEnginePmonReset()
} }
#define REG_FUNC(nid, name) reg_psv_func(nid, &sceCodecEngine, #name, name) #define REG_FUNC(nid, name) REG_FNID(SceCodecEngine, nid, name)
psv_log_base sceCodecEngine("SceCodecEngine", []() DECLARE(arm_module_manager::SceCodecEngine)("SceCodecEngine", []()
{ {
sceCodecEngine.on_load = nullptr;
sceCodecEngine.on_unload = nullptr;
sceCodecEngine.on_stop = nullptr;
sceCodecEngine.on_error = nullptr;
REG_FUNC(0x3E718890, sceCodecEnginePmonStart); REG_FUNC(0x3E718890, sceCodecEnginePmonStart);
REG_FUNC(0x268B1EF5, sceCodecEnginePmonStop); REG_FUNC(0x268B1EF5, sceCodecEnginePmonStop);
REG_FUNC(0x859E4A68, sceCodecEnginePmonGetProcessorLoad); REG_FUNC(0x859E4A68, sceCodecEnginePmonGetProcessorLoad);

View file

@ -5,5 +5,3 @@ struct SceCodecEnginePmonProcessorLoad
le_t<u32> size; le_t<u32> size;
le_t<u32> average; le_t<u32> average;
}; };
extern psv_log_base sceCodecEngine;

View file

@ -1,9 +1,11 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/ARMv7/PSVFuncList.h" #include "Emu/ARMv7/ARMv7Module.h"
#include "sceCommonDialog.h" #include "sceCommonDialog.h"
LOG_CHANNEL(sceCommonDialog);
s32 sceCommonDialogUpdate(vm::cptr<SceCommonDialogUpdateParam> updateParam) s32 sceCommonDialogUpdate(vm::cptr<SceCommonDialogUpdateParam> updateParam)
{ {
throw EXCEPTION(""); throw EXCEPTION("");
@ -205,15 +207,10 @@ s32 scePhotoReviewDialogAbort()
} }
#define REG_FUNC(nid, name) reg_psv_func(nid, &sceCommonDialog, #name, name) #define REG_FUNC(nid, name) REG_FNID(SceCommonDialog, nid, name)
psv_log_base sceCommonDialog("SceCommonDialog", []() DECLARE(arm_module_manager::SceCommonDialog)("SceCommonDialog", []()
{ {
sceCommonDialog.on_load = nullptr;
sceCommonDialog.on_unload = nullptr;
sceCommonDialog.on_stop = nullptr;
sceCommonDialog.on_error = nullptr;
REG_FUNC(0x90530F2F, sceCommonDialogUpdate); REG_FUNC(0x90530F2F, sceCommonDialogUpdate);
REG_FUNC(0x755FF270, sceMsgDialogInit); REG_FUNC(0x755FF270, sceMsgDialogInit);
REG_FUNC(0x4107019E, sceMsgDialogGetStatus); REG_FUNC(0x4107019E, sceMsgDialogGetStatus);

View file

@ -298,5 +298,3 @@ struct ScePhotoReviewDialogResult
le_t<s32> result; le_t<s32> result;
char reserved[32]; char reserved[32];
}; };
extern psv_log_base sceCommonDialog;

View file

@ -1,9 +1,11 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/ARMv7/PSVFuncList.h" #include "Emu/ARMv7/ARMv7Module.h"
#include "sceCtrl.h" #include "sceCtrl.h"
LOG_CHANNEL(sceCtrl);
s32 sceCtrlSetSamplingMode(u32 uiMode) s32 sceCtrlSetSamplingMode(u32 uiMode)
{ {
throw EXCEPTION(""); throw EXCEPTION("");
@ -45,15 +47,10 @@ s32 sceCtrlClearRapidFire(s32 port, s32 idx)
} }
#define REG_FUNC(nid, name) reg_psv_func(nid, &sceCtrl, #name, name) #define REG_FUNC(nid, name) REG_FNID(SceCtrl, nid, name)
psv_log_base sceCtrl("SceCtrl", []() DECLARE(arm_module_manager::SceCtrl)("SceCtrl", []()
{ {
sceCtrl.on_load = nullptr;
sceCtrl.on_unload = nullptr;
sceCtrl.on_stop = nullptr;
sceCtrl.on_error = nullptr;
REG_FUNC(0xA497B150, sceCtrlSetSamplingMode); REG_FUNC(0xA497B150, sceCtrlSetSamplingMode);
REG_FUNC(0xEC752AAF, sceCtrlGetSamplingMode); REG_FUNC(0xEC752AAF, sceCtrlGetSamplingMode);
REG_FUNC(0xA9C3CED6, sceCtrlPeekBufferPositive); REG_FUNC(0xA9C3CED6, sceCtrlPeekBufferPositive);

View file

@ -20,5 +20,3 @@ struct SceCtrlRapidFireRule
le_t<u32> uiMake; le_t<u32> uiMake;
le_t<u32> uiBreak; le_t<u32> uiBreak;
}; };
extern psv_log_base sceCtrl;

View file

@ -1,9 +1,11 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/ARMv7/PSVFuncList.h" #include "Emu/ARMv7/ARMv7Module.h"
#include "sceDbg.h" #include "sceDbg.h"
LOG_CHANNEL(sceDbg);
s32 sceDbgSetMinimumLogLevel(s32 minimumLogLevel) s32 sceDbgSetMinimumLogLevel(s32 minimumLogLevel)
{ {
throw EXCEPTION(""); throw EXCEPTION("");
@ -14,26 +16,21 @@ s32 sceDbgSetBreakOnErrorState(SceDbgBreakOnErrorState state)
throw EXCEPTION(""); throw EXCEPTION("");
} }
s32 sceDbgAssertionHandler(vm::cptr<char> pFile, s32 line, b8 stop, vm::cptr<char> pComponent, vm::cptr<char> pMessage, armv7_va_args_t va_args) s32 sceDbgAssertionHandler(vm::cptr<char> pFile, s32 line, b8 stop, vm::cptr<char> pComponent, vm::cptr<char> pMessage, arm_va_args_t va_args)
{ {
throw EXCEPTION(""); throw EXCEPTION("");
} }
s32 sceDbgLoggingHandler(vm::cptr<char> pFile, s32 line, s32 severity, vm::cptr<char> pComponent, vm::cptr<char> pMessage, armv7_va_args_t va_args) s32 sceDbgLoggingHandler(vm::cptr<char> pFile, s32 line, s32 severity, vm::cptr<char> pComponent, vm::cptr<char> pMessage, arm_va_args_t va_args)
{ {
throw EXCEPTION(""); throw EXCEPTION("");
} }
#define REG_FUNC(nid, name) reg_psv_func(nid, &sceDbg, #name, name) #define REG_FUNC(nid, name) REG_FNID(SceDbg, nid, name)
psv_log_base sceDbg("SceDbg", []() DECLARE(arm_module_manager::SceDbg)("SceDbg", []()
{ {
sceDbg.on_load = nullptr;
sceDbg.on_unload = nullptr;
sceDbg.on_stop = nullptr;
sceDbg.on_error = nullptr;
REG_FUNC(0x941622FA, sceDbgSetMinimumLogLevel); REG_FUNC(0x941622FA, sceDbgSetMinimumLogLevel);
REG_FUNC(0x1AF3678B, sceDbgAssertionHandler); REG_FUNC(0x1AF3678B, sceDbgAssertionHandler);
REG_FUNC(0x6605AB19, sceDbgLoggingHandler); REG_FUNC(0x6605AB19, sceDbgLoggingHandler);

View file

@ -5,5 +5,3 @@ enum SceDbgBreakOnErrorState : s32
SCE_DBG_DISABLE_BREAK_ON_ERROR = 0, SCE_DBG_DISABLE_BREAK_ON_ERROR = 0,
SCE_DBG_ENABLE_BREAK_ON_ERROR SCE_DBG_ENABLE_BREAK_ON_ERROR
}; };
extern psv_log_base sceDbg;

View file

@ -1,9 +1,11 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/ARMv7/PSVFuncList.h" #include "Emu/ARMv7/ARMv7Module.h"
#include "sceDeci4p.h" #include "sceDeci4p.h"
LOG_CHANNEL(sceDeci4p);
s32 sceKernelDeci4pOpen(vm::cptr<char> protoname, u32 protonum, u32 bufsize) s32 sceKernelDeci4pOpen(vm::cptr<char> protoname, u32 protonum, u32 bufsize)
{ {
throw EXCEPTION(""); throw EXCEPTION("");
@ -30,15 +32,10 @@ s32 sceKernelDeci4pRegisterCallback(s32 socketid, s32 cbid)
} }
#define REG_FUNC(nid, name) reg_psv_func(nid, &sceDeci4p, #name, name) #define REG_FUNC(nid, name) REG_FNID(SceDeci4pUserp, nid, name)
psv_log_base sceDeci4p("SceDeci4pUserp", []() DECLARE(arm_module_manager::SceDeci4p)("SceDeci4pUserp", []()
{ {
sceDeci4p.on_load = nullptr;
sceDeci4p.on_unload = nullptr;
sceDeci4p.on_stop = nullptr;
sceDeci4p.on_error = nullptr;
REG_FUNC(0x28578FE8, sceKernelDeci4pOpen); REG_FUNC(0x28578FE8, sceKernelDeci4pOpen);
REG_FUNC(0x63B0C50F, sceKernelDeci4pClose); REG_FUNC(0x63B0C50F, sceKernelDeci4pClose);
REG_FUNC(0x971E1C66, sceKernelDeci4pRead); REG_FUNC(0x971E1C66, sceKernelDeci4pRead);

View file

@ -1,5 +1,3 @@
#pragma once #pragma once
using SceKernelDeci4pCallback = s32(s32 notifyId, s32 notifyCount, s32 notifyArg, vm::ptr<void> pCommon); using SceKernelDeci4pCallback = s32(s32 notifyId, s32 notifyCount, s32 notifyArg, vm::ptr<void> pCommon);
extern psv_log_base sceDeci4p;

Some files were not shown because too many files have changed in this diff Show more