diff --git a/.gitmodules b/.gitmodules index fb181e64b1..6a79e8891c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -12,3 +12,6 @@ path = llvm url = https://github.com/llvm-mirror/llvm.git branch = release_35 +[submodule "minidx9"] + path = minidx9 + url = https://github.com/hrydgard/minidx9.git diff --git a/.travis.yml b/.travis.yml index 5b47d8dd7a..8fef9bddc8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,10 @@ compiler: - clang - gcc +env: + global: + - secure: "jA29KvTCTR7q4BMzPPUBGazjJwrIWa7k4fo5ZSMlyxh2NbztZTKQYwodgDcXBoptCd1KJ9H3FXwBnNdMNVnTkvoPL9uWnN4K/3D1D20FCag1kmlBwnaVqVei5cRiZ9TOMuaxhjkdg8pcrQLTlXEEdMZf6A2OW0VgoBGDVSX9nYc=" + branches: only: - master @@ -37,6 +41,15 @@ before_script: - cd build - cmake .. -script: - - make -j 4 +addons: + coverity_scan: + project: + name: "DHrpcs3/rpcs3" + description: "PS3 emulator/debugger" + notification_email: raul.tambre@gmail.com + build_command_prepend: "" + build_command: "make -j 4" + branch_pattern: coverity_scan +script: + - if [ ${COVERITY_SCAN_BRANCH} != 1 ]; then make -j 4; fi diff --git a/README.md b/README.md index 6b034b3ed4..b63652fffb 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,10 @@ RPCS3 ===== [![Build Status](https://travis-ci.org/DHrpcs3/rpcs3.svg?branch=master)](https://travis-ci.org/DHrpcs3/rpcs3) + + Coverity Scan Build Status + An open-source PlayStation 3 emulator/debugger written in C++. diff --git a/Utilities/BEType.h b/Utilities/BEType.h index 768e25770c..27997618bd 100644 --- a/Utilities/BEType.h +++ b/Utilities/BEType.h @@ -284,15 +284,9 @@ union _CRT_ALIGN(16) u128 _u64[1] = _u64[0] = 0; } - std::string to_hex() const - { - return fmt::Format("%016llx%016llx", _u64[1], _u64[0]); - } + std::string to_hex() const; - std::string to_xyzw() const - { - return fmt::Format("x: %g y: %g z: %g w: %g", _f[3], _f[2], _f[1], _f[0]); - } + std::string to_xyzw() const; static __forceinline u128 byteswap(const u128 val) { @@ -378,65 +372,97 @@ template struct se_t; template struct se_t { - static __forceinline T func(const T src) + static __forceinline u8 to_be(const T& src) { - return src; + return (u8&)src; + } + + static __forceinline T from_be(const u8 src) + { + return (T&)src; } }; template struct se_t { - static __forceinline T func(const T src) + static __forceinline u16 to_be(const T& src) { - const u16 res = _byteswap_ushort((u16&)src); + return _byteswap_ushort((u16&)src); + } + + static __forceinline T from_be(const u16 src) + { + const u16 res = _byteswap_ushort(src); return (T&)res; } }; template struct se_t { - static __forceinline T func(const T src) + static __forceinline u32 to_be(const T& src) { - const u32 res = _byteswap_ulong((u32&)src); + return _byteswap_ulong((u32&)src); + } + + static __forceinline T from_be(const u32 src) + { + const u32 res = _byteswap_ulong(src); return (T&)res; } }; template struct se_t { - static __forceinline T func(const T src) + static __forceinline u64 to_be(const T& src) { - const u64 res = _byteswap_uint64((u64&)src); + return _byteswap_uint64((u64&)src); + } + + static __forceinline T from_be(const u64 src) + { + const u64 res = _byteswap_uint64(src); return (T&)res; } }; -//template T re(const T val) { T res; se_t::func(res, val); return res; } -//template void re(T1& dst, const T2 val) { se_t::func(dst, val); } - -template struct const_se_t; -template struct const_se_t +template struct se_t { - static const T value = (T)_value; + static __forceinline u128 to_be(const T& src) + { + return u128::byteswap((u128&)src); + } + + static __forceinline T from_be(const u128& src) + { + const u128 res = u128::byteswap(src); + return (T&)res; + } }; -template struct const_se_t +template struct const_se_t; + +template struct const_se_t { - static const T value = ((_value >> 8) & 0xff) | ((_value << 8) & 0xff00); + static const u8 value = _value; }; -template struct const_se_t +template struct const_se_t { - static const T value = + static const u16 value = ((_value >> 8) & 0xff) | ((_value << 8) & 0xff00); +}; + +template struct const_se_t +{ + static const u32 value = ((_value >> 24) & 0x000000ff) | ((_value >> 8) & 0x0000ff00) | ((_value << 8) & 0x00ff0000) | ((_value << 24) & 0xff000000); }; -template struct const_se_t +template struct const_se_t { - static const T value = + static const u64 value = ((_value >> 56) & 0x00000000000000ff) | ((_value >> 40) & 0x000000000000ff00) | ((_value >> 24) & 0x0000000000ff0000) | @@ -447,17 +473,53 @@ template struct const_se_t ((_value << 56) & 0xff00000000000000); }; +template +struct be_storage_t +{ + static_assert(!size, "Bad be_storage_t type"); +}; + +template +struct be_storage_t +{ + typedef u8 type; +}; + +template +struct be_storage_t +{ + typedef u16 type; +}; + +template +struct be_storage_t +{ + typedef u32 type; +}; + +template +struct be_storage_t +{ + typedef u64 type; +}; + +template +struct be_storage_t +{ + typedef u128 type; +}; + +#define IS_LE_MACHINE + template class be_t { - static_assert(sizeof(T2) == 1 || sizeof(T2) == 2 || sizeof(T2) == 4 || sizeof(T2) == 8, "Bad be_t type"); - public: typedef typename std::remove_cv::type type; - static const bool is_le_machine = true; + typedef typename be_storage_t::type stype; private: - type m_data; + stype m_data; template struct _convert @@ -489,63 +551,68 @@ private: } }; -public: - const type& ToBE() const + const stype& ToBE() const { return m_data; } type ToLE() const { - return se_t::func(m_data); + return se_t::from_be(m_data); } - void FromBE(const type& value) + void FromBE(const stype& value) { m_data = value; } void FromLE(const type& value) { - m_data = se_t::func(value); + m_data = se_t::to_be(value); } - static be_t MakeFromLE(const type value) +public: + static be_t MakeFromLE(const type& value) { - type data = se_t::func(value); + stype data = se_t::to_be(value); return (be_t&)data; } - static be_t MakeFromBE(const type value) + static be_t MakeFromBE(const stype& value) { return (be_t&)value; } //make be_t from current machine byte ordering - static be_t make(const type value) + static be_t make(const type& value) { - return is_le_machine ? MakeFromLE(value) : MakeFromBE(value); +#ifdef IS_LE_MACHINE + return MakeFromLE(value); +#else + return MakeFromBE(value); +#endif } //get value in current machine byte ordering __forceinline type value() const { - return is_le_machine ? ToLE() : ToBE(); +#ifdef IS_LE_MACHINE + return ToLE(); +#else + return ToBE(); +#endif } - //be_t() = default; - //be_t(const be_t& value) = default; - - //be_t(type value) - //{ - // m_data = se_t::func(value); - //} + const stype& data() const + { + return ToBE(); + } be_t& operator = (const be_t& value) = default; - be_t& operator = (type value) + be_t& operator = (const type& value) { - m_data = se_t::func(value); + m_data = se_t::to_be(value); return *this; } @@ -691,86 +758,86 @@ template struct _se, T1, value> : pub #define se32(x) _se::value #define se64(x) _se::value -template __forceinline static u8 Read8(T& f) +template __forceinline u8 Read8(T& f) { u8 ret; f.Read(&ret, sizeof(ret)); return ret; } -template __forceinline static u16 Read16(T& f) +template __forceinline u16 Read16(T& f) { be_t ret; f.Read(&ret, sizeof(ret)); return ret; } -template __forceinline static u32 Read32(T& f) +template __forceinline u32 Read32(T& f) { be_t ret; f.Read(&ret, sizeof(ret)); return ret; } -template __forceinline static u64 Read64(T& f) +template __forceinline u64 Read64(T& f) { be_t ret; f.Read(&ret, sizeof(ret)); return ret; } -template __forceinline static u16 Read16LE(T& f) +template __forceinline u16 Read16LE(T& f) { u16 ret; f.Read(&ret, sizeof(ret)); return ret; } -template __forceinline static u32 Read32LE(T& f) +template __forceinline u32 Read32LE(T& f) { u32 ret; f.Read(&ret, sizeof(ret)); return ret; } -template __forceinline static u64 Read64LE(T& f) +template __forceinline u64 Read64LE(T& f) { u64 ret; f.Read(&ret, sizeof(ret)); return ret; } -template __forceinline static void Write8(T& f, const u8 data) +template __forceinline void Write8(T& f, const u8 data) { f.Write(&data, sizeof(data)); } -template __forceinline static void Write16LE(T& f, const u16 data) +template __forceinline void Write16LE(T& f, const u16 data) { f.Write(&data, sizeof(data)); } -template __forceinline static void Write32LE(T& f, const u32 data) +template __forceinline void Write32LE(T& f, const u32 data) { f.Write(&data, sizeof(data)); } -template __forceinline static void Write64LE(T& f, const u64 data) +template __forceinline void Write64LE(T& f, const u64 data) { f.Write(&data, sizeof(data)); } -template __forceinline static void Write16(T& f, const u16 data) +template __forceinline void Write16(T& f, const u16 data) { Write16LE(f, re16(data)); } -template __forceinline static void Write32(T& f, const u32 data) +template __forceinline void Write32(T& f, const u32 data) { Write32LE(f, re32(data)); } -template __forceinline static void Write64(T& f, const u64 data) +template __forceinline void Write64(T& f, const u64 data) { Write64LE(f, re64(data)); } @@ -821,4 +888,4 @@ template __forceinline void convert_le_be(Tto& dst, Tfrom&& src) { dst = convert_le_be_t::func(src); -} \ No newline at end of file +} diff --git a/Utilities/GNU.h b/Utilities/GNU.h index 91fc34ae50..b1988b4dfa 100644 --- a/Utilities/GNU.h +++ b/Utilities/GNU.h @@ -289,9 +289,7 @@ static __forceinline uint64_t InterlockedXor(volatile uint64_t* dest, uint64_t v static __forceinline uint32_t cntlz32(uint32_t arg) { -#if defined(__GNUG__) - return __builtin_clzl(arg); -#else +#if defined(_MSC_VER) unsigned long res; if (!_BitScanReverse(&res, arg)) { @@ -301,14 +299,21 @@ static __forceinline uint32_t cntlz32(uint32_t arg) { return res ^ 31; } +#else + if (arg) + { + return __builtin_clzll((uint64_t)arg) - 32; + } + else + { + return 32; + } #endif } static __forceinline uint64_t cntlz64(uint64_t arg) { -#if defined(__GNUG__) - return __builtin_clzll(arg); -#else +#if defined(_MSC_VER) unsigned long res; if (!_BitScanReverse64(&res, arg)) { @@ -318,6 +323,15 @@ static __forceinline uint64_t cntlz64(uint64_t arg) { return res ^ 63; } +#else + if (arg) + { + return __builtin_clzll(arg); + } + else + { + return 64; + } #endif } diff --git a/Utilities/Log.cpp b/Utilities/Log.cpp index 562be95d8a..44ed7dedf7 100644 --- a/Utilities/Log.cpp +++ b/Utilities/Log.cpp @@ -235,3 +235,17 @@ LogChannel &LogManager::getChannel(LogType type) { return mChannels[static_cast(type)]; } + +void log_message(Log::LogType type, Log::LogSeverity sev, const char* text) +{ + log_message(type, sev, std::string(text)); +} + +void log_message(Log::LogType type, Log::LogSeverity sev, std::string text) +{ + //another msvc bug makes this not work, uncomment this and delete everything else in this function when it's fixed + //Log::LogManager::getInstance().log({logType, severity, text}) + + Log::LogMessage msg{ type, sev, std::move(text) }; + Log::LogManager::getInstance().log(msg); +} diff --git a/Utilities/Log.h b/Utilities/Log.h index c40d2a82c6..d1710f05cf 100644 --- a/Utilities/Log.h +++ b/Utilities/Log.h @@ -126,18 +126,11 @@ static struct { inline operator Log::LogType() { return Log::LogType::SPU; } } S static struct { inline operator Log::LogType() { return Log::LogType::ARMv7; } } ARMv7; static struct { inline operator Log::LogType() { return Log::LogType::TTY; } } TTY; -inline void log_message(Log::LogType type, Log::LogSeverity sev, const char* text) -{ - //another msvc bug makes this not work, uncomment this and delete everything else in this function when it's fixed - //Log::LogManager::getInstance().log({logType, severity, text}) +void log_message(Log::LogType type, Log::LogSeverity sev, const char* text); +void log_message(Log::LogType type, Log::LogSeverity sev, std::string text); - Log::LogMessage msg{type, sev, text}; - Log::LogManager::getInstance().log(msg); +template +__noinline void log_message(Log::LogType type, Log::LogSeverity sev, const char* fmt, Targs... args) +{ + log_message(type, sev, fmt::detail::format(fmt, strlen(fmt), fmt::do_unveil(args)...)); } - -template -inline void log_message(Log::LogType type, Log::LogSeverity sev, const char* text, T arg, Ts... args) -{ - Log::LogMessage msg{type, sev, fmt::Format(text, arg, args...)}; - Log::LogManager::getInstance().log(msg); -} \ No newline at end of file diff --git a/Utilities/StrFmt.cpp b/Utilities/StrFmt.cpp index 1d3e6144e0..4c8c43cdf2 100644 --- a/Utilities/StrFmt.cpp +++ b/Utilities/StrFmt.cpp @@ -1,7 +1,160 @@ #include "stdafx.h" -#include "StrFmt.h" #include +std::string u128::to_hex() const +{ + return fmt::format("%016llx%016llx", _u64[1], _u64[0]); +} + +std::string u128::to_xyzw() const +{ + return fmt::Format("x: %g y: %g z: %g w: %g", _f[3], _f[2], _f[1], _f[0]); +} + +std::string fmt::to_hex(u64 value, size_t count) +{ + assert(count - 1 < 16); + count = std::max(count, 16 - cntlz64(value) / 4); + + char res[16] = {}; + + for (size_t i = count - 1; ~i; i--, value /= 16) + { + res[i] = "0123456789abcdef"[value % 16]; + } + + return std::string(res, count); +} + +std::string fmt::to_udec(u64 value) +{ + char res[20] = {}; + size_t first = sizeof(res); + + if (!value) + { + res[--first] = '0'; + } + + for (; value; value /= 10) + { + res[--first] = '0' + (value % 10); + } + + return std::string(&res[first], sizeof(res) - first); +} + +std::string fmt::to_sdec(s64 svalue) +{ + const bool sign = svalue < 0; + u64 value = sign ? -svalue : svalue; + + char res[20] = {}; + size_t first = sizeof(res); + + if (!value) + { + res[--first] = '0'; + } + + for (; value; value /= 10) + { + res[--first] = '0' + (value % 10); + } + + if (sign) + { + res[--first] = '-'; + } + + return std::string(&res[first], sizeof(res) - first); +} + +size_t fmt::detail::get_fmt_start(const char* fmt, size_t len) +{ + for (size_t i = 0; i < len; i++) + { + if (fmt[i] == '%') + { + return i; + } + } + + return len; +} + +size_t fmt::detail::get_fmt_len(const char* fmt, size_t len) +{ + assert(len >= 2 && fmt[0] == '%'); + + size_t res = 2; + + if (fmt[1] == '.' || fmt[1] == '0') + { + assert(len >= 4 && fmt[2] - '1' < 9); + res += 2; + fmt += 2; + len -= 2; + + if (fmt[1] == '1') + { + assert(len >= 3 && fmt[2] - '0' < 7); + res++; + fmt++; + len--; + } + } + + if (fmt[1] == 'l') + { + assert(len >= 3); + res++; + fmt++; + len--; + } + + if (fmt[1] == 'l') + { + assert(len >= 3); + res++; + fmt++; + len--; + } + + return res; +} + +size_t fmt::detail::get_fmt_precision(const char* fmt, size_t len) +{ + assert(len >= 2); + + if (fmt[1] == '.' || fmt[1] == '0') + { + assert(len >= 4 && fmt[2] - '1' < 9); + + if (fmt[2] == '1') + { + assert(len >= 5 && fmt[3] - '0' < 7); + return 10 + fmt[3] - '0'; + } + + return fmt[2] - '0'; + } + + return 1; +} + +std::string fmt::detail::format(const char* fmt, size_t len) +{ + const size_t fmt_start = get_fmt_start(fmt, len); + if (fmt_start != len) + { + throw "Excessive formatting: " + std::string(fmt, len); + } + + return std::string(fmt, len); +} + extern const std::string fmt::placeholder = "???"; std::string replace_first(const std::string& src, const std::string& from, const std::string& to) diff --git a/Utilities/StrFmt.h b/Utilities/StrFmt.h index 963bb8b1b8..36a1ee4abb 100644 --- a/Utilities/StrFmt.h +++ b/Utilities/StrFmt.h @@ -1,18 +1,16 @@ #pragma once + class wxString; #if defined(_MSC_VER) #define snprintf _snprintf #endif -namespace fmt{ - using std::string; - using std::ostream; - using std::ostringstream; - +namespace fmt +{ struct empty_t{}; - extern const string placeholder; + extern const std::string placeholder; template std::string AfterLast(const std::string& source, T searchstr) @@ -51,11 +49,11 @@ namespace fmt{ // `fmt::placeholder` after `pos` everything in `fmt` after pos is written // to `os`. Then `arg` is written to `os` after appending a space character template - empty_t write(const string &fmt, ostream &os, string::size_type &pos, T &&arg) + empty_t write(const std::string &fmt, std::ostream &os, std::string::size_type &pos, T &&arg) { - string::size_type ins = fmt.find(placeholder, pos); + std::string::size_type ins = fmt.find(placeholder, pos); - if (ins == string::npos) + if (ins == std::string::npos) { os.write(fmt.data() + pos, fmt.size() - pos); os << ' ' << arg; @@ -77,10 +75,10 @@ namespace fmt{ // inserted use `fmt::placeholder`. If there's not enough placeholders // the rest of the arguments are appended at the end, seperated by spaces template - string SFormat(const string &fmt, Args&& ... parameters) + std::string SFormat(const std::string &fmt, Args&& ... parameters) { - ostringstream os; - string::size_type pos = 0; + std::ostringstream os; + std::string::size_type pos = 0; std::initializer_list { write(fmt, os, pos, parameters)... }; if (!fmt.empty()) @@ -88,7 +86,7 @@ namespace fmt{ os.write(fmt.data() + pos, fmt.size() - pos); } - string result = os.str(); + std::string result = os.str(); return result; } @@ -98,10 +96,10 @@ namespace fmt{ //wrapper to deal with advance sprintf formating options with automatic length finding template - string Format(const char* fmt, Args ... parameters) + std::string Format(const char* fmt, Args ... parameters) { size_t length = 256; - string str; + std::string str; for (;;) { @@ -116,7 +114,7 @@ namespace fmt{ #endif if (printlen < length) { - str = string(buffptr.data(), printlen); + str = std::string(buffptr.data(), printlen); break; } length *= 2; @@ -175,13 +173,480 @@ namespace fmt{ return src; } + std::string to_hex(u64 value, size_t count = 1); + std::string to_udec(u64 value); + std::string to_sdec(s64 value); + + namespace detail + { + size_t get_fmt_start(const char* fmt, size_t len); + size_t get_fmt_len(const char* fmt, size_t len); + size_t get_fmt_precision(const char* fmt, size_t len); + + template + struct get_fmt + { + static_assert(!sizeof(T), "Unsupported fmt::format argument"); + }; + + template<> + struct get_fmt + { + static std::string text(const char* fmt, size_t len, u8 arg) + { + if (fmt[len - 1] == 'x') + { + return to_hex(arg, get_fmt_precision(fmt, len)); + } + else if (fmt[len - 1] == 'd') + { + return to_udec(arg); + } + else + { + throw "Invalid formatting (u8): " + std::string(fmt, len); + } + + return{}; + } + }; + + template<> + struct get_fmt + { + static std::string text(const char* fmt, size_t len, u16 arg) + { + if (fmt[len - 1] == 'x') + { + return to_hex(arg, get_fmt_precision(fmt, len)); + } + else if (fmt[len - 1] == 'd') + { + return to_udec(arg); + } + else + { + throw "Invalid formatting (u16): " + std::string(fmt, len); + } + + return{}; + } + }; + + template<> + struct get_fmt + { + static std::string text(const char* fmt, size_t len, u32 arg) + { + if (fmt[len - 1] == 'x') + { + return to_hex(arg, get_fmt_precision(fmt, len)); + } + else if (fmt[len - 1] == 'd') + { + return to_udec(arg); + } + else + { + throw "Invalid formatting (u32): " + std::string(fmt, len); + } + + return{}; + } + }; + + template<> + struct get_fmt + { + static std::string text(const char* fmt, size_t len, u64 arg) + { + if (fmt[len - 1] == 'x') + { + return to_hex(arg, get_fmt_precision(fmt, len)); + } + else if (fmt[len - 1] == 'd') + { + return to_udec(arg); + } + else + { + throw "Invalid formatting (u64): " + std::string(fmt, len); + } + + return{}; + } + }; + + template<> + struct get_fmt + { + static std::string text(const char* fmt, size_t len, s8 arg) + { + if (fmt[len - 1] == 'x') + { + return to_hex((u8)arg, get_fmt_precision(fmt, len)); + } + else if (fmt[len - 1] == 'd') + { + return to_sdec(arg); + } + else + { + throw "Invalid formatting (s8): " + std::string(fmt, len); + } + + return{}; + } + }; + + template<> + struct get_fmt + { + static std::string text(const char* fmt, size_t len, s16 arg) + { + if (fmt[len - 1] == 'x') + { + return to_hex((u16)arg, get_fmt_precision(fmt, len)); + } + else if (fmt[len - 1] == 'd') + { + return to_sdec(arg); + } + else + { + throw "Invalid formatting (s16): " + std::string(fmt, len); + } + + return{}; + } + }; + + template<> + struct get_fmt + { + static std::string text(const char* fmt, size_t len, s32 arg) + { + if (fmt[len - 1] == 'x') + { + return to_hex((u32)arg, get_fmt_precision(fmt, len)); + } + else if (fmt[len - 1] == 'd') + { + return to_sdec(arg); + } + else + { + throw "Invalid formatting (s32): " + std::string(fmt, len); + } + + return{}; + } + }; + + template<> + struct get_fmt + { + static std::string text(const char* fmt, size_t len, s64 arg) + { + if (fmt[len - 1] == 'x') + { + return to_hex((u64)arg, get_fmt_precision(fmt, len)); + } + else if (fmt[len - 1] == 'd') + { + return to_sdec(arg); + } + else + { + throw "Invalid formatting (s64): " + std::string(fmt, len); + } + + return{}; + } + }; + + template<> + struct get_fmt + { + static std::string text(const char* fmt, size_t len, float arg) + { + if (fmt[len - 1] == 'x') + { + return to_hex((u32&)arg, get_fmt_precision(fmt, len)); + } + else if (fmt[len - 1] == 'f') + { + return std::to_string(arg); + } + else + { + throw "Invalid formatting (float): " + std::string(fmt, len); + } + + return{}; + } + }; + + template<> + struct get_fmt + { + static std::string text(const char* fmt, size_t len, double arg) + { + if (fmt[len - 1] == 'x') + { + return to_hex((u64&)arg, get_fmt_precision(fmt, len)); + } + else if (fmt[len - 1] == 'f') + { + return std::to_string(arg); + } + else + { + throw "Invalid formatting (double): " + std::string(fmt, len); + } + + return{}; + } + }; + + template<> + struct get_fmt + { + static std::string text(const char* fmt, size_t len, bool arg) + { + if (fmt[len - 1] == 'x') + { + return to_hex(arg, get_fmt_precision(fmt, len)); + } + else if (fmt[len - 1] == 'd') + { + return arg ? "1" : "0"; + } + else if (fmt[len - 1] == 's') + { + return arg ? "true" : "false"; + } + else + { + throw "Invalid formatting (bool): " + std::string(fmt, len); + } + + return{}; + } + }; + + template<> + struct get_fmt + { + static std::string text(const char* fmt, size_t len, char* arg) + { + if (fmt[len - 1] == 's') + { + return arg; + } + else + { + throw "Invalid formatting (char*): " + std::string(fmt, len); + } + + return{}; + } + }; + + template<> + struct get_fmt + { + static std::string text(const char* fmt, size_t len, const char* arg) + { + if (fmt[len - 1] == 's') + { + return arg; + } + else + { + throw "Invalid formatting (const char*): " + std::string(fmt, len); + } + + return{}; + } + }; + + //template + //struct get_fmt + //{ + // static std::string text(const char* fmt, size_t len, const char(&arg)[size]) + // { + // if (fmt[len - 1] == 's') + // { + // return std::string(arg, size); + // } + // else + // { + // throw "Invalid formatting (char[size]): " + std::string(fmt, len); + // } + + // return{}; + // } + //}; + + //template + //struct get_fmt + //{ + // static std::string text(const char* fmt, size_t len, const char(&arg)[size]) + // { + // if (fmt[len - 1] == 's') + // { + // return std::string(arg, size); + // } + // else + // { + // throw "Invalid formatting (const char[size]): " + std::string(fmt, len); + // } + + // return{}; + // } + //}; + + template<> + struct get_fmt + { + static std::string text(const char* fmt, size_t len, const std::string& arg) + { + if (fmt[len - 1] == 's') + { + return arg; + } + else + { + throw "Invalid formatting (std::string): " + std::string(fmt, len); + } + + return{}; + } + }; + + std::string format(const char* fmt, size_t len); // terminator + + template + std::string format(const char* fmt, size_t len, const T& arg, Args... args) + { + const size_t fmt_start = get_fmt_start(fmt, len); + const size_t fmt_len = get_fmt_len(fmt + fmt_start, len - fmt_start); + const size_t fmt_end = fmt_start + fmt_len; + + return std::string(fmt, fmt_start) + get_fmt::text(fmt + fmt_start, fmt_len, arg) + format(fmt + fmt_end, len - fmt_end, args...); + } + }; + + template::value> + struct unveil + { + typedef T result_type; + + __forceinline static result_type get_value(const T& arg) + { + return arg; + } + }; + + template + struct unveil + { + typedef const char* result_type; + + __forceinline static result_type get_value(const char(&arg)[N]) + { + return arg; + } + }; + + template<> + struct unveil + { + typedef const std::string& result_type; + + __forceinline static result_type get_value(const std::string& arg) + { + return arg; + } + }; + + template + struct unveil + { + typedef typename std::underlying_type::type result_type; + + __forceinline static result_type get_value(const T& arg) + { + return static_cast(arg); + } + }; + + template + struct unveil, false> + { + typedef typename unveil::result_type result_type; + + __forceinline static result_type get_value(const be_t& arg) + { + return unveil::get_value(arg.value()); + } + }; + + template + __forceinline typename unveil::result_type do_unveil(const T& arg) + { + return unveil::get_value(arg); + } + + /* + fmt::format(const char* fmt, args...) + + Formatting function with very limited functionality (compared to printf-like formatting) and be_t<> support + + Supported types: + + u8, s8 (%x, %d) + u16, s16 (%x, %d) + u32, s32 (%x, %d) + u64, s64 (%x, %d) + float (%x, %f) + double (%x, %f) + bool (%x, %d, %s) + char*, const char*, std::string (%s) + + be_t<> of any appropriate type in this list (fmt::unveil) + enum of any appropriate type in this list (fmt::unveil) + + External specializations (can be found in another headers): + vm::ps3::ptr (fmt::unveil) (vm_ptr.h) (with appropriate address type, using .addr() can be avoided) + vm::ps3::bptr (fmt::unveil) (vm_ptr.h) + vm::psv::ptr (fmt::unveil) (vm_ptr.h) + vm::ps3::ref (fmt::unveil) (vm_ref.h) + vm::ps3::bref (fmt::unveil) (vm_ref.h) + vm::psv::ref (fmt::unveil) (vm_ref.h) + + Supported formatting: + %d - decimal; to_sdec() and to_udec() + %x - hexadecimal; to_hex(), %08x - hexadecimal with minimal length (from 02 to 016) + %s - string; generates "true" or "false" for bool + %f - floating point; only basic std::to_string() functionality + + Other features are not supported. + */ + template + __forceinline std::string format(const char* fmt, Args... args) + { + return detail::format(fmt, strlen(fmt), do_unveil(args)...); + } + //convert a wxString to a std::string encoded in utf8 //CAUTION, only use this to interface with wxWidgets classes std::string ToUTF8(const wxString& right); //convert a std::string encoded in utf8 to a wxString //CAUTION, only use this to interface with wxWidgets classes - wxString FromUTF8(const string& right); + wxString FromUTF8(const std::string& right); //TODO: remove this after every snippet that uses it is gone //WARNING: not fully compatible with CmpNoCase from wxString diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index 6014c607bf..2539c791cd 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -1,16 +1,24 @@ #include "stdafx.h" -#include "Emu/System.h" #include "Log.h" +#include "rpcs3/Ini.h" +#include "Emu/System.h" +#include "Emu/CPU/CPUThread.h" +#include "Emu/SysCalls/SysCalls.h" #include "Thread.h" #ifdef _WIN32 #include +#else +#include +#include #endif void SetCurrentThreadDebugName(const char* threadName) { -#ifdef _WIN32 // this is VS-specific way to set thread names for the debugger +#if defined(_MSC_VER) // this is VS-specific way to set thread names for the debugger + #pragma pack(push,8) + struct THREADNAME_INFO { DWORD dwType; @@ -18,6 +26,7 @@ void SetCurrentThreadDebugName(const char* threadName) DWORD dwThreadID; DWORD dwFlags; } info; + #pragma pack(pop) info.dwType = 0x1000; @@ -32,9 +41,300 @@ void SetCurrentThreadDebugName(const char* threadName) __except (EXCEPTION_EXECUTE_HANDLER) { } + #endif } +enum x64_reg_t : u32 +{ + X64R_EAX, + X64R_ECX, + X64R_EDX, + X64R_EBX, + X64R_ESP, + X64R_EBP, + X64R_ESI, + X64R_EDI, + X64R_R8D, + X64R_R9D, + X64R_R10D, + X64R_R11D, + X64R_R12D, + X64R_R13D, + X64R_R14D, + X64R_R15D, + X64R32 = X64R_EAX, + + X64_IMM32, +}; + +enum x64_op_t : u32 +{ + X64OP_LOAD, // obtain and put the value into x64 register (from Memory.ReadMMIO32, for example) + X64OP_STORE, // take the value from x64 register or an immediate and use it (pass in Memory.WriteMMIO32, for example) + // example: add eax,[rax] -> X64OP_LOAD_ADD (add the value to x64 register) + // example: add [rax],eax -> X64OP_LOAD_ADD_STORE (this will probably never happen for MMIO registers) +}; + +void decode_x64_reg_op(const u8* code, x64_op_t& decoded_op, x64_reg_t& decoded_reg, size_t& decoded_size) +{ + // simple analysis of x64 code allows to reinterpret MOV or other instructions in any desired way + decoded_size = 0; + + u8 rex = 0; + u8 reg = 0; // set to 8 by REX prefix + u8 pg2 = 0; + + // check prefixes: + for (;; code++, decoded_size++) + { + switch (const u8 prefix = *code) + { + case 0xf0: throw fmt::format("decode_x64_reg_op(%016llxh): 0x%02x (LOCK prefix) found", (size_t)code - decoded_size, prefix); // group 1 + case 0xf2: throw fmt::format("decode_x64_reg_op(%016llxh): 0x%02x (REPNE/REPNZ prefix) found", (size_t)code - decoded_size, prefix); // group 1 + case 0xf3: throw fmt::format("decode_x64_reg_op(%016llxh): 0x%02x (REP/REPE/REPZ prefix) found", (size_t)code - decoded_size, prefix); // group 1 + + case 0x2e: // group 2 + case 0x36: + case 0x3e: + case 0x26: + case 0x64: + case 0x65: + { + if (!pg2) + { + pg2 = prefix; // probably, segment register + continue; + } + else + { + throw fmt::format("decode_x64_reg_op(%016llxh): 0x%02x (group 2 prefix) found after 0x%02x", (size_t)code - decoded_size, prefix, pg2); + } + } + + case 0x66: throw fmt::format("decode_x64_reg_op(%016llxh): 0x%02x (operand-size override prefix) found", (size_t)code - decoded_size, prefix); // group 3 + case 0x67: throw fmt::format("decode_x64_reg_op(%016llxh): 0x%02x (address-size override prefix) found", (size_t)code - decoded_size, prefix); // group 4 + + default: + { + if ((prefix & 0xf0) == 0x40) // check REX prefix + { + if (rex) + { + throw fmt::format("decode_x64_reg_op(%016llxh): 0x%02x (REX prefix) found after 0x%02x", (size_t)code - decoded_size, prefix, rex); + } + if (prefix & 0x80) // check REX.W bit + { + throw fmt::format("decode_x64_reg_op(%016llxh): 0x%02x (REX.W bit) found", (size_t)code - decoded_size, prefix); + } + if (prefix & 0x04) // check REX.R bit + { + reg = 8; + } + rex = prefix; + continue; + } + } + } + + break; + } + + auto get_modRM_r32 = [](const u8* code, const u8 reg_base) -> x64_reg_t + { + return (x64_reg_t)((((*code & 0x38) >> 3) | reg_base) + X64R32); + }; + + auto get_modRM_size = [](const u8* code) -> size_t + { + switch (*code >> 6) // check Mod + { + case 0: return (*code & 0x07) == 4 ? 2 : 1; // check SIB + case 1: return (*code & 0x07) == 4 ? 3 : 2; // check SIB (disp8) + case 2: return (*code & 0x07) == 4 ? 6 : 5; // check SIB (disp32) + default: return 1; + } + }; + + decoded_size++; + switch (const u8 op1 = *code++) + { + case 0x89: // MOV r/m32, r32 + { + decoded_op = X64OP_STORE; + decoded_reg = get_modRM_r32(code, reg); + decoded_size += get_modRM_size(code); + return; + } + case 0x8b: // MOV r32, r/m32 + { + decoded_op = X64OP_LOAD; + decoded_reg = get_modRM_r32(code, reg); + decoded_size += get_modRM_size(code); + return; + } + case 0xc7: + { + if (get_modRM_r32(code, 0) == X64R_EAX) // MOV r/m32, imm32 (not tested) + { + decoded_op = X64OP_STORE; + decoded_reg = X64_IMM32; + decoded_size = get_modRM_size(code) + 4; + return; + } + } + default: + { + throw fmt::format("decode_x64_reg_op(%016llxh): unsupported opcode found (0x%02x, 0x%02x, 0x%02x)", (size_t)code - decoded_size, op1, code[0], code[1]); + } + } +} + +#ifdef _WIN32 + +typedef CONTEXT x64_context; + +#define RIP 16 +#define X64REG(context, reg) ((&context->Rax)[reg]) + +#else + +typedef ucontext_t x64_context; +typedef decltype(REG_RIP) reg_table_t; +#define RIP 16 + +static const reg_table_t reg_table[17] = +{ + REG_RAX, REG_RCX, REG_RDX, REG_RBX, REG_RSP, REG_RBP, REG_RSI, REG_RDI, + REG_R8, REG_R9, REG_R10, REG_R11, REG_R12, REG_R13, REG_R14, REG_R15, REG_RIP +}; + +#define X64REG(context, reg) (context->uc_mcontext.gregs[reg_table[reg]]) + +#endif + +bool handle_access_violation(const u32 addr, x64_context* context) +{ + if (addr - RAW_SPU_BASE_ADDR < (6 * RAW_SPU_OFFSET) && (addr % RAW_SPU_OFFSET) >= RAW_SPU_PROB_OFFSET) // RawSPU MMIO registers + { + // one x64 instruction is manually decoded and interpreted + x64_op_t op; + x64_reg_t reg; + size_t size; + decode_x64_reg_op((const u8*)X64REG(context, RIP), op, reg, size); + + // get x64 reg value (for store operations) + u64 reg_value; + if (reg - X64R32 < 16) + { + // load the value from x64 register + reg_value = (u32)X64REG(context, reg - X64R32); + } + else if (reg == X64_IMM32) + { + // load the immediate value (assuming it's at the end of the instruction) + reg_value = *(u32*)(X64REG(context, RIP) + size - 4); + } + else + { + assert(!"Invalid x64_reg_t value"); + } + + bool save_reg = false; + + switch (op) + { + case X64OP_LOAD: + { + reg_value = re32(Memory.ReadMMIO32(addr)); + save_reg = true; + break; + } + case X64OP_STORE: + { + Memory.WriteMMIO32(addr, re32((u32)reg_value)); + break; + } + default: assert(!"Invalid x64_op_t value"); + } + + // save x64 reg value (for load operations) + if (save_reg) + { + if (reg - X64R32 < 16) + { + // store the value into x64 register + X64REG(context, reg - X64R32) = (u32)reg_value; + } + else + { + assert(!"Invalid x64_reg_t value (saving)"); + } + } + + // skip decoded instruction + X64REG(context, RIP) += size; + return true; + } + + // TODO: allow recovering from a page fault as a feature of PS3 virtual memory + return false; +} + +#ifdef _WIN32 + +void _se_translator(unsigned int u, EXCEPTION_POINTERS* pExp) +{ + const u64 addr64 = (u64)pExp->ExceptionRecord->ExceptionInformation[1] - (u64)Memory.GetBaseAddr(); + const bool is_writing = pExp->ExceptionRecord->ExceptionInformation[0] != 0; + if (u == EXCEPTION_ACCESS_VIOLATION && (u32)addr64 == addr64) + { + if (handle_access_violation((u32)addr64, pExp->ContextRecord)) + { + // restore context (further code shouldn't be reached) + RtlRestoreContext(pExp->ContextRecord, nullptr); + + // it's dangerous because destructors won't be executed + } + + throw fmt::format("Access violation %s location 0x%llx", is_writing ? "writing" : "reading", addr64); + } + + // else some fatal error (should crash) +} + +#else + +void signal_handler(int sig, siginfo_t* info, void* uct) +{ + const u64 addr64 = (u64)info->si_addr - (u64)Memory.GetBaseAddr(); + if ((u32)addr64 == addr64 && GetCurrentNamedThread()) + { + if (handle_access_violation((u32)addr64, (ucontext_t*)uct)) + { + return; // proceed execution + } + + // TODO: this may be wrong + throw fmt::format("Access violation at location 0x%llx", addr64); + } + + // else some fatal error + exit(EXIT_FAILURE); +} + +const int sigaction_result = []() -> int +{ + struct sigaction sa; + + sa.sa_flags = SA_SIGINFO; + sigemptyset(&sa.sa_mask); + sa.sa_sigaction = signal_handler; + return sigaction(SIGSEGV, &sa, NULL); +}(); + +#endif + thread_local NamedThreadBase* g_tls_this_thread = nullptr; std::atomic g_thread_count(0); @@ -45,7 +345,7 @@ NamedThreadBase* GetCurrentNamedThread() void SetCurrentNamedThread(NamedThreadBase* value) { - auto old_value = g_tls_this_thread; + const auto old_value = g_tls_this_thread; if (old_value == value) { @@ -54,7 +354,7 @@ void SetCurrentNamedThread(NamedThreadBase* value) if (value && value->m_tls_assigned.exchange(true)) { - LOG_ERROR(GENERAL, "Thread '%s' was already assigned to g_tls_this_thread of another thread", value->GetThreadName().c_str()); + LOG_ERROR(GENERAL, "Thread '%s' was already assigned to g_tls_this_thread of another thread", value->GetThreadName()); g_tls_this_thread = nullptr; } else @@ -119,6 +419,12 @@ void ThreadBase::Start() { SetCurrentThreadDebugName(GetThreadName().c_str()); +#ifdef _WIN32 + auto old_se_translator = _set_se_translator(_se_translator); +#else + if (sigaction_result == -1) assert(!"sigaction() failed"); +#endif + SetCurrentNamedThread(this); g_thread_count++; @@ -138,6 +444,10 @@ void ThreadBase::Start() m_alive = false; SetCurrentNamedThread(nullptr); g_thread_count--; + +#ifdef _WIN32 + _set_se_translator(old_se_translator); +#endif }); } @@ -187,31 +497,82 @@ bool ThreadBase::TestDestroy() const return m_destroy; } -thread::thread(const std::string& name, std::function func) : m_name(name) +thread_t::thread_t(const std::string& name, bool autojoin, std::function func) + : m_name(name) + , m_state(TS_NON_EXISTENT) + , m_autojoin(autojoin) { start(func); } -thread::thread(const std::string& name) : m_name(name) +thread_t::thread_t(const std::string& name, std::function func) + : m_name(name) + , m_state(TS_NON_EXISTENT) + , m_autojoin(false) +{ + start(func); +} + +thread_t::thread_t(const std::string& name) + : m_name(name) + , m_state(TS_NON_EXISTENT) + , m_autojoin(false) { } -thread::thread() +thread_t::thread_t() + : m_state(TS_NON_EXISTENT) + , m_autojoin(false) { } -void thread::start(std::function func) +void thread_t::set_name(const std::string& name) { + m_name = name; +} + +thread_t::~thread_t() +{ + if (m_state == TS_JOINABLE) + { + if (m_autojoin) + { + m_thr.join(); + } + else + { + m_thr.detach(); + } + } +} + +void thread_t::start(std::function func) +{ + if (m_state.exchange(TS_NON_EXISTENT) == TS_JOINABLE) + { + m_thr.join(); // forcefully join previously created thread + } + std::string name = m_name; - m_thr = std::thread([func, name]() { SetCurrentThreadDebugName(name.c_str()); +#ifdef _WIN32 + auto old_se_translator = _set_se_translator(_se_translator); +#else + if (sigaction_result == -1) assert(!"sigaction() failed"); +#endif + NamedThreadBase info(name); SetCurrentNamedThread(&info); g_thread_count++; + if (Ini.HLELogging.GetValue()) + { + LOG_NOTICE(HLE, name + " started"); + } + try { func(); @@ -225,24 +586,57 @@ void thread::start(std::function func) LOG_ERROR(GENERAL, "%s: %s", name.c_str(), e.c_str()); } + if (Emu.IsStopped()) + { + LOG_NOTICE(HLE, name + " aborted"); + } + else if (Ini.HLELogging.GetValue()) + { + LOG_NOTICE(HLE, name + " ended"); + } + SetCurrentNamedThread(nullptr); g_thread_count--; + +#ifdef _WIN32 + _set_se_translator(old_se_translator); +#endif }); + + if (m_state.exchange(TS_JOINABLE) == TS_JOINABLE) + { + assert(!"thread_t::start() failed"); // probably started from another thread + } } -void thread::detach() +void thread_t::detach() { - m_thr.detach(); + if (m_state.exchange(TS_NON_EXISTENT) == TS_JOINABLE) + { + m_thr.detach(); + } + else + { + assert(!"thread_t::detach() failed"); // probably joined or detached + } } -void thread::join() +void thread_t::join() { - m_thr.join(); + if (m_state.exchange(TS_NON_EXISTENT) == TS_JOINABLE) + { + m_thr.join(); + } + else + { + assert(!"thread_t::join() failed"); // probably joined or detached + } } -bool thread::joinable() const +bool thread_t::joinable() const { - return m_thr.joinable(); + //return m_thr.joinable(); + return m_state == TS_JOINABLE; } bool waiter_map_t::is_stopped(u64 signal_id) @@ -306,7 +700,10 @@ void waiter_map_t::notify(u64 signal_id) } } -bool squeue_test_exit(const volatile bool* do_exit) +const std::function SQUEUE_ALWAYS_EXIT = [](){ return true; }; +const std::function SQUEUE_NEVER_EXIT = [](){ return false; }; + +bool squeue_test_exit() { - return Emu.IsStopped() || (do_exit && *do_exit); + return Emu.IsStopped(); } diff --git a/Utilities/Thread.h b/Utilities/Thread.h index 4b54317bec..4e51438636 100644 --- a/Utilities/Thread.h +++ b/Utilities/Thread.h @@ -54,18 +54,34 @@ public: virtual void Task() = 0; }; -class thread +class thread_t { + enum thread_state_t + { + TS_NON_EXISTENT, + TS_JOINABLE, + }; + + std::atomic m_state; std::string m_name; std::thread m_thr; + bool m_autojoin; public: - thread(const std::string& name, std::function func); - thread(const std::string& name); - thread(); + thread_t(const std::string& name, bool autojoin, std::function func); + thread_t(const std::string& name, std::function func); + thread_t(const std::string& name); + thread_t(); + ~thread_t(); + thread_t(const thread_t& right) = delete; + thread_t(thread_t&& right) = delete; + + thread_t& operator =(const thread_t& right) = delete; + thread_t& operator =(thread_t&& right) = delete; public: + void set_name(const std::string& name); void start(std::function func); void detach(); void join(); @@ -148,7 +164,10 @@ public: void notify(u64 signal_id); }; -bool squeue_test_exit(const volatile bool* do_exit); +extern const std::function SQUEUE_ALWAYS_EXIT; +extern const std::function SQUEUE_NEVER_EXIT; + +bool squeue_test_exit(); template class squeue_t @@ -199,7 +218,7 @@ public: return m_sync.read_relaxed().count == sq_size; } - bool push(const T& data, const volatile bool* do_exit = nullptr) + bool push(const T& data, const std::function& test_exit) { u32 pos = 0; @@ -222,7 +241,7 @@ public: return SQSVR_OK; })) { - if (res == SQSVR_FAILED && squeue_test_exit(do_exit)) + if (res == SQSVR_FAILED && (test_exit() || squeue_test_exit())) { return false; } @@ -247,14 +266,22 @@ public: return true; } - bool try_push(const T& data) + bool push(const T& data, const volatile bool* do_exit) { - static const volatile bool no_wait = true; - - return push(data, &no_wait); + return push(data, [do_exit](){ return do_exit && *do_exit; }); } - bool pop(T& data, const volatile bool* do_exit = nullptr) + __forceinline bool push(const T& data) + { + return push(data, SQUEUE_NEVER_EXIT); + } + + __forceinline bool try_push(const T& data) + { + return push(data, SQUEUE_ALWAYS_EXIT); + } + + bool pop(T& data, const std::function& test_exit) { u32 pos = 0; @@ -277,7 +304,7 @@ public: return SQSVR_OK; })) { - if (res == SQSVR_FAILED && squeue_test_exit(do_exit)) + if (res == SQSVR_FAILED && (test_exit() || squeue_test_exit())) { return false; } @@ -307,14 +334,22 @@ public: return true; } - bool try_pop(T& data) + bool pop(T& data, const volatile bool* do_exit) { - static const volatile bool no_wait = true; - - return pop(data, &no_wait); + return pop(data, [do_exit](){ return do_exit && *do_exit; }); } - bool peek(T& data, u32 start_pos = 0, const volatile bool* do_exit = nullptr) + __forceinline bool pop(T& data) + { + return pop(data, SQUEUE_NEVER_EXIT); + } + + __forceinline bool try_pop(T& data) + { + return pop(data, SQUEUE_ALWAYS_EXIT); + } + + bool peek(T& data, u32 start_pos, const std::function& test_exit) { assert(start_pos < sq_size); u32 pos = 0; @@ -332,13 +367,13 @@ public: { return SQSVR_LOCKED; } - + sync.pop_lock = 1; pos = sync.position + start_pos; return SQSVR_OK; })) { - if (res == SQSVR_FAILED && squeue_test_exit(do_exit)) + if (res == SQSVR_FAILED && (test_exit() || squeue_test_exit())) { return false; } @@ -361,11 +396,19 @@ public: return true; } - bool try_peek(T& data, u32 start_pos = 0) + bool peek(T& data, u32 start_pos, const volatile bool* do_exit) { - static const volatile bool no_wait = true; + return peek(data, start_pos, [do_exit](){ return do_exit && *do_exit; }); + } - return peek(data, start_pos, &no_wait); + __forceinline bool peek(T& data, u32 start_pos = 0) + { + return peek(data, start_pos, SQUEUE_NEVER_EXIT); + } + + __forceinline bool try_peek(T& data, u32 start_pos = 0) + { + return peek(data, start_pos, SQUEUE_ALWAYS_EXIT); } class squeue_data_t diff --git a/Utilities/rFile.cpp b/Utilities/rFile.cpp index 912452ef89..e6f657d39e 100644 --- a/Utilities/rFile.cpp +++ b/Utilities/rFile.cpp @@ -114,7 +114,7 @@ bool rRmdir(const std::string &dir) if (int err = rmdir(dir.c_str())) #endif { - LOG_ERROR(GENERAL, "Error deleting directory %s: %i", dir.c_str(), GET_API_ERROR); + LOG_ERROR(GENERAL, "Error deleting directory %s: 0x%llx", dir.c_str(), (u64)GET_API_ERROR); return false; } return true; @@ -149,7 +149,7 @@ bool rRemoveFile(const std::string &file) if (int err = unlink(file.c_str())) #endif { - LOG_ERROR(GENERAL, "Error deleting %s: %i", file.c_str(), GET_API_ERROR); + LOG_ERROR(GENERAL, "Error deleting file %s: 0x%llx", file.c_str(), (u64)GET_API_ERROR); return false; } return true; diff --git a/minidx9 b/minidx9 new file mode 160000 index 0000000000..ec19e64346 --- /dev/null +++ b/minidx9 @@ -0,0 +1 @@ +Subproject commit ec19e643461c84dbb256f6faaaab02cba61d4edc diff --git a/rpcs3/CMakeLists.txt b/rpcs3/CMakeLists.txt index 9245ac9125..c5e6ebe4a0 100644 --- a/rpcs3/CMakeLists.txt +++ b/rpcs3/CMakeLists.txt @@ -5,6 +5,13 @@ include(cotire) project(rpcs3) +# Generate git-version.h at build time. +add_custom_target(GitVersion ALL + DEPENDS something_that_never_exists) +add_custom_command(OUTPUT something_that_never_exists + COMMAND ${CMAKE_COMMAND} -DSOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR} + -P ${CMAKE_CURRENT_SOURCE_DIR}/git-version.cmake) + if (CMAKE_COMPILER_IS_GNUCXX) if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7.0) message(FATAL_ERROR "GCC ${CMAKE_CXX_COMPILER_VERSION} is too old.") diff --git a/rpcs3/Crypto/unedat.cpp b/rpcs3/Crypto/unedat.cpp index 27ddbffb6a..f4d57c49d0 100644 --- a/rpcs3/Crypto/unedat.cpp +++ b/rpcs3/Crypto/unedat.cpp @@ -288,7 +288,7 @@ int decrypt_data(rFile *in, rFile *out, EDAT_HEADER *edat, NPD_HEADER *npd, unsi if (!decrypt(hash_mode, crypto_mode, (npd->version == 4), enc_data, dec_data, length, key_result, iv, hash, hash_result)) { if (verbose) - LOG_WARNING(LOADER, "EDAT: Block at offset 0x%llx has invalid hash!", offset); + LOG_WARNING(LOADER, "EDAT: Block at offset 0x%llx has invalid hash!", (u64)offset); return 1; } @@ -695,7 +695,7 @@ bool extract_data(rFile *input, rFile *output, const char* input_file_name, unsi LOG_NOTICE(LOADER, "SDAT HEADER"); LOG_NOTICE(LOADER, "SDAT flags: 0x%08X", EDAT->flags); LOG_NOTICE(LOADER, "SDAT block size: 0x%08X", EDAT->block_size); - LOG_NOTICE(LOADER, "SDAT file size: 0x%08X", EDAT->file_size); + LOG_NOTICE(LOADER, "SDAT file size: 0x%08X", (u64)EDAT->file_size); } // Generate SDAT key. @@ -708,7 +708,7 @@ bool extract_data(rFile *input, rFile *output, const char* input_file_name, unsi LOG_NOTICE(LOADER, "EDAT HEADER"); LOG_NOTICE(LOADER, "EDAT flags: 0x%08X", EDAT->flags); LOG_NOTICE(LOADER, "EDAT block size: 0x%08X", EDAT->block_size); - LOG_NOTICE(LOADER, "EDAT file size: 0x%08X", EDAT->file_size); + LOG_NOTICE(LOADER, "EDAT file size: 0x%08X", (u64)EDAT->file_size); } // Perform header validation (EDAT only). diff --git a/rpcs3/Crypto/unpkg.cpp b/rpcs3/Crypto/unpkg.cpp index 5d7846046f..65e1d3e394 100644 --- a/rpcs3/Crypto/unpkg.cpp +++ b/rpcs3/Crypto/unpkg.cpp @@ -158,24 +158,31 @@ bool LoadEntries(rFile& dec_pkg_f, PKGHeader* m_header, PKGEntry *m_entries) bool UnpackEntry(rFile& dec_pkg_f, const PKGEntry& entry, std::string dir) { - u8 buf[BUF_SIZE]; + char buf[BUF_SIZE]; dec_pkg_f.Seek(entry.name_offset); dec_pkg_f.Read(buf, entry.name_size); buf[entry.name_size] = 0; - switch (entry.type & (0xff)) + switch (entry.type.data() >> 24) { - case PKG_FILE_ENTRY_NPDRM: - case PKG_FILE_ENTRY_NPDRMEDAT: - case PKG_FILE_ENTRY_SDAT: - case PKG_FILE_ENTRY_REGULAR: + case PKG_FILE_ENTRY_NPDRM: + case PKG_FILE_ENTRY_NPDRMEDAT: + case PKG_FILE_ENTRY_SDAT: + case PKG_FILE_ENTRY_REGULAR: + { + rFile out; + auto path = dir + std::string(buf, entry.name_size); + if (rExists(path)) + { + LOG_WARNING(LOADER, "PKG Loader: File is overwritten: %s", path.c_str()); + } + + if (out.Create(path, true /* overwriting */)) { - rFile out; - out.Create(dir + std::string(reinterpret_cast(buf), entry.name_size)); dec_pkg_f.Seek(entry.file_offset); - for (u64 size = 0; size < entry.file_size; ) { + for (u64 size = 0; size < entry.file_size;) { size += dec_pkg_f.Read(buf, BUF_SIZE); if (size > entry.file_size) out.Write(buf, BUF_SIZE - (size - entry.file_size)); @@ -183,14 +190,33 @@ bool UnpackEntry(rFile& dec_pkg_f, const PKGEntry& entry, std::string dir) out.Write(buf, BUF_SIZE); } out.Close(); + return true; + } + else + { + LOG_ERROR(LOADER, "PKG Loader: Could not create file: %s", path.c_str()); + return false; } - break; - - case PKG_FILE_ENTRY_FOLDER: - rMkdir(dir + std::string(reinterpret_cast(buf), entry.name_size)); - break; } - return true; + + case PKG_FILE_ENTRY_FOLDER: + { + auto path = dir + std::string(buf, entry.name_size); + if (!rExists(path) && !rMkdir(path)) + { + LOG_ERROR(LOADER, "PKG Loader: Could not create directory: %s", path.c_str()); + return false; + } + + return true; + } + + default: + { + LOG_ERROR(LOADER, "PKG Loader: unknown PKG file entry: 0x%x", entry.type); + return false; + } + } } int Unpack(rFile& pkg_f, std::string src, std::string dst) diff --git a/rpcs3/Emu/ARMv7/ARMv7Thread.h b/rpcs3/Emu/ARMv7/ARMv7Thread.h index ce63376273..22e655188d 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Thread.h +++ b/rpcs3/Emu/ARMv7/ARMv7Thread.h @@ -1,5 +1,4 @@ #pragma once - #include "Emu/CPU/CPUThread.h" #include "Emu/Memory/Memory.h" @@ -210,3 +209,131 @@ public: return *this; } }; + +template::value> +struct cast_armv7_gpr +{ + static_assert(is_enum, "Invalid type for cast_armv7_gpr"); + + typedef typename std::underlying_type::type underlying_type; + + __forceinline static u32 to_gpr(const T& value) + { + return cast_armv7_gpr::to_gpr(static_cast(value)); + } + + __forceinline static T from_gpr(const u32 reg) + { + return static_cast(cast_armv7_gpr::from_gpr(reg)); + } +}; + +template<> +struct cast_armv7_gpr +{ + __forceinline static u32 to_gpr(const u8& value) + { + return value; + } + + __forceinline static u8 from_gpr(const u32 reg) + { + return static_cast(reg); + } +}; + +template<> +struct cast_armv7_gpr +{ + __forceinline static u32 to_gpr(const u16& value) + { + return value; + } + + __forceinline static u16 from_gpr(const u32 reg) + { + return static_cast(reg); + } +}; + +template<> +struct cast_armv7_gpr +{ + __forceinline static u32 to_gpr(const u32& value) + { + return value; + } + + __forceinline static u32 from_gpr(const u32 reg) + { + return reg; + } +}; + +template<> +struct cast_armv7_gpr +{ + __forceinline static u32 to_gpr(const s8& value) + { + return value; + } + + __forceinline static s8 from_gpr(const u32 reg) + { + return static_cast(reg); + } +}; + +template<> +struct cast_armv7_gpr +{ + __forceinline static u32 to_gpr(const s16& value) + { + return value; + } + + __forceinline static s16 from_gpr(const u32 reg) + { + return static_cast(reg); + } +}; + +template<> +struct cast_armv7_gpr +{ + __forceinline static u32 to_gpr(const s32& value) + { + return value; + } + + __forceinline static s32 from_gpr(const u32 reg) + { + return static_cast(reg); + } +}; + +template<> +struct cast_armv7_gpr +{ + __forceinline static u32 to_gpr(const bool& value) + { + return value; + } + + __forceinline static bool from_gpr(const u32 reg) + { + return reinterpret_cast(reg); + } +}; + +template +__forceinline u32 cast_to_armv7_gpr(const T& value) +{ + return cast_armv7_gpr::to_gpr(value); +} + +template +__forceinline T cast_from_armv7_gpr(const u32 reg) +{ + return cast_armv7_gpr::from_gpr(reg); +} diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp index 562193cb22..7ae9f6a2a6 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp @@ -95,20 +95,18 @@ s32 sceKernelCreateThread( s32 cpuAffinityMask, vm::psv::ptr pOptParam) { - sceLibKernel.Error("sceKernelCreateThread(pName_addr=0x%x ('%s'), entry_addr=0x%x, initPriority=%d, stackSize=0x%x, attr=0x%x, cpuAffinityMask=0x%x, pOptParam_addr=0x%x)", - pName.addr(), pName.get_ptr(), entry.addr(), initPriority, stackSize, attr, cpuAffinityMask, pOptParam.addr()); + sceLibKernel.Error("sceKernelCreateThread(pName=0x%x, entry=0x%x, initPriority=%d, stackSize=0x%x, attr=0x%x, cpuAffinityMask=0x%x, pOptParam=0x%x)", + pName, entry, initPriority, stackSize, attr, cpuAffinityMask, pOptParam); - std::string name = pName.get_ptr(); - - ARMv7Thread& new_thread = *(ARMv7Thread*)&Emu.GetCPU().AddThread(CPU_THREAD_ARMv7); + ARMv7Thread& new_thread = static_cast(Emu.GetCPU().AddThread(CPU_THREAD_ARMv7)); u32 id = new_thread.GetId(); new_thread.SetEntry(entry.addr() ^ 1); new_thread.SetPrio(initPriority); new_thread.SetStackSize(stackSize); - new_thread.SetName(name); + new_thread.SetName(pName.get_ptr()); - sceLibKernel.Error("*** New ARMv7 Thread [%s] (entry=0x%x): id = %d", name.c_str(), entry, id); + sceLibKernel.Error("*** New ARMv7 Thread [%s] (entry=0x%x)^1: id = %d", pName.get_ptr(), entry, id); new_thread.Run(); @@ -119,7 +117,7 @@ s32 sceKernelCreateThread( s32 sceKernelStartThread(s32 threadId, u32 argSize, vm::psv::ptr pArgBlock) { - sceLibKernel.Error("sceKernelStartThread(threadId=%d, argSize=%d, pArgBlock_addr=0x%x)", threadId, argSize, pArgBlock.addr()); + sceLibKernel.Error("sceKernelStartThread(threadId=%d, argSize=%d, pArgBlock=0x%x)", threadId, argSize, pArgBlock); std::shared_ptr t = Emu.GetCPU().GetThread(threadId); @@ -128,15 +126,17 @@ s32 sceKernelStartThread(s32 threadId, u32 argSize, vm::psv::ptr pAr RETURN_ERROR(SCE_KERNEL_ERROR_INVALID_UID); } + ARMv7Thread& thread = static_cast(*t); + // push arg block onto the stack - u32 pos = (static_cast(t.get())->SP -= argSize); + const u32 pos = (thread.SP -= argSize); memcpy(vm::get_ptr(pos), pArgBlock.get_ptr(), argSize); // set SceKernelThreadEntry function arguments - static_cast(t.get())->write_gpr(0, argSize); - static_cast(t.get())->write_gpr(1, pos); + thread.write_gpr(0, argSize); + thread.write_gpr(1, pos); - t->Exec(); + thread.Exec(); return SCE_OK; } @@ -208,7 +208,7 @@ s32 sceKernelChangeCurrentThreadAttr(u32 clearAttr, u32 setAttr) s32 sceKernelGetThreadExitStatus(s32 threadId, vm::psv::ptr pExitStatus) { - sceLibKernel.Todo("sceKernelGetThreadExitStatus(threadId=%d, pExitStatus_addr=0x%x)", threadId, pExitStatus.addr()); + sceLibKernel.Todo("sceKernelGetThreadExitStatus(threadId=%d, pExitStatus=0x%x)", threadId, pExitStatus); return SCE_OK; } @@ -229,21 +229,21 @@ s32 sceKernelCheckWaitableStatus() s32 sceKernelGetThreadInfo(s32 threadId, vm::psv::ptr pInfo) { - sceLibKernel.Todo("sceKernelGetThreadInfo(threadId=%d, pInfo_addr=0x%x)", threadId, pInfo.addr()); + sceLibKernel.Todo("sceKernelGetThreadInfo(threadId=%d, pInfo=0x%x)", threadId, pInfo); return SCE_OK; } s32 sceKernelGetThreadRunStatus(vm::psv::ptr pStatus) { - sceLibKernel.Todo("sceKernelGetThreadRunStatus(pStatus_addr=0x%x)", pStatus.addr()); + sceLibKernel.Todo("sceKernelGetThreadRunStatus(pStatus=0x%x)", pStatus); return SCE_OK; } s32 sceKernelGetSystemInfo(vm::psv::ptr pInfo) { - sceLibKernel.Todo("sceKernelGetSystemInfo(pInfo_addr=0x%x)", pInfo.addr()); + sceLibKernel.Todo("sceKernelGetSystemInfo(pInfo=0x%x)", pInfo); return SCE_OK; } @@ -285,14 +285,14 @@ s32 sceKernelDelayThreadCB(u32 usec) s32 sceKernelWaitThreadEnd(s32 threadId, vm::psv::ptr pExitStatus, vm::psv::ptr pTimeout) { - sceLibKernel.Todo("sceKernelWaitThreadEnd(threadId=%d, pExitStatus_addr=0x%x, pTimeout_addr=0x%x)", threadId, pExitStatus.addr(), pTimeout.addr()); + sceLibKernel.Todo("sceKernelWaitThreadEnd(threadId=%d, pExitStatus=0x%x, pTimeout=0x%x)", threadId, pExitStatus, pTimeout); return SCE_OK; } s32 sceKernelWaitThreadEndCB(s32 threadId, vm::psv::ptr pExitStatus, vm::psv::ptr pTimeout) { - sceLibKernel.Todo("sceKernelWaitThreadEndCB(threadId=%d, pExitStatus_addr=0x%x, pTimeout_addr=0x%x)", threadId, pExitStatus.addr(), pTimeout.addr()); + sceLibKernel.Todo("sceKernelWaitThreadEndCB(threadId=%d, pExitStatus=0x%x, pTimeout=0x%x)", threadId, pExitStatus, pTimeout); return SCE_OK; } diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp index a9173350a1..9abcf593e4 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp @@ -26,9 +26,9 @@ namespace sce_libc_func }); } - void printf(vm::psv::ptr fmt) + void printf(vm::psv::ptr fmt) // va_args... { - sceLibc.Error("printf(fmt_addr=0x%x)", fmt.addr()); + sceLibc.Error("printf(fmt=0x%x)", fmt); LOG_NOTICE(TTY, "%s", fmt.get_ptr()); } @@ -40,14 +40,14 @@ namespace sce_libc_func void memcpy(vm::psv::ptr dst, vm::psv::ptr src, u32 size) { - sceLibc.Error("memcpy(dst_addr=0x%x, src_addr=0x%x, size=0x%x)", dst.addr(), src.addr(), size); + sceLibc.Error("memcpy(dst=0x%x, src=0x%x, size=0x%x)", dst, src, size); ::memcpy(dst.get_ptr(), src.get_ptr(), size); } void _Assert(vm::psv::ptr text, vm::psv::ptr func) { - sceLibc.Error("_Assert(text_addr=0x%x, func_addr=0x%x)", text.addr(), func.addr()); + sceLibc.Error("_Assert(text=0x%x, func=0x%x)", text, func); LOG_ERROR(TTY, "%s : %s", func.get_ptr(), text.get_ptr()); Emu.Pause(); diff --git a/rpcs3/Emu/ARMv7/PSVFuncList.cpp b/rpcs3/Emu/ARMv7/PSVFuncList.cpp index d1d3d2b1a6..84262b3b0f 100644 --- a/rpcs3/Emu/ARMv7/PSVFuncList.cpp +++ b/rpcs3/Emu/ARMv7/PSVFuncList.cpp @@ -1,4 +1,5 @@ #include "stdafx.h" +#include #include "Utilities/Log.h" #include "Emu/System.h" #include "PSVFuncList.h" @@ -7,29 +8,19 @@ std::vector g_psv_func_list; void add_psv_func(psv_func& data) { + // setup special functions (without NIDs) if (!g_psv_func_list.size()) { psv_func unimplemented; - unimplemented.nid = 0x00000000; // must not be a valid id - unimplemented.name = "INVALID FUNCTION (0x0)"; - unimplemented.func.reset(new psv_func_detail::func_binder([]() -> u32 - { - LOG_ERROR(HLE, "Unimplemented function executed"); - Emu.Pause(); - - return 0xffffffffu; - })); + unimplemented.nid = 0; + unimplemented.name = "Special function (unimplemented stub)"; + unimplemented.func.reset(new psv_func_detail::func_binder([](ARMv7Thread& CPU){ CPU.m_last_syscall = vm::psv::read32(CPU.PC + 4); throw "Unimplemented function executed"; })); g_psv_func_list.push_back(unimplemented); psv_func hle_return; - hle_return.nid = 0x00000001; // must not be a valid id - hle_return.name = "INVALID FUNCTION (0x1)"; - hle_return.func.reset(new psv_func_detail::func_binder([](ARMv7Thread& CPU) - { - CPU.FastStop(); - - return; - })); + hle_return.nid = 1; + hle_return.name = "Special function (return from HLE)"; + hle_return.func.reset(new psv_func_detail::func_binder([](ARMv7Thread& CPU){ CPU.FastStop(); })); g_psv_func_list.push_back(hle_return); } @@ -40,7 +31,7 @@ psv_func* get_psv_func_by_nid(u32 nid) { for (auto& f : g_psv_func_list) { - if (f.nid == nid) + if (f.nid == nid && &f - g_psv_func_list.data() >= 2 /* special functions count */) { return &f; } @@ -61,8 +52,13 @@ u32 get_psv_func_index(psv_func* func) void execute_psv_func_by_index(ARMv7Thread& CPU, u32 index) { assert(index < g_psv_func_list.size()); + + auto old_last_syscall = CPU.m_last_syscall; + CPU.m_last_syscall = g_psv_func_list[index].nid; (*g_psv_func_list[index].func)(CPU); + + CPU.m_last_syscall = old_last_syscall; } extern psv_log_base sceLibc; diff --git a/rpcs3/Emu/ARMv7/PSVFuncList.h b/rpcs3/Emu/ARMv7/PSVFuncList.h index 998225799d..9fe75a647a 100644 --- a/rpcs3/Emu/ARMv7/PSVFuncList.h +++ b/rpcs3/Emu/ARMv7/PSVFuncList.h @@ -425,7 +425,7 @@ namespace psv_func_detail static __forceinline T func(ARMv7Thread& CPU) { - return (T&)CPU.GPR[g_count - 1]; + return cast_from_armv7_gpr(CPU.GPR[g_count - 1]); } }; @@ -444,7 +444,7 @@ namespace psv_func_detail struct bind_arg { static_assert(v_count <= 0, "TODO: Unsupported argument type (vector)"); - static_assert(sizeof(T) == 16, "Invalid function argument type for ARG_VECTOR"); + static_assert(std::is_same::value, "Invalid function argument type for ARG_VECTOR"); static __forceinline T func(ARMv7Thread& CPU) { @@ -460,8 +460,9 @@ namespace psv_func_detail static __forceinline T func(ARMv7Thread& CPU) { + // TODO: check const u32 res = CPU.GetStackArg(g_count); - return (T&)res; + return cast_from_armv7_gpr(res); } }; @@ -473,9 +474,9 @@ namespace psv_func_detail static_assert(type == ARG_GENERAL, "Wrong use of bind_result template"); static_assert(sizeof(T) <= 4, "Invalid function result type for ARG_GENERAL"); - static __forceinline void func(ARMv7Thread& CPU, T result) + static __forceinline void func(ARMv7Thread& CPU, const T& result) { - (T&)CPU.GPR[0] = result; + CPU.GPR[0] = cast_to_armv7_gpr(result); } }; @@ -484,7 +485,7 @@ namespace psv_func_detail //{ // static_assert(sizeof(T) <= 8, "Invalid function result type for ARG_FLOAT"); - // static __forceinline void func(ARMv7Thread& CPU, T result) + // static __forceinline void func(ARMv7Thread& CPU, const T& result) // { // } //}; @@ -492,9 +493,9 @@ namespace psv_func_detail //template //struct bind_result //{ - // static_assert(sizeof(T) == 16, "Invalid function result type for ARG_VECTOR"); + // static_assert(std::is_same::value, "Invalid function result type for ARG_VECTOR"); - // static __forceinline void func(ARMv7Thread& CPU, const T result) + // static __forceinline void func(ARMv7Thread& CPU, const T& result) // { // } //}; @@ -518,21 +519,21 @@ namespace psv_func_detail }; template - static __forceinline RT call(F f, Tuple && t) + __forceinline RT call(F f, Tuple && t) { typedef typename std::decay::type ttype; return psv_func_detail::call_impl::value, std::tuple_size::value>::call(f, std::forward(t)); } template - static __forceinline std::tuple<> iterate(ARMv7Thread& CPU) + __forceinline std::tuple<> iterate(ARMv7Thread& CPU) { // terminator return std::tuple<>(); } template - static __forceinline std::tuple iterate(ARMv7Thread& CPU) + __forceinline std::tuple iterate(ARMv7Thread& CPU) { static_assert(!std::is_pointer::value, "Invalid function argument type (pointer)"); static_assert(!std::is_reference::value, "Invalid function argument type (reference)"); @@ -549,6 +550,16 @@ namespace psv_func_detail return std::tuple_cat(std::tuple(bind_arg::func(CPU)), iterate(CPU)); } + template + struct result_type + { + static_assert(!std::is_pointer::value, "Invalid function result type (pointer)"); + static_assert(!std::is_reference::value, "Invalid function result type (reference)"); + static const bool is_float = std::is_floating_point::value; + static const bool is_vector = std::is_same::value; + static const bind_arg_type value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL); + }; + template class func_binder; @@ -605,13 +616,7 @@ namespace psv_func_detail virtual void operator()(ARMv7Thread& CPU) { - static_assert(!std::is_pointer::value, "Invalid function result type (pointer)"); - static_assert(!std::is_reference::value, "Invalid function result type (reference)"); - const bool is_float = std::is_floating_point::value; - const bool is_vector = std::is_same::value; - const bind_arg_type t = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL); - - bind_result::func(CPU, call(m_call, iterate<0, 0, 0, T...>(CPU))); + bind_result::value>::func(CPU, call(m_call, iterate<0, 0, 0, T...>(CPU))); } }; @@ -630,13 +635,7 @@ namespace psv_func_detail virtual void operator()(ARMv7Thread& CPU) { - static_assert(!std::is_pointer::value, "Invalid function result type (pointer)"); - static_assert(!std::is_reference::value, "Invalid function result type (reference)"); - const bool is_float = std::is_floating_point::value; - const bool is_vector = std::is_same::value; - const bind_arg_type t = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL); - - bind_result::func(CPU, call(m_call, std::tuple_cat(std::tuple(CPU), iterate<0, 0, 0, T...>(CPU)))); + bind_result::value>::func(CPU, call(m_call, std::tuple_cat(std::tuple(CPU), iterate<0, 0, 0, T...>(CPU)))); } }; } diff --git a/rpcs3/Emu/Audio/AL/OpenALThread.cpp b/rpcs3/Emu/Audio/AL/OpenALThread.cpp index 5d24514d46..14fcd2dc5e 100644 --- a/rpcs3/Emu/Audio/AL/OpenALThread.cpp +++ b/rpcs3/Emu/Audio/AL/OpenALThread.cpp @@ -11,11 +11,9 @@ ALCenum g_last_alc_error = ALC_NO_ERROR; #define checkForAlError(sit) if((g_last_al_error = alGetError()) != AL_NO_ERROR) printAlError(g_last_al_error, sit) #define checkForAlcError(sit) if((g_last_alc_error = alcGetError(m_device)) != ALC_NO_ERROR) printAlcError(g_last_alc_error, sit) -static const ALenum g_audio_format = Ini.AudioConvertToU16.GetValue() ? AL_FORMAT_STEREO16 : AL_FORMAT_STEREO_FLOAT32; - void printAlError(ALenum err, const char* situation) { - if(err != AL_NO_ERROR) + if (err != AL_NO_ERROR) { LOG_ERROR(HLE, "%s: OpenAL error 0x%04x", situation, err); Emu.Pause(); @@ -24,7 +22,7 @@ void printAlError(ALenum err, const char* situation) void printAlcError(ALCenum err, const char* situation) { - if(err != ALC_NO_ERROR) + if (err != ALC_NO_ERROR) { LOG_ERROR(HLE, "%s: OpenALC error 0x%04x", situation, err); Emu.Pause(); @@ -63,7 +61,7 @@ void OpenALThread::Play() alGetSourcei(m_source, AL_SOURCE_STATE, &state); checkForAlError("OpenALThread::Play -> alGetSourcei"); - if(state != AL_PLAYING) + if (state != AL_PLAYING) { alSourcePlay(m_source); checkForAlError("alSourcePlay"); @@ -74,7 +72,7 @@ void OpenALThread::Close() { alSourceStop(m_source); checkForAlError("alSourceStop"); - if (alIsSource(m_source)) + if (alIsSource(m_source)) alDeleteSources(1, &m_source); alDeleteBuffers(g_al_buffers_count, m_buffers); @@ -87,7 +85,7 @@ void OpenALThread::Stop() checkForAlError("alSourceStop"); } -void OpenALThread::Open(const void* src, ALsizei size) +void OpenALThread::Open(const void* src, int size) { alGenSources(1, &m_source); checkForAlError("alGenSources"); @@ -100,9 +98,10 @@ void OpenALThread::Open(const void* src, ALsizei size) m_buffer_size = size; - for(uint i=0; i alGetSourcei"); - - while(size) + + while (size) { - if(buffers_count-- <= 0) + if (buffers_count-- <= 0) { Play(); alGetSourcei(m_source, AL_BUFFERS_PROCESSED, &buffers_count); checkForAlError("OpenALThread::AddData(in loop) -> alGetSourcei"); - + continue; } @@ -135,8 +134,9 @@ void OpenALThread::AddData(const void* src, ALsizei size) checkForAlError("alSourceUnqueueBuffers"); int bsize = size < m_buffer_size ? size : m_buffer_size; - if (!AddBlock(buffer, bsize, bsrc)) - LOG_ERROR(HLE, "OpenALThread::AddBlock: invalid block size: %d", bsize); + + alBufferData(buffer, Ini.AudioConvertToU16.GetValue() ? AL_FORMAT_71CHN16 : AL_FORMAT_71CHN32, bsrc, bsize, 48000); + checkForAlError("alBufferData"); alSourceQueueBuffers(m_source, 1, &buffer); checkForAlError("alSourceQueueBuffers"); @@ -146,14 +146,4 @@ void OpenALThread::AddData(const void* src, ALsizei size) } Play(); -} - -bool OpenALThread::AddBlock(const ALuint buffer_id, const ALsizei size, const void* src) -{ - if (size < 1) return false; - - alBufferData(buffer_id, g_audio_format, src, size, 48000); - checkForAlError("alBufferData"); - - return true; -} +} \ No newline at end of file diff --git a/rpcs3/Emu/Audio/AL/OpenALThread.h b/rpcs3/Emu/Audio/AL/OpenALThread.h index 49d4dd4f79..a02a100435 100644 --- a/rpcs3/Emu/Audio/AL/OpenALThread.h +++ b/rpcs3/Emu/Audio/AL/OpenALThread.h @@ -1,8 +1,9 @@ #pragma once +#include "Emu/Audio/AudioThread.h" #include "OpenAL/include/alext.h" -class OpenALThread +class OpenALThread : public AudioThread { private: static const uint g_al_buffers_count = 16; @@ -14,15 +15,13 @@ private: ALsizei m_buffer_size; public: - ~OpenALThread(); + virtual ~OpenALThread(); - void Init(); - void Quit(); - void Play(); - void Open(const void* src, ALsizei size); - void Close(); - void Stop(); - bool AddBlock(const ALuint buffer_id, ALsizei size, const void* src); - void AddData(const void* src, ALsizei size); + virtual void Init(); + virtual void Quit(); + virtual void Play(); + virtual void Open(const void* src, int size); + virtual void Close(); + virtual void Stop(); + virtual void AddData(const void* src, int size); }; - diff --git a/rpcs3/Emu/Audio/AudioDumper.cpp b/rpcs3/Emu/Audio/AudioDumper.cpp index 0e51fd4a42..1ccd7d24cc 100644 --- a/rpcs3/Emu/Audio/AudioDumper.cpp +++ b/rpcs3/Emu/Audio/AudioDumper.cpp @@ -1,22 +1,32 @@ #include "stdafx.h" #include "AudioDumper.h" -AudioDumper::AudioDumper(u8 ch) : m_header(ch) +AudioDumper::AudioDumper() : m_header(0), m_init(false) { } AudioDumper::~AudioDumper() { + Finalize(); } -bool AudioDumper::Init() +bool AudioDumper::Init(u8 ch) { - return m_output.Open("audio.wav", rFile::write); + if ((m_init = m_output.Open("audio.wav", rFile::write))) + { + m_header = WAVHeader(ch); + WriteHeader(); + } + + return m_init; } void AudioDumper::WriteHeader() { - m_output.Write(&m_header, sizeof(m_header)); // write file header + if (m_init) + { + m_output.Write(&m_header, sizeof(m_header)); // write file header + } } size_t AudioDumper::WriteData(const void* buffer, size_t size) @@ -31,17 +41,27 @@ size_t AudioDumper::WriteData(const void* buffer, size_t size) { if (((u8*)buffer)[i + (size & ~7)]) do_save = true; } - if (!do_save) return size; // ignore empty data + + if (m_init && do_save) +#else + if (m_init) #endif - size_t ret = m_output.Write(buffer, size); - m_header.Size += (u32)ret; - m_header.RIFF.Size += (u32)ret; - return ret; + { + size_t ret = m_output.Write(buffer, size); + m_header.Size += (u32)ret; + m_header.RIFF.Size += (u32)ret; + return ret; + } + + return size; } void AudioDumper::Finalize() { - m_output.Seek(0); - m_output.Write(&m_header, sizeof(m_header)); // write fixed file header - m_output.Close(); + if (m_init) + { + m_output.Seek(0); + m_output.Write(&m_header, sizeof(m_header)); // write fixed file header + m_output.Close(); + } } \ No newline at end of file diff --git a/rpcs3/Emu/Audio/AudioDumper.h b/rpcs3/Emu/Audio/AudioDumper.h index ebf0f1db25..849adb851d 100644 --- a/rpcs3/Emu/Audio/AudioDumper.h +++ b/rpcs3/Emu/Audio/AudioDumper.h @@ -55,17 +55,18 @@ struct WAVHeader class AudioDumper { -private: WAVHeader m_header; rFile m_output; + bool m_init; public: - AudioDumper(u8 ch); + AudioDumper(); ~AudioDumper(); - bool Init(); +public: + bool Init(u8 ch); void WriteHeader(); size_t WriteData(const void* buffer, size_t size); void Finalize(); - const u8 GetCh() const { return (u8)m_header.FMT.NumChannels; } + const u16 GetCh() const { return m_header.FMT.NumChannels; } }; diff --git a/rpcs3/Emu/Audio/AudioManager.cpp b/rpcs3/Emu/Audio/AudioManager.cpp index 1207e61d6b..8e19fc7542 100644 --- a/rpcs3/Emu/Audio/AudioManager.cpp +++ b/rpcs3/Emu/Audio/AudioManager.cpp @@ -1,24 +1,28 @@ #include "stdafx.h" #include "rpcs3/Ini.h" #include "AudioManager.h" +#include "AL/OpenALThread.h" +#include "Null/NullAudioThread.h" +#include "XAudio2/XAudio2Thread.h" -OpenALThread* m_audio_out; - -AudioManager::AudioManager() +AudioManager::AudioManager() : m_audio_out(nullptr) { } void AudioManager::Init() { - if(m_audio_out) return; + if (m_audio_out) return; m_audio_info.Init(); - switch(Ini.AudioOutMode.GetValue()) + switch (Ini.AudioOutMode.GetValue()) { default: - case 0: m_audio_out = nullptr; break; + case 0: m_audio_out = new NullAudioThread(); break; case 1: m_audio_out = new OpenALThread(); break; +#if defined (_WIN32) + case 2: m_audio_out = new XAudio2Thread(); break; +#endif } } diff --git a/rpcs3/Emu/Audio/AudioManager.h b/rpcs3/Emu/Audio/AudioManager.h index dc448b7ced..56e18f99a8 100644 --- a/rpcs3/Emu/Audio/AudioManager.h +++ b/rpcs3/Emu/Audio/AudioManager.h @@ -1,17 +1,17 @@ #pragma once #include "sysutil_audio.h" -#include "AL/OpenALThread.h" +#include "AudioThread.h" struct AudioInfo { struct { - u8 type; + u8 type; u8 channel; - u8 encoder; + u8 encoder; u8 fs; - u32 layout; - u32 downMixer; + u32 layout; + u32 downMixer; } mode; AudioInfo() @@ -21,9 +21,9 @@ struct AudioInfo void Init() { mode.type = CELL_AUDIO_OUT_CODING_TYPE_LPCM; - mode.channel = CELL_AUDIO_OUT_CHNUM_2; + mode.channel = CELL_AUDIO_OUT_CHNUM_8; mode.fs = CELL_AUDIO_OUT_FS_48KHZ; - mode.layout = CELL_AUDIO_OUT_SPEAKER_LAYOUT_2CH; + mode.layout = CELL_AUDIO_OUT_SPEAKER_LAYOUT_8CH_LREClrxy; mode.encoder = CELL_AUDIO_OUT_CODING_TYPE_LPCM; mode.downMixer = CELL_AUDIO_OUT_DOWNMIXER_NONE; } @@ -32,16 +32,15 @@ struct AudioInfo class AudioManager { AudioInfo m_audio_info; + AudioThread* m_audio_out; public: AudioManager(); void Init(); void Close(); + AudioThread& GetAudioOut() { assert(m_audio_out); return *m_audio_out; } AudioInfo& GetInfo() { return m_audio_info; } u8 GetState(); -}; - -extern OpenALThread* m_audio_out; - +}; \ No newline at end of file diff --git a/rpcs3/Emu/Audio/AudioThread.h b/rpcs3/Emu/Audio/AudioThread.h new file mode 100644 index 0000000000..fa600ba9cb --- /dev/null +++ b/rpcs3/Emu/Audio/AudioThread.h @@ -0,0 +1,15 @@ +#pragma once + +class AudioThread +{ +public: + virtual ~AudioThread() {} + + virtual void Init() = 0; + virtual void Quit() = 0; + virtual void Play() = 0; + virtual void Open(const void* src, int size) = 0; + virtual void Close() = 0; + virtual void Stop() = 0; + virtual void AddData(const void* src, int size) = 0; +}; \ No newline at end of file diff --git a/rpcs3/Emu/Audio/Null/NullAudioThread.h b/rpcs3/Emu/Audio/Null/NullAudioThread.h new file mode 100644 index 0000000000..46de961af2 --- /dev/null +++ b/rpcs3/Emu/Audio/Null/NullAudioThread.h @@ -0,0 +1,18 @@ +#pragma once + +#include "Emu/Audio/AudioThread.h" + +class NullAudioThread : public AudioThread +{ +public: + NullAudioThread() {} + virtual ~NullAudioThread() {} + + virtual void Init() {} + virtual void Quit() {} + virtual void Play() {} + virtual void Open(const void* src, int size) {} + virtual void Close() {} + virtual void Stop() {} + virtual void AddData(const void* src, int size) {} +}; diff --git a/rpcs3/Emu/Audio/XAudio2/XAudio2Thread.cpp b/rpcs3/Emu/Audio/XAudio2/XAudio2Thread.cpp new file mode 100644 index 0000000000..e8155b89a3 --- /dev/null +++ b/rpcs3/Emu/Audio/XAudio2/XAudio2Thread.cpp @@ -0,0 +1,141 @@ +#include "stdafx.h" +#include "Utilities/Log.h" +#include "Emu/System.h" +#include "rpcs3/Ini.h" + +#if defined (_WIN32) +#include "XAudio2Thread.h" + +XAudio2Thread::~XAudio2Thread() +{ + if (m_source_voice) Quit(); +} + +void XAudio2Thread::Init() +{ + HRESULT hr = S_OK; + +#if (_WIN32_WINNT < 0x0602) + hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + if (FAILED(hr)) + { + LOG_ERROR(GENERAL, "XAudio2Thread : CoInitializeEx() failed(0x%08x)", (u32)hr); + Emu.Pause(); + return; + } +#endif + + hr = XAudio2Create(&m_xaudio2_instance, 0, XAUDIO2_DEFAULT_PROCESSOR); + if (FAILED(hr)) + { + LOG_ERROR(GENERAL, "XAudio2Thread : XAudio2Create() failed(0x%08x)", (u32)hr); + Emu.Pause(); + return; + } + + hr = m_xaudio2_instance->CreateMasteringVoice(&m_master_voice); + if (FAILED(hr)) + { + LOG_ERROR(GENERAL, "XAudio2Thread : CreateMasteringVoice() failed(0x%08x)", (u32)hr); + m_xaudio2_instance->Release(); + Emu.Pause(); + } +} + +void XAudio2Thread::Quit() +{ + Stop(); + m_source_voice->DestroyVoice(); + m_source_voice = nullptr; + m_master_voice->DestroyVoice(); + m_master_voice = nullptr; + m_xaudio2_instance->StopEngine(); + m_xaudio2_instance->Release(); + m_xaudio2_instance = nullptr; + +#if (_WIN32_WINNT < 0x0602) + CoUninitialize(); +#endif +} + +void XAudio2Thread::Play() +{ + HRESULT hr = m_source_voice->Start(); + if (FAILED(hr)) + { + LOG_ERROR(GENERAL, "XAudio2Thread : Start() failed(0x%08x)", (u32)hr); + Emu.Pause(); + } +} + +void XAudio2Thread::Close() +{ + Stop(); + HRESULT hr = m_source_voice->FlushSourceBuffers(); + if (FAILED(hr)) + { + LOG_ERROR(GENERAL, "XAudio2Thread : FlushSourceBuffers() failed(0x%08x)", (u32)hr); + Emu.Pause(); + } +} + +void XAudio2Thread::Stop() +{ + HRESULT hr = m_source_voice->Stop(); + if (FAILED(hr)) + { + LOG_ERROR(GENERAL, "XAudio2Thread : Stop() failed(0x%08x)", (u32)hr); + Emu.Pause(); + } +} + +void XAudio2Thread::Open(const void* src, int size) +{ + HRESULT hr; + + WORD sample_size = Ini.AudioConvertToU16.GetValue() ? sizeof(u16) : sizeof(float); + WORD channels = 8; + + WAVEFORMATEX waveformatex; + waveformatex.wFormatTag = Ini.AudioConvertToU16.GetValue() ? WAVE_FORMAT_PCM : WAVE_FORMAT_IEEE_FLOAT; + waveformatex.nChannels = channels; + waveformatex.nSamplesPerSec = 48000; + waveformatex.nAvgBytesPerSec = 48000 * (DWORD)channels * (DWORD)sample_size; + waveformatex.nBlockAlign = channels * sample_size; + waveformatex.wBitsPerSample = sample_size * 8; + waveformatex.cbSize = 0; + + hr = m_xaudio2_instance->CreateSourceVoice(&m_source_voice, &waveformatex, 0, XAUDIO2_DEFAULT_FREQ_RATIO); + if (FAILED(hr)) + { + LOG_ERROR(GENERAL, "XAudio2Thread : CreateSourceVoice() failed(0x%08x)", (u32)hr); + Emu.Pause(); + return; + } + + AddData(src, size); + Play(); +} + +void XAudio2Thread::AddData(const void* src, int size) +{ + XAUDIO2_BUFFER buffer; + + buffer.AudioBytes = size; + buffer.Flags = 0; + buffer.LoopBegin = XAUDIO2_NO_LOOP_REGION; + buffer.LoopCount = 0; + buffer.LoopLength = 0; + buffer.pAudioData = (const BYTE*)src; + buffer.pContext = 0; + buffer.PlayBegin = 0; + buffer.PlayLength = 256; + + HRESULT hr = m_source_voice->SubmitSourceBuffer(&buffer); + if (FAILED(hr)) + { + LOG_ERROR(GENERAL, "XAudio2Thread : AddData() failed(0x%08x)", (u32)hr); + Emu.Pause(); + } +} +#endif diff --git a/rpcs3/Emu/Audio/XAudio2/XAudio2Thread.h b/rpcs3/Emu/Audio/XAudio2/XAudio2Thread.h new file mode 100644 index 0000000000..3a362714ad --- /dev/null +++ b/rpcs3/Emu/Audio/XAudio2/XAudio2Thread.h @@ -0,0 +1,35 @@ +#pragma once + +#include "Emu/Audio/AudioThread.h" +#if defined (_WIN32) + +// forced define Win7, delete this for using XAudio2 2.8 +#define WINVER 0x0601 +#define _WIN32_WINNT 0x0601 + +#if (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/) +#include +#pragma comment(lib,"xaudio2.lib") +#else +#include "XAudio2.h" // XAudio2 2.8 available only on Win8+, used XAudio2 2.7 from dxsdk +#endif + +class XAudio2Thread : public AudioThread +{ +private: + IXAudio2* m_xaudio2_instance; + IXAudio2MasteringVoice* m_master_voice; + IXAudio2SourceVoice* m_source_voice; + +public: + virtual ~XAudio2Thread(); + + virtual void Init(); + virtual void Quit(); + virtual void Play(); + virtual void Open(const void* src, int size); + virtual void Close(); + virtual void Stop(); + virtual void AddData(const void* src, int size); +}; +#endif \ No newline at end of file diff --git a/rpcs3/Emu/CPU/CPUDisAsm.h b/rpcs3/Emu/CPU/CPUDisAsm.h index 9fe6ce1692..7c4d9badb0 100644 --- a/rpcs3/Emu/CPU/CPUDisAsm.h +++ b/rpcs3/Emu/CPU/CPUDisAsm.h @@ -18,19 +18,19 @@ protected: switch(m_mode) { case CPUDisAsm_DumpMode: - last_opcode = fmt::Format("\t%08x:\t%02x %02x %02x %02x\t%s\n", dump_pc, + last_opcode = fmt::format("\t%08x:\t%02x %02x %02x %02x\t%s\n", dump_pc, offset[dump_pc], offset[dump_pc + 1], offset[dump_pc + 2], - offset[dump_pc + 3], value.c_str()); + offset[dump_pc + 3], value); break; case CPUDisAsm_InterpreterMode: - last_opcode = fmt::Format("[%08x] %02x %02x %02x %02x: %s", dump_pc, + last_opcode = fmt::format("[%08x] %02x %02x %02x %02x: %s", dump_pc, offset[dump_pc], offset[dump_pc + 1], offset[dump_pc + 2], - offset[dump_pc + 3], value.c_str()); + offset[dump_pc + 3], value); break; case CPUDisAsm_CompilerElfMode: diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index b3986e970d..df64539f20 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -1,10 +1,11 @@ #include "stdafx.h" #include "rpcs3/Ini.h" -#include "Emu/SysCalls/SysCalls.h" #include "Utilities/Log.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/DbgCommand.h" +#include "Emu/SysCalls/SysCalls.h" +#include "Emu/ARMv7/PSVFuncList.h" #include "CPUDecoder.h" #include "CPUThread.h" @@ -254,29 +255,72 @@ void CPUThread::ExecOnce() SendDbgCommand(DID_PAUSED_THREAD, this); } -#ifdef _WIN32 -void _se_translator(unsigned int u, EXCEPTION_POINTERS* pExp) -{ - const u64 addr = (u64)pExp->ExceptionRecord->ExceptionInformation[1] - (u64)Memory.GetBaseAddr(); - CPUThread* t = GetCurrentCPUThread(); - if (u == EXCEPTION_ACCESS_VIOLATION && addr < 0x100000000 && t) - { - // TODO: allow recovering from a page fault - throw fmt::Format("Access violation: addr = 0x%x (is_alive=%d, last_syscall=0x%llx (%s))", - (u32)addr, t->IsAlive() ? 1 : 0, t->m_last_syscall, SysCalls::GetHLEFuncName((u32)t->m_last_syscall).c_str()); - } - else - { - // some fatal error (should crash) - return; - } -} -#else -// TODO: linux version -#endif - void CPUThread::Task() { + auto get_syscall_name = [this](u64 syscall) -> std::string + { + switch (GetType()) + { + case CPU_THREAD_ARMv7: + { + if ((u32)syscall == syscall) + { + if (syscall) + { + if (auto func = get_psv_func_by_nid((u32)syscall)) + { + return func->name; + } + } + else + { + return{}; + } + } + + return "unknown function"; + } + + case CPU_THREAD_PPU: + { + if ((u32)syscall == syscall) + { + if (syscall) + { + if (syscall < 1024) + { + // TODO: + //return SysCalls::GetSyscallName((u32)syscall); + return "unknown syscall"; + } + else + { + return SysCalls::GetHLEFuncName((u32)syscall); + } + } + else + { + return{}; + } + } + + return "unknown function"; + } + + case CPU_THREAD_SPU: + case CPU_THREAD_RAW_SPU: + default: + { + if (!syscall) + { + return{}; + } + + return "unknown function"; + } + } + }; + if (Ini.HLELogging.GetValue()) LOG_NOTICE(GENERAL, "%s enter", CPUThread::GetFName().c_str()); const std::vector& bp = Emu.GetBreakPoints(); @@ -292,12 +336,6 @@ void CPUThread::Task() std::vector trace; -#ifdef _WIN32 - auto old_se_translator = _set_se_translator(_se_translator); -#else - // TODO: linux version -#endif - try { while (true) @@ -337,21 +375,17 @@ void CPUThread::Task() } catch (const std::string& e) { - LOG_ERROR(GENERAL, "Exception: %s", e.c_str()); + LOG_ERROR(GENERAL, "Exception: %s (is_alive=%d, m_last_syscall=0x%llx (%s))", e, IsAlive(), m_last_syscall, get_syscall_name(m_last_syscall)); + LOG_NOTICE(GENERAL, RegsToString()); Emu.Pause(); } catch (const char* e) { - LOG_ERROR(GENERAL, "Exception: %s", e); + LOG_ERROR(GENERAL, "Exception: %s (is_alive=%d, m_last_syscall=0x%llx (%s))", e, IsAlive(), m_last_syscall, get_syscall_name(m_last_syscall)); + LOG_NOTICE(GENERAL, RegsToString()); Emu.Pause(); } -#ifdef _WIN32 - _set_se_translator(old_se_translator); -#else - // TODO: linux version -#endif - if (trace.size()) { LOG_NOTICE(GENERAL, "Trace begin (%d elements)", trace.size()); diff --git a/rpcs3/Emu/CPU/CPUThread.h b/rpcs3/Emu/CPU/CPUThread.h index 6b1471705b..7261d0f28d 100644 --- a/rpcs3/Emu/CPU/CPUThread.h +++ b/rpcs3/Emu/CPU/CPUThread.h @@ -70,12 +70,7 @@ public: std::string GetName() const { return NamedThreadBase::GetThreadName(); } std::string GetFName() const { - return - fmt::Format("%s[%d] Thread%s", - GetTypeString().c_str(), - m_id, - (GetName().empty() ? std::string("") : fmt::Format(" (%s)", GetName().c_str())).c_str() - ); + return fmt::format("%s[%d] Thread (%s)", GetTypeString(), m_id, GetName()); } static std::string CPUThreadTypeToString(CPUThreadType type) @@ -111,8 +106,7 @@ public: virtual std::string GetThreadName() const { - std::string temp = (GetFName() + fmt::Format("[0x%08x]", PC)); - return temp; + return fmt::format("%s[0x%08x]", GetFName(), PC); } CPUDecoder * GetDecoder() { return m_dec; }; diff --git a/rpcs3/Emu/CPU/CPUThreadManager.cpp b/rpcs3/Emu/CPU/CPUThreadManager.cpp index 493d1896cc..fa682b4e82 100644 --- a/rpcs3/Emu/CPU/CPUThreadManager.cpp +++ b/rpcs3/Emu/CPU/CPUThreadManager.cpp @@ -55,7 +55,7 @@ CPUThread& CPUThreadManager::AddThread(CPUThreadType type) default: assert(0); } - new_thread->SetId(Emu.GetIdManager().GetNewID(fmt::Format("%s Thread", new_thread->GetTypeString().c_str()), new_thread)); + new_thread->SetId(Emu.GetIdManager().GetNewID(new_thread->GetTypeString() + " Thread", new_thread)); m_threads.push_back(new_thread); SendDbgCommand(DID_CREATE_THREAD, new_thread.get()); diff --git a/rpcs3/Emu/Cell/Common.h b/rpcs3/Emu/Cell/Common.h new file mode 100644 index 0000000000..214af66bce --- /dev/null +++ b/rpcs3/Emu/Cell/Common.h @@ -0,0 +1,10 @@ +#pragma once + +// Floating-point rounding mode (for both PPU and SPU) +enum FPSCR_RN +{ + FPSCR_RN_NEAR = 0, + FPSCR_RN_ZERO = 1, + FPSCR_RN_PINF = 2, + FPSCR_RN_MINF = 3, +}; diff --git a/rpcs3/Emu/Cell/PPCThread.h b/rpcs3/Emu/Cell/PPCThread.h index c7e5dab93c..99471f7a80 100644 --- a/rpcs3/Emu/Cell/PPCThread.h +++ b/rpcs3/Emu/Cell/PPCThread.h @@ -9,7 +9,7 @@ public: virtual std::string GetThreadName() const { - return (GetFName() + fmt::Format("[0x%08x]", PC)); + return fmt::format("%s[0x%08x]", GetFName(), PC); } protected: diff --git a/rpcs3/Emu/Cell/PPUDisAsm.h b/rpcs3/Emu/Cell/PPUDisAsm.h index 531b21bc37..228c9edd4e 100644 --- a/rpcs3/Emu/Cell/PPUDisAsm.h +++ b/rpcs3/Emu/Cell/PPUDisAsm.h @@ -1675,6 +1675,10 @@ private: { DisAsm_V1_R2("stvlx", vs, ra, rb); } + void STDBRX(u32 rs, u32 ra, u32 rb) + { + DisAsm_R3("stdbrx", rs, ra, rb); + } void STSWX(u32 rs, u32 ra, u32 rb) { DisAsm_R3("swswx", rs, ra, rb); diff --git a/rpcs3/Emu/Cell/PPUInstrTable.h b/rpcs3/Emu/Cell/PPUInstrTable.h index c9f03c789d..a22627f2ae 100644 --- a/rpcs3/Emu/Cell/PPUInstrTable.h +++ b/rpcs3/Emu/Cell/PPUInstrTable.h @@ -226,6 +226,9 @@ namespace PPU_instr #define bind_instr(list, name, ...) \ static const auto& name = make_instr(list, #name, &PPUOpcodes::name, ##__VA_ARGS__) +#define bind_instr_oe(list, name, ...) \ + bind_instr(list, name, ##__VA_ARGS__); \ + static const auto& name##O = make_instr(list, #name "O", &PPUOpcodes::name, ##__VA_ARGS__) bind_instr(main_list, TDI, TO, RA, simm16); bind_instr(main_list, TWI, TO, RA, simm16); @@ -456,9 +459,9 @@ namespace PPU_instr /*0x004*/bind_instr(g1f_list, TW, TO, RA, RB); /*0x006*/bind_instr(g1f_list, LVSL, VD, RA, RB); /*0x007*/bind_instr(g1f_list, LVEBX, VD, RA, RB); - /*0x008*/bind_instr(g1f_list, SUBFC, RD, RA, RB, OE, RC); + /*0x008*/bind_instr_oe(g1f_list, SUBFC, RD, RA, RB, OE, RC); /*0x009*/bind_instr(g1f_list, MULHDU, RD, RA, RB, RC); - /*0x00a*/bind_instr(g1f_list, ADDC, RD, RA, RB, OE, RC); + /*0x00a*/bind_instr_oe(g1f_list, ADDC, RD, RA, RB, OE, RC); /*0x00b*/bind_instr(g1f_list, MULHWU, RD, RA, RB, RC); /*0x013*/bind_instr(g1f_list, MFOCRF, L_11, RD, CRM); /*0x014*/bind_instr(g1f_list, LWARX, RD, RA, RB); @@ -471,7 +474,7 @@ namespace PPU_instr /*0x020*/bind_instr(g1f_list, CMPL, CRFD, L_10, RA, RB); /*0x026*/bind_instr(g1f_list, LVSR, VD, RA, RB); /*0x027*/bind_instr(g1f_list, LVEHX, VD, RA, RB); - /*0x028*/bind_instr(g1f_list, SUBF, RD, RA, RB, OE, RC); + /*0x028*/bind_instr_oe(g1f_list, SUBF, RD, RA, RB, OE, RC); /*0x035*/bind_instr(g1f_list, LDUX, RD, RA, RB); /*0x036*/bind_instr(g1f_list, DCBST, RA, RB); /*0x037*/bind_instr(g1f_list, LWZUX, RD, RA, RB); @@ -485,12 +488,12 @@ namespace PPU_instr /*0x056*/bind_instr(g1f_list, DCBF, RA, RB); /*0x057*/bind_instr(g1f_list, LBZX, RD, RA, RB); /*0x067*/bind_instr(g1f_list, LVX, VD, RA, RB); - /*0x068*/bind_instr(g1f_list, NEG, RD, RA, OE, RC); + /*0x068*/bind_instr_oe(g1f_list, NEG, RD, RA, OE, RC); /*0x077*/bind_instr(g1f_list, LBZUX, RD, RA, RB); /*0x07c*/bind_instr(g1f_list, NOR, RA, RS, RB, RC); /*0x087*/bind_instr(g1f_list, STVEBX, VS, RA, RB); - /*0x088*/bind_instr(g1f_list, SUBFE, RD, RA, RB, OE, RC); - /*0x08a*/bind_instr(g1f_list, ADDE, RD, RA, RB, OE, RC); + /*0x088*/bind_instr_oe(g1f_list, SUBFE, RD, RA, RB, OE, RC); + /*0x08a*/bind_instr_oe(g1f_list, ADDE, RD, RA, RB, OE, RC); /*0x090*/bind_instr(g1f_list, MTOCRF, L_11, CRM, RS); /*0x095*/bind_instr(g1f_list, STDX, RS, RA, RB); /*0x096*/bind_instr(g1f_list, STWCX_, RS, RA, RB); @@ -499,18 +502,18 @@ namespace PPU_instr /*0x0b5*/bind_instr(g1f_list, STDUX, RS, RA, RB); /*0x0b7*/bind_instr(g1f_list, STWUX, RS, RA, RB); /*0x0c7*/bind_instr(g1f_list, STVEWX, VS, RA, RB); - /*0x0c8*/bind_instr(g1f_list, SUBFZE, RD, RA, OE, RC); - /*0x0ca*/bind_instr(g1f_list, ADDZE, RD, RA, OE, RC); + /*0x0c8*/bind_instr_oe(g1f_list, SUBFZE, RD, RA, OE, RC); + /*0x0ca*/bind_instr_oe(g1f_list, ADDZE, RD, RA, OE, RC); /*0x0d6*/bind_instr(g1f_list, STDCX_, RS, RA, RB); /*0x0d7*/bind_instr(g1f_list, STBX, RS, RA, RB); /*0x0e7*/bind_instr(g1f_list, STVX, VS, RA, RB); - /*0x0e8*/bind_instr(g1f_list, SUBFME, RD, RA, OE, RC); - /*0x0e9*/bind_instr(g1f_list, MULLD, RD, RA, RB, OE, RC); - /*0x0ea*/bind_instr(g1f_list, ADDME, RD, RA, OE, RC); - /*0x0eb*/bind_instr(g1f_list, MULLW, RD, RA, RB, OE, RC); + /*0x0e8*/bind_instr_oe(g1f_list, SUBFME, RD, RA, OE, RC); + /*0x0e9*/bind_instr_oe(g1f_list, MULLD, RD, RA, RB, OE, RC); + /*0x0ea*/bind_instr_oe(g1f_list, ADDME, RD, RA, OE, RC); + /*0x0eb*/bind_instr_oe(g1f_list, MULLW, RD, RA, RB, OE, RC); /*0x0f6*/bind_instr(g1f_list, DCBTST, RA, RB, TH); /*0x0f7*/bind_instr(g1f_list, STBUX, RS, RA, RB); - /*0x10a*/bind_instr(g1f_list, ADD, RD, RA, RB, OE, RC); + /*0x10a*/bind_instr_oe(g1f_list, ADD, RD, RA, RB, OE, RC); /*0x116*/bind_instr(g1f_list, DCBT, RA, RB, TH); /*0x117*/bind_instr(g1f_list, LHZX, RD, RA, RB); /*0x11c*/bind_instr(g1f_list, EQV, RA, RS, RB, RC); @@ -531,15 +534,21 @@ namespace PPU_instr /*0x1b6*/bind_instr(g1f_list, ECOWX, RS, RA, RB); /*0x1b7*/bind_instr(g1f_list, STHUX, RS, RA, RB); /*0x1bc*/bind_instr(g1f_list, OR, RA, RS, RB, RC); - /*0x1c9*/bind_instr(g1f_list, DIVDU, RD, RA, RB, OE, RC); - /*0x1cb*/bind_instr(g1f_list, DIVWU, RD, RA, RB, OE, RC); + /*0x1c9*/bind_instr_oe(g1f_list, DIVDU, RD, RA, RB, OE, RC); + /*0x1cb*/bind_instr_oe(g1f_list, DIVWU, RD, RA, RB, OE, RC); /*0x1d3*/bind_instr(g1f_list, MTSPR, SPR, RS); /*0x1d6*///DCBI /*0x1dc*/bind_instr(g1f_list, NAND, RA, RS, RB, RC); /*0x1e7*/bind_instr(g1f_list, STVXL, VS, RA, RB); - /*0x1e9*/bind_instr(g1f_list, DIVD, RD, RA, RB, OE, RC); - /*0x1eb*/bind_instr(g1f_list, DIVW, RD, RA, RB, OE, RC); + /*0x1e9*/bind_instr_oe(g1f_list, DIVD, RD, RA, RB, OE, RC); + /*0x1eb*/bind_instr_oe(g1f_list, DIVW, RD, RA, RB, OE, RC); /*0x207*/bind_instr(g1f_list, LVLX, VD, RA, RB); + // MULH{D|DU|W|WU} don't use OE, but a real Cell accepts + // opcodes with OE=1 and Rc=0, behaving as if OE was not set. + // OE=1 and Rc=1 causes an invalid instruction exception, but + // we don't worry about that. + static const auto& MULHDUO = make_instr<0x209>(g1f_list, "MULHDUO", &PPUOpcodes::MULHDU, RD, RA, RB, RC); + static const auto& MULHWUO = make_instr<0x20b>(g1f_list, "MULHWUO", &PPUOpcodes::MULHWU, RD, RA, RB, RC); /*0x214*/bind_instr(g1f_list, LDBRX, RD, RA, RB); /*0x215*/bind_instr(g1f_list, LSWX, RD, RA, RB); /*0x216*/bind_instr(g1f_list, LWBRX, RD, RA, RB); @@ -548,11 +557,14 @@ namespace PPU_instr /*0x21b*/bind_instr(g1f_list, SRD, RA, RS, RB, RC); /*0x227*/bind_instr(g1f_list, LVRX, VD, RA, RB); /*0x237*/bind_instr(g1f_list, LFSUX, FRD, RA, RB); + static const auto& MULHDO = make_instr<0x249>(g1f_list, "MULHDO", &PPUOpcodes::MULHD, RD, RA, RB, RC); + static const auto& MULHWO = make_instr<0x24b>(g1f_list, "MULHWO", &PPUOpcodes::MULHW, RD, RA, RB, RC); /*0x255*/bind_instr(g1f_list, LSWI, RD, RA, NB); /*0x256*/bind_instr(g1f_list, SYNC, L_9_10); /*0x257*/bind_instr(g1f_list, LFDX, FRD, RA, RB); /*0x277*/bind_instr(g1f_list, LFDUX, FRD, RA, RB); /*0x287*/bind_instr(g1f_list, STVLX, VS, RA, RB); + /*0x294*/bind_instr(g1f_list, STDBRX, RD, RA, RB); /*0x296*/bind_instr(g1f_list, STSWX, RS, RA, RB); /*0x296*/bind_instr(g1f_list, STWBRX, RS, RA, RB); /*0x297*/bind_instr(g1f_list, STFSX, FRS, RA, RB); @@ -657,4 +669,4 @@ namespace PPU_instr using namespace lists; using namespace implicts; #undef bind_instr -}; \ No newline at end of file +}; diff --git a/rpcs3/Emu/Cell/PPUInterpreter.h b/rpcs3/Emu/Cell/PPUInterpreter.h index 6349e52fd9..201385e827 100644 --- a/rpcs3/Emu/Cell/PPUInterpreter.h +++ b/rpcs3/Emu/Cell/PPUInterpreter.h @@ -17,13 +17,13 @@ #define _rotl64(x,r) (((u64)(x) << (r)) | ((u64)(x) >> (64 - (r)))) #endif -#define UNIMPLEMENTED() UNK(__FUNCTION__) +#include #if 0//def _DEBUG #define HLE_CALL_DEBUG #endif -static u64 rotate_mask[64][64]; +extern u64 rotate_mask[64][64]; // defined in PPUThread.cpp, static didn't work correctly in GCC 4.9 for some reason inline void InitRotateMask() { static bool inited = false; @@ -55,6 +55,33 @@ u64 rotr64(const u64 x, const u8 n) { return (x >> n) | (x << (64 - n)); } #define rotl64 _rotl64 #define rotr64 _rotr64 +static double SilenceNaN(double x) +{ + u64 bits = (u64&)x; + bits |= 0x0008000000000000ULL; + return (double&)bits; +} + +static void SetHostRoundingMode(u32 rn) +{ + switch (rn) + { + case FPSCR_RN_NEAR: + fesetround(FE_TONEAREST); + break; + case FPSCR_RN_ZERO: + fesetround(FE_TOWARDZERO); + break; + case FPSCR_RN_PINF: + fesetround(FE_UPWARD); + break; + case FPSCR_RN_MINF: + fesetround(FE_DOWNWARD); + break; + } +} + + namespace ppu_recompiler_llvm { class Compiler; } @@ -74,6 +101,13 @@ public: } private: + void CheckHostFPExceptions() + { + CPU.SetFPSCR_FI(fetestexcept(FE_INEXACT) != 0); + if (fetestexcept(FE_UNDERFLOW)) CPU.SetFPSCRException(FPSCR_UX); + if (fetestexcept(FE_OVERFLOW)) CPU.SetFPSCRException(FPSCR_OX); + } + void Exit() {} void SysCall() @@ -98,7 +132,7 @@ private: void NULL_OP() { - UNK("null"); + throw "Null operation"; } void NOP() @@ -146,17 +180,11 @@ private: case 0x001: return CPU.XER.XER; case 0x008: return CPU.LR; case 0x009: return CPU.CTR; - case 0x100: - case 0x101: - case 0x102: - case 0x103: - case 0x104: - case 0x105: - case 0x106: - case 0x107: return CPU.USPRG[n - 0x100]; + case 0x100: return CPU.VRSAVE; + case 0x103: return CPU.SPRG[3]; case 0x10C: CPU.TB = get_time(); return CPU.TB; - case 0x10D: CPU.TB = get_time(); return CPU.TBH; + case 0x10D: CPU.TB = get_time(); return CPU.TB >> 32; case 0x110: case 0x111: @@ -168,8 +196,7 @@ private: case 0x117: return CPU.SPRG[n - 0x110]; } - UNK(fmt::Format("ReadSPR error: Unknown SPR 0x%x!", n)); - return CPU.XER.XER; + throw fmt::Format("ReadSPR(0x%x) error: unknown SPR (0x%x)", spr, n); } void WriteSPR(u32 spr, u64 value) @@ -181,17 +208,11 @@ private: case 0x001: CPU.XER.XER = value; return; case 0x008: CPU.LR = value; return; case 0x009: CPU.CTR = value; return; - case 0x100: - case 0x101: - case 0x102: - case 0x103: - case 0x104: - case 0x105: - case 0x106: - case 0x107: CPU.USPRG[n - 0x100] = value; return; + case 0x100: CPU.VRSAVE = (u32)value; return; + case 0x103: throw fmt::Format("WriteSPR(0x103, 0x%llx): Write to read-only SPR", value); - case 0x10C: UNK("WriteSPR: Write to time-based SPR. Report this to a developer!"); return; - case 0x10D: UNK("WriteSPR: Write to time-based SPR upper. Report this to a developer!"); return; + case 0x10C: throw fmt::Format("WriteSPR(0x10C, 0x%llx): Write to time-based SPR", value); + case 0x10D: throw fmt::Format("WriteSPR(0x10D, 0x%llx): Write to time-based SPR", value); case 0x110: case 0x111: @@ -203,8 +224,7 @@ private: case 0x117: CPU.SPRG[n - 0x110] = value; return; } - UNK(fmt::Format("WriteSPR error: Unknown SPR 0x%x!", n)); - return; + throw fmt::Format("WriteSPR(0x%x, 0x%llx) error: unknown SPR (0x%x)", spr, value, n); } void TDI(u32 to, u32 ra, s32 simm16) @@ -217,7 +237,7 @@ private: ((u64)a < (u64)simm16 && (to & 0x2)) || ((u64)a > (u64)simm16 && (to & 0x1)) ) { - UNK(fmt::Format("Trap! (tdi 0x%x, r%d, 0x%x)", to, ra, simm16)); + throw fmt::Format("Trap! (tdi 0x%x, r%d, 0x%x)", to, ra, simm16); } } @@ -231,7 +251,7 @@ private: ((u32)a < (u32)simm16 && (to & 0x2)) || ((u32)a > (u32)simm16 && (to & 0x1)) ) { - UNK(fmt::Format("Trap! (twi 0x%x, r%d, 0x%x)", to, ra, simm16)); + throw fmt::Format("Trap! (twi 0x%x, r%d, 0x%x)", to, ra, simm16); } } @@ -254,9 +274,19 @@ private: } void VADDFP(u32 vd, u32 va, u32 vb) { + SetHostRoundingMode(FPSCR_RN_NEAR); for (uint w = 0; w < 4; w++) { - CPU.VPR[vd]._f[w] = CPU.VPR[va]._f[w] + CPU.VPR[vb]._f[w]; + const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]); + const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); + if (std::isnan(a)) + CPU.VPR[vd]._f[w] = SilenceNaN(a); + else if (std::isnan(b)) + CPU.VPR[vd]._f[w] = SilenceNaN(b); + else if (std::isinf(a) && std::isinf(b) && a != b) + CPU.VPR[vd]._f[w] = (float)FPR_NAN; + else + CPU.VPR[vd]._f[w] = CheckVSCR_NJ(a + b); } } void VADDSBS(u32 vd, u32 va, u32 vb) //nf @@ -441,6 +471,7 @@ private: } void VCFSX(u32 vd, u32 uimm5, u32 vb) { + SetHostRoundingMode(FPSCR_RN_NEAR); u32 scale = 1 << uimm5; for (uint w = 0; w < 4; w++) @@ -450,6 +481,7 @@ private: } void VCFUX(u32 vd, u32 uimm5, u32 vb) { + SetHostRoundingMode(FPSCR_RN_NEAR); u32 scale = 1 << uimm5; for (uint w = 0; w < 4; w++) @@ -457,34 +489,19 @@ private: CPU.VPR[vd]._f[w] = ((float)CPU.VPR[vb]._u32[w]) / scale; } } - void VCMPBFP(u32 vd, u32 va, u32 vb) - { - for (uint w = 0; w < 4; w++) - { - u32 mask = 0; - - const float A = CheckVSCR_NJ(CPU.VPR[va]._f[w]); - const float B = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - - if (A > B) mask |= 1 << 31; - if (A < -B) mask |= 1 << 30; - - CPU.VPR[vd]._u32[w] = mask; - } - } - void VCMPBFP_(u32 vd, u32 va, u32 vb) + void VCMPBFP(u32 vd, u32 va, u32 vb, bool rc) { bool allInBounds = true; for (uint w = 0; w < 4; w++) { - u32 mask = 0; + u32 mask = 1<<31 | 1<<30; - const float A = CheckVSCR_NJ(CPU.VPR[va]._f[w]); - const float B = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); + const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]); + const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); - if (A > B) mask |= 1 << 31; - if (A < -B) mask |= 1 << 30; + if (a <= b) mask &= ~(1 << 31); + if (a >= -b) mask &= ~(1 << 30); CPU.VPR[vd]._u32[w] = mask; @@ -492,18 +509,16 @@ private: allInBounds = false; } - // Bit n°2 of CR6 - CPU.SetCR(6, 0); - CPU.SetCRBit(6, 0x2, allInBounds); - } - void VCMPEQFP(u32 vd, u32 va, u32 vb) - { - for (uint w = 0; w < 4; w++) + if (rc) { - CPU.VPR[vd]._u32[w] = CPU.VPR[va]._f[w] == CPU.VPR[vb]._f[w] ? 0xffffffff : 0; + // Bit n°2 of CR6 + CPU.SetCR(6, 0); + CPU.SetCRBit(6, 0x2, allInBounds); } } - void VCMPEQFP_(u32 vd, u32 va, u32 vb) + void VCMPBFP(u32 vd, u32 va, u32 vb) {VCMPBFP(vd, va, vb, false);} + void VCMPBFP_(u32 vd, u32 va, u32 vb) {VCMPBFP(vd, va, vb, true);} + void VCMPEQFP(u32 vd, u32 va, u32 vb, bool rc) { int all_equal = 0x8; int none_equal = 0x2; @@ -522,16 +537,11 @@ private: } } - CPU.CR.cr6 = all_equal | none_equal; + if (rc) CPU.CR.cr6 = all_equal | none_equal; } - void VCMPEQUB(u32 vd, u32 va, u32 vb) - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._u8[b] = CPU.VPR[va]._u8[b] == CPU.VPR[vb]._u8[b] ? 0xff : 0; - } - } - void VCMPEQUB_(u32 vd, u32 va, u32 vb) + void VCMPEQFP(u32 vd, u32 va, u32 vb) {VCMPEQFP(vd, va, vb, false);} + void VCMPEQFP_(u32 vd, u32 va, u32 vb) {VCMPEQFP(vd, va, vb, true);} + void VCMPEQUB(u32 vd, u32 va, u32 vb, bool rc) { int all_equal = 0x8; int none_equal = 0x2; @@ -550,16 +560,11 @@ private: } } - CPU.CR.cr6 = all_equal | none_equal; + if (rc) CPU.CR.cr6 = all_equal | none_equal; } - void VCMPEQUH(u32 vd, u32 va, u32 vb) //nf - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = CPU.VPR[va]._u16[h] == CPU.VPR[vb]._u16[h] ? 0xffff : 0; - } - } - void VCMPEQUH_(u32 vd, u32 va, u32 vb) //nf + void VCMPEQUB(u32 vd, u32 va, u32 vb) {VCMPEQUB(vd, va, vb, false);} + void VCMPEQUB_(u32 vd, u32 va, u32 vb) {VCMPEQUB(vd, va, vb, true);} + void VCMPEQUH(u32 vd, u32 va, u32 vb, bool rc) //nf { int all_equal = 0x8; int none_equal = 0x2; @@ -578,16 +583,11 @@ private: } } - CPU.CR.cr6 = all_equal | none_equal; + if (rc) CPU.CR.cr6 = all_equal | none_equal; } - void VCMPEQUW(u32 vd, u32 va, u32 vb) - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] == CPU.VPR[vb]._u32[w] ? 0xffffffff : 0; - } - } - void VCMPEQUW_(u32 vd, u32 va, u32 vb) + void VCMPEQUH(u32 vd, u32 va, u32 vb) {VCMPEQUH(vd, va, vb, false);} + void VCMPEQUH_(u32 vd, u32 va, u32 vb) {VCMPEQUH(vd, va, vb, true);} + void VCMPEQUW(u32 vd, u32 va, u32 vb, bool rc) { int all_equal = 0x8; int none_equal = 0x2; @@ -606,16 +606,11 @@ private: } } - CPU.CR.cr6 = all_equal | none_equal; + if (rc) CPU.CR.cr6 = all_equal | none_equal; } - void VCMPGEFP(u32 vd, u32 va, u32 vb) - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = CPU.VPR[va]._f[w] >= CPU.VPR[vb]._f[w] ? 0xffffffff : 0; - } - } - void VCMPGEFP_(u32 vd, u32 va, u32 vb) + void VCMPEQUW(u32 vd, u32 va, u32 vb) {VCMPEQUW(vd, va, vb, false);} + void VCMPEQUW_(u32 vd, u32 va, u32 vb) {VCMPEQUW(vd, va, vb, true);} + void VCMPGEFP(u32 vd, u32 va, u32 vb, bool rc) { int all_ge = 0x8; int none_ge = 0x2; @@ -634,16 +629,11 @@ private: } } - CPU.CR.cr6 = all_ge | none_ge; + if (rc) CPU.CR.cr6 = all_ge | none_ge; } - void VCMPGTFP(u32 vd, u32 va, u32 vb) - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = CPU.VPR[va]._f[w] > CPU.VPR[vb]._f[w] ? 0xffffffff : 0; - } - } - void VCMPGTFP_(u32 vd, u32 va, u32 vb) + void VCMPGEFP(u32 vd, u32 va, u32 vb) {VCMPGEFP(vd, va, vb, false);} + void VCMPGEFP_(u32 vd, u32 va, u32 vb) {VCMPGEFP(vd, va, vb, true);} + void VCMPGTFP(u32 vd, u32 va, u32 vb, bool rc) { int all_ge = 0x8; int none_ge = 0x2; @@ -662,16 +652,11 @@ private: } } - CPU.CR.cr6 = all_ge | none_ge; + if (rc) CPU.CR.cr6 = all_ge | none_ge; } - void VCMPGTSB(u32 vd, u32 va, u32 vb) //nf - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._u8[b] = CPU.VPR[va]._s8[b] > CPU.VPR[vb]._s8[b] ? 0xff : 0; - } - } - void VCMPGTSB_(u32 vd, u32 va, u32 vb) + void VCMPGTFP(u32 vd, u32 va, u32 vb) {VCMPGTFP(vd, va, vb, false);} + void VCMPGTFP_(u32 vd, u32 va, u32 vb) {VCMPGTFP(vd, va, vb, true);} + void VCMPGTSB(u32 vd, u32 va, u32 vb, bool rc) //nf { int all_gt = 0x8; int none_gt = 0x2; @@ -690,16 +675,11 @@ private: } } - CPU.CR.cr6 = all_gt | none_gt; + if (rc) CPU.CR.cr6 = all_gt | none_gt; } - void VCMPGTSH(u32 vd, u32 va, u32 vb) - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = CPU.VPR[va]._s16[h] > CPU.VPR[vb]._s16[h] ? 0xffff : 0; - } - } - void VCMPGTSH_(u32 vd, u32 va, u32 vb) + void VCMPGTSB(u32 vd, u32 va, u32 vb) {VCMPGTSB(vd, va, vb, false);} + void VCMPGTSB_(u32 vd, u32 va, u32 vb) {VCMPGTSB(vd, va, vb, true);} + void VCMPGTSH(u32 vd, u32 va, u32 vb, bool rc) { int all_gt = 0x8; int none_gt = 0x2; @@ -718,16 +698,11 @@ private: } } - CPU.CR.cr6 = all_gt | none_gt; + if (rc) CPU.CR.cr6 = all_gt | none_gt; } - void VCMPGTSW(u32 vd, u32 va, u32 vb) - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = CPU.VPR[va]._s32[w] > CPU.VPR[vb]._s32[w] ? 0xffffffff : 0; - } - } - void VCMPGTSW_(u32 vd, u32 va, u32 vb) + void VCMPGTSH(u32 vd, u32 va, u32 vb) {VCMPGTSH(vd, va, vb, false);} + void VCMPGTSH_(u32 vd, u32 va, u32 vb) {VCMPGTSH(vd, va, vb, true);} + void VCMPGTSW(u32 vd, u32 va, u32 vb, bool rc) { int all_gt = 0x8; int none_gt = 0x2; @@ -746,16 +721,11 @@ private: } } - CPU.CR.cr6 = all_gt | none_gt; + if (rc) CPU.CR.cr6 = all_gt | none_gt; } - void VCMPGTUB(u32 vd, u32 va, u32 vb) - { - for (uint b = 0; b < 16; b++) - { - CPU.VPR[vd]._u8[b] = CPU.VPR[va]._u8[b] > CPU.VPR[vb]._u8[b] ? 0xff : 0; - } - } - void VCMPGTUB_(u32 vd, u32 va, u32 vb) + void VCMPGTSW(u32 vd, u32 va, u32 vb) {VCMPGTSW(vd, va, vb, false);} + void VCMPGTSW_(u32 vd, u32 va, u32 vb) {VCMPGTSW(vd, va, vb, true);} + void VCMPGTUB(u32 vd, u32 va, u32 vb, bool rc) { int all_gt = 0x8; int none_gt = 0x2; @@ -774,16 +744,11 @@ private: } } - CPU.CR.cr6 = all_gt | none_gt; + if (rc) CPU.CR.cr6 = all_gt | none_gt; } - void VCMPGTUH(u32 vd, u32 va, u32 vb) - { - for (uint h = 0; h < 8; h++) - { - CPU.VPR[vd]._u16[h] = CPU.VPR[va]._u16[h] > CPU.VPR[vb]._u16[h] ? 0xffff : 0; - } - } - void VCMPGTUH_(u32 vd, u32 va, u32 vb) + void VCMPGTUB(u32 vd, u32 va, u32 vb) {VCMPGTUB(vd, va, vb, false);} + void VCMPGTUB_(u32 vd, u32 va, u32 vb) {VCMPGTUB(vd, va, vb, true);} + void VCMPGTUH(u32 vd, u32 va, u32 vb, bool rc) { int all_gt = 0x8; int none_gt = 0x2; @@ -802,16 +767,11 @@ private: } } - CPU.CR.cr6 = all_gt | none_gt; + if (rc) CPU.CR.cr6 = all_gt | none_gt; } - void VCMPGTUW(u32 vd, u32 va, u32 vb) - { - for (uint w = 0; w < 4; w++) - { - CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] > CPU.VPR[vb]._u32[w] ? 0xffffffff : 0; - } - } - void VCMPGTUW_(u32 vd, u32 va, u32 vb) + void VCMPGTUH(u32 vd, u32 va, u32 vb) {VCMPGTUH(vd, va, vb, false);} + void VCMPGTUH_(u32 vd, u32 va, u32 vb) {VCMPGTUH(vd, va, vb, true);} + void VCMPGTUW(u32 vd, u32 va, u32 vb, bool rc) { int all_gt = 0x8; int none_gt = 0x2; @@ -830,28 +790,37 @@ private: } } - CPU.CR.cr6 = all_gt | none_gt; + if (rc) CPU.CR.cr6 = all_gt | none_gt; } + void VCMPGTUW(u32 vd, u32 va, u32 vb) {VCMPGTUW(vd, va, vb, false);} + void VCMPGTUW_(u32 vd, u32 va, u32 vb) {VCMPGTUW(vd, va, vb, true);} void VCTSXS(u32 vd, u32 uimm5, u32 vb) { u32 nScale = 1 << uimm5; for (uint w = 0; w < 4; w++) { - double result = (double)CPU.VPR[vb]._f[w] * nScale; - - if (result > 0x7fffffff) + const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); + if (std::isnan(b)) { - CPU.VPR[vd]._s32[w] = (int)0x7fffffff; - CPU.VSCR.SAT = 1; + CPU.VPR[vd]._s32[w] = 0; } - else if (result < -pow(2, 31)) + else { - CPU.VPR[vd]._s32[w] = (int)0x80000000; - CPU.VSCR.SAT = 1; + double result = (double)b * nScale; + if (result > 0x7fffffff) + { + CPU.VPR[vd]._s32[w] = (int)0x7fffffff; + CPU.VSCR.SAT = 1; + } + else if (result < -pow(2, 31)) + { + CPU.VPR[vd]._s32[w] = (int)0x80000000; + CPU.VSCR.SAT = 1; + } + else + CPU.VPR[vd]._s32[w] = (int)trunc(result); } - else // C rounding = Round towards 0 - CPU.VPR[vd]._s32[w] = (int)result; } } void VCTUXS(u32 vd, u32 uimm5, u32 vb) @@ -860,21 +829,27 @@ private: for (uint w = 0; w < 4; w++) { - // C rounding = Round towards 0 - double result = (double)CPU.VPR[vb]._f[w] * nScale; - - if (result > 0xffffffffu) + const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); + if (std::isnan(b)) { - CPU.VPR[vd]._u32[w] = 0xffffffffu; - CPU.VSCR.SAT = 1; - } - else if (result < 0) - { - CPU.VPR[vd]._u32[w] = 0; - CPU.VSCR.SAT = 1; + CPU.VPR[vd]._s32[w] = 0; } else - CPU.VPR[vd]._u32[w] = (u32)result; + { + double result = (double)b * nScale; + if (result > 0xffffffffu) + { + CPU.VPR[vd]._u32[w] = 0xffffffffu; + CPU.VSCR.SAT = 1; + } + else if (result < 0) + { + CPU.VPR[vd]._u32[w] = 0; + CPU.VSCR.SAT = 1; + } + else + CPU.VPR[vd]._u32[w] = (u32)trunc(result); + } } } void VEXPTEFP(u32 vd, u32 vb) @@ -882,32 +857,74 @@ private: // vd = 2^x // ISA : Note that the value placed into the element of vD may vary between implementations // and between different executions on the same implementation. + SetHostRoundingMode(FPSCR_RN_NEAR); for (uint w = 0; w < 4; w++) { - CPU.VPR[vd]._f[w] = powf(2.0f, CPU.VPR[vb]._f[w]); + const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); + if (std::isnan(b)) + CPU.VPR[vd]._f[w] = SilenceNaN(b); + else + CPU.VPR[vd]._f[w] = CheckVSCR_NJ(powf(2.0f, b)); } } void VLOGEFP(u32 vd, u32 vb) { // ISA : Note that the value placed into the element of vD may vary between implementations // and between different executions on the same implementation. + SetHostRoundingMode(FPSCR_RN_NEAR); for (uint w = 0; w < 4; w++) { - CPU.VPR[vd]._f[w] = log2f(CPU.VPR[vb]._f[w]); + const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); + if (std::isnan(b)) + CPU.VPR[vd]._f[w] = SilenceNaN(b); + else + CPU.VPR[vd]._f[w] = log2f(b); // Can never be denormal. } } void VMADDFP(u32 vd, u32 va, u32 vc, u32 vb) { + SetHostRoundingMode(FPSCR_RN_NEAR); for (uint w = 0; w < 4; w++) { - CPU.VPR[vd]._f[w] = CPU.VPR[va]._f[w] * CPU.VPR[vc]._f[w] + CPU.VPR[vb]._f[w]; + const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]); + const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); + const float c = CheckVSCR_NJ(CPU.VPR[vc]._f[w]); + if (std::isnan(a)) + CPU.VPR[vd]._f[w] = SilenceNaN(a); + else if (std::isnan(b)) + CPU.VPR[vd]._f[w] = SilenceNaN(b); + else if (std::isnan(c)) + CPU.VPR[vd]._f[w] = SilenceNaN(c); + else if ((std::isinf(a) && c == 0) || (a == 0 && std::isinf(c))) + CPU.VPR[vd]._f[w] = (float)FPR_NAN; + else + { + const float result = fmaf(a, c, b); + if (std::isnan(result)) + CPU.VPR[vd]._f[w] = (float)FPR_NAN; + else + CPU.VPR[vd]._f[w] = CheckVSCR_NJ(result); + } } } void VMAXFP(u32 vd, u32 va, u32 vb) { for (uint w = 0; w < 4; w++) { - CPU.VPR[vd]._f[w] = std::max(CPU.VPR[va]._f[w], CPU.VPR[vb]._f[w]); + const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]); + const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); + if (std::isnan(a)) + CPU.VPR[vd]._f[w] = SilenceNaN(a); + else if (std::isnan(b)) + CPU.VPR[vd]._f[w] = SilenceNaN(b); + else if (a > b) + CPU.VPR[vd]._f[w] = a; + else if (b > a) + CPU.VPR[vd]._f[w] = b; + else if (CPU.VPR[vb]._u32[w] == 0x80000000) + CPU.VPR[vd]._f[w] = a; // max(+0,-0) = +0 + else + CPU.VPR[vd]._f[w] = b; } } void VMAXSB(u32 vd, u32 va, u32 vb) //nf @@ -994,7 +1011,20 @@ private: { for (uint w = 0; w < 4; w++) { - CPU.VPR[vd]._f[w] = std::min(CPU.VPR[va]._f[w], CPU.VPR[vb]._f[w]); + const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]); + const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); + if (std::isnan(a)) + CPU.VPR[vd]._f[w] = SilenceNaN(a); + else if (std::isnan(b)) + CPU.VPR[vd]._f[w] = SilenceNaN(b); + else if (a < b) + CPU.VPR[vd]._f[w] = a; + else if (b < a) + CPU.VPR[vd]._f[w] = b; + else if (CPU.VPR[vb]._u32[w] == 0x00000000) + CPU.VPR[vd]._f[w] = a; // min(-0,+0) = -0 + else + CPU.VPR[vd]._f[w] = b; } } void VMINSB(u32 vd, u32 va, u32 vb) //nf @@ -1279,9 +1309,28 @@ private: } void VNMSUBFP(u32 vd, u32 va, u32 vc, u32 vb) { + SetHostRoundingMode(FPSCR_RN_NEAR); for (uint w = 0; w < 4; w++) { - CPU.VPR[vd]._f[w] = -(CPU.VPR[va]._f[w] * CPU.VPR[vc]._f[w] - CPU.VPR[vb]._f[w]); + const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]); + const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); + const float c = CheckVSCR_NJ(CPU.VPR[vc]._f[w]); + if (std::isnan(a)) + CPU.VPR[vd]._f[w] = SilenceNaN(a); + else if (std::isnan(b)) + CPU.VPR[vd]._f[w] = SilenceNaN(b); + else if (std::isnan(c)) + CPU.VPR[vd]._f[w] = SilenceNaN(c); + else if ((std::isinf(a) && c == 0) || (a == 0 && std::isinf(c))) + CPU.VPR[vd]._f[w] = (float)FPR_NAN; + else + { + const float result = -fmaf(a, c, -b); + if (std::isnan(result)) + CPU.VPR[vd]._f[w] = (float)FPR_NAN; + else + CPU.VPR[vd]._f[w] = CheckVSCR_NJ(result); + } } } void VNOR(u32 vd, u32 va, u32 vb) @@ -1554,37 +1603,61 @@ private: } void VREFP(u32 vd, u32 vb) { + SetHostRoundingMode(FPSCR_RN_NEAR); for (uint w = 0; w < 4; w++) { - CPU.VPR[vd]._f[w] = 1.0f / CPU.VPR[vb]._f[w]; + const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); + if (std::isnan(b)) + CPU.VPR[vd]._f[w] = SilenceNaN(b); + else + CPU.VPR[vd]._f[w] = CheckVSCR_NJ(1.0f / b); } } void VRFIM(u32 vd, u32 vb) { for (uint w = 0; w < 4; w++) { - CPU.VPR[vd]._f[w] = floorf(CPU.VPR[vb]._f[w]); + const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); + if (std::isnan(b)) + CPU.VPR[vd]._f[w] = SilenceNaN(b); + else + CPU.VPR[vd]._f[w] = floorf(CPU.VPR[vb]._f[w]); } } void VRFIN(u32 vd, u32 vb) { for (uint w = 0; w < 4; w++) { - CPU.VPR[vd]._f[w] = nearbyintf(CPU.VPR[vb]._f[w]); + const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); + if (std::isnan(b)) + CPU.VPR[vd]._f[w] = SilenceNaN(b); + else + { + SetHostRoundingMode(FPSCR_RN_NEAR); + CPU.VPR[vd]._f[w] = nearbyintf(CPU.VPR[vb]._f[w]); + } } } void VRFIP(u32 vd, u32 vb) { for (uint w = 0; w < 4; w++) { - CPU.VPR[vd]._f[w] = ceilf(CPU.VPR[vb]._f[w]); + const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); + if (std::isnan(b)) + CPU.VPR[vd]._f[w] = SilenceNaN(b); + else + CPU.VPR[vd]._f[w] = ceilf(CPU.VPR[vb]._f[w]); } } void VRFIZ(u32 vd, u32 vb) { for (uint w = 0; w < 4; w++) { - CPU.VPR[vd]._f[w] = truncf(CPU.VPR[vb]._f[w]); + const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); + if (std::isnan(b)) + CPU.VPR[vd]._f[w] = SilenceNaN(b); + else + CPU.VPR[vd]._f[w] = truncf(CPU.VPR[vb]._f[w]); } } void VRLB(u32 vd, u32 va, u32 vb) //nf @@ -1612,10 +1685,17 @@ private: } void VRSQRTEFP(u32 vd, u32 vb) { + SetHostRoundingMode(FPSCR_RN_NEAR); for (uint w = 0; w < 4; w++) { //TODO: accurate div - CPU.VPR[vd]._f[w] = 1.0f / sqrtf(CPU.VPR[vb]._f[w]); + const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); + if (std::isnan(b)) + CPU.VPR[vd]._f[w] = SilenceNaN(b); + else if (b < 0) + CPU.VPR[vd]._f[w] = (float)FPR_NAN; + else + CPU.VPR[vd]._f[w] = 1.0f / sqrtf(b); // Can never be denormal. } } void VSEL(u32 vd, u32 va, u32 vb, u32 vc) @@ -1806,9 +1886,19 @@ private: } void VSUBFP(u32 vd, u32 va, u32 vb) { + SetHostRoundingMode(FPSCR_RN_NEAR); for (uint w = 0; w < 4; w++) { - CPU.VPR[vd]._f[w] = CPU.VPR[va]._f[w] - CPU.VPR[vb]._f[w]; + const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]); + const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]); + if (std::isnan(a)) + CPU.VPR[vd]._f[w] = SilenceNaN(a); + else if (std::isnan(b)) + CPU.VPR[vd]._f[w] = SilenceNaN(b); + else if (std::isinf(a) && std::isinf(b) && a == b) + CPU.VPR[vd]._f[w] = (float)FPR_NAN; + else + CPU.VPR[vd]._f[w] = CheckVSCR_NJ(a - b); } } void VSUBSBS(u32 vd, u32 va, u32 vb) //nf @@ -1939,15 +2029,14 @@ private: } void VSUMSWS(u32 vd, u32 va, u32 vb) { - CPU.VPR[vd].clear(); - - s64 sum = CPU.VPR[vb]._s32[3]; + s64 sum = CPU.VPR[vb]._s32[0]; for (uint w = 0; w < 4; w++) { sum += CPU.VPR[va]._s32[w]; } + CPU.VPR[vd].clear(); if (sum > INT32_MAX) { CPU.VPR[vd]._s32[0] = (s32)INT32_MAX; @@ -2169,7 +2258,7 @@ private: switch (lev) { case 0x0: SysCall(); break; - case 0x1: UNK("HyperCall LV1"); break; + case 0x1: throw "SC(): HyperCall LV1"; case 0x2: Emu.GetSFuncManager().StaticExecute(CPU, (u32)CPU.GPR[11]); if (Ini.HLELogging.GetValue()) @@ -2179,7 +2268,7 @@ private: } break; case 0x3: CPU.FastStop(); break; - default: UNK(fmt::Format("Unknown sc: 0x%x", lev)); break; + default: throw fmt::Format("SC(): unknown level (0x%x)", lev); } } void B(s32 ll, u32 aa, u32 lk) @@ -2247,7 +2336,7 @@ private: } void BCCTR(u32 bo, u32 bi, u32 bh, u32 lk) { - if(bo & 0x10 || CPU.IsCR(bi) == (bo & 0x8)) + if(bo & 0x10 || CPU.IsCR(bi) == ((bo & 0x8) != 0)) { const u32 nextLR = CPU.PC + 4; CPU.SetBranch(branchTarget(0, (u32)CPU.CTR), true); @@ -2343,7 +2432,7 @@ private: ((u32)a < (u32)b && (to & 0x2)) || ((u32)a > (u32)b && (to & 0x1)) ) { - UNK(fmt::Format("Trap! (tw 0x%x, r%d, r%d)", to, ra, rb)); + throw fmt::Format("Trap! (tw 0x%x, r%d, r%d)", to, ra, rb); } } void LVSL(u32 vd, u32 ra, u32 rb) @@ -2376,13 +2465,7 @@ private: void LVEBX(u32 vd, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - CPU.VPR[vd]._u8[15 - (addr & 0xf)] = vm::read8((u32)addr); + CPU.VPR[vd]._u8[15 - (addr & 0xf)] = vm::read8(vm::cast(addr)); // check LVEWX comments } void SUBFC(u32 rd, u32 ra, u32 rb, u32 oe, bool rc) @@ -2391,16 +2474,16 @@ private: const u64 RB = CPU.GPR[rb]; CPU.GPR[rd] = ~RA + RB + 1; CPU.XER.CA = CPU.IsCarry(~RA, RB, 1); - if(oe) UNK("subfco"); + if(oe) CPU.SetOV((~RA>>63 == RB>>63) && (~RA>>63 != CPU.GPR[rd]>>63)); if(rc) CPU.UpdateCR0(CPU.GPR[rd]); } void ADDC(u32 rd, u32 ra, u32 rb, u32 oe, bool rc) { - const s64 RA = CPU.GPR[ra]; - const s64 RB = CPU.GPR[rb]; + const u64 RA = CPU.GPR[ra]; + const u64 RB = CPU.GPR[rb]; CPU.GPR[rd] = RA + RB; CPU.XER.CA = CPU.IsCarry(RA, RB); - if(oe) UNK("addco"); + if(oe) CPU.SetOV((RA>>63 == RB>>63) && (RA>>63 != CPU.GPR[rd]>>63)); if(rc) CPU.UpdateCR0(CPU.GPR[rd]); } void MULHDU(u32 rd, u32 ra, u32 rb, bool rc) @@ -2448,36 +2531,18 @@ private: void LWARX(u32 rd, u32 ra, u32 rb) { CPU.R_ADDR = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)CPU.R_ADDR != CPU.R_ADDR) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, CPU.R_ADDR); - Emu.Pause(); - return; - } - CPU.R_VALUE = vm::get_ref((u32)CPU.R_ADDR); + CPU.R_VALUE = vm::get_ref(vm::cast(CPU.R_ADDR)); CPU.GPR[rd] = re32((u32)CPU.R_VALUE); } void LDX(u32 rd, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - CPU.GPR[rd] = vm::read64((u32)addr); + CPU.GPR[rd] = vm::read64(vm::cast(addr)); } void LWZX(u32 rd, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - CPU.GPR[rd] = vm::read32((u32)addr); + CPU.GPR[rd] = vm::read32(vm::cast(addr)); } void SLW(u32 ra, u32 rs, u32 rb, bool rc) { @@ -2549,31 +2614,21 @@ private: void LVEHX(u32 vd, u32 ra, u32 rb) { const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~1ULL; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - CPU.VPR[vd]._u16[7 - ((addr >> 1) & 0x7)] = vm::read16((u32)addr); + CPU.VPR[vd]._u16[7 - ((addr >> 1) & 0x7)] = vm::read16(vm::cast(addr)); // check LVEWX comments } void SUBF(u32 rd, u32 ra, u32 rb, u32 oe, bool rc) { - CPU.GPR[rd] = CPU.GPR[rb] - CPU.GPR[ra]; - if(oe) UNK("subfo"); + const u64 RA = CPU.GPR[ra]; + const u64 RB = CPU.GPR[rb]; + CPU.GPR[rd] = RB - RA; + if(oe) CPU.SetOV((~RA>>63 == RB>>63) && (~RA>>63 != CPU.GPR[rd]>>63)); if(rc) CPU.UpdateCR0(CPU.GPR[rd]); } void LDUX(u32 rd, u32 ra, u32 rb) { const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - CPU.GPR[rd] = vm::read64((u32)addr); + CPU.GPR[rd] = vm::read64(vm::cast(addr)); CPU.GPR[ra] = addr; } void DCBST(u32 ra, u32 rb) @@ -2582,13 +2637,7 @@ private: void LWZUX(u32 rd, u32 ra, u32 rb) { const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - CPU.GPR[rd] = vm::read32((u32)addr); + CPU.GPR[rd] = vm::read32(vm::cast(addr)); CPU.GPR[ra] = addr; } void CNTLZD(u32 ra, u32 rs, bool rc) @@ -2609,18 +2658,12 @@ private: } void TD(u32 to, u32 ra, u32 rb) { - UNK("td"); + throw "TD()"; } void LVEWX(u32 vd, u32 ra, u32 rb) { const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~3ULL; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - CPU.VPR[vd]._u32[3 - ((addr >> 2) & 0x3)] = vm::read32((u32)addr); + CPU.VPR[vd]._u32[3 - ((addr >> 2) & 0x3)] = vm::read32(vm::cast(addr)); // It's not very good idea to implement it using read128(), // because it can theoretically read RawSPU 32-bit MMIO register (read128() will fail) //CPU.VPR[vd] = vm::read128((ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~0xfULL); @@ -2640,13 +2683,7 @@ private: void LDARX(u32 rd, u32 ra, u32 rb) { CPU.R_ADDR = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)CPU.R_ADDR != CPU.R_ADDR) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, CPU.R_ADDR); - Emu.Pause(); - return; - } - CPU.R_VALUE = vm::get_ref((u32)CPU.R_ADDR); + CPU.R_VALUE = vm::get_ref(vm::cast(CPU.R_ADDR)); CPU.GPR[rd] = re64(CPU.R_VALUE); } void DCBF(u32 ra, u32 rb) @@ -2655,13 +2692,7 @@ private: void LBZX(u32 rd, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - CPU.GPR[rd] = vm::read8((u32)addr); + CPU.GPR[rd] = vm::read8(vm::cast(addr)); } void LVX(u32 vd, u32 ra, u32 rb) { @@ -2669,8 +2700,9 @@ private: } void NEG(u32 rd, u32 ra, u32 oe, bool rc) { - CPU.GPR[rd] = 0-CPU.GPR[ra]; - if(oe) UNK("nego"); + const u64 RA = CPU.GPR[ra]; + CPU.GPR[rd] = 0 - RA; + if(oe) CPU.SetOV((~RA>>63 == 0) && (~RA>>63 != CPU.GPR[rd]>>63)); if(rc) CPU.UpdateCR0(CPU.GPR[rd]); } void LBZUX(u32 rd, u32 ra, u32 rb) @@ -2678,13 +2710,7 @@ private: //if(ra == 0 || ra == rd) throw "Bad instruction [LBZUX]"; const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - CPU.GPR[rd] = vm::read8((u32)addr); + CPU.GPR[rd] = vm::read8(vm::cast(addr)); CPU.GPR[ra] = addr; } void NOR(u32 ra, u32 rs, u32 rb, bool rc) @@ -2695,14 +2721,8 @@ private: void STVEBX(u32 vs, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } const u8 eb = addr & 0xf; - vm::write8((u32)addr, CPU.VPR[vs]._u8[15 - eb]); + vm::write8(vm::cast(addr), CPU.VPR[vs]._u8[15 - eb]); } void SUBFE(u32 rd, u32 ra, u32 rb, u32 oe, bool rc) { @@ -2710,8 +2730,8 @@ private: const u64 RB = CPU.GPR[rb]; CPU.GPR[rd] = ~RA + RB + CPU.XER.CA; CPU.XER.CA = CPU.IsCarry(~RA, RB, CPU.XER.CA); + if(oe) CPU.SetOV((~RA>>63 == RB>>63) && (~RA>>63 != CPU.GPR[rd]>>63)); if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - if(oe) UNK("subfeo"); } void ADDE(u32 rd, u32 ra, u32 rb, u32 oe, bool rc) { @@ -2735,8 +2755,8 @@ private: CPU.GPR[rd] = RA + RB; CPU.XER.CA = CPU.IsCarry(RA, RB); } + if(oe) CPU.SetOV((RA>>63 == RB>>63) && (RA>>63 != CPU.GPR[rd]>>63)); if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - if(oe) UNK("addeo"); } void MTOCRF(u32 l, u32 crm, u32 rs) { @@ -2766,7 +2786,7 @@ private: { if(crm & (1 << i)) { - CPU.SetCR(7 - i, CPU.GPR[rs] & (0xf << (i * 4))); + CPU.SetCR(7 - i, (CPU.GPR[rs] >> (i * 4)) & 0xf); } } } @@ -2774,99 +2794,57 @@ private: void STDX(u32 rs, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - vm::write64((u32)addr, CPU.GPR[rs]); + vm::write64(vm::cast(addr), CPU.GPR[rs]); } void STWCX_(u32 rs, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } if (CPU.R_ADDR == addr) { - CPU.SetCR_EQ(0, InterlockedCompareExchange(vm::get_ptr((u32)CPU.R_ADDR), re32((u32)CPU.GPR[rs]), (u32)CPU.R_VALUE) == (u32)CPU.R_VALUE); - CPU.R_ADDR = 0; + CPU.SetCR_EQ(0, InterlockedCompareExchange(vm::get_ptr(vm::cast(CPU.R_ADDR)), re32((u32)CPU.GPR[rs]), (u32)CPU.R_VALUE) == (u32)CPU.R_VALUE); } else { CPU.SetCR_EQ(0, false); } + CPU.R_ADDR = 0; } void STWX(u32 rs, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - vm::write32((u32)addr, (u32)CPU.GPR[rs]); + vm::write32(vm::cast(addr), (u32)CPU.GPR[rs]); } void STVEHX(u32 vs, u32 ra, u32 rb) { const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~1ULL; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } const u8 eb = (addr & 0xf) >> 1; - vm::write16((u32)addr, CPU.VPR[vs]._u16[7 - eb]); + vm::write16(vm::cast(addr), CPU.VPR[vs]._u16[7 - eb]); } void STDUX(u32 rs, u32 ra, u32 rb) { const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - vm::write64((u32)addr, CPU.GPR[rs]); + vm::write64(vm::cast(addr), CPU.GPR[rs]); CPU.GPR[ra] = addr; } void STWUX(u32 rs, u32 ra, u32 rb) { const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - vm::write32((u32)addr, (u32)CPU.GPR[rs]); + vm::write32(vm::cast(addr), (u32)CPU.GPR[rs]); CPU.GPR[ra] = addr; } void STVEWX(u32 vs, u32 ra, u32 rb) { const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~3ULL; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } const u8 eb = (addr & 0xf) >> 2; - vm::write32((u32)addr, CPU.VPR[vs]._u32[3 - eb]); + vm::write32(vm::cast(addr), CPU.VPR[vs]._u32[3 - eb]); } void ADDZE(u32 rd, u32 ra, u32 oe, bool rc) { const u64 RA = CPU.GPR[ra]; CPU.GPR[rd] = RA + CPU.XER.CA; CPU.XER.CA = CPU.IsCarry(RA, CPU.XER.CA); - if(oe) LOG_WARNING(PPU, "addzeo"); + if(oe) CPU.SetOV((RA>>63 == 0) && (RA>>63 != CPU.GPR[rd]>>63)); if(rc) CPU.UpdateCR0(CPU.GPR[rd]); } void SUBFZE(u32 rd, u32 ra, u32 oe, bool rc) @@ -2874,39 +2852,27 @@ private: const u64 RA = CPU.GPR[ra]; CPU.GPR[rd] = ~RA + CPU.XER.CA; CPU.XER.CA = CPU.IsCarry(~RA, CPU.XER.CA); - if (oe) LOG_WARNING(PPU, "subfzeo"); - if (rc) CPU.UpdateCR0(CPU.GPR[rd]); + if(oe) CPU.SetOV((~RA>>63 == 0) && (~RA>>63 != CPU.GPR[rd]>>63)); + if(rc) CPU.UpdateCR0(CPU.GPR[rd]); } void STDCX_(u32 rs, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } if (CPU.R_ADDR == addr) { - CPU.SetCR_EQ(0, InterlockedCompareExchange(vm::get_ptr((u32)CPU.R_ADDR), re64(CPU.GPR[rs]), CPU.R_VALUE) == CPU.R_VALUE); - CPU.R_ADDR = 0; + CPU.SetCR_EQ(0, InterlockedCompareExchange(vm::get_ptr(vm::cast(CPU.R_ADDR)), re64(CPU.GPR[rs]), CPU.R_VALUE) == CPU.R_VALUE); } else { CPU.SetCR_EQ(0, false); } + CPU.R_ADDR = 0; } void STBX(u32 rs, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - vm::write8((u32)addr, (u8)CPU.GPR[rs]); + vm::write8(vm::cast(addr), (u8)CPU.GPR[rs]); } void STVX(u32 vs, u32 ra, u32 rb) { @@ -2917,14 +2883,20 @@ private: const u64 RA = CPU.GPR[ra]; CPU.GPR[rd] = ~RA + CPU.XER.CA + ~0ULL; CPU.XER.CA = CPU.IsCarry(~RA, CPU.XER.CA, ~0ULL); - if (oe) LOG_WARNING(PPU, "subfmeo"); - if (rc) CPU.UpdateCR0(CPU.GPR[rd]); + if(oe) CPU.SetOV((~RA>>63 == 1) && (~RA>>63 != CPU.GPR[rd]>>63)); + if(rc) CPU.UpdateCR0(CPU.GPR[rd]); } void MULLD(u32 rd, u32 ra, u32 rb, u32 oe, bool rc) { - CPU.GPR[rd] = (s64)((s64)CPU.GPR[ra] * (s64)CPU.GPR[rb]); + const s64 RA = CPU.GPR[ra]; + const s64 RB = CPU.GPR[rb]; + CPU.GPR[rd] = (s64)(RA * RB); + if(oe) + { + const s64 high = __mulh(RA, RB); + CPU.SetOV(high != s64(CPU.GPR[rd]) >> 63); + } if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - if(oe) UNK("mulldo"); } void ADDME(u32 rd, u32 ra, u32 oe, bool rc) { @@ -2932,14 +2904,14 @@ private: CPU.GPR[rd] = RA + CPU.XER.CA - 1; CPU.XER.CA |= RA != 0; - if(oe) UNK("addmeo"); + if(oe) CPU.SetOV((u64(RA)>>63 == 1) && (u64(RA)>>63 != CPU.GPR[rd]>>63)); if(rc) CPU.UpdateCR0(CPU.GPR[rd]); } void MULLW(u32 rd, u32 ra, u32 rb, u32 oe, bool rc) { CPU.GPR[rd] = (s64)((s64)(s32)CPU.GPR[ra] * (s64)(s32)CPU.GPR[rb]); + if(oe) CPU.SetOV(s64(CPU.GPR[rd]) < s64(-1)<<31 || s64(CPU.GPR[rd]) >= s64(1)<<31); if(rc) CPU.UpdateCR0(CPU.GPR[rd]); - if(oe) UNK("mullwo"); } void DCBTST(u32 ra, u32 rb, u32 th) { @@ -2947,13 +2919,7 @@ private: void STBUX(u32 rs, u32 ra, u32 rb) { const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - vm::write8((u32)addr, (u8)CPU.GPR[rs]); + vm::write8(vm::cast(addr), (u8)CPU.GPR[rs]); CPU.GPR[ra] = addr; } void ADD(u32 rd, u32 ra, u32 rb, u32 oe, bool rc) @@ -2961,7 +2927,7 @@ private: const u64 RA = CPU.GPR[ra]; const u64 RB = CPU.GPR[rb]; CPU.GPR[rd] = RA + RB; - if(oe) UNK("addo"); + if(oe) CPU.SetOV((RA>>63 == RB>>63) && (RA>>63 != CPU.GPR[rd]>>63)); if(rc) CPU.UpdateCR0(CPU.GPR[rd]); } void DCBT(u32 ra, u32 rb, u32 th) @@ -2970,13 +2936,7 @@ private: void LHZX(u32 rd, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - CPU.GPR[rd] = vm::read16((u32)addr); + CPU.GPR[rd] = vm::read16(vm::cast(addr)); } void EQV(u32 ra, u32 rs, u32 rb, bool rc) { @@ -2987,24 +2947,12 @@ private: { //HACK! const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - CPU.GPR[rd] = vm::read32((u32)addr); + CPU.GPR[rd] = vm::read32(vm::cast(addr)); } void LHZUX(u32 rd, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - CPU.GPR[rd] = vm::read16((u32)addr); + CPU.GPR[rd] = vm::read16(vm::cast(addr)); CPU.GPR[ra] = addr; } void XOR(u32 ra, u32 rs, u32 rb, bool rc) @@ -3019,13 +2967,7 @@ private: void LWAX(u32 rd, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - CPU.GPR[rd] = (s64)(s32)vm::read32((u32)addr); + CPU.GPR[rd] = (s64)(s32)vm::read32(vm::cast(addr)); } void DST(u32 ra, u32 rb, u32 strm, u32 t) { @@ -3033,13 +2975,7 @@ private: void LHAX(u32 rd, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - CPU.GPR[rd] = (s64)(s16)vm::read16((u32)addr); + CPU.GPR[rd] = (s64)(s16)vm::read16(vm::cast(addr)); } void LVXL(u32 vd, u32 ra, u32 rb) { @@ -3053,20 +2989,14 @@ private: switch(n) { case 0x10C: CPU.GPR[rd] = CPU.TB; break; - case 0x10D: CPU.GPR[rd] = CPU.TBH; break; - default: UNK(fmt::Format("mftb r%d, %d", rd, spr)); break; + case 0x10D: CPU.GPR[rd] = CPU.TB >> 32; break; + default: throw fmt::Format("mftb r%d, %d", rd, spr); } } void LWAUX(u32 rd, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - CPU.GPR[rd] = (s64)(s32)vm::read32((u32)addr); + CPU.GPR[rd] = (s64)(s32)vm::read32(vm::cast(addr)); CPU.GPR[ra] = addr; } void DSTST(u32 ra, u32 rb, u32 strm, u32 t) @@ -3075,25 +3005,13 @@ private: void LHAUX(u32 rd, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - CPU.GPR[rd] = (s64)(s16)vm::read16((u32)addr); + CPU.GPR[rd] = (s64)(s16)vm::read16(vm::cast(addr)); CPU.GPR[ra] = addr; } void STHX(u32 rs, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - vm::write16((u32)addr, (u16)CPU.GPR[rs]); + vm::write16(vm::cast(addr), (u16)CPU.GPR[rs]); } void ORC(u32 ra, u32 rs, u32 rb, bool rc) { @@ -3104,24 +3022,12 @@ private: { //HACK! const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - vm::write32((u32)addr, (u32)CPU.GPR[rs]); + vm::write32(vm::cast(addr), (u32)CPU.GPR[rs]); } void STHUX(u32 rs, u32 ra, u32 rb) { const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - vm::write16((u32)addr, (u16)CPU.GPR[rs]); + vm::write16(vm::cast(addr), (u16)CPU.GPR[rs]); CPU.GPR[ra] = addr; } void OR(u32 ra, u32 rs, u32 rb, bool rc) @@ -3136,11 +3042,12 @@ private: if(RB == 0) { - if(oe) UNK("divduo"); + if(oe) CPU.SetOV(true); CPU.GPR[rd] = 0; } else { + if(oe) CPU.SetOV(false); CPU.GPR[rd] = RA / RB; } @@ -3153,11 +3060,12 @@ private: if(RB == 0) { - if(oe) UNK("divwuo"); + if(oe) CPU.SetOV(true); CPU.GPR[rd] = 0; } else { + if(oe) CPU.SetOV(false); CPU.GPR[rd] = RA / RB; } @@ -3187,11 +3095,12 @@ private: if (RB == 0 || ((u64)RA == (1ULL << 63) && RB == -1)) { - if(oe) UNK("divdo"); + if(oe) CPU.SetOV(true); CPU.GPR[rd] = /*(((u64)RA & (1ULL << 63)) && RB == 0) ? -1 :*/ 0; } else { + if(oe) CPU.SetOV(false); CPU.GPR[rd] = RA / RB; } @@ -3204,11 +3113,12 @@ private: if (RB == 0 || ((u32)RA == (1 << 31) && RB == -1)) { - if(oe) UNK("divwo"); + if(oe) CPU.SetOV(true); CPU.GPR[rd] = /*(((u32)RA & (1 << 31)) && RB == 0) ? -1 :*/ 0; } else { + if(oe) CPU.SetOV(false); CPU.GPR[rd] = (u32)(RA / RB); } @@ -3217,53 +3127,53 @@ private: void LVLX(u32 vd, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } const u32 eb = addr & 0xf; CPU.VPR[vd].clear(); - for (u32 i = 0; i < 16u - eb; ++i) CPU.VPR[vd]._u8[15 - i] = vm::read8((u32)addr + i); + for (u32 i = 0; i < 16u - eb; ++i) CPU.VPR[vd]._u8[15 - i] = vm::read8(vm::cast(addr + i)); } void LDBRX(u32 rd, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - CPU.GPR[rd] = vm::get_ref((u32)addr); + CPU.GPR[rd] = vm::get_ref(vm::cast(addr)); } void LSWX(u32 rd, u32 ra, u32 rb) { - UNK("lswx"); + u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; + u32 count = CPU.XER.XER & 0x7F; + for (; count >= 4; count -= 4, addr += 4, rd = (rd+1) & 31) + { + CPU.GPR[rd] = vm::get_ref>(vm::cast(addr)); + } + if (count) + { + u32 value = 0; + for (u32 byte = 0; byte < count; byte++) + { + u32 byte_value = vm::get_ref(vm::cast(addr+byte)); + value |= byte_value << ((3^byte)*8); + } + CPU.GPR[rd] = value; + } } void LWBRX(u32 rd, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - CPU.GPR[rd] = vm::get_ref((u32)addr); + CPU.GPR[rd] = vm::get_ref(vm::cast(addr)); } void LFSX(u32 frd, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) + float val = vm::get_ref>(vm::cast(addr)).value(); + if (!FPRdouble::IsNaN(val)) { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; + CPU.FPR[frd] = val; + } + else + { + u64 bits = (u32&)val; + (u64&)CPU.FPR[frd] = (bits & 0x80000000) << 32 | 7ULL << 60 | (bits & 0x7fffffff) << 29; } - CPU.FPR[frd] = vm::get_ref>((u32)addr).ToLE(); } void SRW(u32 ra, u32 rs, u32 rb, bool rc) { @@ -3286,26 +3196,14 @@ private: void LVRX(u32 vd, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } const u8 eb = addr & 0xf; CPU.VPR[vd].clear(); - for (u32 i = 16 - eb; i < 16; ++i) CPU.VPR[vd]._u8[15 - i] = vm::read8((u32)addr + i - 16); + for (u32 i = 16 - eb; i < 16; ++i) CPU.VPR[vd]._u8[15 - i] = vm::read8(vm::cast(addr + i - 16)); } void LSWI(u32 rd, u32 ra, u32 nb) { u64 addr = ra ? CPU.GPR[ra] : 0; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } u64 N = nb ? nb : 32; u8 reg = rd; @@ -3313,7 +3211,7 @@ private: { if (N > 3) { - CPU.GPR[reg] = vm::read32((u32)addr); + CPU.GPR[reg] = vm::read32(vm::cast(addr)); addr += 4; N -= 4; } @@ -3324,7 +3222,7 @@ private: while (N > 0) { N = N - 1; - buf |= vm::read8((u32)addr) << (i * 8); + buf |= vm::read8(vm::cast(addr)) << (i * 8); addr++; i--; } @@ -3336,14 +3234,16 @@ private: void LFSUX(u32 frd, u32 ra, u32 rb) { const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - if ((u32)addr != addr) + float val = vm::get_ref>(vm::cast(addr)).value(); + if (!FPRdouble::IsNaN(val)) { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; + CPU.FPR[frd] = val; + } + else + { + u64 bits = (u32&)val; + (u64&)CPU.FPR[frd] = (bits & 0x80000000) << 32 | 7ULL << 60 | (bits & 0x7fffffff) << 29; } - (u64&)CPU.FPR[frd] = vm::read32((u32)addr); - CPU.FPR[frd] = (float&)CPU.FPR[frd]; CPU.GPR[ra] = addr; } void SYNC(u32 l) @@ -3353,99 +3253,90 @@ private: void LFDX(u32 frd, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - (u64&)CPU.FPR[frd] = vm::read64((u32)addr); + CPU.FPR[frd] = vm::get_ref>(vm::cast(addr)).value(); } void LFDUX(u32 frd, u32 ra, u32 rb) { const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - (u64&)CPU.FPR[frd] = vm::read64((u32)addr); + CPU.FPR[frd] = vm::get_ref>(vm::cast(addr)).value(); CPU.GPR[ra] = addr; } void STVLX(u32 vs, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } const u32 eb = addr & 0xf; - for (u32 i = 0; i < 16u - eb; ++i) vm::write8((u32)addr + i, CPU.VPR[vs]._u8[15 - i]); + for (u32 i = 0; i < 16u - eb; ++i) vm::write8(vm::cast(addr + i), CPU.VPR[vs]._u8[15 - i]); + } + void STDBRX(u32 rs, u32 ra, u32 rb) + { + const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; + vm::get_ref(vm::cast(addr)) = CPU.GPR[rs]; } void STSWX(u32 rs, u32 ra, u32 rb) { - UNK("stwsx"); + u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; + u32 count = CPU.XER.XER & 0x7F; + for (; count >= 4; count -= 4, addr += 4, rs = (rs+1) & 31) + { + vm::write32(vm::cast(addr), (u32)CPU.GPR[rs]); + } + if (count) + { + u32 value = (u32)CPU.GPR[rs]; + for (u32 byte = 0; byte < count; byte++) + { + u32 byte_value = (u8)(value >> ((3^byte)*8)); + vm::write8(vm::cast(addr+byte), byte_value); + } + } } void STWBRX(u32 rs, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - vm::get_ref((u32)addr) = (u32)CPU.GPR[rs]; + vm::get_ref(vm::cast(addr)) = (u32)CPU.GPR[rs]; } void STFSX(u32 frs, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) + double val = CPU.FPR[frs]; + if (!FPRdouble::IsNaN(val)) { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; + vm::get_ref>(vm::cast(addr)) = (float)val; + } + else + { + u64 bits = (u64&)val; + u32 bits32 = (bits>>32 & 0x80000000) | (bits>>29 & 0x7fffffff); + vm::get_ref>(vm::cast(addr)) = (float)bits32; } - vm::write32((u32)addr, CPU.FPR[frs].To32()); } void STVRX(u32 vs, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } const u8 eb = addr & 0xf; - for (u32 i = 16 - eb; i < 16; ++i) vm::write8((u32)addr + i - 16, CPU.VPR[vs]._u8[15 - i]); + for (u32 i = 16 - eb; i < 16; ++i) vm::write8(vm::cast(addr + i - 16), CPU.VPR[vs]._u8[15 - i]); } void STFSUX(u32 frs, u32 ra, u32 rb) { const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - if ((u32)addr != addr) + double val = CPU.FPR[frs]; + if (!FPRdouble::IsNaN(val)) { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; + vm::get_ref>(vm::cast(addr)) = (float)val; + } + else + { + u64 bits = (u64&)val; + u32 bits32 = (bits>>32 & 0x80000000) | (bits>>29 & 0x7fffffff); + vm::get_ref>(vm::cast(addr)) = (float)bits32; } - vm::write32((u32)addr, CPU.FPR[frs].To32()); CPU.GPR[ra] = addr; } void STSWI(u32 rd, u32 ra, u32 nb) { u64 addr = ra ? CPU.GPR[ra] : 0; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } u64 N = nb ? nb : 32; u8 reg = rd; @@ -3453,7 +3344,7 @@ private: { if (N > 3) { - vm::write32((u32)addr, (u32)CPU.GPR[reg]); + vm::write32(vm::cast(addr), (u32)CPU.GPR[reg]); addr += 4; N -= 4; } @@ -3463,7 +3354,7 @@ private: while (N > 0) { N = N - 1; - vm::write8((u32)addr, (0xFF000000 & buf) >> 24); + vm::write8(vm::cast(addr), (0xFF000000 & buf) >> 24); buf <<= 8; addr++; } @@ -3474,50 +3365,26 @@ private: void STFDX(u32 frs, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - vm::write64((u32)addr, (u64&)CPU.FPR[frs]); + vm::get_ref>(vm::cast(addr)) = CPU.FPR[frs]; } void STFDUX(u32 frs, u32 ra, u32 rb) { const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - vm::write64((u32)addr, (u64&)CPU.FPR[frs]); + vm::get_ref>(vm::cast(addr)) = CPU.FPR[frs]; CPU.GPR[ra] = addr; } void LVLXL(u32 vd, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } const u32 eb = addr & 0xf; CPU.VPR[vd].clear(); - for (u32 i = 0; i < 16u - eb; ++i) CPU.VPR[vd]._u8[15 - i] = vm::read8((u32)addr + i); + for (u32 i = 0; i < 16u - eb; ++i) CPU.VPR[vd]._u8[15 - i] = vm::read8(vm::cast(addr + i)); } void LHBRX(u32 rd, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - CPU.GPR[rd] = vm::get_ref((u32)addr); + CPU.GPR[rd] = vm::get_ref(vm::cast(addr)); } void SRAW(u32 ra, u32 rs, u32 rb, bool rc) { @@ -3556,16 +3423,10 @@ private: void LVRXL(u32 vd, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } const u8 eb = addr & 0xf; CPU.VPR[vd].clear(); - for (u32 i = 16 - eb; i < 16; ++i) CPU.VPR[vd]._u8[15 - i] = vm::read8((u32)addr + i - 16); + for (u32 i = 16 - eb; i < 16; ++i) CPU.VPR[vd]._u8[15 - i] = vm::read8(vm::cast(addr + i - 16)); } void DSS(u32 strm, u32 a) { @@ -3597,26 +3458,14 @@ private: void STVLXL(u32 vs, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } const u32 eb = addr & 0xf; - for (u32 i = 0; i < 16u - eb; ++i) vm::write8((u32)addr + i, CPU.VPR[vs]._u8[15 - i]); + for (u32 i = 0; i < 16u - eb; ++i) vm::write8(vm::cast(addr + i), CPU.VPR[vs]._u8[15 - i]); } void STHBRX(u32 rs, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - vm::get_ref((u32)addr) = (u16)CPU.GPR[rs]; + vm::get_ref(vm::cast(addr)) = (u16)CPU.GPR[rs]; } void EXTSH(u32 ra, u32 rs, bool rc) { @@ -3626,15 +3475,9 @@ private: void STVRXL(u32 vs, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } const u8 eb = addr & 0xf; - for (u32 i = 16 - eb; i < 16; ++i) vm::write8((u32)addr + i - 16, CPU.VPR[vs]._u8[15 - i]); + for (u32 i = 16 - eb; i < 16; ++i) vm::write8(vm::cast(addr + i - 16), CPU.VPR[vs]._u8[15 - i]); } void EXTSB(u32 ra, u32 rs, bool rc) { @@ -3644,13 +3487,7 @@ private: void STFIWX(u32 frs, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - vm::write32((u32)addr, (u32&)CPU.FPR[frs]); + vm::write32(vm::cast(addr), (u32&)CPU.FPR[frs]); } void EXTSW(u32 ra, u32 rs, bool rc) { @@ -3664,498 +3501,286 @@ private: void DCBZ(u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - auto const cache_line = vm::get_ptr((u32)addr & ~127); + auto const cache_line = vm::get_ptr(vm::cast(addr) & ~127); if (cache_line) memset(cache_line, 0, 128); } void LWZ(u32 rd, u32 ra, s32 d) { const u64 addr = ra ? CPU.GPR[ra] + d : d; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - CPU.GPR[rd] = vm::read32((u32)addr); + CPU.GPR[rd] = vm::read32(vm::cast(addr)); } void LWZU(u32 rd, u32 ra, s32 d) { const u64 addr = CPU.GPR[ra] + d; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - CPU.GPR[rd] = vm::read32((u32)addr); + CPU.GPR[rd] = vm::read32(vm::cast(addr)); CPU.GPR[ra] = addr; } void LBZ(u32 rd, u32 ra, s32 d) { const u64 addr = ra ? CPU.GPR[ra] + d : d; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - CPU.GPR[rd] = vm::read8((u32)addr); + CPU.GPR[rd] = vm::read8(vm::cast(addr)); } void LBZU(u32 rd, u32 ra, s32 d) { const u64 addr = CPU.GPR[ra] + d; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - CPU.GPR[rd] = vm::read8((u32)addr); + CPU.GPR[rd] = vm::read8(vm::cast(addr)); CPU.GPR[ra] = addr; } void STW(u32 rs, u32 ra, s32 d) { const u64 addr = ra ? CPU.GPR[ra] + d : d; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - vm::write32((u32)addr, (u32)CPU.GPR[rs]); + vm::write32(vm::cast(addr), (u32)CPU.GPR[rs]); } void STWU(u32 rs, u32 ra, s32 d) { const u64 addr = CPU.GPR[ra] + d; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - vm::write32((u32)addr, (u32)CPU.GPR[rs]); + vm::write32(vm::cast(addr), (u32)CPU.GPR[rs]); CPU.GPR[ra] = addr; } void STB(u32 rs, u32 ra, s32 d) { const u64 addr = ra ? CPU.GPR[ra] + d : d; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - vm::write8((u32)addr, (u8)CPU.GPR[rs]); + vm::write8(vm::cast(addr), (u8)CPU.GPR[rs]); } void STBU(u32 rs, u32 ra, s32 d) { const u64 addr = CPU.GPR[ra] + d; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - vm::write8((u32)addr, (u8)CPU.GPR[rs]); + vm::write8(vm::cast(addr), (u8)CPU.GPR[rs]); CPU.GPR[ra] = addr; } void LHZ(u32 rd, u32 ra, s32 d) { const u64 addr = ra ? CPU.GPR[ra] + d : d; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - CPU.GPR[rd] = vm::read16((u32)addr); + CPU.GPR[rd] = vm::read16(vm::cast(addr)); } void LHZU(u32 rd, u32 ra, s32 d) { const u64 addr = CPU.GPR[ra] + d; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - CPU.GPR[rd] = vm::read16((u32)addr); + CPU.GPR[rd] = vm::read16(vm::cast(addr)); CPU.GPR[ra] = addr; } void LHA(u32 rd, u32 ra, s32 d) { const u64 addr = ra ? CPU.GPR[ra] + d : d; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - CPU.GPR[rd] = (s64)(s16)vm::read16((u32)addr); + CPU.GPR[rd] = (s64)(s16)vm::read16(vm::cast(addr)); } void LHAU(u32 rd, u32 ra, s32 d) { const u64 addr = CPU.GPR[ra] + d; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - CPU.GPR[rd] = (s64)(s16)vm::read16((u32)addr); + CPU.GPR[rd] = (s64)(s16)vm::read16(vm::cast(addr)); CPU.GPR[ra] = addr; } void STH(u32 rs, u32 ra, s32 d) { const u64 addr = ra ? CPU.GPR[ra] + d : d; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - vm::write16((u32)addr, (u16)CPU.GPR[rs]); + vm::write16(vm::cast(addr), (u16)CPU.GPR[rs]); } void STHU(u32 rs, u32 ra, s32 d) { const u64 addr = CPU.GPR[ra] + d; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - vm::write16((u32)addr, (u16)CPU.GPR[rs]); + vm::write16(vm::cast(addr), (u16)CPU.GPR[rs]); CPU.GPR[ra] = addr; } void LMW(u32 rd, u32 ra, s32 d) { u64 addr = ra ? CPU.GPR[ra] + d : d; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } for(u32 i=rd; i<32; ++i, addr += 4) { - CPU.GPR[i] = vm::read32((u32)addr); + CPU.GPR[i] = vm::read32(vm::cast(addr)); } } void STMW(u32 rs, u32 ra, s32 d) { u64 addr = ra ? CPU.GPR[ra] + d : d; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } for(u32 i=rs; i<32; ++i, addr += 4) { - vm::write32((u32)addr, (u32)CPU.GPR[i]); + vm::write32(vm::cast(addr), (u32)CPU.GPR[i]); } } void LFS(u32 frd, u32 ra, s32 d) { const u64 addr = ra ? CPU.GPR[ra] + d : d; - if ((u32)addr != addr) + float val = vm::get_ref>(vm::cast(addr)).value(); + if (!FPRdouble::IsNaN(val)) { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; + CPU.FPR[frd] = val; + } + else + { + u64 bits = (u32&)val; + (u64&)CPU.FPR[frd] = (bits & 0x80000000) << 32 | 7ULL << 60 | (bits & 0x7fffffff) << 29; } - const u32 v = vm::read32((u32)addr); - CPU.FPR[frd] = (float&)v; } void LFSU(u32 frd, u32 ra, s32 ds) { const u64 addr = CPU.GPR[ra] + ds; - if ((u32)addr != addr) + float val = vm::get_ref>(vm::cast(addr)).value(); + if (!FPRdouble::IsNaN(val)) { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; + CPU.FPR[frd] = val; + } + else + { + u64 bits = (u32&)val; + (u64&)CPU.FPR[frd] = (bits & 0x80000000) << 32 | 7ULL << 60 | (bits & 0x7fffffff) << 29; } - const u32 v = vm::read32((u32)addr); - CPU.FPR[frd] = (float&)v; CPU.GPR[ra] = addr; } void LFD(u32 frd, u32 ra, s32 d) { const u64 addr = ra ? CPU.GPR[ra] + d : d; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - (u64&)CPU.FPR[frd] = vm::read64((u32)addr); + CPU.FPR[frd] = vm::get_ref>(vm::cast(addr)).value(); } void LFDU(u32 frd, u32 ra, s32 ds) { const u64 addr = CPU.GPR[ra] + ds; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - (u64&)CPU.FPR[frd] = vm::read64((u32)addr); + CPU.FPR[frd] = vm::get_ref>(vm::cast(addr)).value(); CPU.GPR[ra] = addr; } void STFS(u32 frs, u32 ra, s32 d) { const u64 addr = ra ? CPU.GPR[ra] + d : d; - if ((u32)addr != addr) + double val = CPU.FPR[frs]; + if (!FPRdouble::IsNaN(val)) { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; + vm::get_ref>(vm::cast(addr)) = (float)val; + } + else + { + u64 bits = (u64&)val; + u32 bits32 = (bits>>32 & 0x80000000) | (bits>>29 & 0x7fffffff); + vm::get_ref>(vm::cast(addr)) = (float)bits32; } - vm::write32((u32)addr, CPU.FPR[frs].To32()); } void STFSU(u32 frs, u32 ra, s32 d) { const u64 addr = CPU.GPR[ra] + d; - if ((u32)addr != addr) + double val = CPU.FPR[frs]; + if (!FPRdouble::IsNaN(val)) { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; + vm::get_ref>(vm::cast(addr)) = (float)val; + } + else + { + u64 bits = (u64&)val; + u32 bits32 = (bits>>32 & 0x80000000) | (bits>>29 & 0x7fffffff); + vm::get_ref>(vm::cast(addr)) = (float)bits32; } - vm::write32((u32)addr, CPU.FPR[frs].To32()); CPU.GPR[ra] = addr; } void STFD(u32 frs, u32 ra, s32 d) { const u64 addr = ra ? CPU.GPR[ra] + d : d; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - vm::write64((u32)addr, (u64&)CPU.FPR[frs]); + vm::get_ref>(vm::cast(addr)) = CPU.FPR[frs]; } void STFDU(u32 frs, u32 ra, s32 d) { const u64 addr = CPU.GPR[ra] + d; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - vm::write64((u32)addr, (u64&)CPU.FPR[frs]); + vm::get_ref>(vm::cast(addr)) = CPU.FPR[frs]; CPU.GPR[ra] = addr; } void LD(u32 rd, u32 ra, s32 ds) { const u64 addr = ra ? CPU.GPR[ra] + ds : ds; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - CPU.GPR[rd] = vm::read64((u32)addr); + CPU.GPR[rd] = vm::read64(vm::cast(addr)); } void LDU(u32 rd, u32 ra, s32 ds) { //if(ra == 0 || rt == ra) return; const u64 addr = CPU.GPR[ra] + ds; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - CPU.GPR[rd] = vm::read64((u32)addr); + CPU.GPR[rd] = vm::read64(vm::cast(addr)); CPU.GPR[ra] = addr; } void LWA(u32 rd, u32 ra, s32 ds) { const u64 addr = ra ? CPU.GPR[ra] + ds : ds; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - CPU.GPR[rd] = (s64)(s32)vm::read32((u32)addr); + CPU.GPR[rd] = (s64)(s32)vm::read32(vm::cast(addr)); } - void FDIVS(u32 frd, u32 fra, u32 frb, bool rc) + void FDIVS(u32 frd, u32 fra, u32 frb, bool rc) {FDIV(frd, fra, frb, rc, true);} + void FSUBS(u32 frd, u32 fra, u32 frb, bool rc) {FSUB(frd, fra, frb, rc, true);} + void FADDS(u32 frd, u32 fra, u32 frb, bool rc) {FADD(frd, fra, frb, rc, true);} + void FSQRTS(u32 frd, u32 frb, bool rc) {FSQRT(frd, frb, rc, true);} + void FRES(u32 frd, u32 frb, bool rc) { - if(FPRdouble::IsNaN(CPU.FPR[fra])) + SetHostRoundingMode(CPU.FPSCR.RN); + const double b = CPU.FPR[frb]; + if(FPRdouble::IsSNaN(b)) { - CPU.FPR[frd] = CPU.FPR[fra]; + CPU.SetFPSCRException(FPSCR_VXSNAN); + CPU.FPSCR.FR = 0; + CPU.FPSCR.FI = 0; + if(CPU.FPSCR.VE) + { + if(rc) CPU.UpdateCR1(); + return; + } } - else if(FPRdouble::IsNaN(CPU.FPR[frb])) + if(FPRdouble::IsNaN(b)) { - CPU.FPR[frd] = CPU.FPR[frb]; + CPU.FPR[frd] = SilenceNaN(b); + } + else if(b == 0.0) + { + CPU.SetFPSCRException(FPSCR_ZX); + CPU.FPSCR.FR = 0; + CPU.FPSCR.FI = 0; + if (CPU.FPSCR.ZE) + { + if(rc) CPU.UpdateCR1(); + return; + } + CPU.FPR[frd] = 1.0 / b; } else { - if(CPU.FPR[frb] == 0.0) - { - if(CPU.FPR[fra] == 0.0) - { - CPU.FPSCR.VXZDZ = true; - CPU.FPR[frd] = FPR_NAN; - } - else - { - CPU.FPR[frd] = (float)(CPU.FPR[fra] / CPU.FPR[frb]); - } - - CPU.FPSCR.ZX = true; - } - else if(FPRdouble::IsINF(CPU.FPR[fra]) && FPRdouble::IsINF(CPU.FPR[frb])) - { - CPU.FPSCR.VXIDI = true; - CPU.FPR[frd] = FPR_NAN; - } - else - { - CPU.FPR[frd] = (float)(CPU.FPR[fra] / CPU.FPR[frb]); - } + feclearexcept(FE_ALL_EXCEPT); + CPU.FPR[frd] = static_cast(1.0 / b); + CheckHostFPExceptions(); } - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) UNK("fdivs.");//CPU.UpdateCR1(CPU.FPR[frd]); - } - void FSUBS(u32 frd, u32 fra, u32 frb, bool rc) - { - CPU.FPR[frd] = static_cast(CPU.FPR[fra] - CPU.FPR[frb]); - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) UNK("fsubs.");//CPU.UpdateCR1(CPU.FPR[frd]); - } - void FADDS(u32 frd, u32 fra, u32 frb, bool rc) - { - CPU.FPR[frd] = static_cast(CPU.FPR[fra] + CPU.FPR[frb]); - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) UNK("fadds.");//CPU.UpdateCR1(CPU.FPR[frd]); - } - void FSQRTS(u32 frd, u32 frb, bool rc) - { - CPU.FPR[frd] = static_cast(sqrt(CPU.FPR[frb])); - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) UNK("fsqrts.");//CPU.UpdateCR1(CPU.FPR[frd]); - } - void FRES(u32 frd, u32 frb, bool rc) - { - if(CPU.FPR[frb] == 0.0) - { - CPU.SetFPSCRException(FPSCR_ZX); - } - CPU.FPR[frd] = static_cast(1.0 / CPU.FPR[frb]); - if(rc) UNK("fres.");//CPU.UpdateCR1(CPU.FPR[frd]); - } - void FMULS(u32 frd, u32 fra, u32 frc, bool rc) - { - CPU.FPR[frd] = static_cast(CPU.FPR[fra] * CPU.FPR[frc]); - CPU.FPSCR.FI = 0; - CPU.FPSCR.FR = 0; - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) UNK("fmuls.");//CPU.UpdateCR1(CPU.FPR[frd]); - } - void FMADDS(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) - { - CPU.FPR[frd] = static_cast(CPU.FPR[fra] * CPU.FPR[frc] + CPU.FPR[frb]); - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) UNK("fmadds.");//CPU.UpdateCR1(CPU.FPR[frd]); - } - void FMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) - { - CPU.FPR[frd] = static_cast(CPU.FPR[fra] * CPU.FPR[frc] - CPU.FPR[frb]); - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) UNK("fmsubs.");//CPU.UpdateCR1(CPU.FPR[frd]); - } - void FNMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) - { - CPU.FPR[frd] = static_cast(-(CPU.FPR[fra] * CPU.FPR[frc] - CPU.FPR[frb])); - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) UNK("fnmsubs.");////CPU.UpdateCR1(CPU.FPR[frd]); - } - void FNMADDS(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) - { - CPU.FPR[frd] = static_cast(-(CPU.FPR[fra] * CPU.FPR[frc] + CPU.FPR[frb])); - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) UNK("fnmadds.");//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } + void FMULS(u32 frd, u32 fra, u32 frc, bool rc) {FMUL(frd, fra, frc, rc, true);} + void FMADDS(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) {FMADD(frd, fra, frc, frb, rc, false, false, true);} + void FMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) {FMADD(frd, fra, frc, frb, rc, false, true, true);} + void FNMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) {FMADD(frd, fra, frc, frb, rc, true, true, true);} + void FNMADDS(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) {FMADD(frd, fra, frc, frb, rc, true, false, true);} void STD(u32 rs, u32 ra, s32 d) { const u64 addr = ra ? CPU.GPR[ra] + d : d; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - vm::write64((u32)addr, CPU.GPR[rs]); + vm::write64(vm::cast(addr), CPU.GPR[rs]); } void STDU(u32 rs, u32 ra, s32 ds) { //if(ra == 0 || rs == ra) return; const u64 addr = CPU.GPR[ra] + ds; - if ((u32)addr != addr) - { - LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); - Emu.Pause(); - return; - } - vm::write64((u32)addr, CPU.GPR[rs]); + vm::write64(vm::cast(addr), CPU.GPR[rs]); CPU.GPR[ra] = addr; } void MTFSB1(u32 crbd, bool rc) { u64 mask = (1ULL << (31 - crbd)); + if ((crbd >= 3 && crbd <= 6) && !(CPU.FPSCR.FPSCR & mask)) mask |= 1ULL << 31; //FPSCR.FX if ((crbd == 29) && !CPU.FPSCR.NI) LOG_WARNING(PPU, "Non-IEEE mode enabled"); - CPU.FPSCR.FPSCR |= mask; + CPU.SetFPSCR(CPU.FPSCR.FPSCR | mask); - if(rc) UNIMPLEMENTED(); + if(rc) CPU.UpdateCR1(); } void MCRFS(u32 crbd, u32 crbs) { - CPU.SetCR(crbd, (CPU.FPSCR.FPSCR >> ((7 - crbs) * 4)) & 0xf); - - switch (crbs) - { - case 0: - CPU.FPSCR.FX = CPU.FPSCR.OX = 0; - break; - case 1: - CPU.FPSCR.UX = CPU.FPSCR.ZX = CPU.FPSCR.XX = CPU.FPSCR.VXSNAN = 0; - break; - case 2: - CPU.FPSCR.VXISI = CPU.FPSCR.VXIDI = CPU.FPSCR.VXZDZ = CPU.FPSCR.VXIMZ = 0; - break; - case 3: - CPU.FPSCR.VXVC = 0; - break; - case 5: - CPU.FPSCR.VXSOFT = CPU.FPSCR.VXSQRT = CPU.FPSCR.VXCVI = 0; - break; - default: - break; - } + CPU.SetCR(crbd, (CPU.FPSCR.FPSCR >> ((7 - crbs) * 4)) & 0xf); + const u32 exceptions_mask = 0x9FF80700; + CPU.SetFPSCR(CPU.FPSCR.FPSCR & ~(exceptions_mask & 0xf << ((7 - crbs) * 4))); } void MTFSB0(u32 crbd, bool rc) { u64 mask = (1ULL << (31 - crbd)); if ((crbd == 29) && !CPU.FPSCR.NI) LOG_WARNING(PPU, "Non-IEEE mode disabled"); - CPU.FPSCR.FPSCR &= ~mask; + CPU.SetFPSCR(CPU.FPSCR.FPSCR & ~mask); - if(rc) UNIMPLEMENTED(); + if(rc) CPU.UpdateCR1(); } void MTFSFI(u32 crfd, u32 i, bool rc) { @@ -4163,8 +3788,7 @@ private: u32 val = (i & 0xF) << ((7 - crfd) * 4); const u32 oldNI = CPU.FPSCR.NI; - CPU.FPSCR.FPSCR &= ~mask; - CPU.FPSCR.FPSCR |= val; + CPU.SetFPSCR((CPU.FPSCR.FPSCR & ~mask) | val); if (CPU.FPSCR.NI != oldNI) { if (oldNI) @@ -4173,12 +3797,12 @@ private: LOG_WARNING(PPU, "Non-IEEE mode enabled"); } - if(rc) UNIMPLEMENTED(); + if(rc) CPU.UpdateCR1(); } void MFFS(u32 frd, bool rc) { (u64&)CPU.FPR[frd] = CPU.FPSCR.FPSCR; - if(rc) UNIMPLEMENTED(); + if(rc) CPU.UpdateCR1(); } void MTFSF(u32 flm, u32 frb, bool rc) { @@ -4187,9 +3811,10 @@ private: { if(flm & (1 << i)) mask |= 0xf << (i * 4); } + mask &= ~0x60000000; const u32 oldNI = CPU.FPSCR.NI; - CPU.FPSCR.FPSCR = (CPU.FPSCR.FPSCR & ~mask) | ((u32&)CPU.FPR[frb] & mask); + CPU.SetFPSCR((CPU.FPSCR.FPSCR & ~mask) | ((u32&)CPU.FPR[frb] & mask)); if (CPU.FPSCR.NI != oldNI) { if (oldNI) @@ -4197,7 +3822,7 @@ private: else LOG_WARNING(PPU, "Non-IEEE mode enabled"); } - if(rc) UNK("mtfsf."); + if(rc) CPU.UpdateCR1(); } void FCMPU(u32 crfd, u32 fra, u32 frb) { @@ -4216,58 +3841,91 @@ private: } void FRSP(u32 frd, u32 frb, bool rc) { + SetHostRoundingMode(CPU.FPSCR.RN); const double b = CPU.FPR[frb]; + if (FPRdouble::IsSNaN(b)) + { + CPU.SetFPSCRException(FPSCR_VXSNAN); + CPU.FPSCR.FR = 0; + CPU.FPSCR.FI = 0; + if (CPU.FPSCR.VE) + { + if(rc) CPU.UpdateCR1(); + return; + } + } double b0 = b; if(CPU.FPSCR.NI) { if (((u64&)b0 & DOUBLE_EXP) < 0x3800000000000000ULL) (u64&)b0 &= DOUBLE_SIGN; } + feclearexcept(FE_ALL_EXCEPT); const double r = static_cast(b0); - CPU.FPSCR.FR = fabs(r) > fabs(b); - CPU.SetFPSCR_FI(b != r); - CPU.FPSCR.FPRF = PPCdouble(r).GetType(); + if (FPRdouble::IsNaN(r)) + { + CPU.FPSCR.FR = 0; + CPU.FPSCR.FI = 0; + } + else + { + CPU.FPSCR.FR = fabs(r) > fabs(b); + CheckHostFPExceptions(); + } + u32 type = PPCdouble(r).GetType(); + if (type == FPR_PN && r < ldexp(1.0, -126)) type = FPR_PD; + else if (type == FPR_NN && r > ldexp(-1.0, -126)) type = FPR_ND; + CPU.FPSCR.FPRF = type; CPU.FPR[frd] = r; + if(rc) CPU.UpdateCR1(); } - void FCTIW(u32 frd, u32 frb, bool rc) + void FCTIW(u32 frd, u32 frb, bool rc) {FCTIW(frd, frb, rc, false);} + void FCTIW(u32 frd, u32 frb, bool rc, bool truncate) { const double b = CPU.FPR[frb]; u32 r; - if(b > (double)0x7fffffff) + if (FPRdouble::IsNaN(b) || b < -(double)0x80000000) { - r = 0x7fffffff; CPU.SetFPSCRException(FPSCR_VXCVI); + if(FPRdouble::IsSNaN(b)) CPU.SetFPSCRException(FPSCR_VXSNAN); CPU.FPSCR.FI = 0; CPU.FPSCR.FR = 0; - } - else if (b < -(double)0x80000000) - { + if(CPU.FPSCR.VE) + { + if(rc) CPU.UpdateCR1(); + return; + } r = 0x80000000; + } + else if(b > (double)0x7fffffff) + { CPU.SetFPSCRException(FPSCR_VXCVI); CPU.FPSCR.FI = 0; CPU.FPSCR.FR = 0; + if(CPU.FPSCR.VE) + { + if(rc) CPU.UpdateCR1(); + return; + } + r = 0x7fffffff; } else { s32 i = 0; - switch(CPU.FPSCR.RN) + const u32 rn = truncate ? FPSCR_RN_ZERO : CPU.FPSCR.RN; + switch(rn) { case FPSCR_RN_NEAR: - { - double t = b + 0.5; - i = (s32)t; - if (t - i < 0 || (t - i == 0 && b > 0)) i--; - break; - } + SetHostRoundingMode(FPSCR_RN_NEAR); + i = (s32)nearbyint(b); + break; case FPSCR_RN_ZERO: i = (s32)b; break; case FPSCR_RN_PINF: - i = (s32)b; - if (b - i > 0) i++; + i = (s32)ceil(b); break; case FPSCR_RN_MINF: - i = (s32)b; - if (b - i < 0) i--; + i = (s32)floor(b); break; } r = (u32)i; @@ -4285,168 +3943,396 @@ private: } (u64&)CPU.FPR[frd] = r; - if(rc) UNK("fctiw."); + if(rc) CPU.UpdateCR1(); } - void FCTIWZ(u32 frd, u32 frb, bool rc) + void FCTIWZ(u32 frd, u32 frb, bool rc) {FCTIW(frd, frb, rc, true);} + void FDIV(u32 frd, u32 fra, u32 frb, bool rc) {FDIV(frd, fra, frb, rc, false);} + void FDIV(u32 frd, u32 fra, u32 frb, bool rc, bool single) { + SetHostRoundingMode(CPU.FPSCR.RN); + const double a = CPU.FPR[fra]; const double b = CPU.FPR[frb]; - u32 value; - if (b > (double)0x7fffffff) + if(FPRdouble::IsSNaN(a) || FPRdouble::IsSNaN(b)) { - value = 0x7fffffff; - CPU.SetFPSCRException(FPSCR_VXCVI); - CPU.FPSCR.FI = 0; + CPU.SetFPSCRException(FPSCR_VXSNAN); CPU.FPSCR.FR = 0; + CPU.FPSCR.FI = 0; + if(CPU.FPSCR.VE) + { + if(rc) CPU.UpdateCR1(); + return; + } } - else if (b < -(double)0x80000000) + if(FPRdouble::IsNaN(a)) { - value = 0x80000000; - CPU.SetFPSCRException(FPSCR_VXCVI); - CPU.FPSCR.FI = 0; + CPU.FPR[frd] = SilenceNaN(a); + } + else if(FPRdouble::IsNaN(b)) + { + CPU.FPR[frd] = SilenceNaN(b); + } + else if(a == 0.0 && b == 0.0) + { + CPU.SetFPSCRException(FPSCR_VXZDZ); CPU.FPSCR.FR = 0; + CPU.FPSCR.FI = 0; + if(CPU.FPSCR.VE) + { + if(rc) CPU.UpdateCR1(); + return; + } + CPU.FPR[frd] = FPR_NAN; + } + else if(FPRdouble::IsINF(a) && FPRdouble::IsINF(b)) + { + CPU.SetFPSCRException(FPSCR_VXIDI); + CPU.FPSCR.FR = 0; + CPU.FPSCR.FI = 0; + if(CPU.FPSCR.VE) + { + if(rc) CPU.UpdateCR1(); + return; + } + CPU.FPR[frd] = FPR_NAN; } else { - s32 i = (s32)b; - double di = i; - if (di == b) + if(b == 0.0) { - CPU.SetFPSCR_FI(0); - CPU.FPSCR.FR = 0; - } - else - { - CPU.SetFPSCR_FI(1); - CPU.FPSCR.FR = fabs(di) > fabs(b); - } - value = (u32)i; - } - - (u64&)CPU.FPR[frd] = (u64)value; - if(rc) UNK("fctiwz."); - } - void FDIV(u32 frd, u32 fra, u32 frb, bool rc) - { - double res; - - if(FPRdouble::IsNaN(CPU.FPR[fra])) - { - res = CPU.FPR[fra]; - } - else if(FPRdouble::IsNaN(CPU.FPR[frb])) - { - res = CPU.FPR[frb]; - } - else - { - if(CPU.FPR[frb] == 0.0) - { - if(CPU.FPR[fra] == 0.0) - { - CPU.FPSCR.VXZDZ = 1; - res = FPR_NAN; - } - else - { - res = CPU.FPR[fra] / CPU.FPR[frb]; - } - CPU.SetFPSCRException(FPSCR_ZX); + CPU.FPSCR.FR = 0; + CPU.FPSCR.FI = 0; + if (CPU.FPSCR.ZE) + { + if(rc) CPU.UpdateCR1(); + return; + } } - else if(FPRdouble::IsINF(CPU.FPR[fra]) && FPRdouble::IsINF(CPU.FPR[frb])) - { - CPU.FPSCR.VXIDI = 1; - res = FPR_NAN; - } - else - { - res = CPU.FPR[fra] / CPU.FPR[frb]; - } + feclearexcept(FE_ALL_EXCEPT); + const double res = a / b; + if(single) CPU.FPR[frd] = (float)res; + else CPU.FPR[frd] = res; + CheckHostFPExceptions(); } - CPU.FPR[frd] = res; CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) UNK("fdiv.");//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } - void FSUB(u32 frd, u32 fra, u32 frb, bool rc) + void FSUB(u32 frd, u32 fra, u32 frb, bool rc) {FSUB(frd, fra, frb, rc, false);} + void FSUB(u32 frd, u32 fra, u32 frb, bool rc, bool single) { - CPU.FPR[frd] = CPU.FPR[fra] - CPU.FPR[frb]; + SetHostRoundingMode(CPU.FPSCR.RN); + const double a = CPU.FPR[fra]; + const double b = CPU.FPR[frb]; + if(FPRdouble::IsSNaN(a) || FPRdouble::IsSNaN(b)) + { + CPU.SetFPSCRException(FPSCR_VXSNAN); + CPU.FPSCR.FR = 0; + CPU.FPSCR.FI = 0; + if(CPU.FPSCR.VE) + { + if(rc) CPU.UpdateCR1(); + return; + } + } + if(FPRdouble::IsNaN(a)) + { + CPU.FPR[frd] = SilenceNaN(a); + } + else if(FPRdouble::IsNaN(b)) + { + CPU.FPR[frd] = SilenceNaN(b); + } + else if(FPRdouble::IsINF(a) && FPRdouble::IsINF(b) && a == b) + { + CPU.SetFPSCRException(FPSCR_VXISI); + CPU.FPSCR.FR = 0; + CPU.FPSCR.FI = 0; + if(CPU.FPSCR.VE) + { + if(rc) CPU.UpdateCR1(); + return; + } + CPU.FPR[frd] = FPR_NAN; + } + else + { + feclearexcept(FE_ALL_EXCEPT); + const double res = a - b; + if(single) CPU.FPR[frd] = (float)res; + else CPU.FPR[frd] = res; + CheckHostFPExceptions(); + } CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) UNK("fsub.");//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } - void FADD(u32 frd, u32 fra, u32 frb, bool rc) + void FADD(u32 frd, u32 fra, u32 frb, bool rc) {FADD(frd, fra, frb, rc, false);} + void FADD(u32 frd, u32 fra, u32 frb, bool rc, bool single) { - CPU.FPR[frd] = CPU.FPR[fra] + CPU.FPR[frb]; + SetHostRoundingMode(CPU.FPSCR.RN); + const double a = CPU.FPR[fra]; + const double b = CPU.FPR[frb]; + if(FPRdouble::IsSNaN(a) || FPRdouble::IsSNaN(b)) + { + CPU.SetFPSCRException(FPSCR_VXSNAN); + CPU.FPSCR.FR = 0; + CPU.FPSCR.FI = 0; + if(CPU.FPSCR.VE) + { + if(rc) CPU.UpdateCR1(); + return; + } + } + if(FPRdouble::IsNaN(a)) + { + CPU.FPR[frd] = SilenceNaN(a); + } + else if(FPRdouble::IsNaN(b)) + { + CPU.FPR[frd] = SilenceNaN(b); + } + else if(FPRdouble::IsINF(a) && FPRdouble::IsINF(b) && a != b) + { + CPU.SetFPSCRException(FPSCR_VXISI); + CPU.FPSCR.FR = 0; + CPU.FPSCR.FI = 0; + if(CPU.FPSCR.VE) + { + if(rc) CPU.UpdateCR1(); + return; + } + CPU.FPR[frd] = FPR_NAN; + } + else + { + feclearexcept(FE_ALL_EXCEPT); + const double res = a + b; + if(single) CPU.FPR[frd] = (float)res; + else CPU.FPR[frd] = res; + CheckHostFPExceptions(); + } CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) UNK("fadd.");//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } - void FSQRT(u32 frd, u32 frb, bool rc) + void FSQRT(u32 frd, u32 frb, bool rc) {FSQRT(frd, frb, rc, false);} + void FSQRT(u32 frd, u32 frb, bool rc, bool single) { - CPU.FPR[frd] = sqrt(CPU.FPR[frb]); + SetHostRoundingMode(CPU.FPSCR.RN); + const double b = CPU.FPR[frb]; + if(FPRdouble::IsSNaN(b)) + { + CPU.SetFPSCRException(FPSCR_VXSNAN); + CPU.FPSCR.FR = 0; + CPU.FPSCR.FI = 0; + if(CPU.FPSCR.VE) + { + if(rc) CPU.UpdateCR1(); + return; + } + } + if(FPRdouble::IsNaN(b)) + { + CPU.FPR[frd] = SilenceNaN(b); + } + else if(b < 0.0) + { + CPU.SetFPSCRException(FPSCR_VXSQRT); + CPU.FPSCR.FR = 0; + CPU.FPSCR.FI = 0; + if(CPU.FPSCR.VE) + { + if(rc) CPU.UpdateCR1(); + return; + } + CPU.FPR[frd] = FPR_NAN; + } + else + { + feclearexcept(FE_ALL_EXCEPT); + const double res = sqrt(b); + if(single) CPU.FPR[frd] = (float)res; + else CPU.FPR[frd] = res; + CheckHostFPExceptions(); + } CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) UNK("fsqrt.");//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } void FSEL(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) { CPU.FPR[frd] = CPU.FPR[fra] >= 0.0 ? CPU.FPR[frc] : CPU.FPR[frb]; - if(rc) UNK("fsel.");//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } - void FMUL(u32 frd, u32 fra, u32 frc, bool rc) + void FMUL(u32 frd, u32 fra, u32 frc, bool rc) {FMUL(frd, fra, frc, rc, false);} + void FMUL(u32 frd, u32 fra, u32 frc, bool rc, bool single) { - if((FPRdouble::IsINF(CPU.FPR[fra]) && CPU.FPR[frc] == 0.0) || (FPRdouble::IsINF(CPU.FPR[frc]) && CPU.FPR[fra] == 0.0)) + SetHostRoundingMode(CPU.FPSCR.RN); + const double a = CPU.FPR[fra]; + const double c = CPU.FPR[frc]; + if(FPRdouble::IsSNaN(a) || FPRdouble::IsSNaN(c)) + { + CPU.SetFPSCRException(FPSCR_VXSNAN); + CPU.FPSCR.FR = 0; + CPU.FPSCR.FI = 0; + if(CPU.FPSCR.VE) + { + if(rc) CPU.UpdateCR1(); + return; + } + } + if(FPRdouble::IsNaN(a)) + { + CPU.FPR[frd] = SilenceNaN(a); + } + else if(FPRdouble::IsNaN(c)) + { + CPU.FPR[frd] = SilenceNaN(c); + } + else if((FPRdouble::IsINF(a) && c == 0.0) || (a == 0.0 && FPRdouble::IsINF(c))) { CPU.SetFPSCRException(FPSCR_VXIMZ); - CPU.FPR[frd] = FPR_NAN; - CPU.FPSCR.FI = 0; CPU.FPSCR.FR = 0; - CPU.FPSCR.FPRF = FPR_QNAN; + CPU.FPSCR.FI = 0; + if(CPU.FPSCR.VE) + { + if(rc) CPU.UpdateCR1(); + return; + } + CPU.FPR[frd] = FPR_NAN; } else { - if(FPRdouble::IsSNaN(CPU.FPR[fra]) || FPRdouble::IsSNaN(CPU.FPR[frc])) - { - CPU.SetFPSCRException(FPSCR_VXSNAN); - } - - CPU.FPR[frd] = CPU.FPR[fra] * CPU.FPR[frc]; - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); + feclearexcept(FE_ALL_EXCEPT); + const double res = a * c; + if(single) CPU.FPR[frd] = (float)res; + else CPU.FPR[frd] = res; + CheckHostFPExceptions(); } - - if(rc) UNK("fmul.");//CPU.UpdateCR1(CPU.FPR[frd]); + CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); + if(rc) CPU.UpdateCR1(); } void FRSQRTE(u32 frd, u32 frb, bool rc) { - if(CPU.FPR[frb] == 0.0) + SetHostRoundingMode(CPU.FPSCR.RN); + const double b = CPU.FPR[frb]; + if(FPRdouble::IsSNaN(b)) + { + CPU.SetFPSCRException(FPSCR_VXSNAN); + CPU.FPSCR.FR = 0; + CPU.FPSCR.FI = 0; + if(CPU.FPSCR.VE) + { + if(rc) CPU.UpdateCR1(); + return; + } + } + if(FPRdouble::IsNaN(b)) + { + CPU.FPR[frd] = SilenceNaN(b); + } + else if(b < 0.0) + { + CPU.SetFPSCRException(FPSCR_VXSQRT); + CPU.FPSCR.FR = 0; + CPU.FPSCR.FI = 0; + if(CPU.FPSCR.VE) + { + if(rc) CPU.UpdateCR1(); + return; + } + CPU.FPR[frd] = FPR_NAN; + } + else if(b == 0.0) { CPU.SetFPSCRException(FPSCR_ZX); + CPU.FPSCR.FR = 0; + CPU.FPSCR.FI = 0; + if (CPU.FPSCR.ZE) + { + if(rc) CPU.UpdateCR1(); + return; + } + CPU.FPR[frd] = 1.0 / b; + } + else + { + feclearexcept(FE_ALL_EXCEPT); + CPU.FPR[frd] = 1.0 / sqrt(b); + CheckHostFPExceptions(); } - CPU.FPR[frd] = 1.0 / sqrt(CPU.FPR[frb]); - if(rc) UNK("frsqrte.");//CPU.UpdateCR1(CPU.FPR[frd]); - } - void FMSUB(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) - { - CPU.FPR[frd] = CPU.FPR[fra] * CPU.FPR[frc] - CPU.FPR[frb]; CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) UNK("fmsub.");//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } - void FMADD(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) + void FMSUB(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) {FMADD(frd, fra, frc, frb, rc, false, true, false);} + void FMADD(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) {FMADD(frd, fra, frc, frb, rc, false, false, false);} + void FMADD(u32 frd, u32 fra, u32 frc, u32 frb, bool rc, bool neg, bool sub, bool single) { - CPU.FPR[frd] = CPU.FPR[fra] * CPU.FPR[frc] + CPU.FPR[frb]; + SetHostRoundingMode(CPU.FPSCR.RN); + const double a = CPU.FPR[fra]; + const double b = CPU.FPR[frb]; + const double c = CPU.FPR[frc]; + if(FPRdouble::IsSNaN(a) || FPRdouble::IsSNaN(b) || FPRdouble::IsSNaN(c)) + { + CPU.SetFPSCRException(FPSCR_VXSNAN); + CPU.FPSCR.FR = 0; + CPU.FPSCR.FI = 0; + if(CPU.FPSCR.VE) + { + if(rc) CPU.UpdateCR1(); + return; + } + } + if(FPRdouble::IsNaN(a)) + { + CPU.FPR[frd] = SilenceNaN(a); + } + else if(FPRdouble::IsNaN(b)) + { + CPU.FPR[frd] = SilenceNaN(b); + } + else if(FPRdouble::IsNaN(c)) + { + CPU.FPR[frd] = SilenceNaN(c); + } + else if((FPRdouble::IsINF(a) && c == 0.0) || (a == 0.0 && FPRdouble::IsINF(c))) + { + CPU.SetFPSCRException(FPSCR_VXIMZ); + CPU.FPSCR.FR = 0; + CPU.FPSCR.FI = 0; + if(CPU.FPSCR.VE) + { + if(rc) CPU.UpdateCR1(); + return; + } + CPU.FPR[frd] = FPR_NAN; + } + else + { + const double res = fma(a, c, sub ? -b : b); + if(FPRdouble::IsNaN(res)) + { + CPU.SetFPSCRException(FPSCR_VXISI); + CPU.FPSCR.FR = 0; + CPU.FPSCR.FI = 0; + if(CPU.FPSCR.VE) + { + if(rc) CPU.UpdateCR1(); + return; + } + CPU.FPR[frd] = FPR_NAN; + } + else + { + feclearexcept(FE_ALL_EXCEPT); + if(single) CPU.FPR[frd] = (float)(neg ? -res : res); + else CPU.FPR[frd] = (neg ? -res : res); + CheckHostFPExceptions(); + } + } CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) UNK("fmadd.");//CPU.UpdateCR1(CPU.FPR[frd]); - } - void FNMSUB(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) - { - CPU.FPR[frd] = -(CPU.FPR[fra] * CPU.FPR[frc] - CPU.FPR[frb]); - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) UNK("fnmsub.");//CPU.UpdateCR1(CPU.FPR[frd]); - } - void FNMADD(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) - { - CPU.FPR[frd] = -(CPU.FPR[fra] * CPU.FPR[frc] + CPU.FPR[frb]); - CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) UNK("fnmadd.");//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } + void FNMSUB(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) {FMADD(frd, fra, frc, frb, rc, true, true, false);} + void FNMADD(u32 frd, u32 fra, u32 frc, u32 frb, bool rc) {FMADD(frd, fra, frc, frb, rc, true, false, false);} void FCMPO(u32 crfd, u32 fra, u32 frb) { int cmp_res = FPRdouble::Cmp(CPU.FPR[fra], CPU.FPR[frb]); @@ -4472,63 +4358,71 @@ private: void FNEG(u32 frd, u32 frb, bool rc) { CPU.FPR[frd] = -CPU.FPR[frb]; - if(rc) UNK("fneg.");//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } void FMR(u32 frd, u32 frb, bool rc) { CPU.FPR[frd] = CPU.FPR[frb]; - if(rc) UNK("fmr.");//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } void FNABS(u32 frd, u32 frb, bool rc) { CPU.FPR[frd] = -fabs(CPU.FPR[frb]); - if(rc) UNK("fnabs.");//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } void FABS(u32 frd, u32 frb, bool rc) { CPU.FPR[frd] = fabs(CPU.FPR[frb]); - if(rc) UNK("fabs.");//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } - void FCTID(u32 frd, u32 frb, bool rc) + void FCTID(u32 frd, u32 frb, bool rc) {FCTID(frd, frb, rc, false);} + void FCTID(u32 frd, u32 frb, bool rc, bool truncate) { const double b = CPU.FPR[frb]; u64 r; - if(b > (double)0x7fffffffffffffff) + if (FPRdouble::IsNaN(b) || b < -(double)0x8000000000000000) { - r = 0x7fffffffffffffff; CPU.SetFPSCRException(FPSCR_VXCVI); + if(FPRdouble::IsSNaN(b)) CPU.SetFPSCRException(FPSCR_VXSNAN); CPU.FPSCR.FI = 0; CPU.FPSCR.FR = 0; - } - else if (b < -(double)0x8000000000000000) - { + if(CPU.FPSCR.VE) + { + if(rc) CPU.UpdateCR1(); + return; + } r = 0x8000000000000000; + } + else if(b >= (double)0x8000000000000000) + { CPU.SetFPSCRException(FPSCR_VXCVI); CPU.FPSCR.FI = 0; CPU.FPSCR.FR = 0; + if(CPU.FPSCR.VE) + { + if(rc) CPU.UpdateCR1(); + return; + } + r = 0x7fffffffffffffff; } else { s64 i = 0; - switch(CPU.FPSCR.RN) + const u32 rn = truncate ? FPSCR_RN_ZERO : CPU.FPSCR.RN; + switch(rn) { case FPSCR_RN_NEAR: - { - double t = b + 0.5; - i = (s64)t; - if (t - i < 0 || (t - i == 0 && b > 0)) i--; - break; - } + SetHostRoundingMode(FPSCR_RN_NEAR); + i = (s64)nearbyint(b); + break; case FPSCR_RN_ZERO: i = (s64)b; break; case FPSCR_RN_PINF: - i = (s64)b; - if (b - i > 0) i++; + i = (s64)ceil(b); break; case FPSCR_RN_MINF: - i = (s64)b; - if (b - i < 0) i--; + i = (s64)floor(b); break; } r = (u64)i; @@ -4546,46 +4440,9 @@ private: } (u64&)CPU.FPR[frd] = r; - if(rc) UNK("fctid."); - } - void FCTIDZ(u32 frd, u32 frb, bool rc) - { - const double b = CPU.FPR[frb]; - u64 r; - if(b > (double)0x7fffffffffffffff) - { - r = 0x7fffffffffffffff; - CPU.SetFPSCRException(FPSCR_VXCVI); - CPU.FPSCR.FI = 0; - CPU.FPSCR.FR = 0; - } - else if (b < -(double)0x8000000000000000) - { - r = 0x8000000000000000; - CPU.SetFPSCRException(FPSCR_VXCVI); - CPU.FPSCR.FI = 0; - CPU.FPSCR.FR = 0; - } - else - { - s64 i = (s64)b; - double di = (double)i; - if (di == b) - { - CPU.SetFPSCR_FI(0); - CPU.FPSCR.FR = 0; - } - else - { - CPU.SetFPSCR_FI(1); - CPU.FPSCR.FR = fabs(di) > fabs(b); - } - r = (u64)i; - } - - (u64&)CPU.FPR[frd] = r; - if(rc) UNK("fctidz."); + if(rc) CPU.UpdateCR1(); } + void FCTIDZ(u32 frd, u32 frb, bool rc) {FCTID(frd, frb, rc, true);} void FCFID(u32 frd, u32 frb, bool rc) { s64 bi = (s64&)CPU.FPR[frb]; @@ -4606,41 +4463,11 @@ private: CPU.FPR[frd] = bf; CPU.FPSCR.FPRF = CPU.FPR[frd].GetType(); - if(rc) UNK("fcfid.");//CPU.UpdateCR1(CPU.FPR[frd]); + if(rc) CPU.UpdateCR1(); } void UNK(const u32 code, const u32 opcode, const u32 gcode) { - UNK(fmt::Format("Unknown/Illegal opcode! (0x%08x : 0x%x : 0x%x)", code, opcode, gcode)); - } - - void UNK(const std::string& err, bool pause = true) - { - LOG_ERROR(PPU, "%s #pc: 0x%x", err.c_str(), CPU.PC); - - if(!pause) return; - - Emu.Pause(); - - for(uint i=0; i<32; ++i) LOG_NOTICE(PPU, "r%d = 0x%llx", i, CPU.GPR[i]); - for(uint i=0; i<32; ++i) LOG_NOTICE(PPU, "f%d = %llf", i, CPU.FPR[i]); - for(uint i=0; i<32; ++i) LOG_NOTICE(PPU, "v%d = 0x%s [%s]", i, CPU.VPR[i].to_hex().c_str(), CPU.VPR[i].to_xyzw().c_str()); - LOG_NOTICE(PPU, "CR = 0x%08x", CPU.CR.CR); - LOG_NOTICE(PPU, "LR = 0x%llx", CPU.LR); - LOG_NOTICE(PPU, "CTR = 0x%llx", CPU.CTR); - LOG_NOTICE(PPU, "XER = 0x%llx [CA=%lld | OV=%lld | SO=%lld]", CPU.XER.XER, fmt::by_value(CPU.XER.CA), fmt::by_value(CPU.XER.OV), fmt::by_value(CPU.XER.SO)); - LOG_NOTICE(PPU, "FPSCR = 0x%x " - "[RN=%d | NI=%d | XE=%d | ZE=%d | UE=%d | OE=%d | VE=%d | " - "VXCVI=%d | VXSQRT=%d | VXSOFT=%d | FPRF=%d | " - "FI=%d | FR=%d | VXVC=%d | VXIMZ=%d | " - "VXZDZ=%d | VXIDI=%d | VXISI=%d | VXSNAN=%d | " - "XX=%d | ZX=%d | UX=%d | OX=%d | VX=%d | FEX=%d | FX=%d]", - CPU.FPSCR.FPSCR, - fmt::by_value(CPU.FPSCR.RN), - fmt::by_value(CPU.FPSCR.NI), fmt::by_value(CPU.FPSCR.XE), fmt::by_value(CPU.FPSCR.ZE), fmt::by_value(CPU.FPSCR.UE), fmt::by_value(CPU.FPSCR.OE), fmt::by_value(CPU.FPSCR.VE), - fmt::by_value(CPU.FPSCR.VXCVI), fmt::by_value(CPU.FPSCR.VXSQRT), fmt::by_value(CPU.FPSCR.VXSOFT), fmt::by_value(CPU.FPSCR.FPRF), - fmt::by_value(CPU.FPSCR.FI), fmt::by_value(CPU.FPSCR.FR), fmt::by_value(CPU.FPSCR.VXVC), fmt::by_value(CPU.FPSCR.VXIMZ), - fmt::by_value(CPU.FPSCR.VXZDZ), fmt::by_value(CPU.FPSCR.VXIDI), fmt::by_value(CPU.FPSCR.VXISI), fmt::by_value(CPU.FPSCR.VXSNAN), - fmt::by_value(CPU.FPSCR.XX), fmt::by_value(CPU.FPSCR.ZX), fmt::by_value(CPU.FPSCR.UX), fmt::by_value(CPU.FPSCR.OX), fmt::by_value(CPU.FPSCR.VX), fmt::by_value(CPU.FPSCR.FEX), fmt::by_value(CPU.FPSCR.FX)); + throw fmt::Format("Unknown/Illegal opcode! (0x%08x : 0x%x : 0x%x)", code, opcode, gcode); } }; diff --git a/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp b/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp index 1451a80c27..c14d0a4131 100644 --- a/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp +++ b/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp @@ -3311,7 +3311,7 @@ void Compiler::MFSPR(u32 rd, u32 spr) { rd_i64 = GetCtr(); break; case 0x100: - rd_i64 = GetUsprg0(); + rd_i64 = GetVrsave(); break; case 0x10C: rd_i64 = Call("get_time", get_time); @@ -3503,7 +3503,7 @@ void Compiler::MTSPR(u32 spr, u32 rs) { SetCtr(rs_i64); break; case 0x100: - SetUsprg0(rs_i64); + SetVrsave(rs_i64); break; default: assert(0); @@ -3746,6 +3746,16 @@ void Compiler::STVLX(u32 vs, u32 ra, u32 rb) { addr_i8_ptr, vs_i8_ptr, size_i64, m_ir_builder->getInt32(1), m_ir_builder->getInt1(false)); } +void Compiler::STDBRX(u32 rs, u32 ra, u32 rb) { + auto addr_i64 = GetGpr(rb); + if (ra) { + auto ra_i64 = GetGpr(ra); + addr_i64 = m_ir_builder->CreateAdd(ra_i64, addr_i64); + } + + WriteMemory(addr_i64, GetGpr(rs), 0, false); +} + void Compiler::STSWX(u32 rs, u32 ra, u32 rb) { CompilationError("STSWX"); } @@ -5268,17 +5278,19 @@ void Compiler::SetXerSo(Value * so) { SetXer(xer_i64); } -Value * Compiler::GetUsprg0() { - auto usrpg0_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, USPRG)); - auto usprg0_i64_ptr = m_ir_builder->CreateBitCast(usrpg0_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); - return m_ir_builder->CreateAlignedLoad(usprg0_i64_ptr, 8); +Value * Compiler::GetVrsave() { + auto vrsave_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, VRSAVE)); + auto vrsave_i32_ptr = m_ir_builder->CreateBitCast(vrsave_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo()); + auto val_i32 = m_ir_builder->CreateAlignedLoad(vrsave_i32_ptr, 4); + return m_ir_builder->CreateZExtOrTrunc(val_i32, m_ir_builder->getInt64Ty()); } -void Compiler::SetUsprg0(Value * val_x64) { +void Compiler::SetVrsave(Value * val_x64) { auto val_i64 = m_ir_builder->CreateBitCast(val_x64, m_ir_builder->getInt64Ty()); - auto usprg0_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, USPRG)); - auto usprg0_i64_ptr = m_ir_builder->CreateBitCast(usprg0_i8_ptr, m_ir_builder->getInt64Ty()->getPointerTo()); - m_ir_builder->CreateAlignedStore(val_i64, usprg0_i64_ptr, 8); + auto val_i32 = m_ir_builder->CreateZExtOrTrunc(val_i64, m_ir_builder->getInt32Ty()); + auto vrsave_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, VRSAVE)); + auto vrsave_i32_ptr = m_ir_builder->CreateBitCast(vrsave_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo()); + m_ir_builder->CreateAlignedStore(val_i32, vrsave_i32_ptr, 8); } Value * Compiler::GetFpscr() { diff --git a/rpcs3/Emu/Cell/PPULLVMRecompiler.h b/rpcs3/Emu/Cell/PPULLVMRecompiler.h index 1d656cc4a1..715e9f08ab 100644 --- a/rpcs3/Emu/Cell/PPULLVMRecompiler.h +++ b/rpcs3/Emu/Cell/PPULLVMRecompiler.h @@ -598,6 +598,7 @@ namespace ppu_recompiler_llvm { void LFDX(u32 frd, u32 ra, u32 rb) override; void LFDUX(u32 frd, u32 ra, u32 rb) override; void STVLX(u32 vs, u32 ra, u32 rb) override; + void STDBRX(u32 rd, u32 ra, u32 rb) override; void STSWX(u32 rs, u32 ra, u32 rb) override; void STWBRX(u32 rs, u32 ra, u32 rb) override; void STFSX(u32 frs, u32 ra, u32 rb) override; @@ -859,11 +860,11 @@ namespace ppu_recompiler_llvm { /// Set the SO bit of XER void SetXerSo(llvm::Value * so); - /// Get USPRG0 - llvm::Value * GetUsprg0(); + /// Get VRSAVE + llvm::Value * GetVrsave(); - /// Set USPRG0 - void SetUsprg0(llvm::Value * val_x64); + /// Set VRSAVE + void SetVrsave(llvm::Value * val_x64); /// Load FPSCR llvm::Value * GetFpscr(); diff --git a/rpcs3/Emu/Cell/PPUOpcodes.h b/rpcs3/Emu/Cell/PPUOpcodes.h index 39b9e08aa9..aee76ba295 100644 --- a/rpcs3/Emu/Cell/PPUOpcodes.h +++ b/rpcs3/Emu/Cell/PPUOpcodes.h @@ -344,6 +344,8 @@ namespace PPU_opcodes DIVD = 0x1e9, DIVW = 0x1eb, LVLX = 0x207, //Load Vector Left Indexed + SUBFCO = 0x208, + ADDCO = 0x20a, LDBRX = 0x214, LSWX = 0x215, LWBRX = 0x216, @@ -351,21 +353,33 @@ namespace PPU_opcodes SRW = 0x218, SRD = 0x21b, LVRX = 0x227, //Load Vector Right Indexed + SUBFO = 0x228, LFSUX = 0x237, LSWI = 0x255, SYNC = 0x256, LFDX = 0x257, + NEGO = 0x268, LFDUX = 0x277, STVLX = 0x287, //Store Vector Left Indexed + SUBFEO = 0x288, + ADDEO = 0x28a, + STDBRX = 0x294, STSWX = 0x295, STWBRX = 0x296, STFSX = 0x297, STVRX = 0x2a7, //Store Vector Right Indexed STFSUX = 0x2b7, + SUBFZEO= 0x2c8, + ADDZEO = 0x2ca, STSWI = 0x2d5, STFDX = 0x2d7, //Store Floating-Point Double Indexed + SUBFMEO= 0x2e8, + MULLDO = 0x2e9, + ADDMEO = 0x2ea, + MULLWO = 0x2eb, STFDUX = 0x2f7, LVLXL = 0x307, //Load Vector Left Indexed Last + ADDO = 0x30a, LHBRX = 0x316, SRAW = 0x318, SRAD = 0x31a, @@ -380,9 +394,13 @@ namespace PPU_opcodes EXTSH = 0x39a, STVRXL = 0x3a7, //Store Vector Right Indexed Last EXTSB = 0x3ba, + DIVDUO = 0x3c9, + DIVWUO = 0x3cb, STFIWX = 0x3d7, EXTSW = 0x3da, ICBI = 0x3d6, //Instruction Cache Block Invalidate + DIVDO = 0x3e9, + DIVWO = 0x3eb, DCBZ = 0x3f6, //Data Cache Block Set to Zero }; @@ -759,6 +777,7 @@ public: virtual void LFDX(u32 frd, u32 ra, u32 rb) = 0; virtual void LFDUX(u32 frd, u32 ra, u32 rb) = 0; virtual void STVLX(u32 vs, u32 ra, u32 rb) = 0; + virtual void STDBRX(u32 rs, u32 ra, u32 rb) = 0; virtual void STSWX(u32 rs, u32 ra, u32 rb) = 0; virtual void STWBRX(u32 rs, u32 ra, u32 rb) = 0; virtual void STFSX(u32 frs, u32 ra, u32 rb) = 0; diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 0364198974..9e5588276a 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -13,6 +13,8 @@ //#include "Emu/Cell/PPURecompiler.h" #include "Emu/CPU/CPUThreadManager.h" +u64 rotate_mask[64][64]; + PPUThread& GetCurrentPPUThread() { PPCThread* thread = GetCurrentPPCThread(); @@ -41,7 +43,6 @@ void PPUThread::DoReset() memset(FPR, 0, sizeof(FPR)); memset(GPR, 0, sizeof(GPR)); memset(SPRG, 0, sizeof(SPRG)); - memset(USPRG, 0, sizeof(USPRG)); CR.CR = 0; LR = 0; @@ -50,6 +51,7 @@ void PPUThread::DoReset() XER.XER = 0; FPSCR.FPSCR = 0; VSCR.VSCR = 0; + VRSAVE = 0; cycle = 0; } @@ -187,7 +189,7 @@ int FPRdouble::Cmp(PPCdouble a, PPCdouble b) u64 PPUThread::GetStackArg(s32 i) { - return vm::read64(GPR[1] + 0x70 + 0x8 * (i - 9)); + return vm::read64(vm::cast(GPR[1] + 0x70 + 0x8 * (i - 9))); } u64 PPUThread::FastCall2(u32 addr, u32 rtoc) diff --git a/rpcs3/Emu/Cell/PPUThread.h b/rpcs3/Emu/Cell/PPUThread.h index 717dd151f1..2c5c13246d 100644 --- a/rpcs3/Emu/Cell/PPUThread.h +++ b/rpcs3/Emu/Cell/PPUThread.h @@ -1,4 +1,5 @@ #pragma once +#include "Emu/Cell/Common.h" #include "Emu/Cell/PPCThread.h" #include "Emu/Memory/vm.h" @@ -53,14 +54,8 @@ enum FPSCR_EXP FPSCR_VXSOFT = 0x00000400, FPSCR_VXSQRT = 0x00000200, FPSCR_VXCVI = 0x00000100, -}; -enum FPSCR_RN -{ - FPSCR_RN_NEAR = 0, - FPSCR_RN_ZERO = 1, - FPSCR_RN_PINF = 2, - FPSCR_RN_MINF = 3, + FPSCR_VX_ALL = FPSCR_VXSNAN | FPSCR_VXISI | FPSCR_VXIDI | FPSCR_VXZDZ | FPSCR_VXIMZ | FPSCR_VXVC | FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI, }; static const u64 DOUBLE_SIGN = 0x8000000000000000ULL; @@ -441,18 +436,22 @@ struct PPCdouble PPCdouble() : _u64(0) { + type = UpdateType(); } PPCdouble(double val) : _double(val) { + type = UpdateType(); } PPCdouble(u64 val) : _u64(val) { + type = UpdateType(); } PPCdouble(u32 val) : _u64(val) { + type = UpdateType(); } }; @@ -531,20 +530,12 @@ public: u64 LR; //SPR 0x008 : Link Register u64 CTR; //SPR 0x009 : Count Register - u64 USPRG[8]; //SPR 0x100 - 0x107: User-SPR General-Purpose Registers + u32 VRSAVE; //SPR 0x100: VR Save/Restore Register (32 bits) + u64 SPRG[8]; //SPR 0x110 - 0x117 : SPR General-Purpose Registers //TBR : Time-Base Registers - union - { - u64 TB; //TBR 0x10C - 0x10D - - struct - { - u32 TBH; - u32 TBL; - }; - }; + u64 TB; //TBR 0x10C - 0x10D u64 cycle; @@ -652,7 +643,7 @@ public: UpdateCRn(0, val, 0); } - template void UpdateCR1() + void UpdateCR1() { SetCR_LT(1, FPSCR.FX); SetCR_GT(1, FPSCR.FEX); @@ -670,10 +661,37 @@ public: bool IsCarry(const u64 a, const u64 b) { return (a + b) < a; } bool IsCarry(const u64 a, const u64 b, const u64 c) { return IsCarry(a, b) || IsCarry(a + b, c); } + void SetOV(const bool set) + { + XER.OV = set; + XER.SO |= set; + } + + void UpdateFPSCR_FEX() + { + const u32 exceptions = (FPSCR.FPSCR >> 25) & 0x1F; + const u32 enabled = (FPSCR.FPSCR >> 3) & 0x1F; + if (exceptions & enabled) FPSCR.FEX = 1; + } + + void UpdateFPSCR_VX() + { + if (FPSCR.FPSCR & FPSCR_VX_ALL) FPSCR.VX = 1; + } + + void SetFPSCR(const u32 val) + { + FPSCR.FPSCR = val & ~(FPSCR_FEX | FPSCR_VX); + UpdateFPSCR_VX(); + UpdateFPSCR_FEX(); + } + void SetFPSCRException(const FPSCR_EXP mask) { if ((FPSCR.FPSCR & mask) != mask) FPSCR.FX = 1; FPSCR.FPSCR |= mask; + UpdateFPSCR_VX(); + UpdateFPSCR_FEX(); } void SetFPSCR_FI(const u32 val) @@ -811,4 +829,160 @@ public: cpu_thread& args(std::initializer_list values) override; cpu_thread& run() override; ppu_thread& gpr(uint index, u64 value); -}; \ No newline at end of file +}; + +template::value> +struct cast_ppu_gpr +{ + static_assert(is_enum, "Invalid type for cast_ppu_gpr"); + + typedef typename std::underlying_type::type underlying_type; + + __forceinline static u64 to_gpr(const T& value) + { + return cast_ppu_gpr::to_gpr(static_cast(value)); + } + + __forceinline static T from_gpr(const u64 reg) + { + return static_cast(cast_ppu_gpr::from_gpr(reg)); + } +}; + +template<> +struct cast_ppu_gpr +{ + __forceinline static u64 to_gpr(const u8& value) + { + return value; + } + + __forceinline static u8 from_gpr(const u64 reg) + { + return static_cast(reg); + } +}; + +template<> +struct cast_ppu_gpr +{ + __forceinline static u64 to_gpr(const u16& value) + { + return value; + } + + __forceinline static u16 from_gpr(const u64 reg) + { + return static_cast(reg); + } +}; + +template<> +struct cast_ppu_gpr +{ + __forceinline static u64 to_gpr(const u32& value) + { + return value; + } + + __forceinline static u32 from_gpr(const u64 reg) + { + return static_cast(reg); + } +}; + +template<> +struct cast_ppu_gpr +{ + __forceinline static u64 to_gpr(const u64& value) + { + return value; + } + + __forceinline static u64 from_gpr(const u64 reg) + { + return reg; + } +}; + +template<> +struct cast_ppu_gpr +{ + __forceinline static u64 to_gpr(const s8& value) + { + return value; + } + + __forceinline static s8 from_gpr(const u64 reg) + { + return static_cast(reg); + } +}; + +template<> +struct cast_ppu_gpr +{ + __forceinline static u64 to_gpr(const s16& value) + { + return value; + } + + __forceinline static s16 from_gpr(const u64 reg) + { + return static_cast(reg); + } +}; + +template<> +struct cast_ppu_gpr +{ + __forceinline static u64 to_gpr(const s32& value) + { + return value; + } + + __forceinline static s32 from_gpr(const u64 reg) + { + return static_cast(reg); + } +}; + +template<> +struct cast_ppu_gpr +{ + __forceinline static u64 to_gpr(const s64& value) + { + return value; + } + + __forceinline static s64 from_gpr(const u64 reg) + { + return static_cast(reg); + } +}; + +template<> +struct cast_ppu_gpr +{ + __forceinline static u64 to_gpr(const bool& value) + { + return value; + } + + __forceinline static bool from_gpr(const u64 reg) + { + return reinterpret_cast(reg); + } +}; + +template +__forceinline u64 cast_to_ppu_gpr(const T& value) +{ + return cast_ppu_gpr::to_gpr(value); +} + +template +__forceinline T cast_from_ppu_gpr(const u64 reg) +{ + return cast_ppu_gpr::from_gpr(reg); +} diff --git a/rpcs3/Emu/Cell/RawSPUThread.cpp b/rpcs3/Emu/Cell/RawSPUThread.cpp index 92e0425628..ba4c98f363 100644 --- a/rpcs3/Emu/Cell/RawSPUThread.cpp +++ b/rpcs3/Emu/Cell/RawSPUThread.cpp @@ -1,6 +1,8 @@ #include "stdafx.h" #include "Utilities/Log.h" #include "Emu/Memory/Memory.h" +#include "Emu/System.h" +#include "Emu/SysCalls/Callback.h" #include "Emu/Cell/RawSPUThread.h" @@ -137,8 +139,14 @@ bool RawSPUThread::Write32(const u64 addr, const u32 value) { if (value == SPU_RUNCNTL_RUNNABLE) { - SPU.Status.SetValue(SPU_STATUS_RUNNING); - Exec(); + // calling Exec() directly in SIGSEGV handler may cause problems + // (probably because Exec() creates new thread, faults of this thread aren't handled by this handler anymore) + Emu.GetCallbackManager().Async([this](PPUThread& PPU) + { + SPU.Status.SetValue(SPU_STATUS_RUNNING); + Exec(); + }); + } else if (value == SPU_RUNCNTL_STOP) { diff --git a/rpcs3/Emu/Cell/SPUInterpreter.h b/rpcs3/Emu/Cell/SPUInterpreter.h index 4d8125575f..151eb4e436 100644 --- a/rpcs3/Emu/Cell/SPUInterpreter.h +++ b/rpcs3/Emu/Cell/SPUInterpreter.h @@ -1,5 +1,26 @@ #pragma once +#include + +static void SetHostRoundingMode(u32 rn) +{ + switch (rn) + { + case FPSCR_RN_NEAR: + fesetround(FE_TONEAREST); + break; + case FPSCR_RN_ZERO: + fesetround(FE_TOWARDZERO); + break; + case FPSCR_RN_PINF: + fesetround(FE_UPWARD); + break; + case FPSCR_RN_MINF: + fesetround(FE_DOWNWARD); + break; + } +} + #define UNIMPLEMENTED() UNK(__FUNCTION__) #define MEM_AND_REG_HASH() \ @@ -11,6 +32,54 @@ #define LOG5_OPCODE(...) /// +// Floating-point utility constants and functions +static const u32 FLOAT_MAX_NORMAL_I = 0x7F7FFFFF; +static const float& FLOAT_MAX_NORMAL = (float&)FLOAT_MAX_NORMAL_I; +static const u32 FLOAT_NAN_I = 0x7FC00000; +static const float& FLOAT_NAN = (float&)FLOAT_NAN_I; +static const u64 DOUBLE_NAN_I = 0x7FF8000000000000ULL; +static const double& DOUBLE_NAN = (double&)DOUBLE_NAN_I; +static inline bool issnan(double x) {return isnan(x) && ((s64&)x)<<12 > 0;} +static inline bool issnan(float x) {return isnan(x) && ((s32&)x)<<9 > 0;} +static inline int fexpf(float x) {return ((u32&)x >> 23) & 0xFF;} +static inline bool isextended(float x) {return fexpf(x) == 255;} +static inline float extended(bool sign, u32 mantissa) // returns -1^sign * 2^127 * (1.mantissa) +{ + u32 bits = sign<<31 | 0x7F800000 | mantissa; + return (float&)bits; +} +static inline float ldexpf_extended(float x, int exp) // ldexpf() for extended values, assumes result is in range +{ + u32 bits = (u32&)x; + if (bits << 1 != 0) bits += exp * 0x00800000; + return (float&)bits; +} +static inline bool isdenormal(float x) +{ + const int fpc = _fpclass(x); +#ifdef __GNUG__ + return fpc == FP_SUBNORMAL; +#else + return (fpc & (_FPCLASS_PD | _FPCLASS_ND)) != 0; +#endif +} +static inline bool isdenormal(double x) +{ + const int fpc = _fpclass(x); +#ifdef __GNUG__ + return fpc == FP_SUBNORMAL; +#else + return (fpc & (_FPCLASS_PD | _FPCLASS_ND)) != 0; +#endif +} +static double SilenceNaN(double x) +{ + u64 bits = (u64&)x; + bits |= 0x0008000000000000ULL; + return (double&)bits; +} + + class SPUInterpreter : public SPUOpcodes { private: @@ -47,7 +116,7 @@ private: } void MFSPR(u32 rt, u32 sa) { - UNIMPLEMENTED(); // not used + CPU.GPR[rt].clear(); // All SPRs read as zero. } void RDCH(u32 rt, u32 ra) { @@ -243,7 +312,7 @@ private: } void MTSPR(u32 rt, u32 sa) { - UNIMPLEMENTED(); // not used + // SPR writes are ignored. } void WRCH(u32 ra, u32 rt) { @@ -431,16 +500,41 @@ private: } void FREST(u32 rt, u32 ra) { - //CPU.GPR[rt]._m128 = _mm_rcp_ps(CPU.GPR[ra]._m128); + SetHostRoundingMode(FPSCR_RN_ZERO); for (int i = 0; i < 4; i++) - CPU.GPR[rt]._f[i] = 1 / CPU.GPR[ra]._f[i]; + { + const float a = CPU.GPR[ra]._f[i]; + float result; + if (fexpf(a) == 0) + { + CPU.FPSCR.setDivideByZeroFlag(i); + result = extended(std::signbit(a), 0x7FFFFF); + } + else if (isextended(a)) + result = 0.0f; + else + result = 1 / a; + CPU.GPR[rt]._f[i] = result; + } } void FRSQEST(u32 rt, u32 ra) { - //const __u32x4 FloatAbsMask = {0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff}; - //CPU.GPR[rt]._m128 = _mm_rsqrt_ps(_mm_and_ps(CPU.GPR[ra]._m128, FloatAbsMask.m128)); + SetHostRoundingMode(FPSCR_RN_ZERO); for (int i = 0; i < 4; i++) - CPU.GPR[rt]._f[i] = 1 / sqrt(abs(CPU.GPR[ra]._f[i])); + { + const float a = CPU.GPR[ra]._f[i]; + float result; + if (fexpf(a) == 0) + { + CPU.FPSCR.setDivideByZeroFlag(i); + result = extended(0, 0x7FFFFF); + } + else if (isextended(a)) + result = 0.5f / sqrtf(fabsf(ldexpf_extended(a, -2))); + else + result = 1 / sqrtf(fabsf(a)); + CPU.GPR[rt]._f[i] = result; + } } void LQX(u32 rt, u32 ra, u32 rb) { @@ -828,37 +922,186 @@ private: } void FCGT(u32 rt, u32 ra, u32 rb) { - CPU.GPR[rt]._u32[0] = CPU.GPR[ra]._f[0] > CPU.GPR[rb]._f[0] ? 0xffffffff : 0; - CPU.GPR[rt]._u32[1] = CPU.GPR[ra]._f[1] > CPU.GPR[rb]._f[1] ? 0xffffffff : 0; - CPU.GPR[rt]._u32[2] = CPU.GPR[ra]._f[2] > CPU.GPR[rb]._f[2] ? 0xffffffff : 0; - CPU.GPR[rt]._u32[3] = CPU.GPR[ra]._f[3] > CPU.GPR[rb]._f[3] ? 0xffffffff : 0; + for (int i = 0; i < 4; i++) + { + const u32 a = CPU.GPR[ra]._u32[i]; + const u32 b = CPU.GPR[rb]._u32[i]; + const u32 abs_a = a & 0x7FFFFFFF; + const u32 abs_b = b & 0x7FFFFFFF; + const bool a_zero = (abs_a < 0x00800000); + const bool b_zero = (abs_b < 0x00800000); + bool pass; + if (a_zero) + pass = b >= 0x80800000; + else if (b_zero) + pass = (s32)a >= 0x00800000; + else if (a >= 0x80000000) + pass = (b >= 0x80000000 && a < b); + else + pass = (b >= 0x80000000 || a > b); + CPU.GPR[rt]._u32[i] = pass ? 0xFFFFFFFF : 0; + } } void DFCGT(u32 rt, u32 ra, u32 rb) { UNIMPLEMENTED(); // cannot be used } - void FA(u32 rt, u32 ra, u32 rb) + void FA_FS(u32 rt, u32 ra, u32 rb, bool sub) { + SetHostRoundingMode(FPSCR_RN_ZERO); for (int w = 0; w < 4; w++) { - CPU.GPR[rt]._f[w] = CPU.GPR[ra]._f[w] + CPU.GPR[rb]._f[w]; - //if (CPU.GPR[rt]._f[w] == -0.0f) CPU.GPR[rt]._f[w] = 0.0f; - } - } - void FS(u32 rt, u32 ra, u32 rb) - { - for (int w = 0; w < 4; w++) - { - CPU.GPR[rt]._f[w] = CPU.GPR[ra]._f[w] - CPU.GPR[rb]._f[w]; - //if (CPU.GPR[rt]._f[w] == -0.0f) CPU.GPR[rt]._f[w] = 0.0f; + const float a = CPU.GPR[ra]._f[w]; + const float b = sub ? -CPU.GPR[rb]._f[w] : CPU.GPR[rb]._f[w]; + float result; + if (isdenormal(a)) + { + CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SDIFF); + if (b == 0.0f || isdenormal(b)) + result = +0.0f; + else + result = b; + } + else if (isdenormal(b)) + { + CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SDIFF); + if (a == 0.0f) + result = +0.0f; + else + result = a; + } + else if (isextended(a) || isextended(b)) + { + CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SDIFF); + if (isextended(a) && fexpf(b) < 255-32) + { + if (std::signbit(a) != std::signbit(b)) + { + const u32 bits = (u32&)a - 1; + result = (float&)bits; + } + else + + result = a; + } + else if (isextended(b) && fexpf(a) < 255-32) + { + if (std::signbit(a) != std::signbit(b)) + { + const u32 bits = (u32&)b - 1; + result = (float&)bits; + } + else + result = b; + } + else + { + feclearexcept(FE_ALL_EXCEPT); + result = ldexpf_extended(a, -1) + ldexpf_extended(b, -1); + result = ldexpf_extended(result, 1); + if (fetestexcept(FE_OVERFLOW)) + { + CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SOVF); + result = extended(std::signbit(result), 0x7FFFFF); + } + } + } + else + { + result = a + b; + if (result == copysignf(FLOAT_MAX_NORMAL, result)) + { + result = ldexpf_extended(ldexpf(a,-1) + ldexpf(b,-1), 1); + if (isextended(result)) + CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SDIFF); + } + else if (isdenormal(result)) + { + CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SUNF | FPSCR_SDIFF); + result = +0.0f; + } + else if (result == 0.0f) + { + if (fabsf(a) != fabsf(b)) + CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SUNF | FPSCR_SDIFF); + result = +0.0f; + } + } + CPU.GPR[rt]._f[w] = result; } } + void FA(u32 rt, u32 ra, u32 rb) {FA_FS(rt, ra, rb, false);} + void FS(u32 rt, u32 ra, u32 rb) {FA_FS(rt, ra, rb, true);} void FM(u32 rt, u32 ra, u32 rb) { + SetHostRoundingMode(FPSCR_RN_ZERO); for (int w = 0; w < 4; w++) { - CPU.GPR[rt]._f[w] = CPU.GPR[ra]._f[w] * CPU.GPR[rb]._f[w]; - //if (CPU.GPR[rt]._f[w] == -0.0f) CPU.GPR[rt]._f[w] = 0.0f; + const float a = CPU.GPR[ra]._f[w]; + const float b = CPU.GPR[rb]._f[w]; + float result; + if (isdenormal(a) || isdenormal(b)) + { + CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SDIFF); + result = +0.0f; + } + else if (isextended(a) || isextended(b)) + { + CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SDIFF); + const bool sign = std::signbit(a) ^ std::signbit(b); + if (a == 0.0f || b == 0.0f) + { + result = +0.0f; + } + else if ((fexpf(a)-127) + (fexpf(b)-127) >= 129) + { + CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SOVF); + result = extended(sign, 0x7FFFFF); + } + else + { + if (isextended(a)) + result = ldexpf_extended(a, -1) * b; + else + result = a * ldexpf_extended(b, -1); + if (result == copysignf(FLOAT_MAX_NORMAL, result)) + { + CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SOVF); + result = extended(sign, 0x7FFFFF); + } + else + result = ldexpf_extended(result, 1); + } + } + else + { + result = a * b; + if (result == copysignf(FLOAT_MAX_NORMAL, result)) + { + feclearexcept(FE_ALL_EXCEPT); + if (fexpf(a) > fexpf(b)) + result = ldexpf(a, -1) * b; + else + result = a * ldexpf(b, -1); + result = ldexpf_extended(result, 1); + if (isextended(result)) + CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SDIFF); + if (fetestexcept(FE_OVERFLOW)) + CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SOVF); + } + else if (isdenormal(result)) + { + CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SUNF | FPSCR_SDIFF); + result = +0.0f; + } + else if (result == 0.0f) + { + if (a != 0.0f & b != 0.0f) + CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SUNF | FPSCR_SDIFF); + result = +0.0f; + } + } + CPU.GPR[rt]._f[w] = result; } } void CLGTH(u32 rt, u32 ra, u32 rb) @@ -873,30 +1116,84 @@ private: } void FCMGT(u32 rt, u32 ra, u32 rb) { - CPU.GPR[rt]._u32[0] = fabs(CPU.GPR[ra]._f[0]) > fabs(CPU.GPR[rb]._f[0]) ? 0xffffffff : 0; - CPU.GPR[rt]._u32[1] = fabs(CPU.GPR[ra]._f[1]) > fabs(CPU.GPR[rb]._f[1]) ? 0xffffffff : 0; - CPU.GPR[rt]._u32[2] = fabs(CPU.GPR[ra]._f[2]) > fabs(CPU.GPR[rb]._f[2]) ? 0xffffffff : 0; - CPU.GPR[rt]._u32[3] = fabs(CPU.GPR[ra]._f[3]) > fabs(CPU.GPR[rb]._f[3]) ? 0xffffffff : 0; + for (int i = 0; i < 4; i++) + { + const u32 a = CPU.GPR[ra]._u32[i]; + const u32 b = CPU.GPR[rb]._u32[i]; + const u32 abs_a = a & 0x7FFFFFFF; + const u32 abs_b = b & 0x7FFFFFFF; + const bool a_zero = (abs_a < 0x00800000); + const bool b_zero = (abs_b < 0x00800000); + bool pass; + if (a_zero) + pass = false; + else if (b_zero) + pass = !a_zero; + else + pass = abs_a > abs_b; + CPU.GPR[rt]._u32[i] = pass ? 0xFFFFFFFF : 0; + } } void DFCMGT(u32 rt, u32 ra, u32 rb) { UNIMPLEMENTED(); // cannot be used } - void DFA(u32 rt, u32 ra, u32 rb) + enum DoubleOp {DFASM_A, DFASM_S, DFASM_M}; + void DFASM(u32 rt, u32 ra, u32 rb, DoubleOp op) { - CPU.GPR[rt]._d[0] = CPU.GPR[ra]._d[0] + CPU.GPR[rb]._d[0]; - CPU.GPR[rt]._d[1] = CPU.GPR[ra]._d[1] + CPU.GPR[rb]._d[1]; - } - void DFS(u32 rt, u32 ra, u32 rb) - { - CPU.GPR[rt]._d[0] = CPU.GPR[ra]._d[0] - CPU.GPR[rb]._d[0]; - CPU.GPR[rt]._d[1] = CPU.GPR[ra]._d[1] - CPU.GPR[rb]._d[1]; - } - void DFM(u32 rt, u32 ra, u32 rb) - { - CPU.GPR[rt]._d[0] = CPU.GPR[ra]._d[0] * CPU.GPR[rb]._d[0]; - CPU.GPR[rt]._d[1] = CPU.GPR[ra]._d[1] * CPU.GPR[rb]._d[1]; + for (int i = 0; i < 2; i++) + { + double a = CPU.GPR[ra]._d[i]; + double b = CPU.GPR[rb]._d[i]; + if (isdenormal(a)) + { + CPU.FPSCR.setDoublePrecisionExceptionFlags(i, FPSCR_DDENORM); + a = copysign(0.0, a); + } + if (isdenormal(b)) + { + CPU.FPSCR.setDoublePrecisionExceptionFlags(i, FPSCR_DDENORM); + b = copysign(0.0, b); + } + double result; + if (isnan(a) || isnan(b)) + { + CPU.FPSCR.setDoublePrecisionExceptionFlags(i, FPSCR_DNAN); + if (issnan(a) || issnan(b)) + CPU.FPSCR.setDoublePrecisionExceptionFlags(i, FPSCR_DINV); + result = DOUBLE_NAN; + } + else + { + SetHostRoundingMode(CPU.FPSCR.checkSliceRounding(i)); + feclearexcept(FE_ALL_EXCEPT); + switch (op) + { + case DFASM_A: result = a + b; break; + case DFASM_S: result = a - b; break; + case DFASM_M: result = a * b; break; + } + if (fetestexcept(FE_INVALID)) + { + CPU.FPSCR.setDoublePrecisionExceptionFlags(i, FPSCR_DINV); + result = DOUBLE_NAN; + } + else + { + if (fetestexcept(FE_OVERFLOW)) + CPU.FPSCR.setDoublePrecisionExceptionFlags(i, FPSCR_DOVF); + if (fetestexcept(FE_UNDERFLOW)) + CPU.FPSCR.setDoublePrecisionExceptionFlags(i, FPSCR_DUNF); + if (fetestexcept(FE_INEXACT)) + CPU.FPSCR.setDoublePrecisionExceptionFlags(i, FPSCR_DINX); + } + } + CPU.GPR[rt]._d[i] = result; + } } + void DFA(u32 rt, u32 ra, u32 rb) {DFASM(rt, ra, rb, DFASM_A);} + void DFS(u32 rt, u32 ra, u32 rb) {DFASM(rt, ra, rb, DFASM_S);} + void DFM(u32 rt, u32 ra, u32 rb) {DFASM(rt, ra, rb, DFASM_M);} void CLGTB(u32 rt, u32 ra, u32 rb) { for (int b = 0; b < 16; b++) @@ -910,26 +1207,64 @@ private: CPU.Stop(); } } - void DFMA(u32 rt, u32 ra, u32 rb) + void DFMA(u32 rt, u32 ra, u32 rb, bool neg, bool sub) { - CPU.GPR[rt]._d[0] += CPU.GPR[ra]._d[0] * CPU.GPR[rb]._d[0]; - CPU.GPR[rt]._d[1] += CPU.GPR[ra]._d[1] * CPU.GPR[rb]._d[1]; - } - void DFMS(u32 rt, u32 ra, u32 rb) - { - CPU.GPR[rt]._d[0] = CPU.GPR[ra]._d[0] * CPU.GPR[rb]._d[0] - CPU.GPR[rt]._d[0]; - CPU.GPR[rt]._d[1] = CPU.GPR[ra]._d[1] * CPU.GPR[rb]._d[1] - CPU.GPR[rt]._d[1]; - } - void DFNMS(u32 rt, u32 ra, u32 rb) - { - CPU.GPR[rt]._d[0] -= CPU.GPR[ra]._d[0] * CPU.GPR[rb]._d[0]; - CPU.GPR[rt]._d[1] -= CPU.GPR[ra]._d[1] * CPU.GPR[rb]._d[1]; - } - void DFNMA(u32 rt, u32 ra, u32 rb) - { - CPU.GPR[rt]._d[0] = -(CPU.GPR[ra]._d[0] * CPU.GPR[rb]._d[0] + CPU.GPR[rt]._d[0]); - CPU.GPR[rt]._d[1] = -(CPU.GPR[ra]._d[1] * CPU.GPR[rb]._d[1] + CPU.GPR[rt]._d[1]); + for (int i = 0; i < 2; i++) + { + double a = CPU.GPR[ra]._d[i]; + double b = CPU.GPR[rb]._d[i]; + double c = CPU.GPR[rt]._d[i]; + if (isdenormal(a)) + { + CPU.FPSCR.setDoublePrecisionExceptionFlags(i, FPSCR_DDENORM); + a = copysign(0.0, a); + } + if (isdenormal(b)) + { + CPU.FPSCR.setDoublePrecisionExceptionFlags(i, FPSCR_DDENORM); + b = copysign(0.0, b); + } + if (isdenormal(c)) + { + CPU.FPSCR.setDoublePrecisionExceptionFlags(i, FPSCR_DDENORM); + c = copysign(0.0, c); + } + double result; + if (isnan(a) || isnan(b) || isnan(c)) + { + CPU.FPSCR.setDoublePrecisionExceptionFlags(i, FPSCR_DNAN); + if (issnan(a) || issnan(b) || issnan(c) || (isinf(a) && b == 0.0f) || (a == 0.0f && isinf(b))) + CPU.FPSCR.setDoublePrecisionExceptionFlags(i, FPSCR_DINV); + result = DOUBLE_NAN; + } + else + { + SetHostRoundingMode(CPU.FPSCR.checkSliceRounding(i)); + feclearexcept(FE_ALL_EXCEPT); + result = fma(a, b, sub ? -c : c); + if (fetestexcept(FE_INVALID)) + { + CPU.FPSCR.setDoublePrecisionExceptionFlags(i, FPSCR_DINV); + result = DOUBLE_NAN; + } + else + { + if (fetestexcept(FE_OVERFLOW)) + CPU.FPSCR.setDoublePrecisionExceptionFlags(i, FPSCR_DOVF); + if (fetestexcept(FE_UNDERFLOW)) + CPU.FPSCR.setDoublePrecisionExceptionFlags(i, FPSCR_DUNF); + if (fetestexcept(FE_INEXACT)) + CPU.FPSCR.setDoublePrecisionExceptionFlags(i, FPSCR_DINX); + if (neg) result = -result; + } + } + CPU.GPR[rt]._d[i] = result; + } } + void DFMA(u32 rt, u32 ra, u32 rb) {DFMA(rt, ra, rb, false, false);} + void DFMS(u32 rt, u32 ra, u32 rb) {DFMA(rt, ra, rb, false, true);} + void DFNMS(u32 rt, u32 ra, u32 rb) {DFMA(rt, ra, rb, true, true);} + void DFNMA(u32 rt, u32 ra, u32 rb) {DFMA(rt, ra, rb, true, false);} void CEQ(u32 rt, u32 ra, u32 rb) { for (int w = 0; w < 4; w++) @@ -981,29 +1316,67 @@ private: void FSCRRD(u32 rt) { - // TODO (rarely used) - CPU.GPR[rt].clear(); + CPU.GPR[rt]._u32[3] = CPU.FPSCR._u32[3]; + CPU.GPR[rt]._u32[2] = CPU.FPSCR._u32[2]; + CPU.GPR[rt]._u32[1] = CPU.FPSCR._u32[1]; + CPU.GPR[rt]._u32[0] = CPU.FPSCR._u32[0]; } void FESD(u32 rt, u32 ra) { - CPU.GPR[rt]._d[0] = (double)CPU.GPR[ra]._f[1]; - CPU.GPR[rt]._d[1] = (double)CPU.GPR[ra]._f[3]; + for (int i = 0; i < 2; i++) + { + const float a = CPU.GPR[ra]._f[i*2+1]; + if (isnan(a)) + { + CPU.FPSCR.setDoublePrecisionExceptionFlags(i, FPSCR_DNAN); + if (issnan(a)) + CPU.FPSCR.setDoublePrecisionExceptionFlags(i, FPSCR_DINV); + CPU.GPR[rt]._d[i] = DOUBLE_NAN; + } + else if (isdenormal(a)) + { + CPU.FPSCR.setDoublePrecisionExceptionFlags(i, FPSCR_DDENORM); + CPU.GPR[rt]._d[i] = 0.0; + } + else + { + CPU.GPR[rt]._d[i] = (double)a; + } + } } void FRDS(u32 rt, u32 ra) { - CPU.GPR[rt]._f[1] = (float)CPU.GPR[ra]._d[0]; - CPU.GPR[rt]._u32[0] = 0x00000000; - CPU.GPR[rt]._f[3] = (float)CPU.GPR[ra]._d[1]; - CPU.GPR[rt]._u32[2] = 0x00000000; + for (int i = 0; i < 2; i++) + { + SetHostRoundingMode(CPU.FPSCR.checkSliceRounding(i)); + const double a = CPU.GPR[ra]._d[i]; + if (isnan(a)) + { + CPU.FPSCR.setDoublePrecisionExceptionFlags(i, FPSCR_DNAN); + if (issnan(a)) + CPU.FPSCR.setDoublePrecisionExceptionFlags(i, FPSCR_DINV); + CPU.GPR[rt]._f[i*2+1] = FLOAT_NAN; + } + else + { + feclearexcept(FE_ALL_EXCEPT); + CPU.GPR[rt]._f[i*2+1] = (float)a; + if (fetestexcept(FE_OVERFLOW)) + CPU.FPSCR.setDoublePrecisionExceptionFlags(i, FPSCR_DOVF); + if (fetestexcept(FE_UNDERFLOW)) + CPU.FPSCR.setDoublePrecisionExceptionFlags(i, FPSCR_DUNF); + if (fetestexcept(FE_INEXACT)) + CPU.FPSCR.setDoublePrecisionExceptionFlags(i, FPSCR_DINX); + } + CPU.GPR[rt]._u32[i*2] = 0; + } } void FSCRWR(u32 rt, u32 ra) { - // TODO (rarely used) - if (CPU.GPR[ra]._u64[0] || CPU.GPR[ra]._u64[1]) - { - LOG_ERROR(SPU, "FSCRWR(%d,%d): value = %s", rt, ra, CPU.GPR[ra].to_hex().c_str()); - UNIMPLEMENTED(); - } + CPU.FPSCR._u32[3] = CPU.GPR[ra]._u32[3] & 0x00000F07; + CPU.FPSCR._u32[2] = CPU.GPR[ra]._u32[2] & 0x00003F07; + CPU.FPSCR._u32[1] = CPU.GPR[ra]._u32[1] & 0x00003F07; + CPU.FPSCR._u32[0] = CPU.GPR[ra]._u32[0] & 0x00000F07; } void DFTSV(u32 rt, u32 ra, s32 i7) { @@ -1011,10 +1384,17 @@ private: } void FCEQ(u32 rt, u32 ra, u32 rb) { - CPU.GPR[rt]._u32[0] = CPU.GPR[ra]._f[0] == CPU.GPR[rb]._f[0] ? 0xffffffff : 0; - CPU.GPR[rt]._u32[1] = CPU.GPR[ra]._f[1] == CPU.GPR[rb]._f[1] ? 0xffffffff : 0; - CPU.GPR[rt]._u32[2] = CPU.GPR[ra]._f[2] == CPU.GPR[rb]._f[2] ? 0xffffffff : 0; - CPU.GPR[rt]._u32[3] = CPU.GPR[ra]._f[3] == CPU.GPR[rb]._f[3] ? 0xffffffff : 0; + for (int i = 0; i < 4; i++) + { + const u32 a = CPU.GPR[ra]._u32[i]; + const u32 b = CPU.GPR[rb]._u32[i]; + const u32 abs_a = a & 0x7FFFFFFF; + const u32 abs_b = b & 0x7FFFFFFF; + const bool a_zero = (abs_a < 0x00800000); + const bool b_zero = (abs_b < 0x00800000); + const bool pass = a == b || (a_zero && b_zero); + CPU.GPR[rt]._u32[i] = pass ? 0xFFFFFFFF : 0; + } } void DFCEQ(u32 rt, u32 ra, u32 rb) { @@ -1047,10 +1427,17 @@ private: } void FCMEQ(u32 rt, u32 ra, u32 rb) { - CPU.GPR[rt]._u32[0] = fabs(CPU.GPR[ra]._f[0]) == fabs(CPU.GPR[rb]._f[0]) ? 0xffffffff : 0; - CPU.GPR[rt]._u32[1] = fabs(CPU.GPR[ra]._f[1]) == fabs(CPU.GPR[rb]._f[1]) ? 0xffffffff : 0; - CPU.GPR[rt]._u32[2] = fabs(CPU.GPR[ra]._f[2]) == fabs(CPU.GPR[rb]._f[2]) ? 0xffffffff : 0; - CPU.GPR[rt]._u32[3] = fabs(CPU.GPR[ra]._f[3]) == fabs(CPU.GPR[rb]._f[3]) ? 0xffffffff : 0; + for (int i = 0; i < 4; i++) + { + const u32 a = CPU.GPR[ra]._u32[i]; + const u32 b = CPU.GPR[rb]._u32[i]; + const u32 abs_a = a & 0x7FFFFFFF; + const u32 abs_b = b & 0x7FFFFFFF; + const bool a_zero = (abs_a < 0x00800000); + const bool b_zero = (abs_b < 0x00800000); + const bool pass = abs_a == abs_b || (a_zero && b_zero); + CPU.GPR[rt]._u32[i] = pass ? 0xFFFFFFFF : 0; + } } void DFCMEQ(u32 rt, u32 ra, u32 rb) { @@ -1084,53 +1471,54 @@ private: //0 - 9 void CFLTS(u32 rt, u32 ra, s32 i8) { - const u32 scale = 173 - (i8 & 0xff); //unsigned immediate + const int scale = 173 - (i8 & 0xff); //unsigned immediate for (int i = 0; i < 4; i++) { - u32 exp = ((CPU.GPR[ra]._u32[i] >> 23) & 0xff) + scale; - - if (exp > 255) - exp = 255; - - CPU.GPR[rt]._u32[i] = (CPU.GPR[ra]._u32[i] & 0x807fffff) | (exp << 23); - - if (CPU.GPR[rt]._f[i] > 0x7fffffff) - CPU.GPR[rt]._u32[i] = 0x7fffffff; - else if (CPU.GPR[rt]._f[i] < -pow(2, 31)) - CPU.GPR[rt]._u32[i] = 0x80000000; + const float a = CPU.GPR[ra]._f[i]; + float scaled; + if ((fexpf(a)-127) + scale >= 32) + scaled = copysignf(4294967296.0f, a); else - CPU.GPR[rt]._s32[i] = (s32)CPU.GPR[rt]._f[i]; //trunc + scaled = ldexpf(a, scale); + s32 result; + if (scaled >= 2147483648.0f) + result = 0x7FFFFFFF; + else if (scaled < -2147483648.0f) + result = 0x80000000; + else + result = (s32)scaled; + CPU.GPR[rt]._s32[i] = result; } } void CFLTU(u32 rt, u32 ra, s32 i8) { - const u32 scale = 173 - (i8 & 0xff); //unsigned immediate + const int scale = 173 - (i8 & 0xff); //unsigned immediate for (int i = 0; i < 4; i++) { - u32 exp = ((CPU.GPR[ra]._u32[i] >> 23) & 0xff) + scale; - - if (exp > 255) - exp = 255; - - if (CPU.GPR[ra]._u32[i] & 0x80000000) //if negative, result = 0 - CPU.GPR[rt]._u32[i] = 0; + const float a = CPU.GPR[ra]._f[i]; + float scaled; + if ((fexpf(a)-127) + scale >= 32) + scaled = copysignf(4294967296.0f, a); else - { - CPU.GPR[rt]._u32[i] = (CPU.GPR[ra]._u32[i] & 0x807fffff) | (exp << 23); - - if (CPU.GPR[rt]._f[i] > 0xffffffff) //if big, result = max - CPU.GPR[rt]._u32[i] = 0xffffffff; - else - CPU.GPR[rt]._u32[i] = (u32)floor(CPU.GPR[rt]._f[i]); - } + scaled = ldexpf(a, scale); + u32 result; + if (scaled >= 4294967296.0f) + result = 0xFFFFFFFF; + else if (scaled < 0.0f) + result = 0; + else + result = (u32)scaled; + CPU.GPR[rt]._u32[i] = result; } } void CSFLT(u32 rt, u32 ra, s32 i8) { - const u32 scale = 155 - (i8 & 0xff); //unsigned immediate + SetHostRoundingMode(FPSCR_RN_ZERO); + const int scale = 155 - (i8 & 0xff); //unsigned immediate for (int i = 0; i < 4; i++) { - CPU.GPR[rt]._f[i] = (float)CPU.GPR[ra]._s32[i]; + const s32 a = CPU.GPR[ra]._s32[i]; + CPU.GPR[rt]._f[i] = (float)a; u32 exp = ((CPU.GPR[rt]._u32[i] >> 23) & 0xff) - scale; @@ -1138,14 +1526,21 @@ private: exp = 0; CPU.GPR[rt]._u32[i] = (CPU.GPR[rt]._u32[i] & 0x807fffff) | (exp << 23); + if (isdenormal(CPU.GPR[rt]._f[i]) || (CPU.GPR[rt]._f[i] == 0.0f && a != 0)) + { + CPU.FPSCR.setSinglePrecisionExceptionFlags(i, FPSCR_SUNF | FPSCR_SDIFF); + CPU.GPR[rt]._f[i] = 0.0f; + } } } void CUFLT(u32 rt, u32 ra, s32 i8) { - const u32 scale = 155 - (i8 & 0xff); //unsigned immediate + SetHostRoundingMode(FPSCR_RN_ZERO); + const int scale = 155 - (i8 & 0xff); //unsigned immediate for (int i = 0; i < 4; i++) { - CPU.GPR[rt]._f[i] = (float)CPU.GPR[ra]._u32[i]; + const u32 a = CPU.GPR[ra]._u32[i]; + CPU.GPR[rt]._f[i] = (float)a; u32 exp = ((CPU.GPR[rt]._u32[i] >> 23) & 0xff) - scale; @@ -1153,6 +1548,11 @@ private: exp = 0; CPU.GPR[rt]._u32[i] = (CPU.GPR[rt]._u32[i] & 0x807fffff) | (exp << 23); + if (isdenormal(CPU.GPR[rt]._f[i]) || (CPU.GPR[rt]._f[i] == 0.0f && a != 0)) + { + CPU.FPSCR.setSinglePrecisionExceptionFlags(i, FPSCR_SUNF | FPSCR_SDIFF); + CPU.GPR[rt]._f[i] = 0.0f; + } } } @@ -1524,28 +1924,151 @@ private: for (int w = 0; w < 4; w++) CPU.GPR[rt]._s32[w] = CPU.GPR[ra]._s16[w*2] * CPU.GPR[rb]._s16[w*2] + CPU.GPR[rc]._s32[w]; } - void FNMS(u32 rt, u32 ra, u32 rb, u32 rc) + void FNMS(u32 rt, u32 ra, u32 rb, u32 rc) {FMA(rt, ra, rb, rc, true, true);} + void FMA(u32 rt, u32 ra, u32 rb, u32 rc) {FMA(rt, ra, rb, rc, false, false);} + void FMS(u32 rt, u32 ra, u32 rb, u32 rc) {FMA(rt, ra, rb, rc, false, true);} + void FMA(u32 rt, u32 ra, u32 rb, u32 rc, bool neg, bool sub) { + SetHostRoundingMode(FPSCR_RN_ZERO); for (int w = 0; w < 4; w++) { - CPU.GPR[rt]._f[w] = CPU.GPR[rc]._f[w] - CPU.GPR[ra]._f[w] * CPU.GPR[rb]._f[w]; - //if (CPU.GPR[rt]._f[w] == -0.0f) CPU.GPR[rt]._f[w] = 0.0f; - } - } - void FMA(u32 rt, u32 ra, u32 rb, u32 rc) - { - for (int w = 0; w < 4; w++) - { - CPU.GPR[rt]._f[w] = CPU.GPR[rc]._f[w] + CPU.GPR[ra]._f[w] * CPU.GPR[rb]._f[w]; - //if (CPU.GPR[rt]._f[w] == -0.0f) CPU.GPR[rt]._f[w] = 0.0f; - } - } - void FMS(u32 rt, u32 ra, u32 rb, u32 rc) - { - for (int w = 0; w < 4; w++) - { - CPU.GPR[rt]._f[w] = CPU.GPR[ra]._f[w] * CPU.GPR[rb]._f[w] - CPU.GPR[rc]._f[w]; - //if (CPU.GPR[rt]._f[w] == -0.0f) CPU.GPR[rt]._f[w] = 0.0f; + float a = CPU.GPR[ra]._f[w]; + float b = neg ? -CPU.GPR[rb]._f[w] : CPU.GPR[rb]._f[w]; + float c = (neg != sub) ? -CPU.GPR[rc]._f[w] : CPU.GPR[rc]._f[w]; + if (isdenormal(a)) + { + CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SDIFF); + a = 0.0f; + } + if (isdenormal(b)) + { + CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SDIFF); + b = 0.0f; + } + if (isdenormal(c)) + { + CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SDIFF); + c = 0.0f; + } + + const bool sign = std::signbit(a) ^ std::signbit(b); + float result; + + if (isextended(a) || isextended(b)) + { + CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SDIFF); + if (a == 0.0f || b == 0.0f) + { + result = c; + } + else if ((fexpf(a)-127) + (fexpf(b)-127) >= 130) + { + CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SOVF); + result = extended(sign, 0x7FFFFF); + } + else + { + float new_a, new_b; + if (isextended(a)) + { + new_a = ldexpf_extended(a, -2); + new_b = b; + } + else + { + new_a = a; + new_b = ldexpf_extended(b, -2); + } + if (fexpf(c) < 3) + { + result = new_a * new_b; + if (c != 0.0f && std::signbit(c) != sign) + { + u32 bits = (u32&)result - 1; + result = (float&)bits; + } + } + else + { + result = fmaf(new_a, new_b, ldexpf_extended(c, -2)); + } + if (fabsf(result) >= ldexpf(1.0f, 127)) + { + CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SOVF); + result = extended(sign, 0x7FFFFF); + } + else + { + result = ldexpf_extended(result, 2); + } + } + } + else if (isextended(c)) + { + CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SDIFF); + if (a == 0.0f || b == 0.0f) + { + result = c; + } + else if ((fexpf(a)-127) + (fexpf(b)-127) < 96) + { + result = c; + if (sign != std::signbit(c)) + { + u32 bits = (u32&)result - 1; + result = (float&)bits; + } + } + else + { + result = fmaf(ldexpf(a,-1), ldexpf(b,-1), ldexpf_extended(c,-2)); + if (fabsf(result) >= ldexpf(1.0f, 127)) + { + CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SOVF); + result = extended(sign, 0x7FFFFF); + } + else + { + result = ldexpf_extended(result, 2); + } + } + } + else + { + feclearexcept(FE_ALL_EXCEPT); + result = fmaf(a, b, c); + if (fetestexcept(FE_OVERFLOW)) + { + CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SDIFF); + if (fexpf(a) > fexpf(b)) + result = fmaf(ldexpf(a,-2), b, ldexpf(c,-2)); + else + result = fmaf(a, ldexpf(b,-2), ldexpf(c,-2)); + if (fabsf(result) >= ldexpf(1.0f, 127)) + { + CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SOVF); + result = extended(sign, 0x7FFFFF); + } + else + { + result = ldexpf_extended(result, 2); + } + } + else if (fetestexcept(FE_UNDERFLOW)) + { + CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SUNF | FPSCR_SDIFF); + } + } + if (isdenormal(result)) + { + CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SUNF | FPSCR_SDIFF); + result = 0.0f; + } + else if (result == 0.0f) + { + result = +0.0f; + } + CPU.GPR[rt]._f[w] = result; } } diff --git a/rpcs3/Emu/Cell/SPURecompilerCore.cpp b/rpcs3/Emu/Cell/SPURecompilerCore.cpp index 8d733bd8b4..197f42987e 100644 --- a/rpcs3/Emu/Cell/SPURecompilerCore.cpp +++ b/rpcs3/Emu/Cell/SPURecompilerCore.cpp @@ -228,7 +228,7 @@ u8 SPURecompilerCore::DecodeMemory(const u32 address) //need_check = true; } } - //LOG_ERROR(Log::SPU, "SPURecompilerCore::DecodeMemory(ls_addr=0x%x): code has changed", pos * sizeof(u32)); + //LOG_ERROR(Log::SPU, "SPURecompilerCore::DecodeMemory(ls=0x%x): code has changed", pos * sizeof(u32)); } } @@ -239,7 +239,7 @@ u8 SPURecompilerCore::DecodeMemory(const u32 address) did_compile = true; if (entry[pos].valid == 0) { - LOG_ERROR(Log::SPU, "SPURecompilerCore::Compile(ls_addr=0x%x): branch to 0x0 opcode", pos * sizeof(u32)); + LOG_ERROR(Log::SPU, "SPURecompilerCore::Compile(ls=0x%x): branch to 0x0 opcode", pos * sizeof(u32)); Emu.Pause(); return 0; } @@ -255,7 +255,7 @@ u8 SPURecompilerCore::DecodeMemory(const u32 address) //if (did_compile) { - //LOG2_OPCODE("SPURecompilerCore::DecodeMemory(ls_addr=0x%x): NewPC = 0x%llx", address, (u64)res << 2); + //LOG2_OPCODE("SPURecompilerCore::DecodeMemory(ls=0x%x): NewPC = 0x%llx", address, (u64)res << 2); //if (pos == 0x19c >> 2) { //Emu.Pause(); @@ -281,7 +281,7 @@ u8 SPURecompilerCore::DecodeMemory(const u32 address) if (did_compile) { - //LOG2_OPCODE("SPURecompilerCore::DecodeMemory(ls_addr=0x%x): NewPC = 0x%llx", address, (u64)res << 2); + //LOG2_OPCODE("SPURecompilerCore::DecodeMemory(ls=0x%x): NewPC = 0x%llx", address, (u64)res << 2); //if (pos == 0x340 >> 2) { //Emu.Pause(); diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index c9f3fa6c5e..95f678bf02 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -292,8 +292,8 @@ void SPUThread::ProcessCmd(u32 cmd, u32 tag, u32 lsa, u64 ea, u32 size) void SPUThread::ListCmd(u32 lsa, u64 ea, u16 tag, u16 size, u32 cmd, MFCReg& MFCArgs) { - u32 list_addr = ea & 0x3ffff; - u32 list_size = size / 8; + const u32 list_addr = ea & 0x3ffff; + const u32 list_size = size / 8; lsa &= 0x3fff0; struct list_element @@ -309,27 +309,31 @@ void SPUThread::ListCmd(u32 lsa, u64 ea, u16 tag, u16 size, u32 cmd, MFCReg& MFC { auto rec = vm::ptr::make(ls_offset + list_addr + i * 8); - u32 size = rec->ts; - if (!(rec->s.ToBE() & se16(0x8000)) && size < 16 && size != 1 && size != 2 && size != 4 && size != 8) + const u32 size = rec->ts; + if (!(rec->s.data() & se16(0x8000)) && size < 16 && size != 1 && size != 2 && size != 4 && size != 8) { LOG_ERROR(Log::SPU, "DMA List: invalid transfer size(%d)", size); result = MFC_PPU_DMA_CMD_SEQUENCE_ERROR; break; } - u32 addr = rec->ea; - + const u32 addr = rec->ea; if (size) + { ProcessCmd(cmd, tag, lsa | (addr & 0xf), addr, size); + } - if (Ini.HLELogging.GetValue() || rec->s.ToBE()) - LOG_NOTICE(Log::SPU, "*** list element(%d/%d): s = 0x%x, ts = 0x%x, low ea = 0x%x (lsa = 0x%x)", - i, list_size, (u16)rec->s, (u16)rec->ts, (u32)rec->ea, lsa | (addr & 0xf)); + if (Ini.HLELogging.GetValue() || rec->s.data()) + { + LOG_NOTICE(Log::SPU, "*** list element(%d/%d): s = 0x%x, ts = 0x%x, low ea = 0x%x (lsa = 0x%x)", i, list_size, rec->s, rec->ts, rec->ea, lsa | (addr & 0xf)); + } if (size) - lsa += std::max(size, (u32)16); + { + lsa += std::max(size, 16); + } - if (rec->s.ToBE() & se16(0x8000)) + if (rec->s.data() & se16(0x8000)) { StallStat.PushUncond_OR(1 << tag); @@ -339,12 +343,12 @@ void SPUThread::ListCmd(u32 lsa, u64 ea, u16 tag, u16 size, u32 cmd, MFCReg& MFC result = MFC_PPU_DMA_CMD_SEQUENCE_ERROR; break; } + StallList[tag].MFCArgs = &MFCArgs; StallList[tag].cmd = cmd; StallList[tag].ea = (ea & ~0xffffffff) | (list_addr + (i + 1) * 8); StallList[tag].lsa = lsa; StallList[tag].size = (list_size - i - 1) * 8; - break; } } @@ -554,6 +558,8 @@ u32 SPUThread::GetChannelCount(u32 ch) switch (ch) { + case SPU_WrSRR0: res = 1; break; + case SPU_RdSRR0: res = 1; break; case SPU_WrOutMbox: res = SPU.Out_MBox.GetFreeCount(); break; case SPU_WrOutIntrMbox: res = SPU.Out_IntrMBox.GetFreeCount(); break; case SPU_RdInMbox: res = SPU.In_MBox.GetCount(); break; @@ -585,6 +591,9 @@ void SPUThread::WriteChannel(u32 ch, const u128& r) switch (ch) { + case SPU_WrSRR0: + SRR0 = v & 0x3FFFC; //LSLR & ~3 + break; case SPU_WrOutIntrMbox: { if (!group) // if RawSPU @@ -906,6 +915,9 @@ void SPUThread::ReadChannel(u128& r, u32 ch) switch (ch) { + case SPU_RdSRR0: + v = SRR0; + break; case SPU_RdInMbox: { while (!SPU.In_MBox.Pop(v) && !Emu.IsStopped()) @@ -1219,4 +1231,4 @@ spu_thread::spu_thread(u32 entry, const std::string& name, u32 stack_size, u32 p thread->SetPrio(prio ? prio : Emu.GetInfo().GetProcParam().primary_prio); argc = 0; -} \ No newline at end of file +} diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index 323b5b25d2..f880e5ca6e 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -1,4 +1,5 @@ #pragma once +#include "Emu/Cell/Common.h" #include "Emu/Memory/atomic_type.h" #include "PPCThread.h" #include "Emu/SysCalls/lv2/sleep_queue_type.h" @@ -167,45 +168,46 @@ struct g_imm_table_struct extern const g_imm_table_struct g_imm_table; -//Floating point status and control register. Unsure if this is one of the GPRs or SPRs +enum FPSCR_EX +{ + //Single-precision exceptions + FPSCR_SOVF = 1 << 2, //Overflow + FPSCR_SUNF = 1 << 1, //Underflow + FPSCR_SDIFF = 1 << 0, //Different (could be IEEE non-compliant) + //Double-precision exceptions + FPSCR_DOVF = 1 << 13, //Overflow + FPSCR_DUNF = 1 << 12, //Underflow + FPSCR_DINX = 1 << 11, //Inexact + FPSCR_DINV = 1 << 10, //Invalid operation + FPSCR_DNAN = 1 << 9, //NaN + FPSCR_DDENORM = 1 << 8, //Denormal +}; + //Is 128 bits, but bits 0-19, 24-28, 32-49, 56-60, 64-81, 88-92, 96-115, 120-124 are unused -class FPSCR +class SPU_FPSCR { public: - u64 low; - u64 hi; + u32 _u32[4]; - FPSCR() {} + SPU_FPSCR() {} std::string ToString() const { - return "FPSCR writer not yet implemented"; //fmt::Format("%08x%08x%08x%08x", _u32[3], _u32[2], _u32[1], _u32[0]); + return fmt::Format("%08x%08x%08x%08x", _u32[3], _u32[2], _u32[1], _u32[0]); } void Reset() { memset(this, 0, sizeof(*this)); } - //slice -> 0 - 1 (4 slices total, only two have rounding) - //0 -> round even - //1 -> round towards zero (truncate) - //2 -> round towards positive inf - //3 -> round towards neg inf + //slice -> 0 - 1 (double-precision slice index) + //NOTE: slices follow u128 indexing, i.e. slice 0 is RIGHT end of register! + //roundTo -> FPSCR_RN_* void setSliceRounding(u8 slice, u8 roundTo) { - u64 mask = roundTo; - switch(slice) - { - case 0: - mask = mask << 20; - break; - case 1: - mask = mask << 22; - break; - } - - //rounding is located in the low end of the FPSCR - this->low = this->low & mask; + int shift = 8 + 2*slice; + //rounding is located in the left end of the FPSCR + this->_u32[3] = (this->_u32[3] & ~(3 << shift)) | (roundTo << shift); } //Slice 0 or 1 u8 checkSliceRounding(u8 slice) const @@ -213,10 +215,10 @@ public: switch(slice) { case 0: - return this->low >> 20 & 0x3; + return this->_u32[3] >> 8 & 0x3; case 1: - return this->low >> 22 & 0x3; + return this->_u32[3] >> 10 & 0x3; default: throw fmt::Format("Unexpected slice value in FPSCR::checkSliceRounding(): %d", slice); @@ -224,34 +226,28 @@ public: } } - //Single Precision Exception Flags (all 3 slices) + //Single-precision exception flags (all 4 slices) //slice -> slice number (0-3) - //exception: 1 -> Overflow 2 -> Underflow 4-> Diff (could be IE^3 non compliant) - void setSinglePrecisionExceptionFlags(u8 slice, u8 exception) + //exception: FPSCR_S* bitmask + void setSinglePrecisionExceptionFlags(u8 slice, u32 exceptions) { - u64 mask = exception; - switch(slice) - { - case 0: - mask = mask << 29; - this->low = this->low & mask; - break; - case 1: - mask = mask << 61; - this->low = this->low & mask; - break; - case 2: - mask = mask << 29; - this->hi = this->hi & mask; - break; - case 3: - mask = mask << 61; - this->hi = this->hi & mask; - break; - } - + _u32[slice] |= exceptions; + } + + //Single-precision divide-by-zero flags (all 4 slices) + //slice -> slice number (0-3) + void setDivideByZeroFlag(u8 slice) + { + _u32[0] |= 1 << (8 + slice); + } + + //Double-precision exception flags + //slice -> slice number (0-1) + //exception: FPSCR_D* bitmask + void setDoublePrecisionExceptionFlags(u8 slice, u32 exceptions) + { + _u32[1+slice] |= exceptions; } - }; union SPU_SNRConfig_hdr @@ -277,7 +273,8 @@ class SPUThread : public PPCThread { public: u128 GPR[128]; // General-Purpose Registers - //FPSCR FPSCR; + SPU_FPSCR FPSCR; + u32 SRR0; SPU_SNRConfig_hdr cfg; // Signal Notification Registers Configuration (OR-mode enabled: 0x1 for SNR1, 0x2 for SNR2) u64 R_ADDR; // reservation address @@ -630,4 +627,4 @@ public: return *this; } -}; \ No newline at end of file +}; diff --git a/rpcs3/Emu/FS/VFS.cpp b/rpcs3/Emu/FS/VFS.cpp index 01489759a6..f65cfbdcb2 100644 --- a/rpcs3/Emu/FS/VFS.cpp +++ b/rpcs3/Emu/FS/VFS.cpp @@ -10,7 +10,8 @@ std::vector simplify_path_blocks(const std::string& path) { - std::vector path_blocks = std::move(fmt::split(fmt::tolower(path), { "/", "\\" })); + // fmt::tolower() removed + std::vector path_blocks = std::move(fmt::split(path, { "/", "\\" })); for (size_t i = 0; i < path_blocks.size(); ++i) { @@ -28,7 +29,7 @@ std::vector simplify_path_blocks(const std::string& path) return path_blocks; } -std::string simplify_path(const std::string& path, bool is_dir) +std::string simplify_path(const std::string& path, bool is_dir, bool is_ps3) { std::vector path_blocks = simplify_path_blocks(path); @@ -36,8 +37,17 @@ std::string simplify_path(const std::string& path, bool is_dir) return ""; std::string result = fmt::merge(path_blocks, "/"); + +#ifdef _WIN32 + if (is_ps3) +#endif + { + result = "/" + result; + } - return is_dir ? result + "/" : result; + if (is_dir) result = result + "/"; + + return result; } VFS::~VFS() @@ -47,11 +57,11 @@ VFS::~VFS() void VFS::Mount(const std::string& ps3_path, const std::string& local_path, vfsDevice* device) { - std::string simpl_ps3_path = simplify_path(ps3_path, true); + std::string simpl_ps3_path = simplify_path(ps3_path, true, true); UnMount(simpl_ps3_path); - device->SetPath(simpl_ps3_path, simplify_path(local_path, true)); + device->SetPath(simpl_ps3_path, simplify_path(local_path, true, false)); m_devices.push_back(device); if (m_devices.size() > 1) @@ -65,9 +75,9 @@ void VFS::Link(const std::string& mount_point, const std::string& ps3_path) links[simplify_path_blocks(mount_point)] = simplify_path_blocks(ps3_path); } -std::string VFS::GetLinked(std::string ps3_path) const +std::string VFS::GetLinked(const std::string& ps3_path) const { - ps3_path = fmt::tolower(ps3_path); + // fmt::tolower removed auto path_blocks = fmt::split(ps3_path, { "/", "\\" }); for (auto link : links) @@ -95,7 +105,7 @@ std::string VFS::GetLinked(std::string ps3_path) const void VFS::UnMount(const std::string& ps3_path) { - std::string simpl_ps3_path = simplify_path(ps3_path, true); + std::string simpl_ps3_path = simplify_path(ps3_path, true, true); for (u32 i = 0; i < m_devices.size(); ++i) { @@ -320,18 +330,21 @@ vfsDevice* VFS::GetDevice(const std::string& ps3_path, std::string& path) const path += "/" + ps3_path_blocks[i]; } - path = simplify_path(path, false); - + path = simplify_path(path, false, false); + return m_devices[max_i]; }; - if (auto res = try_get_device(GetLinked(ps3_path))) - return res; + if (!ps3_path.size() || ps3_path[0] != '/') + { + return nullptr; + } - if (auto res = try_get_device(GetLinked(cwd + ps3_path))) - return res; + return try_get_device(GetLinked(ps3_path)); - return nullptr; + // What is it? cwd is real path, ps3_path is ps3 path, but GetLinked accepts ps3 path + //if (auto res = try_get_device(GetLinked(cwd + ps3_path))) + // return res; } vfsDevice* VFS::GetDeviceLocal(const std::string& local_path, std::string& path) const @@ -374,14 +387,14 @@ vfsDevice* VFS::GetDeviceLocal(const std::string& local_path, std::string& path) path += "/" + local_path_blocks[i]; } - path = simplify_path(path, false); + path = simplify_path(path, false, true); return m_devices[max_i]; } void VFS::Init(const std::string& path) { - cwd = simplify_path(path, true); + cwd = simplify_path(path, true, false); UnMountAll(); diff --git a/rpcs3/Emu/FS/VFS.h b/rpcs3/Emu/FS/VFS.h index aad5121211..38a63e94c4 100644 --- a/rpcs3/Emu/FS/VFS.h +++ b/rpcs3/Emu/FS/VFS.h @@ -44,7 +44,7 @@ struct VFSManagerEntry }; std::vector simplify_path_blocks(const std::string& path); -std::string simplify_path(const std::string& path, bool is_dir); +std::string simplify_path(const std::string& path, bool is_dir, bool is_ps3); struct VFS { @@ -74,7 +74,7 @@ struct VFS void UnMount(const std::string& ps3_path); void UnMountAll(); - std::string GetLinked(std::string ps3_path) const; + std::string GetLinked(const std::string& ps3_path) const; vfsFileBase* OpenFile(const std::string& ps3_path, vfsOpenMode mode) const; vfsDirBase* OpenDir(const std::string& ps3_path) const; diff --git a/rpcs3/Emu/FS/vfsDir.cpp b/rpcs3/Emu/FS/vfsDir.cpp index a6e2cc565f..c8c7c0a9d4 100644 --- a/rpcs3/Emu/FS/vfsDir.cpp +++ b/rpcs3/Emu/FS/vfsDir.cpp @@ -29,7 +29,7 @@ bool vfsDir::Open(const std::string& path) DirEntryInfo info; - m_cwd = simplify_path(Emu.GetVFS().GetLinked(0 && m_stream && m_stream->IsOpened() ? m_stream->GetPath() : path), true); + m_cwd = simplify_path(Emu.GetVFS().GetLinked(0 && m_stream && m_stream->IsOpened() ? m_stream->GetPath() : path), true, true); auto blocks = simplify_path_blocks(GetPath()); diff --git a/rpcs3/Emu/Io/XInput/XInputPadHandler.cpp b/rpcs3/Emu/Io/XInput/XInputPadHandler.cpp index 27033c5d32..51c6d6474c 100644 --- a/rpcs3/Emu/Io/XInput/XInputPadHandler.cpp +++ b/rpcs3/Emu/Io/XInput/XInputPadHandler.cpp @@ -111,7 +111,7 @@ void XInputPadHandler::Close() { active = false; if (WaitForSingleObject(thread, THREAD_TIMEOUT) != WAIT_OBJECT_0) - LOG_ERROR(HLE, "XInput thread could not stop within %d milliseconds", THREAD_TIMEOUT); + LOG_ERROR(HLE, "XInput thread could not stop within %d milliseconds", (u32)THREAD_TIMEOUT); thread = nullptr; } diff --git a/rpcs3/Emu/Memory/Memory.cpp b/rpcs3/Emu/Memory/Memory.cpp index 9aa328b14e..6c5d405eab 100644 --- a/rpcs3/Emu/Memory/Memory.cpp +++ b/rpcs3/Emu/Memory/Memory.cpp @@ -170,28 +170,29 @@ void MemoryBase::Close() MemoryBlocks.clear(); } -bool MemoryBase::WriteMMIO32(u32 addr, const u32 data) +void MemoryBase::WriteMMIO32(u32 addr, const u32 data) { LV2_LOCK(0); if (RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET] && ((RawSPUThread*)RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET])->Write32(addr, data)) { - return true; + return; } - return false; + throw fmt::Format("%s(addr=0x%x, data=0x%x) failed", __FUNCTION__, addr, data); } -bool MemoryBase::ReadMMIO32(u32 addr, u32& res) +u32 MemoryBase::ReadMMIO32(u32 addr) { LV2_LOCK(0); + u32 res; if (RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET] && ((RawSPUThread*)RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET])->Read32(addr, &res)) { - return true; + return res; } - return false; + throw fmt::Format("%s(addr=0x%x) failed", __FUNCTION__, addr); } bool MemoryBase::Map(const u64 addr, const u32 size) diff --git a/rpcs3/Emu/Memory/Memory.h b/rpcs3/Emu/Memory/Memory.h index 069e7a8609..5ba0e1dd7b 100644 --- a/rpcs3/Emu/Memory/Memory.h +++ b/rpcs3/Emu/Memory/Memory.h @@ -83,21 +83,6 @@ public: void UnregisterPages(u64 addr, u32 size); - u32 RealToVirtualAddr(const void* addr) - { - const u64 res = (u64)addr - (u64)GetBaseAddr(); - - if ((u32)res == res) - { - return (u32)res; - } - else - { - assert(!addr); - return 0; - } - } - u32 InitRawSPU(MemoryBlock* raw_spu); void CloseRawSPU(MemoryBlock* raw_spu, const u32 num); @@ -127,9 +112,9 @@ public: void Close(); - __noinline bool WriteMMIO32(u32 addr, const u32 data); + __noinline void WriteMMIO32(u32 addr, const u32 data); - __noinline bool ReadMMIO32(u32 addr, u32& res); + __noinline u32 ReadMMIO32(u32 addr); u32 GetUserMemTotalSize() { diff --git a/rpcs3/Emu/Memory/vm.cpp b/rpcs3/Emu/Memory/vm.cpp index dbac50e797..25a4d8c0e7 100644 --- a/rpcs3/Emu/Memory/vm.cpp +++ b/rpcs3/Emu/Memory/vm.cpp @@ -1,5 +1,7 @@ #include "stdafx.h" #include "Memory.h" +#include "Emu/CPU/CPUThread.h" +#include "Emu/Cell/PPUThread.h" namespace vm { @@ -50,6 +52,20 @@ namespace vm return g_locations[location].deallocator(addr); } + u32 get_addr(const void* real_pointer) + { + const u64 diff = (u64)real_pointer - (u64)g_base_addr; + const u32 res = (u32)diff; + + if (res == diff) + { + return res; + } + + assert(!real_pointer); + return 0; + } + namespace ps3 { u32 main_alloc(u32 size) @@ -143,4 +159,84 @@ namespace vm { Memory.Close(); } + + u32 stack_push(CPUThread& CPU, u32 size, u32 align_v, u32& old_pos) + { + switch (CPU.GetType()) + { + case CPU_THREAD_PPU: + { + PPUThread& PPU = static_cast(CPU); + + assert(align_v); + old_pos = (u32)PPU.GPR[1]; + PPU.GPR[1] -= align(size, 8); // room minimal possible size + PPU.GPR[1] &= ~(align_v - 1); // fix stack alignment + + if (PPU.GPR[1] < CPU.GetStackAddr()) + { + // stack overflow + PPU.GPR[1] = old_pos; + return 0; + } + else + { + return (u32)PPU.GPR[1]; + } + } + + case CPU_THREAD_SPU: + case CPU_THREAD_RAW_SPU: + { + assert(!"stack_push(): SPU not supported"); + return 0; + } + + case CPU_THREAD_ARMv7: + { + assert(!"stack_push(): ARMv7 not supported"); + return 0; + } + + default: + { + assert(!"stack_push(): invalid thread type"); + return 0; + } + } + } + + void stack_pop(CPUThread& CPU, u32 addr, u32 old_pos) + { + switch (CPU.GetType()) + { + case CPU_THREAD_PPU: + { + PPUThread& PPU = static_cast(CPU); + + assert(PPU.GPR[1] == addr); + PPU.GPR[1] = old_pos; + return; + } + + case CPU_THREAD_SPU: + case CPU_THREAD_RAW_SPU: + { + assert(!"stack_pop(): SPU not supported"); + return; + } + + case CPU_THREAD_ARMv7: + { + assert(!"stack_pop(): ARMv7 not supported"); + return; + } + + default: + { + assert(!"stack_pop(): invalid thread type"); + return; + } + } + } } \ No newline at end of file diff --git a/rpcs3/Emu/Memory/vm.h b/rpcs3/Emu/Memory/vm.h index ed78cf54c2..9068888ead 100644 --- a/rpcs3/Emu/Memory/vm.h +++ b/rpcs3/Emu/Memory/vm.h @@ -1,6 +1,8 @@ #pragma once #include "Memory.h" +class CPUThread; + namespace vm { enum memory_location : uint @@ -29,7 +31,7 @@ namespace vm template T* const get_ptr(u32 addr) { - return (T*)((u8*)g_base_addr + addr); + return reinterpret_cast(static_cast(g_base_addr) + addr); } template @@ -38,56 +40,100 @@ namespace vm return *get_ptr(addr); } + u32 get_addr(const void* real_pointer); + + template + struct cast_ptr + { + static_assert(std::is_same::value, "Unsupported vm::cast() type"); + + __forceinline static u32 cast(const T& addr, const char* func) + { + return 0; + } + }; + + template<> + struct cast_ptr + { + __forceinline static u32 cast(const u32 addr, const char* func) + { + return addr; + } + }; + + template<> + struct cast_ptr + { + __forceinline static u32 cast(const u64 addr, const char* func) + { + const u32 res = static_cast(addr); + if (res != addr) + { + throw fmt::Format("%s(): invalid address 0x%llx", func, addr); + } + + return res; + } + }; + + template + struct cast_ptr> + { + __forceinline static u32 cast(const be_t& addr, const char* func) + { + return cast_ptr::cast(addr.value(), func); + } + }; + + template + __forceinline static u32 cast(const T& addr, const char* func = "vm::cast") + { + return cast_ptr::cast(addr, func); + } + namespace ps3 { void init(); static u8 read8(u32 addr) { - return *((u8*)g_base_addr + addr); + return get_ref(addr); } static void write8(u32 addr, u8 value) { - *((u8*)g_base_addr + addr) = value; + get_ref(addr) = value; } static u16 read16(u32 addr) { - return re16(*(u16*)((u8*)g_base_addr + addr)); + return get_ref>(addr); } static void write16(u32 addr, be_t value) { - *(be_t*)((u8*)g_base_addr + addr) = value; + get_ref>(addr) = value; } static u32 read32(u32 addr) { - u32 res; - if (addr < RAW_SPU_BASE_ADDR || (addr % RAW_SPU_OFFSET) < RAW_SPU_PROB_OFFSET || !Memory.ReadMMIO32((u32)addr, res)) - { - res = re32(*(u32*)((u8*)g_base_addr + addr)); - } - return res; + return get_ref>(addr); } static void write32(u32 addr, be_t value) { - if (addr < RAW_SPU_BASE_ADDR || (addr % RAW_SPU_OFFSET) < RAW_SPU_PROB_OFFSET || !Memory.WriteMMIO32((u32)addr, value)) - { - *(be_t*)((u8*)g_base_addr + addr) = value; - } + get_ref>(addr) = value; } static u64 read64(u32 addr) { - return re64(*(u64*)((u8*)g_base_addr + addr)); + return get_ref>(addr); } static void write64(u32 addr, be_t value) { - *(be_t*)((u8*)g_base_addr + addr) = value; + get_ref>(addr) = value; } static void write16(u32 addr, u16 value) @@ -107,12 +153,12 @@ namespace vm static u128 read128(u32 addr) { - return re128(*(u128*)((u8*)g_base_addr + addr)); + return get_ref>(addr); } static void write128(u32 addr, u128 value) { - *(u128*)((u8*)g_base_addr + addr) = re128(value); + get_ref>(addr) = value; } } @@ -122,52 +168,52 @@ namespace vm static u8 read8(u32 addr) { - return *((u8*)g_base_addr + addr); + return get_ref(addr); } static void write8(u32 addr, u8 value) { - *((u8*)g_base_addr + addr) = value; + get_ref(addr) = value; } static u16 read16(u32 addr) { - return *(u16*)((u8*)g_base_addr + addr); + return get_ref(addr); } static void write16(u32 addr, u16 value) { - *(u16*)((u8*)g_base_addr + addr) = value; + get_ref(addr) = value; } static u32 read32(u32 addr) { - return *(u32*)((u8*)g_base_addr + addr); + return get_ref(addr); } static void write32(u32 addr, u32 value) { - *(u32*)((u8*)g_base_addr + addr) = value; + get_ref(addr) = value; } static u64 read64(u32 addr) { - return *(u64*)((u8*)g_base_addr + addr); + return get_ref(addr); } static void write64(u32 addr, u64 value) { - *(u64*)((u8*)g_base_addr + addr) = value; + get_ref(addr) = value; } static u128 read128(u32 addr) { - return *(u128*)((u8*)g_base_addr + addr); + return get_ref(addr); } static void write128(u32 addr, u128 value) { - *(u128*)((u8*)g_base_addr + addr) = value; + get_ref(addr) = value; } } @@ -179,6 +225,9 @@ namespace vm } void close(); + + u32 stack_push(CPUThread& CPU, u32 size, u32 align, u32& old_pos); + void stack_pop(CPUThread& CPU, u32 addr, u32 old_pos); } #include "vm_ref.h" diff --git a/rpcs3/Emu/Memory/vm_ptr.h b/rpcs3/Emu/Memory/vm_ptr.h index 60ae33900b..5915a52a05 100644 --- a/rpcs3/Emu/Memory/vm_ptr.h +++ b/rpcs3/Emu/Memory/vm_ptr.h @@ -11,49 +11,50 @@ namespace vm public: typedef typename std::remove_cv::type type; + static const u32 address_size = sizeof(AT); _ptr_base operator++ (int) { AT result = m_addr; - m_addr += sizeof(AT); + m_addr += address_size; return make(result); } _ptr_base& operator++ () { - m_addr += sizeof(AT); + m_addr += address_size; return *this; } _ptr_base operator-- (int) { AT result = m_addr; - m_addr -= sizeof(AT); + m_addr -= address_size; return make(result); } _ptr_base& operator-- () { - m_addr -= sizeof(AT); + m_addr -= address_size; return *this; } _ptr_base& operator += (AT count) { - m_addr += count * sizeof(AT); + m_addr += count * address_size; return *this; } _ptr_base& operator -= (AT count) { - m_addr -= count * sizeof(AT); + m_addr -= count * address_size; return *this; } - _ptr_base operator + (typename remove_be_t::type count) const { return make(m_addr + count * sizeof(AT)); } - _ptr_base operator + (typename to_be_t::type count) const { return make(m_addr + count * sizeof(AT)); } - _ptr_base operator - (typename remove_be_t::type count) const { return make(m_addr - count * sizeof(AT)); } - _ptr_base operator - (typename to_be_t::type count) const { return make(m_addr - count * sizeof(AT)); } + _ptr_base operator + (typename remove_be_t::type count) const { return make(m_addr + count * address_size); } + _ptr_base operator + (typename to_be_t::type count) const { return make(m_addr + count * address_size); } + _ptr_base operator - (typename remove_be_t::type count) const { return make(m_addr - count * address_size); } + _ptr_base operator - (typename to_be_t::type count) const { return make(m_addr - count * address_size); } __forceinline bool operator <(const _ptr_base& right) const { return m_addr < right.m_addr; } __forceinline bool operator <=(const _ptr_base& right) const { return m_addr <= right.m_addr; } @@ -67,21 +68,19 @@ namespace vm __forceinline _ptr_base::value, typename to_be_t::type, AT>>& operator *() const { - return vm::get_ref<_ptr_base::value, typename to_be_t::type, AT>>>((u32)m_addr); + return vm::get_ref<_ptr_base::value, typename to_be_t::type, AT>>>(vm::cast(m_addr)); } __forceinline _ptr_base::value, typename to_be_t::type, AT>>& operator [](AT index) const { - return vm::get_ref<_ptr_base::value, typename to_be_t::type, AT>>>((u32)(m_addr + sizeof(AT)* index)); + return vm::get_ref<_ptr_base::value, typename to_be_t::type, AT>>>(vm::cast(m_addr + sizeof(AT)* index)); } - //typedef typename invert_be_t::type AT2; - template operator const _ptr_base() const { - typename std::remove_const::type addr = convert_le_be(m_addr); - return (_ptr_base&)addr; + const AT2 addr = convert_le_be(m_addr); + return reinterpret_cast&>(addr); } AT addr() const @@ -94,9 +93,9 @@ namespace vm m_addr = value; } - static _ptr_base make(AT addr) + static const _ptr_base make(const AT& addr) { - return (_ptr_base&)addr; + return reinterpret_cast(addr); } _ptr_base& operator = (const _ptr_base& right) = default; @@ -109,68 +108,69 @@ namespace vm public: typedef typename std::remove_cv::type type; + static const u32 data_size = sizeof(T); __forceinline T* const operator -> () const { - return vm::get_ptr((u32)m_addr); + return vm::get_ptr(vm::cast(m_addr)); } _ptr_base operator++ (int) { AT result = m_addr; - m_addr += sizeof(T); + m_addr += data_size; return make(result); } _ptr_base& operator++ () { - m_addr += sizeof(T); + m_addr += data_size; return *this; } _ptr_base operator-- (int) { AT result = m_addr; - m_addr -= sizeof(T); + m_addr -= data_size; return make(result); } _ptr_base& operator-- () { - m_addr -= sizeof(T); + m_addr -= data_size; return *this; } _ptr_base& operator += (AT count) { - m_addr += count * sizeof(T); + m_addr += count * data_size; return *this; } _ptr_base& operator -= (AT count) { - m_addr -= count * sizeof(T); + m_addr -= count * data_size; return *this; } - _ptr_base operator + (typename remove_be_t::type count) const { return make(m_addr + count * sizeof(T)); } - _ptr_base operator + (typename to_be_t::type count) const { return make(m_addr + count * sizeof(T)); } - _ptr_base operator - (typename remove_be_t::type count) const { return make(m_addr - count * sizeof(T)); } - _ptr_base operator - (typename to_be_t::type count) const { return make(m_addr - count * sizeof(T)); } + _ptr_base operator + (typename remove_be_t::type count) const { return make(m_addr + count * data_size); } + _ptr_base operator + (typename to_be_t::type count) const { return make(m_addr + count * data_size); } + _ptr_base operator - (typename remove_be_t::type count) const { return make(m_addr - count * data_size); } + _ptr_base operator - (typename to_be_t::type count) const { return make(m_addr - count * data_size); } __forceinline T& operator *() const { - return vm::get_ref((u32)m_addr); + return vm::get_ref(vm::cast(m_addr)); } __forceinline T& operator [](typename remove_be_t::type index) const { - return vm::get_ref((u32)(m_addr + sizeof(T) * index)); + return vm::get_ref(vm::cast(m_addr + data_size * index)); } __forceinline T& operator [](typename to_be_t::forced_type index) const { - return vm::get_ref((u32)(m_addr + sizeof(T)* index)); + return vm::get_ref(vm::cast(m_addr + data_size * index)); } __forceinline bool operator <(const _ptr_base& right) const { return m_addr < right.m_addr; } @@ -183,18 +183,6 @@ namespace vm __forceinline bool operator !=(const nullptr_t& right) const { return m_addr != 0; } explicit operator bool() const { return m_addr != 0; } explicit operator T*() const { return get_ptr(); } - - /* - operator _ref_base() - { - return _ref_base::make(m_addr); - } - - operator const _ref_base() const - { - return _ref_base::make(m_addr); - } - */ AT addr() const { @@ -207,29 +195,21 @@ namespace vm m_addr = convert_le_be(value); } - /* - operator T*() const - { - return get_ptr(); - } - */ - //typedef typename invert_be_t::type AT2; - template operator const _ptr_base() const { - typename std::remove_const::type addr = convert_le_be(m_addr); - return (_ptr_base&)addr; + const AT2 addr = convert_le_be(m_addr); + return reinterpret_cast&>(addr); } T* get_ptr() const { - return vm::get_ptr((u32)m_addr); + return vm::get_ptr(vm::cast(m_addr)); } - static _ptr_base make(AT addr) + static const _ptr_base make(const AT& addr) { - return (_ptr_base&)addr; + return reinterpret_cast(addr); } _ptr_base& operator = (const _ptr_base& right) = default; @@ -253,7 +233,7 @@ namespace vm void* get_ptr() const { - return vm::get_ptr((u32)m_addr); + return vm::get_ptr(vm::cast(m_addr)); } explicit operator void*() const @@ -271,25 +251,23 @@ namespace vm __forceinline bool operator !=(const nullptr_t& right) const { return m_addr != 0; } explicit operator bool() const { return m_addr != 0; } - //typedef typename invert_be_t::type AT2; - template operator const _ptr_base() const { - typename std::remove_const::type addr = convert_le_be(m_addr); - return (_ptr_base&)addr; + const AT2 addr = convert_le_be(m_addr); + return reinterpret_cast&>(addr); } template operator const _ptr_base() const { - typename std::remove_const::type addr = convert_le_be(m_addr); - return (_ptr_base&)addr; + const AT2 addr = convert_le_be(m_addr); + return reinterpret_cast&>(addr); } - static _ptr_base make(AT addr) + static const _ptr_base make(const AT& addr) { - return (_ptr_base&)addr; + return reinterpret_cast(addr); } _ptr_base& operator = (const _ptr_base& right) = default; @@ -313,7 +291,7 @@ namespace vm const void* get_ptr() const { - return vm::get_ptr((u32)m_addr); + return vm::get_ptr(vm::cast(m_addr)); } explicit operator const void*() const @@ -331,18 +309,16 @@ namespace vm __forceinline bool operator !=(const nullptr_t& right) const { return m_addr != 0; } explicit operator bool() const { return m_addr != 0; } - //typedef typename invert_be_t::type AT2; - template operator const _ptr_base() const { - typename std::remove_const::type addr = convert_le_be(m_addr); - return (_ptr_base&)addr; + const AT2 addr = convert_le_be(m_addr); + return reinterpret_cast&>(addr); } - static _ptr_base make(AT addr) + static const _ptr_base make(const AT& addr) { - return (_ptr_base&)addr; + return reinterpret_cast(addr); } _ptr_base& operator = (const _ptr_base& right) = default; @@ -356,7 +332,7 @@ namespace vm public: typedef RT(*type)(T...); - RT call(CPUThread& CPU, T... args) const; // defined in CB_FUNC.h, call using specified CPU thread context + RT operator()(CPUThread& CPU, T... args) const; // defined in CB_FUNC.h, call using specified CPU thread context RT operator()(T... args) const; // defined in CB_FUNC.h, call using current CPU thread context @@ -380,23 +356,21 @@ namespace vm __forceinline bool operator !=(const nullptr_t& right) const { return m_addr != 0; } explicit operator bool() const { return m_addr != 0; } - //typedef typename invert_be_t::type AT2; - template operator const _ptr_base() const { - typename std::remove_const::type addr = convert_le_be(m_addr); - return (_ptr_base&)addr; + const AT2 addr = convert_le_be(m_addr); + return reinterpret_cast&>(addr); } - static _ptr_base make(AT addr) + static const _ptr_base make(const AT& addr) { - return (_ptr_base&)addr; + return reinterpret_cast(addr); } operator const std::function() const { - typename std::remove_const::type addr = convert_le_be(m_addr); + const AT addr = convert_le_be(m_addr); return [addr](T... args) -> RT { return make(addr)(args...); }; } @@ -406,75 +380,88 @@ namespace vm //BE pointer to LE data template struct bptrl : public _ptr_base::type> { - static bptrl make(AT addr) + static const bptrl make(AT addr) { - return (bptrl&)addr; + auto res = _ptr_base::type>::make(convert_le_be::type>(addr)); + return static_cast(res); } using _ptr_base::type>::operator=; - //using _ptr_base::type>::operator const _ptr_base; }; //BE pointer to BE data template struct bptrb : public _ptr_base::type, lvl, typename to_be_t::type> { - static bptrb make(AT addr) + static const bptrb make(AT addr) { - return (bptrb&)addr; + auto res = _ptr_base::type, lvl, typename to_be_t::type>::make(convert_le_be::type>(addr)); + return static_cast(res); } using _ptr_base::type, lvl, typename to_be_t::type>::operator=; - //using _ptr_base::type, lvl, typename to_be_t::type>::operator const _ptr_base::type, lvl, AT>; }; //LE pointer to BE data template struct lptrb : public _ptr_base::type, lvl, AT> { - static lptrb make(AT addr) + static const lptrb make(AT addr) { - return (lptrb&)addr; + auto res = _ptr_base::type, lvl, AT>::make(addr); + return static_cast(res); } using _ptr_base::type, lvl, AT>::operator=; - //using _ptr_base::type, lvl, AT>::operator const _ptr_base::type, lvl, typename to_be_t::type>; }; //LE pointer to LE data template struct lptrl : public _ptr_base { - static lptrl make(AT addr) + static const lptrl make(AT addr) { - return (lptrl&)addr; + auto res = _ptr_base::make(addr); + return static_cast(res); } using _ptr_base::operator=; - //using _ptr_base::operator const _ptr_base::type>; }; namespace ps3 { + template struct ptr; + template struct bptr; + //default pointer for HLE functions (LE pointer to BE data) - template struct ptr : public lptrb + template struct ptr : public lptrb { - static ptr make(AT addr) + static const ptr make(AT addr) { - return (ptr&)addr; + auto res = lptrb::make(addr); + return static_cast(res); + } + + vm::ps3::bptr to_be() const + { + return vm::ps3::bptr::make(this->addr()); } using lptrb::operator=; - //using lptrb::operator const _ptr_base::type, lvl, AT>; }; //default pointer for HLE structures (BE pointer to BE data) - template struct bptr : public bptrb + template struct bptr : public bptrb { - static bptr make(AT addr) + static const bptr make(AT addr) { - return (bptr&)addr; + auto res = bptrb::make(addr); + return static_cast(res); + } + + vm::ps3::ptr to_le() const + { + return vm::ps3::ptr::make(this->addr()); } using bptrb::operator=; - //using bptrb::operator const _ptr_base::type, lvl, AT>; }; } @@ -483,9 +470,10 @@ namespace vm //default pointer for HLE functions & structures (LE pointer to LE data) template struct ptr : public lptrl { - static ptr make(AT addr) + static const ptr make(AT addr) { - return (ptr&)addr; + auto res = lptrl::make(addr); + return static_cast(res); } using lptrl::operator=; @@ -494,4 +482,80 @@ namespace vm //PS3 emulation is main now, so lets it be as default using namespace ps3; -} \ No newline at end of file +} + +namespace fmt +{ + // external specializations for fmt::format function + + template + struct unveil, false> + { + typedef typename unveil::result_type result_type; + + __forceinline static result_type get_value(const vm::ps3::ptr& arg) + { + return unveil::get_value(arg.addr()); + } + }; + + template + struct unveil, false> + { + typedef typename unveil::result_type result_type; + + __forceinline static result_type get_value(const vm::ps3::bptr& arg) + { + return unveil::get_value(arg.addr()); + } + }; + + template + struct unveil, false> + { + typedef typename unveil::result_type result_type; + + __forceinline static result_type get_value(const vm::psv::ptr& arg) + { + return unveil::get_value(arg.addr()); + } + }; +} + +// external specializations for PPU GPR (SC_FUNC.h, CB_FUNC.h) + +template +struct cast_ppu_gpr; + +template +struct cast_ppu_gpr, false> +{ + __forceinline static u64 to_gpr(const vm::ps3::ptr& value) + { + return value.addr(); + } + + __forceinline static vm::ps3::ptr from_gpr(const u64 reg) + { + return vm::ps3::ptr::make(cast_ppu_gpr::value>::from_gpr(reg)); + } +}; + +// external specializations for ARMv7 GPR + +template +struct cast_armv7_gpr; + +template +struct cast_armv7_gpr, false> +{ + __forceinline static u32 to_gpr(const vm::psv::ptr& value) + { + return value.addr(); + } + + __forceinline static vm::psv::ptr from_gpr(const u32 reg) + { + return vm::psv::ptr::make(cast_armv7_gpr::value>::from_gpr(reg)); + } +}; diff --git a/rpcs3/Emu/Memory/vm_ref.h b/rpcs3/Emu/Memory/vm_ref.h index 4d682e1ab1..5788457c3b 100644 --- a/rpcs3/Emu/Memory/vm_ref.h +++ b/rpcs3/Emu/Memory/vm_ref.h @@ -28,9 +28,9 @@ namespace vm return m_addr; } - static _ref_base make(AT addr) + static _ref_base make(const AT& addr) { - return (_ref_base&)addr; + return reinterpret_cast<_ref_base&>(addr); } _ref_base& operator = (le_type right) @@ -108,4 +108,80 @@ namespace vm //PS3 emulation is main now, so lets it be as default using namespace ps3; -} \ No newline at end of file +} + +namespace fmt +{ + // external specializations for fmt::format function + + template + struct unveil, false> + { + typedef typename unveil::result_type result_type; + + __forceinline static result_type get_value(const vm::ps3::ref& arg) + { + return unveil::get_value(arg.addr()); + } + }; + + template + struct unveil, false> + { + typedef typename unveil::result_type result_type; + + __forceinline static result_type get_value(const vm::ps3::bref& arg) + { + return unveil::get_value(arg.addr()); + } + }; + + template + struct unveil, false> + { + typedef typename unveil::result_type result_type; + + __forceinline static result_type get_value(const vm::psv::ref& arg) + { + return unveil::get_value(arg.addr()); + } + }; +} + +// external specializations for PPU GPR (SC_FUNC.h, CB_FUNC.h) + +template +struct cast_ppu_gpr; + +template +struct cast_ppu_gpr, false> +{ + __forceinline static u64 to_gpr(const vm::ps3::ref& value) + { + return value.addr(); + } + + __forceinline static vm::ps3::ref from_gpr(const u64 reg) + { + return vm::ps3::ref::make(cast_ppu_gpr::value>::from_gpr(reg)); + } +}; + +// external specializations for ARMv7 GPR + +template +struct cast_armv7_gpr; + +template +struct cast_armv7_gpr, false> +{ + __forceinline static u32 to_gpr(const vm::psv::ref& value) + { + return value.addr(); + } + + __forceinline static vm::psv::ref from_gpr(const u32 reg) + { + return vm::psv::ref::make(cast_armv7_gpr::value>::from_gpr(reg)); + } +}; diff --git a/rpcs3/Emu/Memory/vm_var.h b/rpcs3/Emu/Memory/vm_var.h index c3d637abda..95ea373f9e 100644 --- a/rpcs3/Emu/Memory/vm_var.h +++ b/rpcs3/Emu/Memory/vm_var.h @@ -1,5 +1,7 @@ #pragma once +class CPUThread; + namespace vm { template @@ -33,7 +35,7 @@ namespace vm void alloc() { - m_addr = (u32)Memory.Alloc(size(), m_align); + m_addr = vm::cast(Memory.Alloc(size(), m_align)); m_ptr = vm::get_ptr(m_addr); } @@ -160,7 +162,7 @@ namespace vm void alloc() { - m_addr = (u32)Memory.Alloc(size(), m_align); + m_addr = vm::cast(Memory.Alloc(size(), m_align)); m_ptr = vm::get_ptr(m_addr); } @@ -495,4 +497,130 @@ namespace vm return (NT*)(m_ptr + offset); } }; + + template + class stackvar + { + struct stack_allocation + { + T* ptr; + u32 addr; + u32 size; + u32 align; + u32 old_pos; + + stack_allocation(CPUThread& CPU, u32 size, u32 align) + : size(size) + , align(align) + { + addr = stack_push(CPU, size, align, old_pos); + ptr = vm::get_ptr(addr); + } + + stack_allocation() = delete; + stack_allocation(const stack_allocation& r) = delete; + stack_allocation(stack_allocation&& r) = delete; + stack_allocation& operator = (const stack_allocation& r) = delete; + stack_allocation& operator = (stack_allocation&& r) = delete; + + } const m_data; + + CPUThread& m_thread; + + public: + stackvar(CPUThread& CPU, u32 size = sizeof(T), u32 align = __alignof(T)) + : m_data(CPU, size, align) + , m_thread(CPU) + { + } + + stackvar(const stackvar& r) + : m_data(r.m_thread, r.m_data.m_size, r.m_data.m_align) + , m_thread(r.m_thread) + { + *m_data.ptr = *r.m_data.ptr; + } + + stackvar(stackvar&& r) = delete; + + ~stackvar() + { + stack_pop(m_thread, m_data.addr, m_data.old_pos); + } + + stackvar& operator = (const stackvar& r) + { + *m_data.ptr = *r.m_data.ptr; + return *this; + } + + stackvar& operator = (stackvar&& r) = delete; + + T* operator -> () + { + return m_data.ptr; + } + + const T* operator -> () const + { + return m_data.ptr; + } + + T* get_ptr() + { + return m_data.ptr; + } + + const T* get_ptr() const + { + return m_data.ptr; + } + + T& value() + { + return *m_data.ptr; + } + + const T& value() const + { + return *m_data.ptr; + } + + u32 addr() const + { + return m_data.addr; + } + + u32 size() const + { + return m_data.size; + } + + /* + operator const ref() const + { + return addr(); + } + */ + + template operator const ps3::ptr() const + { + return ps3::ptr::make(m_data.addr); + } + + template operator const ps3::ptr() const + { + return ps3::ptr::make(m_data.addr); + } + + operator T&() + { + return *m_data.ptr; + } + + operator const T&() const + { + return *m_data.ptr; + } + }; } \ No newline at end of file diff --git a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp index bca4dbc7c0..ea6bb1a0bb 100644 --- a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp @@ -102,9 +102,9 @@ std::string GLFragmentDecompilerThread::AddConst() return name; } - auto data = vm::ptr::make(m_addr + m_size + m_offset); + auto data = vm::ptr::make(m_addr + m_size + 4 * sizeof(u32)); - m_offset += 4 * 4; + m_offset = 2 * 4 * sizeof(u32); u32 x = GetData(data[0]); u32 y = GetData(data[1]); u32 z = GetData(data[2]); @@ -350,7 +350,7 @@ std::string GLFragmentDecompilerThread::BuildCode() p += param.Format(); } - return std::string("#version 330\n" + return std::string("#version 420\n" "\n" + p + "\n" "void main()\n{\n" + main + "}\n"); diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index ab6ed0302b..35ec0a7dc5 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -734,7 +734,7 @@ void DrawCursorObj::Draw() void DrawCursorObj::InitializeShaders() { m_vp.shader = - "#version 330\n" + "#version 420\n" "\n" "uniform vec4 in_pos;\n" "uniform vec2 in_tc;\n" @@ -747,10 +747,10 @@ void DrawCursorObj::InitializeShaders() "}\n"; m_fp.shader = - "#version 330\n" + "#version 420\n" "\n" "in vec2 tc;\n" - "uniform sampler2D tex0;\n" + "layout (binding = 0) uniform sampler2D tex0;\n" "layout (location = 0) out vec4 res;\n" "\n" "void main()\n" @@ -1623,7 +1623,8 @@ void GLGSRender::InitDrawBuffers() void GLGSRender::Enable(u32 cmd, u32 enable) { - switch (cmd) { + switch (cmd) + { case NV4097_SET_DITHER_ENABLE: enable ? glEnable(GL_DITHER) : glDisable(GL_DITHER); break; @@ -1696,6 +1697,10 @@ void GLGSRender::Enable(u32 cmd, u32 enable) enable ? glEnable(GL_DEPTH_BOUNDS_TEST_EXT) : glDisable(GL_DEPTH_BOUNDS_TEST_EXT); break; + case NV4097_SET_TWO_SIDED_STENCIL_TEST_ENABLE: + enable ? glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT) : glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT); + break; + case NV4097_SET_USER_CLIP_PLANE_CONTROL: const u32 clip_plane_0 = enable & 0xf; const u32 clip_plane_1 = (enable >> 4) & 0xf; @@ -1791,9 +1796,9 @@ void GLGSRender::PointSize(float size) checkForGlError("glPointSize"); } -void GLGSRender::LogicOp(u32 opcdoe) +void GLGSRender::LogicOp(u32 opcode) { - glLogicOp(opcdoe); + glLogicOp(opcode); checkForGlError("glLogicOp"); } @@ -1809,6 +1814,12 @@ void GLGSRender::LineStipple(u16 factor, u16 pattern) checkForGlError("glLineStipple"); } +void GLGSRender::PolygonStipple(u32 pattern) +{ + glPolygonStipple((const GLubyte*)pattern); + checkForGlError("glPolygonStipple"); +} + void GLGSRender::PrimitiveRestartIndex(u32 index) { glPrimitiveRestartIndex(index); @@ -1895,6 +1906,39 @@ void GLGSRender::Scissor(u16 x, u16 y, u16 width, u16 height) checkForGlError("glScissor"); } +void GLGSRender::StencilOp(u32 fail, u32 zfail, u32 zpass) +{ + glStencilOp(fail, zfail, zpass); + checkForGlError("glStencilOp"); +} + +void GLGSRender::StencilMask(u32 mask) +{ + glStencilMask(mask); + checkForGlError("glStencilMask"); +} + +void GLGSRender::StencilFunc(u32 func, u32 ref, u32 mask) +{ + glStencilFunc(func, ref, mask); + checkForGlError("glStencilFunc"); +} + +void GLGSRender::StencilOpSeparate(u32 mode, u32 fail, u32 zfail, u32 zpass) +{ + mode ? glStencilOpSeparate(GL_FRONT, fail, zfail, zpass) : glStencilOpSeparate(GL_BACK, fail, zfail, zpass); +} + +void GLGSRender::StencilMaskSeparate(u32 mode, u32 mask) +{ + mode ? glStencilMaskSeparate(GL_FRONT, mask) : glStencilMaskSeparate(GL_BACK, mask); +} + +void GLGSRender::StencilFuncSeparate(u32 mode, u32 func, u32 ref, u32 mask) +{ + mode ? glStencilFuncSeparate(GL_FRONT, func, ref, mask) : glStencilFuncSeparate(GL_BACK, func, ref, mask); +} + void GLGSRender::ExecCMD() { if (!LoadProgram()) @@ -1906,77 +1950,12 @@ void GLGSRender::ExecCMD() InitDrawBuffers(); - if (m_set_two_sided_stencil_test_enable) - { - if (m_set_stencil_fail && m_set_stencil_zfail && m_set_stencil_zpass) - { - glStencilOpSeparate(GL_FRONT, m_stencil_fail, m_stencil_zfail, m_stencil_zpass); - checkForGlError("glStencilOpSeparate"); - } - - if (m_set_stencil_mask) - { - glStencilMaskSeparate(GL_FRONT, m_stencil_mask); - checkForGlError("glStencilMaskSeparate"); - } - - if (m_set_stencil_func && m_set_stencil_func_ref && m_set_stencil_func_mask) - { - glStencilFuncSeparate(GL_FRONT, m_stencil_func, m_stencil_func_ref, m_stencil_func_mask); - checkForGlError("glStencilFuncSeparate"); - } - - if (m_set_back_stencil_fail && m_set_back_stencil_zfail && m_set_back_stencil_zpass) - { - glStencilOpSeparate(GL_BACK, m_back_stencil_fail, m_back_stencil_zfail, m_back_stencil_zpass); - checkForGlError("glStencilOpSeparate(GL_BACK)"); - } - - if (m_set_back_stencil_mask) - { - glStencilMaskSeparate(GL_BACK, m_back_stencil_mask); - checkForGlError("glStencilMaskSeparate(GL_BACK)"); - } - - if (m_set_back_stencil_func && m_set_back_stencil_func_ref && m_set_back_stencil_func_mask) - { - glStencilFuncSeparate(GL_BACK, m_back_stencil_func, m_back_stencil_func_ref, m_back_stencil_func_mask); - checkForGlError("glStencilFuncSeparate(GL_BACK)"); - } - } - else - { - if (m_set_stencil_fail && m_set_stencil_zfail && m_set_stencil_zpass) - { - glStencilOp(m_stencil_fail, m_stencil_zfail, m_stencil_zpass); - checkForGlError("glStencilOp"); - } - - if (m_set_stencil_mask) - { - glStencilMask(m_stencil_mask); - checkForGlError("glStencilMask"); - } - - if (m_set_stencil_func && m_set_stencil_func_ref && m_set_stencil_func_mask) - { - glStencilFunc(m_stencil_func, m_stencil_func_ref, m_stencil_func_mask); - checkForGlError("glStencilFunc"); - } - } - - if (m_set_polygon_stipple) - { - glPolygonStipple((const GLubyte*)m_polygon_stipple_pattern); - checkForGlError("glPolygonStipple"); - } - if (m_indexed_array.m_count && m_draw_array_count) { LOG_WARNING(RSX, "m_indexed_array.m_count && draw_array_count"); } - for (u32 i=0; i < m_textures_count; ++i) + for (u32 i = 0; i < m_textures_count; ++i) { if (!m_textures[i].IsEnabled()) continue; @@ -1999,7 +1978,7 @@ void GLGSRender::ExecCMD() m_gl_vertex_textures[i].Create(); m_gl_vertex_textures[i].Bind(); checkForGlError(fmt::Format("m_gl_vertex_textures[%d].Bind", i)); - m_program.SetTex(i); + m_program.SetVTex(i); m_gl_vertex_textures[i].Init(m_vertex_textures[i]); checkForGlError(fmt::Format("m_gl_vertex_textures[%d].Init", i)); } @@ -2055,12 +2034,6 @@ void GLGSRender::ExecCMD() void GLGSRender::Flip() { - if (m_set_scissor_horizontal && m_set_scissor_vertical) - { - glScissor(0, 0, RSXThread::m_width, RSXThread::m_height); - checkForGlError("glScissor"); - } - static u8* src_buffer = nullptr; static u32 width = 0; static u32 height = 0; @@ -2161,13 +2134,6 @@ void GLGSRender::Flip() m_frame->Flip(m_context); - // Restore scissor - if (m_set_scissor_horizontal && m_set_scissor_vertical) - { - glScissor(m_scissor_x, m_scissor_y, m_scissor_w, m_scissor_h); - checkForGlError("glScissor"); - } - } u32 LinearToSwizzleAddress(u32 x, u32 y, u32 z, u32 log2_width, u32 log2_height, u32 log2_depth) diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.h b/rpcs3/Emu/RSX/GL/GLGSRender.h index dbaa1135ea..7ab9f406d1 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.h +++ b/rpcs3/Emu/RSX/GL/GLGSRender.h @@ -201,9 +201,10 @@ protected: virtual void DepthMask(u32 flag); virtual void PolygonMode(u32 face, u32 mode); virtual void PointSize(float size); - virtual void LogicOp(u32 opcdoe); + virtual void LogicOp(u32 opcode); virtual void LineWidth(float width); virtual void LineStipple(u16 factor, u16 pattern); + virtual void PolygonStipple(u32 pattern); virtual void PrimitiveRestartIndex(u32 index); virtual void CullFace(u32 mode); virtual void FrontFace(u32 mode); @@ -218,5 +219,11 @@ protected: virtual void ShadeModel(u32 mode); virtual void DepthBoundsEXT(float min, float max); virtual void Scissor(u16 x, u16 y, u16 width, u16 height); + virtual void StencilOp(u32 fail, u32 zfail, u32 zpass); + virtual void StencilMask(u32 mask); + virtual void StencilFunc(u32 func, u32 ref, u32 mask); + virtual void StencilOpSeparate(u32 mode, u32 fail, u32 zfail, u32 zpass); + virtual void StencilMaskSeparate(u32 mode, u32 mask); + virtual void StencilFuncSeparate(u32 mode, u32 func, u32 ref, u32 mask); virtual void Flip(); }; diff --git a/rpcs3/Emu/RSX/GL/GLVertexProgram.cpp b/rpcs3/Emu/RSX/GL/GLVertexProgram.cpp index 28723bf0b6..5b730555a5 100644 --- a/rpcs3/Emu/RSX/GL/GLVertexProgram.cpp +++ b/rpcs3/Emu/RSX/GL/GLVertexProgram.cpp @@ -48,7 +48,7 @@ std::string GLVertexDecompilerThread::GetDST(bool isSca) default: if (d3.dst > 15) - LOG_ERROR(RSX, "dst index out of range: %u", d3.dst); + LOG_ERROR(RSX, fmt::Format("dst index out of range: %u", d3.dst)); ret += m_parr.AddParam(PARAM_NONE, "vec4", std::string("dst_reg") + std::to_string(d3.dst), d3.dst == 0 ? "vec4(0.0f, 0.0f, 0.0f, 1.0f)" : "vec4(0.0)"); break; } @@ -92,7 +92,7 @@ std::string GLVertexDecompilerThread::GetSRC(const u32 n) break; default: - LOG_ERROR(RSX, "Bad src%u reg type: %d", n, fmt::by_value(src[n].reg_type)); + LOG_ERROR(RSX, fmt::Format("Bad src%u reg type: %d", n, fmt::by_value(src[n].reg_type))); Emu.Pause(); break; } @@ -498,7 +498,7 @@ std::string GLVertexDecompilerThread::BuildCode() } static const std::string& prot = - "#version 330\n" + "#version 420\n" "\n" "uniform mat4 scaleOffsetMat = mat4(1.0);\n" "%s\n" diff --git a/rpcs3/Emu/RSX/Null/NullGSRender.h b/rpcs3/Emu/RSX/Null/NullGSRender.h index de2167a8b7..53786c3b8e 100644 --- a/rpcs3/Emu/RSX/Null/NullGSRender.h +++ b/rpcs3/Emu/RSX/Null/NullGSRender.h @@ -26,9 +26,10 @@ private: virtual void DepthMask(u32 flag) {} virtual void PolygonMode(u32 face, u32 mode) {} virtual void PointSize(float size) {} - virtual void LogicOp(u32 opcdoe) {} + virtual void LogicOp(u32 opcode) {} virtual void LineWidth(float width) {} virtual void LineStipple(u16 factor, u16 pattern) {} + virtual void PolygonStipple(u32 pattern) {} virtual void PrimitiveRestartIndex(u32 index) {} virtual void CullFace(u32 mode) {} virtual void FrontFace(u32 mode) {} @@ -43,6 +44,12 @@ private: virtual void ShadeModel(u32 mode) {} virtual void DepthBoundsEXT(float min, float max) {} virtual void Scissor(u16 x, u16 y, u16 width, u16 height) {} + virtual void StencilOp(u32 fail, u32 zfail, u32 zpass) {} + virtual void StencilMask(u32 mask) {} + virtual void StencilFunc(u32 func, u32 ref, u32 mask) {} + virtual void StencilOpSeparate(u32 mode, u32 fail, u32 zfail, u32 zpass) {} + virtual void StencilMaskSeparate(u32 mode, u32 mask) {} + virtual void StencilFuncSeparate(u32 mode, u32 func, u32 ref, u32 mask) {} virtual void Flip() {} virtual void Close() {} }; diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index e57931d415..906b0281c3 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -10,7 +10,7 @@ #include "Emu/SysCalls/CB_FUNC.h" #include "Emu/SysCalls/lv2/sys_time.h" -#define ARGS(x) (x >= count ? OutOfArgsCount(x, cmd, count, args.addr()) : args[x].ToLE()) +#define ARGS(x) (x >= count ? OutOfArgsCount(x, cmd, count, args.addr()) : args[x].value()) #define CMD_DEBUG 0 u32 methodRegisters[0xffff]; @@ -177,7 +177,7 @@ u32 RSXThread::OutOfArgsCount(const uint x, const u32 cmd, const u32 count, cons debug += "("; for (u32 i = 0; i < count; ++i) debug += (i ? ", " : "") + fmt::Format("0x%x", ARGS(i)); debug += ")"; - LOG_NOTICE(RSX, "OutOfArgsCount(x=%u, count=%u): %s", x, count, debug.c_str()); + LOG_NOTICE(RSX, "OutOfArgsCount(x=%d, count=%d): %s", x, count, debug.c_str()); return 0; } @@ -289,9 +289,9 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const if (m_flip_handler) { auto cb = m_flip_handler; - Emu.GetCallbackManager().Async([cb]() + Emu.GetCallbackManager().Async([cb](PPUThread& CPU) { - cb(1); + cb(CPU, 1); }); } @@ -1270,7 +1270,8 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV4097_SET_TWO_SIDED_STENCIL_TEST_ENABLE: { - m_set_two_sided_stencil_test_enable = ARGS(0) ? true : false; + const u32 value = ARGS(0); + Enable(cmd, ARGS(0)); } break; @@ -1283,84 +1284,85 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV4097_SET_STENCIL_MASK: { + const u32 value = ARGS(0); m_set_stencil_mask = true; - m_stencil_mask = ARGS(0); + StencilMask(value); } break; case NV4097_SET_STENCIL_FUNC: { - m_set_stencil_func = true; - m_stencil_func = ARGS(0); - - if (count >= 2) + if (count == 3) { - m_set_stencil_func_ref = true; + m_set_stencil_func = true; + m_stencil_func = ARGS(0); m_stencil_func_ref = ARGS(1); - - if (count >= 3) - { - m_set_stencil_func_mask = true; - m_stencil_func_mask = ARGS(2); - } + m_stencil_func_mask = ARGS(2); + StencilFunc(m_stencil_func, m_stencil_func_ref, m_stencil_func_mask); } } break; case NV4097_SET_STENCIL_FUNC_REF: { - m_set_stencil_func_ref = true; m_stencil_func_ref = ARGS(0); + + if (m_set_stencil_func) + { + StencilFunc(m_stencil_func, m_stencil_func_ref, m_stencil_func_mask); + } } break; case NV4097_SET_STENCIL_FUNC_MASK: { - m_set_stencil_func_mask = true; m_stencil_func_mask = ARGS(0); + + if (m_set_stencil_func) + { + StencilFunc(m_stencil_func, m_stencil_func_ref, m_stencil_func_mask); + } } break; case NV4097_SET_STENCIL_OP_FAIL: { - m_set_stencil_fail = true; - m_stencil_fail = ARGS(0); - - if (count >= 2) + if (count == 3) { - m_set_stencil_zfail = true; + m_set_stencil_op_fail = true; + m_stencil_fail = ARGS(0); m_stencil_zfail = ARGS(1); - - if (count >= 3) - { - m_set_stencil_zpass = true; - m_stencil_zpass = ARGS(2); - } + m_stencil_zpass = ARGS(2); + StencilOp(m_stencil_fail, m_stencil_zfail, m_stencil_zpass); } } break; case NV4097_SET_BACK_STENCIL_MASK: { - m_set_back_stencil_mask = true; m_back_stencil_mask = ARGS(0); + + StencilMaskSeparate(0, m_back_stencil_mask); // GL_BACK + + if (m_set_stencil_mask) + { + StencilMaskSeparate(1, m_stencil_mask); // GL_FRONT + } } break; case NV4097_SET_BACK_STENCIL_FUNC: { - m_set_back_stencil_func = true; - m_back_stencil_func = ARGS(0); - - if (count >= 2) + if (count == 3) { - m_set_back_stencil_func_ref = true; + m_set_back_stencil_func = true; + m_back_stencil_func = ARGS(0); m_back_stencil_func_ref = ARGS(1); - - if (count >= 3) + m_back_stencil_func_mask = ARGS(2); + StencilFuncSeparate(0, m_back_stencil_func, m_back_stencil_func_ref, m_back_stencil_func_mask); // GL_BACK + if (m_set_stencil_func) { - m_set_back_stencil_func_mask = true; - m_back_stencil_func_mask = ARGS(2); + StencilFuncSeparate(1, m_stencil_func, m_stencil_func_ref, m_stencil_func_mask); // GL_FRONT } } } @@ -1368,34 +1370,52 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV4097_SET_BACK_STENCIL_FUNC_REF: { - m_set_back_stencil_func_ref = true; m_back_stencil_func_ref = ARGS(0); + + if (m_set_back_stencil_func) + { + StencilFuncSeparate(0, m_back_stencil_func, m_back_stencil_func_ref, m_back_stencil_func_mask); // GL_BACK + + if (m_set_stencil_func) + { + StencilFuncSeparate(1, m_stencil_func, m_stencil_func_ref, m_stencil_func_mask); // GL_FRONT + } + } + } break; case NV4097_SET_BACK_STENCIL_FUNC_MASK: { - m_set_back_stencil_func_mask = true; m_back_stencil_func_mask = ARGS(0); + + if (m_set_back_stencil_func) + { + StencilFuncSeparate(0, m_back_stencil_func, m_back_stencil_func_ref, m_back_stencil_func_mask); // GL_BACK + + if (m_set_stencil_func) + { + StencilFuncSeparate(1, m_stencil_func, m_stencil_func_ref, m_stencil_func_mask); // GL_FRONT + } + } } break; case NV4097_SET_BACK_STENCIL_OP_FAIL: { - m_set_stencil_fail = true; - m_stencil_fail = ARGS(0); - - if (count >= 2) + if (count == 3) { - m_set_back_stencil_zfail = true; + m_back_stencil_fail = ARGS(0); m_back_stencil_zfail = ARGS(1); + m_back_stencil_zpass = ARGS(2); + StencilOpSeparate(0, m_back_stencil_fail, m_back_stencil_zfail, m_back_stencil_zpass); // GL_BACK - if (count >= 3) + if (m_set_stencil_op_fail) { - m_set_back_stencil_zpass = true; - m_back_stencil_zpass = ARGS(2); + StencilOpSeparate(1, m_stencil_fail, m_stencil_zfail, m_stencil_zpass); // GL_FRONT } } + } break; @@ -1764,9 +1784,11 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV4097_SET_POLYGON_STIPPLE_PATTERN: { + u32 pattern[32]; for (u32 i = 0; i < 32; i++) { - m_polygon_stipple_pattern[i] = ARGS(i); + pattern[i] = ARGS(i); + PolygonStipple(pattern[i]); } } break; @@ -2179,9 +2201,9 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const { const u32 cause = ARGS(0); auto cb = m_user_handler; - Emu.GetCallbackManager().Async([cb, cause]() + Emu.GetCallbackManager().Async([cb, cause](PPUThread& CPU) { - cb(cause); + cb(CPU, cause); }); } break; @@ -2326,31 +2348,24 @@ void RSXThread::Task() OnInitThread(); m_last_flip_time = get_system_time() - 1000000; - volatile bool is_vblank_stopped = false; - thread vblank("VBlank thread", [&]() + thread_t vblank("VBlank thread", true /* autojoin */, [this]() { const u64 start_time = get_system_time(); m_vblank_count = 0; - while (!TestDestroy()) + while (!TestDestroy() && !Emu.IsStopped()) { - if (Emu.IsStopped()) - { - LOG_WARNING(RSX, "VBlank thread aborted"); - return; - } - if (get_system_time() - start_time > m_vblank_count * 1000000 / 60) { m_vblank_count++; if (m_vblank_handler) { auto cb = m_vblank_handler; - Emu.GetCallbackManager().Async([cb]() + Emu.GetCallbackManager().Async([cb](PPUThread& CPU) { - cb(1); + cb(CPU, 1); }); } continue; @@ -2358,17 +2373,14 @@ void RSXThread::Task() std::this_thread::sleep_for (std::chrono::milliseconds(1)); // hack } - - is_vblank_stopped = true; }); - vblank.detach(); while (!TestDestroy()) try { if (Emu.IsStopped()) { LOG_WARNING(RSX, "RSX thread aborted"); - return; + break; } std::lock_guard lock(m_cs_main); @@ -2387,7 +2399,7 @@ void RSXThread::Task() m_sem_flush.post_and_wait(); } - std::this_thread::sleep_for (std::chrono::milliseconds(1)); // hack + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack continue; } @@ -2454,24 +2466,17 @@ void RSXThread::Task() value += (count + 1) * 4; }); } - catch (const std::string& e) { LOG_ERROR(RSX, "Exception: %s", e.c_str()); Emu.Pause(); } - catch (const char* e) { LOG_ERROR(RSX, "Exception: %s", e); Emu.Pause(); } - while (!is_vblank_stopped) - { - std::this_thread::sleep_for (std::chrono::milliseconds(1)); // hack - } - LOG_NOTICE(RSX, "RSX thread ended"); OnExitThread(); @@ -2500,7 +2505,7 @@ u32 RSXThread::ReadIO32(u32 addr) u32 value; if (!Memory.RSXIOMem.Read32(addr, &value)) { - throw fmt::Format("%s(rsxio_addr=0x%x): RSXIO memory not mapped", __FUNCTION__, addr); + throw fmt::Format("%s(addr=0x%x): RSXIO memory not mapped", __FUNCTION__, addr); } return value; } @@ -2509,6 +2514,6 @@ void RSXThread::WriteIO32(u32 addr, u32 value) { if (!Memory.RSXIOMem.Write32(addr, value)) { - throw fmt::Format("%s(rsxio_addr=0x%x): RSXIO memory not mapped", __FUNCTION__, addr); + throw fmt::Format("%s(addr=0x%x): RSXIO memory not mapped", __FUNCTION__, addr); } } diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index ed74dbf027..618573d21a 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -307,6 +307,7 @@ public: u32 m_back_stencil_zfail; bool m_set_back_stencil_zpass; u32 m_back_stencil_zpass; + bool m_set_stencil_op_fail; // Line width bool m_set_line_width; @@ -578,6 +579,7 @@ protected: m_set_back_stencil_fail = false; m_set_back_stencil_zfail = false; m_set_back_stencil_zpass = false; + m_set_stencil_op_fail = false; m_set_point_sprite_control = false; m_set_point_size = false; m_set_line_width = false; @@ -643,9 +645,10 @@ protected: virtual void DepthMask(u32 flag) = 0; virtual void PolygonMode(u32 face, u32 mode) = 0; virtual void PointSize(float size) = 0; - virtual void LogicOp(u32 opcdoe) = 0; + virtual void LogicOp(u32 opcode) = 0; virtual void LineWidth(float width) = 0; virtual void LineStipple(u16 factor, u16 pattern) = 0; + virtual void PolygonStipple(u32 pattern) = 0; virtual void PrimitiveRestartIndex(u32 index) = 0; virtual void CullFace(u32 mode) = 0; virtual void FrontFace(u32 mode) = 0; @@ -660,6 +663,12 @@ protected: virtual void ShadeModel(u32 mode) = 0; virtual void DepthBoundsEXT(float min, float max) = 0; virtual void Scissor(u16 x, u16 y, u16 width, u16 height) = 0; + virtual void StencilOp(u32 fail, u32 zfail, u32 zpass) = 0; + virtual void StencilMask(u32 mask) = 0; + virtual void StencilFunc(u32 func, u32 ref, u32 mask) = 0; + virtual void StencilOpSeparate(u32 mode, u32 fail, u32 zfail, u32 zpass) = 0; + virtual void StencilMaskSeparate(u32 mode, u32 mask) = 0; + virtual void StencilFuncSeparate(u32 mode, u32 func, u32 ref, u32 mask) = 0; virtual void Flip() = 0; void LoadVertexData(u32 first, u32 count) diff --git a/rpcs3/Emu/SysCalls/CB_FUNC.h b/rpcs3/Emu/SysCalls/CB_FUNC.h index 35588da48a..403a703db5 100644 --- a/rpcs3/Emu/SysCalls/CB_FUNC.h +++ b/rpcs3/Emu/SysCalls/CB_FUNC.h @@ -24,9 +24,9 @@ namespace cb_detail { static_assert(sizeof(T) <= 8, "Invalid callback argument type for ARG_GENERAL"); - __forceinline static void set_value(PPUThread& CPU, const T arg) + __forceinline static void set_value(PPUThread& CPU, const T& arg) { - (T&)CPU.GPR[g_count + 2] = arg; + CPU.GPR[g_count + 2] = cast_to_ppu_gpr(arg); } }; @@ -35,9 +35,9 @@ namespace cb_detail { static_assert(sizeof(T) <= 8, "Invalid callback argument type for ARG_FLOAT"); - __forceinline static void set_value(PPUThread& CPU, const T arg) + __forceinline static void set_value(PPUThread& CPU, const T& arg) { - CPU.FPR[f_count] = arg; + CPU.FPR[f_count] = static_cast(arg); } }; @@ -46,9 +46,9 @@ namespace cb_detail { static_assert(std::is_same::value, "Invalid callback argument type for ARG_VECTOR"); - __forceinline static void set_value(PPUThread& CPU, const T arg) + __forceinline static void set_value(PPUThread& CPU, const T& arg) { - (T&)CPU.VPR[v_count + 1] = arg; + CPU.VPR[v_count + 1] = arg; } }; @@ -59,13 +59,11 @@ namespace cb_detail static_assert(v_count <= 12, "TODO: Unsupported stack argument type (vector)"); static_assert(sizeof(T) <= 8, "Invalid callback argument type for ARG_STACK"); - __forceinline static void set_value(PPUThread& CPU, const T arg) + __forceinline static void set_value(PPUThread& CPU, const T& arg) { const int stack_pos = 0x70 + (g_count - 9) * 8 - FIXED_STACK_FRAME_SIZE; static_assert(stack_pos < 0, "TODO: Increase fixed stack frame size (arg count limit broken)"); - u64 value = 0; - (T&)value = arg; - vm::write64(CPU.GPR[1] + stack_pos, value); + vm::write64(CPU.GPR[1] + stack_pos, cast_to_ppu_gpr(arg)); } }; @@ -103,7 +101,7 @@ namespace cb_detail __forceinline static T get_value(const PPUThread& CPU) { - return (T&)CPU.GPR[3]; + return cast_from_ppu_gpr(CPU.GPR[3]); } }; @@ -114,18 +112,18 @@ namespace cb_detail __forceinline static T get_value(const PPUThread& CPU) { - return (T)CPU.FPR[1]; + return static_cast(CPU.FPR[1]); } }; template struct _func_res { - static_assert(sizeof(T) == 16, "Invalid callback result type for ARG_VECTOR"); + static_assert(std::is_same::value, "Invalid callback result type for ARG_VECTOR"); __forceinline static T get_value(const PPUThread& CPU) { - return (T&)CPU.VPR[2]; + return CPU.VPR[2]; } }; @@ -165,29 +163,31 @@ namespace cb_detail namespace vm { template - __forceinline RT _ptr_base::call(CPUThread& CPU, T... args) const + __forceinline RT _ptr_base::operator()(CPUThread& CPU, T... args) const { - const u32 pc = vm::get_ref>(m_addr); - const u32 rtoc = vm::get_ref>(m_addr + 4); + auto data = vm::get_ptr>(vm::cast(m_addr)); + const u32 pc = data[0]; + const u32 rtoc = data[1]; + assert(CPU.GetType() == CPU_THREAD_PPU); return cb_detail::_func_caller::call(static_cast(CPU), pc, rtoc, args...); } template - __forceinline RT _ptr_base::operator ()(T... args) const + __forceinline RT _ptr_base::operator()(T... args) const { - return call(GetCurrentPPUThread(), args...); + return operator()(GetCurrentPPUThread(), args...); } } template -RT cb_call(PPUThread& CPU, u32 pc, u32 rtoc, T... args) +__forceinline RT cb_call(PPUThread& CPU, u32 pc, u32 rtoc, T... args) { return cb_detail::_func_caller::call(CPU, pc, rtoc, args...); } -template -void cb_call(PPUThread& CPU, u32 pc, u32 rtoc, T... args) -{ - cb_detail::_func_caller::call(CPU, pc, rtoc, args...); -} \ No newline at end of file +//template +//void cb_call(PPUThread& CPU, u32 pc, u32 rtoc, T... args) +//{ +// cb_detail::_func_caller::call(CPU, pc, rtoc, args...); +//} diff --git a/rpcs3/Emu/SysCalls/Callback.cpp b/rpcs3/Emu/SysCalls/Callback.cpp index 71fa8ba830..b0d10c5316 100644 --- a/rpcs3/Emu/SysCalls/Callback.cpp +++ b/rpcs3/Emu/SysCalls/Callback.cpp @@ -7,25 +7,33 @@ #include "Emu/ARMv7/ARMv7Thread.h" #include "Callback.h" -void CallbackManager::Register(const std::function& func) +void CallbackManager::Register(const std::function& func) { std::lock_guard lock(m_mutex); - m_cb_list.push_back(func); + m_cb_list.push_back([=](CPUThread& CPU) -> s32 + { + assert(CPU.GetType() == CPU_THREAD_PPU); + return func(static_cast(CPU)); + }); } -void CallbackManager::Async(const std::function& func) +void CallbackManager::Async(const std::function& func) { std::lock_guard lock(m_mutex); - m_async_list.push_back(func); + m_async_list.push_back([=](CPUThread& CPU) + { + assert(CPU.GetType() == CPU_THREAD_PPU); + func(static_cast(CPU)); + }); + m_cb_thread->Notify(); } -bool CallbackManager::Check(s32& result) +bool CallbackManager::Check(CPUThread& CPU, s32& result) { - std::function func = nullptr; - + std::function func; { std::lock_guard lock(m_mutex); @@ -38,7 +46,7 @@ bool CallbackManager::Check(s32& result) if (func) { - result = func(); + result = func(CPU); return true; } else @@ -74,13 +82,13 @@ void CallbackManager::Init() static_cast(m_cb_thread)->DoRun(); } - thread cb_async_thread("CallbackManager::Async() thread", [this]() + thread_t cb_async_thread("CallbackManager thread", [this]() { SetCurrentNamedThread(m_cb_thread); while (!Emu.IsStopped()) { - std::function func = nullptr; + std::function func; { std::lock_guard lock(m_mutex); @@ -93,14 +101,13 @@ void CallbackManager::Init() if (func) { - func(); + func(*m_cb_thread); continue; } + m_cb_thread->WaitForAnySignal(); } }); - - cb_async_thread.detach(); } void CallbackManager::Clear() @@ -110,3 +117,40 @@ void CallbackManager::Clear() m_cb_list.clear(); m_async_list.clear(); } + +u64 CallbackManager::AddPauseCallback(const std::function& func) +{ + std::lock_guard lock(m_mutex); + + m_pause_cb_list.push_back({ func, next_tag }); + return next_tag++; +} + +void CallbackManager::RemovePauseCallback(const u64 tag) +{ + std::lock_guard lock(m_mutex); + + for (auto& data : m_pause_cb_list) + { + if (data.tag == tag) + { + m_pause_cb_list.erase(m_pause_cb_list.begin() + (&data - m_pause_cb_list.data())); + return; + } + } + + assert(!"CallbackManager()::RemovePauseCallback(): tag not found"); +} + +void CallbackManager::RunPauseCallbacks(const bool is_paused) +{ + std::lock_guard lock(m_mutex); + + for (auto& data : m_pause_cb_list) + { + if (data.cb) + { + data.cb(is_paused); + } + } +} diff --git a/rpcs3/Emu/SysCalls/Callback.h b/rpcs3/Emu/SysCalls/Callback.h index ba16b38830..2e8c64cf92 100644 --- a/rpcs3/Emu/SysCalls/Callback.h +++ b/rpcs3/Emu/SysCalls/Callback.h @@ -1,22 +1,64 @@ #pragma once class CPUThread; +class PPUThread; + +typedef void(PauseResumeCB)(bool is_paused); class CallbackManager { - std::vector> m_cb_list; - std::vector> m_async_list; - CPUThread* m_cb_thread; std::mutex m_mutex; + std::vector> m_cb_list; + std::vector> m_async_list; + CPUThread* m_cb_thread; + + struct PauseResumeCBS + { + std::function cb; + u64 tag; + }; + + u64 next_tag; // not initialized, only increased + std::vector m_pause_cb_list; public: - void Register(const std::function& func); // register callback (called in Check() method) + void Register(const std::function& func); // register callback (called in Check() method) - void Async(const std::function& func); // register callback for callback thread (called immediately) + void Async(const std::function& func); // register callback for callback thread (called immediately) - bool Check(s32& result); // call one callback registered by Register() method + bool Check(CPUThread& CPU, s32& result); // call one callback registered by Register() method void Init(); void Clear(); + + u64 AddPauseCallback(const std::function& func); // register callback for pausing/resuming emulation events + void RemovePauseCallback(const u64 tag); // unregister callback (uses the result of AddPauseCallback() function) + void RunPauseCallbacks(const bool is_paused); +}; + +class PauseCallbackRegisterer +{ + CallbackManager& cb_manager; + u64 cb_tag; + +public: + PauseCallbackRegisterer(CallbackManager& cb_manager, const std::function& func) + : cb_manager(cb_manager) + , cb_tag(cb_manager.AddPauseCallback(func)) + { + } + + PauseCallbackRegisterer() = delete; + PauseCallbackRegisterer(const PauseCallbackRegisterer& right) = delete; + PauseCallbackRegisterer(PauseCallbackRegisterer&& right) = delete; + + ~PauseCallbackRegisterer() + { + cb_manager.RemovePauseCallback(cb_tag); + } + + PauseCallbackRegisterer& operator =(const PauseCallbackRegisterer& right) = delete; + PauseCallbackRegisterer& operator =(PauseCallbackRegisterer&& right) = delete; + }; diff --git a/rpcs3/Emu/SysCalls/LogBase.cpp b/rpcs3/Emu/SysCalls/LogBase.cpp index 0f1a48edf4..f0ff6628fb 100644 --- a/rpcs3/Emu/SysCalls/LogBase.cpp +++ b/rpcs3/Emu/SysCalls/LogBase.cpp @@ -9,25 +9,15 @@ bool LogBase::CheckLogging() const return Ini.HLELogging.GetValue() || m_logging; } -void LogBase::LogOutput(LogType type, const char* info, const std::string& text) const +void LogBase::LogOutput(LogType type, const std::string& text) const { switch (type) { - case LogNotice: LOG_NOTICE(HLE, "%s%s%s", GetName().c_str(), info, text.c_str()); break; - case LogSuccess: LOG_SUCCESS(HLE, "%s%s%s", GetName().c_str(), info, text.c_str()); break; - case LogWarning: LOG_WARNING(HLE, "%s%s%s", GetName().c_str(), info, text.c_str()); break; - case LogError: LOG_ERROR(HLE, "%s%s%s", GetName().c_str(), info, text.c_str()); break; - } -} - -void LogBase::LogOutput(LogType type, const u32 id, const char* info, const std::string& text) const -{ - switch (type) - { - case LogNotice: LOG_NOTICE(HLE, "%s[%d]%s%s", GetName().c_str(), id, info, text.c_str()); break; - case LogSuccess: LOG_SUCCESS(HLE, "%s[%d]%s%s", GetName().c_str(), id, info, text.c_str()); break; - case LogWarning: LOG_WARNING(HLE, "%s[%d]%s%s", GetName().c_str(), id, info, text.c_str()); break; - case LogError: LOG_ERROR(HLE, "%s[%d]%s%s", GetName().c_str(), id, info, text.c_str()); break; + case LogNotice: LOG_NOTICE(HLE, GetName() + ": " + text); break; + case LogSuccess: LOG_SUCCESS(HLE, GetName() + ": " + text); break; + case LogWarning: LOG_WARNING(HLE, GetName() + ": " + text); break; + case LogError: LOG_ERROR(HLE, GetName() + " error: " + text); break; + case LogTodo: LOG_ERROR(HLE, GetName() + " TODO: " + text); break; } } @@ -60,22 +50,22 @@ void hle::error::print(const char* func) { if (func) { - base->Error("%s(): %s (0x%X)", func, text.c_str(), code); + base->Error("%s(): %s (0x%x)", func, text.c_str(), code); } else { - base->Error("%s (0x%X)", text.c_str(), code); + base->Error("%s (0x%x)", text.c_str(), code); } } else { if (func) { - LOG_ERROR(HLE, "%s(): %s (0x%X)", func, text.c_str(), code); + LOG_ERROR(HLE, "%s(): %s (0x%x)", func, text.c_str(), code); } else { - LOG_ERROR(HLE, "%s (0x%X)", text.c_str(), code); + LOG_ERROR(HLE, "%s (0x%x)", text.c_str(), code); } } } diff --git a/rpcs3/Emu/SysCalls/LogBase.h b/rpcs3/Emu/SysCalls/LogBase.h index d3aa862efb..7f496d6c6e 100644 --- a/rpcs3/Emu/SysCalls/LogBase.h +++ b/rpcs3/Emu/SysCalls/LogBase.h @@ -11,10 +11,16 @@ class LogBase LogSuccess, LogWarning, LogError, + LogTodo, }; - void LogOutput(LogType type, const char* info, const std::string& text) const; - void LogOutput(LogType type, const u32 id, const char* info, const std::string& text) const; + void LogOutput(LogType type, const std::string& text) const; + + template + __noinline void LogPrepare(LogType type, const char* fmt, size_t len, Targs... args) const + { + LogOutput(type, fmt::detail::format(fmt, len, args...)); + } public: void SetLogging(bool value) @@ -29,17 +35,14 @@ public: virtual const std::string& GetName() const = 0; - template __noinline void Notice(const u32 id, const char* fmt, Targs... args) const + template + __forceinline void Notice(const char* fmt, Targs... args) const { - LogOutput(LogNotice, id, " : ", fmt::Format(fmt, args...)); + LogPrepare(LogNotice, fmt, strlen(fmt), fmt::do_unveil(args)...); } - template __noinline void Notice(const char* fmt, Targs... args) const - { - LogOutput(LogNotice, ": ", fmt::Format(fmt, args...)); - } - - template __forceinline void Log(const char* fmt, Targs... args) const + template + __forceinline void Log(const char* fmt, Targs... args) const { if (CheckLogging()) { @@ -47,52 +50,28 @@ public: } } - template __forceinline void Log(const u32 id, const char* fmt, Targs... args) const + template + __forceinline void Success(const char* fmt, Targs... args) const { - if (CheckLogging()) - { - Notice(id, fmt, args...); - } + LogPrepare(LogSuccess, fmt, strlen(fmt), fmt::do_unveil(args)...); } - template __noinline void Success(const u32 id, const char* fmt, Targs... args) const + template + __forceinline void Warning(const char* fmt, Targs... args) const { - LogOutput(LogSuccess, id, " : ", fmt::Format(fmt, args...)); + LogPrepare(LogWarning, fmt, strlen(fmt), fmt::do_unveil(args)...); } - template __noinline void Success(const char* fmt, Targs... args) const + template + __forceinline void Error(const char* fmt, Targs... args) const { - LogOutput(LogSuccess, ": ", fmt::Format(fmt, args...)); + LogPrepare(LogError, fmt, strlen(fmt), fmt::do_unveil(args)...); } - template __noinline void Warning(const u32 id, const char* fmt, Targs... args) const + template + __forceinline void Todo(const char* fmt, Targs... args) const { - LogOutput(LogWarning, id, " warning: ", fmt::Format(fmt, args...)); - } - - template __noinline void Warning(const char* fmt, Targs... args) const - { - LogOutput(LogWarning, " warning: ", fmt::Format(fmt, args...)); - } - - template __noinline void Error(const u32 id, const char* fmt, Targs... args) const - { - LogOutput(LogError, id, " error: ", fmt::Format(fmt, args...)); - } - - template __noinline void Error(const char* fmt, Targs... args) const - { - LogOutput(LogError, " error: ", fmt::Format(fmt, args...)); - } - - template __noinline void Todo(const u32 id, const char* fmt, Targs... args) const - { - LogOutput(LogError, id, " TODO: ", fmt::Format(fmt, args...)); - } - - template __noinline void Todo(const char* fmt, Targs... args) const - { - LogOutput(LogError, " TODO: ", fmt::Format(fmt, args...)); + LogPrepare(LogTodo, fmt, strlen(fmt), fmt::do_unveil(args)...); } }; diff --git a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp index 139ab029f0..75a8763003 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp @@ -174,7 +174,7 @@ next: buf_size -= adec.reader.size; res += adec.reader.size; - adec.cbFunc.call(*adec.adecCb, adec.id, CELL_ADEC_MSG_TYPE_AUDONE, adec.task.au.auInfo_addr, adec.cbArg); + adec.cbFunc(*adec.adecCb, adec.id, CELL_ADEC_MSG_TYPE_AUDONE, adec.task.au.auInfo_addr, adec.cbArg); adec.job.pop(adec.task); @@ -224,7 +224,7 @@ u32 adecOpen(AudioDecoder* adec_ptr) adec.id = adec_id; adec.adecCb = (PPUThread*)&Emu.GetCPU().AddThread(CPU_THREAD_PPU); - adec.adecCb->SetName("Audio Decoder[" + std::to_string(adec_id) + "] Callback"); + adec.adecCb->SetName(fmt::format("AudioDecoder[%d] Callback", adec_id)); adec.adecCb->SetEntry(0); adec.adecCb->SetPrio(1001); adec.adecCb->SetStackSize(0x10000); @@ -232,11 +232,9 @@ u32 adecOpen(AudioDecoder* adec_ptr) adec.adecCb->InitRegs(); adec.adecCb->DoRun(); - thread t("Audio Decoder[" + std::to_string(adec_id) + "] Thread", [adec_ptr, sptr]() + thread_t t(fmt::format("AudioDecoder[%d] Thread", adec_id), [adec_ptr, sptr]() { AudioDecoder& adec = *adec_ptr; - cellAdec->Notice("Audio Decoder thread started"); - AdecTask& task = adec.task; while (true) @@ -279,7 +277,7 @@ u32 adecOpen(AudioDecoder* adec_ptr) { // TODO: finalize cellAdec->Warning("adecEndSeq:"); - adec.cbFunc.call(*adec.adecCb, adec.id, CELL_ADEC_MSG_TYPE_SEQDONE, CELL_OK, adec.cbArg); + adec.cbFunc(*adec.adecCb, adec.id, CELL_ADEC_MSG_TYPE_SEQDONE, CELL_OK, adec.cbArg); adec.just_finished = true; break; @@ -455,12 +453,12 @@ u32 adecOpen(AudioDecoder* adec_ptr) if (adec.frames.push(frame, &adec.is_closed)) { frame.data = nullptr; // to prevent destruction - adec.cbFunc.call(*adec.adecCb, adec.id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, adec.cbArg); + adec.cbFunc(*adec.adecCb, adec.id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, adec.cbArg); } } } - adec.cbFunc.call(*adec.adecCb, adec.id, CELL_ADEC_MSG_TYPE_AUDONE, task.au.auInfo_addr, adec.cbArg); + adec.cbFunc(*adec.adecCb, adec.id, CELL_ADEC_MSG_TYPE_AUDONE, task.au.auInfo_addr, adec.cbArg); break; } @@ -471,18 +469,14 @@ u32 adecOpen(AudioDecoder* adec_ptr) default: { - ADEC_ERROR("Audio Decoder thread error: unknown task(%d)", task.type); + ADEC_ERROR("AudioDecoder thread error: unknown task(%d)", task.type); } } } adec.is_finished = true; - if (adec.is_closed) cellAdec->Notice("Audio Decoder thread ended"); - if (Emu.IsStopped()) cellAdec->Warning("Audio Decoder thread aborted"); }); - t.detach(); - return adec_id; } @@ -535,7 +529,7 @@ int cellAdecOpen(vm::ptr type, vm::ptr res, vm:: if (!adecCheckType(type->audioCodecType)) return CELL_ADEC_ERROR_ARG; - *handle = adecOpen(new AudioDecoder(type->audioCodecType, res->startAddr, res->totalMemSize, vm::ptr::make(cb->cbFunc.addr()), cb->cbArg)); + *handle = adecOpen(new AudioDecoder(type->audioCodecType, res->startAddr, res->totalMemSize, cb->cbFunc.to_le(), cb->cbArg)); return CELL_OK; } @@ -547,7 +541,7 @@ int cellAdecOpenEx(vm::ptr type, vm::ptr res, if (!adecCheckType(type->audioCodecType)) return CELL_ADEC_ERROR_ARG; - *handle = adecOpen(new AudioDecoder(type->audioCodecType, res->startAddr, res->totalMemSize, vm::ptr::make(cb->cbFunc.addr()), cb->cbArg)); + *handle = adecOpen(new AudioDecoder(type->audioCodecType, res->startAddr, res->totalMemSize, cb->cbFunc.to_le(), cb->cbArg)); return CELL_OK; } @@ -617,7 +611,7 @@ int cellAdecStartSeq(u32 handle, u32 param_addr) { auto param = vm::ptr::make(param_addr); - cellAdec->Todo("*** CellAdecParamMP3: bw_pcm=%d", param->bw_pcm.ToLE()); + cellAdec->Todo("*** CellAdecParamMP3: bw_pcm=%d", param->bw_pcm); break; } default: diff --git a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp index 69b95612cd..56cd7a7e79 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp @@ -2,6 +2,7 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/SysCalls/Modules.h" +#include "Emu/SysCalls/Callback.h" #include "Emu/Memory/atomic_type.h" #include "rpcs3/Ini.h" @@ -11,749 +12,752 @@ #include "Emu/Event.h" #include "Emu/Audio/AudioManager.h" #include "Emu/Audio/AudioDumper.h" -#include "Emu/Audio/cellAudio.h" + +#include "cellAudio.h" Module *cellAudio = nullptr; -static std::mutex audioMutex; +AudioConfig g_audio; -AudioConfig m_config; - -static const bool g_is_u16 = Ini.AudioConvertToU16.GetValue(); - -// libaudio Functions - -#define BUFFER_NUM 32 -#define BUFFER_SIZE 256 -int cellAudioInit() +s32 cellAudioInit() { cellAudio->Warning("cellAudioInit()"); - if (m_config.m_is_audio_initialized) + if (!g_audio.state.compare_and_swap_test(AUDIO_STATE_NOT_INITIALIZED, AUDIO_STATE_INITIALIZED)) { return CELL_AUDIO_ERROR_ALREADY_INIT; } - m_config.m_is_audio_initialized = true; - m_config.start_time = 0; - m_config.counter = 0; + // clear ports + for (auto& port : g_audio.ports) + { + port.state.write_relaxed(AUDIO_PORT_STATE_CLOSED); + } - // alloc memory - m_config.m_buffer = (u32)Memory.Alloc(128 * 1024 * m_config.AUDIO_PORT_COUNT, 1024); - memset(vm::get_ptr(m_config.m_buffer), 0, 128 * 1024 * m_config.AUDIO_PORT_COUNT); - m_config.m_indexes = (u32)Memory.Alloc(sizeof(u64) * m_config.AUDIO_PORT_COUNT, 16); - memset(vm::get_ptr(m_config.m_indexes), 0, sizeof(u64) * m_config.AUDIO_PORT_COUNT); + // reset variables + g_audio.start_time = 0; + g_audio.counter = 0; + g_audio.keys.clear(); + g_audio.start_time = get_system_time(); - thread t("Audio Thread", []() + // alloc memory (only once until the emulator is stopped) + g_audio.buffer = g_audio.buffer ? g_audio.buffer : vm::cast(Memory.MainMem.AllocAlign(AUDIO_PORT_OFFSET * AUDIO_PORT_COUNT, 4096)); + g_audio.indexes = g_audio.indexes ? g_audio.indexes : vm::cast(Memory.MainMem.AllocAlign(sizeof(u64) * AUDIO_PORT_COUNT, __alignof(u64))); + + // clear memory + memset(vm::get_ptr(g_audio.buffer), 0, AUDIO_PORT_OFFSET * AUDIO_PORT_COUNT); + memset(vm::get_ptr(g_audio.indexes), 0, sizeof(u64) * AUDIO_PORT_COUNT); + + // start audio thread + g_audio.audio_thread.start([]() + { + const bool do_dump = Ini.AudioDumpToFile.GetValue(); + + AudioDumper m_dump; + if (do_dump && !m_dump.Init(2)) // Init AudioDumper for 2 channels { - AudioDumper m_dump(8); // WAV file header (8 ch) + throw "AudioDumper::Init() failed"; + } - bool do_dump = Ini.AudioDumpToFile.GetValue(); - - if (do_dump && !m_dump.Init()) + float buf2ch[2 * BUFFER_SIZE]; // intermediate buffer for 2 channels + float buf8ch[8 * BUFFER_SIZE]; // intermediate buffer for 8 channels + + static const size_t out_buffer_size = 8 * BUFFER_SIZE; // output buffer for 8 channels + + std::unique_ptr out_buffer[BUFFER_NUM]; + + for (u32 i = 0; i < BUFFER_NUM; i++) + { + out_buffer[i].reset(new float[out_buffer_size] {}); + } + + squeue_t out_queue; + + std::vector keys; + + thread_t iat("Internal Audio Thread", true /* autojoin */, [&out_queue]() + { + const bool use_u16 = Ini.AudioConvertToU16.GetValue(); + + Emu.GetAudioManager().GetAudioOut().Init(); + + bool opened = false; + float* buffer; + + while (out_queue.pop(buffer, [](){ return g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED; })) { - cellAudio->Error("cellAudioInit(): AudioDumper::Init() failed"); - return; - } - - cellAudio->Notice("Audio thread started"); - - if (Ini.AudioDumpToFile.GetValue()) - m_dump.WriteHeader(); - - float buf2ch[2 * BUFFER_SIZE]; // intermediate buffer for 2 channels - float buf8ch[8 * BUFFER_SIZE]; // intermediate buffer for 8 channels - - uint oal_buffer_offset = 0; - const uint oal_buffer_size = 2 * BUFFER_SIZE; - - std::unique_ptr oal_buffer[BUFFER_NUM]; - std::unique_ptr oal_buffer_float[BUFFER_NUM]; - - for (u32 i = 0; i < BUFFER_NUM; i++) - { - oal_buffer[i] = std::unique_ptr(new s16[oal_buffer_size] {} ); - oal_buffer_float[i] = std::unique_ptr(new float[oal_buffer_size] {} ); - } - - squeue_t queue; - squeue_t queue_float; - - std::vector keys; - - if(m_audio_out) - { - m_audio_out->Init(); - - // Note: What if the ini value changes? - if (g_is_u16) - m_audio_out->Open(oal_buffer[0].get(), oal_buffer_size * sizeof(s16)); - else - m_audio_out->Open(oal_buffer_float[0].get(), oal_buffer_size * sizeof(float)); - } - - m_config.start_time = get_system_time(); - - volatile bool internal_finished = false; - - thread iat("Internal Audio Thread", [oal_buffer_size, &queue, &queue_float, &internal_finished]() - { - while (true) - { - s16* oal_buffer = nullptr; - float* oal_buffer_float = nullptr; - - if (g_is_u16) - queue.pop(oal_buffer); - else - queue_float.pop(oal_buffer_float); - - if (g_is_u16) - { - if (oal_buffer) - { - m_audio_out->AddData(oal_buffer, oal_buffer_size * sizeof(s16)); - continue; - } - } - else - { - if (oal_buffer_float) - { - m_audio_out->AddData(oal_buffer_float, oal_buffer_size * sizeof(float)); - continue; - } - } - internal_finished = true; - return; - } - }); - iat.detach(); - - while (m_config.m_is_audio_initialized) - { - if (Emu.IsStopped()) - { - cellAudio->Warning("Audio thread aborted"); - goto abort; - } - - const u64 stamp0 = get_system_time(); - - // TODO: send beforemix event (in ~2,6 ms before mixing) - - // precise time of sleeping: 5,(3) ms (or 256/48000 sec) - if (m_config.counter * 256000000 / 48000 >= stamp0 - m_config.start_time) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - continue; - } - - m_config.counter++; - - const u32 oal_pos = m_config.counter % BUFFER_NUM; - - if (Emu.IsPaused()) - { - continue; - } - - bool first_mix = true; - - // mixing: - for (u32 i = 0; i < m_config.AUDIO_PORT_COUNT; i++) - { - if (!m_config.m_ports[i].m_is_audio_port_started) continue; - - AudioPortConfig& port = m_config.m_ports[i]; - - const u32 block_size = port.channel * 256; - const u32 position = port.tag % port.block; // old value - const u32 buf_addr = m_config.m_buffer + (i * 128 * 1024) + (position * block_size * sizeof(float)); - - auto buf = vm::get_ptr>(buf_addr); - - static const float k = 1.0f; // may be 1.0f - const float m = port.level; - - if (port.channel == 2) - { - if (first_mix) - { - for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) - { - // reverse byte order - const float left = buf[i + 0] * m; - const float right = buf[i + 1] * m; - - buf2ch[i + 0] = left; - buf2ch[i + 1] = right; - - buf8ch[i * 4 + 0] = left; - buf8ch[i * 4 + 1] = right; - buf8ch[i * 4 + 2] = 0.0f; - buf8ch[i * 4 + 3] = 0.0f; - buf8ch[i * 4 + 4] = 0.0f; - buf8ch[i * 4 + 5] = 0.0f; - buf8ch[i * 4 + 6] = 0.0f; - buf8ch[i * 4 + 7] = 0.0f; - } - first_mix = false; - } - else - { - for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) - { - const float left = buf[i + 0] * m; - const float right = buf[i + 1] * m; - - buf2ch[i + 0] += left; - buf2ch[i + 1] += right; - - buf8ch[i * 4 + 0] += left; - buf8ch[i * 4 + 1] += right; - } - } - } - else if (port.channel == 6) - { - if (first_mix) - { - for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) - { - const float left = buf[i * 3 + 0] * m; - const float right = buf[i * 3 + 1] * m; - const float center = buf[i * 3 + 2] * m; - const float low_freq = buf[i * 3 + 3] * m; - const float rear_left = buf[i * 3 + 4] * m; - const float rear_right = buf[i * 3 + 5] * m; - - const float mid = (center + low_freq) * 0.708f; - buf2ch[i + 0] = (left + rear_left + mid) * k; - buf2ch[i + 1] = (right + rear_right + mid) * k; - - buf8ch[i * 4 + 0] = left; - buf8ch[i * 4 + 1] = right; - buf8ch[i * 4 + 2] = center; - buf8ch[i * 4 + 3] = low_freq; - buf8ch[i * 4 + 4] = rear_left; - buf8ch[i * 4 + 5] = rear_right; - buf8ch[i * 4 + 6] = 0.0f; - buf8ch[i * 4 + 7] = 0.0f; - } - first_mix = false; - } - else - { - for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) - { - const float left = buf[i * 3 + 0] * m; - const float right = buf[i * 3 + 1] * m; - const float center = buf[i * 3 + 2] * m; - const float low_freq = buf[i * 3 + 3] * m; - const float rear_left = buf[i * 3 + 4] * m; - const float rear_right = buf[i * 3 + 5] * m; - - const float mid = (center + low_freq) * 0.708f; - buf2ch[i + 0] += (left + rear_left + mid) * k; - buf2ch[i + 1] += (right + rear_right + mid) * k; - - buf8ch[i * 4 + 0] += left; - buf8ch[i * 4 + 1] += right; - buf8ch[i * 4 + 2] += center; - buf8ch[i * 4 + 3] += low_freq; - buf8ch[i * 4 + 4] += rear_left; - buf8ch[i * 4 + 5] += rear_right; - } - } - } - else if (port.channel == 8) - { - if (first_mix) - { - for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) - { - const float left = buf[i * 4 + 0] * m; - const float right = buf[i * 4 + 1] * m; - const float center = buf[i * 4 + 2] * m; - const float low_freq = buf[i * 4 + 3] * m; - const float rear_left = buf[i * 4 + 4] * m; - const float rear_right = buf[i * 4 + 5] * m; - const float side_left = buf[i * 4 + 6] * m; - const float side_right = buf[i * 4 + 7] * m; - - const float mid = (center + low_freq) * 0.708f; - buf2ch[i + 0] = (left + rear_left + side_left + mid) * k; - buf2ch[i + 1] = (right + rear_right + side_right + mid) * k; - - buf8ch[i * 4 + 0] = left; - buf8ch[i * 4 + 1] = right; - buf8ch[i * 4 + 2] = center; - buf8ch[i * 4 + 3] = low_freq; - buf8ch[i * 4 + 4] = rear_left; - buf8ch[i * 4 + 5] = rear_right; - buf8ch[i * 4 + 6] = side_left; - buf8ch[i * 4 + 7] = side_right; - } - first_mix = false; - } - else - { - for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) - { - const float left = buf[i * 4 + 0] * m; - const float right = buf[i * 4 + 1] * m; - const float center = buf[i * 4 + 2] * m; - const float low_freq = buf[i * 4 + 3] * m; - const float rear_left = buf[i * 4 + 4] * m; - const float rear_right = buf[i * 4 + 5] * m; - const float side_left = buf[i * 4 + 6] * m; - const float side_right = buf[i * 4 + 7] * m; - - const float mid = (center + low_freq) * 0.708f; - buf2ch[i + 0] += (left + rear_left + side_left + mid) * k; - buf2ch[i + 1] += (right + rear_right + side_right + mid) * k; - - buf8ch[i * 4 + 0] += left; - buf8ch[i * 4 + 1] += right; - buf8ch[i * 4 + 2] += center; - buf8ch[i * 4 + 3] += low_freq; - buf8ch[i * 4 + 4] += rear_left; - buf8ch[i * 4 + 5] += rear_right; - buf8ch[i * 4 + 6] += side_left; - buf8ch[i * 4 + 7] += side_right; - } - } - } - - memset(buf, 0, block_size * sizeof(float)); - } - - // convert the data from float to u16 with clipping: - if (!first_mix) + if (use_u16) { + // convert the data from float to u16 with clipping: // 2x MULPS // 2x MAXPS (optional) // 2x MINPS (optional) // 2x CVTPS2DQ (converts float to s32) // PACKSSDW (converts s32 to s16 with signed saturation) - if (g_is_u16) + u16 buf_u16[out_buffer_size]; + for (size_t i = 0; i < out_buffer_size; i += 8) { - for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 8) - { - static const __m128 float2u16 = { 0x8000, 0x8000, 0x8000, 0x8000 }; - (__m128i&)(oal_buffer[oal_pos][oal_buffer_offset + i]) = _mm_packs_epi32( - _mm_cvtps_epi32(_mm_mul_ps((__m128&)(buf2ch[i]), float2u16)), - _mm_cvtps_epi32(_mm_mul_ps((__m128&)(buf2ch[i + 4]), float2u16))); - } - } - else - for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i++) - { - oal_buffer_float[oal_pos][oal_buffer_offset + i] = buf2ch[i]; - } - } - - //const u64 stamp1 = get_system_time(); - - if (first_mix) - { - if (g_is_u16) memset(&oal_buffer[oal_pos][0], 0, oal_buffer_size * sizeof(s16)); - else memset(&oal_buffer_float[oal_pos][0], 0, oal_buffer_size * sizeof(float)); - } - oal_buffer_offset += sizeof(buf2ch) / sizeof(float); - - if(oal_buffer_offset >= oal_buffer_size) - { - if(m_audio_out) - { - if (g_is_u16) - queue.push(&oal_buffer[oal_pos][0]); - - queue_float.push(&oal_buffer_float[oal_pos][0]); + static const __m128 float2u16 = { 0x8000, 0x8000, 0x8000, 0x8000 }; + (__m128i&)(buf_u16[i]) = _mm_packs_epi32( + _mm_cvtps_epi32(_mm_mul_ps((__m128&)(buffer[i]), float2u16)), + _mm_cvtps_epi32(_mm_mul_ps((__m128&)(buffer[i + 4]), float2u16))); } - oal_buffer_offset = 0; - } - - //const u64 stamp2 = get_system_time(); - - // send aftermix event (normal audio event) - { - std::lock_guard lock(audioMutex); - // update indexes: - auto indexes = vm::ptr::make(m_config.m_indexes); - for (u32 i = 0; i < m_config.AUDIO_PORT_COUNT; i++) + if (!opened) { - if (!m_config.m_ports[i].m_is_audio_port_started) continue; - - AudioPortConfig& port = m_config.m_ports[i]; - - u32 position = port.tag % port.block; // old value - port.counter = m_config.counter; - port.tag++; // absolute index of block that will be read - indexes[i] = (position + 1) % port.block; // write new value - } - // load keys: - keys.resize(m_config.m_keys.size()); - memcpy(keys.data(), m_config.m_keys.data(), sizeof(u64) * keys.size()); - } - for (u32 i = 0; i < keys.size(); i++) - { - // TODO: check event source - Emu.GetEventManager().SendEvent(keys[i], 0x10103000e010e07, 0, 0, 0); - } - - //const u64 stamp3 = get_system_time(); - - if (do_dump && !first_mix) - { - if (m_dump.GetCh() == 8) - { - if (m_dump.WriteData(&buf8ch, sizeof(buf8ch)) != sizeof(buf8ch)) // write file data - { - cellAudio->Error("cellAudioInit(): AudioDumper::WriteData() failed"); - goto abort; - } - } - else if (m_dump.GetCh() == 2) - { - if (m_dump.WriteData(&buf2ch, sizeof(buf2ch)) != sizeof(buf2ch)) // write file data - { - cellAudio->Error("cellAudioInit(): AudioDumper::WriteData() failed"); - goto abort; - } + Emu.GetAudioManager().GetAudioOut().Open(buf_u16, out_buffer_size * sizeof(u16)); + opened = true; } else { - cellAudio->Error("cellAudioInit(): unknown AudioDumper::GetCh() value (%d)", m_dump.GetCh()); - goto abort; + Emu.GetAudioManager().GetAudioOut().AddData(buf_u16, out_buffer_size * sizeof(u16)); + } + } + else + { + if (!opened) + { + Emu.GetAudioManager().GetAudioOut().Open(buffer, out_buffer_size * sizeof(float)); + opened = true; + } + else + { + Emu.GetAudioManager().GetAudioOut().AddData(buffer, out_buffer_size * sizeof(float)); } } - - //LOG_NOTICE(HLE, "Audio perf: start=%d (access=%d, AddData=%d, events=%d, dump=%d)", - //stamp0 - m_config.start_time, stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2, get_system_time() - stamp3); - } - cellAudio->Notice("Audio thread ended"); -abort: - queue.push(nullptr); - queue_float.push(nullptr); - - if(do_dump) - m_dump.Finalize(); - - m_config.m_is_audio_initialized = false; - - m_config.m_keys.clear(); - for (u32 i = 0; i < m_config.AUDIO_PORT_COUNT; i++) - { - AudioPortConfig& port = m_config.m_ports[i]; - port.m_is_audio_port_opened = false; - port.m_is_audio_port_started = false; - } - m_config.m_port_in_use = 0; - - while (!internal_finished) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } - m_config.m_is_audio_finalized = true; + Emu.GetAudioManager().GetAudioOut().Quit(); }); - t.detach(); - while (!m_config.start_time) // waiting for initialization - { - if (Emu.IsStopped()) + u64 last_pause_time; + std::atomic added_time(0); + NamedThreadBase* audio_thread = GetCurrentNamedThread(); + + PauseCallbackRegisterer pcb(Emu.GetCallbackManager(), [&last_pause_time, &added_time, audio_thread](bool is_paused) { - cellAudio->Warning("cellAudioInit() aborted"); - return CELL_OK; + if (is_paused) + { + last_pause_time = get_system_time(); + } + else + { + added_time += get_system_time() - last_pause_time; + audio_thread->Notify(); + } + }); + + while (g_audio.state.read_relaxed() == AUDIO_STATE_INITIALIZED && !Emu.IsStopped()) + { + if (Emu.IsPaused()) + { + GetCurrentNamedThread()->WaitForAnySignal(); + continue; + } + + if (added_time) + { + g_audio.start_time += added_time.exchange(0); + } + + const u64 stamp0 = get_system_time(); + + // TODO: send beforemix event (in ~2,6 ms before mixing) + + // precise time of sleeping: 5,(3) ms (or 256/48000 sec) + const u64 expected_time = g_audio.counter * AUDIO_SAMPLES * MHZ / 48000; + if (expected_time >= stamp0 - g_audio.start_time) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + continue; + } + + // crutch to hide giant lags caused by debugger + const u64 missed_time = stamp0 - g_audio.start_time - expected_time; + if (missed_time > AUDIO_SAMPLES * MHZ / 48000) + { + cellAudio->Notice("%f ms adjusted", (float)missed_time / 1000); + g_audio.start_time += missed_time; + } + + g_audio.counter++; + + const u32 out_pos = g_audio.counter % BUFFER_NUM; + + //if (Emu.IsPaused()) + //{ + // continue; + //} + + bool first_mix = true; + + // mixing: + for (auto& port : g_audio.ports) + { + if (port.state.read_relaxed() != AUDIO_PORT_STATE_STARTED) continue; + + const u32 block_size = port.channel * AUDIO_SAMPLES; + const u32 position = port.tag % port.block; // old value + const u32 buf_addr = port.addr + position * block_size * sizeof(float); + + auto buf = vm::get_ptr>(buf_addr); + + static const float k = 1.0f; // may be 1.0f + const float& m = port.level; + + auto step_volume = [](AudioPortConfig& port) // part of cellAudioSetPortLevel functionality + { + if (port.level_inc) + { + port.level += port.level_inc; + + if (port.level_inc > 0.0f) + { + if (port.level_set - port.level <= 0.0f) + { + port.level = port.level_set; + port.level_inc = 0.0f; + } + } + else + { + if (port.level_set - port.level >= 0.0f) + { + port.level = port.level_set; + port.level_inc = 0.0f; + } + } + } + }; + + if (port.channel == 2) + { + if (first_mix) + { + for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) + { + step_volume(port); + + // reverse byte order + const float left = buf[i + 0] * m; + const float right = buf[i + 1] * m; + + buf2ch[i + 0] = left; + buf2ch[i + 1] = right; + + buf8ch[i * 4 + 0] = left; + buf8ch[i * 4 + 1] = right; + buf8ch[i * 4 + 2] = 0.0f; + buf8ch[i * 4 + 3] = 0.0f; + buf8ch[i * 4 + 4] = 0.0f; + buf8ch[i * 4 + 5] = 0.0f; + buf8ch[i * 4 + 6] = 0.0f; + buf8ch[i * 4 + 7] = 0.0f; + } + first_mix = false; + } + else + { + for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) + { + step_volume(port); + + const float left = buf[i + 0] * m; + const float right = buf[i + 1] * m; + + buf2ch[i + 0] += left; + buf2ch[i + 1] += right; + + buf8ch[i * 4 + 0] += left; + buf8ch[i * 4 + 1] += right; + } + } + } + else if (port.channel == 8) + { + if (first_mix) + { + for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) + { + step_volume(port); + + const float left = buf[i * 4 + 0] * m; + const float right = buf[i * 4 + 1] * m; + const float center = buf[i * 4 + 2] * m; + const float low_freq = buf[i * 4 + 3] * m; + const float rear_left = buf[i * 4 + 4] * m; + const float rear_right = buf[i * 4 + 5] * m; + const float side_left = buf[i * 4 + 6] * m; + const float side_right = buf[i * 4 + 7] * m; + + const float mid = (center + low_freq) * 0.708f; + buf2ch[i + 0] = (left + rear_left + side_left + mid) * k; + buf2ch[i + 1] = (right + rear_right + side_right + mid) * k; + + buf8ch[i * 4 + 0] = left; + buf8ch[i * 4 + 1] = right; + buf8ch[i * 4 + 2] = center; + buf8ch[i * 4 + 3] = low_freq; + buf8ch[i * 4 + 4] = rear_left; + buf8ch[i * 4 + 5] = rear_right; + buf8ch[i * 4 + 6] = side_left; + buf8ch[i * 4 + 7] = side_right; + } + first_mix = false; + } + else + { + for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i += 2) + { + step_volume(port); + + const float left = buf[i * 4 + 0] * m; + const float right = buf[i * 4 + 1] * m; + const float center = buf[i * 4 + 2] * m; + const float low_freq = buf[i * 4 + 3] * m; + const float rear_left = buf[i * 4 + 4] * m; + const float rear_right = buf[i * 4 + 5] * m; + const float side_left = buf[i * 4 + 6] * m; + const float side_right = buf[i * 4 + 7] * m; + + const float mid = (center + low_freq) * 0.708f; + buf2ch[i + 0] += (left + rear_left + side_left + mid) * k; + buf2ch[i + 1] += (right + rear_right + side_right + mid) * k; + + buf8ch[i * 4 + 0] += left; + buf8ch[i * 4 + 1] += right; + buf8ch[i * 4 + 2] += center; + buf8ch[i * 4 + 3] += low_freq; + buf8ch[i * 4 + 4] += rear_left; + buf8ch[i * 4 + 5] += rear_right; + buf8ch[i * 4 + 6] += side_left; + buf8ch[i * 4 + 7] += side_right; + } + } + } + else + { + throw fmt::format("Unknown channel count (port=%d, channel=%d)", &port - g_audio.ports, port.channel); + } + + memset(buf, 0, block_size * sizeof(float)); + } + + + if (!first_mix) + { + // copy output data (2 ch) + //for (u32 i = 0; i < (sizeof(buf2ch) / sizeof(float)); i++) + //{ + // out_buffer[out_pos][i] = buf2ch[i]; + //} + + // copy output data (8 ch) + for (u32 i = 0; i < (sizeof(buf8ch) / sizeof(float)); i++) + { + out_buffer[out_pos][i] = buf8ch[i]; + } + } + + //const u64 stamp1 = get_system_time(); + + if (first_mix) + { + memset(out_buffer[out_pos].get(), 0, out_buffer_size * sizeof(float)); + } + + if (!out_queue.push(out_buffer[out_pos].get(), [](){ return g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED; })) + { + break; + } + + //const u64 stamp2 = get_system_time(); + + // send aftermix event (normal audio event) + { + std::lock_guard lock(g_audio.mutex); + // update indexes: + auto indexes = vm::ptr::make(g_audio.indexes); + for (u32 i = 0; i < AUDIO_PORT_COUNT; i++) + { + AudioPortConfig& port = g_audio.ports[i]; + + if (port.state.read_relaxed() != AUDIO_PORT_STATE_STARTED) continue; + + u32 position = port.tag % port.block; // old value + port.counter = g_audio.counter; + port.tag++; // absolute index of block that will be read + indexes[i] = (position + 1) % port.block; // write new value + } + // load keys: + keys.resize(g_audio.keys.size()); + memcpy(keys.data(), g_audio.keys.data(), sizeof(u64) * keys.size()); + } + for (u32 i = 0; i < keys.size(); i++) + { + // TODO: check event source + Emu.GetEventManager().SendEvent(keys[i], 0x10103000e010e07, 0, 0, 0); + } + + //const u64 stamp3 = get_system_time(); + + if (do_dump && !first_mix) + { + if (m_dump.GetCh() == 8) + { + if (m_dump.WriteData(&buf8ch, sizeof(buf8ch)) != sizeof(buf8ch)) // write file data (8 ch) + { + throw "AudioDumper::WriteData() failed (8 ch)"; + } + } + else if (m_dump.GetCh() == 2) + { + if (m_dump.WriteData(&buf2ch, sizeof(buf2ch)) != sizeof(buf2ch)) // write file data (2 ch) + { + throw "AudioDumper::WriteData() failed (2 ch)"; + } + } + else + { + throw fmt::format("AudioDumper::GetCh() returned unknown value (%d)", m_dump.GetCh()); + } + } + + //LOG_NOTICE(HLE, "Audio perf: start=%d (access=%d, AddData=%d, events=%d, dump=%d)", + //stamp0 - m_config.start_time, stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2, get_system_time() - stamp3); } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack - } + }); return CELL_OK; } -int cellAudioQuit() +s32 cellAudioQuit() { cellAudio->Warning("cellAudioQuit()"); - if (!m_config.m_is_audio_initialized) + if (!g_audio.state.compare_and_swap_test(AUDIO_STATE_INITIALIZED, AUDIO_STATE_FINALIZED)) { return CELL_AUDIO_ERROR_NOT_INIT; } - m_config.m_is_audio_initialized = false; - - while (!m_config.m_is_audio_finalized) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack - if (Emu.IsStopped()) - { - cellAudio->Warning("cellAudioQuit(): aborted"); - return CELL_OK; - } - } - - Memory.Free(m_config.m_buffer); - Memory.Free(m_config.m_indexes); - + g_audio.audio_thread.join(); + g_audio.state.exchange(AUDIO_STATE_NOT_INITIALIZED); return CELL_OK; } -int cellAudioPortOpen(vm::ptr audioParam, vm::ptr portNum) +s32 cellAudioPortOpen(vm::ptr audioParam, vm::ptr portNum) { - cellAudio->Warning("cellAudioPortOpen(audioParam_addr=0x%x, portNum_addr=0x%x)", audioParam.addr(), portNum.addr()); + cellAudio->Warning("cellAudioPortOpen(audioParam=0x%x, portNum=0x%x)", audioParam, portNum); - if (audioParam->nChannel > 8 || audioParam->nBlock > 16) + if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (!audioParam || !portNum) { return CELL_AUDIO_ERROR_PARAM; } - if (m_config.m_port_in_use >= m_config.AUDIO_PORT_COUNT) + const u64 channel = audioParam->nChannel; + const u64 block = audioParam->nBlock; + const u64 attr = audioParam->attr; + + // check attributes + if (channel != CELL_AUDIO_PORT_2CH && + channel != CELL_AUDIO_PORT_8CH && + channel) + { + return CELL_AUDIO_ERROR_PARAM; + } + + if (block != CELL_AUDIO_BLOCK_8 && + block != CELL_AUDIO_BLOCK_16 && + block != 2 && + block != 4 && + block != 32) + { + return CELL_AUDIO_ERROR_PARAM; + } + + // list unsupported flags + if (attr & CELL_AUDIO_PORTATTR_BGM) + { + cellAudio->Todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_BGM"); + } + if (attr & CELL_AUDIO_PORTATTR_OUT_SECONDARY) + { + cellAudio->Todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_SECONDARY"); + } + if (attr & CELL_AUDIO_PORTATTR_OUT_PERSONAL_0) + { + cellAudio->Todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_PERSONAL_0"); + } + if (attr & CELL_AUDIO_PORTATTR_OUT_PERSONAL_1) + { + cellAudio->Todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_PERSONAL_1"); + } + if (attr & CELL_AUDIO_PORTATTR_OUT_PERSONAL_2) + { + cellAudio->Todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_PERSONAL_2"); + } + if (attr & CELL_AUDIO_PORTATTR_OUT_PERSONAL_3) + { + cellAudio->Todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_PERSONAL_3"); + } + if (attr & CELL_AUDIO_PORTATTR_OUT_NO_ROUTE) + { + cellAudio->Todo("cellAudioPortOpen(): CELL_AUDIO_PORTATTR_OUT_NO_ROUTE"); + } + if (attr & 0xFFFFFFFFF0EFEFEEULL) + { + cellAudio->Todo("cellAudioPortOpen(): unknown attributes set (0x%llx)", attr); + } + + // open audio port + const u32 port_index = g_audio.open_port(); + + if (!~port_index) { return CELL_AUDIO_ERROR_PORT_FULL; } - for (u32 i = 0; i < m_config.AUDIO_PORT_COUNT; i++) + AudioPortConfig& port = g_audio.ports[port_index]; + + port.channel = (u32)channel; + port.block = (u32)block; + port.attr = attr; + port.addr = g_audio.buffer + AUDIO_PORT_OFFSET * port_index; + port.read_index_addr = g_audio.indexes + sizeof(u64) * port_index; + port.size = port.channel * port.block * AUDIO_SAMPLES * sizeof(float); + port.tag = 0; + + if (port.attr & CELL_AUDIO_PORTATTR_INITLEVEL) { - if (!m_config.m_ports[i].m_is_audio_port_opened) - { - AudioPortConfig& port = m_config.m_ports[i]; - - port.channel = (u8)audioParam->nChannel; - port.block = (u8)audioParam->nBlock; - port.attr = audioParam->attr; - port.addr = m_config.m_buffer + (128 * 1024 * i); - port.read_index_addr = m_config.m_indexes + (sizeof(u64) * i); - port.size = port.channel * port.block * 256 * sizeof(float); - if (port.attr & CELL_AUDIO_PORTATTR_INITLEVEL) - { - port.level = audioParam->level; - } - else - { - port.level = 1.0f; - } - - *portNum = i; - cellAudio->Warning("*** audio port opened(nChannel=%d, nBlock=%d, attr=0x%llx, level=%f): port = %d", - port.channel, port.block, port.attr, port.level, i); - - port.m_is_audio_port_opened = true; - port.m_is_audio_port_started = false; - port.tag = 0; - - m_config.m_port_in_use++; - return CELL_OK; - } + port.level = audioParam->level; + } + else + { + port.level = 1.0f; } - return CELL_AUDIO_ERROR_PORT_FULL; + port.level_set = port.level; + port.level_inc = 0.0f; + + *portNum = port_index; + cellAudio->Warning("*** audio port opened(nChannel=%d, nBlock=%d, attr=0x%llx, level=%f): port = %d", channel, block, attr, port.level, port_index); + + return CELL_OK; } -int cellAudioGetPortConfig(u32 portNum, vm::ptr portConfig) +s32 cellAudioGetPortConfig(u32 portNum, vm::ptr portConfig) { - cellAudio->Warning("cellAudioGetPortConfig(portNum=0x%x, portConfig_addr=0x%x)", portNum, portConfig.addr()); + cellAudio->Warning("cellAudioGetPortConfig(portNum=0x%x, portConfig=0x%x)", portNum, portConfig); - if (portNum >= m_config.AUDIO_PORT_COUNT) + if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (!portConfig || portNum >= AUDIO_PORT_COUNT) { return CELL_AUDIO_ERROR_PARAM; } - if (!m_config.m_ports[portNum].m_is_audio_port_opened) - { - portConfig->status = CELL_AUDIO_STATUS_CLOSE; - } - else if (m_config.m_ports[portNum].m_is_audio_port_started) - { - portConfig->status = CELL_AUDIO_STATUS_RUN; - } - else - { - portConfig->status = CELL_AUDIO_STATUS_READY; - } + AudioPortConfig& port = g_audio.ports[portNum]; - AudioPortConfig& port = m_config.m_ports[portNum]; + portConfig->readIndexAddr = port.read_index_addr; + + switch (auto state = port.state.read_sync()) + { + case AUDIO_PORT_STATE_CLOSED: portConfig->status = CELL_AUDIO_STATUS_CLOSE; break; + case AUDIO_PORT_STATE_OPENED: portConfig->status = CELL_AUDIO_STATUS_READY; break; + case AUDIO_PORT_STATE_STARTED: portConfig->status = CELL_AUDIO_STATUS_RUN; break; + default: throw fmt::format("cellAudioGetPortConfig(%d): invalid port state (0x%x)", portNum, state); + } portConfig->nChannel = port.channel; portConfig->nBlock = port.block; portConfig->portSize = port.size; - portConfig->portAddr = port.addr; // 0x20020000 - portConfig->readIndexAddr = port.read_index_addr; // 0x20010010 on ps3 - - cellAudio->Log("*** port config: nChannel=%d, nBlock=%d, portSize=0x%x, portAddr=0x%x, readIndexAddr=0x%x", - (u32)portConfig->nChannel, (u32)portConfig->nBlock, (u32)portConfig->portSize, (u32)portConfig->portAddr, (u32)portConfig->readIndexAddr); - // portAddr - readIndexAddr == 0xFFF0 on ps3 - + portConfig->portAddr = port.addr; return CELL_OK; } -int cellAudioPortStart(u32 portNum) +s32 cellAudioPortStart(u32 portNum) { cellAudio->Warning("cellAudioPortStart(portNum=0x%x)", portNum); - if (portNum >= m_config.AUDIO_PORT_COUNT) + if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (portNum >= AUDIO_PORT_COUNT) { return CELL_AUDIO_ERROR_PARAM; } - if (!m_config.m_ports[portNum].m_is_audio_port_opened) + switch (auto state = g_audio.ports[portNum].state.compare_and_swap(AUDIO_PORT_STATE_OPENED, AUDIO_PORT_STATE_STARTED)) { - return CELL_AUDIO_ERROR_PORT_OPEN; + case AUDIO_PORT_STATE_CLOSED: return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + case AUDIO_PORT_STATE_STARTED: return CELL_AUDIO_ERROR_PORT_ALREADY_RUN; + case AUDIO_PORT_STATE_OPENED: return CELL_OK; + default: throw fmt::format("cellAudioPortStart(%d): invalid port state (0x%x)", portNum, state); } - - if (m_config.m_ports[portNum].m_is_audio_port_started) - { - return CELL_AUDIO_ERROR_PORT_ALREADY_RUN; - } - - m_config.m_ports[portNum].m_is_audio_port_started = true; - - return CELL_OK; } -int cellAudioPortClose(u32 portNum) +s32 cellAudioPortClose(u32 portNum) { cellAudio->Warning("cellAudioPortClose(portNum=0x%x)", portNum); - if (portNum >= m_config.AUDIO_PORT_COUNT) + if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (portNum >= AUDIO_PORT_COUNT) { return CELL_AUDIO_ERROR_PARAM; } - if (!m_config.m_ports[portNum].m_is_audio_port_opened) + switch (auto state = g_audio.ports[portNum].state.exchange(AUDIO_PORT_STATE_CLOSED)) { - return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + case AUDIO_PORT_STATE_CLOSED: return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + case AUDIO_PORT_STATE_STARTED: return CELL_OK; + case AUDIO_PORT_STATE_OPENED: return CELL_OK; + default: throw fmt::format("cellAudioPortClose(%d): invalid port state (0x%x)", portNum, state); } - - m_config.m_ports[portNum].m_is_audio_port_started = false; - m_config.m_ports[portNum].m_is_audio_port_opened = false; - m_config.m_port_in_use--; - return CELL_OK; } -int cellAudioPortStop(u32 portNum) +s32 cellAudioPortStop(u32 portNum) { - cellAudio->Warning("cellAudioPortStop(portNum=0x%x)",portNum); - - if (portNum >= m_config.AUDIO_PORT_COUNT) + cellAudio->Warning("cellAudioPortStop(portNum=0x%x)", portNum); + + if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (portNum >= AUDIO_PORT_COUNT) { return CELL_AUDIO_ERROR_PARAM; } - if (!m_config.m_ports[portNum].m_is_audio_port_opened) + switch (auto state = g_audio.ports[portNum].state.compare_and_swap(AUDIO_PORT_STATE_STARTED, AUDIO_PORT_STATE_OPENED)) { - return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + case AUDIO_PORT_STATE_CLOSED: return CELL_AUDIO_ERROR_PORT_NOT_RUN; + case AUDIO_PORT_STATE_STARTED: return CELL_OK; + case AUDIO_PORT_STATE_OPENED: return CELL_AUDIO_ERROR_PORT_NOT_RUN; + default: throw fmt::format("cellAudioPortStop(%d): invalid port state (0x%x)", portNum, state); } - - if (!m_config.m_ports[portNum].m_is_audio_port_started) - { - return CELL_AUDIO_ERROR_PORT_NOT_RUN; - } - - m_config.m_ports[portNum].m_is_audio_port_started = false; - return CELL_OK; } -int cellAudioGetPortTimestamp(u32 portNum, u64 tag, vm::ptr stamp) +s32 cellAudioGetPortTimestamp(u32 portNum, u64 tag, vm::ptr stamp) { - cellAudio->Log("cellAudioGetPortTimestamp(portNum=0x%x, tag=0x%llx, stamp_addr=0x%x)", portNum, tag, stamp.addr()); + cellAudio->Log("cellAudioGetPortTimestamp(portNum=0x%x, tag=0x%llx, stamp=0x%x)", portNum, tag, stamp); - if (portNum >= m_config.AUDIO_PORT_COUNT) + if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (portNum >= AUDIO_PORT_COUNT) { return CELL_AUDIO_ERROR_PARAM; } - if (!m_config.m_ports[portNum].m_is_audio_port_opened) + AudioPortConfig& port = g_audio.ports[portNum]; + + if (port.state.read_relaxed() == AUDIO_PORT_STATE_CLOSED) { return CELL_AUDIO_ERROR_PORT_NOT_OPEN; } - if (!m_config.m_ports[portNum].m_is_audio_port_started) - { - return CELL_AUDIO_ERROR_PORT_NOT_RUN; - } + // TODO: check tag (CELL_AUDIO_ERROR_TAG_NOT_FOUND error) - AudioPortConfig& port = m_config.m_ports[portNum]; + std::lock_guard lock(g_audio.mutex); - std::lock_guard lock(audioMutex); - - *stamp = m_config.start_time + (port.counter + (tag - port.tag)) * 256000000 / 48000; + *stamp = g_audio.start_time + (port.counter + (tag - port.tag)) * 256000000 / 48000; return CELL_OK; } -int cellAudioGetPortBlockTag(u32 portNum, u64 blockNo, vm::ptr tag) +s32 cellAudioGetPortBlockTag(u32 portNum, u64 blockNo, vm::ptr tag) { - cellAudio->Log("cellAudioGetPortBlockTag(portNum=0x%x, blockNo=0x%llx, tag_addr=0x%x)", portNum, blockNo, tag.addr()); + cellAudio->Log("cellAudioGetPortBlockTag(portNum=0x%x, blockNo=0x%llx, tag=0x%x)", portNum, blockNo, tag); - if (portNum >= m_config.AUDIO_PORT_COUNT) + if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (portNum >= AUDIO_PORT_COUNT) { return CELL_AUDIO_ERROR_PARAM; } - if (!m_config.m_ports[portNum].m_is_audio_port_opened) + AudioPortConfig& port = g_audio.ports[portNum]; + + if (port.state.read_relaxed() == AUDIO_PORT_STATE_CLOSED) { return CELL_AUDIO_ERROR_PORT_NOT_OPEN; } - if (!m_config.m_ports[portNum].m_is_audio_port_started) - { - return CELL_AUDIO_ERROR_PORT_NOT_RUN; - } - - AudioPortConfig& port = m_config.m_ports[portNum]; - if (blockNo >= port.block) { - cellAudio->Error("cellAudioGetPortBlockTag: wrong blockNo(%lld)", blockNo); return CELL_AUDIO_ERROR_PARAM; } - std::lock_guard lock(audioMutex); + std::lock_guard lock(g_audio.mutex); u64 tag_base = port.tag; if (tag_base % port.block > blockNo) { - tag_base &= ~(port.block-1); + tag_base &= ~(port.block - 1); tag_base += port.block; } else { - tag_base &= ~(port.block-1); + tag_base &= ~(port.block - 1); } *tag = tag_base + blockNo; return CELL_OK; } -int cellAudioSetPortLevel(u32 portNum, float level) +s32 cellAudioSetPortLevel(u32 portNum, float level) { - cellAudio->Todo("cellAudioSetPortLevel(portNum=0x%x, level=%f)", portNum, level); + cellAudio->Log("cellAudioSetPortLevel(portNum=0x%x, level=%f)", portNum, level); - AudioPortConfig& port = m_config.m_ports[portNum]; + if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } - if (portNum >= m_config.AUDIO_PORT_COUNT) + if (portNum >= AUDIO_PORT_COUNT) { return CELL_AUDIO_ERROR_PARAM; } - if (!port.m_is_audio_port_opened) + AudioPortConfig& port = g_audio.ports[portNum]; + + if (port.state.read_relaxed() == AUDIO_PORT_STATE_CLOSED) { return CELL_AUDIO_ERROR_PORT_NOT_OPEN; } - if (!port.m_is_audio_port_started) + if (level >= 0.0f) { - return CELL_AUDIO_ERROR_PORT_NOT_RUN; + std::lock_guard lock(g_audio.mutex); + + port.level_set = level; + port.level_inc = (port.level - level) / 624.0f; + } + else + { + cellAudio->Todo("cellAudioSetPortLevel(portNum=0x%x): negative level value (%f)", portNum, level); } - - std::lock_guard lock(audioMutex); - - port.level = level; // TODO return CELL_OK; } @@ -763,7 +767,7 @@ int cellAudioCreateNotifyEventQueue(vm::ptr id, vm::ptr key) { cellAudio->Warning("cellAudioCreateNotifyEventQueue(id_addr=0x%x, key_addr=0x%x)", id.addr(), key.addr()); - std::lock_guard lock(audioMutex); + std::lock_guard lock(g_audio.mutex); u64 event_key = 0; while (Emu.GetEventManager().CheckKey((event_key << 48) | 0x80004d494f323221)) @@ -796,21 +800,21 @@ int cellAudioSetNotifyEventQueue(u64 key) { cellAudio->Warning("cellAudioSetNotifyEventQueue(key=0x%llx)", key); - std::lock_guard lock(audioMutex); + std::lock_guard lock(g_audio.mutex); - for (u32 i = 0; i < m_config.m_keys.size(); i++) // check for duplicates + for (u32 i = 0; i < g_audio.keys.size(); i++) // check for duplicates { - if (m_config.m_keys[i] == key) + if (g_audio.keys[i] == key) { return CELL_AUDIO_ERROR_PARAM; } } - m_config.m_keys.push_back(key); + g_audio.keys.push_back(key); /*EventQueue* eq; if (!Emu.GetEventManager().GetEventQueue(key, eq)) { - return CELL_AUDIO_ERROR_PARAM; + return CELL_AUDIO_ERROR_PARAM; }*/ // TODO: connect port (?????) @@ -828,14 +832,14 @@ int cellAudioRemoveNotifyEventQueue(u64 key) { cellAudio->Warning("cellAudioRemoveNotifyEventQueue(key=0x%llx)", key); - std::lock_guard lock(audioMutex); + std::lock_guard lock(g_audio.mutex); bool found = false; - for (u32 i = 0; i < m_config.m_keys.size(); i++) + for (u32 i = 0; i < g_audio.keys.size(); i++) { - if (m_config.m_keys[i] == key) + if (g_audio.keys[i] == key) { - m_config.m_keys.erase(m_config.m_keys.begin() + i); + g_audio.keys.erase(g_audio.keys.begin() + i); found = true; break; } @@ -850,7 +854,7 @@ int cellAudioRemoveNotifyEventQueue(u64 key) /*EventQueue* eq; if (!Emu.GetEventManager().GetEventQueue(key, eq)) { - return CELL_AUDIO_ERROR_PARAM; + return CELL_AUDIO_ERROR_PARAM; }*/ // TODO: disconnect port @@ -864,117 +868,143 @@ int cellAudioRemoveNotifyEventQueueEx(u64 key, u32 iFlags) return CELL_OK; } -int cellAudioAddData(u32 portNum, vm::ptr src, u32 samples, float volume) +s32 cellAudioAddData(u32 portNum, vm::ptr src, u32 samples, float volume) { - cellAudio->Warning("cellAudioAddData(portNum=0x%x, src_addr=0x%x, samples=%d, volume=%f)", portNum, src.addr(), samples, volume); - - if (src.addr() % 16) - return CELL_AUDIO_ERROR_PARAM; + cellAudio->Log("cellAudioAddData(portNum=%d, src=0x%x, samples=%d, volume=%f)", portNum, src, samples, volume); - AudioPortConfig& port = m_config.m_ports[portNum]; + if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } - if (portNum >= m_config.AUDIO_PORT_COUNT) + if (portNum >= AUDIO_PORT_COUNT || !src || src.addr() % 4) { return CELL_AUDIO_ERROR_PARAM; } - if (!port.m_is_audio_port_opened) + if (samples != 256) { - return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + // despite the docs, seems that only fixed value is supported + cellAudio->Error("cellAudioAddData(): invalid samples value (0x%x)", samples); + return CELL_AUDIO_ERROR_PARAM; } - if (!port.m_is_audio_port_started) - { - return CELL_AUDIO_ERROR_PORT_NOT_RUN; - } + const AudioPortConfig& port = g_audio.ports[portNum]; - std::lock_guard lock(audioMutex); - - u32 addr = port.addr; - u32 src_addr = src.addr(); + const auto dst = vm::ptr::make(port.addr + (port.tag % port.block) * port.channel * 256 * sizeof(float)); - for (u32 i = 0; i < samples; i++) + for (u32 i = 0; i < samples * port.channel; i++) { - // vm::write32(addr, (u32)((float)vm::read32(src_addr) * volume)); // TODO: use volume? - vm::write32(addr, vm::read32(src_addr)); - src_addr += (port.size / samples); - addr += (port.size / samples); + dst[i] += src[i] * volume; // mix all channels } return CELL_OK; } -int cellAudioAdd2chData(u32 portNum, vm::ptr src, u32 samples, float volume) +s32 cellAudioAdd2chData(u32 portNum, vm::ptr src, u32 samples, float volume) { - cellAudio->Warning("cellAudioAdd2chData(portNum=0x%x, src_addr=0x%x, samples=%d, volume=%f)", portNum, src.addr(), samples, volume); - - AudioPortConfig& port = m_config.m_ports[portNum]; + cellAudio->Log("cellAudioAdd2chData(portNum=%d, src=0x%x, samples=%d, volume=%f)", portNum, src, samples, volume); - if (portNum >= m_config.AUDIO_PORT_COUNT) + if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (portNum >= AUDIO_PORT_COUNT || !src || src.addr() % 4) { return CELL_AUDIO_ERROR_PARAM; } - if (!port.m_is_audio_port_opened) + if (samples != 256) { - return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + // despite the docs, seems that only fixed value is supported + cellAudio->Error("cellAudioAdd2chData(): invalid samples value (0x%x)", samples); + return CELL_AUDIO_ERROR_PARAM; } - if (!port.m_is_audio_port_started) + const AudioPortConfig& port = g_audio.ports[portNum]; + + const auto dst = vm::ptr::make(port.addr + (port.tag % port.block) * port.channel * 256 * sizeof(float)); + + if (port.channel == 2) { - return CELL_AUDIO_ERROR_PORT_NOT_RUN; + cellAudio->Error("cellAudioAdd2chData(portNum=%d): port.channel = 2", portNum); + } + else if (port.channel == 6) + { + for (u32 i = 0; i < samples; i++) + { + dst[i * 6 + 0] += src[i * 2 + 0] * volume; // mix L ch + dst[i * 6 + 1] += src[i * 2 + 1] * volume; // mix R ch + //dst[i * 6 + 2] += 0.0f; // center + //dst[i * 6 + 3] += 0.0f; // LFE + //dst[i * 6 + 4] += 0.0f; // rear L + //dst[i * 6 + 5] += 0.0f; // rear R + } + } + else if (port.channel == 8) + { + for (u32 i = 0; i < samples; i++) + { + dst[i * 8 + 0] += src[i * 2 + 0] * volume; // mix L ch + dst[i * 8 + 1] += src[i * 2 + 1] * volume; // mix R ch + //dst[i * 8 + 2] += 0.0f; // center + //dst[i * 8 + 3] += 0.0f; // LFE + //dst[i * 8 + 4] += 0.0f; // rear L + //dst[i * 8 + 5] += 0.0f; // rear R + //dst[i * 8 + 6] += 0.0f; // side L + //dst[i * 8 + 7] += 0.0f; // side R + } + } + else + { + cellAudio->Error("cellAudioAdd2chData(portNum=%d): invalid port.channel value (%d)", portNum, port.channel); } - std::lock_guard lock(audioMutex); - - u32 addr = port.addr; - u32 src_addr = src.addr(); - - for (u32 i = 0; i < samples; i++) - { - // vm::write32(addr, (u32)((float)vm::read32(src_addr) * volume)); // TODO: use volume? - vm::write32(addr, vm::read32(src_addr)); - src_addr += (2 * port.block * 256 * sizeof(float) / samples); - addr += (2 * port.block * 256 * sizeof(float) / samples); - } - return CELL_OK; } -int cellAudioAdd6chData(u32 portNum, vm::ptr src, float volume) +s32 cellAudioAdd6chData(u32 portNum, vm::ptr src, float volume) { - cellAudio->Warning("cellAudioAdd6chData(portNum=0x%x, src_addr=0x%x, volume=%f)", portNum, src.addr(), volume); - - AudioPortConfig& port = m_config.m_ports[portNum]; + cellAudio->Log("cellAudioAdd6chData(portNum=%d, src=0x%x, volume=%f)", portNum, src, volume); - if (portNum >= m_config.AUDIO_PORT_COUNT) + if (g_audio.state.read_relaxed() != AUDIO_STATE_INITIALIZED) + { + return CELL_AUDIO_ERROR_NOT_INIT; + } + + if (portNum >= AUDIO_PORT_COUNT || !src || src.addr() % 4) { return CELL_AUDIO_ERROR_PARAM; } - if (!port.m_is_audio_port_opened) + const AudioPortConfig& port = g_audio.ports[portNum]; + + const auto dst = vm::ptr::make(port.addr + (port.tag % port.block) * port.channel * 256 * sizeof(float)); + + if (port.channel == 2 || port.channel == 6) { - return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + cellAudio->Error("cellAudioAdd2chData(portNum=%d): port.channel = %d", portNum, port.channel); + } + else if (port.channel == 8) + { + for (u32 i = 0; i < 256; i++) + { + dst[i * 8 + 0] += src[i * 6 + 0] * volume; // mix L ch + dst[i * 8 + 1] += src[i * 6 + 1] * volume; // mix R ch + dst[i * 8 + 2] += src[i * 6 + 2] * volume; // mix center + dst[i * 8 + 3] += src[i * 6 + 3] * volume; // mix LFE + dst[i * 8 + 4] += src[i * 6 + 4] * volume; // mix rear L + dst[i * 8 + 5] += src[i * 6 + 5] * volume; // mix rear R + //dst[i * 8 + 6] += 0.0f; // side L + //dst[i * 8 + 7] += 0.0f; // side R + } + } + else + { + cellAudio->Error("cellAudioAdd6chData(portNum=%d): invalid port.channel value (%d)", portNum, port.channel); } - if (!port.m_is_audio_port_started) - { - return CELL_AUDIO_ERROR_PORT_NOT_RUN; - } - - std::lock_guard lock(audioMutex); - - u32 addr = port.addr; - u32 src_addr = src.addr(); - - for (u32 i = 0; i < 256; i++) - { - // vm::write32(addr, (u32)((float)vm::read32(src_addr) * volume)); // TODO: use volume? - vm::write32(addr, vm::read32(src_addr)); - src_addr += (6 * port.block * sizeof(float)); - addr += (6 * port.block * sizeof(float)); - } - return CELL_OK; } @@ -1006,20 +1036,36 @@ void cellAudio_init(Module *pxThis) { cellAudio = pxThis; - cellAudio->AddFunc(0x0b168f92, cellAudioInit); - cellAudio->AddFunc(0x4129fe2d, cellAudioPortClose); - cellAudio->AddFunc(0x5b1e2c73, cellAudioPortStop); - cellAudio->AddFunc(0x74a66af0, cellAudioGetPortConfig); - cellAudio->AddFunc(0x89be28f2, cellAudioPortStart); - cellAudio->AddFunc(0xca5ac370, cellAudioQuit); - cellAudio->AddFunc(0xcd7bc431, cellAudioPortOpen); - cellAudio->AddFunc(0x56dfe179, cellAudioSetPortLevel); - cellAudio->AddFunc(0x04af134e, cellAudioCreateNotifyEventQueue); - cellAudio->AddFunc(0x31211f6b, cellAudioMiscSetAccessoryVolume); - cellAudio->AddFunc(0x377e0cd9, cellAudioSetNotifyEventQueue); - cellAudio->AddFunc(0x4109d08c, cellAudioGetPortTimestamp); - cellAudio->AddFunc(0x9e4b1db8, cellAudioAdd2chData); - cellAudio->AddFunc(0xdab029aa, cellAudioAddData); - cellAudio->AddFunc(0xe4046afe, cellAudioGetPortBlockTag); - cellAudio->AddFunc(0xff3626fd, cellAudioRemoveNotifyEventQueue); + g_audio.state.write_relaxed(AUDIO_STATE_NOT_INITIALIZED); + g_audio.buffer = 0; + g_audio.indexes = 0; + + REG_FUNC(cellAudio, cellAudioInit); + REG_FUNC(cellAudio, cellAudioPortClose); + REG_FUNC(cellAudio, cellAudioPortStop); + REG_FUNC(cellAudio, cellAudioGetPortConfig); + REG_FUNC(cellAudio, cellAudioPortStart); + REG_FUNC(cellAudio, cellAudioQuit); + REG_FUNC(cellAudio, cellAudioPortOpen); + REG_FUNC(cellAudio, cellAudioSetPortLevel); + REG_FUNC(cellAudio, cellAudioCreateNotifyEventQueue); + REG_FUNC(cellAudio, cellAudioCreateNotifyEventQueueEx); + REG_FUNC(cellAudio, cellAudioMiscSetAccessoryVolume); + REG_FUNC(cellAudio, cellAudioSetNotifyEventQueue); + REG_FUNC(cellAudio, cellAudioSetNotifyEventQueueEx); + REG_FUNC(cellAudio, cellAudioGetPortTimestamp); + REG_FUNC(cellAudio, cellAudioAdd2chData); + REG_FUNC(cellAudio, cellAudioAdd6chData); + REG_FUNC(cellAudio, cellAudioAddData); + REG_FUNC(cellAudio, cellAudioGetPortBlockTag); + REG_FUNC(cellAudio, cellAudioRemoveNotifyEventQueue); + REG_FUNC(cellAudio, cellAudioRemoveNotifyEventQueueEx); + REG_FUNC(cellAudio, cellAudioSendAck); + REG_FUNC(cellAudio, cellAudioSetPersonalDevice); + REG_FUNC(cellAudio, cellAudioUnsetPersonalDevice); +} + +void cellAudio_load() +{ + // CELL_SYSMODULE AUDIO module is rarely loaded manually, so cellAudio_load() won't be called in every case } diff --git a/rpcs3/Emu/Audio/cellAudio.h b/rpcs3/Emu/SysCalls/Modules/cellAudio.h similarity index 74% rename from rpcs3/Emu/Audio/cellAudio.h rename to rpcs3/Emu/SysCalls/Modules/cellAudio.h index b6cabcea59..ca165476c1 100644 --- a/rpcs3/Emu/Audio/cellAudio.h +++ b/rpcs3/Emu/SysCalls/Modules/cellAudio.h @@ -72,51 +72,76 @@ struct CellAudioPortConfig be_t portAddr; }; +enum : u32 +{ + BUFFER_NUM = 32, + BUFFER_SIZE = 256, + AUDIO_PORT_COUNT = 8, + AUDIO_PORT_OFFSET = 256 * 1024, + AUDIO_SAMPLES = CELL_AUDIO_BLOCK_SAMPLES, +}; + +enum AudioState : u32 +{ + AUDIO_STATE_NOT_INITIALIZED, + AUDIO_STATE_INITIALIZED, + AUDIO_STATE_FINALIZED, +}; + +enum AudioPortState : u32 +{ + AUDIO_PORT_STATE_CLOSED, + AUDIO_PORT_STATE_OPENED, + AUDIO_PORT_STATE_STARTED, +}; + struct AudioPortConfig { - bool m_is_audio_port_opened; - bool m_is_audio_port_started; - u8 channel; - u8 block; - float level; + std::mutex mutex; + atomic_le_t state; + + u32 channel; + u32 block; u64 attr; u64 tag; u64 counter; // copy of global counter u32 addr; u32 read_index_addr; u32 size; + float level; + float level_set; + float level_inc; }; struct AudioConfig //custom structure { - enum - { - AUDIO_PORT_COUNT = 8, - }; - AudioPortConfig m_ports[AUDIO_PORT_COUNT]; - u32 m_buffer; // 1 MB memory for audio ports - u32 m_indexes; // current block indexes and other info - bool m_is_audio_initialized; - bool m_is_audio_finalized; - u32 m_port_in_use; + std::mutex mutex; + atomic_le_t state; + thread_t audio_thread; + + AudioPortConfig ports[AUDIO_PORT_COUNT]; + u32 buffer; // 1 MB memory for audio ports + u32 indexes; // current block indexes and other info u64 counter; u64 start_time; - std::vector m_keys; + std::vector keys; - AudioConfig() - : m_is_audio_initialized(false) - , m_is_audio_finalized(false) - , m_port_in_use(0) - , counter(0) + AudioConfig() : audio_thread("Audio Thread") { - memset(&m_ports, 0, sizeof(AudioPortConfig) * AUDIO_PORT_COUNT); } - void Clear() + u32 open_port() { - memset(&m_ports, 0, sizeof(AudioPortConfig) * AUDIO_PORT_COUNT); - m_port_in_use = 0; + for (u32 i = 0; i < AUDIO_PORT_COUNT; i++) + { + if (ports[i].state.compare_and_swap_test(AUDIO_PORT_STATE_CLOSED, AUDIO_PORT_STATE_OPENED)) + { + return i; + } + } + + return ~0; } }; -extern AudioConfig m_config; +extern AudioConfig g_audio; diff --git a/rpcs3/Emu/SysCalls/Modules/cellCamera.cpp b/rpcs3/Emu/SysCalls/Modules/cellCamera.cpp index c0fe253842..467e18e214 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellCamera.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellCamera.cpp @@ -82,7 +82,7 @@ int cellCameraGetDeviceGUID() int cellCameraGetType(s32 dev_num, vm::ptr type) { - cellCamera->Warning("cellCameraGetType(dev_num=%d, type_addr=0x%x)", dev_num, type); + cellCamera->Warning("cellCameraGetType(dev_num=%d, type_addr=0x%x)", dev_num, type.addr()); if (!cellCameraInstance.m_bInitialized) return CELL_CAMERA_ERROR_NOT_INIT; diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp index 5c17b81125..9bf3c1ff03 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp @@ -83,7 +83,7 @@ PesHeader::PesHeader(DemuxerStream& stream) ElementaryStream::ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr cbFunc, u32 cbArg, u32 spec) : dmux(dmux) - , memAddr(a128(addr)) + , memAddr(align(addr, 128)) , memSize(size - (addr - memAddr)) , fidMajor(fidMajor) , fidMinor(fidMinor) @@ -92,7 +92,7 @@ ElementaryStream::ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMaj , cbFunc(cbFunc) , cbArg(cbArg) , spec(spec) - , put(a128(addr)) + , put(align(addr, 128)) , put_count(0) , got_count(0) , released(0) @@ -184,7 +184,7 @@ void ElementaryStream::push_au(u32 size, u64 dts, u64 pts, u64 userdata, bool ra addr = put; - put = a128(put + 128 + size); + put = align(put + 128 + size, 128); put_count++; } @@ -306,7 +306,7 @@ u32 dmuxOpen(Demuxer* dmux_ptr) dmux.id = dmux_id; dmux.dmuxCb = (PPUThread*)&Emu.GetCPU().AddThread(CPU_THREAD_PPU); - dmux.dmuxCb->SetName("Demuxer[" + std::to_string(dmux_id) + "] Callback"); + dmux.dmuxCb->SetName(fmt::format("Demuxer[%d] Callback", dmux_id)); dmux.dmuxCb->SetEntry(0); dmux.dmuxCb->SetPrio(1001); dmux.dmuxCb->SetStackSize(0x10000); @@ -314,10 +314,9 @@ u32 dmuxOpen(Demuxer* dmux_ptr) dmux.dmuxCb->InitRegs(); dmux.dmuxCb->DoRun(); - thread t("Demuxer[" + std::to_string(dmux_id) + "] Thread", [dmux_ptr, sptr]() + thread_t t(fmt::format("Demuxer[%d] Thread", dmux_id), [dmux_ptr, sptr]() { Demuxer& dmux = *dmux_ptr; - cellDmux->Notice("Demuxer thread started (mem=0x%x, size=0x%x, cb=0x%x, arg=0x%x)", dmux.memAddr, dmux.memSize, dmux.cbFunc, dmux.cbArg); DemuxerTask task; DemuxerStream stream = {}; @@ -347,16 +346,16 @@ u32 dmuxOpen(Demuxer* dmux_ptr) if (!stream.peek(code)) { // demuxing finished - auto dmuxMsg = vm::ptr::make(a128(dmux.memAddr) + (cb_add ^= 16)); + auto dmuxMsg = vm::ptr::make(dmux.memAddr + (cb_add ^= 16)); dmuxMsg->msgType = CELL_DMUX_MSG_TYPE_DEMUX_DONE; dmuxMsg->supplementalInfo = stream.userdata; - dmux.cbFunc.call(*dmux.dmuxCb, dmux.id, dmuxMsg, dmux.cbArg); + dmux.cbFunc(*dmux.dmuxCb, dmux.id, dmuxMsg, dmux.cbArg); dmux.is_running = false; continue; } - switch (code.ToLE()) + switch (code.value()) { case PACK_START_CODE: { @@ -387,9 +386,9 @@ u32 dmuxOpen(Demuxer* dmux_ptr) stream.skip(4); stream.get(len); - if (!stream.check(len.ToLE())) + if (!stream.check(len)) { - DMUX_ERROR("End of stream (PADDING_STREAM, len=%d)", len.ToLE()); + DMUX_ERROR("End of stream (PADDING_STREAM, len=%d)", len); } stream.skip(len); break; @@ -404,11 +403,11 @@ u32 dmuxOpen(Demuxer* dmux_ptr) stream.skip(4); stream.get(len); - cellDmux->Notice("PRIVATE_STREAM_2 (%d)", len.ToLE()); + cellDmux->Notice("PRIVATE_STREAM_2 (%d)", len); - if (!stream.check(len.ToLE())) + if (!stream.check(len)) { - DMUX_ERROR("End of stream (PRIVATE_STREAM_2, len=%d)", len.ToLE()); + DMUX_ERROR("End of stream (PRIVATE_STREAM_2, len=%d)", len); } stream.skip(len); break; @@ -426,20 +425,20 @@ u32 dmuxOpen(Demuxer* dmux_ptr) stream.skip(4); stream.get(len); - if (!stream.check(len.ToLE())) + if (!stream.check(len)) { - DMUX_ERROR("End of stream (PRIVATE_STREAM_1, len=%d)", len.ToLE()); + DMUX_ERROR("End of stream (PRIVATE_STREAM_1, len=%d)", len); } const PesHeader pes(stream); if (!pes.is_ok) { - DMUX_ERROR("PesHeader error (PRIVATE_STREAM_1, len=%d)", len.ToLE()); + DMUX_ERROR("PesHeader error (PRIVATE_STREAM_1, len=%d)", len); } if (len < pes.size + 4) { - DMUX_ERROR("End of block (PRIVATE_STREAM_1, PesHeader + fid_minor, len=%d)", len.ToLE()); + DMUX_ERROR("End of block (PRIVATE_STREAM_1, PesHeader + fid_minor, len=%d)", len); } len -= pes.size + 4; @@ -462,7 +461,7 @@ u32 dmuxOpen(Demuxer* dmux_ptr) if (len < 3 || !stream.check(3)) { - DMUX_ERROR("End of block (ATX, unknown header, len=%d)", len.ToLE()); + DMUX_ERROR("End of block (ATX, unknown header, len=%d)", len); } len -= 3; stream.skip(3); @@ -484,7 +483,7 @@ u32 dmuxOpen(Demuxer* dmux_ptr) if (data[0] != 0x0f || data[1] != 0xd0) { - DMUX_ERROR("ATX: 0x0fd0 header not found (ats=0x%llx)", ((be_t*)data)->ToLE()); + DMUX_ERROR("ATX: 0x0fd0 header not found (ats=0x%llx)", *(be_t*)data); } u32 frame_size = ((((u32)data[2] & 0x3) << 8) | (u32)data[3]) * 8 + 8; @@ -495,17 +494,17 @@ u32 dmuxOpen(Demuxer* dmux_ptr) es.push_au(frame_size + 8, es.last_dts, es.last_pts, stream.userdata, false /* TODO: set correct value */, 0); - //cellDmux->Notice("ATX AU pushed (ats=0x%llx, frame_size=%d)", ((be_t*)data)->ToLE(), frame_size); + //cellDmux->Notice("ATX AU pushed (ats=0x%llx, frame_size=%d)", *(be_t*)data, frame_size); - auto esMsg = vm::ptr::make(a128(dmux.memAddr) + (cb_add ^= 16)); + auto esMsg = vm::ptr::make(dmux.memAddr + (cb_add ^= 16)); esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND; esMsg->supplementalInfo = stream.userdata; - es.cbFunc.call(*dmux.dmuxCb, dmux.id, es.id, esMsg, es.cbArg); + es.cbFunc(*dmux.dmuxCb, dmux.id, es.id, esMsg, es.cbArg); } } else { - cellDmux->Notice("PRIVATE_STREAM_1 (len=%d, fid_minor=0x%x)", len.ToLE(), fid_minor); + cellDmux->Notice("PRIVATE_STREAM_1 (len=%d, fid_minor=0x%x)", len, fid_minor); stream.skip(len); } break; @@ -521,29 +520,29 @@ u32 dmuxOpen(Demuxer* dmux_ptr) if (!stream.check(6)) { - DMUX_ERROR("End of stream (video, code=0x%x)", code.ToLE()); + DMUX_ERROR("End of stream (video, code=0x%x)", code); } stream.skip(4); stream.get(len); - if (!stream.check(len.ToLE())) + if (!stream.check(len)) { - DMUX_ERROR("End of stream (video, code=0x%x, len=%d)", code.ToLE(), len.ToLE()); + DMUX_ERROR("End of stream (video, code=0x%x, len=%d)", code, len); } const PesHeader pes(stream); if (!pes.is_ok) { - DMUX_ERROR("PesHeader error (video, code=0x%x, len=%d)", code.ToLE(), len.ToLE()); + DMUX_ERROR("PesHeader error (video, code=0x%x, len=%d)", code, len); } if (len < pes.size + 3) { - DMUX_ERROR("End of block (video, code=0x%x, PesHeader)", code.ToLE()); + DMUX_ERROR("End of block (video, code=0x%x, PesHeader)", code); } len -= pes.size + 3; - const u32 ch = code.ToLE() % 16; + const u32 ch = code % 16; if (esAVC[ch]) { ElementaryStream& es = *esAVC[ch]; @@ -562,10 +561,10 @@ u32 dmuxOpen(Demuxer* dmux_ptr) es.push_au(old_size, es.last_dts, es.last_pts, stream.userdata, false /* TODO: set correct value */, 0); // callback - auto esMsg = vm::ptr::make(a128(dmux.memAddr) + (cb_add ^= 16)); + auto esMsg = vm::ptr::make(dmux.memAddr + (cb_add ^= 16)); esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND; esMsg->supplementalInfo = stream.userdata; - es.cbFunc.call(*dmux.dmuxCb, dmux.id, es.id, esMsg, es.cbArg); + es.cbFunc(*dmux.dmuxCb, dmux.id, es.id, esMsg, es.cbArg); } if (pes.has_ts) @@ -576,13 +575,13 @@ u32 dmuxOpen(Demuxer* dmux_ptr) } // reconstruction of MPEG2-PS stream for vdec module - const u32 size = (u32)len.ToLE() + pes.size + 9; + const u32 size = len + pes.size + 9; stream = backup; es.push(stream, size); } else { - cellDmux->Notice("Video stream (code=0x%x, len=%d)", code.ToLE(), len.ToLE()); + cellDmux->Notice("Video stream (code=0x%x, len=%d)", code, len); stream.skip(len); } break; @@ -590,9 +589,9 @@ u32 dmuxOpen(Demuxer* dmux_ptr) default: { - if ((code.ToLE() & PACKET_START_CODE_MASK) == PACKET_START_CODE_PREFIX) + if ((code & PACKET_START_CODE_MASK) == PACKET_START_CODE_PREFIX) { - DMUX_ERROR("Unknown code found (0x%x)", code.ToLE()); + DMUX_ERROR("Unknown code found (0x%x)", code); } // search @@ -634,10 +633,10 @@ u32 dmuxOpen(Demuxer* dmux_ptr) case dmuxResetStream: case dmuxResetStreamAndWaitDone: { - auto dmuxMsg = vm::ptr::make(a128(dmux.memAddr) + (cb_add ^= 16)); + auto dmuxMsg = vm::ptr::make(dmux.memAddr + (cb_add ^= 16)); dmuxMsg->msgType = CELL_DMUX_MSG_TYPE_DEMUX_DONE; dmuxMsg->supplementalInfo = stream.userdata; - dmux.cbFunc.call(*dmux.dmuxCb, dmux.id, dmuxMsg, dmux.cbArg); + dmux.cbFunc(*dmux.dmuxCb, dmux.id, dmuxMsg, dmux.cbArg); stream = {}; dmux.is_running = false; @@ -722,10 +721,10 @@ u32 dmuxOpen(Demuxer* dmux_ptr) es.push_au(old_size, es.last_dts, es.last_pts, stream.userdata, false, 0); // callback - auto esMsg = vm::ptr::make(a128(dmux.memAddr) + (cb_add ^= 16)); + auto esMsg = vm::ptr::make(dmux.memAddr + (cb_add ^= 16)); esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND; esMsg->supplementalInfo = stream.userdata; - es.cbFunc.call(*dmux.dmuxCb, dmux.id, es.id, esMsg, es.cbArg); + es.cbFunc(*dmux.dmuxCb, dmux.id, es.id, esMsg, es.cbArg); } if (es.raw_data.size()) @@ -734,10 +733,10 @@ u32 dmuxOpen(Demuxer* dmux_ptr) } // callback - auto esMsg = vm::ptr::make(a128(dmux.memAddr) + (cb_add ^= 16)); + auto esMsg = vm::ptr::make(dmux.memAddr + (cb_add ^= 16)); esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_FLUSH_DONE; esMsg->supplementalInfo = stream.userdata; - es.cbFunc.call(*dmux.dmuxCb, dmux.id, es.id, esMsg, es.cbArg); + es.cbFunc(*dmux.dmuxCb, dmux.id, es.id, esMsg, es.cbArg); break; } @@ -760,12 +759,8 @@ u32 dmuxOpen(Demuxer* dmux_ptr) } dmux.is_finished = true; - if (Emu.IsStopped()) cellDmux->Warning("Demuxer thread aborted"); - if (dmux.is_closed) cellDmux->Notice("Demuxer thread ended"); }); - t.detach(); - return dmux_id; } @@ -808,7 +803,7 @@ int cellDmuxOpen(vm::ptr demuxerType, vm::ptrmemAddr, demuxerResource->memSize, vm::ptr::make(demuxerCb->cbMsgFunc.addr()), demuxerCb->cbArg)); + *demuxerHandle = dmuxOpen(new Demuxer(demuxerResource->memAddr, demuxerResource->memSize, demuxerCb->cbMsgFunc.to_le(), demuxerCb->cbArg)); return CELL_OK; } @@ -826,7 +821,7 @@ int cellDmuxOpenEx(vm::ptr demuxerType, vm::ptrmemAddr, demuxerResourceEx->memSize, vm::ptr::make(demuxerCb->cbMsgFunc.addr()), demuxerCb->cbArg)); + *demuxerHandle = dmuxOpen(new Demuxer(demuxerResourceEx->memAddr, demuxerResourceEx->memSize, demuxerCb->cbMsgFunc.to_le(), demuxerCb->cbArg)); return CELL_OK; } @@ -844,7 +839,7 @@ int cellDmuxOpen2(vm::ptr demuxerType2, vm::ptrmemAddr, demuxerResource2->memSize, vm::ptr::make(demuxerCb->cbMsgFunc.addr()), demuxerCb->cbArg)); + *demuxerHandle = dmuxOpen(new Demuxer(demuxerResource2->memAddr, demuxerResource2->memSize, demuxerCb->cbMsgFunc.to_le(), demuxerCb->cbArg)); return CELL_OK; } @@ -993,14 +988,14 @@ int cellDmuxEnableEs(u32 demuxerHandle, vm::ptr esFil std::shared_ptr es(new ElementaryStream(dmux.get(), esResourceInfo->memAddr, esResourceInfo->memSize, esFilterId->filterIdMajor, esFilterId->filterIdMinor, esFilterId->supplementalInfo1, esFilterId->supplementalInfo2, - vm::ptr::make(esCb->cbEsMsgFunc.addr()), esCb->cbArg, esSpecificInfo_addr)); + esCb->cbEsMsgFunc.to_le(), esCb->cbArg, esSpecificInfo_addr)); u32 id = cellDmux->GetNewId(es); es->id = id; *esHandle = id; cellDmux->Warning("*** New ES(dmux=%d, addr=0x%x, size=0x%x, filter(0x%x, 0x%x, 0x%x, 0x%x), cb=0x%x(arg=0x%x), spec=0x%x): id = %d", - demuxerHandle, es->memAddr, es->memSize, es->fidMajor, es->fidMinor, es->sup1, es->sup2, esCb->cbEsMsgFunc.addr(), es->cbArg, es->spec, id); + demuxerHandle, es->memAddr, es->memSize, es->fidMajor, es->fidMinor, es->sup1, es->sup2, es->cbFunc, es->cbArg, es->spec, id); DemuxerTask task(dmuxEnableEs); task.es.es = id; diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.h b/rpcs3/Emu/SysCalls/Modules/cellDmux.h index 6f0ed352b3..8a2a70cc5b 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.h +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.h @@ -1,8 +1,5 @@ #pragma once -// align size or address to 128 -#define a128(x) ((x + 127) & (~127)) - // Error Codes enum { diff --git a/rpcs3/Emu/SysCalls/Modules/cellFont.cpp b/rpcs3/Emu/SysCalls/Modules/cellFont.cpp index 0d709d6d39..69199e2f2c 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellFont.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellFont.cpp @@ -36,11 +36,11 @@ int cellFontGetRevisionFlags(vm::ptr> revisionFlags) return CELL_FONT_OK; } -int cellFontInit(vm::ptr config) +int cellFontInit(PPUThread& CPU, vm::ptr config) { cellFont->Log("cellFontInit(config=0x%x)", config.addr()); - vm::var> revisionFlags; + vm::stackvar> revisionFlags(CPU); revisionFlags.value() = 0; cellFontGetRevisionFlags(revisionFlags); return cellFontInitializeWithRevision(revisionFlags.value(), config); @@ -101,7 +101,7 @@ int cellFontOpenFontFile(vm::ptr library, vm::ptr f return ret; } -int cellFontOpenFontset(vm::ptr library, vm::ptr fontType, vm::ptr font) +int cellFontOpenFontset(PPUThread& CPU, vm::ptr library, vm::ptr fontType, vm::ptr font) { cellFont->Log("cellFontOpenFontset(library_addr=0x%x, fontType_addr=0x%x, font_addr=0x%x)", library.addr(), fontType.addr(), font.addr()); @@ -177,7 +177,7 @@ int cellFontOpenFontset(vm::ptr library, vm::ptr return CELL_FONT_ERROR_NO_SUPPORT_FONTSET; } - vm::var f((u32)file.length() + 1, 1); + vm::stackvar f(CPU, (u32)file.length() + 1, 1); memcpy(f.get_ptr(), file.c_str(), file.size() + 1); int ret = cellFontOpenFontFile(library, f, 0, 0, font); //TODO: Find the correct values of subNum, uniqueId font->origin = CELL_FONT_OPEN_FONTSET; diff --git a/rpcs3/Emu/SysCalls/Modules/cellGame.cpp b/rpcs3/Emu/SysCalls/Modules/cellGame.cpp index 227d43ca96..6fb4df09ca 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellGame.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellGame.cpp @@ -201,7 +201,7 @@ int cellGameContentPermit(vm::ptr contentInfoPath, vm: return CELL_GAME_RET_OK; } -int cellGameDataCheckCreate2(u32 version, vm::ptr dirName, u32 errDialog, +int cellGameDataCheckCreate2(PPUThread& CPU, u32 version, vm::ptr dirName, u32 errDialog, vm::ptr cbResult, vm::ptr get, vm::ptr set)> funcStat, u32 container) { cellGame->Warning("cellGameDataCheckCreate(2)(version=0x%x, dirName_addr=0x%x, errDialog=0x%x, funcStat_addr=0x%x, container=%d)", @@ -238,10 +238,9 @@ int cellGameDataCheckCreate2(u32 version, vm::ptr dirName, u32 errDi return CELL_GAMEDATA_ERROR_BROKEN; } - // TODO: use memory container - vm::var cbResult; - vm::var cbGet; - vm::var cbSet; + vm::stackvar cbResult(CPU); + vm::stackvar cbGet(CPU); + vm::stackvar cbSet(CPU); cbGet.value() = {}; @@ -273,7 +272,7 @@ int cellGameDataCheckCreate2(u32 version, vm::ptr dirName, u32 errDi if (cbSet->setParam) { // TODO: write PARAM.SFO from cbSet - cellGame->Todo("cellGameDataCheckCreate(2)(): writing PARAM.SFO parameters (addr=0x%x)", cbSet->setParam.addr()); + cellGame->Todo("cellGameDataCheckCreate(2)(): writing PARAM.SFO parameters (addr=0x%x)", cbSet->setParam); } switch ((s32)cbResult->result) @@ -307,11 +306,11 @@ int cellGameDataCheckCreate2(u32 version, vm::ptr dirName, u32 errDi } } -int cellGameDataCheckCreate(u32 version, vm::ptr dirName, u32 errDialog, +int cellGameDataCheckCreate(PPUThread& CPU, u32 version, vm::ptr dirName, u32 errDialog, vm::ptr cbResult, vm::ptr get, vm::ptr set)> funcStat, u32 container) { // TODO: almost identical, the only difference is that this function will always calculate the size of game data - return cellGameDataCheckCreate2(version, dirName, errDialog, funcStat, container); + return cellGameDataCheckCreate2(CPU, version, dirName, errDialog, funcStat, container); } int cellGameCreateGameData(vm::ptr init, vm::ptr tmp_contentInfoPath, vm::ptr tmp_usrdirPath) @@ -444,11 +443,11 @@ int cellGameContentErrorDialog(s32 type, s32 errNeedSizeKB, vm::ptr std::string errorMsg; if (type == CELL_GAME_ERRDIALOG_NOSPACE || type == CELL_GAME_ERRDIALOG_NOSPACE_EXIT) { - errorMsg = fmt::Format("ERROR: %s\nSpace needed: %d KB", errorName.c_str(), errNeedSizeKB, dirName); + errorMsg = fmt::format("ERROR: %s\nSpace needed: %d KB", errorName, errNeedSizeKB); } else { - errorMsg = fmt::Format("ERROR: %s", errorName.c_str()); + errorMsg = fmt::format("ERROR: %s", errorName); } if (dirName) diff --git a/rpcs3/Emu/SysCalls/Modules/cellGame.h b/rpcs3/Emu/SysCalls/Modules/cellGame.h index 0e7f6e3e95..1ccda34eb1 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellGame.h +++ b/rpcs3/Emu/SysCalls/Modules/cellGame.h @@ -199,4 +199,4 @@ struct CellGameDataStatSet { vm::bptr setParam; be_t reserved; -}; \ No newline at end of file +}; diff --git a/rpcs3/Emu/SysCalls/Modules/cellGem.cpp b/rpcs3/Emu/SysCalls/Modules/cellGem.cpp index d9f51ef96a..118a428a0a 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellGem.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellGem.cpp @@ -190,10 +190,9 @@ int cellGemGetInfo() return CELL_OK; } -// Should int be used, even when type is int_32t (s32)? -s32 cellGemGetMemorySize(be_t max_connect) +s32 cellGemGetMemorySize(s32 max_connect) { - cellGem->Warning("cellGemGetMemorySize(max_connect=%i)", max_connect); + cellGem->Warning("cellGemGetMemorySize(max_connect=%d)", max_connect); if (max_connect > CELL_GEM_MAX_NUM) return CELL_GEM_ERROR_INVALID_PARAMETER; diff --git a/rpcs3/Emu/SysCalls/Modules/cellGifDec.cpp b/rpcs3/Emu/SysCalls/Modules/cellGifDec.cpp index 48f52fa422..dc4a63cab1 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellGifDec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellGifDec.cpp @@ -30,17 +30,17 @@ int cellGifDecOpen(u32 mainHandle, vm::ptr subHandle, vm::ptrfd = 0; current_subHandle->src = *src; - switch(src->srcSelect.ToBE()) + switch(src->srcSelect.data()) { case se32(CELL_GIFDEC_BUFFER): - current_subHandle->fileSize = src->streamSize.ToLE(); + current_subHandle->fileSize = src->streamSize; break; case se32(CELL_GIFDEC_FILE): // Get file descriptor vm::var> fd; - int ret = cellFsOpen(vm::ptr::make(src->fileName.addr()), 0, fd, vm::ptr::make(0), 0); - current_subHandle->fd = fd->ToLE(); + int ret = cellFsOpen(src->fileName.to_le(), 0, fd, vm::ptr::make(0), 0); + current_subHandle->fd = fd.value(); if (ret != CELL_OK) return CELL_GIFDEC_ERROR_OPEN_FILE; // Get size of file @@ -74,7 +74,7 @@ int cellGifDecReadHeader(u32 mainHandle, u32 subHandle, vm::ptr vm::var buffer; // Alloc buffer for GIF header vm::var> pos, nread; - switch(subHandle_data->src.srcSelect.ToBE()) + switch(subHandle_data->src.srcSelect.data()) { case se32(CELL_GIFDEC_BUFFER): memmove(buffer.begin(), vm::get_ptr(subHandle_data->src.streamPtr), buffer.size()); @@ -156,7 +156,7 @@ int cellGifDecDecodeData(u32 mainHandle, u32 subHandle, vm::ptr data, vm::pt vm::var gif((u32)fileSize); vm::var> pos, nread; - switch(subHandle_data->src.srcSelect.ToBE()) + switch(subHandle_data->src.srcSelect.data()) { case se32(CELL_GIFDEC_BUFFER): memmove(gif.begin(), vm::get_ptr(subHandle_data->src.streamPtr), gif.size()); diff --git a/rpcs3/Emu/SysCalls/Modules/cellJpgDec.cpp b/rpcs3/Emu/SysCalls/Modules/cellJpgDec.cpp index e907298dc8..963ed69d80 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellJpgDec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellJpgDec.cpp @@ -36,17 +36,17 @@ int cellJpgDecOpen(u32 mainHandle, vm::ptr subHandle, vm::ptrfd = 0; current_subHandle->src = *src; - switch(src->srcSelect.ToBE()) + switch(src->srcSelect.data()) { case se32(CELL_JPGDEC_BUFFER): - current_subHandle->fileSize = src->streamSize.ToLE(); + current_subHandle->fileSize = src->streamSize; break; case se32(CELL_JPGDEC_FILE): // Get file descriptor vm::var> fd; - int ret = cellFsOpen(vm::ptr::make(src->fileName.addr()), 0, fd, vm::ptr::make(0), 0); - current_subHandle->fd = fd->ToLE(); + int ret = cellFsOpen(src->fileName.to_le(), 0, fd, vm::ptr::make(0), 0); + current_subHandle->fd = fd.value(); if (ret != CELL_OK) return CELL_JPGDEC_ERROR_OPEN_FILE; // Get size of file @@ -94,7 +94,7 @@ int cellJpgDecReadHeader(u32 mainHandle, u32 subHandle, vm::ptr vm::var buffer((u32)fileSize); vm::var> pos, nread; - switch(subHandle_data->src.srcSelect.ToBE()) + switch(subHandle_data->src.srcSelect.data()) { case se32(CELL_JPGDEC_BUFFER): memmove(buffer.begin(), vm::get_ptr(subHandle_data->src.streamPtr), buffer.size()); @@ -163,7 +163,7 @@ int cellJpgDecDecodeData(u32 mainHandle, u32 subHandle, vm::ptr data, vm::pt vm::var jpg((u32)fileSize); vm::var> pos, nread; - switch(subHandle_data->src.srcSelect.ToBE()) + switch(subHandle_data->src.srcSelect.data()) { case se32(CELL_JPGDEC_BUFFER): memmove(jpg.begin(), vm::get_ptr(subHandle_data->src.streamPtr), jpg.size()); @@ -261,7 +261,7 @@ int cellJpgDecDecodeData(u32 mainHandle, u32 subHandle, vm::ptr data, vm::pt case CELL_JPG_UPSAMPLE_ONLY: case CELL_JPG_GRAYSCALE_TO_ALPHA_RGBA: case CELL_JPG_GRAYSCALE_TO_ALPHA_ARGB: - cellJpgDec->Error("cellJpgDecDecodeData: Unsupported color space (%d)", current_outParam.outputColorSpace.ToLE()); + cellJpgDec->Error("cellJpgDecDecodeData: Unsupported color space (%d)", current_outParam.outputColorSpace); break; default: diff --git a/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.cpp b/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.cpp index f6f7fefbbe..64107c9461 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.cpp @@ -123,7 +123,7 @@ s32 cellMsgDialogOpen2(u32 type, vm::ptr msgString, vm::ptr msgString, vm::ptr s32 + const s32 status = (s32)g_msg_dialog_status; + Emu.GetCallbackManager().Register([callback, userData, status](PPUThread& PPU) -> s32 { - callback(status, userData); + callback(PPU, status, userData); return CELL_OK; }); } @@ -186,7 +186,6 @@ s32 cellMsgDialogOpen2(u32 type, vm::ptr msgString, vm::ptrLog("cellPadSetPressMode(port_no=%u, mode=%u)", port_no, mode); + sys_io->Log("cellPadSetPressMode(port_no=%d, mode=%d)", port_no, mode); if (!Emu.GetPadManager().IsInited()) return CELL_PAD_ERROR_UNINITIALIZED; if (mode != 0 && mode != 1) return CELL_PAD_ERROR_INVALID_PARAMETER; const PadInfo& rinfo = Emu.GetPadManager().GetInfo(); @@ -405,7 +405,7 @@ int cellPadSetPressMode(u32 port_no, u32 mode) int cellPadSetSensorMode(u32 port_no, u32 mode) { - sys_io->Log("cellPadSetSensorMode(port_no=%u, mode=%u)", port_no, mode); + sys_io->Log("cellPadSetSensorMode(port_no=%d, mode=%d)", port_no, mode); if (!Emu.GetPadManager().IsInited()) return CELL_PAD_ERROR_UNINITIALIZED; if (mode != 0 && mode != 1) return CELL_PAD_ERROR_INVALID_PARAMETER; const PadInfo& rinfo = Emu.GetPadManager().GetInfo(); diff --git a/rpcs3/Emu/SysCalls/Modules/cellPngDec.cpp b/rpcs3/Emu/SysCalls/Modules/cellPngDec.cpp index 973c1dff2b..d509f4f6c7 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPngDec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellPngDec.cpp @@ -77,17 +77,17 @@ s64 pngDecOpen( stream->fd = 0; stream->src = *src; - switch ((u32)src->srcSelect.ToBE()) + switch (src->srcSelect.data()) { case se32(CELL_PNGDEC_BUFFER): - stream->fileSize = src->streamSize.ToLE(); + stream->fileSize = src->streamSize; break; case se32(CELL_PNGDEC_FILE): // Get file descriptor vm::var> fd; - int ret = cellFsOpen(vm::ptr::make(src->fileName.addr()), 0, fd, vm::ptr::make(0), 0); - stream->fd = fd->ToLE(); + int ret = cellFsOpen(src->fileName.to_le(), 0, fd, vm::ptr::make(0), 0); + stream->fd = fd.value(); if (ret != CELL_OK) return CELL_PNGDEC_ERROR_OPEN_FILE; // Get size of file @@ -145,7 +145,7 @@ s64 pngReadHeader( auto buffer_32 = buffer.To>(); vm::var> pos, nread; - switch ((u32)stream->src.srcSelect.ToBE()) + switch (stream->src.srcSelect.data()) { case se32(CELL_PNGDEC_BUFFER): memmove(buffer.begin(), stream->src.streamPtr.get_ptr(), buffer.size()); @@ -156,9 +156,9 @@ s64 pngReadHeader( break; } - if (buffer_32[0].ToBE() != se32(0x89504E47) || - buffer_32[1].ToBE() != se32(0x0D0A1A0A) || // Error: The first 8 bytes are not a valid PNG signature - buffer_32[3].ToBE() != se32(0x49484452)) // Error: The PNG file does not start with an IHDR chunk + if (buffer_32[0].data() != se32(0x89504E47) || + buffer_32[1].data() != se32(0x0D0A1A0A) || // Error: The first 8 bytes are not a valid PNG signature + buffer_32[3].data() != se32(0x49484452)) // Error: The PNG file does not start with an IHDR chunk { return CELL_PNGDEC_ERROR_HEADER; } @@ -206,7 +206,7 @@ s64 pngDecSetParameter( current_outParam.outputHeight = current_info.imageHeight; current_outParam.outputColorSpace = inParam->outputColorSpace; - switch ((u32)current_outParam.outputColorSpace.ToBE()) + switch (current_outParam.outputColorSpace.data()) { case se32(CELL_PNGDEC_PALETTE): case se32(CELL_PNGDEC_GRAYSCALE): @@ -223,7 +223,7 @@ s64 pngDecSetParameter( current_outParam.outputComponents = 4; break; default: - cellPngDec->Error("pngDecSetParameter: Unsupported color space (%d)", current_outParam.outputColorSpace.ToLE()); + cellPngDec->Error("pngDecSetParameter: Unsupported color space (%d)", current_outParam.outputColorSpace); return CELL_PNGDEC_ERROR_ARG; } @@ -254,7 +254,7 @@ s64 pngDecodeData( vm::var png((u32)fileSize); vm::var> pos, nread; - switch ((u32)stream->src.srcSelect.ToBE()) + switch (stream->src.srcSelect.data()) { case se32(CELL_PNGDEC_BUFFER): memmove(png.begin(), stream->src.streamPtr.get_ptr(), png.size()); @@ -283,7 +283,7 @@ s64 pngDecodeData( const int bytesPerLine = (u32)dataCtrlParam->outputBytesPerLine; uint image_size = width * height; - switch ((u32)current_outParam.outputColorSpace.ToBE()) + switch (current_outParam.outputColorSpace.data()) { case se32(CELL_PNGDEC_RGB): case se32(CELL_PNGDEC_RGBA): @@ -352,11 +352,11 @@ s64 pngDecodeData( case se32(CELL_PNGDEC_GRAYSCALE): case se32(CELL_PNGDEC_PALETTE): case se32(CELL_PNGDEC_GRAYSCALE_ALPHA): - cellPngDec->Error("pngDecodeData: Unsupported color space (%d)", current_outParam.outputColorSpace.ToLE()); + cellPngDec->Error("pngDecodeData: Unsupported color space (%d)", current_outParam.outputColorSpace); break; default: - cellPngDec->Error("pngDecodeData: Unsupported color space (%d)", current_outParam.outputColorSpace.ToLE()); + cellPngDec->Error("pngDecodeData: Unsupported color space (%d)", current_outParam.outputColorSpace); return CELL_PNGDEC_ERROR_ARG; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellResc.cpp b/rpcs3/Emu/SysCalls/Modules/cellResc.cpp index c87eb12b6d..7cf2717bea 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellResc.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellResc.cpp @@ -970,11 +970,11 @@ int cellRescSetSrc(s32 idx, vm::ptr src) return CELL_RESC_ERROR_BAD_ARGUMENT; } - cellResc->Log(" *** format=0x%x", src->format.ToLE()); - cellResc->Log(" *** pitch=%d", src->pitch.ToLE()); - cellResc->Log(" *** width=%d", src->width.ToLE()); - cellResc->Log(" *** height=%d", src->height.ToLE()); - cellResc->Log(" *** offset=0x%x", src->offset.ToLE()); + cellResc->Log(" *** format=0x%x", src->format); + cellResc->Log(" *** pitch=%d", src->pitch); + cellResc->Log(" *** width=%d", src->width); + cellResc->Log(" *** height=%d", src->height); + cellResc->Log(" *** offset=0x%x", src->offset); s_rescInternalInstance->m_rescSrc[idx] = *src; @@ -1054,7 +1054,7 @@ int cellRescSetBufferAddress(vm::ptr colorBuffers, vm::ptr vertexArray for (int i=0; im_dstOffsets[i] = dstOffset->ToLE() + i * s_rescInternalInstance->m_dstBufInterval; + s_rescInternalInstance->m_dstOffsets[i] = dstOffset.value() + i * s_rescInternalInstance->m_dstBufInterval; } for (int i=0; iWarning("cellRescCreateInterlaceTable(ea_addr=0x%x, depth = %i, length = %i)", ea_addr, depth, length); + cellResc->Warning("cellRescCreateInterlaceTable(ea_addr=0x%x, srcH=%f, depth=%d, length=%d)", ea_addr, srcH, depth, length); if (!s_rescInternalInstance->m_bInitialized) { diff --git a/rpcs3/Emu/SysCalls/Modules/cellRtc.cpp b/rpcs3/Emu/SysCalls/Modules/cellRtc.cpp index aae606a4d1..59b166eee3 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellRtc.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellRtc.cpp @@ -81,7 +81,7 @@ int cellRtcFormatRfc2822(vm::ptr pszDateTime, vm::ptr pUtc, s date.Add(tz); // Format date string in RFC2822 format (e.g.: Mon, 01 Jan 1990 12:00:00 +0000). - const std::string& str = date.Format("%a, %d %b %Y %T %z", rDateTime::TZ::UTC); + const std::string str = date.Format("%a, %d %b %Y %T %z", rDateTime::TZ::UTC); memcpy(pszDateTime.get_ptr(), str.c_str(), str.size() + 1); return CELL_OK; @@ -95,7 +95,7 @@ int cellRtcFormatRfc2822LocalTime(vm::ptr pszDateTime, vm::ptrtick); // Format date string in RFC2822 format (e.g.: Mon, 01 Jan 1990 12:00:00 +0000). - const std::string& str = date.Format("%a, %d %b %Y %T %z", rDateTime::TZ::Local); + const std::string str = date.Format("%a, %d %b %Y %T %z", rDateTime::TZ::Local); memcpy(pszDateTime.get_ptr(), str.c_str(), str.size() + 1); return CELL_OK; @@ -113,7 +113,7 @@ int cellRtcFormatRfc3339(vm::ptr pszDateTime, vm::ptr pUtc, s date.Add(tz); // Format date string in RFC3339 format (e.g.: 1990-01-01T12:00:00.00Z). - const std::string& str = date.Format("%FT%T.%zZ", rDateTime::TZ::UTC); + const std::string str = date.Format("%FT%T.%zZ", rDateTime::TZ::UTC); memcpy(pszDateTime.get_ptr(), str.c_str(), str.size() + 1); return CELL_OK; @@ -127,7 +127,7 @@ int cellRtcFormatRfc3339LocalTime(vm::ptr pszDateTime, vm::ptrtick); // Format date string in RFC3339 format (e.g.: 1990-01-01T12:00:00.00Z). - const std::string& str = date.Format("%FT%T.%zZ", rDateTime::TZ::Local); + const std::string str = date.Format("%FT%T.%zZ", rDateTime::TZ::Local); memcpy(pszDateTime.get_ptr(), str.c_str(), str.size() + 1); return CELL_OK; @@ -163,7 +163,7 @@ int cellRtcGetTick(vm::ptr pTime, vm::ptr pTick) { cellRtc->Log("cellRtcGetTick(pTime=0x%x, pTick=0x%x)", pTime.addr(), pTick.addr()); - rDateTime datetime = rDateTime(pTime->day, (rDateTime::Month)pTime->month.ToLE(), pTime->year, pTime->hour, pTime->minute, pTime->second, (pTime->microsecond / 1000)); + rDateTime datetime = rDateTime(pTime->day, (rDateTime::Month)pTime->month.value(), pTime->year, pTime->hour, pTime->minute, pTime->second, (pTime->microsecond / 1000)); pTick->tick = datetime.GetTicks(); return CELL_OK; @@ -315,7 +315,7 @@ int cellRtcGetDosTime(vm::ptr pDateTime, vm::ptr puiDosTim cellRtc->Log("cellRtcGetDosTime(pDateTime=0x%x, puiDosTime=0x%x)", pDateTime.addr(), puiDosTime.addr()); // Convert to DOS time. - rDateTime date_time = rDateTime(pDateTime->day, (rDateTime::Month)pDateTime->month.ToLE(), pDateTime->year, pDateTime->hour, pDateTime->minute, pDateTime->second, (pDateTime->microsecond / 1000)); + rDateTime date_time = rDateTime(pDateTime->day, (rDateTime::Month)pDateTime->month.value(), pDateTime->year, pDateTime->hour, pDateTime->minute, pDateTime->second, (pDateTime->microsecond / 1000)); *puiDosTime = date_time.GetAsDOS(); return CELL_OK; @@ -326,7 +326,7 @@ int cellRtcGetTime_t(vm::ptr pDateTime, vm::ptr piTime) cellRtc->Log("cellRtcGetTime_t(pDateTime=0x%x, piTime=0x%x)", pDateTime.addr(), piTime.addr()); // Convert to POSIX time_t. - rDateTime date_time = rDateTime(pDateTime->day, (rDateTime::Month)pDateTime->month.ToLE(), pDateTime->year, pDateTime->hour, pDateTime->minute, pDateTime->second, (pDateTime->microsecond / 1000)); + rDateTime date_time = rDateTime(pDateTime->day, (rDateTime::Month)pDateTime->month.value(), pDateTime->year, pDateTime->hour, pDateTime->minute, pDateTime->second, (pDateTime->microsecond / 1000)); *piTime = convertToUNIXTime(date_time.GetSecond(rDateTime::TZ::UTC), date_time.GetMinute(rDateTime::TZ::UTC), date_time.GetHour(rDateTime::TZ::UTC), date_time.GetDay(rDateTime::TZ::UTC), date_time.GetYear(rDateTime::TZ::UTC)); @@ -338,7 +338,7 @@ int cellRtcGetWin32FileTime(vm::ptr pDateTime, vm::ptr pul cellRtc->Log("cellRtcGetWin32FileTime(pDateTime=0x%x, pulWin32FileTime=0x%x)", pDateTime.addr(), pulWin32FileTime.addr()); // Convert to WIN32 FILETIME. - rDateTime date_time = rDateTime(pDateTime->day, (rDateTime::Month)pDateTime->month.ToLE(), pDateTime->year, pDateTime->hour, pDateTime->minute, pDateTime->second, (pDateTime->microsecond / 1000)); + rDateTime date_time = rDateTime(pDateTime->day, (rDateTime::Month)pDateTime->month.value(), pDateTime->year, pDateTime->hour, pDateTime->minute, pDateTime->second, (pDateTime->microsecond / 1000)); *pulWin32FileTime = convertToWin32FILETIME(date_time.GetSecond(rDateTime::TZ::UTC), date_time.GetMinute(rDateTime::TZ::UTC), date_time.GetHour(rDateTime::TZ::UTC), date_time.GetDay(rDateTime::TZ::UTC), date_time.GetYear(rDateTime::TZ::UTC)); @@ -382,7 +382,7 @@ int cellRtcSetTime_t(vm::ptr pDateTime, u64 iTime) int cellRtcSetWin32FileTime(vm::ptr pDateTime, u64 ulWin32FileTime) { - cellRtc->Log("cellRtcSetWin32FileTime(pDateTime=0x%x, ulWin32FileTime=0x%llx)", pDateTime, ulWin32FileTime); + cellRtc->Log("cellRtcSetWin32FileTime(pDateTime_addr=0x%x, ulWin32FileTime=0x%llx)", pDateTime.addr(), ulWin32FileTime); rDateTime date_time = rDateTime((time_t)ulWin32FileTime); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSail.cpp b/rpcs3/Emu/SysCalls/Modules/cellSail.cpp index 9e5ee1fc73..1e4cdc6741 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSail.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSail.cpp @@ -94,7 +94,7 @@ int cellSailDescriptorIsAutoSelection(vm::ptr pSelf) return CELL_OK; } -int cellSailDescriptorCreateDatabase(vm::ptr pSelf, vm::ptr pDatabase, be_t size, be_t arg) +int cellSailDescriptorCreateDatabase(vm::ptr pSelf, vm::ptr pDatabase, u32 size, u64 arg) { cellSail->Warning("cellSailDescriptorCreateDatabase(pSelf=0x%x, pDatabase=0x%x, size=0x%x, arg=0x%x", pSelf.addr(), pDatabase.addr(), size, arg); @@ -825,7 +825,7 @@ int cellSailPlayerIsPaused(vm::ptr pSelf) int cellSailPlayerSetRepeatMode(vm::ptr pSelf, s32 repeatMode, vm::ptr pCommand) { - cellSail->Warning("cellSailPlayerSetRepeatMode(pSelf_addr=0x%x, repeatMode=%i, pCommand_addr=0x%x)", pSelf.addr(), repeatMode, pCommand.addr()); + cellSail->Warning("cellSailPlayerSetRepeatMode(pSelf_addr=0x%x, repeatMode=%d, pCommand_addr=0x%x)", pSelf.addr(), repeatMode, pCommand.addr()); pSelf->repeatMode = repeatMode; pSelf->playbackCommand = pCommand; diff --git a/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp b/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp index 58d0df01d0..18724020af 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp @@ -205,7 +205,7 @@ void getSaveDataStat(SaveDataEntry entry, vm::ptr statGet) strcpy_trunc(statGet->getParam.listParam, entry.listParam); statGet->fileNum = 0; - statGet->fileList.set(be_t::make(0)); + statGet->fileList.set(0); statGet->fileListNum = 0; std::string saveDir = "/dev_hdd0/home/00000001/savedata/" + entry.dirName; // TODO: Get the path of the current user vfsDir dir(saveDir); @@ -242,7 +242,7 @@ void getSaveDataStat(SaveDataEntry entry, vm::ptr statGet) } } - statGet->fileList = vm::ptr::make((u32)Memory.Alloc(sizeof(CellSaveDataFileStat) * fileEntries.size(), 8)); + statGet->fileList.set((u32)Memory.Alloc(sizeof(CellSaveDataFileStat) * fileEntries.size(), 8)); for (u32 i = 0; i < fileEntries.size(); i++) { CellSaveDataFileStat *dst = &statGet->fileList[i]; memcpy(dst, &fileEntries[i], sizeof(CellSaveDataFileStat)); @@ -306,7 +306,7 @@ s32 modifySaveDataFiles(vm::ptr funcFile, vm::ptrWarning("modifySaveDataFiles: File operation CELL_SAVEDATA_FILEOP_WRITE_NOTRUNC not yet implemented"); + cellSysutil->Todo("modifySaveDataFiles: CELL_SAVEDATA_FILEOP_WRITE_NOTRUNC"); break; default: @@ -317,16 +317,22 @@ s32 modifySaveDataFiles(vm::ptr funcFile, vm::ptrIsOpened()) file->Close(); } - return CELL_SAVEDATA_RET_OK; + return CELL_OK; } // Functions -int cellSaveDataListSave2(u32 version, vm::ptr setList, vm::ptr setBuf, - vm::ptr funcList, vm::ptr funcStat, vm::ptr funcFile, - u32 container, vm::ptr userdata) +s32 cellSaveDataListSave2( + u32 version, + vm::ptr setList, + vm::ptr setBuf, + vm::ptr funcList, + vm::ptr funcStat, + vm::ptr funcFile, + u32 container, + vm::ptr userdata) { - cellSysutil->Warning("cellSaveDataListSave2(version=%d, setList_addr=0x%x, setBuf_addr=0x%x, funcList_addr=0x%x, funcStat_addr=0x%x, funcFile_addr=0x%x, container=0x%x, userdata_addr=0x%x)", + cellSysutil->Warning("cellSaveDataListSave2(version=%d, setList_addr=0x%x, setBuf_addr=0x%x, funcList_addr=0x%x, funcStat_addr=0x%x, funcFile_addr=0x%x, container=%d, userdata_addr=0x%x)", version, setList.addr(), setBuf.addr(), funcList.addr(), funcStat.addr(), funcFile.addr(), container, userdata.addr()); vm::var result; @@ -360,8 +366,8 @@ int cellSaveDataListSave2(u32 version, vm::ptr setList, vm: // Sort the entries and fill the listGet->dirList array std::sort(saveEntries.begin(), saveEntries.end(), sortSaveDataEntry(setList->sortType, setList->sortOrder)); - listGet->dirList = vm::bptr::make(setBuf->buf.addr()); - auto dirList = vm::get_ptr(listGet->dirList.addr()); + listGet->dirList.set(setBuf->buf.addr()); + auto dirList = listGet->dirList.get_ptr(); for (u32 i=0; i setList, vm: return CELL_SAVEDATA_ERROR_CBRESULT; } - setSaveDataList(saveEntries, vm::ptr::make(listSet->fixedList.addr()), listSet->fixedListNum); + setSaveDataList(saveEntries, listSet->fixedList.to_le(), listSet->fixedListNum); if (listSet->newData) - addNewSaveDataEntry(saveEntries, vm::ptr::make(listSet->newData.addr())); + addNewSaveDataEntry(saveEntries, listSet->newData.to_le()); if (saveEntries.size() == 0) { - cellSysutil->Warning("cellSaveDataListSave2: No save entries found!"); // TODO: Find a better way to handle this error - return CELL_SAVEDATA_RET_OK; + cellSysutil->Error("cellSaveDataListSave2: No save entries found!"); // TODO: Find a better way to handle this error + return CELL_OK; } u32 focusIndex = focusSaveDataEntry(saveEntries, listSet->focusPosition); @@ -407,11 +413,17 @@ int cellSaveDataListSave2(u32 version, vm::ptr setList, vm: return ret; } -int cellSaveDataListLoad2(u32 version, vm::ptr setList, vm::ptr setBuf, - vm::ptr funcList, vm::ptr funcStat, vm::ptr funcFile, - u32 container, vm::ptr userdata) +s32 cellSaveDataListLoad2( + u32 version, + vm::ptr setList, + vm::ptr setBuf, + vm::ptr funcList, + vm::ptr funcStat, + vm::ptr funcFile, + u32 container, + vm::ptr userdata) { - cellSysutil->Warning("cellSaveDataListLoad2(version=%d, setList_addr=0x%x, setBuf_addr=0x%x, funcList_addr=0x%x, funcStat_addr=0x%x, funcFile_addr=0x%x, container=0x%x, userdata_addr=0x%x)", + cellSysutil->Warning("cellSaveDataListLoad2(version=%d, setList_addr=0x%x, setBuf_addr=0x%x, funcList_addr=0x%x, funcStat_addr=0x%x, funcFile_addr=0x%x, container=%d, userdata_addr=0x%x)", version, setList.addr(), setBuf.addr(), funcList.addr(), funcStat.addr(), funcFile.addr(), container, userdata.addr()); vm::var result; @@ -446,8 +458,8 @@ int cellSaveDataListLoad2(u32 version, vm::ptr setList, vm: // Sort the entries and fill the listGet->dirList array std::sort(saveEntries.begin(), saveEntries.end(), sortSaveDataEntry(setList->sortType, setList->sortOrder)); - listGet->dirList = vm::bptr::make(setBuf->buf.addr()); - auto dirList = vm::get_ptr(listGet->dirList.addr()); + listGet->dirList.set(setBuf->buf.addr()); + auto dirList = listGet->dirList.get_ptr(); for (u32 i=0; i setList, vm: return CELL_SAVEDATA_ERROR_CBRESULT; } - setSaveDataList(saveEntries, vm::ptr::make(listSet->fixedList.addr()), listSet->fixedListNum); + setSaveDataList(saveEntries, listSet->fixedList.to_le(), listSet->fixedListNum); if (listSet->newData) - addNewSaveDataEntry(saveEntries, vm::ptr::make(listSet->newData.addr())); + addNewSaveDataEntry(saveEntries, listSet->newData.to_le()); if (saveEntries.size() == 0) { - cellSysutil->Warning("cellSaveDataListLoad2: No save entries found!"); // TODO: Find a better way to handle this error - return CELL_SAVEDATA_RET_OK; + cellSysutil->Error("cellSaveDataListLoad2: No save entries found!"); // TODO: Find a better way to handle this error + return CELL_OK; } u32 focusIndex = focusSaveDataEntry(saveEntries, listSet->focusPosition); @@ -493,11 +505,17 @@ int cellSaveDataListLoad2(u32 version, vm::ptr setList, vm: return ret; } -int cellSaveDataFixedSave2(u32 version, vm::ptr setList, vm::ptr setBuf, - vm::ptr funcFixed, vm::ptr funcStat, vm::ptr funcFile, - u32 container, vm::ptr userdata) +s32 cellSaveDataFixedSave2( + u32 version, + vm::ptr setList, + vm::ptr setBuf, + vm::ptr funcFixed, + vm::ptr funcStat, + vm::ptr funcFile, + u32 container, + vm::ptr userdata) { - cellSysutil->Warning("cellSaveDataFixedSave2(version=%d, setList_addr=0x%x, setBuf_addr=0x%x, funcFixed_addr=0x%x, funcStat_addr=0x%x, funcFile_addr=0x%x, container=0x%x, userdata_addr=0x%x)", + cellSysutil->Warning("cellSaveDataFixedSave2(version=%d, setList_addr=0x%x, setBuf_addr=0x%x, funcFixed_addr=0x%x, funcStat_addr=0x%x, funcFile_addr=0x%x, container=%d, userdata_addr=0x%x)", version, setList.addr(), setBuf.addr(), funcFixed.addr(), funcStat.addr(), funcFile.addr(), container, userdata.addr()); vm::var result; @@ -530,8 +548,8 @@ int cellSaveDataFixedSave2(u32 version, vm::ptr setList, v // Sort the entries and fill the listGet->dirList array std::sort(saveEntries.begin(), saveEntries.end(), sortSaveDataEntry(setList->sortType, setList->sortOrder)); - listGet->dirList = vm::bptr::make(setBuf->buf.addr()); - auto dirList = vm::get_ptr(listGet->dirList.addr()); + listGet->dirList.set(setBuf->buf.addr()); + auto dirList = listGet->dirList.get_ptr(); for (u32 i = 0; i setList, v return ret; } -int cellSaveDataFixedLoad2(u32 version, vm::ptr setList, vm::ptr setBuf, - vm::ptr funcFixed, vm::ptr funcStat, vm::ptr funcFile, - u32 container, vm::ptr userdata) +s32 cellSaveDataFixedLoad2( + u32 version, + vm::ptr setList, + vm::ptr setBuf, + vm::ptr funcFixed, + vm::ptr funcStat, + vm::ptr funcFile, + u32 container, + vm::ptr userdata) { - cellSysutil->Warning("cellSaveDataFixedLoad2(version=%d, setList_addr=0x%x, setBuf=0x%x, funcList=0x%x, funcStat=0x%x, funcFile=0x%x, container=0x%x, userdata_addr=0x%x)", + cellSysutil->Warning("cellSaveDataFixedLoad2(version=%d, setList_addr=0x%x, setBuf_addr=0x%x, funcFixed_addr=0x%x, funcStat_addr=0x%x, funcFile_addr=0x%x, container=%d, userdata_addr=0x%x)", version, setList.addr(), setBuf.addr(), funcFixed.addr(), funcStat.addr(), funcFile.addr(), container, userdata.addr()); vm::var result; @@ -600,8 +624,8 @@ int cellSaveDataFixedLoad2(u32 version, vm::ptr setList, v // Sort the entries and fill the listGet->dirList array std::sort(saveEntries.begin(), saveEntries.end(), sortSaveDataEntry(setList->sortType, setList->sortOrder)); - listGet->dirList = vm::bptr::make(setBuf->buf.addr()); - auto dirList = vm::get_ptr(listGet->dirList.addr()); + listGet->dirList.set(setBuf->buf.addr()); + auto dirList = listGet->dirList.get_ptr(); for (u32 i = 0; i setList, v return ret; } -int cellSaveDataAutoSave2(u32 version, vm::ptr dirName, u32 errDialog, vm::ptr setBuf, - vm::ptr funcStat, vm::ptr funcFile, - u32 container, vm::ptr userdata) +s32 cellSaveDataAutoSave2( + u32 version, + vm::ptr dirName, + u32 errDialog, + vm::ptr setBuf, + vm::ptr funcStat, + vm::ptr funcFile, + u32 container, + vm::ptr userdata) { - cellSysutil->Warning("cellSaveDataAutoSave2(version=%d, dirName_addr=0x%x, errDialog=%d, setBuf=0x%x, funcList=0x%x, funcStat=0x%x, funcFile=0x%x, container=0x%x, userdata_addr=0x%x)", + cellSysutil->Warning("cellSaveDataAutoSave2(version=%d, dirName_addr=0x%x, errDialog=%d, setBuf_addr=0x%x, funcStat_addr=0x%x, funcFile_addr=0x%x, container=%d, userdata_addr=0x%x)", version, dirName.addr(), errDialog, setBuf.addr(), funcStat.addr(), funcFile.addr(), container, userdata.addr()); vm::var result; @@ -685,14 +715,20 @@ int cellSaveDataAutoSave2(u32 version, vm::ptr dirName, u32 errDialo // Enter the loop where the save files are read/created/deleted. s32 ret = modifySaveDataFiles(funcFile, result, saveBaseDir + (char*)statGet->dir.dirName); - return CELL_SAVEDATA_RET_OK; + return CELL_OK; } -int cellSaveDataAutoLoad2(u32 version, vm::ptr dirName, u32 errDialog, vm::ptr setBuf, - vm::ptr funcStat, vm::ptr funcFile, - u32 container, vm::ptr userdata) +s32 cellSaveDataAutoLoad2( + u32 version, + vm::ptr dirName, + u32 errDialog, + vm::ptr setBuf, + vm::ptr funcStat, + vm::ptr funcFile, + u32 container, + vm::ptr userdata) { - cellSysutil->Warning("cellSaveDataAutoLoad2(version=%d, dirName_addr=0x%x, errDialog=%d, setBuf=0x%x, funcList=0x%x, funcStat=0x%x, funcFile=0x%x, container=0x%x, userdata_addr=0x%x)", + cellSysutil->Warning("cellSaveDataAutoLoad2(version=%d, dirName_addr=0x%x, errDialog=%d, setBuf_addr=0x%x, funcStat_addr=0x%x, funcFile_addr=0x%x, container=%d, userdata_addr=0x%x)", version, dirName.addr(), errDialog, setBuf.addr(), funcStat.addr(), funcFile.addr(), container, userdata.addr()); vm::var result; @@ -715,7 +751,7 @@ int cellSaveDataAutoLoad2(u32 version, vm::ptr dirName, u32 errDialo // The target entry does not exist if (saveEntries.size() == 0) { - cellSysutil->Warning("cellSaveDataAutoLoad2: Couldn't find save entry (%s)", dirN.c_str()); + cellSysutil->Error("cellSaveDataAutoLoad2: Couldn't find save entry (%s)", dirN.c_str()); return CELL_OK; // TODO: Can anyone check the actual behaviour of a PS3 when saves are not found? } @@ -735,13 +771,21 @@ int cellSaveDataAutoLoad2(u32 version, vm::ptr dirName, u32 errDialo // Enter the loop where the save files are read/created/deleted. s32 ret = modifySaveDataFiles(funcFile, result, saveBaseDir + (char*)statGet->dir.dirName); - return CELL_SAVEDATA_RET_OK; + return CELL_OK; } -int cellSaveDataListAutoSave(u32 version, u32 errDialog, vm::ptr setList, vm::ptr setBuf, vm::ptr funcFixed, - vm::ptr funcStat, vm::ptr funcFile, u32 container, vm::ptr userdata) +s32 cellSaveDataListAutoSave( + u32 version, + u32 errDialog, + vm::ptr setList, + vm::ptr setBuf, + vm::ptr funcFixed, + vm::ptr funcStat, + vm::ptr funcFile, + u32 container, + vm::ptr userdata) { - cellSysutil->Todo("cellSaveDataListAutoSave(version=%d, errDialog=%d, setBuf=0x%x, funcFixed=0x%x, funcStat=0x%x, funcFile=0x%x, container=0x%x, userdata_addr=0x%x)", + cellSysutil->Todo("cellSaveDataListAutoSave(version=%d, errDialog=%d, setList_addr=0x%x, setBuf_addr=0x%x, funcFixed_addr=0x%x, funcStat_addr=0x%x, funcFile_addr=0x%x, container=%d, userdata_addr=0x%x)", version, errDialog, setList.addr(), setBuf.addr(), funcFixed.addr(), funcStat.addr(), funcFile.addr(), container, userdata.addr()); //vm::var result; @@ -792,19 +836,10 @@ int cellSaveDataListAutoSave(u32 version, u32 errDialog, vm::ptrfixedList.addr(), listSet->fixedListNum); - //if (listSet->newData) - // addNewSaveDataEntry(saveEntries, (u32)listSet->newData.addr()); - //if (saveEntries.size() == 0) { - // cellSysutil->Warning("cellSaveDataListAutoSave: No save entries found!"); // TODO: Find a better way to handle this error - // return CELL_SAVEDATA_RET_OK; - //} - - //u32 focusIndex = focusSaveDataEntry(saveEntries, listSet->focusPosition); - //// TODO: Display the dialog here - //u32 selectedIndex = focusIndex; // TODO: Until the dialog is implemented, select always the focused entry - //getSaveDataStat(saveEntries[selectedIndex], statGet.addr()); - //result->userdata_addr = userdata_addr; + //setSaveDataFixed(saveEntries, fixedSet); + //getSaveDataStat(saveEntries[0], statGet); // There should be only one element in this list + //// TODO: Display the Yes|No dialog here + //result->userdata = userdata; //funcStat(result, statGet, statSet); //Memory.Free(statGet->fileList.addr()); @@ -814,19 +849,27 @@ int cellSaveDataListAutoSave(u32 version, u32 errDialog, vm::ptrsetParam) - //addNewSaveDataEntry(saveEntries, (u32)listSet->newData.addr()); // TODO: This *is* wrong + //// TODO: Write PARAM.SFO file //*/ //// Enter the loop where the save files are read/created/deleted. //s32 ret = modifySaveDataFiles(funcFile, result, saveBaseDir + (char*)statGet->dir.dirName); - return CELL_SAVEDATA_RET_OK; + return CELL_OK; } -int cellSaveDataListAutoLoad(u32 version, u32 errDialog, vm::ptr setList, vm::ptr setBuf, vm::ptr funcFixed, - vm::ptr funcStat, vm::ptr funcFile, u32 container, vm::ptr userdata) +s32 cellSaveDataListAutoLoad( + u32 version, + u32 errDialog, + vm::ptr setList, + vm::ptr setBuf, + vm::ptr funcFixed, + vm::ptr funcStat, + vm::ptr funcFile, + u32 container, + vm::ptr userdata) { - cellSysutil->Todo("cellSaveDataListAutoLoad(version=%d, errDialog=%d, setBuf=0x%x, funcFixed=0x%x, funcStat=0x%x, funcFile=0x%x, container=0x%x, userdata_addr=0x%x)", - version, errDialog, setList.addr(), setBuf.addr(), funcFixed.addr(), funcStat.addr(), funcFile.addr(), container, userdata.addr()); + cellSysutil->Todo("cellSaveDataListAutoLoad(version=%d, errDialog=%d, setList_addr=0x%x, setBuf_addr=0x%x, funcFixed_addr=0x%x, funcStat_addr=0x%x, funcFile_addr=0x%x, container=%d, userdata_addr=0x%x)", + version, errDialog, setList.addr(), setBuf.addr(), funcFixed.addr(), funcStat.addr(), funcFile.addr(), container, userdata.addr()); //vm::var result; //vm::var listGet; @@ -876,193 +919,411 @@ int cellSaveDataListAutoLoad(u32 version, u32 errDialog, vm::ptrfixedList.addr(), listSet->fixedListNum); - //if (listSet->newData) - // addNewSaveDataEntry(saveEntries, (u32)listSet->newData.addr()); - //if (saveEntries.size() == 0) { - // cellSysutil->Warning("cellSaveDataListAutoLoad: No save entries found!"); // TODO: Find a better way to handle this error - // return CELL_SAVEDATA_RET_OK; - //} + //setSaveDataFixed(saveEntries, fixedSet); + //getSaveDataStat(saveEntries[0], statGet); // There should be only one element in this list + //// TODO: Display the Yes|No dialog here + //result->userdata = userdata; - //u32 focusIndex = focusSaveDataEntry(saveEntries, listSet->focusPosition); - //// TODO: Display the dialog here - //u32 selectedIndex = focusIndex; // TODO: Until the dialog is implemented, select always the focused entry - //getSaveDataStat(saveEntries[selectedIndex], statGet.addr()); - //result->userdata_addr = userdata_addr; - - //funcStat(result.addr(), statGet.addr(), statSet.addr()); + //funcStat(result, statGet, statSet); //Memory.Free(statGet->fileList.addr()); - //if (result->result < 0) { - // cellSysutil->Error("cellSaveDataListAutoLoad: CellSaveDataStatCallback failed."); // TODO: Once we verify that the entire SysCall is working, delete this debug error message. + // cellSysutil->Error("cellSaveDataFixedLoad2: CellSaveDataStatCallback failed."); // TODO: Once we verify that the entire SysCall is working, delete this debug error message. // return CELL_SAVEDATA_ERROR_CBRESULT; //} - ///*if (statSet->setParam) //// TODO: Write PARAM.SFO file //*/ //// Enter the loop where the save files are read/created/deleted. //s32 ret = modifySaveDataFiles(funcFile, result, saveBaseDir + (char*)statGet->dir.dirName); - return CELL_SAVEDATA_RET_OK; + return CELL_OK; } -int cellSaveDataDelete2(u32 container) +s32 cellSaveDataDelete2(u32 container) { - cellSysutil->Todo("cellSaveDataDelete2(container=0x%x)", container); + cellSysutil->Todo("cellSaveDataDelete2(container=%d)", container); + return CELL_SAVEDATA_RET_CANCEL; } -int cellSaveDataFixedDelete(vm::ptr setList, vm::ptr setBuf, vm::ptr funcFixed, vm::ptr funcDone, - u32 container, u32 userdata_addr) +s32 cellSaveDataFixedDelete( + vm::ptr setList, + vm::ptr setBuf, + vm::ptr funcFixed, + vm::ptr funcDone, + u32 container, + vm::ptr userdata) { - cellSysutil->Todo("cellSaveDataFixedDelete(setList=0x%x, setBuf=0x%x, funcFixed=0x%x, funcDone=0x%x, container=0x%x, userdata_addr=0x%x)", setList.addr(), setBuf.addr(), funcFixed.addr(), - funcDone.addr(), container, userdata_addr); - return CELL_SAVEDATA_RET_OK; + cellSysutil->Todo("cellSaveDataFixedDelete(setList_addr=0x%x, setBuf_addr=0x%x, funcFixed_addr=0x%x, funcDone_addr=0x%x, container=%d, userdata_addr=0x%x)", + setList.addr(), setBuf.addr(), funcFixed.addr(), funcDone.addr(), container, userdata.addr()); + + return CELL_OK; } -int cellSaveDataUserListSave(u32 version, u32 userId, vm::ptr setList, vm::ptr setBuf, vm::ptr funcList, - vm::ptr funcStat, vm::ptr funcFile, u32 container, u32 userdata_addr) +s32 cellSaveDataUserListSave( + u32 version, + u32 userId, + vm::ptr setList, + vm::ptr setBuf, + vm::ptr funcList, + vm::ptr funcStat, + vm::ptr funcFile, + u32 container, + vm::ptr userdata) { - cellSysutil->Todo("cellSaveDataUserListSave(version=%d, userId=%d, setList=0x%x, setBuf=0x%x, funcList=0x%x, funcStat=0x%x, funcFile=0x%x, container=0x%x, userdata_addr=0x%x)", version, - userId, setList.addr(), setBuf.addr(), funcList.addr(), funcStat.addr(), funcFile.addr(), container, userdata_addr); - return CELL_SAVEDATA_RET_OK; + cellSysutil->Todo("cellSaveDataUserListSave(version=%d, userId=%d, setList_addr=0x%x, setBuf_addr=0x%x, funcList_addr=0x%x, funcStat_addr=0x%x, funcFile_addr=0x%x, container=%d, userdata_addr=0x%x)", + version, userId, setList.addr(), setBuf.addr(), funcList.addr(), funcStat.addr(), funcFile.addr(), container, userdata.addr()); + + return CELL_OK; } -int cellSaveDataUserListLoad(u32 version, u32 userId, vm::ptr setList, vm::ptr setBuf, vm::ptr funcList, - vm::ptr funcStat, vm::ptr funcFile, u32 container, u32 userdata_addr) +s32 cellSaveDataUserListLoad( + u32 version, + u32 userId, + vm::ptr setList, + vm::ptr setBuf, + vm::ptr funcList, + vm::ptr funcStat, + vm::ptr funcFile, + u32 container, + vm::ptr userdata) { - cellSysutil->Todo("cellSaveDataUserListLoad(version=%d, userId=%d, setList=0x%x, setBuf=0x%x, funcList=0x%x, funcStat=0x%x, funcFile=0x%x, container=0x%x, userdata_addr=0x%x)", version, - userId, setList.addr(), setBuf.addr(), funcList.addr(), funcStat.addr(), funcFile.addr(), container, userdata_addr); - return CELL_SAVEDATA_RET_OK; + cellSysutil->Todo("cellSaveDataUserListLoad(version=%d, userId=%d, setList_addr=0x%x, setBuf_addr=0x%x, funcList_addr=0x%x, funcStat_addr=0x%x, funcFile_addr=0x%x, container=%d, userdata_addr=0x%x)", + version, userId, setList.addr(), setBuf.addr(), funcList.addr(), funcStat.addr(), funcFile.addr(), container, userdata.addr()); + + return CELL_OK; } -int cellSaveDataUserFixedSave(u32 version, u32 userId, vm::ptr setList, vm::ptr setBuf, vm::ptr funcFixed, - vm::ptr funcStat, vm::ptr funcFile, u32 container, u32 userdata_addr) +s32 cellSaveDataUserFixedSave( + u32 version, + u32 userId, + vm::ptr setList, + vm::ptr setBuf, + vm::ptr funcFixed, + vm::ptr funcStat, + vm::ptr funcFile, + u32 container, + vm::ptr userdata) { - cellSysutil->Todo("cellSaveDataUserFixedSave(version=%d, userId=%d, setList=0x%x, setBuf=0x%x, funcFixed=0x%x, funcStat=0x%x, funcFile=0x%x, container=0x%x, userdata_addr=0x%x)", version, - userId, setList.addr(), setBuf.addr(), funcFixed.addr(), funcStat.addr(), funcFile.addr(), container, userdata_addr); - return CELL_SAVEDATA_RET_OK; + cellSysutil->Todo("cellSaveDataUserFixedSave(version=%d, userId=%d, setList_addr=0x%x, setBuf_addr=0x%x, funcFixed_addr=0x%x, funcStat_addr=0x%x, funcFile_addr=0x%x, container=%d, userdata_addr=0x%x)", + version, userId, setList.addr(), setBuf.addr(), funcFixed.addr(), funcStat.addr(), funcFile.addr(), container, userdata.addr()); + + return CELL_OK; } -int cellSaveDataUserFixedLoad(u32 version, u32 userId, vm::ptr setList, vm::ptr setBuf, vm::ptr funcFixed, - vm::ptr funcStat, vm::ptr funcFile, u32 container, u32 userdata_addr) +s32 cellSaveDataUserFixedLoad( + u32 version, + u32 userId, + vm::ptr setList, + vm::ptr setBuf, + vm::ptr funcFixed, + vm::ptr funcStat, + vm::ptr funcFile, + u32 container, + vm::ptr userdata) { - cellSysutil->Todo("cellSaveDataUserFixedLoad(version=%d, userId=%d, setList=0x%x, setBuf=0x%x, funcFixed=0x%x, funcStat=0x%x, funcFile=0x%x, container=0x%x, userdata_addr=0x%x)", version, - userId, setList.addr(), setBuf.addr(), funcFixed.addr(), funcStat.addr(), funcFile.addr(), container, userdata_addr); - return CELL_SAVEDATA_RET_OK; + cellSysutil->Todo("cellSaveDataUserFixedLoad(version=%d, userId=%d, setList_addr=0x%x, setBuf_addr=0x%x, funcFixed_addr=0x%x, funcStat_addr=0x%x, funcFile_addr=0x%x, container=%d, userdata_addr=0x%x)", + version, userId, setList.addr(), setBuf.addr(), funcFixed.addr(), funcStat.addr(), funcFile.addr(), container, userdata.addr()); + + return CELL_OK; } -int cellSaveDataUserAutoSave(u32 version, u32 userId, u32 dirName_addr, u32 errDialog, vm::ptr setBuf, vm::ptr funcStat, - vm::ptr funcFile, u32 container, u32 userdata_addr) +s32 cellSaveDataUserAutoSave( + u32 version, + u32 userId, + vm::ptr dirName, + u32 errDialog, + vm::ptr setBuf, + vm::ptr funcStat, + vm::ptr funcFile, + u32 container, + vm::ptr userdata) { - cellSysutil->Todo("cellSaveDataUserAutoSave(version=%d, userId=%d, dirName_addr=0x%x, errDialog=%d, setBuf=0x%x, funcStat=0x%x, funcFile=0x%x, container=0x%x, userdata_addr=0x%x)", version, - userId, dirName_addr, errDialog, setBuf.addr(), funcStat.addr(), funcFile.addr(), container, userdata_addr); - return CELL_SAVEDATA_RET_OK; + cellSysutil->Todo("cellSaveDataUserAutoSave(version=%d, userId=%d, dirName_addr=0x%x, errDialog=%d, setBuf_addr=0x%x, funcStat_addr=0x%x, funcFile=0x%x, container=%d, userdata_addr=0x%x)", + version, userId, dirName.addr(), errDialog, setBuf.addr(), funcStat.addr(), funcFile.addr(), container, userdata.addr()); + + return CELL_OK; } -int cellSaveDataUserAutoLoad(u32 version, u32 userId, u32 dirName_addr, u32 errDialog, vm::ptr setBuf, vm::ptr funcStat, - vm::ptr funcFile, u32 container, u32 userdata_addr) +s32 cellSaveDataUserAutoLoad( + u32 version, + u32 userId, + vm::ptr dirName, + u32 errDialog, + vm::ptr setBuf, + vm::ptr funcStat, + vm::ptr funcFile, + u32 container, + vm::ptr userdata) { - cellSysutil->Todo("cellSaveDataUserAutoLoad(version=%d, userId=%d, dirName_addr=0x%x, errDialog=%d, setBuf=0x%x, funcStat=0x%x, funcFile=0x%x, container=0x%x, userdata_addr=0x%x)", version, - userId, dirName_addr, errDialog, setBuf.addr(), funcStat.addr(), funcFile.addr(), container, userdata_addr); - return CELL_SAVEDATA_RET_OK; + cellSysutil->Todo("cellSaveDataUserAutoLoad(version=%d, userId=%d, dirName_addr=0x%x, errDialog=%d, setBuf_addr=0x%x, funcStat_addr=0x%x, funcFile=0x%x, container=%d, userdata_addr=0x%x)", + version, userId, dirName.addr(), errDialog, setBuf.addr(), funcStat.addr(), funcFile.addr(), container, userdata.addr()); + + return CELL_OK; } -int cellSaveDataUserListAutoSave(u32 version, u32 userId, u32 errDialog, vm::ptr setList, vm::ptr setBuf, vm::ptr funcFixed, - vm::ptr funcStat, vm::ptr funcFile, u32 container, u32 userdata_addr) +s32 cellSaveDataUserListAutoSave( + u32 version, + u32 userId, + u32 errDialog, + vm::ptr setList, + vm::ptr setBuf, + vm::ptr funcFixed, + vm::ptr funcStat, + vm::ptr funcFile, + u32 container, + vm::ptr userdata) { - cellSysutil->Todo("cellSaveDataUserListAutoSave(version=%d, userId=%d, errDialog=%d, setList=0x%x, setBuf=0x%x, funcFixed=0x%x, funcStat=0x%x, funcFile=0x%x, container=0x%x, userdata_addr=0x%x)", - version, userId, errDialog, setList.addr(), setBuf.addr(), funcFixed.addr(), funcStat.addr(), funcFile.addr(), container, userdata_addr); - return CELL_SAVEDATA_RET_OK; + cellSysutil->Todo("cellSaveDataUserListAutoSave(version=%d, userId=%d, errDialog=%d, setList_addr=0x%x, setBuf_addr=0x%x, funcFixed_addr=0x%x, funcStat_addr=0x%x, funcFile_addr=0x%x, container=%d, userdata_addr=0x%x)", + version, userId, errDialog, setList.addr(), setBuf.addr(), funcFixed.addr(), funcStat.addr(), funcFile.addr(), container, userdata.addr()); + + return CELL_OK; } -int cellSaveDataUserListAutoLoad(u32 version, u32 userId, u32 errDialog, vm::ptr setList, vm::ptr setBuf, vm::ptr funcFixed, - vm::ptr funcStat, vm::ptr funcFile, u32 container, u32 userdata_addr) +s32 cellSaveDataUserListAutoLoad( + u32 version, + u32 userId, + u32 errDialog, + vm::ptr setList, + vm::ptr setBuf, + vm::ptr funcFixed, + vm::ptr funcStat, + vm::ptr funcFile, + u32 container, + vm::ptr userdata) { - cellSysutil->Todo("cellSaveDataUserListAutoLoad(version=%d, userId=%d, errDialog=%D, setList=0x%x, setBuf=0x%x, funcFixed=0x%x, funcStat=0x%x, funcFile=0x%x, container=0x%x, userdata_addr=0x%x)", - version, userId, errDialog, setList.addr(), setBuf.addr(), funcFixed.addr(), funcStat.addr(), funcFile.addr(), container, userdata_addr); - return CELL_SAVEDATA_RET_OK; + cellSysutil->Todo("cellSaveDataUserListAutoLoad(version=%d, userId=%d, errDialog=%d, setList_addr=0x%x, setBuf_addr=0x%x, funcFixed_addr=0x%x, funcStat_addr=0x%x, funcFile_addr=0x%x, container=%d, userdata_addr=0x%x)", + version, userId, errDialog, setList.addr(), setBuf.addr(), funcFixed.addr(), funcStat.addr(), funcFile.addr(), container, userdata.addr()); + + return CELL_OK; } -int cellSaveDataUserFixedDelete() //CellSysutilUserId userId, CellSaveDataSetList *setList, CellSaveDataSetBuf *setBuf, CellSaveDataFixedCallback funcFixed, CellSaveDataDoneCallback funcDone, sys_memory_container_t container, void *userdata +s32 cellSaveDataUserFixedDelete( + u32 userId, + vm::ptr setList, + vm::ptr setBuf, + vm::ptr funcFixed, + vm::ptr funcDone, + u32 container, + vm::ptr userdata) { - UNIMPLEMENTED_FUNC(cellSysutil); - return CELL_SAVEDATA_RET_OK; + cellSysutil->Todo("cellSaveDataUserFixedDelete(userId=%d, setList_addr=0x%x, setBuf_addr=0x%x, funcFixed_addr=0x%x, funcDone_addr=0x%x, container=%d, userdata_addr=0x%x)", + userId, setList.addr(), setBuf.addr(), funcFixed.addr(), funcDone.addr(), container, userdata.addr()); + + return CELL_OK; } -//void cellSaveDataEnableOverlay(); //int enable +void cellSaveDataEnableOverlay(s32 enable) +{ + cellSysutil->Todo("cellSaveDataEnableOverlay(enable=%d)", enable); + + return; +} // Functions (Extensions) -int cellSaveDataListDelete() //CellSaveDataSetList *setList, CellSaveDataSetBuf *setBuf, CellSaveDataListCallback funcList, CellSaveDataDoneCallback funcDone, sys_memory_container_t container, void *userdata +s32 cellSaveDataListDelete( + vm::ptr setList, + vm::ptr setBuf, + vm::ptr funcList, + vm::ptr funcDone, + u32 container, + vm::ptr userdata) { UNIMPLEMENTED_FUNC(cellSysutil); - return CELL_SAVEDATA_RET_OK; + + return CELL_OK; } -int cellSaveDataListImport() //CellSaveDataSetList *setList, u32 maxSizeKB, CellSaveDataDoneCallback funcDone, sys_memory_container_t container, void *userdata +s32 cellSaveDataListImport( + vm::ptr setList, + u32 maxSizeKB, + vm::ptr funcDone, + u32 container, + vm::ptr userdata) { UNIMPLEMENTED_FUNC(cellSysutil); - return CELL_SAVEDATA_RET_OK; + + return CELL_OK; } -int cellSaveDataListExport() //CellSaveDataSetList *setList, u32 maxSizeKB, CellSaveDataDoneCallback funcDone, sys_memory_container_t container, void *userdata +s32 cellSaveDataListExport( + vm::ptr setList, + u32 maxSizeKB, + vm::ptr funcDone, + u32 container, + vm::ptr userdata) { UNIMPLEMENTED_FUNC(cellSysutil); - return CELL_SAVEDATA_RET_OK; + + return CELL_OK; } -int cellSaveDataFixedImport() //const char *dirName, u32 maxSizeKB, CellSaveDataDoneCallback funcDone, sys_memory_container_t container, void *userdata +s32 cellSaveDataFixedImport( + vm::ptr dirName, + u32 maxSizeKB, + vm::ptr funcDone, + u32 container, + vm::ptr userdata) { UNIMPLEMENTED_FUNC(cellSysutil); - return CELL_SAVEDATA_RET_OK; + + return CELL_OK; } -int cellSaveDataFixedExport() //const char *dirName, u32 maxSizeKB, CellSaveDataDoneCallback funcDone, sys_memory_container_t container, void *userdata +s32 cellSaveDataFixedExport( + vm::ptr dirName, + u32 maxSizeKB, + vm::ptr funcDone, + u32 container, + vm::ptr userdata) { UNIMPLEMENTED_FUNC(cellSysutil); - return CELL_SAVEDATA_RET_OK; + + return CELL_OK; } -int cellSaveDataGetListItem() //const char *dirName, CellSaveDataDirStat *dir, CellSaveDataSystemFileParam *sysFileParam, vm::ptr bind, vm::ptr sizeKB +s32 cellSaveDataGetListItem( + vm::ptr dirName, + vm::ptr dir, + vm::ptr sysFileParam, + vm::ptr bind, + vm::ptr sizeKB) { UNIMPLEMENTED_FUNC(cellSysutil); - return CELL_SAVEDATA_RET_OK; + + return CELL_OK; } -int cellSaveDataUserListDelete() //CellSysutilUserId userId, CellSaveDataSetList *setList, CellSaveDataSetBuf *setBuf, CellSaveDataListCallback funcList, CellSaveDataDoneCallback funcDone,sys_memory_container_t container, void *userdata +s32 cellSaveDataUserListDelete( + u32 userId, + vm::ptr setList, + vm::ptr setBuf, + vm::ptr funcList, + vm::ptr funcDone, + u32 container, + vm::ptr userdata) { UNIMPLEMENTED_FUNC(cellSysutil); - return CELL_SAVEDATA_RET_OK; + + return CELL_OK; } -int cellSaveDataUserListImport() //CellSysutilUserId userId, CellSaveDataSetList *setList, u32 maxSizeKB, CellSaveDataDoneCallback funcDone, sys_memory_container_t container, void *userdata +s32 cellSaveDataUserListImport( + u32 userId, + vm::ptr setList, + u32 maxSizeKB, + vm::ptr funcDone, + u32 container, + vm::ptr userdata) { UNIMPLEMENTED_FUNC(cellSysutil); - return CELL_SAVEDATA_RET_OK; + + return CELL_OK; } -int cellSaveDataUserListExport() //CellSysutilUserId userId, CellSaveDataSetList *setList, u32 maxSizeKB, CellSaveDataDoneCallback funcDone, sys_memory_container_t container, void *userdata +s32 cellSaveDataUserListExport( + u32 userId, + vm::ptr setList, + u32 maxSizeKB, + vm::ptr funcDone, + u32 container, + vm::ptr userdata) { UNIMPLEMENTED_FUNC(cellSysutil); - return CELL_SAVEDATA_RET_OK; + + return CELL_OK; } -int cellSaveDataUserFixedImport() //CellSysutilUserId userId, const char *dirName, u32 maxSizeKB, CellSaveDataDoneCallback funcDone, sys_memory_container_t container, void *userdata +s32 cellSaveDataUserFixedImport( + u32 userId, + vm::ptr dirName, + u32 maxSizeKB, + vm::ptr funcDone, + u32 container, + vm::ptr userdata) { UNIMPLEMENTED_FUNC(cellSysutil); - return CELL_SAVEDATA_RET_OK; + + return CELL_OK; } -int cellSaveDataUserFixedExport() //CellSysutilUserId userId, const char *dirName, u32 maxSizeKB, CellSaveDataDoneCallback funcDone, sys_memory_container_t container, void *userdata +s32 cellSaveDataUserFixedExport( + u32 userId, + vm::ptr dirName, + u32 maxSizeKB, + vm::ptr funcDone, + u32 container, + vm::ptr userdata) { UNIMPLEMENTED_FUNC(cellSysutil); - return CELL_SAVEDATA_RET_OK; + + return CELL_OK; } -int cellSaveDataUserGetListItem() //CellSysutilUserId userId, const char *dirName, CellSaveDataDirStat *dir, CellSaveDataSystemFileParam *sysFileParam, vm::ptr bind, vm::ptr sizeKB +s32 cellSaveDataUserGetListItem( + u32 userId, + vm::ptr dirName, + vm::ptr dir, + vm::ptr sysFileParam, + vm::ptr bind, + vm::ptr sizeKB) { UNIMPLEMENTED_FUNC(cellSysutil); - return CELL_SAVEDATA_RET_OK; + + return CELL_OK; +} + +void cellSysutil_SaveData_init() +{ + // libsysutil functions: + + REG_FUNC(cellSysutil, cellSaveDataEnableOverlay); + + REG_FUNC(cellSysutil, cellSaveDataDelete2); + //REG_FUNC(cellSysutil, cellSaveDataDelete); + REG_FUNC(cellSysutil, cellSaveDataUserFixedDelete); + REG_FUNC(cellSysutil, cellSaveDataFixedDelete); + + REG_FUNC(cellSysutil, cellSaveDataUserFixedLoad); + REG_FUNC(cellSysutil, cellSaveDataUserFixedSave); + REG_FUNC(cellSysutil, cellSaveDataFixedLoad2); + REG_FUNC(cellSysutil, cellSaveDataFixedSave2); + //REG_FUNC(cellSysutil, cellSaveDataFixedLoad); + //REG_FUNC(cellSysutil, cellSaveDataFixedSave); + + REG_FUNC(cellSysutil, cellSaveDataUserListLoad); + REG_FUNC(cellSysutil, cellSaveDataUserListSave); + REG_FUNC(cellSysutil, cellSaveDataListLoad2); + REG_FUNC(cellSysutil, cellSaveDataListSave2); + //REG_FUNC(cellSysutil, cellSaveDataListLoad); + //REG_FUNC(cellSysutil, cellSaveDataListSave); + + REG_FUNC(cellSysutil, cellSaveDataUserListAutoLoad); + REG_FUNC(cellSysutil, cellSaveDataUserListAutoSave); + REG_FUNC(cellSysutil, cellSaveDataListAutoLoad); + REG_FUNC(cellSysutil, cellSaveDataListAutoSave); + + REG_FUNC(cellSysutil, cellSaveDataUserAutoLoad); + REG_FUNC(cellSysutil, cellSaveDataUserAutoSave); + REG_FUNC(cellSysutil, cellSaveDataAutoLoad2); + REG_FUNC(cellSysutil, cellSaveDataAutoSave2); + //REG_FUNC(cellSysutil, cellSaveDataAutoLoad); + //REG_FUNC(cellSysutil, cellSaveDataAutoSave); + + // libsysutil_savedata functions: + REG_FUNC(cellSysutil, cellSaveDataUserGetListItem); + REG_FUNC(cellSysutil, cellSaveDataGetListItem); + REG_FUNC(cellSysutil, cellSaveDataUserListDelete); + REG_FUNC(cellSysutil, cellSaveDataListDelete); + REG_FUNC(cellSysutil, cellSaveDataUserFixedExport); + REG_FUNC(cellSysutil, cellSaveDataUserFixedImport); + REG_FUNC(cellSysutil, cellSaveDataUserListExport); + REG_FUNC(cellSysutil, cellSaveDataUserListImport); + REG_FUNC(cellSysutil, cellSaveDataFixedExport); + REG_FUNC(cellSysutil, cellSaveDataFixedImport); + REG_FUNC(cellSysutil, cellSaveDataListExport); + REG_FUNC(cellSysutil, cellSaveDataListImport); + + // libsysutil_savedata_psp functions: } diff --git a/rpcs3/Emu/SysCalls/Modules/cellSaveData.h b/rpcs3/Emu/SysCalls/Modules/cellSaveData.h index d03bf2893a..3daa006334 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSaveData.h +++ b/rpcs3/Emu/SysCalls/Modules/cellSaveData.h @@ -257,10 +257,10 @@ struct CellSaveDataDoneGet // Callback Functions typedef void(*CellSaveDataFixedCallback)(vm::ptr cbResult, vm::ptr get, vm::ptr set); -typedef void(*CellSaveDataListCallback) (vm::ptr cbResult, vm::ptr get, vm::ptr set); -typedef void(*CellSaveDataStatCallback) (vm::ptr cbResult, vm::ptr get, vm::ptr set); -typedef void(*CellSaveDataFileCallback) (vm::ptr cbResult, vm::ptr get, vm::ptr set); -typedef void(*CellSaveDataDoneCallback) (vm::ptr cbResult, vm::ptr get); +typedef void(*CellSaveDataListCallback)(vm::ptr cbResult, vm::ptr get, vm::ptr set); +typedef void(*CellSaveDataStatCallback)(vm::ptr cbResult, vm::ptr get, vm::ptr set); +typedef void(*CellSaveDataFileCallback)(vm::ptr cbResult, vm::ptr get, vm::ptr set); +typedef void(*CellSaveDataDoneCallback)(vm::ptr cbResult, vm::ptr get); // Auxiliary Structs @@ -279,35 +279,3 @@ struct SaveDataEntry u32 iconBufSize; bool isNew; }; - - -// Function declarations -int cellSaveDataListSave2(u32 version, vm::ptr setList, vm::ptr setBuf, - vm::ptr funcList, vm::ptr funcStat, vm::ptr funcFile, - u32 container, vm::ptr userdata); - -int cellSaveDataListLoad2(u32 version, vm::ptr setList, vm::ptr setBuf, - vm::ptr funcList, vm::ptr funcStat, vm::ptr funcFile, - u32 container, vm::ptr userdata); - -int cellSaveDataFixedSave2(u32 version, vm::ptr setList, vm::ptr setBuf, - vm::ptr funcFixed, vm::ptr funcStat, vm::ptr funcFile, - u32 container, vm::ptr userdata); - -int cellSaveDataFixedLoad2(u32 version, vm::ptr setList, vm::ptr setBuf, - vm::ptr funcFixed, vm::ptr funcStat, vm::ptr funcFile, - u32 container, vm::ptr userdata); - -int cellSaveDataAutoSave2(u32 version, vm::ptr dirName, u32 errDialog, vm::ptr setBuf, - vm::ptr funcStat, vm::ptr funcFile, - u32 container, vm::ptr userdata); - -int cellSaveDataAutoLoad2(u32 version, vm::ptr dirName, u32 errDialog, vm::ptr setBuf, - vm::ptr funcStat, vm::ptr funcFile, - u32 container, vm::ptr userdata); - -int cellSaveDataListAutoSave(u32 version, u32 errDialog, vm::ptr setList, vm::ptr setBuf, vm::ptr funcFixed, - vm::ptr funcStat, vm::ptr funcFile, u32 container, vm::ptr userdata); - -int cellSaveDataListAutoLoad(u32 version, u32 errDialog, vm::ptr setList, vm::ptr setBuf, vm::ptr funcFixed, - vm::ptr funcStat, vm::ptr funcFile, u32 container, vm::ptr userdata); \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp b/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp index a9a50e2bbe..25bf599222 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp @@ -34,7 +34,7 @@ s64 spursCreateLv2EventQueue(vm::ptr spurs, u32& queue_id, vm::ptr> queue; s32 res = cb_call, vm::ptr, vm::ptr, s32, u32>(GetCurrentPPUThread(), libsre + 0xB14C, libsre_rtoc, spurs, queue, port, size, vm::read32(libsre_rtoc - 0x7E2C)); - queue_id = queue->ToLE(); + queue_id = queue; return res; #endif @@ -68,7 +68,7 @@ s64 spursInit( { #ifdef PRX_DEBUG_XXX return cb_call, u32, u32, s32, s32, s32, u32, u32, u32, u32, u32, u32, u32>(GetCurrentPPUThread(), libsre + 0x74E4, libsre_rtoc, - spurs, revision, sdkVersion, nSpus, spuPriority, ppuPriority, flags, Memory.RealToVirtualAddr(prefix), prefixSize, container, Memory.RealToVirtualAddr(swlPriority), swlMaxSpu, swlIsPreem); + spurs, revision, sdkVersion, nSpus, spuPriority, ppuPriority, flags, vm::get_addr(prefix), prefixSize, container, vm::get_addr(swlPriority), swlMaxSpu, swlIsPreem); #endif // SPURS initialization (asserts should actually rollback and return the error instead) @@ -273,7 +273,7 @@ s64 spursInit( if (Emu.IsStopped()) break; spurs->m.xD64.exchange(0); - if (spurs->m.exception.ToBE() == 0) + if (spurs->m.exception.data() == 0) { bool do_break = false; for (u32 i = 0; i < 16; i++) @@ -397,7 +397,7 @@ s64 spursInit( s32 res = CELL_OK; #ifdef PRX_DEBUG res = cb_call, u32, u32, u32>(GetCurrentPPUThread(), libsre + 0x10428, libsre_rtoc, - spurs, Memory.RealToVirtualAddr(swlPriority), swlMaxSpu, swlIsPreem); + spurs, vm::get_addr(swlPriority), swlMaxSpu, swlIsPreem); #endif assert(res == CELL_OK); } @@ -460,7 +460,7 @@ s64 cellSpursInitializeWithAttribute(vm::ptr spurs, vm::ptrm.nSpus, attr->m.spuPriority, attr->m.ppuPriority, - attr->m.flags.ToLE() | (attr->m.exitIfNoWork ? SAF_EXIT_IF_NO_WORK : 0), + attr->m.flags | (attr->m.exitIfNoWork ? SAF_EXIT_IF_NO_WORK : 0), attr->m.prefix, attr->m.prefixSize, attr->m.container, @@ -496,7 +496,7 @@ s64 cellSpursInitializeWithAttribute2(vm::ptr spurs, vm::ptrm.nSpus, attr->m.spuPriority, attr->m.ppuPriority, - attr->m.flags.ToLE() | (attr->m.exitIfNoWork ? SAF_EXIT_IF_NO_WORK : 0) | SAF_SECOND_VERSION, + attr->m.flags | (attr->m.exitIfNoWork ? SAF_EXIT_IF_NO_WORK : 0) | SAF_SECOND_VERSION, attr->m.prefix, attr->m.prefixSize, attr->m.container, @@ -548,7 +548,7 @@ s64 cellSpursAttributeSetMemoryContainerForSpuThread(vm::ptr return CELL_SPURS_CORE_ERROR_ALIGN; } - if (attr->m.flags.ToLE() & SAF_SPU_TGT_EXCLUSIVE_NON_CONTEXT) + if (attr->m.flags & SAF_SPU_TGT_EXCLUSIVE_NON_CONTEXT) { return CELL_SPURS_CORE_ERROR_STAT; } @@ -622,7 +622,7 @@ s64 cellSpursAttributeSetSpuThreadGroupType(vm::ptr attr, s3 if (type == SYS_SPU_THREAD_GROUP_TYPE_EXCLUSIVE_NON_CONTEXT) { - if (attr->m.flags.ToLE() & SAF_SPU_MEMORY_CONTAINER_SET) + if (attr->m.flags & SAF_SPU_MEMORY_CONTAINER_SET) { return CELL_SPURS_CORE_ERROR_STAT; } @@ -673,7 +673,7 @@ s64 cellSpursAttributeEnableSystemWorkload(vm::ptr attr, vm: { return CELL_SPURS_CORE_ERROR_PERM; } - if (attr->m.flags.ToLE() & SAF_SYSTEM_WORKLOAD_ENABLED) + if (attr->m.flags & SAF_SYSTEM_WORKLOAD_ENABLED) { return CELL_SPURS_CORE_ERROR_BUSY; } @@ -737,7 +737,7 @@ s64 spursAttachLv2EventQueue(vm::ptr spurs, u32 queue, vm::ptr po { return CELL_SPURS_CORE_ERROR_ALIGN; } - if (spurs->m.exception.ToBE()) + if (spurs->m.exception.data()) { return CELL_SPURS_CORE_ERROR_STAT; } @@ -977,7 +977,7 @@ s64 spursWakeUp(PPUThread& CPU, vm::ptr spurs) { return CELL_SPURS_POLICY_MODULE_ERROR_ALIGN; } - if (spurs->m.exception.ToBE()) + if (spurs->m.exception.data()) { return CELL_SPURS_POLICY_MODULE_ERROR_STAT; } @@ -1024,7 +1024,7 @@ s32 spursAddWorkload( { #ifdef PRX_DEBUG_XXX return cb_call, vm::ptr, vm::ptr, u32, u64, u32, u32, u32, u32, u32, u32, u32>(GetCurrentPPUThread(), libsre + 0x96EC, libsre_rtoc, - spurs, wid, pm, size, data, Memory.RealToVirtualAddr(priorityTable), minContention, maxContention, + spurs, wid, pm, size, data, vm::get_addr(priorityTable), minContention, maxContention, nameClass.addr(), nameInstance.addr(), hook.addr(), hookArg.addr()); #endif @@ -1040,7 +1040,7 @@ s32 spursAddWorkload( { return CELL_SPURS_POLICY_MODULE_ERROR_INVAL; } - if (spurs->m.exception.ToBE()) + if (spurs->m.exception.data()) { return CELL_SPURS_POLICY_MODULE_ERROR_STAT; } @@ -1146,7 +1146,7 @@ s32 spursAddWorkload( CellSpurs::WorkloadInfo& wkl = wnum <= 15 ? spurs->m.wklInfo1[wnum] : spurs->m.wklInfo2[wnum & 0xf]; spurs->m.wklMskB.atomic_op_sync([spurs, &wkl, wnum, &res_wkl](be_t& v) { - const u32 mask = v.ToLE() & ~(0x80000000u >> wnum); + const u32 mask = v & ~(0x80000000u >> wnum); res_wkl = 0; for (u32 i = 0, m = 0x80000000, k = 0; i < 32; i++, m >>= 1) @@ -1389,11 +1389,11 @@ s64 _cellSpursWorkloadFlagReceiver(vm::ptr spurs, u32 wid, u32 is_set { return CELL_SPURS_POLICY_MODULE_ERROR_INVAL; } - if ((spurs->m.wklMskA.read_relaxed().ToLE() & (0x80000000u >> wid)) == 0) + if ((spurs->m.wklMskA.read_relaxed() & (0x80000000u >> wid)) == 0) { return CELL_SPURS_POLICY_MODULE_ERROR_SRCH; } - if (spurs->m.exception.ToBE()) + if (spurs->m.exception.data()) { return CELL_SPURS_POLICY_MODULE_ERROR_STAT; } @@ -1456,7 +1456,7 @@ s64 cellSpursGetWorkloadFlag(vm::ptr spurs, vm::ptrset(Memory.RealToVirtualAddr(&spurs->m.wklFlag)); + flag->set(vm::get_addr(&spurs->m.wklFlag)); return CELL_OK; } @@ -1551,11 +1551,11 @@ s64 cellSpursReadyCountStore(vm::ptr spurs, u32 wid, u32 value) { return CELL_SPURS_POLICY_MODULE_ERROR_INVAL; } - if ((spurs->m.wklMskA.read_relaxed().ToLE() & (0x80000000u >> wid)) == 0) + if ((spurs->m.wklMskA.read_relaxed() & (0x80000000u >> wid)) == 0) { return CELL_SPURS_POLICY_MODULE_ERROR_SRCH; } - if (spurs->m.exception.ToBE() || spurs->wklState(wid).read_relaxed() != 2) + if (spurs->m.exception.data() || spurs->wklState(wid).read_relaxed() != 2) { return CELL_SPURS_POLICY_MODULE_ERROR_STAT; } @@ -2324,7 +2324,7 @@ s64 spursCreateTaskset(vm::ptr spurs, vm::ptr tasks // TODO: Check return code taskset->m.x72 = 0x80; - taskset->m.wid.FromBE(*wid); + taskset->m.wid = *wid; // TODO: cellSpursSetExceptionEventHandler(spurs, wid, hook, taskset); // TODO: Check return code diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpurs.h b/rpcs3/Emu/SysCalls/Modules/cellSpurs.h index 32798e6006..ecbfc03efc 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpurs.h +++ b/rpcs3/Emu/SysCalls/Modules/cellSpurs.h @@ -499,12 +499,12 @@ struct CellSpurs __forceinline vm::ptr get_lwmutex() { - return vm::ptr::make(Memory.RealToVirtualAddr(&m.mutex)); + return vm::ptr::make(vm::get_addr(&m.mutex)); } __forceinline vm::ptr get_lwcond() { - return vm::ptr::make(Memory.RealToVirtualAddr(&m.cond)); + return vm::ptr::make(vm::get_addr(&m.cond)); } }; diff --git a/rpcs3/Emu/SysCalls/Modules/cellSync.cpp b/rpcs3/Emu/SysCalls/Modules/cellSync.cpp index fca2ca40f7..0c372e82e8 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSync.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSync.cpp @@ -308,7 +308,7 @@ s32 cellSyncRwmInitialize(vm::ptr rwm, vm::ptr buffer, u32 bu s32 syncRwmTryReadBeginOp(CellSyncRwm::data_t& rwm) { - if (rwm.m_writers.ToBE()) + if (rwm.m_writers.data()) { return CELL_SYNC_ERROR_BUSY; } @@ -319,9 +319,8 @@ s32 syncRwmTryReadBeginOp(CellSyncRwm::data_t& rwm) s32 syncRwmReadEndOp(CellSyncRwm::data_t& rwm) { - if (!rwm.m_readers.ToBE()) + if (!rwm.m_readers.data()) { - cellSync->Error("syncRwmReadEndOp(rwm_addr=0x%x): m_readers == 0 (m_writers=%d)", Memory.RealToVirtualAddr(&rwm), (u16)rwm.m_writers); return CELL_SYNC_ERROR_ABORT; } @@ -354,6 +353,7 @@ s32 cellSyncRwmRead(vm::ptr rwm, vm::ptr buffer) // prx: decrease m_readers (return 0x8041010C if already zero) if (s32 res = rwm->data.atomic_op(CELL_OK, syncRwmReadEndOp)) { + cellSync->Error("syncRwmReadEndOp(rwm=0x%x) failed: m_readers == 0", rwm); return res; } @@ -392,7 +392,7 @@ s32 cellSyncRwmTryRead(vm::ptr rwm, vm::ptr buffer) s32 syncRwmTryWriteBeginOp(CellSyncRwm::data_t& rwm) { - if (rwm.m_writers.ToBE()) + if (rwm.m_writers.data()) { return CELL_SYNC_ERROR_BUSY; } @@ -422,7 +422,7 @@ s32 cellSyncRwmWrite(vm::ptr rwm, vm::ptr buffer) // prx: wait until m_readers == 0 g_sync_rwm_write_wm.wait_op(rwm.addr(), [rwm]() { - return rwm->data.read_relaxed().m_readers.ToBE() == 0; + return rwm->data.read_relaxed().m_readers.data() == 0; }); // prx: copy data from buffer_addr @@ -934,13 +934,13 @@ s32 syncLFQueueInitialize(vm::ptr queue, vm::ptr buffer, u3 const auto old = queue->init.read_relaxed(); auto init = old; - if (old.ToBE()) + if (old.data()) { if (sdk_ver > 0x17ffff && old != 2) { return CELL_SYNC_ERROR_STAT; } - old_value = old.ToLE(); + old_value = old; } else { @@ -1030,7 +1030,7 @@ s32 syncLFQueueGetPushPointer(vm::ptr queue, s32& pointer, u32 s32 var2 = (s32)(s16)push.m_h8; s32 res; - if (useEventQueue && ((s32)push.m_h5 != var2 || push.m_h7.ToBE() != 0)) + if (useEventQueue && ((s32)push.m_h5 != var2 || push.m_h7.data() != 0)) { res = CELL_SYNC_ERROR_BUSY; } @@ -1058,7 +1058,7 @@ s32 syncLFQueueGetPushPointer(vm::ptr queue, s32& pointer, u32 else if (!isBlocking) { res = CELL_SYNC_ERROR_AGAIN; - if (!push.m_h7.ToBE() || res) + if (!push.m_h7.data() || res) { return res; } @@ -1081,7 +1081,7 @@ s32 syncLFQueueGetPushPointer(vm::ptr queue, s32& pointer, u32 if (queue->push1.compare_and_swap_test(old, push)) { - if (!push.m_h7.ToBE() || res) + if (!push.m_h7.data() || res) { return res; } @@ -1287,7 +1287,7 @@ s32 _cellSyncLFQueueCompletePushPointer2(vm::ptr queue, s32 poi return syncLFQueueCompletePushPointer2(queue, pointer, fpSendSignal); } -s32 _cellSyncLFQueuePushBody(vm::ptr queue, vm::ptr buffer, u32 isBlocking) +s32 _cellSyncLFQueuePushBody(PPUThread& CPU, vm::ptr queue, vm::ptr buffer, u32 isBlocking) { // cellSyncLFQueuePush has 1 in isBlocking param, cellSyncLFQueueTryPush has 0 cellSync->Warning("_cellSyncLFQueuePushBody(queue_addr=0x%x, buffer_addr=0x%x, isBlocking=%d)", queue.addr(), buffer.addr(), isBlocking); @@ -1302,10 +1302,8 @@ s32 _cellSyncLFQueuePushBody(vm::ptr queue, vm::ptr } s32 position; - //syncLFQueueDump(queue); - #ifdef PRX_DEBUG - vm::var> position_v; + vm::stackvar> position_v(CPU); #endif while (true) { @@ -1314,9 +1312,9 @@ s32 _cellSyncLFQueuePushBody(vm::ptr queue, vm::ptr if (queue->m_direction != CELL_SYNC_QUEUE_ANY2ANY) { #ifdef PRX_DEBUG_XXX - res = cb_caller, u32, u32, u64>::call(GetCurrentPPUThread(), libsre + 0x24B0, libsre_rtoc, + res = cb_call, u32, u32, u64>(CPU, libsre + 0x24B0, libsre_rtoc, queue, position_v.addr(), isBlocking, 0); - position = position_v->ToLE(); + position = position_v.value(); #else res = syncLFQueueGetPushPointer(queue, position, isBlocking, 0); #endif @@ -1324,17 +1322,14 @@ s32 _cellSyncLFQueuePushBody(vm::ptr queue, vm::ptr else { #ifdef PRX_DEBUG - res = cb_call, u32, u32, u64>(GetCurrentPPUThread(), libsre + 0x3050, libsre_rtoc, + res = cb_call, u32, u32, u64>(CPU, libsre + 0x3050, libsre_rtoc, queue, position_v.addr(), isBlocking, 0); - position = position_v->ToLE(); + position = position_v.value(); #else res = syncLFQueueGetPushPointer2(queue, position, isBlocking, 0); #endif } - //LOG_NOTICE(HLE, "... position = %d", position); - //syncLFQueueDump(queue); - if (!isBlocking || res != CELL_SYNC_ERROR_AGAIN) { if (res) @@ -1352,15 +1347,16 @@ s32 _cellSyncLFQueuePushBody(vm::ptr queue, vm::ptr } } - s32 depth = (u32)queue->m_depth; - s32 size = (u32)queue->m_size; - memcpy(vm::get_ptr((u64)(queue->m_buffer.addr() & ~1ull) + size * (position >= depth ? position - depth : position)), buffer.get_ptr(), size); + const s32 depth = (u32)queue->m_depth; + const s32 size = (u32)queue->m_size; + const u32 addr = vm::cast((queue->m_buffer.addr() & ~1ull) + size * (position >= depth ? position - depth : position)); + memcpy(vm::get_ptr(addr), buffer.get_ptr(), size); s32 res; if (queue->m_direction != CELL_SYNC_QUEUE_ANY2ANY) { #ifdef PRX_DEBUG_XXX - res = cb_caller, s32, u64>::call(GetCurrentPPUThread(), libsre + 0x26C0, libsre_rtoc, + res = cb_call, s32, u64>(CPU, libsre + 0x26C0, libsre_rtoc, queue, position, 0); #else res = syncLFQueueCompletePushPointer(queue, position, nullptr); @@ -1369,14 +1365,13 @@ s32 _cellSyncLFQueuePushBody(vm::ptr queue, vm::ptr else { #ifdef PRX_DEBUG - res = cb_call, s32, u64>(GetCurrentPPUThread(), libsre + 0x355C, libsre_rtoc, + res = cb_call, s32, u64>(CPU, libsre + 0x355C, libsre_rtoc, queue, position, 0); #else res = syncLFQueueCompletePushPointer2(queue, position, nullptr); #endif } - //syncLFQueueDump(queue); return res; } @@ -1412,7 +1407,7 @@ s32 syncLFQueueGetPopPointer(vm::ptr queue, s32& pointer, u32 i s32 var2 = (s32)(s16)pop.m_h4; s32 res; - if (useEventQueue && ((s32)(u16)pop.m_h1 != var2 || pop.m_h3.ToBE() != 0)) + if (useEventQueue && ((s32)(u16)pop.m_h1 != var2 || pop.m_h3.data() != 0)) { res = CELL_SYNC_ERROR_BUSY; } @@ -1440,7 +1435,7 @@ s32 syncLFQueueGetPopPointer(vm::ptr queue, s32& pointer, u32 i else if (!isBlocking) { res = CELL_SYNC_ERROR_AGAIN; - if (!pop.m_h3.ToBE() || res) + if (!pop.m_h3.data() || res) { return res; } @@ -1463,7 +1458,7 @@ s32 syncLFQueueGetPopPointer(vm::ptr queue, s32& pointer, u32 i if (queue->pop1.compare_and_swap_test(old, pop)) { - if (!pop.m_h3.ToBE() || res) + if (!pop.m_h3.data() || res) { return res; } @@ -1669,7 +1664,7 @@ s32 _cellSyncLFQueueCompletePopPointer2(vm::ptr queue, s32 poin return syncLFQueueCompletePopPointer2(queue, pointer, fpSendSignal, noQueueFull); } -s32 _cellSyncLFQueuePopBody(vm::ptr queue, vm::ptr buffer, u32 isBlocking) +s32 _cellSyncLFQueuePopBody(PPUThread& CPU, vm::ptr queue, vm::ptr buffer, u32 isBlocking) { // cellSyncLFQueuePop has 1 in isBlocking param, cellSyncLFQueueTryPop has 0 cellSync->Warning("_cellSyncLFQueuePopBody(queue_addr=0x%x, buffer_addr=0x%x, isBlocking=%d)", queue.addr(), buffer.addr(), isBlocking); @@ -1685,7 +1680,7 @@ s32 _cellSyncLFQueuePopBody(vm::ptr queue, vm::ptr buffer s32 position; #ifdef PRX_DEBUG - vm::var> position_v; + vm::stackvar> position_v(CPU); #endif while (true) { @@ -1693,9 +1688,9 @@ s32 _cellSyncLFQueuePopBody(vm::ptr queue, vm::ptr buffer if (queue->m_direction != CELL_SYNC_QUEUE_ANY2ANY) { #ifdef PRX_DEBUG_XXX - res = cb_caller, u32, u32, u64, u64>::call(GetCurrentPPUThread(), libsre + 0x2A90, libsre_rtoc, + res = cb_call, u32, u32, u64, u64>(CPU, libsre + 0x2A90, libsre_rtoc, queue, position_v.addr(), isBlocking, 0, 0); - position = position_v->ToLE(); + position = position_v.value(); #else res = syncLFQueueGetPopPointer(queue, position, isBlocking, 0, 0); #endif @@ -1703,9 +1698,9 @@ s32 _cellSyncLFQueuePopBody(vm::ptr queue, vm::ptr buffer else { #ifdef PRX_DEBUG - res = cb_call, u32, u32, u64>(GetCurrentPPUThread(), libsre + 0x39AC, libsre_rtoc, + res = cb_call, u32, u32, u64>(CPU, libsre + 0x39AC, libsre_rtoc, queue, position_v.addr(), isBlocking, 0); - position = position_v->ToLE(); + position = position_v.value(); #else res = syncLFQueueGetPopPointer2(queue, position, isBlocking, 0); #endif @@ -1728,15 +1723,16 @@ s32 _cellSyncLFQueuePopBody(vm::ptr queue, vm::ptr buffer } } - s32 depth = (u32)queue->m_depth; - s32 size = (u32)queue->m_size; - memcpy(buffer.get_ptr(), vm::get_ptr((u64)(queue->m_buffer.addr() & ~1ull) + size * (position >= depth ? position - depth : position)), size); + const s32 depth = (u32)queue->m_depth; + const s32 size = (u32)queue->m_size; + const u32 addr = vm::cast((queue->m_buffer.addr() & ~1) + size * (position >= depth ? position - depth : position)); + memcpy(buffer.get_ptr(), vm::get_ptr(addr), size); s32 res; if (queue->m_direction != CELL_SYNC_QUEUE_ANY2ANY) { #ifdef PRX_DEBUG_XXX - res = cb_caller, s32, u64, u64>::call(GetCurrentPPUThread(), libsre + 0x2CA8, libsre_rtoc, + res = cb_call, s32, u64, u64>(CPU, libsre + 0x2CA8, libsre_rtoc, queue, position, 0, 0); #else res = syncLFQueueCompletePopPointer(queue, position, nullptr, 0); @@ -1745,7 +1741,7 @@ s32 _cellSyncLFQueuePopBody(vm::ptr queue, vm::ptr buffer else { #ifdef PRX_DEBUG - res = cb_call, s32, u64, u64>(GetCurrentPPUThread(), libsre + 0x3EB8, libsre_rtoc, + res = cb_call, s32, u64, u64>(CPU, libsre + 0x3EB8, libsre_rtoc, queue, position, 0, 0); #else res = syncLFQueueCompletePopPointer2(queue, position, nullptr, 0); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp b/rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp index 5afa9e72dc..33059ed1aa 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp @@ -18,7 +18,6 @@ #include "cellMsgDialog.h" #include "cellGame.h" #include "cellSysutil.h" -#include "cellSaveData.h" typedef void (*CellHddGameStatCallback)(vm::ptr cbResult, vm::ptr get, vm::ptr set); @@ -241,7 +240,7 @@ int cellVideoOutGetConfiguration(u32 videoOut, vm::ptr info) { - cellSysutil->Warning("cellVideoOutGetDeviceInfo(videoOut=%u, deviceIndex=%u, info_addr=0x%x)", + cellSysutil->Warning("cellVideoOutGetDeviceInfo(videoOut=%d, deviceIndex=%d, info_addr=0x%x)", videoOut, deviceIndex, info.addr()); if(deviceIndex) return CELL_VIDEO_OUT_ERROR_DEVICE_NOT_FOUND; @@ -286,8 +285,7 @@ int cellVideoOutGetNumberOfDevice(u32 videoOut) int cellVideoOutGetResolutionAvailability(u32 videoOut, u32 resolutionId, u32 aspect, u32 option) { - cellSysutil->Warning("cellVideoOutGetResolutionAvailability(videoOut=%d, resolutionId=0x%x, option_addr=0x%x, aspect=%d, option=%d)", - videoOut, resolutionId, aspect, option); + cellSysutil->Warning("cellVideoOutGetResolutionAvailability(videoOut=%d, resolutionId=0x%x, aspect=%d, option=%d)", videoOut, resolutionId, aspect, option); if (!Ini.GS3DTV.GetValue() && (resolutionId == CELL_VIDEO_OUT_RESOLUTION_720_3D_FRAME_PACKING || resolutionId == CELL_VIDEO_OUT_RESOLUTION_1024x720_3D_FRAME_PACKING || resolutionId == CELL_VIDEO_OUT_RESOLUTION_960x720_3D_FRAME_PACKING || resolutionId == CELL_VIDEO_OUT_RESOLUTION_800x720_3D_FRAME_PACKING || @@ -312,28 +310,28 @@ struct sys_callback void sysutilSendSystemCommand(u64 status, u64 param) { - // TODO: check it and find the source of the return value (not sure that void becomes CELL_OK) + // TODO: check it and find the source of the return value (void isn't equal to CELL_OK) for (auto& cb : g_sys_callback) { if (cb.func) { - Emu.GetCallbackManager().Register([=]() -> s32 + Emu.GetCallbackManager().Register([=](PPUThread& PPU) -> s32 { - cb.func(status, param, cb.arg); + cb.func(PPU, status, param, cb.arg); return CELL_OK; }); } } } -s32 cellSysutilCheckCallback() +s32 cellSysutilCheckCallback(PPUThread& CPU) { cellSysutil->Log("cellSysutilCheckCallback()"); s32 res; u32 count = 0; - while (Emu.GetCallbackManager().Check(res)) + while (Emu.GetCallbackManager().Check(CPU, res)) { count++; @@ -392,7 +390,7 @@ int cellAudioOutGetSoundAvailability(u32 audioOut, u32 type, u32 fs, u32 option) option = 0; - int available = 2; // should be at least 2 + int available = 8; // should be at least 2 switch(fs) { @@ -433,7 +431,7 @@ int cellAudioOutGetSoundAvailability2(u32 audioOut, u32 type, u32 fs, u32 ch, u3 option = 0; - int available = 2; // should be at least 2 + int available = 8; // should be at least 2 switch(fs) { @@ -580,9 +578,9 @@ int cellAudioOutGetDeviceInfo(u32 audioOut, u32 deviceIndex, vm::ptrstate = CELL_AUDIO_OUT_DEVICE_STATE_AVAILABLE; info->latency = 1000; info->availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM; - info->availableModes[0].channel = CELL_AUDIO_OUT_CHNUM_2; + info->availableModes[0].channel = CELL_AUDIO_OUT_CHNUM_8; info->availableModes[0].fs = CELL_AUDIO_OUT_FS_48KHZ; - info->availableModes[0].layout = CELL_AUDIO_OUT_SPEAKER_LAYOUT_2CH; + info->availableModes[0].layout = CELL_AUDIO_OUT_SPEAKER_LAYOUT_8CH_LREClrxy; return CELL_AUDIO_OUT_SUCCEEDED; } @@ -749,8 +747,8 @@ int cellHddGameCheck(u32 version, vm::ptr dirName, u32 errDialog, vm funcStat(result, get, set); - if (result->result.ToLE() != CELL_HDDGAME_CBRESULT_OK && - result->result.ToLE() != CELL_HDDGAME_CBRESULT_OK_CANCEL) { + if (result->result != CELL_HDDGAME_CBRESULT_OK && + result->result != CELL_HDDGAME_CBRESULT_OK_CANCEL) { return CELL_HDDGAME_ERROR_CBRESULT; } @@ -836,12 +834,14 @@ int cellWebBrowserEstimate2(const vm::ptr config, v return CELL_OK; } -extern int cellGameDataCheckCreate2(u32 version, vm::ptr dirName, u32 errDialog, +extern int cellGameDataCheckCreate2(PPUThread& CPU, u32 version, vm::ptr dirName, u32 errDialog, vm::ptr cbResult, vm::ptr get, vm::ptr set)> funcStat, u32 container); -extern int cellGameDataCheckCreate(u32 version, vm::ptr dirName, u32 errDialog, +extern int cellGameDataCheckCreate(PPUThread& CPU, u32 version, vm::ptr dirName, u32 errDialog, vm::ptr cbResult, vm::ptr get, vm::ptr set)> funcStat, u32 container); +extern void cellSysutil_SaveData_init(); + void cellSysutil_init(Module *pxThis) { cellSysutil = pxThis; @@ -894,36 +894,13 @@ void cellSysutil_init(Module *pxThis) //cellSysutil->AddFunc(0x9ca9ffa7, cellHddGameSetSystemVer); //cellSysutil->AddFunc(0xafd605b3, cellHddGameExitBroken); - //cellSysutil_SaveData - //cellSysutil->AddFunc(0x04c06fc2, cellSaveDataGetListItem); - //cellSysutil->AddFunc(0x273d116a, cellSaveDataUserListExport); - //cellSysutil->AddFunc(0x27cb8bc2, cellSaveDataListDelete); - //cellSysutil->AddFunc(0x39d6ee43, cellSaveDataUserListImport); - //cellSysutil->AddFunc(0x46a2d878, cellSaveDataFixedExport); - //cellSysutil->AddFunc(0x491cc554, cellSaveDataListExport); - //cellSysutil->AddFunc(0x52541151, cellSaveDataFixedImport); - //cellSysutil->AddFunc(0x529231b0, cellSaveDataUserFixedImport); - //cellSysutil->AddFunc(0x6b4e0de6, cellSaveDataListImport); - //cellSysutil->AddFunc(0x7048a9ba, cellSaveDataUserListDelete); - //cellSysutil->AddFunc(0x95ae2cde, cellSaveDataUserFixedExport); - //cellSysutil->AddFunc(0xf6482036, cellSaveDataUserGetListItem); - cellSysutil->AddFunc(0x2de0d663, cellSaveDataListSave2); - cellSysutil->AddFunc(0x1dfbfdd6, cellSaveDataListLoad2); - cellSysutil->AddFunc(0x2aae9ef5, cellSaveDataFixedSave2); - cellSysutil->AddFunc(0x2a8eada2, cellSaveDataFixedLoad2); - cellSysutil->AddFunc(0x8b7ed64b, cellSaveDataAutoSave2); - cellSysutil->AddFunc(0xfbd5c856, cellSaveDataAutoLoad2); - cellSysutil->AddFunc(0x4dd03a4e, cellSaveDataListAutoSave); - cellSysutil->AddFunc(0x21425307, cellSaveDataListAutoLoad); - //cellSysutil->AddFunc(0xedadd797, cellSaveDataDelete2); - //cellSysutil->AddFunc(0x0f03cfb0, cellSaveDataUserListSave); - //cellSysutil->AddFunc(0x39dd8425, cellSaveDataUserListLoad); - //cellSysutil->AddFunc(0x40b34847, cellSaveDataUserFixedSave); - //cellSysutil->AddFunc(0x6e7264ed, cellSaveDataUserFixedLoad); - //cellSysutil->AddFunc(0x52aac4fa, cellSaveDataUserAutoSave); - //cellSysutil->AddFunc(0xcdc6aefd, cellSaveDataUserAutoLoad); - //cellSysutil->AddFunc(0x0e091c36, cellSaveDataUserListAutoSave); - //cellSysutil->AddFunc(0xe7fa820b, cellSaveDataEnableOverlay); + //cellSysutil->AddFunc(0x886D0747, cellSysutilRegisterCallbackDispatcher); + //cellSysutil->AddFunc(0xA2720DF2, cellSysutilPacketWrite); + //cellSysutil->AddFunc(0x75AA7373, doc.write); + //cellSysutil->AddFunc(0x2D96313F, packet_read); + + // cellSaveData functions + cellSysutil_SaveData_init(); cellSysutil->AddFunc(0x6d087930, cellWebBrowserEstimate2); diff --git a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp index ddf5726ff4..518e4589bb 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp @@ -147,7 +147,7 @@ next: buf_size -= vdec.reader.size; res += vdec.reader.size; - vdec.cbFunc.call(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_AUDONE, CELL_OK, vdec.cbArg); + vdec.cbFunc(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_AUDONE, CELL_OK, vdec.cbArg); vdec.job.pop(vdec.task); @@ -214,7 +214,7 @@ u32 vdecOpen(VideoDecoder* vdec_ptr) vdec.id = vdec_id; vdec.vdecCb = (PPUThread*)&Emu.GetCPU().AddThread(CPU_THREAD_PPU); - vdec.vdecCb->SetName("Video Decoder[" + std::to_string(vdec_id) + "] Callback"); + vdec.vdecCb->SetName(fmt::format("VideoDecoder[%d] Callback", vdec_id)); vdec.vdecCb->SetEntry(0); vdec.vdecCb->SetPrio(1001); vdec.vdecCb->SetStackSize(0x10000); @@ -222,11 +222,9 @@ u32 vdecOpen(VideoDecoder* vdec_ptr) vdec.vdecCb->InitRegs(); vdec.vdecCb->DoRun(); - thread t("Video Decoder[" + std::to_string(vdec_id) + "] Thread", [vdec_ptr, sptr]() + thread_t t(fmt::format("VideoDecoder[%d] Thread", vdec_id), [vdec_ptr, sptr]() { VideoDecoder& vdec = *vdec_ptr; - cellVdec->Notice("Video Decoder thread started"); - VdecTask& task = vdec.task; while (true) @@ -259,7 +257,7 @@ u32 vdecOpen(VideoDecoder* vdec_ptr) // TODO: finalize cellVdec->Warning("vdecEndSeq:"); - vdec.cbFunc.call(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_SEQDONE, CELL_OK, vdec.cbArg); + vdec.cbFunc(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_SEQDONE, CELL_OK, vdec.cbArg); vdec.just_finished = true; break; @@ -431,7 +429,15 @@ u32 vdecOpen(VideoDecoder* vdec_ptr) { if (vdec.last_pts == -1) { - vdec.last_pts = 0x8000; //av_frame_get_best_effort_timestamp(frame.data); + u64 ts = av_frame_get_best_effort_timestamp(frame.data); + if (ts != AV_NOPTS_VALUE) + { + vdec.last_pts = ts; + } + else + { + vdec.last_pts = 0; + } } else switch (vdec.frc_set) { @@ -516,12 +522,12 @@ u32 vdecOpen(VideoDecoder* vdec_ptr) if (vdec.frames.push(frame, &vdec.is_closed)) { frame.data = nullptr; // to prevent destruction - vdec.cbFunc.call(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_PICOUT, CELL_OK, vdec.cbArg); + vdec.cbFunc(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_PICOUT, CELL_OK, vdec.cbArg); } } } - vdec.cbFunc.call(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_AUDONE, CELL_OK, vdec.cbArg); + vdec.cbFunc(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_AUDONE, CELL_OK, vdec.cbArg); break; } @@ -539,18 +545,14 @@ u32 vdecOpen(VideoDecoder* vdec_ptr) default: { - VDEC_ERROR("Video Decoder thread error: unknown task(%d)", task.type); + VDEC_ERROR("VideoDecoder thread error: unknown task(%d)", task.type); } } } vdec.is_finished = true; - if (Emu.IsStopped()) cellVdec->Warning("Video Decoder thread aborted"); - if (vdec.is_closed) cellVdec->Notice("Video Decoder thread ended"); }); - t.detach(); - return vdec_id; } @@ -573,7 +575,7 @@ int cellVdecOpen(vm::ptr type, vm::ptrWarning("cellVdecOpen(type_addr=0x%x, res_addr=0x%x, cb_addr=0x%x, handle_addr=0x%x)", type.addr(), res.addr(), cb.addr(), handle.addr()); - *handle = vdecOpen(new VideoDecoder(type->codecType, type->profileLevel, res->memAddr, res->memSize, vm::ptr::make(cb->cbFunc.addr()), cb->cbArg)); + *handle = vdecOpen(new VideoDecoder(type->codecType, type->profileLevel, res->memAddr, res->memSize, cb->cbFunc.to_le(), cb->cbArg)); return CELL_OK; } @@ -583,7 +585,7 @@ int cellVdecOpenEx(vm::ptr type, vm::ptrWarning("cellVdecOpenEx(type_addr=0x%x, res_addr=0x%x, cb_addr=0x%x, handle_addr=0x%x)", type.addr(), res.addr(), cb.addr(), handle.addr()); - *handle = vdecOpen(new VideoDecoder(type->codecType, type->profileLevel, res->memAddr, res->memSize, vm::ptr::make(cb->cbFunc.addr()), cb->cbArg)); + *handle = vdecOpen(new VideoDecoder(type->codecType, type->profileLevel, res->memAddr, res->memSize, cb->cbFunc.to_le(), cb->cbArg)); return CELL_OK; } @@ -693,7 +695,7 @@ int cellVdecGetPicture(u32 handle, vm::ptr format, vm:: if (outBuff) { - u32 buf_size = a128(av_image_get_buffer_size(vdec->ctx->pix_fmt, vdec->ctx->width, vdec->ctx->height, 1)); + const u32 buf_size = align(av_image_get_buffer_size(vdec->ctx->pix_fmt, vdec->ctx->width, vdec->ctx->height, 1), 128); if (format->formatType != CELL_VDEC_PICFMT_YUV420_PLANAR) { @@ -753,7 +755,7 @@ int cellVdecGetPicItem(u32 handle, vm::ptr picItem_ptr) info->codecType = vdec->type; info->startAddr = 0x00000123; // invalid value (no address for picture) - info->size = a128(av_image_get_buffer_size(vdec->ctx->pix_fmt, vdec->ctx->width, vdec->ctx->height, 1)); + info->size = align(av_image_get_buffer_size(vdec->ctx->pix_fmt, vdec->ctx->width, vdec->ctx->height, 1), 128); info->auNum = 1; info->auPts[0].lower = (u32)vf.pts; info->auPts[0].upper = vf.pts >> 32; diff --git a/rpcs3/Emu/SysCalls/Modules/cellVdec.h b/rpcs3/Emu/SysCalls/Modules/cellVdec.h index e03cc26f06..e53955e70e 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVdec.h +++ b/rpcs3/Emu/SysCalls/Modules/cellVdec.h @@ -1,7 +1,5 @@ #pragma once -#define a128(x) ((x + 127) & (~127)) - // Error Codes enum { diff --git a/rpcs3/Emu/SysCalls/Modules/libmixer.cpp b/rpcs3/Emu/SysCalls/Modules/libmixer.cpp index 21646f4d1c..0030923d06 100644 --- a/rpcs3/Emu/SysCalls/Modules/libmixer.cpp +++ b/rpcs3/Emu/SysCalls/Modules/libmixer.cpp @@ -5,14 +5,12 @@ #include "Emu/SysCalls/CB_FUNC.h" #include "Emu/CPU/CPUThreadManager.h" -#include "Emu/Audio/cellAudio.h" +#include "cellAudio.h" #include "libmixer.h" Module *libmixer = nullptr; -CellSurMixerConfig surMixer; - -#define SUR_PORT (7) +SurMixerConfig g_surmx; vm::ptr surMixerCb; vm::ptr surMixerCbArg; std::mutex mixer_mutex; @@ -23,8 +21,7 @@ std::vector ssp; int cellAANAddData(u32 aan_handle, u32 aan_port, u32 offset, vm::ptr addr, u32 samples) { - libmixer->Log("cellAANAddData(handle=%d, port=%d, offset=0x%x, addr=0x%x, samples=%d)", - aan_handle, aan_port, offset, addr.addr(), samples); + libmixer->Log("cellAANAddData(handle=%d, port=%d, offset=0x%x, addr_addr=0x%x, samples=%d)", aan_handle, aan_port, offset, addr.addr(), samples); u32 type = aan_port >> 16; u32 port = aan_port & 0xffff; @@ -32,21 +29,20 @@ int cellAANAddData(u32 aan_handle, u32 aan_port, u32 offset, vm::ptr addr switch (type) { case CELL_SURMIXER_CHSTRIP_TYPE1A: - if (port >= surMixer.chStrips1) type = 0; break; + if (port >= g_surmx.ch_strips_1) type = 0; break; case CELL_SURMIXER_CHSTRIP_TYPE2A: - if (port >= surMixer.chStrips2) type = 0; break; + if (port >= g_surmx.ch_strips_2) type = 0; break; case CELL_SURMIXER_CHSTRIP_TYPE6A: - if (port >= surMixer.chStrips6) type = 0; break; + if (port >= g_surmx.ch_strips_6) type = 0; break; case CELL_SURMIXER_CHSTRIP_TYPE8A: - if (port >= surMixer.chStrips8) type = 0; break; + if (port >= g_surmx.ch_strips_8) type = 0; break; default: type = 0; break; } if (aan_handle != 0x11111111 || samples != 256 || !type || offset != 0) { - libmixer->Error("cellAANAddData(handle=%d, port=%d, offset=0x%x, addr=0x%x, samples=%d): invalid parameters", - aan_handle, aan_port, offset, addr, samples); + libmixer->Error("cellAANAddData(handle=%d, port=%d, offset=0x%x, addr_addr=0x%x, samples=%d): invalid parameters", aan_handle, aan_port, offset, addr.addr(), samples); return CELL_LIBMIXER_ERROR_INVALID_PARAMATER; } @@ -298,35 +294,37 @@ int cellSurMixerCreate(vm::ptr config) { libmixer->Warning("cellSurMixerCreate(config_addr=0x%x)", config.addr()); - surMixer = *config; + g_surmx.audio_port = g_audio.open_port(); - AudioPortConfig& port = m_config.m_ports[SUR_PORT]; - - if (port.m_is_audio_port_opened) + if (!~g_surmx.audio_port) { return CELL_LIBMIXER_ERROR_FULL; } + g_surmx.priority = config->priority; + g_surmx.ch_strips_1 = config->chStrips1; + g_surmx.ch_strips_2 = config->chStrips2; + g_surmx.ch_strips_6 = config->chStrips6; + g_surmx.ch_strips_8 = config->chStrips8; + + AudioPortConfig& port = g_audio.ports[g_surmx.audio_port]; + port.channel = 8; port.block = 16; port.attr = 0; port.level = 1.0f; + port.tag = 0; libmixer->Warning("*** audio port opened(default)"); - port.m_is_audio_port_opened = true; - port.tag = 0; - m_config.m_port_in_use++; - - libmixer->Warning("*** surMixer created (ch1=%d, ch2=%d, ch6=%d, ch8=%d)", - (u32)surMixer.chStrips1, (u32)surMixer.chStrips2, (u32)surMixer.chStrips6, (u32)surMixer.chStrips8); - mixcount = 0; surMixerCb.set(0); - thread t("Surmixer Thread", []() + libmixer->Warning("*** surMixer created (ch1=%d, ch2=%d, ch6=%d, ch8=%d)", config->chStrips1, config->chStrips2, config->chStrips6, config->chStrips8); + + thread_t t("Surmixer Thread", []() { - AudioPortConfig& port = m_config.m_ports[SUR_PORT]; + AudioPortConfig& port = g_audio.ports[g_surmx.audio_port]; PPUThread& cb_thread = *(PPUThread*)&Emu.GetCPU().AddThread(CPU_THREAD_PPU); cb_thread.SetName("Surmixer Callback Thread"); @@ -337,28 +335,22 @@ int cellSurMixerCreate(vm::ptr config) cb_thread.InitRegs(); cb_thread.DoRun(); - while (port.m_is_audio_port_opened) + while (port.state.read_relaxed() != AUDIO_PORT_STATE_CLOSED && !Emu.IsStopped()) { - if (Emu.IsStopped()) - { - libmixer->Warning("Surmixer aborted"); - break; - } - if (mixcount > (port.tag + 0)) // adding positive value (1-15): preemptive buffer filling (hack) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack continue; } - if (port.m_is_audio_port_started) + if (port.state.read_relaxed() == AUDIO_PORT_STATE_STARTED) { //u64 stamp0 = get_system_time(); memset(mixdata, 0, sizeof(mixdata)); if (surMixerCb) { - surMixerCb.call(cb_thread, surMixerCbArg, (u32)mixcount, 256); + surMixerCb(cb_thread, surMixerCbArg, (u32)mixcount, 256); } //u64 stamp1 = get_system_time(); @@ -442,7 +434,7 @@ int cellSurMixerCreate(vm::ptr config) //u64 stamp2 = get_system_time(); - auto buf = vm::get_ptr>(m_config.m_buffer + (128 * 1024 * SUR_PORT) + (mixcount % port.block) * port.channel * 256 * sizeof(float)); + auto buf = vm::get_ptr>(port.addr + (mixcount % port.block) * port.channel * AUDIO_SAMPLES * sizeof(float)); for (u32 i = 0; i < (sizeof(mixdata) / sizeof(float)); i++) { @@ -466,7 +458,6 @@ int cellSurMixerCreate(vm::ptr config) Emu.GetCPU().RemoveThread(cb_thread.GetId()); surMixerCb.set(0); }); - t.detach(); return CELL_OK; } @@ -517,13 +508,13 @@ int cellSurMixerStart() { libmixer->Warning("cellSurMixerStart()"); - AudioPortConfig& port = m_config.m_ports[SUR_PORT]; - - if (port.m_is_audio_port_opened) + if (g_surmx.audio_port >= AUDIO_PORT_COUNT) { - port.m_is_audio_port_started = true; + return CELL_LIBMIXER_ERROR_NOT_INITIALIZED; } - + + g_audio.ports[g_surmx.audio_port].state.compare_and_swap(AUDIO_PORT_STATE_OPENED, AUDIO_PORT_STATE_STARTED); + return CELL_OK; } @@ -537,19 +528,17 @@ int cellSurMixerFinalize() { libmixer->Warning("cellSurMixerFinalize()"); - AudioPortConfig& port = m_config.m_ports[SUR_PORT]; - - if (port.m_is_audio_port_opened) + if (g_surmx.audio_port >= AUDIO_PORT_COUNT) { - port.m_is_audio_port_started = false; - port.m_is_audio_port_opened = false; - m_config.m_port_in_use--; + return CELL_LIBMIXER_ERROR_NOT_INITIALIZED; } + g_audio.ports[g_surmx.audio_port].state.compare_and_swap(AUDIO_PORT_STATE_OPENED, AUDIO_PORT_STATE_CLOSED); + return CELL_OK; } -int cellSurMixerSurBusAddData(u32 busNo, u32 offset, u32 addr, u32 samples) +int cellSurMixerSurBusAddData(u32 busNo, u32 offset, vm::ptr addr, u32 samples) { if (busNo < 8 && samples == 256 && offset == 0) { @@ -566,8 +555,7 @@ int cellSurMixerSurBusAddData(u32 busNo, u32 offset, u32 addr, u32 samples) for (u32 i = 0; i < samples; i++) { // reverse byte order and mix - u32 v = vm::read32(addr + i * sizeof(float)); - mixdata[i*8+busNo] += (float&)v; + mixdata[i * 8 + busNo] += addr[i]; } return CELL_OK; @@ -583,13 +571,13 @@ int cellSurMixerPause(u32 type) { libmixer->Warning("cellSurMixerPause(type=%d)", type); - AudioPortConfig& port = m_config.m_ports[SUR_PORT]; - - if (port.m_is_audio_port_opened) + if (g_surmx.audio_port >= AUDIO_PORT_COUNT) { - port.m_is_audio_port_started = false; + return CELL_LIBMIXER_ERROR_NOT_INITIALIZED; } + g_audio.ports[g_surmx.audio_port].state.compare_and_swap(AUDIO_PORT_STATE_STARTED, AUDIO_PORT_STATE_OPENED); + return CELL_OK; } @@ -605,7 +593,7 @@ int cellSurMixerGetTimestamp(u64 tag, vm::ptr stamp) { libmixer->Log("cellSurMixerGetTimestamp(tag=0x%llx, stamp_addr=0x%x)", tag, stamp.addr()); - *stamp = m_config.start_time + (tag) * 256000000 / 48000; // ??? + *stamp = g_audio.start_time + (tag) * 256000000 / 48000; // ??? return CELL_OK; } @@ -640,6 +628,8 @@ void libmixer_init(Module *pxThis) { libmixer = pxThis; + g_surmx.audio_port = ~0; + REG_SUB(libmixer, "surmxAAN", cellAANAddData, 0xffffffff7c691b78, 0xffffffff7c0802a6, diff --git a/rpcs3/Emu/SysCalls/Modules/libmixer.h b/rpcs3/Emu/SysCalls/Modules/libmixer.h index 45f8a26af9..9a7978f9a5 100644 --- a/rpcs3/Emu/SysCalls/Modules/libmixer.h +++ b/rpcs3/Emu/SysCalls/Modules/libmixer.h @@ -1,6 +1,7 @@ #pragma once -enum //libmixer Error Codes +// Error Codes +enum { CELL_LIBMIXER_ERROR_NOT_INITIALIZED = 0x80310002, CELL_LIBMIXER_ERROR_INVALID_PARAMATER = 0x80310003, @@ -164,6 +165,16 @@ struct CellSurMixerChStripParam be_t intVal; }; +struct SurMixerConfig +{ + u32 audio_port; + s32 priority; + u32 ch_strips_1; + u32 ch_strips_2; + u32 ch_strips_6; + u32 ch_strips_8; +}; + struct SSPlayer { bool m_created; // SSPlayerCreate/Remove diff --git a/rpcs3/Emu/SysCalls/Modules/libsynth2.cpp b/rpcs3/Emu/SysCalls/Modules/libsynth2.cpp index 9cc4119865..6c1304868d 100644 --- a/rpcs3/Emu/SysCalls/Modules/libsynth2.cpp +++ b/rpcs3/Emu/SysCalls/Modules/libsynth2.cpp @@ -60,13 +60,13 @@ u32 cellSoundSynth2GetAddr(u16 reg) int cellSoundSynth2SetEffectAttr(s16 bus, vm::ptr attr) { - libsynth2.Todo("cellSoundSynth2SetEffectAttr(bus=%d, attr_addr=0x%x)", bus, attr.addr()); + libsynth2.Todo("cellSoundSynth2SetEffectAttr(bus=%d, attr=0x%x)", bus, attr); return CELL_OK; } int cellSoundSynth2SetEffectMode(s16 bus, vm::ptr attr) { - libsynth2.Todo("cellSoundSynth2SetEffectMode(bus=%d, attr_addr=0x%x)", bus, attr.addr()); + libsynth2.Todo("cellSoundSynth2SetEffectMode(bus=%d, attr=0x%x)", bus, attr); return CELL_OK; } @@ -77,8 +77,7 @@ void cellSoundSynth2SetCoreAttr(u16 entry, u16 value) int cellSoundSynth2Generate(u16 samples, u32 L_addr, u32 R_addr, u32 Lr_addr, u32 Rr_addr) { - libsynth2.Todo("cellSoundSynth2Generate(samples=0x%x, left=0x%x, right=0x%x, left_rear=0x%x, right_rear=0x%x)", - samples, L_addr, R_addr, Lr_addr, Rr_addr); + libsynth2.Todo("cellSoundSynth2Generate(samples=0x%x, left=0x%x, right=0x%x, left_rear=0x%x, right_rear=0x%x)", samples, L_addr, R_addr, Lr_addr, Rr_addr); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/Modules/sceNp.cpp b/rpcs3/Emu/SysCalls/Modules/sceNp.cpp index a05edc415c..5b6ac6cd11 100644 --- a/rpcs3/Emu/SysCalls/Modules/sceNp.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sceNp.cpp @@ -311,7 +311,7 @@ int sceNpBasicAddFriend() int sceNpBasicGetFriendListEntryCount(vm::ptr count) { - sceNp->Warning("sceNpBasicGetFriendListEntryCount(count=%d)", count); + sceNp->Warning("sceNpBasicGetFriendListEntryCount(count_addr=0x%x)", count.addr()); if (!sceNpInstance.m_bSceNpInitialized) return SCE_NP_BASIC_ERROR_NOT_INITIALIZED; @@ -476,7 +476,7 @@ int sceNpBasicGetClanMessageEntry(u32 index, vm::ptr from) int sceNpBasicGetMessageEntryCount(u32 type, vm::ptr count) { - sceNp->Warning("sceNpBasicGetMessageEntryCount(type=%d, count=%d)", type, count); + sceNp->Warning("sceNpBasicGetMessageEntryCount(type=%d, count_addr=0x%x)", type, count.addr()); if (!sceNpInstance.m_bSceNpInitialized) return SCE_NP_BASIC_ERROR_NOT_INITIALIZED; @@ -984,7 +984,7 @@ int sceNpManagerGetAccountAge() int sceNpManagerGetContentRatingFlag(vm::ptr isRestricted, vm::ptr age) { - sceNp->Warning("sceNpManagerGetContentRatingFlag(isRestricted=%d, age=%d)", isRestricted, age); + sceNp->Warning("sceNpManagerGetContentRatingFlag(isRestricted_addr=0x%x, age_addr=0x%x)", isRestricted.addr(), age.addr()); if (!sceNpInstance.m_bSceNpInitialized) return SCE_NP_ERROR_NOT_INITIALIZED; diff --git a/rpcs3/Emu/SysCalls/Modules/sceNpTrophy.cpp b/rpcs3/Emu/SysCalls/Modules/sceNpTrophy.cpp index 0cfbcf4f75..26a1246041 100644 --- a/rpcs3/Emu/SysCalls/Modules/sceNpTrophy.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sceNpTrophy.cpp @@ -378,7 +378,7 @@ int sceNpTrophyGetTrophyIcon() int sceNpTrophyGetTrophyInfo(u32 context, u32 handle, s32 trophyId, vm::ptr details, vm::ptr data) { - sceNpTrophy->Warning("sceNpTrophyGetTrophyInfo(context=%u, handle=%u, trophyId=%d, details_addr=0x%x, data_addr=0x%x)", + sceNpTrophy->Warning("sceNpTrophyGetTrophyInfo(context=%d, handle=%d, trophyId=%d, details_addr=0x%x, data_addr=0x%x)", context, handle, trophyId, details.addr(), data.addr()); if (!sceNpTrophyInstance.m_bInitialized) diff --git a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp index faf91a529f..1629d3fb05 100644 --- a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp @@ -286,7 +286,7 @@ s32 _sys_spu_printf_finalize() return CELL_OK; } -s64 _sys_spu_printf_attach_group(u32 group) +s32 _sys_spu_printf_attach_group(PPUThread& CPU, u32 group) { sysPrxForUser->Warning("_sys_spu_printf_attach_group(group=%d)", group); @@ -295,10 +295,10 @@ s64 _sys_spu_printf_attach_group(u32 group) return CELL_ESTAT; } - return spu_printf_agcb(group); + return spu_printf_agcb(CPU, group); } -s64 _sys_spu_printf_detach_group(u32 group) +s32 _sys_spu_printf_detach_group(PPUThread& CPU, u32 group) { sysPrxForUser->Warning("_sys_spu_printf_detach_group(group=%d)", group); @@ -307,10 +307,10 @@ s64 _sys_spu_printf_detach_group(u32 group) return CELL_ESTAT; } - return spu_printf_dgcb(group); + return spu_printf_dgcb(CPU, group); } -s64 _sys_spu_printf_attach_thread(u32 thread) +s32 _sys_spu_printf_attach_thread(PPUThread& CPU, u32 thread) { sysPrxForUser->Warning("_sys_spu_printf_attach_thread(thread=%d)", thread); @@ -319,10 +319,10 @@ s64 _sys_spu_printf_attach_thread(u32 thread) return CELL_ESTAT; } - return spu_printf_atcb(thread); + return spu_printf_atcb(CPU, thread); } -s64 _sys_spu_printf_detach_thread(u32 thread) +s32 _sys_spu_printf_detach_thread(PPUThread& CPU, u32 thread) { sysPrxForUser->Warning("_sys_spu_printf_detach_thread(thread=%d)", thread); @@ -331,7 +331,7 @@ s64 _sys_spu_printf_detach_thread(u32 thread) return CELL_ESTAT; } - return spu_printf_dtcb(thread); + return spu_printf_dtcb(CPU, thread); } s32 _sys_snprintf(vm::ptr dst, u32 count, vm::ptr fmt) // va_args... diff --git a/rpcs3/Emu/SysCalls/Modules/sys_net.cpp b/rpcs3/Emu/SysCalls/Modules/sys_net.cpp index 9f550557c1..3307007470 100644 --- a/rpcs3/Emu/SysCalls/Modules/sys_net.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sys_net.cpp @@ -114,7 +114,7 @@ int sys_net_accept(s32 s, vm::ptr addr, vm::ptr pad int sys_net_bind(s32 s, vm::ptr addr, u32 addrlen) { - sys_net->Warning("bind(s=%d, family_addr=0x%x, addrlen=%u)", s, addr.addr(), addrlen); + sys_net->Warning("bind(s=%d, family_addr=0x%x, addrlen=%d)", s, addr.addr(), addrlen); sockaddr_in saddr; memcpy(&saddr, addr.get_ptr(), sizeof(sockaddr_in)); saddr.sin_family = addr->sin_family; @@ -127,7 +127,7 @@ int sys_net_bind(s32 s, vm::ptr addr, u32 addrlen) int sys_net_connect(s32 s, vm::ptr addr, u32 addrlen) { - sys_net->Warning("connect(s=%d, family_addr=0x%x, addrlen=%u)", s, addr.addr(), addrlen); + sys_net->Warning("connect(s=%d, family_addr=0x%x, addrlen=%d)", s, addr.addr(), addrlen); sockaddr_in saddr; memcpy(&saddr, addr.get_ptr(), sizeof(sockaddr_in)); saddr.sin_family = addr->sin_family; @@ -242,7 +242,7 @@ int sys_net_recv(s32 s, vm::ptr buf, u32 len, s32 flags) int sys_net_recvfrom(s32 s, vm::ptr buf, u32 len, s32 flags, vm::ptr addr, vm::ptr paddrlen) { - sys_net->Warning("recvfrom(s=%d, buf_addr=0x%x, len=%u, flags=0x%x, addr_addr=0x%x, paddrlen=0x%x)", + sys_net->Warning("recvfrom(s=%d, buf_addr=0x%x, len=%d, flags=0x%x, addr_addr=0x%x, paddrlen=0x%x)", s, buf.addr(), len, flags, addr.addr(), paddrlen.addr()); sockaddr _addr; @@ -278,7 +278,7 @@ int sendmsg() int sys_net_sendto(s32 s, vm::ptr buf, u32 len, s32 flags, vm::ptr addr, u32 addrlen) { - sys_net->Warning("sendto(s=%d, buf_addr=0x%x, len=%u, flags=0x%x, addr=0x%x, addrlen=%u)", + sys_net->Warning("sendto(s=%d, buf_addr=0x%x, len=%d, flags=0x%x, addr=0x%x, addrlen=%d)", s, buf.addr(), len, flags, addr.addr(), addrlen); sockaddr _addr; @@ -291,7 +291,7 @@ int sys_net_sendto(s32 s, vm::ptr buf, u32 len, s32 flags, vm::ptr optval, u32 optlen) { - sys_net->Warning("socket(s=%d, level=%d, optname=%d, optval_addr=0x%x, optlen=%u)", s, level, optname, optval.addr(), optlen); + sys_net->Warning("socket(s=%d, level=%d, optname=%d, optval_addr=0x%x, optlen=%d)", s, level, optname, optval.addr(), optlen); int ret = setsockopt(s, level, optname, optval.get_ptr(), optlen); *g_lastError = getLastError(); diff --git a/rpcs3/Emu/SysCalls/SC_FUNC.h b/rpcs3/Emu/SysCalls/SC_FUNC.h index 111c4333b2..1a025f2f63 100644 --- a/rpcs3/Emu/SysCalls/SC_FUNC.h +++ b/rpcs3/Emu/SysCalls/SC_FUNC.h @@ -8,7 +8,7 @@ public: virtual ~func_caller(){}; }; -namespace detail +namespace ppu_func_detail { enum bind_arg_type { @@ -28,7 +28,7 @@ namespace detail static __forceinline T func(PPUThread& CPU) { - return (T&)CPU.GPR[g_count + 2]; + return cast_from_ppu_gpr(CPU.GPR[g_count + 2]); } }; @@ -39,18 +39,18 @@ namespace detail static __forceinline T func(PPUThread& CPU) { - return (T)CPU.FPR[f_count]; + return static_cast(CPU.FPR[f_count]); } }; template struct bind_arg { - static_assert(sizeof(T) == 16, "Invalid function argument type for ARG_VECTOR"); + static_assert(std::is_same::value, "Invalid function argument type for ARG_VECTOR"); static __forceinline T func(PPUThread& CPU) { - return (T&)CPU.VPR[v_count + 1]; + return CPU.VPR[v_count + 1]; } }; @@ -65,7 +65,7 @@ namespace detail { // TODO: check stack argument displacement const u64 res = CPU.GetStackArg(8 + std::max(g_count - 8, 0) + std::max(f_count - 13, 0) + std::max(v_count - 12, 0)); - return (T&)res; + return cast_from_ppu_gpr(res); } }; @@ -75,9 +75,9 @@ namespace detail static_assert(type == ARG_GENERAL, "Wrong use of bind_result template"); static_assert(sizeof(T) <= 8, "Invalid function result type for ARG_GENERAL"); - static __forceinline void func(PPUThread& CPU, T result) + static __forceinline void func(PPUThread& CPU, const T& result) { - (T&)CPU.GPR[3] = result; + CPU.GPR[3] = cast_to_ppu_gpr(result); } }; @@ -86,20 +86,20 @@ namespace detail { static_assert(sizeof(T) <= 8, "Invalid function result type for ARG_FLOAT"); - static __forceinline void func(PPUThread& CPU, T result) + static __forceinline void func(PPUThread& CPU, const T& result) { - CPU.FPR[1] = (double)result; + CPU.FPR[1] = static_cast(result); } }; template struct bind_result { - static_assert(sizeof(T) == 16, "Invalid function result type for ARG_VECTOR"); + static_assert(std::is_same::value, "Invalid function result type for ARG_VECTOR"); - static __forceinline void func(PPUThread& CPU, const T result) + static __forceinline void func(PPUThread& CPU, const T& result) { - (T&)CPU.VPR[2] = result; + CPU.VPR[2] = result; } }; @@ -122,21 +122,21 @@ namespace detail }; template - static __forceinline RT call(F f, Tuple && t) + __forceinline RT call(F f, Tuple && t) { typedef typename std::decay::type ttype; - return detail::call_impl::value, std::tuple_size::value>::call(f, std::forward(t)); + return ppu_func_detail::call_impl::value, std::tuple_size::value>::call(f, std::forward(t)); } template - static __forceinline std::tuple<> iterate(PPUThread& CPU) + __forceinline std::tuple<> iterate(PPUThread& CPU) { // terminator return std::tuple<>(); } template - static __forceinline std::tuple iterate(PPUThread& CPU) + __forceinline std::tuple iterate(PPUThread& CPU) { static_assert(!std::is_pointer::value, "Invalid function argument type (pointer)"); static_assert(!std::is_reference::value, "Invalid function argument type (reference)"); @@ -153,6 +153,16 @@ namespace detail return std::tuple_cat(std::tuple(bind_arg::func(CPU)), iterate(CPU)); } + template + struct result_type + { + static_assert(!std::is_pointer::value, "Invalid function result type (pointer)"); + static_assert(!std::is_reference::value, "Invalid function result type (reference)"); + static const bool is_float = std::is_floating_point::value; + static const bool is_vector = std::is_same::value; + static const bind_arg_type value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL); + }; + template class func_binder; @@ -209,13 +219,7 @@ namespace detail virtual void operator()(PPUThread& CPU) { - static_assert(!std::is_pointer::value, "Invalid function result type (pointer)"); - static_assert(!std::is_reference::value, "Invalid function result type (reference)"); - const bool is_float = std::is_floating_point::value; - const bool is_vector = std::is_same::value; - const bind_arg_type t = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL); - - bind_result::func(CPU, call(m_call, iterate<0, 0, 0, T...>(CPU))); + bind_result::value>::func(CPU, call(m_call, iterate<0, 0, 0, T...>(CPU))); } }; @@ -234,13 +238,7 @@ namespace detail virtual void operator()(PPUThread& CPU) { - static_assert(!std::is_pointer::value, "Invalid function result type (pointer)"); - static_assert(!std::is_reference::value, "Invalid function result type (reference)"); - const bool is_float = std::is_floating_point::value; - const bool is_vector = std::is_same::value; - const bind_arg_type t = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL); - - bind_result::func(CPU, call(m_call, std::tuple_cat(std::tuple(CPU), iterate<0, 0, 0, T...>(CPU)))); + bind_result::value>::func(CPU, call(m_call, std::tuple_cat(std::tuple(CPU), iterate<0, 0, 0, T...>(CPU)))); } }; } @@ -248,5 +246,5 @@ namespace detail template func_caller* bind_func(RT(*call)(T...)) { - return new detail::func_binder(call); + return new ppu_func_detail::func_binder(call); } diff --git a/rpcs3/Emu/SysCalls/lv2/cellFs.cpp b/rpcs3/Emu/SysCalls/lv2/cellFs.cpp index 60e09c82fc..79df2eece7 100644 --- a/rpcs3/Emu/SysCalls/lv2/cellFs.cpp +++ b/rpcs3/Emu/SysCalls/lv2/cellFs.cpp @@ -39,10 +39,9 @@ struct FsRingBufferConfig } fs_config; -s32 cellFsOpen(vm::ptr path, s32 flags, vm::ptr> fd, vm::ptr arg, u64 size) +s32 cellFsOpen(vm::ptr path, s32 flags, vm::ptr> fd, vm::ptr arg, u64 size) { - sys_fs->Log("cellFsOpen(path=\"%s\", flags=0x%x, fd_addr=0x%x, arg_addr=0x%x, size=0x%llx)", - path.get_ptr(), flags, fd.addr(), arg.addr(), size); + sys_fs->Log("cellFsOpen(path=0x%x, flags=0x%x, fd=0x%x, arg=0x%x, size=0x%llx)", path, flags, fd, arg, size); const std::string _path = path.get_ptr(); @@ -97,13 +96,13 @@ s32 cellFsOpen(vm::ptr path, s32 flags, vm::ptr> fd, vm::p if (_oflags != 0) { - sys_fs->Error("\"%s\" has unknown flags! flags: 0x%08x", path.get_ptr(), flags); + sys_fs->Error("cellFsOpen(): '%s' has unknown flags! flags: 0x%08x", path.get_ptr(), flags); return CELL_EINVAL; } if (!Emu.GetVFS().ExistsFile(_path)) { - sys_fs->Error("\"%s\" not found! flags: 0x%08x", path.get_ptr(), flags); + sys_fs->Error("cellFsOpen(): '%s' not found! flags: 0x%08x", path.get_ptr(), flags); return CELL_ENOENT; } @@ -111,21 +110,20 @@ s32 cellFsOpen(vm::ptr path, s32 flags, vm::ptr> fd, vm::p if (!stream || !stream->IsOpened()) { - sys_fs->Error("\"%s\" not found! flags: 0x%08x", path.get_ptr(), flags); + sys_fs->Error("cellFsOpen(): '%s' not found! flags: 0x%08x", path.get_ptr(), flags); return CELL_ENOENT; } u32 id = sys_fs->GetNewId(stream, TYPE_FS_FILE); *fd = id; - sys_fs->Notice("\"%s\" opened: fd = %d", path.get_ptr(), id); + sys_fs->Notice("cellFsOpen(): '%s' opened, id -> 0x%x", path.get_ptr(), id); return CELL_OK; } s32 cellFsRead(u32 fd, vm::ptr buf, u64 nbytes, vm::ptr> nread) { - sys_fs->Log("cellFsRead(fd=%d, buf_addr=0x%x, nbytes=0x%llx, nread_addr=0x%x)", - fd, buf.addr(), nbytes, nread.addr()); + sys_fs->Log("cellFsRead(fd=0x%x, buf=0x%x, nbytes=0x%llx, nread=0x%x)", fd, buf, nbytes, nread); std::shared_ptr file; if (!sys_fs->CheckId(fd, file)) @@ -145,8 +143,7 @@ s32 cellFsRead(u32 fd, vm::ptr buf, u64 nbytes, vm::ptr> nread) s32 cellFsWrite(u32 fd, vm::ptr buf, u64 nbytes, vm::ptr nwrite) { - sys_fs->Log("cellFsWrite(fd=%d, buf_addr=0x%x, nbytes=0x%llx, nwrite_addr=0x%x)", - fd, buf.addr(), nbytes, nwrite.addr()); + sys_fs->Log("cellFsWrite(fd=0x%x, buf=0x%x, nbytes=0x%llx, nwrite=0x%x)", fd, buf, nbytes, nwrite); std::shared_ptr file; if (!sys_fs->CheckId(fd, file)) return CELL_ESRCH; @@ -164,7 +161,7 @@ s32 cellFsWrite(u32 fd, vm::ptr buf, u64 nbytes, vm::ptr nwrite s32 cellFsClose(u32 fd) { - sys_fs->Warning("cellFsClose(fd=%d)", fd); + sys_fs->Warning("cellFsClose(fd=0x%x)", fd); if (!Emu.GetIdManager().RemoveID(fd)) return CELL_ESRCH; @@ -174,7 +171,7 @@ s32 cellFsClose(u32 fd) s32 cellFsOpendir(vm::ptr path, vm::ptr fd) { - sys_fs->Warning("cellFsOpendir(path=\"%s\", fd_addr=0x%x)", path.get_ptr(), fd.addr()); + sys_fs->Warning("cellFsOpendir(path=0x%x, fd=0x%x)", path, fd); std::shared_ptr dir(Emu.GetVFS().OpenDir(path.get_ptr())); if (!dir || !dir->IsOpened()) @@ -188,7 +185,7 @@ s32 cellFsOpendir(vm::ptr path, vm::ptr fd) s32 cellFsReaddir(u32 fd, vm::ptr dir, vm::ptr nread) { - sys_fs->Warning("cellFsReaddir(fd=%d, dir_addr=0x%x, nread_addr=0x%x)", fd, dir.addr(), nread.addr()); + sys_fs->Warning("cellFsReaddir(fd=0x%x, dir=0x%x, nread=0x%x)", fd, dir, nread); std::shared_ptr directory; if (!sys_fs->CheckId(fd, directory)) @@ -212,7 +209,7 @@ s32 cellFsReaddir(u32 fd, vm::ptr dir, vm::ptr nread) s32 cellFsClosedir(u32 fd) { - sys_fs->Warning("cellFsClosedir(fd=%d)", fd); + sys_fs->Warning("cellFsClosedir(fd=0x%x)", fd); if (!Emu.GetIdManager().RemoveID(fd)) return CELL_ESRCH; @@ -222,7 +219,7 @@ s32 cellFsClosedir(u32 fd) s32 cellFsStat(vm::ptr path, vm::ptr sb) { - sys_fs->Warning("cellFsStat(path=\"%s\", sb_addr=0x%x)", path.get_ptr(), sb.addr()); + sys_fs->Warning("cellFsStat(path=0x%x, sb=0x%x)", path, sb); const std::string _path = path.get_ptr(); @@ -242,7 +239,7 @@ s32 cellFsStat(vm::ptr path, vm::ptr sb) if (int result = stat(real_path.c_str(), &buf)) { - sys_fs->Error("stat('%s') failed -> 0x%x", real_path.c_str(), result); + sys_fs->Error("cellFsStat(): stat('%s') failed -> 0x%x", real_path.c_str(), result); } else { @@ -261,7 +258,7 @@ s32 cellFsStat(vm::ptr path, vm::ptr sb) CELL_FS_S_IROTH | CELL_FS_S_IWOTH | CELL_FS_S_IXOTH; if (sb->st_mode == mode) - sys_fs->Error("Mode is the same. Report this to a RPCS3 developer! (%d)", mode); + sys_fs->Error("cellFsStat(): mode is the same (0x%x)", mode); sb->st_uid = uid; sb->st_gid = gid; @@ -290,15 +287,15 @@ s32 cellFsStat(vm::ptr path, vm::ptr sb) } if (sb->st_size == size && size != 0) - sys_fs->Error("Size is the same. Report this to a RPCS3 developer! (%d)", size); + sys_fs->Error("cellFsStat(): size is the same (0x%x)", size); - sys_fs->Warning("cellFsStat: \"%s\" not found.", path.get_ptr()); + sys_fs->Warning("cellFsStat(): '%s' not found", path.get_ptr()); return CELL_ENOENT; } s32 cellFsFstat(u32 fd, vm::ptr sb) { - sys_fs->Warning("cellFsFstat(fd=%d, sb_addr=0x%x)", fd, sb.addr()); + sys_fs->Warning("cellFsFstat(fd=0x%x, sb=0x%x)", fd, sb); IDType type; std::shared_ptr file; @@ -324,7 +321,7 @@ s32 cellFsFstat(u32 fd, vm::ptr sb) s32 cellFsMkdir(vm::ptr path, u32 mode) { - sys_fs->Warning("cellFsMkdir(path=\"%s\", mode=0x%x)", path.get_ptr(), mode); + sys_fs->Warning("cellFsMkdir(path=0x%x, mode=0x%x)", path, mode); const std::string _path = path.get_ptr(); @@ -334,12 +331,13 @@ s32 cellFsMkdir(vm::ptr path, u32 mode) if (!Emu.GetVFS().CreateDir(_path)) return CELL_EBUSY; + sys_fs->Notice("cellFsMkdir(): directory '%s' created", path.get_ptr()); return CELL_OK; } s32 cellFsRename(vm::ptr from, vm::ptr to) { - sys_fs->Warning("cellFsRename(from='%s', to='%s')", from.get_ptr(), to.get_ptr()); + sys_fs->Warning("cellFsRename(from=0x%x, to=0x%x)", from, to); std::string _from = from.get_ptr(); std::string _to = to.get_ptr(); @@ -351,6 +349,7 @@ s32 cellFsRename(vm::ptr from, vm::ptr to) if(!dir.Rename(_from, _to)) return CELL_EBUSY; + sys_fs->Notice("cellFsRename(): directory '%s' renamed to '%s'", from.get_ptr(), to.get_ptr()); return CELL_OK; } } @@ -363,6 +362,7 @@ s32 cellFsRename(vm::ptr from, vm::ptr to) if(!f.Rename(_from, _to)) return CELL_EBUSY; + sys_fs->Notice("cellFsRename(): file '%s' renamed to '%s'", from.get_ptr(), to.get_ptr()); return CELL_OK; } } @@ -371,7 +371,7 @@ s32 cellFsRename(vm::ptr from, vm::ptr to) } s32 cellFsChmod(vm::ptr path, u32 mode) { - sys_fs->Todo("cellFsChmod(path=\"%s\", mode=0x%x)", path.get_ptr(), mode); + sys_fs->Todo("cellFsChmod(path=0x%x, mode=0x%x)", path, mode); // TODO: @@ -389,7 +389,7 @@ s32 cellFsFsync(u32 fd) s32 cellFsRmdir(vm::ptr path) { - sys_fs->Warning("cellFsRmdir(path=\"%s\")", path.get_ptr()); + sys_fs->Warning("cellFsRmdir(path=0x%x)", path.get_ptr()); std::string _path = path.get_ptr(); @@ -400,12 +400,13 @@ s32 cellFsRmdir(vm::ptr path) if (!d.Remove(_path)) return CELL_EBUSY; + sys_fs->Notice("cellFsRmdir(): directory '%s' removed", path.get_ptr()); return CELL_OK; } s32 cellFsUnlink(vm::ptr path) { - sys_fs->Warning("cellFsUnlink(path=\"%s\")", path.get_ptr()); + sys_fs->Warning("cellFsUnlink(path=0x%x)", path); std::string _path = path.get_ptr(); @@ -418,12 +419,13 @@ s32 cellFsUnlink(vm::ptr path) if (!Emu.GetVFS().RemoveFile(_path)) return CELL_EACCES; + sys_fs->Notice("cellFsUnlink(): file '%s' removed", path.get_ptr()); return CELL_OK; } s32 cellFsLseek(u32 fd, s64 offset, u32 whence, vm::ptr> pos) { - sys_fs->Log("cellFsLseek(fd=%d, offset=0x%llx, whence=0x%x, pos_addr=0x%x)", fd, offset, whence, pos.addr()); + sys_fs->Log("cellFsLseek(fd=0x%x, offset=0x%llx, whence=0x%x, pos=0x%x)", fd, offset, whence, pos); vfsSeekMode seek_mode; switch(whence) @@ -432,7 +434,7 @@ s32 cellFsLseek(u32 fd, s64 offset, u32 whence, vm::ptr> pos) case CELL_SEEK_CUR: seek_mode = vfsSeekCur; break; case CELL_SEEK_END: seek_mode = vfsSeekEnd; break; default: - sys_fs->Error(fd, "Unknown seek whence! (0x%x)", whence); + sys_fs->Error("cellFsLseek(fd=0x%x): Unknown seek whence! (0x%x)", fd, whence); return CELL_EINVAL; } @@ -447,7 +449,7 @@ s32 cellFsLseek(u32 fd, s64 offset, u32 whence, vm::ptr> pos) s32 cellFsFtruncate(u32 fd, u64 size) { - sys_fs->Warning("cellFsFtruncate(fd=%d, size=%lld)", fd, size); + sys_fs->Warning("cellFsFtruncate(fd=0x%x, size=0x%llx)", fd, size); IDType type; std::shared_ptr file; @@ -476,12 +478,12 @@ s32 cellFsFtruncate(u32 fd, u64 size) s32 cellFsTruncate(vm::ptr path, u64 size) { - sys_fs->Warning("cellFsTruncate(path=\"%s\", size=%lld)", path.get_ptr(), size); + sys_fs->Warning("cellFsTruncate(path=0x%x, size=0x%llx)", path, size); vfsFile f(path.get_ptr(), vfsReadWrite); if (!f.IsOpened()) { - sys_fs->Warning("cellFsTruncate: \"%s\" not found.", path.get_ptr()); + sys_fs->Warning("cellFsTruncate(): '%s' not found", path.get_ptr()); return CELL_ENOENT; } u64 initialSize = f.GetSize(); @@ -506,8 +508,7 @@ s32 cellFsTruncate(vm::ptr path, u64 size) s32 cellFsFGetBlockSize(u32 fd, vm::ptr sector_size, vm::ptr block_size) { - sys_fs->Warning("cellFsFGetBlockSize(fd=%d, sector_size_addr=0x%x, block_size_addr=0x%x)", - fd, sector_size.addr(), block_size.addr()); + sys_fs->Warning("cellFsFGetBlockSize(fd=0x%x, sector_size=0x%x, block_size=0x%x)", fd, sector_size, block_size); LV2_LOCK(0); @@ -523,8 +524,7 @@ s32 cellFsFGetBlockSize(u32 fd, vm::ptr sector_size, vm::ptr block_siz s32 cellFsGetBlockSize(vm::ptr path, vm::ptr sector_size, vm::ptr block_size) { - sys_fs->Warning("cellFsGetBlockSize(file='%s', sector_size_addr=0x%x, block_size_addr=0x%x)", - path.get_ptr(), sector_size.addr(), block_size.addr()); + sys_fs->Warning("cellFsGetBlockSize(path=0x%x, sector_size=0x%x, block_size=0x%x)", path, sector_size, block_size); *sector_size = 4096; // ? *block_size = 4096; // ? @@ -534,8 +534,7 @@ s32 cellFsGetBlockSize(vm::ptr path, vm::ptr sector_size, vm::p s32 cellFsGetFreeSize(vm::ptr path, vm::ptr block_size, vm::ptr block_count) { - sys_fs->Warning("cellFsGetFreeSize(path=\"%s\", block_size_addr=0x%x, block_count_addr=0x%x)", - path.get_ptr(), block_size.addr(), block_count.addr()); + sys_fs->Warning("cellFsGetFreeSize(path=0x%x, block_size=0x%x, block_count=0x%x)", path, block_size, block_count); // TODO: Get real values. Currently, it always returns 40 GB of free space divided in 4 KB blocks *block_size = 4096; // ? @@ -546,8 +545,7 @@ s32 cellFsGetFreeSize(vm::ptr path, vm::ptr block_size, vm::ptr s32 cellFsGetDirectoryEntries(u32 fd, vm::ptr entries, u32 entries_size, vm::ptr data_count) { - sys_fs->Warning("cellFsGetDirectoryEntries(fd=%d, entries_addr=0x%x, entries_size=0x%x, data_count_addr=0x%x)", - fd, entries.addr(), entries_size, data_count.addr()); + sys_fs->Warning("cellFsGetDirectoryEntries(fd=0x%x, entries=0x%x, entries_size=0x%x, data_count=0x%x)", fd, entries, entries_size, data_count); std::shared_ptr directory; if (!sys_fs->CheckId(fd, directory)) @@ -583,7 +581,7 @@ s32 cellFsGetDirectoryEntries(u32 fd, vm::ptr entries, u32 s32 cellFsStReadInit(u32 fd, vm::ptr ringbuf) { - sys_fs->Warning("cellFsStReadInit(fd=%d, ringbuf_addr=0x%x)", fd, ringbuf.addr()); + sys_fs->Warning("cellFsStReadInit(fd=0x%x, ringbuf=0x%x)", fd, ringbuf); std::shared_ptr file; if (!sys_fs->CheckId(fd, file)) @@ -608,7 +606,7 @@ s32 cellFsStReadInit(u32 fd, vm::ptr ringbuf) s32 cellFsStReadFinish(u32 fd) { - sys_fs->Warning("cellFsStReadFinish(fd=%d)", fd); + sys_fs->Warning("cellFsStReadFinish(fd=0x%x)", fd); std::shared_ptr file; if (!sys_fs->CheckId(fd, file)) @@ -622,7 +620,7 @@ s32 cellFsStReadFinish(u32 fd) s32 cellFsStReadGetRingBuf(u32 fd, vm::ptr ringbuf) { - sys_fs->Warning("cellFsStReadGetRingBuf(fd=%d, ringbuf_addr=0x%x)", fd, ringbuf.addr()); + sys_fs->Warning("cellFsStReadGetRingBuf(fd=0x%x, ringbuf=0x%x)", fd, ringbuf); std::shared_ptr file; if (!sys_fs->CheckId(fd, file)) @@ -630,14 +628,14 @@ s32 cellFsStReadGetRingBuf(u32 fd, vm::ptr ringbuf) *ringbuf = fs_config.m_ring_buffer; - sys_fs->Warning("*** fs stream config: block_size=0x%llx, copy=%d, ringbuf_size=0x%llx, transfer_rate=0x%llx", - (u64)ringbuf->block_size, (u32)ringbuf->copy, (u64)ringbuf->ringbuf_size, (u64)ringbuf->transfer_rate); + sys_fs->Warning("*** fs stream config: block_size=0x%llx, copy=0x%x, ringbuf_size=0x%llx, transfer_rate=0x%llx", + ringbuf->block_size, ringbuf->copy, ringbuf->ringbuf_size, ringbuf->transfer_rate); return CELL_OK; } s32 cellFsStReadGetStatus(u32 fd, vm::ptr status) { - sys_fs->Warning("cellFsStReadGetRingBuf(fd=%d, status_addr=0x%x)", fd, status.addr()); + sys_fs->Warning("cellFsStReadGetRingBuf(fd=0x%x, status=0x%x)", fd, status); std::shared_ptr file; if (!sys_fs->CheckId(fd, file)) @@ -650,7 +648,7 @@ s32 cellFsStReadGetStatus(u32 fd, vm::ptr status) s32 cellFsStReadGetRegid(u32 fd, vm::ptr regid) { - sys_fs->Warning("cellFsStReadGetRingBuf(fd=%d, regid_addr=0x%x)", fd, regid.addr()); + sys_fs->Warning("cellFsStReadGetRingBuf(fd=0x%x, regid=0x%x)", fd, regid); std::shared_ptr file; if (!sys_fs->CheckId(fd, file)) @@ -663,7 +661,7 @@ s32 cellFsStReadGetRegid(u32 fd, vm::ptr regid) s32 cellFsStReadStart(u32 fd, u64 offset, u64 size) { - sys_fs->Todo("cellFsStReadStart(fd=%d, offset=0x%llx, size=0x%llx)", fd, offset, size); + sys_fs->Todo("cellFsStReadStart(fd=0x%x, offset=0x%llx, size=0x%llx)", fd, offset, size); std::shared_ptr file; if (!sys_fs->CheckId(fd, file)) @@ -677,7 +675,7 @@ s32 cellFsStReadStart(u32 fd, u64 offset, u64 size) s32 cellFsStReadStop(u32 fd) { - sys_fs->Warning("cellFsStReadStop(fd=%d)", fd); + sys_fs->Warning("cellFsStReadStop(fd=0x%x)", fd); std::shared_ptr file; if (!sys_fs->CheckId(fd, file)) @@ -688,9 +686,9 @@ s32 cellFsStReadStop(u32 fd) return CELL_OK; } -s32 cellFsStRead(u32 fd, u32 buf_addr, u64 size, vm::ptr rsize) +s32 cellFsStRead(u32 fd, vm::ptr buf, u64 size, vm::ptr rsize) { - sys_fs->Warning("cellFsStRead(fd=%d, buf_addr=0x%x, size=0x%llx, rsize_addr=0x%x)", fd, buf_addr, size, rsize.addr()); + sys_fs->Warning("cellFsStRead(fd=0x%x, buf=0x%x, size=0x%llx, rsize=0x%x)", fd, buf, size, rsize); std::shared_ptr file; if (!sys_fs->CheckId(fd, file)) @@ -702,14 +700,14 @@ s32 cellFsStRead(u32 fd, u32 buf_addr, u64 size, vm::ptr rsize) if (file->Eof()) return CELL_FS_ERANGE; - *rsize = file->Read(vm::get_ptr(buf_addr), size); + *rsize = file->Read(buf.get_ptr(), size); return CELL_OK; } -s32 cellFsStReadGetCurrentAddr(u32 fd, vm::ptr addr, vm::ptr size) +s32 cellFsStReadGetCurrentAddr(u32 fd, vm::ptr> addr, vm::ptr size) { - sys_fs->Todo("cellFsStReadGetCurrentAddr(fd=%d, addr_addr=0x%x, size_addr=0x%x)", fd, addr.addr(), size.addr()); + sys_fs->Todo("cellFsStReadGetCurrentAddr(fd=0x%x, addr=0x%x, size=0x%x)", fd, addr, size); std::shared_ptr file; if (!sys_fs->CheckId(fd, file)) @@ -718,9 +716,9 @@ s32 cellFsStReadGetCurrentAddr(u32 fd, vm::ptr addr, vm::ptr size) return CELL_OK; } -s32 cellFsStReadPutCurrentAddr(u32 fd, u32 addr_addr, u64 size) +s32 cellFsStReadPutCurrentAddr(u32 fd, vm::ptr addr, u64 size) { - sys_fs->Todo("cellFsStReadPutCurrentAddr(fd=%d, addr_addr=0x%x, size=0x%llx)", fd, addr_addr, size); + sys_fs->Todo("cellFsStReadPutCurrentAddr(fd=0x%x, addr=0x%x, size=0x%llx)", fd, addr, size); std::shared_ptr file; if (!sys_fs->CheckId(fd, file)) @@ -731,7 +729,7 @@ s32 cellFsStReadPutCurrentAddr(u32 fd, u32 addr_addr, u64 size) s32 cellFsStReadWait(u32 fd, u64 size) { - sys_fs->Todo("cellFsStReadWait(fd=%d, size=0x%llx)", fd, size); + sys_fs->Todo("cellFsStReadWait(fd=0x%x, size=0x%llx)", fd, size); std::shared_ptr file; if (!sys_fs->CheckId(fd, file)) @@ -742,7 +740,7 @@ s32 cellFsStReadWait(u32 fd, u64 size) s32 cellFsStReadWaitCallback(u32 fd, u64 size, vm::ptr func) { - sys_fs->Todo("cellFsStReadWaitCallback(fd=%d, size=0x%llx, func_addr=0x%x)", fd, size, func.addr()); + sys_fs->Todo("cellFsStReadWaitCallback(fd=0x%x, size=0x%llx, func=0x%x)", fd, size, func); std::shared_ptr file; if (!sys_fs->CheckId(fd, file)) @@ -784,13 +782,13 @@ int sdata_unpack(const std::string& packed_file, const std::string& unpacked_fil if (!packed_stream || !packed_stream->IsOpened()) { - sys_fs->Error("'%s' not found! flags: 0x%08x", packed_file.c_str(), vfsRead); + sys_fs->Error("'%s' not found! flags: 0x%02x", packed_file.c_str(), vfsRead); return CELL_ENOENT; } if (!unpacked_stream || !unpacked_stream->IsOpened()) { - sys_fs->Error("'%s' couldn't be created! flags: 0x%08x", unpacked_file.c_str(), vfsWrite); + sys_fs->Error("'%s' couldn't be created! flags: 0x%02x", unpacked_file.c_str(), vfsWrite); return CELL_ENOENT; } @@ -851,10 +849,9 @@ int sdata_unpack(const std::string& packed_file, const std::string& unpacked_fil return CELL_OK; } -int cellFsSdataOpen(vm::ptr path, int flags, vm::ptr> fd, vm::ptr arg, u64 size) +s32 cellFsSdataOpen(vm::ptr path, s32 flags, vm::ptr> fd, vm::ptr arg, u64 size) { - sys_fs->Warning("cellFsSdataOpen(path=\"%s\", flags=0x%x, fd_addr=0x%x, arg_addr=0x%x, size=0x%llx) -> cellFsOpen()", - path.get_ptr(), flags, fd.addr(), arg.addr(), size); + sys_fs->Warning("cellFsSdataOpen(path=0x%x, flags=0x%x, fd=0x%x, arg=0x%x, size=0x%llx) -> cellFsOpen()", path, flags, fd, arg, size); /*if (flags != CELL_O_RDONLY) return CELL_EINVAL; @@ -876,18 +873,17 @@ int cellFsSdataOpen(vm::ptr path, int flags, vm::ptr> fd, return cellFsOpen(path, flags, fd, arg, size); } -int cellFsSdataOpenByFd(int mself_fd, int flags, vm::ptr sdata_fd, u64 offset, vm::ptr arg, u64 size) +s32 cellFsSdataOpenByFd(u32 mself_fd, s32 flags, vm::ptr sdata_fd, u64 offset, vm::ptr arg, u64 size) { - sys_fs->Todo("cellFsSdataOpenByFd(mself_fd=0x%x, flags=0x%x, sdata_fd_addr=0x%x, offset=0x%llx, arg_addr=0x%x, size=0x%llx) -> cellFsOpen()", - mself_fd, flags, sdata_fd.addr(), offset, arg.addr(), size); + sys_fs->Todo("cellFsSdataOpenByFd(mself_fd=0x%x, flags=0x%x, sdata_fd=0x%x, offset=0x%llx, arg=0x%x, size=0x%llx)", mself_fd, flags, sdata_fd, offset, arg, size); // TODO: return CELL_OK; } -std::atomic g_FsAioReadID(0); -std::atomic g_FsAioReadCur(0); +std::atomic g_FsAioReadID(0); +std::atomic g_FsAioReadCur(0); bool aio_init = false; void fsAioRead(u32 fd, vm::ptr aio, int xid, vm::ptr xaio, int error, int xid, u64 size)> func) @@ -919,7 +915,6 @@ void fsAioRead(u32 fd, vm::ptr aio, int xid, vm::ptroffset); - // TODO: use code from cellFsRead or something if (nbytes != (u32)nbytes) { error = CELL_ENOMEM; @@ -931,24 +926,24 @@ void fsAioRead(u32 fd, vm::ptr aio, int xid, vm::ptrLog("*** fsAioRead(fd=%d, offset=0x%llx, buf_addr=0x%x, size=0x%x, error=0x%x, res=0x%x, xid=0x%x)", - fd, (u64)aio->offset, aio->buf.addr(), (u64)aio->size, error, res, xid); + sys_fs->Log("*** fsAioRead(fd=%d, offset=0x%llx, buf=0x%x, size=0x%llx, error=0x%x, res=0x%llx, xid=0x%x)", + fd, aio->offset, aio->buf, aio->size, error, res, xid); } - if (func) // start callback thread + if (func) { - Emu.GetCallbackManager().Async([func, aio, error, xid, res]() + Emu.GetCallbackManager().Async([func, aio, error, xid, res](PPUThread& CPU) { - func(aio, error, xid, res); + func(CPU, aio, error, xid, res); }); } g_FsAioReadCur++; } -int cellFsAioRead(vm::ptr aio, vm::ptr aio_id, vm::ptr xaio, int error, int xid, u64 size)> func) +s32 cellFsAioRead(vm::ptr aio, vm::ptr id, vm::ptr xaio, s32 error, s32 xid, u64 size)> func) { - sys_fs->Warning("cellFsAioRead(aio_addr=0x%x, id_addr=0x%x, func_addr=0x%x)", aio.addr(), aio_id.addr(), func.addr()); + sys_fs->Warning("cellFsAioRead(aio=0x%x, id=0x%x, func=0x%x)", aio, id, func); if (!aio_init) { @@ -964,49 +959,44 @@ int cellFsAioRead(vm::ptr aio, vm::ptr aio_id, vm::ptr aio, vm::ptr aio_id, vm::ptr xaio, int error, int xid, u64 size)> func) +s32 cellFsAioWrite(vm::ptr aio, vm::ptr id, vm::ptr xaio, s32 error, s32 xid, u64 size)> func) { - sys_fs->Todo("cellFsAioWrite(aio_addr=0x%x, id_addr=0x%x, func_addr=0x%x)", aio.addr(), aio_id.addr(), func.addr()); + sys_fs->Todo("cellFsAioWrite(aio=0x%x, id=0x%x, func=0x%x)", aio, id, func); // TODO: return CELL_OK; } -int cellFsAioInit(vm::ptr mount_point) +s32 cellFsAioInit(vm::ptr mount_point) { - sys_fs->Warning("cellFsAioInit(mount_point_addr=0x%x (%s))", mount_point.addr(), mount_point.get_ptr()); + sys_fs->Warning("cellFsAioInit(mount_point=0x%x)", mount_point); aio_init = true; return CELL_OK; } -int cellFsAioFinish(vm::ptr mount_point) +s32 cellFsAioFinish(vm::ptr mount_point) { - sys_fs->Warning("cellFsAioFinish(mount_point_addr=0x%x (%s))", mount_point.addr(), mount_point.get_ptr()); + sys_fs->Warning("cellFsAioFinish(mount_point=0x%x)", mount_point); - aio_init = false; + //aio_init = false; return CELL_OK; } -int cellFsReadWithOffset(u32 fd, u64 offset, vm::ptr buf, u64 buffer_size, vm::ptr> nread) +s32 cellFsReadWithOffset(PPUThread& CPU, u32 fd, u64 offset, vm::ptr buf, u64 buffer_size, vm::ptr> nread) { - sys_fs->Warning("cellFsReadWithOffset(fd=%d, offset=0x%llx, buf_addr=0x%x, buffer_size=%lld nread=0x%llx)", - fd, offset, buf.addr(), buffer_size, nread.addr()); + sys_fs->Warning("cellFsReadWithOffset(fd=%d, offset=0x%llx, buf=0x%x, buffer_size=%lld, nread=0x%llx)", fd, offset, buf, buffer_size, nread); int ret; - vm::var> oldPos, newPos; + vm::stackvar> oldPos(CPU), newPos(CPU); ret = cellFsLseek(fd, 0, CELL_SEEK_CUR, oldPos); // Save the current position if (ret) return ret; ret = cellFsLseek(fd, offset, CELL_SEEK_SET, newPos); // Move to the specified offset diff --git a/rpcs3/Emu/SysCalls/lv2/cellFs.h b/rpcs3/Emu/SysCalls/lv2/cellFs.h index 6adb71cdc9..e114ef3464 100644 --- a/rpcs3/Emu/SysCalls/lv2/cellFs.h +++ b/rpcs3/Emu/SysCalls/lv2/cellFs.h @@ -128,7 +128,7 @@ struct CellFsRingBuffer }; // SysCalls -s32 cellFsOpen(vm::ptr path, s32 flags, vm::ptr> fd, vm::ptr arg, u64 size); +s32 cellFsOpen(vm::ptr path, s32 flags, vm::ptr> fd, vm::ptr arg, u64 size); s32 cellFsRead(u32 fd, vm::ptr buf, u64 nbytes, vm::ptr> nread); s32 cellFsWrite(u32 fd, vm::ptr buf, u64 nbytes, vm::ptr nwrite); s32 cellFsClose(u32 fd); @@ -150,15 +150,5 @@ s32 cellFsFGetBlockSize(u32 fd, vm::ptr sector_size, vm::ptr block_siz s32 cellFsGetBlockSize(vm::ptr path, vm::ptr sector_size, vm::ptr block_size); s32 cellFsGetFreeSize(vm::ptr path, vm::ptr block_size, vm::ptr block_count); s32 cellFsGetDirectoryEntries(u32 fd, vm::ptr entries, u32 entries_size, vm::ptr data_count); -s32 cellFsStReadInit(u32 fd, vm::ptr ringbuf); -s32 cellFsStReadFinish(u32 fd); -s32 cellFsStReadGetRingBuf(u32 fd, vm::ptr ringbuf); -s32 cellFsStReadGetStatus(u32 fd, vm::ptr status); -s32 cellFsStReadGetRegid(u32 fd, vm::ptr regid); -s32 cellFsStReadStart(u32 fd, u64 offset, u64 size); -s32 cellFsStReadStop(u32 fd); -s32 cellFsStRead(u32 fd, u32 buf_addr, u64 size, vm::ptr rsize); -s32 cellFsStReadGetCurrentAddr(u32 fd, vm::ptr addr_addr, vm::ptr size); -s32 cellFsStReadPutCurrentAddr(u32 fd, u32 addr_addr, u64 size); -s32 cellFsStReadWait(u32 fd, u64 size); -s32 cellFsStReadWaitCallback(u32 fd, u64 size, vm::ptr func); + +// no need to add every function here diff --git a/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp b/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp index 67c9e1001c..313af6025d 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp @@ -17,9 +17,9 @@ s32 sys_cond_create(vm::ptr cond_id, u32 mutex_id, vm::ptrpshared.ToBE() != se32(0x200)) + if (attr->pshared.data() != se32(0x200)) { - sys_cond.Error("Invalid pshared attribute(0x%x)", (u32)attr->pshared); + sys_cond.Error("Unknown pshared attribute (0x%x)", attr->pshared); return CELL_EINVAL; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_event.cpp b/rpcs3/Emu/SysCalls/lv2/sys_event.cpp index 305fccdacb..b64cbeb32d 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_event.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_event.cpp @@ -39,20 +39,20 @@ s32 sys_event_queue_create(vm::ptr equeue_id, vm::ptr return CELL_EINVAL; } - switch (attr->protocol.ToBE()) + switch (attr->protocol.data()) { case se32(SYS_SYNC_PRIORITY): break; - case se32(SYS_SYNC_RETRY): sys_event.Error("Invalid SYS_SYNC_RETRY protocol attr"); return CELL_EINVAL; - case se32(SYS_SYNC_PRIORITY_INHERIT): sys_event.Error("Invalid SYS_SYNC_PRIORITY_INHERIT protocol attr"); return CELL_EINVAL; + case se32(SYS_SYNC_RETRY): sys_event.Error("Invalid protocol (SYS_SYNC_RETRY)"); return CELL_EINVAL; + case se32(SYS_SYNC_PRIORITY_INHERIT): sys_event.Error("Invalid protocol (SYS_SYNC_PRIORITY_INHERIT)"); return CELL_EINVAL; case se32(SYS_SYNC_FIFO): break; - default: sys_event.Error("Unknown 0x%x protocol attr", (u32)attr->protocol); return CELL_EINVAL; + default: sys_event.Error("Unknown protocol (0x%x)", attr->protocol); return CELL_EINVAL; } - switch (attr->type.ToBE()) + switch (attr->type.data()) { case se32(SYS_PPU_QUEUE): break; case se32(SYS_SPU_QUEUE): break; - default: sys_event.Error("Unknown 0x%x type attr", (s32)attr->type); return CELL_EINVAL; + default: sys_event.Error("Unknown event queue type (0x%x)", attr->type); return CELL_EINVAL; } if (event_queue_key && Emu.GetEventManager().CheckKey(event_queue_key)) diff --git a/rpcs3/Emu/SysCalls/lv2/sys_event_flag.cpp b/rpcs3/Emu/SysCalls/lv2/sys_event_flag.cpp index 9c186d6a75..e6c82b7828 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_event_flag.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_event_flag.cpp @@ -69,32 +69,32 @@ s32 sys_event_flag_create(vm::ptr eflag_id, vm::ptr at return CELL_EFAULT; } - switch (attr->protocol.ToBE()) + switch (attr->protocol.data()) { case se32(SYS_SYNC_PRIORITY): break; - case se32(SYS_SYNC_RETRY): sys_event_flag.Todo("sys_event_flag_create(): SYS_SYNC_RETRY"); break; - case se32(SYS_SYNC_PRIORITY_INHERIT): sys_event_flag.Todo("sys_event_flag_create(): SYS_SYNC_PRIORITY_INHERIT"); break; + case se32(SYS_SYNC_RETRY): sys_event_flag.Todo("SYS_SYNC_RETRY"); break; + case se32(SYS_SYNC_PRIORITY_INHERIT): sys_event_flag.Todo("SYS_SYNC_PRIORITY_INHERIT"); break; case se32(SYS_SYNC_FIFO): break; - default: return CELL_EINVAL; + default: sys_event_flag.Error("Unknown protocol (0x%x)", attr->protocol); return CELL_EINVAL; } - if (attr->pshared.ToBE() != se32(0x200)) + if (attr->pshared.data() != se32(0x200)) { + sys_event_flag.Error("Unknown pshared attribute (0x%x)", attr->pshared); return CELL_EINVAL; } - switch (attr->type.ToBE()) + switch (attr->type.data()) { case se32(SYS_SYNC_WAITER_SINGLE): break; case se32(SYS_SYNC_WAITER_MULTIPLE): break; - default: return CELL_EINVAL; + default: sys_event_flag.Error("Unknown event flag type (0x%x)", attr->type); return CELL_EINVAL; } - std::shared_ptr ef(new EventFlag(init, (u32)attr->protocol, (s32)attr->type, attr->name_u64)); + std::shared_ptr ef(new EventFlag(init, attr->protocol, attr->type, attr->name_u64)); u32 id = sys_event_flag.GetNewId(ef, TYPE_EVENT_FLAG); *eflag_id = id; - sys_event_flag.Warning("*** event_flag created [%s] (protocol=0x%x, type=0x%x): id = %d", - std::string(attr->name, 8).c_str(), (u32)attr->protocol, (s32)attr->type, id); + sys_event_flag.Warning("*** event_flag created [%s] (protocol=0x%x, type=0x%x): id = %d", std::string(attr->name, 8).c_str(), attr->protocol, attr->type, id); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_event_flag.h b/rpcs3/Emu/SysCalls/lv2/sys_event_flag.h index 5f21c5f413..2272ca8ca1 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_event_flag.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_event_flag.h @@ -41,10 +41,10 @@ struct EventFlag std::vector waiters; const u32 protocol; - const int type; + const s32 type; const u64 name; - EventFlag(u64 pattern, u32 protocol, int type, u64 name) + EventFlag(u64 pattern, u32 protocol, s32 type, u64 name) : protocol(protocol) , type(type) , name(name) diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp index 6670f797e6..3632747a53 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp @@ -14,10 +14,12 @@ SysCallBase sys_lwcond("sys_lwcond"); s32 lwcond_create(sys_lwcond_t& lwcond, sys_lwmutex_t& lwmutex, u64 name_u64) { - std::shared_ptr lw(new Lwcond(name_u64, Memory.RealToVirtualAddr(&lwcond))); + const u32 addr = vm::get_addr(&lwmutex); + + std::shared_ptr lw(new Lwcond(name_u64, addr)); const u32 id = sys_lwcond.GetNewId(lw, TYPE_LWCOND); - const u32 addr = Memory.RealToVirtualAddr(&lwmutex); + lw->queue.set_full_name(fmt::Format("Lwcond(%d, addr=0x%x)", id, lw->addr)); lwcond.lwmutex.set(addr); lwcond.lwcond_queue = id; @@ -65,7 +67,7 @@ s32 sys_lwcond_signal(vm::ptr lwcond) return CELL_ESRCH; } - auto mutex = vm::ptr::make(lwcond->lwmutex.addr()); + auto mutex = lwcond->lwmutex.to_le(); if (u32 target = lw->queue.signal(mutex->attribute)) { @@ -89,7 +91,7 @@ s32 sys_lwcond_signal_all(vm::ptr lwcond) return CELL_ESRCH; } - auto mutex = vm::ptr::make(lwcond->lwmutex.addr()); + auto mutex = lwcond->lwmutex.to_le(); while (u32 target = lw->queue.signal(mutex->attribute)) { @@ -138,9 +140,9 @@ s32 sys_lwcond_wait(PPUThread& CPU, vm::ptr lwcond, u64 timeout) return CELL_ESRCH; } - auto mutex = vm::ptr::make(lwcond->lwmutex.addr()); + auto mutex = lwcond->lwmutex.to_le(); u32 tid_le = CPU.GetId(); - be_t tid = be_t::make(tid_le); + auto tid = be_t::make(tid_le); std::shared_ptr sq; if (!Emu.GetIdManager().GetIDData((u32)mutex->sleep_queue, sq)) @@ -160,7 +162,7 @@ s32 sys_lwcond_wait(PPUThread& CPU, vm::ptr lwcond, u64 timeout) auto old_recursive = mutex->recursive_count.read_relaxed(); mutex->recursive_count.exchange(be_t::make(0)); - be_t target = be_t::make(sq->signal(mutex->attribute)); + auto target = be_t::make(sq->signal(mutex->attribute)); if (!mutex->owner.compare_and_swap_test(tid, target)) { assert(!"sys_lwcond_wait(): mutex unlocking failed"); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp index 0e5eae950c..03e8e8a776 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp @@ -22,9 +22,10 @@ s32 lwmutex_create(sys_lwmutex_t& lwmutex, u32 protocol, u32 recursive, u64 name lwmutex.recursive_count.write_relaxed(be_t::make(0)); u32 sq_id = sys_lwmutex.GetNewId(sq, TYPE_LWMUTEX); lwmutex.sleep_queue = sq_id; - sq->set_full_name(fmt::Format("Lwmutex(%d, addr=0x%x)", sq_id, Memory.RealToVirtualAddr(&lwmutex))); + sq->set_full_name(fmt::Format("Lwmutex(%d, addr=0x%x)", sq_id, vm::get_addr(&lwmutex))); - sys_lwmutex.Notice("*** lwmutex created [%s] (attribute=0x%x): sq_id = %d", std::string((const char*)&name_u64, 8).c_str(), protocol | recursive, sq_id); + // passing be_t (test) + sys_lwmutex.Notice("*** lwmutex created [%s] (attribute=0x%x): sq_id = %d", std::string((const char*)&name_u64, 8).c_str(), lwmutex.attribute, sq_id); return CELL_OK; } @@ -32,20 +33,20 @@ s32 sys_lwmutex_create(PPUThread& CPU, vm::ptr lwmutex, vm::ptrrecursive.ToBE()) + switch (attr->recursive.data()) { case se32(SYS_SYNC_RECURSIVE): break; case se32(SYS_SYNC_NOT_RECURSIVE): break; - default: sys_lwmutex.Error("Unknown recursive attribute(0x%x)", (u32)attr->recursive); return CELL_EINVAL; + default: sys_lwmutex.Error("Unknown recursive attribute (0x%x)", attr->recursive); return CELL_EINVAL; } - switch (attr->protocol.ToBE()) + switch (attr->protocol.data()) { case se32(SYS_SYNC_PRIORITY): break; case se32(SYS_SYNC_RETRY): break; - case se32(SYS_SYNC_PRIORITY_INHERIT): sys_lwmutex.Error("Invalid SYS_SYNC_PRIORITY_INHERIT protocol attr"); return CELL_EINVAL; + case se32(SYS_SYNC_PRIORITY_INHERIT): sys_lwmutex.Error("Invalid protocol (SYS_SYNC_PRIORITY_INHERIT)"); return CELL_EINVAL; case se32(SYS_SYNC_FIFO): break; - default: sys_lwmutex.Error("Unknown protocol attribute(0x%x)", (u32)attr->protocol); return CELL_EINVAL; + default: sys_lwmutex.Error("Unknown protocol (0x%x)", attr->protocol); return CELL_EINVAL; } return lwmutex_create(*lwmutex, attr->protocol, attr->recursive, attr->name_u64); @@ -96,7 +97,10 @@ s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr lwmutex) s32 sys_lwmutex_t::trylock(be_t tid) { - if (attribute.ToBE() == se32(0xDEADBEEF)) return CELL_EINVAL; + if (attribute.data() == se32(0xDEADBEEF)) + { + return CELL_EINVAL; + } if (!Emu.GetIdManager().CheckID(sleep_queue)) { @@ -107,10 +111,10 @@ s32 sys_lwmutex_t::trylock(be_t tid) if (old_owner == tid) { - if (attribute.ToBE() & se32(SYS_SYNC_RECURSIVE)) + if (attribute.data() & se32(SYS_SYNC_RECURSIVE)) { auto rv = recursive_count.read_relaxed(); - if (!~(rv++).ToBE()) + if (!~(rv++).data()) { return CELL_EKRESOURCE; } @@ -141,7 +145,7 @@ s32 sys_lwmutex_t::unlock(be_t tid) } auto rv = recursive_count.read_relaxed(); - if (!rv.ToBE() || (rv.ToBE() != se32(1) && (attribute.ToBE() & se32(SYS_SYNC_NOT_RECURSIVE)))) + if (!rv.data() || (rv.data() != se32(1) && (attribute.data() & se32(SYS_SYNC_NOT_RECURSIVE)))) { sys_lwmutex.Error("sys_lwmutex_t::unlock(%d): wrong recursive value fixed (%d)", (u32)sleep_queue, (u32)rv); rv = 1; @@ -149,7 +153,7 @@ s32 sys_lwmutex_t::unlock(be_t tid) rv--; recursive_count.exchange(rv); - if (!rv.ToBE()) + if (!rv.data()) { std::shared_ptr sq; if (!Emu.GetIdManager().GetIDData(sleep_queue, sq)) @@ -187,7 +191,7 @@ s32 sys_lwmutex_t::lock(be_t tid, u64 timeout) while (true) { auto old_owner = owner.compare_and_swap(be_t::make(0), tid); - if (!old_owner.ToBE() || old_owner == tid) + if (!old_owner.data() || old_owner == tid) { break; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp b/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp index 07ca016830..70c40689ba 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp @@ -16,12 +16,12 @@ Mutex::~Mutex() { if (u32 tid = owner.read_sync()) { - sys_mutex.Notice("Mutex(%d) was owned by thread %d (recursive=%d)", id, tid, recursive_count.load()); + sys_mutex.Notice("Mutex(%d) was owned by thread %d (recursive=%d)", id.read_relaxed(), tid, recursive_count.load()); } if (u32 count = queue.count()) { - sys_mutex.Notice("Mutex(%d) was waited by %d threads", id, count); + sys_mutex.Notice("Mutex(%d) was waited by %d threads", id.read_relaxed(), count); } } @@ -29,38 +29,37 @@ s32 sys_mutex_create(PPUThread& CPU, vm::ptr mutex_id, vm::ptrprotocol.ToBE()) + switch (attr->protocol.data()) { case se32(SYS_SYNC_FIFO): break; case se32(SYS_SYNC_PRIORITY): break; - case se32(SYS_SYNC_PRIORITY_INHERIT): sys_mutex.Todo("sys_mutex_create(): SYS_SYNC_PRIORITY_INHERIT"); break; - case se32(SYS_SYNC_RETRY): sys_mutex.Error("sys_mutex_create(): SYS_SYNC_RETRY"); return CELL_EINVAL; - default: sys_mutex.Error("Unknown protocol attribute(0x%x)", (u32)attr->protocol); return CELL_EINVAL; + case se32(SYS_SYNC_PRIORITY_INHERIT): sys_mutex.Todo("SYS_SYNC_PRIORITY_INHERIT"); break; + case se32(SYS_SYNC_RETRY): sys_mutex.Error("Invalid protocol (SYS_SYNC_RETRY)"); return CELL_EINVAL; + default: sys_mutex.Error("Unknown protocol (0x%x)", attr->protocol); return CELL_EINVAL; } bool is_recursive; - switch (attr->recursive.ToBE()) + switch (attr->recursive.data()) { case se32(SYS_SYNC_RECURSIVE): is_recursive = true; break; case se32(SYS_SYNC_NOT_RECURSIVE): is_recursive = false; break; - default: sys_mutex.Error("Unknown recursive attribute(0x%x)", (u32)attr->recursive); return CELL_EINVAL; + default: sys_mutex.Error("Unknown recursive attribute (0x%x)", attr->recursive); return CELL_EINVAL; } - if (attr->pshared.ToBE() != se32(0x200)) + if (attr->pshared.data() != se32(0x200)) { - sys_mutex.Error("Unknown pshared attribute(0x%x)", (u32)attr->pshared); + sys_mutex.Error("Unknown pshared attribute (0x%x)", attr->pshared); return CELL_EINVAL; } - std::shared_ptr mutex(new Mutex((u32)attr->protocol, is_recursive, attr->name_u64)); + std::shared_ptr mutex(new Mutex(attr->protocol, is_recursive, attr->name_u64)); const u32 id = sys_mutex.GetNewId(mutex, TYPE_MUTEX); mutex->id.exchange(id); *mutex_id = id; mutex->queue.set_full_name(fmt::Format("Mutex(%d)", id)); - sys_mutex.Warning("*** mutex created [%s] (protocol=0x%x, recursive=%s): id = %d", - std::string(attr->name, 8).c_str(), (u32) attr->protocol, (is_recursive ? "true" : "false"), id); + sys_mutex.Warning("*** mutex created [%s] (protocol=0x%x, recursive=%s): id = %d", std::string(attr->name, 8).c_str(), attr->protocol, is_recursive, id); // TODO: unlock mutex when owner thread does exit return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp b/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp index bb1b49eead..9a7e1768bc 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp @@ -214,10 +214,9 @@ void sys_ppu_thread_once(PPUThread& CPU, vm::ptr> once_ctrl, vm::p { sys_ppu_thread.Warning("sys_ppu_thread_once(once_ctrl_addr=0x%x, init_addr=0x%x)", once_ctrl.addr(), init.addr()); - be_t cmp = be_t::make(SYS_PPU_THREAD_ONCE_INIT); - if (once_ctrl->compare_and_swap(cmp, be_t::make(SYS_PPU_THREAD_DONE_INIT)) == cmp) + if (once_ctrl->compare_and_swap_test(be_t::make(SYS_PPU_THREAD_ONCE_INIT), be_t::make(SYS_PPU_THREAD_DONE_INIT))) { - init.call(CPU); + init(CPU); } } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_prx.h b/rpcs3/Emu/SysCalls/lv2/sys_prx.h index 2e024c1bde..f0c550ecff 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_prx.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_prx.h @@ -71,7 +71,7 @@ struct sys_prx_module_info_t { be_t attributes; be_t version; - s8 name[28]; + char name[28]; be_t toc; vm::bptr exports_start; vm::bptr exports_end; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_rsx.cpp b/rpcs3/Emu/SysCalls/lv2/sys_rsx.cpp index 21b572a4b4..422a765157 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_rsx.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_rsx.cpp @@ -113,7 +113,7 @@ s32 sys_rsx_context_iounmap(u32 context_id, u32 a2, u32 io_addr, u32 size) */ s32 sys_rsx_context_attribute(s32 context_id, u32 package_id, u64 a3, u64 a4, u64 a5, u64 a6) { - sys_rsx.Todo("sys_rsx_context_attribute(context_id=0x%x, package_id=0x%x, a3=%llu, a4=%llu, a5=%llu, a6=%llu)", + sys_rsx.Todo("sys_rsx_context_attribute(context_id=0x%x, package_id=0x%x, a3=0x%llx, a4=0x%llx, a5=0x%llx, a6=0x%llx)", context_id, package_id, a3, a4, a5, a6); switch(package_id) diff --git a/rpcs3/Emu/SysCalls/lv2/sys_rwlock.cpp b/rpcs3/Emu/SysCalls/lv2/sys_rwlock.cpp index 7190e5dfc0..502132b0e1 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_rwlock.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_rwlock.cpp @@ -15,22 +15,28 @@ s32 sys_rwlock_create(vm::ptr rw_lock_id, vm::ptr a { sys_rwlock.Warning("sys_rwlock_create(rw_lock_id_addr=0x%x, attr_addr=0x%x)", rw_lock_id.addr(), attr.addr()); - switch (attr->protocol.ToBE()) + if (!attr) { - case se32(SYS_SYNC_PRIORITY): break; - case se32(SYS_SYNC_RETRY): sys_rwlock.Error("SYS_SYNC_RETRY"); return CELL_EINVAL; - case se32(SYS_SYNC_PRIORITY_INHERIT): sys_rwlock.Todo("SYS_SYNC_PRIORITY_INHERIT"); break; - case se32(SYS_SYNC_FIFO): break; - default: return CELL_EINVAL; + sys_rwlock.Error("sys_rwlock_create(): null attr address"); + return CELL_EFAULT; } - if (attr->pshared.ToBE() != se32(0x200)) + switch (attr->protocol.data()) { - sys_rwlock.Error("Invalid pshared value (0x%x)", (u32)attr->pshared); + case se32(SYS_SYNC_PRIORITY): break; + case se32(SYS_SYNC_RETRY): sys_rwlock.Error("Invalid protocol (SYS_SYNC_RETRY)"); return CELL_EINVAL; + case se32(SYS_SYNC_PRIORITY_INHERIT): sys_rwlock.Todo("SYS_SYNC_PRIORITY_INHERIT"); break; + case se32(SYS_SYNC_FIFO): break; + default: sys_rwlock.Error("Unknown protocol (0x%x)", attr->protocol); return CELL_EINVAL; + } + + if (attr->pshared.data() != se32(0x200)) + { + sys_rwlock.Error("Unknown pshared attribute (0x%x)", attr->pshared); return CELL_EINVAL; } - std::shared_ptr rw(new RWLock((u32)attr->protocol, attr->name_u64)); + std::shared_ptr rw(new RWLock(attr->protocol, attr->name_u64)); const u32 id = sys_rwlock.GetNewId(rw, TYPE_RWLOCK); *rw_lock_id = id; rw->wqueue.set_full_name(fmt::Format("Rwlock(%d)", id)); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp b/rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp index a5291cc684..350c203dcb 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp @@ -45,20 +45,20 @@ s32 sys_semaphore_create(vm::ptr sem, vm::ptr attr sys_semaphore.Error("sys_semaphore_create(): invalid parameters (initial_count=%d, max_count=%d)", initial_count, max_count); return CELL_EINVAL; } - - if (attr->pshared.ToBE() != se32(0x200)) - { - sys_semaphore.Error("sys_semaphore_create(): invalid pshared value(0x%x)", (u32)attr->pshared); - return CELL_EINVAL; - } - switch (attr->protocol.ToBE()) + switch (attr->protocol.data()) { case se32(SYS_SYNC_FIFO): break; case se32(SYS_SYNC_PRIORITY): break; case se32(SYS_SYNC_PRIORITY_INHERIT): sys_semaphore.Todo("SYS_SYNC_PRIORITY_INHERIT"); break; - case se32(SYS_SYNC_RETRY): sys_semaphore.Error("SYS_SYNC_RETRY"); return CELL_EINVAL; - default: sys_semaphore.Error("Unknown protocol attribute(0x%x)", (u32)attr->protocol); return CELL_EINVAL; + case se32(SYS_SYNC_RETRY): sys_semaphore.Error("Invalid protocol (SYS_SYNC_RETRY)"); return CELL_EINVAL; + default: sys_semaphore.Error("Unknown protocol attribute (0x%x)", attr->protocol); return CELL_EINVAL; + } + + if (attr->pshared.data() != se32(0x200)) + { + sys_semaphore.Error("Unknown pshared attribute (0x%x)", attr->pshared); + return CELL_EINVAL; } *sem = semaphore_create(initial_count, max_count, attr->protocol, attr->name_u64); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_spinlock.cpp b/rpcs3/Emu/SysCalls/lv2/sys_spinlock.cpp index 519cf44069..5ee65096ea 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_spinlock.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_spinlock.cpp @@ -21,9 +21,9 @@ void sys_spinlock_lock(vm::ptr> lock) sys_spinlock.Log("sys_spinlock_lock(lock_addr=0x%x)", lock.addr()); // prx: exchange with 0xabadcafe, repeat until exchanged with 0 - while (lock->exchange(be_t::make(0xabadcafe)).ToBE()) + while (lock->exchange(be_t::make(0xabadcafe)).data()) { - while (lock->read_relaxed().ToBE()) + while (lock->read_relaxed().data()) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack if (Emu.IsStopped()) @@ -45,7 +45,7 @@ s32 sys_spinlock_trylock(vm::ptr> lock) sys_spinlock.Log("sys_spinlock_trylock(lock_addr=0x%x)", lock.addr()); // prx: exchange with 0xabadcafe, translate exchanged value - if (lock->exchange(be_t::make(0xabadcafe)).ToBE()) + if (lock->exchange(be_t::make(0xabadcafe)).data()) { return CELL_EBUSY; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_time.h b/rpcs3/Emu/SysCalls/lv2/sys_time.h index 34d755db8a..dacff931e0 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_time.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_time.h @@ -1,6 +1,9 @@ #pragma once -#define MHZ (1000000) +enum : u32 +{ + MHZ = 1000000, +}; // Auxiliary functions u64 get_time(); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_timer.cpp b/rpcs3/Emu/SysCalls/lv2/sys_timer.cpp index 81af2d8d13..7deb78eeb7 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_timer.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_timer.cpp @@ -41,7 +41,7 @@ s32 sys_timer_get_information(u32 timer_id, vm::ptr inf s32 sys_timer_start(u32 timer_id, s64 base_time, u64 period) { - sys_timer.Warning("sys_timer_start_periodic_absolute(timer_id=%d, basetime=%lld, period=%llu)", timer_id, base_time, period); + sys_timer.Warning("sys_timer_start_periodic_absolute(timer_id=%d, basetime=%lld, period=%lld)", timer_id, base_time, period); std::shared_ptr timer_data = nullptr; if(!sys_timer.CheckId(timer_id, timer_data)) return CELL_ESRCH; @@ -76,7 +76,7 @@ s32 sys_timer_stop(u32 timer_id) s32 sys_timer_connect_event_queue(u32 timer_id, u32 queue_id, u64 name, u64 data1, u64 data2) { - sys_timer.Warning("sys_timer_connect_event_queue(timer_id=%d, queue_id=%d, name=%llu, data1=%llu, data2=%llu)", + sys_timer.Warning("sys_timer_connect_event_queue(timer_id=%d, queue_id=%d, name=0x%llx, data1=0x%llx, data2=0x%llx)", timer_id, queue_id, name, data1, data2); std::shared_ptr timer_data = nullptr; diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 9e9da63152..9944a5860f 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -11,6 +11,7 @@ #include "Emu/Cell/SPUThread.h" #include "Emu/Cell/PPUInstrTable.h" #include "Emu/FS/vfsFile.h" +#include "Emu/FS/vfsLocalFile.h" #include "Emu/FS/vfsDeviceLocalFile.h" #include "Emu/DbgCommand.h" @@ -261,7 +262,7 @@ void Emulator::Load() if (!m_loader.load(f)) { - LOG_ERROR(LOADER, "Loading '%s' failed", m_elf_path.c_str()); + LOG_ERROR(LOADER, "Loading '%s' failed", m_path.c_str()); vm::close(); return; } @@ -327,6 +328,8 @@ void Emulator::Pause() if (InterlockedCompareExchange((volatile u32*)&m_status, Paused, Running) == Running) { SendDbgCommand(DID_PAUSED_EMU); + + GetCallbackManager().RunPauseCallbacks(true); } } @@ -340,6 +343,8 @@ void Emulator::Resume() CheckStatus(); SendDbgCommand(DID_RESUMED_EMU); + + GetCallbackManager().RunPauseCallbacks(false); } void Emulator::Stop() @@ -349,17 +354,13 @@ void Emulator::Stop() SendDbgCommand(DID_STOP_EMU); m_status = Stopped; - u32 uncounted = 0; - while (true) + while (g_thread_count) { - if (g_thread_count <= uncounted) - { - LOG_NOTICE(HLE, "All threads stopped..."); - break; - } std::this_thread::sleep_for(std::chrono::milliseconds(1)); } + LOG_NOTICE(HLE, "All threads stopped..."); + m_rsx_callback = 0; // TODO: check finalization order diff --git a/rpcs3/Gui/AboutDialog.h b/rpcs3/Gui/AboutDialog.h index bee94e9b1a..78584d6d3d 100644 --- a/rpcs3/Gui/AboutDialog.h +++ b/rpcs3/Gui/AboutDialog.h @@ -36,11 +36,7 @@ AboutDialog::AboutDialog(wxWindow *parent) t_descr->SetForegroundColour(wxColor(255,255,255)); t_descr->SetPosition(wxPoint(12,50)); -#ifdef _DEBUG - wxStaticText* t_version = new wxStaticText(this, wxID_ANY, wxString::Format("Version: " _PRGNAME_ " git-" RPCS3_GIT_VERSION)); -#else - wxStaticText* t_version = new wxStaticText(this, wxID_ANY, wxString::Format("Version: " _PRGNAME_ " " _PRGVER_)); -#endif + wxStaticText* t_version = new wxStaticText(this, wxID_ANY, wxString::Format(_PRGNAME_" Version : " RPCS3_GIT_VERSION)); t_version->SetBackgroundColour(wxColor(100,100,100)); t_version->SetForegroundColour(wxColor(200,200,200)); t_version->SetPosition(wxPoint(12,66)); diff --git a/rpcs3/Gui/MainFrame.cpp b/rpcs3/Gui/MainFrame.cpp index 595d207423..975af52f18 100644 --- a/rpcs3/Gui/MainFrame.cpp +++ b/rpcs3/Gui/MainFrame.cpp @@ -70,11 +70,7 @@ MainFrame::MainFrame() , m_sys_menu_opened(false) { -#ifdef _DEBUG - SetLabel(wxString::Format(_PRGNAME_ " git-" RPCS3_GIT_VERSION)); -#else - SetLabel(wxString::Format(_PRGNAME_ " " _PRGVER_)); -#endif + SetLabel(wxString::Format(_PRGNAME_ " " RPCS3_GIT_VERSION)); wxMenuBar* menubar = new wxMenuBar(); @@ -221,7 +217,7 @@ void MainFrame::BootGame(wxCommandEvent& WXUNUSED(event)) } else { - LOG_ERROR(HLE, "PS3 executable not found in selected folder (%s)", ctrl.GetPath().wx_str()); + LOG_ERROR(HLE, "PS3 executable not found in selected folder (%s)", fmt::ToUTF8(ctrl.GetPath())); // passing std::string (test) } } @@ -448,7 +444,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) for(int i = 1; i < WXSIZEOF(ResolutionTable); ++i) { - cbox_gs_resolution->Append(wxString::Format("%dx%d", ResolutionTable[i].width.ToLE(), ResolutionTable[i].height.ToLE())); + cbox_gs_resolution->Append(wxString::Format("%dx%d", ResolutionTable[i].width.value(), ResolutionTable[i].height.value())); } cbox_gs_aspect->Append("4:3"); @@ -474,6 +470,9 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) cbox_audio_out->Append("Null"); cbox_audio_out->Append("OpenAL"); +#if defined (_WIN32) + cbox_audio_out->Append("XAudio2"); +#endif cbox_camera->Append("Null"); diff --git a/rpcs3/Gui/VHDDManager.cpp b/rpcs3/Gui/VHDDManager.cpp index 398c893827..aa818aa7a8 100644 --- a/rpcs3/Gui/VHDDManager.cpp +++ b/rpcs3/Gui/VHDDManager.cpp @@ -190,7 +190,7 @@ void VHDDExplorer::OnDropFiles(wxDropFilesEvent& event) for(int i=0; iSeek(handler::get_stream_offset() + phdr.p_paddr.addr()); m_stream->Read(&module_info, sizeof(module_info)); LOG_ERROR(LOADER, "%s (%x):", module_info.name, (u32)module_info.toc); - info.name = std::string((const char*)module_info.name, 28); + info.name = std::string(module_info.name, 28); info.rtoc = module_info.toc; int import_count = (module_info.imports_end - module_info.imports_start) / sizeof(sys_prx_library_info_t); if (import_count) { - LOG_ERROR(LOADER, "**** Lib '%s'has %d imports!", module_info.name, import_count); + LOG_ERROR(LOADER, "**** Lib '%s' has %d imports!", module_info.name, import_count); } sys_prx_library_info_t lib; @@ -399,14 +399,15 @@ namespace loader { for (auto &phdr : m_phdrs) { - switch (phdr.p_type.ToLE()) + switch (phdr.p_type.value()) { case 0x00000001: //LOAD if (phdr.p_memsz) { if (!vm::alloc(phdr.p_vaddr.addr(), (u32)phdr.p_memsz, vm::main)) { - LOG_ERROR(LOADER, "%s(): AllocFixed(0x%llx, 0x%x) failed", __FUNCTION__, phdr.p_vaddr, (u32)phdr.p_memsz); + // addr() has be_t<> type (test) + LOG_ERROR(LOADER, "%s(): AllocFixed(0x%llx, 0x%x) failed", __FUNCTION__, phdr.p_vaddr.addr(), (u32)phdr.p_memsz); return loading_error; } @@ -441,12 +442,12 @@ namespace loader { sys_process_param_info& info = Emu.GetInfo().GetProcParam(); /* - LOG_NOTICE(LOADER, "*** sdk version: 0x%x", info.sdk_version.ToLE()); - LOG_NOTICE(LOADER, "*** primary prio: %d", info.primary_prio.ToLE()); - LOG_NOTICE(LOADER, "*** primary stacksize: 0x%x", info.primary_stacksize.ToLE()); - LOG_NOTICE(LOADER, "*** malloc pagesize: 0x%x", info.malloc_pagesize.ToLE()); - LOG_NOTICE(LOADER, "*** ppc seg: 0x%x", info.ppc_seg.ToLE()); - //LOG_NOTICE(LOADER, "*** crash dump param addr: 0x%x", info.crash_dump_param_addr.ToLE()); + LOG_NOTICE(LOADER, "*** sdk version: 0x%x", info.sdk_version); + LOG_NOTICE(LOADER, "*** primary prio: %d", info.primary_prio); + LOG_NOTICE(LOADER, "*** primary stacksize: 0x%x", info.primary_stacksize); + LOG_NOTICE(LOADER, "*** malloc pagesize: 0x%x", info.malloc_pagesize); + LOG_NOTICE(LOADER, "*** ppc seg: 0x%x", info.ppc_seg); + //LOG_NOTICE(LOADER, "*** crash dump param addr: 0x%x", info.crash_dump_param_addr); */ info = proc_param.info; @@ -462,7 +463,7 @@ namespace loader if (proc_prx_param.magic != 0x1b434cec) { - LOG_ERROR(LOADER, "Bad magic! (0x%x)", proc_prx_param.magic.ToLE()); + LOG_ERROR(LOADER, "Bad magic! (0x%x)", proc_prx_param.magic); break; } diff --git a/rpcs3/Loader/ELF64.h b/rpcs3/Loader/ELF64.h index b78cd643ed..a3acc0475e 100644 --- a/rpcs3/Loader/ELF64.h +++ b/rpcs3/Loader/ELF64.h @@ -34,7 +34,7 @@ namespace loader be_t e_shnum; be_t e_shstrndx; - bool check() const { return e_magic.ToBE() == se32(0x7F454C46); } + bool check() const { return e_magic.data() == se32(0x7F454C46); } } m_ehdr; struct phdr diff --git a/rpcs3/Loader/Loader.cpp b/rpcs3/Loader/Loader.cpp index e86b1d58e3..debb40f589 100644 --- a/rpcs3/Loader/Loader.cpp +++ b/rpcs3/Loader/Loader.cpp @@ -67,7 +67,7 @@ const std::string Ehdr_OS_ABIToString(const u8 os_abi) case 0x66: return "Cell OS LV-2"; }; - return fmt::Format("Unknown (%x)", os_abi); + return fmt::Format("Unknown (0x%x)", os_abi); } const std::string Ehdr_MachineToString(const u16 machine) @@ -80,7 +80,7 @@ const std::string Ehdr_MachineToString(const u16 machine) case MACHINE_ARM: return "ARM"; }; - return fmt::Format("Unknown (%x)", machine); + return fmt::Format("Unknown (0x%x)", machine); } const std::string Phdr_FlagsToString(u32 flags) @@ -105,7 +105,7 @@ const std::string Phdr_FlagsToString(u32 flags) flags &= ~spu << 0x14; flags &= ~rsx << 0x18; - if(flags != 0) return fmt::Format("Unknown %s PPU[%x] SPU[%x] RSX[%x]", ret.c_str(), ppu, spu, rsx); + if(flags != 0) return fmt::Format("Unknown %s PPU[0x%x] SPU[0x%x] RSX[0x%x]", ret.c_str(), ppu, spu, rsx); ret += "PPU[" + FLAGS_TO_STRING(ppu) + "] "; ret += "SPU[" + FLAGS_TO_STRING(spu) + "] "; @@ -125,5 +125,5 @@ const std::string Phdr_TypeToString(const u32 type) case 0x60000002: return "LOOS+2"; }; - return fmt::Format("Unknown (%x)", type); + return fmt::Format("Unknown (0x%x)", type); } diff --git a/rpcs3/Loader/PKG.cpp b/rpcs3/Loader/PKG.cpp index 71478074d5..022a11085e 100644 --- a/rpcs3/Loader/PKG.cpp +++ b/rpcs3/Loader/PKG.cpp @@ -28,16 +28,13 @@ bool PKGLoader::Install(std::string dest) std::string titleID = std::string(title_id).substr(7, 9); if (rExists(dest + titleID)) { - rMessageDialog d_overwrite(NULL, "Another installation was found. Do you want to overwrite it?", "PKG Decrypter / Installer", rYES_NO|rCENTRE); + rMessageDialog d_overwrite(NULL, "Another installation found. Do you want to overwrite it?", "PKG Decrypter / Installer", rYES_NO|rCENTRE); if (d_overwrite.ShowModal() != rID_YES) { LOG_ERROR(LOADER, "PKG Loader: Another installation found in: %s", titleID.c_str()); return false; } - - rRmdir(dest + titleID); - } - if (!rMkdir(dest + titleID)) { - LOG_ERROR(LOADER, "PKG Loader: Could not make the installation directory: %s", titleID.c_str()); + } else if (!rMkdir(dest + titleID)) { + LOG_ERROR(LOADER, "PKG Loader: Could not create the installation directory: %s", titleID.c_str()); return false; } diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index cf88536f65..ace4e4f654 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -1,10 +1,6 @@  - - Debug - LLVM - Win32 - Debug - LLVM x64 @@ -17,26 +13,14 @@ Debug - MemLeak x64 - - Debug - Win32 - Debug x64 - - Release - LLVM - Win32 - Release - LLVM x64 - - Release - Win32 - Release x64 @@ -58,14 +42,9 @@ - NotUsing NotUsing - NotUsing - NotUsing NotUsing NotUsing - NotUsing - NotUsing NotUsing NotUsing @@ -85,6 +64,7 @@ + @@ -253,14 +233,9 @@ true - Create Create - Create - Create Create Create - Create - Create Create Create @@ -301,6 +276,9 @@ + + + @@ -408,6 +386,7 @@ + @@ -474,24 +453,6 @@ emucore - - StaticLibrary - true - v120 - Unicode - - - StaticLibrary - true - v120 - Unicode - - - StaticLibrary - true - v120 - Unicode - StaticLibrary true @@ -510,20 +471,6 @@ v120 Unicode - - StaticLibrary - false - v120 - false - Unicode - - - StaticLibrary - false - v120 - false - Unicode - StaticLibrary false @@ -541,15 +488,6 @@ - - - - - - - - - @@ -559,12 +497,6 @@ - - - - - - @@ -572,88 +504,36 @@ - - $(SolutionDir)$(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - .\;..\;..\asmjit\src\asmjit;..\wxWidgets\include\msvc;..\wxWidgets\include;.\OpenAL\include;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath); - - - $(SolutionDir)$(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - .\;..\;..\asmjit\src\asmjit;..\wxWidgets\include\msvc;..\wxWidgets\include;.\OpenAL\include;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath); - - - $(SolutionDir)$(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - .\;..\;..\asmjit\src\asmjit;..\wxWidgets\include\msvc;..\wxWidgets\include;.\OpenAL\include;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath); - - - $(SolutionDir)$(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - .\;..\;..\asmjit\src\asmjit;..\wxWidgets\include\msvc;..\wxWidgets\include;.\OpenAL\include;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath); - - - $(SolutionDir)$(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - .\;..\;..\asmjit\src\asmjit;..\wxWidgets\include\msvc;..\wxWidgets\include;.\OpenAL\include;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath); - - .\;..\;..\asmjit\src\asmjit;..\wxWidgets\include\msvc;..\wxWidgets\include;.\OpenAL\include;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);..\llvm\include;..\llvm_build\include + .\;..\;..\minidx9\Include;..\asmjit\src\asmjit;..\wxWidgets\include\msvc;..\wxWidgets\include;.\OpenAL\include;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);..\llvm\include;..\llvm_build\include $(Platform)\$(Configuration)\emucore\ + $(LibraryPath) + $(ExcludePath) - .\;..\;..\asmjit\src\asmjit;..\wxWidgets\include\msvc;..\wxWidgets\include;.\OpenAL\include;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);..\llvm\include;..\llvm_build\include + .\;..\;..\minidx9\Include;..\asmjit\src\asmjit;..\wxWidgets\include\msvc;..\wxWidgets\include;.\OpenAL\include;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);..\llvm\include;..\llvm_build\include $(Platform)\$(Configuration)\emucore\ + $(LibraryPath) + $(ExcludePath) - .\;..\;..\asmjit\src\asmjit;..\wxWidgets\include\msvc;..\wxWidgets\include;.\OpenAL\include;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);..\llvm\include;..\llvm_build\include + .\;..\;..\minidx9\Include;..\asmjit\src\asmjit;..\wxWidgets\include\msvc;..\wxWidgets\include;.\OpenAL\include;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);..\llvm\include;..\llvm_build\include $(Platform)\$(Configuration)\emucore\ + $(LibraryPath) + $(ExcludePath) - .\;..\;..\asmjit\src\asmjit;..\wxWidgets\include\msvc;..\wxWidgets\include;.\OpenAL\include;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);..\llvm\include;..\llvm_build\include + .\;..\;..\minidx9\Include;..\asmjit\src\asmjit;..\wxWidgets\include\msvc;..\wxWidgets\include;.\OpenAL\include;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);..\llvm\include;..\llvm_build\include $(Platform)\$(Configuration)\emucore\ + $(LibraryPath) + $(ExcludePath) - .\;..\;..\asmjit\src\asmjit;..\wxWidgets\include\msvc;..\wxWidgets\include;.\OpenAL\include;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);..\llvm\include;..\llvm_build\include + .\;..\;..\minidx9\Include;..\asmjit\src\asmjit;..\wxWidgets\include\msvc;..\wxWidgets\include;.\OpenAL\include;..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\Include;$(VC_IncludePath);$(WindowsSDK_IncludePath);..\llvm\include;..\llvm_build\include $(Platform)\$(Configuration)\emucore\ + $(LibraryPath) + $(ExcludePath) - - - Level3 - Disabled - false - Use - stdafx.h - - - true - - - - - Level3 - Disabled - false - Use - stdafx.h - - - true - - - - - Level3 - Disabled - false - Use - _UNICODE;UNICODE;MSVC_CRT_MEMLEAK_DETECTION;%(PreprocessorDefinitions) - stdafx.h - - - true - - Level3 @@ -664,6 +544,9 @@ stdafx.h Async true + + + false true @@ -679,6 +562,8 @@ stdafx.h Async true + + true @@ -698,43 +583,13 @@ stdafx.h Async true + + true - - - Level3 - MaxSpeed - true - true - false - Use - stdafx.h - - - true - true - true - - - - - Level3 - MaxSpeed - true - true - false - Use - stdafx.h - - - true - true - true - - Level3 @@ -746,6 +601,8 @@ stdafx.h Async true + + true @@ -765,6 +622,8 @@ Async LLVM_AVAILABLE;%(PreprocessorDefinitions) true + + true diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index ef7327a0bd..b82f10e1a1 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -81,6 +81,12 @@ {6f1da5b2-52c5-416b-9b5c-b9897bc1b300} + + {1eae80f6-5aef-4049-81a0-bbfd7602f8f6} + + + {1d6abf72-0f18-43ec-9351-1fed1a3d1a1e} + @@ -653,6 +659,9 @@ Utilities + + Emu\Audio\XAudio2 + Emu\SysCalls\Modules @@ -1264,5 +1273,17 @@ Utilities + + Emu\Audio\Null + + + Emu\Audio + + + Emu\Audio\XAudio2 + + + Emu\SysCalls\Modules + \ No newline at end of file diff --git a/rpcs3/git-version.cmake b/rpcs3/git-version.cmake new file mode 100644 index 0000000000..3a764c50a4 --- /dev/null +++ b/rpcs3/git-version.cmake @@ -0,0 +1,42 @@ +set(GIT_VERSION_FILE "${SOURCE_DIR}/git-version.h") +set(GIT_VERSION "unknown") +set(GIT_VERSION_UPDATE "1") + +find_package(Git) +if(GIT_FOUND) + execute_process(COMMAND ${GIT_EXECUTABLE} describe --always + WORKING_DIRECTORY ${SOURCE_DIR} + RESULT_VARIABLE exit_code + OUTPUT_VARIABLE GIT_VERSION) + if(NOT ${exit_code} EQUAL 0) + message(WARNING "git describe failed, unable to include version.") + endif() + string(STRIP ${GIT_VERSION} GIT_VERSION) +else() + message(WARNING "git not found, unable to include version.") +endif() + +if(EXISTS ${GIT_VERSION_FILE}) + # Don't update if marked not to update. + file(STRINGS ${GIT_VERSION_FILE} match + REGEX "RPCS3_GIT_VERSION_NO_UPDATE 1") + if(NOT ${match} EQUAL "") + set(GIT_VERSION_UPDATE "0") + endif() + + # Don't update if it's already the same. + file(STRINGS ${GIT_VERSION_FILE} match + REGEX "${GIT_VERSION}") + if(NOT ${match} EQUAL "") + set(GIT_VERSION_UPDATE "0") + endif() +endif() + +set(code_string "// This is a generated file.\n\n" + "#define RPCS3_GIT_VERSION \"${GIT_VERSION}\"\n\n" + "// If you don't want this file to update/recompile, change to 1.\n" + "#define RPCS3_GIT_VERSION_NO_UPDATE 0\n") + +if ("${GIT_VERSION_UPDATE}" EQUAL "1") + file(WRITE ${GIT_VERSION_FILE} ${code_string}) +endif() diff --git a/rpcs3/git-version.h b/rpcs3/git-version.h deleted file mode 100644 index f770897486..0000000000 --- a/rpcs3/git-version.h +++ /dev/null @@ -1,6 +0,0 @@ -// This is a generated file. - -#define RPCS3_GIT_VERSION "unknown" - -// If you don't want this file to update/recompile, change to 1. -#define RPCS3_GIT_VERSION_NO_UPDATE 1 diff --git a/rpcs3/rpcs3.cpp b/rpcs3/rpcs3.cpp index 6eb8cbc46b..d7549972fe 100644 --- a/rpcs3/rpcs3.cpp +++ b/rpcs3/rpcs3.cpp @@ -168,7 +168,7 @@ void compile_shader(std::string path) } CgBinaryProgram& prog = vm::get_ref(ptr); - LOG_ERROR(GENERAL, "%d - %x", (u32)prog.profile, (u32)prog.binaryFormatRevision); + LOG_ERROR(GENERAL, "%d - 0x%x", (u32)prog.profile, (u32)prog.binaryFormatRevision); std::string shader; GLParamArray param_array; diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index 44c219a587..ade3c6121a 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -94,6 +94,7 @@ "$(SolutionDir)\Utilities\git-version-gen.cmd" + Updating git-version.h false @@ -120,6 +121,7 @@ "$(SolutionDir)\Utilities\git-version-gen.cmd" + Updating git-version.h false @@ -156,8 +158,8 @@ ..\wxWidgets\lib\vc_x64_lib;..\ffmpeg\Windows\x86_64\lib;..\OpenAL\Win64 - - + "$(SolutionDir)\Utilities\git-version-gen.cmd" + Updating git-version.h diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters index 71062a8296..e55464ae48 100644 --- a/rpcs3/rpcs3.vcxproj.filters +++ b/rpcs3/rpcs3.vcxproj.filters @@ -194,5 +194,8 @@ Gui + + Gui + \ No newline at end of file diff --git a/rpcs3/stdafx.h b/rpcs3/stdafx.h index 2ca972bc49..825c1c4007 100644 --- a/rpcs3/stdafx.h +++ b/rpcs3/stdafx.h @@ -55,8 +55,8 @@ template __forceinline T align(const T addr, int align) return (addr + (align - 1)) & ~(align - 1); } -#include "Utilities/StrFmt.h" #include "Utilities/BEType.h" +#include "Utilities/StrFmt.h" #define _PRGNAME_ "RPCS3" #define _PRGVER_ "0.0.0.5"