Merge remote-tracking branch 'upstream/master' into spurs_taskset

Conflicts:
	rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp
	rpcs3/Emu/SysCalls/Modules/cellSpurs.h
	rpcs3/emucore.vcxproj.filters
This commit is contained in:
S Gopal Rajagopal 2015-01-21 01:13:53 +05:30
commit 411dfd9a3f
141 changed files with 6731 additions and 3936 deletions

3
.gitmodules vendored
View file

@ -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

View file

@ -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

View file

@ -2,6 +2,10 @@ RPCS3
=====
[![Build Status](https://travis-ci.org/DHrpcs3/rpcs3.svg?branch=master)](https://travis-ci.org/DHrpcs3/rpcs3)
<a href="https://scan.coverity.com/projects/3960">
<img alt="Coverity Scan Build Status"
src="https://scan.coverity.com/projects/3960/badge.svg"/>
</a>
An open-source PlayStation 3 emulator/debugger written in C++.

View file

@ -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<typename T, int size = sizeof(T)> struct se_t;
template<typename T> struct se_t<T, 1>
{
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<typename T> struct se_t<T, 2>
{
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<typename T> struct se_t<T, 4>
{
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<typename T> struct se_t<T, 8>
{
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<typename T> T re(const T val) { T res; se_t<T>::func(res, val); return res; }
//template<typename T1, typename T2> void re(T1& dst, const T2 val) { se_t<T1>::func(dst, val); }
template<typename T, u64 _value, int size = sizeof(T)> struct const_se_t;
template<typename T, u64 _value> struct const_se_t<T, _value, 1>
template<typename T> struct se_t<T, 16>
{
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<typename T, u64 _value> struct const_se_t<T, _value, 2>
template<typename T, T _value, size_t size = sizeof(T)> struct const_se_t;
template<u8 _value> struct const_se_t<u8, _value, 1>
{
static const T value = ((_value >> 8) & 0xff) | ((_value << 8) & 0xff00);
static const u8 value = _value;
};
template<typename T, u64 _value> struct const_se_t<T, _value, 4>
template<u16 _value> struct const_se_t<u16, _value, 2>
{
static const T value =
static const u16 value = ((_value >> 8) & 0xff) | ((_value << 8) & 0xff00);
};
template<u32 _value> struct const_se_t<u32, _value, 4>
{
static const u32 value =
((_value >> 24) & 0x000000ff) |
((_value >> 8) & 0x0000ff00) |
((_value << 8) & 0x00ff0000) |
((_value << 24) & 0xff000000);
};
template<typename T, u64 _value> struct const_se_t<T, _value, 8>
template<u64 _value> struct const_se_t<u64, _value, 8>
{
static const T value =
static const u64 value =
((_value >> 56) & 0x00000000000000ff) |
((_value >> 40) & 0x000000000000ff00) |
((_value >> 24) & 0x0000000000ff0000) |
@ -447,17 +473,53 @@ template<typename T, u64 _value> struct const_se_t<T, _value, 8>
((_value << 56) & 0xff00000000000000);
};
template<typename T, size_t size = sizeof(T)>
struct be_storage_t
{
static_assert(!size, "Bad be_storage_t type");
};
template<typename T>
struct be_storage_t<T, 1>
{
typedef u8 type;
};
template<typename T>
struct be_storage_t<T, 2>
{
typedef u16 type;
};
template<typename T>
struct be_storage_t<T, 4>
{
typedef u32 type;
};
template<typename T>
struct be_storage_t<T, 8>
{
typedef u64 type;
};
template<typename T>
struct be_storage_t<T, 16>
{
typedef u128 type;
};
#define IS_LE_MACHINE
template<typename T, typename T2 = T>
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<T>::type type;
static const bool is_le_machine = true;
typedef typename be_storage_t<T2>::type stype;
private:
type m_data;
stype m_data;
template<typename Tto, typename Tfrom, int mode>
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<type, sizeof(T2)>::func(m_data);
return se_t<type, sizeof(T2)>::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<type, sizeof(T2)>::func(value);
m_data = se_t<type, sizeof(T2)>::to_be(value);
}
static be_t MakeFromLE(const type value)
public:
static be_t MakeFromLE(const type& value)
{
type data = se_t<type, sizeof(T2)>::func(value);
stype data = se_t<type, sizeof(T2)>::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<type, sizeof(T2)>::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<type, sizeof(T2)>::func(value);
m_data = se_t<type, sizeof(T2)>::to_be(value);
return *this;
}
@ -691,86 +758,86 @@ template<typename T, typename T1, T1 value> struct _se<be_t<T>, T1, value> : pub
#define se32(x) _se<u32, decltype(x), x>::value
#define se64(x) _se<u64, decltype(x), x>::value
template<typename T> __forceinline static u8 Read8(T& f)
template<typename T> __forceinline u8 Read8(T& f)
{
u8 ret;
f.Read(&ret, sizeof(ret));
return ret;
}
template<typename T> __forceinline static u16 Read16(T& f)
template<typename T> __forceinline u16 Read16(T& f)
{
be_t<u16> ret;
f.Read(&ret, sizeof(ret));
return ret;
}
template<typename T> __forceinline static u32 Read32(T& f)
template<typename T> __forceinline u32 Read32(T& f)
{
be_t<u32> ret;
f.Read(&ret, sizeof(ret));
return ret;
}
template<typename T> __forceinline static u64 Read64(T& f)
template<typename T> __forceinline u64 Read64(T& f)
{
be_t<u64> ret;
f.Read(&ret, sizeof(ret));
return ret;
}
template<typename T> __forceinline static u16 Read16LE(T& f)
template<typename T> __forceinline u16 Read16LE(T& f)
{
u16 ret;
f.Read(&ret, sizeof(ret));
return ret;
}
template<typename T> __forceinline static u32 Read32LE(T& f)
template<typename T> __forceinline u32 Read32LE(T& f)
{
u32 ret;
f.Read(&ret, sizeof(ret));
return ret;
}
template<typename T> __forceinline static u64 Read64LE(T& f)
template<typename T> __forceinline u64 Read64LE(T& f)
{
u64 ret;
f.Read(&ret, sizeof(ret));
return ret;
}
template<typename T> __forceinline static void Write8(T& f, const u8 data)
template<typename T> __forceinline void Write8(T& f, const u8 data)
{
f.Write(&data, sizeof(data));
}
template<typename T> __forceinline static void Write16LE(T& f, const u16 data)
template<typename T> __forceinline void Write16LE(T& f, const u16 data)
{
f.Write(&data, sizeof(data));
}
template<typename T> __forceinline static void Write32LE(T& f, const u32 data)
template<typename T> __forceinline void Write32LE(T& f, const u32 data)
{
f.Write(&data, sizeof(data));
}
template<typename T> __forceinline static void Write64LE(T& f, const u64 data)
template<typename T> __forceinline void Write64LE(T& f, const u64 data)
{
f.Write(&data, sizeof(data));
}
template<typename T> __forceinline static void Write16(T& f, const u16 data)
template<typename T> __forceinline void Write16(T& f, const u16 data)
{
Write16LE(f, re16(data));
}
template<typename T> __forceinline static void Write32(T& f, const u32 data)
template<typename T> __forceinline void Write32(T& f, const u32 data)
{
Write32LE(f, re32(data));
}
template<typename T> __forceinline static void Write64(T& f, const u64 data)
template<typename T> __forceinline void Write64(T& f, const u64 data)
{
Write64LE(f, re64(data));
}

View file

@ -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
}

View file

@ -235,3 +235,17 @@ LogChannel &LogManager::getChannel(LogType type)
{
return mChannels[static_cast<u32>(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);
}

View file

@ -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<typename T, typename ...Ts>
inline void log_message(Log::LogType type, Log::LogSeverity sev, const char* text, T arg, Ts... args)
template<typename... Targs>
__noinline void log_message(Log::LogType type, Log::LogSeverity sev, const char* fmt, Targs... args)
{
Log::LogMessage msg{type, sev, fmt::Format(text, arg, args...)};
Log::LogManager::getInstance().log(msg);
log_message(type, sev, fmt::detail::format(fmt, strlen(fmt), fmt::do_unveil(args)...));
}

View file

@ -1,7 +1,160 @@
#include "stdafx.h"
#include "StrFmt.h"
#include <wx/string.h>
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<u64>(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)

View file

@ -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 <typename T>
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<typename T>
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<typename ... Args>
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<empty_t> { 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<typename ... Args>
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<typename T>
struct get_fmt
{
static_assert(!sizeof(T), "Unsupported fmt::format argument");
};
template<>
struct get_fmt<u8>
{
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<u16>
{
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<u32>
{
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<u64>
{
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<s8>
{
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<s16>
{
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<s32>
{
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<s64>
{
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<float>
{
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<double>
{
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<bool>
{
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<char*>
{
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<const char*>
{
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<size_t size>
//struct get_fmt<char[size], false>
//{
// 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<size_t size>
//struct get_fmt<const char[size], false>
//{
// 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<std::string>
{
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<typename T, typename... Args>
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<T>::text(fmt + fmt_start, fmt_len, arg) + format(fmt + fmt_end, len - fmt_end, args...);
}
};
template<typename T, bool is_enum = std::is_enum<T>::value>
struct unveil
{
typedef T result_type;
__forceinline static result_type get_value(const T& arg)
{
return arg;
}
};
template<size_t N>
struct unveil<const char[N], false>
{
typedef const char* result_type;
__forceinline static result_type get_value(const char(&arg)[N])
{
return arg;
}
};
template<>
struct unveil<std::string, false>
{
typedef const std::string& result_type;
__forceinline static result_type get_value(const std::string& arg)
{
return arg;
}
};
template<typename T>
struct unveil<T, true>
{
typedef typename std::underlying_type<T>::type result_type;
__forceinline static result_type get_value(const T& arg)
{
return static_cast<result_type>(arg);
}
};
template<typename T, typename T2>
struct unveil<be_t<T, T2>, false>
{
typedef typename unveil<T>::result_type result_type;
__forceinline static result_type get_value(const be_t<T, T2>& arg)
{
return unveil<T>::get_value(arg.value());
}
};
template<typename T>
__forceinline typename unveil<T>::result_type do_unveil(const T& arg)
{
return unveil<T>::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<typename... Args>
__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

View file

@ -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 <windows.h>
#else
#include <signal.h>
#include <ucontext.h>
#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<u32> 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<void()> func) : m_name(name)
thread_t::thread_t(const std::string& name, bool autojoin, std::function<void()> 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<void()> 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<void()> 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<void()> 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<void()> func)
LOG_ERROR(GENERAL, "%s: %s", name.c_str(), e.c_str());
}
SetCurrentNamedThread(nullptr);
g_thread_count--;
});
if (Emu.IsStopped())
{
LOG_NOTICE(HLE, name + " aborted");
}
else if (Ini.HLELogging.GetValue())
{
LOG_NOTICE(HLE, name + " ended");
}
void thread::detach()
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_t::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()
{
if (m_state.exchange(TS_NON_EXISTENT) == TS_JOINABLE)
{
m_thr.join();
}
bool thread::joinable() const
else
{
return m_thr.joinable();
assert(!"thread_t::join() failed"); // probably joined or detached
}
}
bool thread_t::joinable() const
{
//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<bool()> SQUEUE_ALWAYS_EXIT = [](){ return true; };
const std::function<bool()> SQUEUE_NEVER_EXIT = [](){ return false; };
bool squeue_test_exit()
{
return Emu.IsStopped() || (do_exit && *do_exit);
return Emu.IsStopped();
}

View file

@ -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<thread_state_t> m_state;
std::string m_name;
std::thread m_thr;
bool m_autojoin;
public:
thread(const std::string& name, std::function<void()> func);
thread(const std::string& name);
thread();
thread_t(const std::string& name, bool autojoin, std::function<void()> func);
thread_t(const std::string& name, std::function<void()> 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<void()> 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<bool()> SQUEUE_ALWAYS_EXIT;
extern const std::function<bool()> SQUEUE_NEVER_EXIT;
bool squeue_test_exit();
template<typename T, u32 sq_size = 256>
class squeue_t
@ -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<bool()>& 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<bool()>& 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<bool()>& test_exit)
{
assert(start_pos < sq_size);
u32 pos = 0;
@ -338,7 +373,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;
}
@ -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

View file

@ -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;

1
minidx9 Submodule

@ -0,0 +1 @@
Subproject commit ec19e643461c84dbb256f6faaaab02cba61d4edc

View file

@ -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.")

View file

@ -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).

View file

@ -158,13 +158,13 @@ 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:
@ -172,7 +172,14 @@ bool UnpackEntry(rFile& dec_pkg_f, const PKGEntry& entry, std::string dir)
case PKG_FILE_ENTRY_REGULAR:
{
rFile out;
out.Create(dir + std::string(reinterpret_cast<char *>(buf), entry.name_size));
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 */))
{
dec_pkg_f.Seek(entry.file_offset);
for (u64 size = 0; size < entry.file_size;) {
@ -183,16 +190,35 @@ 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<char *>(buf), entry.name_size));
break;
{
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)
{
PKGHeader* m_header = (PKGHeader*) malloc (sizeof(PKGHeader));

View file

@ -1,5 +1,4 @@
#pragma once
#include "Emu/CPU/CPUThread.h"
#include "Emu/Memory/Memory.h"
@ -210,3 +209,131 @@ public:
return *this;
}
};
template<typename T, bool is_enum = std::is_enum<T>::value>
struct cast_armv7_gpr
{
static_assert(is_enum, "Invalid type for cast_armv7_gpr");
typedef typename std::underlying_type<T>::type underlying_type;
__forceinline static u32 to_gpr(const T& value)
{
return cast_armv7_gpr<underlying_type>::to_gpr(static_cast<underlying_type>(value));
}
__forceinline static T from_gpr(const u32 reg)
{
return static_cast<T>(cast_armv7_gpr<underlying_type>::from_gpr(reg));
}
};
template<>
struct cast_armv7_gpr<u8, false>
{
__forceinline static u32 to_gpr(const u8& value)
{
return value;
}
__forceinline static u8 from_gpr(const u32 reg)
{
return static_cast<u8>(reg);
}
};
template<>
struct cast_armv7_gpr<u16, false>
{
__forceinline static u32 to_gpr(const u16& value)
{
return value;
}
__forceinline static u16 from_gpr(const u32 reg)
{
return static_cast<u16>(reg);
}
};
template<>
struct cast_armv7_gpr<u32, false>
{
__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<s8, false>
{
__forceinline static u32 to_gpr(const s8& value)
{
return value;
}
__forceinline static s8 from_gpr(const u32 reg)
{
return static_cast<s8>(reg);
}
};
template<>
struct cast_armv7_gpr<s16, false>
{
__forceinline static u32 to_gpr(const s16& value)
{
return value;
}
__forceinline static s16 from_gpr(const u32 reg)
{
return static_cast<s16>(reg);
}
};
template<>
struct cast_armv7_gpr<s32, false>
{
__forceinline static u32 to_gpr(const s32& value)
{
return value;
}
__forceinline static s32 from_gpr(const u32 reg)
{
return static_cast<s32>(reg);
}
};
template<>
struct cast_armv7_gpr<bool, false>
{
__forceinline static u32 to_gpr(const bool& value)
{
return value;
}
__forceinline static bool from_gpr(const u32 reg)
{
return reinterpret_cast<const bool&>(reg);
}
};
template<typename T>
__forceinline u32 cast_to_armv7_gpr(const T& value)
{
return cast_armv7_gpr<T>::to_gpr(value);
}
template<typename T>
__forceinline T cast_from_armv7_gpr(const u32 reg)
{
return cast_armv7_gpr<T>::from_gpr(reg);
}

View file

@ -95,20 +95,18 @@ s32 sceKernelCreateThread(
s32 cpuAffinityMask,
vm::psv::ptr<const SceKernelThreadOptParam> 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<ARMv7Thread&>(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<const void> 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<CPUThread> t = Emu.GetCPU().GetThread(threadId);
@ -128,15 +126,17 @@ s32 sceKernelStartThread(s32 threadId, u32 argSize, vm::psv::ptr<const void> pAr
RETURN_ERROR(SCE_KERNEL_ERROR_INVALID_UID);
}
ARMv7Thread& thread = static_cast<ARMv7Thread&>(*t);
// push arg block onto the stack
u32 pos = (static_cast<ARMv7Thread*>(t.get())->SP -= argSize);
const u32 pos = (thread.SP -= argSize);
memcpy(vm::get_ptr<void>(pos), pArgBlock.get_ptr(), argSize);
// set SceKernelThreadEntry function arguments
static_cast<ARMv7Thread*>(t.get())->write_gpr(0, argSize);
static_cast<ARMv7Thread*>(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<s32> 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<SceKernelThreadInfo> 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<SceKernelThreadRunStatus> 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<SceKernelSystemInfo> 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<s32> pExitStatus, vm::psv::ptr<u32> 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<s32> pExitStatus, vm::psv::ptr<u32> 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;
}

View file

@ -26,9 +26,9 @@ namespace sce_libc_func
});
}
void printf(vm::psv::ptr<const char> fmt)
void printf(vm::psv::ptr<const char> 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<void> dst, vm::psv::ptr<const void> 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<const char> text, vm::psv::ptr<const char> 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();

View file

@ -1,4 +1,5 @@
#include "stdafx.h"
#include <unordered_map>
#include "Utilities/Log.h"
#include "Emu/System.h"
#include "PSVFuncList.h"
@ -7,29 +8,19 @@ std::vector<psv_func> 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>([]() -> 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<void, ARMv7Thread&>([](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<void, ARMv7Thread&>([](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<void, ARMv7Thread&>([](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;
}
@ -62,7 +53,12 @@ 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;

View file

@ -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<T>(CPU.GPR[g_count - 1]);
}
};
@ -444,7 +444,7 @@ namespace psv_func_detail
struct bind_arg<T, ARG_VECTOR, g_count, f_count, v_count>
{
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<T, u128>::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<T>(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<T>(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<typename T>
//struct bind_result<T, ARG_VECTOR>
//{
// static_assert(sizeof(T) == 16, "Invalid function result type for ARG_VECTOR");
// static_assert(std::is_same<T, u128>::value, "Invalid function result type for ARG_VECTOR");
// static __forceinline void func(ARMv7Thread& CPU, const T result)
// static __forceinline void func(ARMv7Thread& CPU, const T& result)
// {
// }
//};
@ -518,21 +519,21 @@ namespace psv_func_detail
};
template <typename RT, typename F, typename Tuple>
static __forceinline RT call(F f, Tuple && t)
__forceinline RT call(F f, Tuple && t)
{
typedef typename std::decay<Tuple>::type ttype;
return psv_func_detail::call_impl<RT, F, Tuple, 0 == std::tuple_size<ttype>::value, std::tuple_size<ttype>::value>::call(f, std::forward<Tuple>(t));
}
template<int g_count, int f_count, int v_count>
static __forceinline std::tuple<> iterate(ARMv7Thread& CPU)
__forceinline std::tuple<> iterate(ARMv7Thread& CPU)
{
// terminator
return std::tuple<>();
}
template<int g_count, int f_count, int v_count, typename T, typename... A>
static __forceinline std::tuple<T, A...> iterate(ARMv7Thread& CPU)
__forceinline std::tuple<T, A...> iterate(ARMv7Thread& CPU)
{
static_assert(!std::is_pointer<T>::value, "Invalid function argument type (pointer)");
static_assert(!std::is_reference<T>::value, "Invalid function argument type (reference)");
@ -549,6 +550,16 @@ namespace psv_func_detail
return std::tuple_cat(std::tuple<T>(bind_arg<T, t, g, f, v>::func(CPU)), iterate<g, f, v, A...>(CPU));
}
template<typename RT>
struct result_type
{
static_assert(!std::is_pointer<RT>::value, "Invalid function result type (pointer)");
static_assert(!std::is_reference<RT>::value, "Invalid function result type (reference)");
static const bool is_float = std::is_floating_point<RT>::value;
static const bool is_vector = std::is_same<RT, u128>::value;
static const bind_arg_type value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL);
};
template<typename RT, typename... T>
class func_binder;
@ -605,13 +616,7 @@ namespace psv_func_detail
virtual void operator()(ARMv7Thread& CPU)
{
static_assert(!std::is_pointer<RT>::value, "Invalid function result type (pointer)");
static_assert(!std::is_reference<RT>::value, "Invalid function result type (reference)");
const bool is_float = std::is_floating_point<RT>::value;
const bool is_vector = std::is_same<RT, u128>::value;
const bind_arg_type t = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL);
bind_result<RT, t>::func(CPU, call<RT>(m_call, iterate<0, 0, 0, T...>(CPU)));
bind_result<RT, result_type<RT>::value>::func(CPU, call<RT>(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<RT>::value, "Invalid function result type (pointer)");
static_assert(!std::is_reference<RT>::value, "Invalid function result type (reference)");
const bool is_float = std::is_floating_point<RT>::value;
const bool is_vector = std::is_same<RT, u128>::value;
const bind_arg_type t = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL);
bind_result<RT, t>::func(CPU, call<RT>(m_call, std::tuple_cat(std::tuple<ARMv7Thread&>(CPU), iterate<0, 0, 0, T...>(CPU))));
bind_result<RT, result_type<RT>::value>::func(CPU, call<RT>(m_call, std::tuple_cat(std::tuple<ARMv7Thread&>(CPU), iterate<0, 0, 0, T...>(CPU))));
}
};
}

View file

@ -11,8 +11,6 @@ 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)
@ -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");
@ -102,7 +100,8 @@ void OpenALThread::Open(const void* src, ALsizei size)
for (uint i = 0; i<g_al_buffers_count; ++i)
{
AddBlock(m_buffers[i], m_buffer_size, src);
alBufferData(m_buffers[i], Ini.AudioConvertToU16.GetValue() ? AL_FORMAT_71CHN16 : AL_FORMAT_71CHN32, src, m_buffer_size, 48000);
checkForAlError("alBufferData");
}
alSourceQueueBuffers(m_source, g_al_buffers_count, m_buffers);
@ -110,7 +109,7 @@ void OpenALThread::Open(const void* src, ALsizei size)
Play();
}
void OpenALThread::AddData(const void* src, ALsizei size)
void OpenALThread::AddData(const void* src, int size)
{
const char* bsrc = (const char*)src;
ALuint buffer;
@ -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");
@ -147,13 +147,3 @@ 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;
}

View file

@ -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);
};

View file

@ -1,23 +1,33 @@
#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()
{
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;
}
return size;
}
void AudioDumper::Finalize()
{
if (m_init)
{
m_output.Seek(0);
m_output.Write(&m_header, sizeof(m_header)); // write fixed file header
m_output.Close();
}
}

View file

@ -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; }
};

View file

@ -1,10 +1,11 @@
#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)
{
}
@ -17,8 +18,11 @@ void AudioManager::Init()
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
}
}

View file

@ -1,6 +1,6 @@
#pragma once
#include "sysutil_audio.h"
#include "AL/OpenALThread.h"
#include "AudioThread.h"
struct 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;

View file

@ -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;
};

View file

@ -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) {}
};

View file

@ -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

View file

@ -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 <xaudio2.h>
#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

View file

@ -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:

View file

@ -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)
void CPUThread::Task()
{
const u64 addr = (u64)pExp->ExceptionRecord->ExceptionInformation[1] - (u64)Memory.GetBaseAddr();
CPUThread* t = GetCurrentCPUThread();
if (u == EXCEPTION_ACCESS_VIOLATION && addr < 0x100000000 && t)
auto get_syscall_name = [this](u64 syscall) -> std::string
{
// 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());
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
{
// some fatal error (should crash)
return;
return{};
}
}
#else
// TODO: linux version
#endif
void CPUThread::Task()
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<u64>& bp = Emu.GetBreakPoints();
@ -292,12 +336,6 @@ void CPUThread::Task()
std::vector<u32> 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());

View file

@ -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; };

View file

@ -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());

10
rpcs3/Emu/Cell/Common.h Normal file
View file

@ -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,
};

View file

@ -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:

View file

@ -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);

View file

@ -226,6 +226,9 @@ namespace PPU_instr
#define bind_instr(list, name, ...) \
static const auto& name = make_instr<PPU_opcodes::name>(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<PPU_opcodes::name##O>(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);

File diff suppressed because it is too large Load diff

View file

@ -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<u64>("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() {

View file

@ -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();

View file

@ -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;

View file

@ -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)

View file

@ -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,21 +530,13 @@ 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 cycle;
u64 R_ADDR; // reservation address
@ -652,7 +643,7 @@ public:
UpdateCRn<T>(0, val, 0);
}
template<typename T> 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)
@ -812,3 +830,159 @@ public:
cpu_thread& run() override;
ppu_thread& gpr(uint index, u64 value);
};
template<typename T, bool is_enum = std::is_enum<T>::value>
struct cast_ppu_gpr
{
static_assert(is_enum, "Invalid type for cast_ppu_gpr");
typedef typename std::underlying_type<T>::type underlying_type;
__forceinline static u64 to_gpr(const T& value)
{
return cast_ppu_gpr<underlying_type>::to_gpr(static_cast<underlying_type>(value));
}
__forceinline static T from_gpr(const u64 reg)
{
return static_cast<T>(cast_ppu_gpr<underlying_type>::from_gpr(reg));
}
};
template<>
struct cast_ppu_gpr<u8, false>
{
__forceinline static u64 to_gpr(const u8& value)
{
return value;
}
__forceinline static u8 from_gpr(const u64 reg)
{
return static_cast<u8>(reg);
}
};
template<>
struct cast_ppu_gpr<u16, false>
{
__forceinline static u64 to_gpr(const u16& value)
{
return value;
}
__forceinline static u16 from_gpr(const u64 reg)
{
return static_cast<u16>(reg);
}
};
template<>
struct cast_ppu_gpr<u32, false>
{
__forceinline static u64 to_gpr(const u32& value)
{
return value;
}
__forceinline static u32 from_gpr(const u64 reg)
{
return static_cast<u32>(reg);
}
};
template<>
struct cast_ppu_gpr<u64, false>
{
__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<s8, false>
{
__forceinline static u64 to_gpr(const s8& value)
{
return value;
}
__forceinline static s8 from_gpr(const u64 reg)
{
return static_cast<s8>(reg);
}
};
template<>
struct cast_ppu_gpr<s16, false>
{
__forceinline static u64 to_gpr(const s16& value)
{
return value;
}
__forceinline static s16 from_gpr(const u64 reg)
{
return static_cast<s16>(reg);
}
};
template<>
struct cast_ppu_gpr<s32, false>
{
__forceinline static u64 to_gpr(const s32& value)
{
return value;
}
__forceinline static s32 from_gpr(const u64 reg)
{
return static_cast<s32>(reg);
}
};
template<>
struct cast_ppu_gpr<s64, false>
{
__forceinline static u64 to_gpr(const s64& value)
{
return value;
}
__forceinline static s64 from_gpr(const u64 reg)
{
return static_cast<s64>(reg);
}
};
template<>
struct cast_ppu_gpr<bool, false>
{
__forceinline static u64 to_gpr(const bool& value)
{
return value;
}
__forceinline static bool from_gpr(const u64 reg)
{
return reinterpret_cast<const bool&>(reg);
}
};
template<typename T>
__forceinline u64 cast_to_ppu_gpr(const T& value)
{
return cast_ppu_gpr<T>::to_gpr(value);
}
template<typename T>
__forceinline T cast_from_ppu_gpr(const u64 reg)
{
return cast_ppu_gpr<T>::from_gpr(reg);
}

View file

@ -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"
@ -136,9 +138,15 @@ bool RawSPUThread::Write32(const u64 addr, const u32 value)
case SPU_RunCntl_offs:
{
if (value == SPU_RUNCNTL_RUNNABLE)
{
// 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)
{

View file

@ -1,5 +1,26 @@
#pragma once
#include <fenv.h>
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)
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))
{
for (int w = 0; w < 4; w++)
CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SDIFF);
if (b == 0.0f || isdenormal(b))
result = +0.0f;
else
result = b;
}
else if (isdenormal(b))
{
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;
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)
for (int i = 0; i < 2; i++)
{
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)
double a = CPU.GPR[ra]._d[i];
double b = CPU.GPR[rb]._d[i];
if (isdenormal(a))
{
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];
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)
for (int i = 0; i < 2; i++)
{
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)
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.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];
CPU.FPSCR.setDoublePrecisionExceptionFlags(i, FPSCR_DDENORM);
a = copysign(0.0, a);
}
void DFNMA(u32 rt, u32 ra, u32 rb)
if (isdenormal(b))
{
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]);
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;
scaled = ldexpf(a, scale);
u32 result;
if (scaled >= 4294967296.0f)
result = 0xFFFFFFFF;
else if (scaled < 0.0f)
result = 0;
else
CPU.GPR[rt]._u32[i] = (u32)floor(CPU.GPR[rt]._f[i]);
}
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;
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;
}
}
void FMA(u32 rt, u32 ra, u32 rb, u32 rc)
else
{
for (int w = 0; w < 4; w++)
result = fmaf(new_a, new_b, ldexpf_extended(c, -2));
}
if (fabsf(result) >= ldexpf(1.0f, 127))
{
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;
CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SOVF);
result = extended(sign, 0x7FFFFF);
}
else
{
result = ldexpf_extended(result, 2);
}
}
void FMS(u32 rt, u32 ra, u32 rb, u32 rc)
}
else if (isextended(c))
{
for (int w = 0; w < 4; w++)
CPU.FPSCR.setSinglePrecisionExceptionFlags(w, FPSCR_SDIFF);
if (a == 0.0f || b == 0.0f)
{
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;
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;
}
}

View file

@ -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();

View file

@ -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<list_element>::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<u32>(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())

View file

@ -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

View file

@ -10,7 +10,8 @@
std::vector<std::string> simplify_path_blocks(const std::string& path)
{
std::vector<std::string> path_blocks = std::move(fmt::split(fmt::tolower(path), { "/", "\\" }));
// fmt::tolower() removed
std::vector<std::string> path_blocks = std::move(fmt::split(path, { "/", "\\" }));
for (size_t i = 0; i < path_blocks.size(); ++i)
{
@ -28,7 +29,7 @@ std::vector<std::string> 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<std::string> path_blocks = simplify_path_blocks(path);
@ -37,7 +38,16 @@ std::string simplify_path(const std::string& path, bool is_dir)
std::string result = fmt::merge(path_blocks, "/");
return is_dir ? result + "/" : result;
#ifdef _WIN32
if (is_ps3)
#endif
{
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,20 +330,23 @@ 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 (auto res = try_get_device(GetLinked(cwd + ps3_path)))
return res;
if (!ps3_path.size() || ps3_path[0] != '/')
{
return nullptr;
}
return try_get_device(GetLinked(ps3_path));
// 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
{
size_t max_eq = 0;
@ -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();

View file

@ -44,7 +44,7 @@ struct VFSManagerEntry
};
std::vector<std::string> 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;

View file

@ -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());

View file

@ -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;
}

View file

@ -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)

View file

@ -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()
{

View file

@ -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<PPUThread&>(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<PPUThread&>(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;
}
}
}
}

View file

@ -1,6 +1,8 @@
#pragma once
#include "Memory.h"
class CPUThread;
namespace vm
{
enum memory_location : uint
@ -29,7 +31,7 @@ namespace vm
template<typename T = void>
T* const get_ptr(u32 addr)
{
return (T*)((u8*)g_base_addr + addr);
return reinterpret_cast<T*>(static_cast<u8*>(g_base_addr) + addr);
}
template<typename T>
@ -38,56 +40,100 @@ namespace vm
return *get_ptr<T>(addr);
}
u32 get_addr(const void* real_pointer);
template<typename T>
struct cast_ptr
{
static_assert(std::is_same<T, u32>::value, "Unsupported vm::cast() type");
__forceinline static u32 cast(const T& addr, const char* func)
{
return 0;
}
};
template<>
struct cast_ptr<u32>
{
__forceinline static u32 cast(const u32 addr, const char* func)
{
return addr;
}
};
template<>
struct cast_ptr<u64>
{
__forceinline static u32 cast(const u64 addr, const char* func)
{
const u32 res = static_cast<u32>(addr);
if (res != addr)
{
throw fmt::Format("%s(): invalid address 0x%llx", func, addr);
}
return res;
}
};
template<typename T, typename T2>
struct cast_ptr<be_t<T, T2>>
{
__forceinline static u32 cast(const be_t<T, T2>& addr, const char* func)
{
return cast_ptr<T>::cast(addr.value(), func);
}
};
template<typename T>
__forceinline static u32 cast(const T& addr, const char* func = "vm::cast")
{
return cast_ptr<T>::cast(addr, func);
}
namespace ps3
{
void init();
static u8 read8(u32 addr)
{
return *((u8*)g_base_addr + addr);
return get_ref<u8>(addr);
}
static void write8(u32 addr, u8 value)
{
*((u8*)g_base_addr + addr) = value;
get_ref<u8>(addr) = value;
}
static u16 read16(u32 addr)
{
return re16(*(u16*)((u8*)g_base_addr + addr));
return get_ref<be_t<u16>>(addr);
}
static void write16(u32 addr, be_t<u16> value)
{
*(be_t<u16>*)((u8*)g_base_addr + addr) = value;
get_ref<be_t<u16>>(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<be_t<u32>>(addr);
}
static void write32(u32 addr, be_t<u32> value)
{
if (addr < RAW_SPU_BASE_ADDR || (addr % RAW_SPU_OFFSET) < RAW_SPU_PROB_OFFSET || !Memory.WriteMMIO32((u32)addr, value))
{
*(be_t<u32>*)((u8*)g_base_addr + addr) = value;
}
get_ref<be_t<u32>>(addr) = value;
}
static u64 read64(u32 addr)
{
return re64(*(u64*)((u8*)g_base_addr + addr));
return get_ref<be_t<u64>>(addr);
}
static void write64(u32 addr, be_t<u64> value)
{
*(be_t<u64>*)((u8*)g_base_addr + addr) = value;
get_ref<be_t<u64>>(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<be_t<u128>>(addr);
}
static void write128(u32 addr, u128 value)
{
*(u128*)((u8*)g_base_addr + addr) = re128(value);
get_ref<be_t<u128>>(addr) = value;
}
}
@ -122,52 +168,52 @@ namespace vm
static u8 read8(u32 addr)
{
return *((u8*)g_base_addr + addr);
return get_ref<u8>(addr);
}
static void write8(u32 addr, u8 value)
{
*((u8*)g_base_addr + addr) = value;
get_ref<u8>(addr) = value;
}
static u16 read16(u32 addr)
{
return *(u16*)((u8*)g_base_addr + addr);
return get_ref<u16>(addr);
}
static void write16(u32 addr, u16 value)
{
*(u16*)((u8*)g_base_addr + addr) = value;
get_ref<u16>(addr) = value;
}
static u32 read32(u32 addr)
{
return *(u32*)((u8*)g_base_addr + addr);
return get_ref<u32>(addr);
}
static void write32(u32 addr, u32 value)
{
*(u32*)((u8*)g_base_addr + addr) = value;
get_ref<u32>(addr) = value;
}
static u64 read64(u32 addr)
{
return *(u64*)((u8*)g_base_addr + addr);
return get_ref<u64>(addr);
}
static void write64(u32 addr, u64 value)
{
*(u64*)((u8*)g_base_addr + addr) = value;
get_ref<u64>(addr) = value;
}
static u128 read128(u32 addr)
{
return *(u128*)((u8*)g_base_addr + addr);
return get_ref<u128>(addr);
}
static void write128(u32 addr, u128 value)
{
*(u128*)((u8*)g_base_addr + addr) = value;
get_ref<u128>(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"

View file

@ -11,49 +11,50 @@ namespace vm
public:
typedef typename std::remove_cv<T>::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<AT>::type count) const { return make(m_addr + count * sizeof(AT)); }
_ptr_base operator + (typename to_be_t<AT>::type count) const { return make(m_addr + count * sizeof(AT)); }
_ptr_base operator - (typename remove_be_t<AT>::type count) const { return make(m_addr - count * sizeof(AT)); }
_ptr_base operator - (typename to_be_t<AT>::type count) const { return make(m_addr - count * sizeof(AT)); }
_ptr_base operator + (typename remove_be_t<AT>::type count) const { return make(m_addr + count * address_size); }
_ptr_base operator + (typename to_be_t<AT>::type count) const { return make(m_addr + count * address_size); }
_ptr_base operator - (typename remove_be_t<AT>::type count) const { return make(m_addr - count * address_size); }
_ptr_base operator - (typename to_be_t<AT>::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<T, lvl - 1, std::conditional<is_be_t<T>::value, typename to_be_t<AT>::type, AT>>& operator *() const
{
return vm::get_ref<_ptr_base<T, lvl - 1, std::conditional<is_be_t<T>::value, typename to_be_t<AT>::type, AT>>>((u32)m_addr);
return vm::get_ref<_ptr_base<T, lvl - 1, std::conditional<is_be_t<T>::value, typename to_be_t<AT>::type, AT>>>(vm::cast(m_addr));
}
__forceinline _ptr_base<T, lvl - 1, std::conditional<is_be_t<T>::value, typename to_be_t<AT>::type, AT>>& operator [](AT index) const
{
return vm::get_ref<_ptr_base<T, lvl - 1, std::conditional<is_be_t<T>::value, typename to_be_t<AT>::type, AT>>>((u32)(m_addr + sizeof(AT)* index));
return vm::get_ref<_ptr_base<T, lvl - 1, std::conditional<is_be_t<T>::value, typename to_be_t<AT>::type, AT>>>(vm::cast(m_addr + sizeof(AT)* index));
}
//typedef typename invert_be_t<AT>::type AT2;
template<typename AT2>
operator const _ptr_base<T, lvl, AT2>() const
{
typename std::remove_const<AT2>::type addr = convert_le_be<AT2>(m_addr);
return (_ptr_base<T, lvl, AT2>&)addr;
const AT2 addr = convert_le_be<AT2>(m_addr);
return reinterpret_cast<const _ptr_base<T, lvl, AT2>&>(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<const _ptr_base&>(addr);
}
_ptr_base& operator = (const _ptr_base& right) = default;
@ -109,68 +108,69 @@ namespace vm
public:
typedef typename std::remove_cv<T>::type type;
static const u32 data_size = sizeof(T);
__forceinline T* const operator -> () const
{
return vm::get_ptr<T>((u32)m_addr);
return vm::get_ptr<T>(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<AT>::type count) const { return make(m_addr + count * sizeof(T)); }
_ptr_base operator + (typename to_be_t<AT>::type count) const { return make(m_addr + count * sizeof(T)); }
_ptr_base operator - (typename remove_be_t<AT>::type count) const { return make(m_addr - count * sizeof(T)); }
_ptr_base operator - (typename to_be_t<AT>::type count) const { return make(m_addr - count * sizeof(T)); }
_ptr_base operator + (typename remove_be_t<AT>::type count) const { return make(m_addr + count * data_size); }
_ptr_base operator + (typename to_be_t<AT>::type count) const { return make(m_addr + count * data_size); }
_ptr_base operator - (typename remove_be_t<AT>::type count) const { return make(m_addr - count * data_size); }
_ptr_base operator - (typename to_be_t<AT>::type count) const { return make(m_addr - count * data_size); }
__forceinline T& operator *() const
{
return vm::get_ref<T>((u32)m_addr);
return vm::get_ref<T>(vm::cast(m_addr));
}
__forceinline T& operator [](typename remove_be_t<AT>::type index) const
{
return vm::get_ref<T>((u32)(m_addr + sizeof(T) * index));
return vm::get_ref<T>(vm::cast(m_addr + data_size * index));
}
__forceinline T& operator [](typename to_be_t<AT>::forced_type index) const
{
return vm::get_ref<T>((u32)(m_addr + sizeof(T)* index));
return vm::get_ref<T>(vm::cast(m_addr + data_size * index));
}
__forceinline bool operator <(const _ptr_base& right) const { return m_addr < right.m_addr; }
@ -184,18 +184,6 @@ namespace vm
explicit operator bool() const { return m_addr != 0; }
explicit operator T*() const { return get_ptr(); }
/*
operator _ref_base<T, AT>()
{
return _ref_base<T, AT>::make(m_addr);
}
operator const _ref_base<T, AT>() const
{
return _ref_base<T, AT>::make(m_addr);
}
*/
AT addr() const
{
return m_addr;
@ -207,29 +195,21 @@ namespace vm
m_addr = convert_le_be<AT>(value);
}
/*
operator T*() const
{
return get_ptr();
}
*/
//typedef typename invert_be_t<AT>::type AT2;
template<typename AT2>
operator const _ptr_base<T, 1, AT2>() const
{
typename std::remove_const<AT2>::type addr = convert_le_be<AT2>(m_addr);
return (_ptr_base<T, 1, AT2>&)addr;
const AT2 addr = convert_le_be<AT2>(m_addr);
return reinterpret_cast<const _ptr_base<T, 1, AT2>&>(addr);
}
T* get_ptr() const
{
return vm::get_ptr<T>((u32)m_addr);
return vm::get_ptr<T>(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<const _ptr_base&>(addr);
}
_ptr_base& operator = (const _ptr_base& right) = default;
@ -253,7 +233,7 @@ namespace vm
void* get_ptr() const
{
return vm::get_ptr<void>((u32)m_addr);
return vm::get_ptr<void>(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<AT>::type AT2;
template<typename AT2>
operator const _ptr_base<void, 1, AT2>() const
{
typename std::remove_const<AT2>::type addr = convert_le_be<AT2>(m_addr);
return (_ptr_base<void, 1, AT2>&)addr;
const AT2 addr = convert_le_be<AT2>(m_addr);
return reinterpret_cast<const _ptr_base<void, 1, AT2>&>(addr);
}
template<typename AT2>
operator const _ptr_base<const void, 1, AT2>() const
{
typename std::remove_const<AT2>::type addr = convert_le_be<AT2>(m_addr);
return (_ptr_base<const void, 1, AT2>&)addr;
const AT2 addr = convert_le_be<AT2>(m_addr);
return reinterpret_cast<const _ptr_base<const void, 1, AT2>&>(addr);
}
static _ptr_base make(AT addr)
static const _ptr_base make(const AT& addr)
{
return (_ptr_base&)addr;
return reinterpret_cast<const _ptr_base&>(addr);
}
_ptr_base& operator = (const _ptr_base& right) = default;
@ -313,7 +291,7 @@ namespace vm
const void* get_ptr() const
{
return vm::get_ptr<const void>((u32)m_addr);
return vm::get_ptr<const void>(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<AT>::type AT2;
template<typename AT2>
operator const _ptr_base<const void, 1, AT2>() const
{
typename std::remove_const<AT2>::type addr = convert_le_be<AT2>(m_addr);
return (_ptr_base<const void, 1, AT2>&)addr;
const AT2 addr = convert_le_be<AT2>(m_addr);
return reinterpret_cast<const _ptr_base<const void, 1, AT2>&>(addr);
}
static _ptr_base make(AT addr)
static const _ptr_base make(const AT& addr)
{
return (_ptr_base&)addr;
return reinterpret_cast<const _ptr_base&>(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<AT>::type AT2;
template<typename AT2>
operator const _ptr_base<RT(*)(T...), 1, AT2>() const
{
typename std::remove_const<AT2>::type addr = convert_le_be<AT2>(m_addr);
return (_ptr_base<RT(*)(T...), 1, AT2>&)addr;
const AT2 addr = convert_le_be<AT2>(m_addr);
return reinterpret_cast<const _ptr_base<RT(*)(T...), 1, AT2>&>(addr);
}
static _ptr_base make(AT addr)
static const _ptr_base make(const AT& addr)
{
return (_ptr_base&)addr;
return reinterpret_cast<const _ptr_base&>(addr);
}
operator const std::function<RT(T...)>() const
{
typename std::remove_const<AT>::type addr = convert_le_be<AT>(m_addr);
const AT addr = convert_le_be<AT>(m_addr);
return [addr](T... args) -> RT { return make(addr)(args...); };
}
@ -406,75 +380,88 @@ namespace vm
//BE pointer to LE data
template<typename T, int lvl = 1, typename AT = u32> struct bptrl : public _ptr_base<T, lvl, typename to_be_t<AT>::type>
{
static bptrl make(AT addr)
static const bptrl make(AT addr)
{
return (bptrl&)addr;
auto res = _ptr_base<T, lvl, typename to_be_t<AT>::type>::make(convert_le_be<typename to_be_t<AT>::type>(addr));
return static_cast<const bptrl&>(res);
}
using _ptr_base<T, lvl, typename to_be_t<AT>::type>::operator=;
//using _ptr_base<T, lvl, typename to_be_t<AT>::type>::operator const _ptr_base<T, lvl, AT>;
};
//BE pointer to BE data
template<typename T, int lvl = 1, typename AT = u32> struct bptrb : public _ptr_base<typename to_be_t<T>::type, lvl, typename to_be_t<AT>::type>
{
static bptrb make(AT addr)
static const bptrb make(AT addr)
{
return (bptrb&)addr;
auto res = _ptr_base<typename to_be_t<T>::type, lvl, typename to_be_t<AT>::type>::make(convert_le_be<typename to_be_t<AT>::type>(addr));
return static_cast<const bptrb&>(res);
}
using _ptr_base<typename to_be_t<T>::type, lvl, typename to_be_t<AT>::type>::operator=;
//using _ptr_base<typename to_be_t<T>::type, lvl, typename to_be_t<AT>::type>::operator const _ptr_base<typename to_be_t<T>::type, lvl, AT>;
};
//LE pointer to BE data
template<typename T, int lvl = 1, typename AT = u32> struct lptrb : public _ptr_base<typename to_be_t<T>::type, lvl, AT>
{
static lptrb make(AT addr)
static const lptrb make(AT addr)
{
return (lptrb&)addr;
auto res = _ptr_base<typename to_be_t<T>::type, lvl, AT>::make(addr);
return static_cast<const lptrb&>(res);
}
using _ptr_base<typename to_be_t<T>::type, lvl, AT>::operator=;
//using _ptr_base<typename to_be_t<T>::type, lvl, AT>::operator const _ptr_base<typename to_be_t<T>::type, lvl, typename to_be_t<AT>::type>;
};
//LE pointer to LE data
template<typename T, int lvl = 1, typename AT = u32> struct lptrl : public _ptr_base<T, lvl, AT>
{
static lptrl make(AT addr)
static const lptrl make(AT addr)
{
return (lptrl&)addr;
auto res = _ptr_base<T, lvl, AT>::make(addr);
return static_cast<const lptrl&>(res);
}
using _ptr_base<T, lvl, AT>::operator=;
//using _ptr_base<T, lvl, AT>::operator const _ptr_base<T, lvl, typename to_be_t<AT>::type>;
};
namespace ps3
{
template<typename T, int lvl = 1, typename AT = u32> struct ptr;
template<typename T, int lvl = 1, typename AT = u32> struct bptr;
//default pointer for HLE functions (LE pointer to BE data)
template<typename T, int lvl = 1, typename AT = u32> struct ptr : public lptrb<T, lvl, AT>
template<typename T, int lvl, typename AT> struct ptr : public lptrb<T, lvl, AT>
{
static ptr make(AT addr)
static const ptr make(AT addr)
{
return (ptr&)addr;
auto res = lptrb<T, lvl, AT>::make(addr);
return static_cast<const ptr&>(res);
}
vm::ps3::bptr<T, lvl, AT> to_be() const
{
return vm::ps3::bptr<T, lvl, AT>::make(this->addr());
}
using lptrb<T, lvl, AT>::operator=;
//using lptrb<T, lvl, AT>::operator const _ptr_base<typename to_be_t<T>::type, lvl, AT>;
};
//default pointer for HLE structures (BE pointer to BE data)
template<typename T, int lvl = 1, typename AT = u32> struct bptr : public bptrb<T, lvl, AT>
template<typename T, int lvl, typename AT> struct bptr : public bptrb<T, lvl, AT>
{
static bptr make(AT addr)
static const bptr make(AT addr)
{
return (bptr&)addr;
auto res = bptrb<T, lvl, AT>::make(addr);
return static_cast<const bptr&>(res);
}
vm::ps3::ptr<T, lvl, AT> to_le() const
{
return vm::ps3::ptr<T, lvl, AT>::make(this->addr());
}
using bptrb<T, lvl, AT>::operator=;
//using bptrb<T, lvl, AT>::operator const _ptr_base<typename to_be_t<T>::type, lvl, AT>;
};
}
@ -483,9 +470,10 @@ namespace vm
//default pointer for HLE functions & structures (LE pointer to LE data)
template<typename T, int lvl = 1, typename AT = u32> struct ptr : public lptrl<T, lvl, AT>
{
static ptr make(AT addr)
static const ptr make(AT addr)
{
return (ptr&)addr;
auto res = lptrl<T, lvl, AT>::make(addr);
return static_cast<const ptr&>(res);
}
using lptrl<T, lvl, AT>::operator=;
@ -495,3 +483,79 @@ namespace vm
//PS3 emulation is main now, so lets it be as default
using namespace ps3;
}
namespace fmt
{
// external specializations for fmt::format function
template<typename T, int lvl, typename AT>
struct unveil<vm::ps3::ptr<T, lvl, AT>, false>
{
typedef typename unveil<AT>::result_type result_type;
__forceinline static result_type get_value(const vm::ps3::ptr<T, lvl, AT>& arg)
{
return unveil<AT>::get_value(arg.addr());
}
};
template<typename T, int lvl, typename AT>
struct unveil<vm::ps3::bptr<T, lvl, AT>, false>
{
typedef typename unveil<AT>::result_type result_type;
__forceinline static result_type get_value(const vm::ps3::bptr<T, lvl, AT>& arg)
{
return unveil<AT>::get_value(arg.addr());
}
};
template<typename T, int lvl, typename AT>
struct unveil<vm::psv::ptr<T, lvl, AT>, false>
{
typedef typename unveil<AT>::result_type result_type;
__forceinline static result_type get_value(const vm::psv::ptr<T, lvl, AT>& arg)
{
return unveil<AT>::get_value(arg.addr());
}
};
}
// external specializations for PPU GPR (SC_FUNC.h, CB_FUNC.h)
template<typename T, bool is_enum>
struct cast_ppu_gpr;
template<typename T, int lvl, typename AT>
struct cast_ppu_gpr<vm::ps3::ptr<T, lvl, AT>, false>
{
__forceinline static u64 to_gpr(const vm::ps3::ptr<T, lvl, AT>& value)
{
return value.addr();
}
__forceinline static vm::ps3::ptr<T, lvl, AT> from_gpr(const u64 reg)
{
return vm::ps3::ptr<T, lvl, AT>::make(cast_ppu_gpr<AT, std::is_enum<AT>::value>::from_gpr(reg));
}
};
// external specializations for ARMv7 GPR
template<typename T, bool is_enum>
struct cast_armv7_gpr;
template<typename T, int lvl, typename AT>
struct cast_armv7_gpr<vm::psv::ptr<T, lvl, AT>, false>
{
__forceinline static u32 to_gpr(const vm::psv::ptr<T, lvl, AT>& value)
{
return value.addr();
}
__forceinline static vm::psv::ptr<T, lvl, AT> from_gpr(const u32 reg)
{
return vm::psv::ptr<T, lvl, AT>::make(cast_armv7_gpr<AT, std::is_enum<AT>::value>::from_gpr(reg));
}
};

View file

@ -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)
@ -109,3 +109,79 @@ namespace vm
//PS3 emulation is main now, so lets it be as default
using namespace ps3;
}
namespace fmt
{
// external specializations for fmt::format function
template<typename T, typename AT>
struct unveil<vm::ps3::ref<T, AT>, false>
{
typedef typename unveil<AT>::result_type result_type;
__forceinline static result_type get_value(const vm::ps3::ref<T, AT>& arg)
{
return unveil<AT>::get_value(arg.addr());
}
};
template<typename T, typename AT>
struct unveil<vm::ps3::bref<T, AT>, false>
{
typedef typename unveil<AT>::result_type result_type;
__forceinline static result_type get_value(const vm::ps3::bref<T, AT>& arg)
{
return unveil<AT>::get_value(arg.addr());
}
};
template<typename T, typename AT>
struct unveil<vm::psv::ref<T, AT>, false>
{
typedef typename unveil<AT>::result_type result_type;
__forceinline static result_type get_value(const vm::psv::ref<T, AT>& arg)
{
return unveil<AT>::get_value(arg.addr());
}
};
}
// external specializations for PPU GPR (SC_FUNC.h, CB_FUNC.h)
template<typename T, bool is_enum>
struct cast_ppu_gpr;
template<typename T, typename AT>
struct cast_ppu_gpr<vm::ps3::ref<T, AT>, false>
{
__forceinline static u64 to_gpr(const vm::ps3::ref<T, AT>& value)
{
return value.addr();
}
__forceinline static vm::ps3::ref<T, AT> from_gpr(const u64 reg)
{
return vm::ps3::ref<T, AT>::make(cast_ppu_gpr<AT, std::is_enum<AT>::value>::from_gpr(reg));
}
};
// external specializations for ARMv7 GPR
template<typename T, bool is_enum>
struct cast_armv7_gpr;
template<typename T, typename AT>
struct cast_armv7_gpr<vm::psv::ref<T, AT>, false>
{
__forceinline static u32 to_gpr(const vm::psv::ref<T, AT>& value)
{
return value.addr();
}
__forceinline static vm::psv::ref<T, AT> from_gpr(const u32 reg)
{
return vm::psv::ref<T, AT>::make(cast_armv7_gpr<AT, std::is_enum<AT>::value>::from_gpr(reg));
}
};

View file

@ -1,5 +1,7 @@
#pragma once
class CPUThread;
namespace vm
{
template<typename T>
@ -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<T>(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<T>(m_addr);
}
@ -495,4 +497,130 @@ namespace vm
return (NT*)(m_ptr + offset);
}
};
template<typename T>
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<T>(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<T>() const
{
return addr();
}
*/
template<typename AT> operator const ps3::ptr<T, 1, AT>() const
{
return ps3::ptr<T, 1, AT>::make(m_data.addr);
}
template<typename AT> operator const ps3::ptr<const T, 1, AT>() const
{
return ps3::ptr<const T, 1, AT>::make(m_data.addr);
}
operator T&()
{
return *m_data.ptr;
}
operator const T&() const
{
return *m_data.ptr;
}
};
}

View file

@ -102,9 +102,9 @@ std::string GLFragmentDecompilerThread::AddConst()
return name;
}
auto data = vm::ptr<u32>::make(m_addr + m_size + m_offset);
auto data = vm::ptr<u32>::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");

View file

@ -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,71 +1950,6 @@ 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");
@ -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)

View file

@ -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();
};

View file

@ -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"

View file

@ -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() {}
};

View file

@ -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:
{
if (count == 3)
{
m_set_stencil_func = true;
m_stencil_func = ARGS(0);
if (count >= 2)
{
m_set_stencil_func_ref = true;
m_stencil_func_ref = ARGS(1);
if (count >= 3)
{
m_set_stencil_func_mask = true;
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;
if (count == 3)
{
m_set_stencil_op_fail = true;
m_stencil_fail = ARGS(0);
if (count >= 2)
{
m_set_stencil_zfail = true;
m_stencil_zfail = ARGS(1);
if (count >= 3)
{
m_set_stencil_zpass = true;
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:
{
if (count == 3)
{
m_set_back_stencil_func = true;
m_back_stencil_func = ARGS(0);
if (count >= 2)
{
m_set_back_stencil_func_ref = true;
m_back_stencil_func_ref = ARGS(1);
if (count >= 3)
{
m_set_back_stencil_func_mask = true;
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)
{
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);
if (count >= 3)
{
m_set_back_stencil_zpass = true;
m_back_stencil_zpass = ARGS(2);
StencilOpSeparate(0, m_back_stencil_fail, m_back_stencil_zfail, m_back_stencil_zpass); // GL_BACK
if (m_set_stencil_op_fail)
{
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<std::mutex> lock(m_cs_main);
@ -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);
}
}

View file

@ -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)

View file

@ -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<T>(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<T>(arg);
}
};
@ -46,9 +46,9 @@ namespace cb_detail
{
static_assert(std::is_same<T, u128>::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<T>(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<T>(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<T>(CPU.FPR[1]);
}
};
template<typename T>
struct _func_res<T, ARG_VECTOR>
{
static_assert(sizeof(T) == 16, "Invalid callback result type for ARG_VECTOR");
static_assert(std::is_same<T, u128>::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<typename AT, typename RT, typename... T>
__forceinline RT _ptr_base<RT(*)(T...), 1, AT>::call(CPUThread& CPU, T... args) const
__forceinline RT _ptr_base<RT(*)(T...), 1, AT>::operator()(CPUThread& CPU, T... args) const
{
const u32 pc = vm::get_ref<be_t<u32>>(m_addr);
const u32 rtoc = vm::get_ref<be_t<u32>>(m_addr + 4);
auto data = vm::get_ptr<be_t<u32>>(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<RT, T...>::call(static_cast<PPUThread&>(CPU), pc, rtoc, args...);
}
template<typename AT, typename RT, typename... T>
__forceinline RT _ptr_base<RT(*)(T...), 1, AT>::operator()(T... args) const
{
return call(GetCurrentPPUThread(), args...);
return operator()(GetCurrentPPUThread(), args...);
}
}
template<typename RT, typename... T>
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<RT, T...>::call(CPU, pc, rtoc, args...);
}
template<typename... T>
void cb_call(PPUThread& CPU, u32 pc, u32 rtoc, T... args)
{
cb_detail::_func_caller<void, T...>::call(CPU, pc, rtoc, args...);
}
//template<typename... T>
//void cb_call(PPUThread& CPU, u32 pc, u32 rtoc, T... args)
//{
// cb_detail::_func_caller<void, T...>::call(CPU, pc, rtoc, args...);
//}

View file

@ -7,25 +7,33 @@
#include "Emu/ARMv7/ARMv7Thread.h"
#include "Callback.h"
void CallbackManager::Register(const std::function<s32()>& func)
void CallbackManager::Register(const std::function<s32(PPUThread& PPU)>& func)
{
std::lock_guard<std::mutex> 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<PPUThread&>(CPU));
});
}
void CallbackManager::Async(const std::function<void()>& func)
void CallbackManager::Async(const std::function<void(PPUThread& PPU)>& func)
{
std::lock_guard<std::mutex> 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<PPUThread&>(CPU));
});
m_cb_thread->Notify();
}
bool CallbackManager::Check(s32& result)
bool CallbackManager::Check(CPUThread& CPU, s32& result)
{
std::function<s32()> func = nullptr;
std::function<s32(CPUThread& CPU)> func;
{
std::lock_guard<std::mutex> 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<PPUThread*>(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<void()> func = nullptr;
std::function<void(CPUThread& CPU)> func;
{
std::lock_guard<std::mutex> 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<PauseResumeCB>& func)
{
std::lock_guard<std::mutex> lock(m_mutex);
m_pause_cb_list.push_back({ func, next_tag });
return next_tag++;
}
void CallbackManager::RemovePauseCallback(const u64 tag)
{
std::lock_guard<std::mutex> 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<std::mutex> lock(m_mutex);
for (auto& data : m_pause_cb_list)
{
if (data.cb)
{
data.cb(is_paused);
}
}
}

View file

@ -1,22 +1,64 @@
#pragma once
class CPUThread;
class PPUThread;
typedef void(PauseResumeCB)(bool is_paused);
class CallbackManager
{
std::vector<std::function<s32()>> m_cb_list;
std::vector<std::function<void()>> m_async_list;
CPUThread* m_cb_thread;
std::mutex m_mutex;
std::vector<std::function<s32(CPUThread&)>> m_cb_list;
std::vector<std::function<void(CPUThread&)>> m_async_list;
CPUThread* m_cb_thread;
struct PauseResumeCBS
{
std::function<PauseResumeCB> cb;
u64 tag;
};
u64 next_tag; // not initialized, only increased
std::vector<PauseResumeCBS> m_pause_cb_list;
public:
void Register(const std::function<s32()>& func); // register callback (called in Check() method)
void Register(const std::function<s32(PPUThread& CPU)>& func); // register callback (called in Check() method)
void Async(const std::function<void()>& func); // register callback for callback thread (called immediately)
void Async(const std::function<void(PPUThread& CPU)>& 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<PauseResumeCB>& 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<PauseResumeCB>& 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;
};

View file

@ -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);
}
}
}

View file

@ -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<typename... Targs>
__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<typename... Targs> __noinline void Notice(const u32 id, const char* fmt, Targs... args) const
template<typename... Targs>
__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<typename... Targs> __noinline void Notice(const char* fmt, Targs... args) const
{
LogOutput(LogNotice, ": ", fmt::Format(fmt, args...));
}
template<typename... Targs> __forceinline void Log(const char* fmt, Targs... args) const
template<typename... Targs>
__forceinline void Log(const char* fmt, Targs... args) const
{
if (CheckLogging())
{
@ -47,52 +50,28 @@ public:
}
}
template<typename... Targs> __forceinline void Log(const u32 id, const char* fmt, Targs... args) const
template<typename... Targs>
__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<typename... Targs> __noinline void Success(const u32 id, const char* fmt, Targs... args) const
template<typename... Targs>
__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<typename... Targs> __noinline void Success(const char* fmt, Targs... args) const
template<typename... Targs>
__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<typename... Targs> __noinline void Warning(const u32 id, const char* fmt, Targs... args) const
template<typename... Targs>
__forceinline void Todo(const char* fmt, Targs... args) const
{
LogOutput(LogWarning, id, " warning: ", fmt::Format(fmt, args...));
}
template<typename... Targs> __noinline void Warning(const char* fmt, Targs... args) const
{
LogOutput(LogWarning, " warning: ", fmt::Format(fmt, args...));
}
template<typename... Targs> __noinline void Error(const u32 id, const char* fmt, Targs... args) const
{
LogOutput(LogError, id, " error: ", fmt::Format(fmt, args...));
}
template<typename... Targs> __noinline void Error(const char* fmt, Targs... args) const
{
LogOutput(LogError, " error: ", fmt::Format(fmt, args...));
}
template<typename... Targs> __noinline void Todo(const u32 id, const char* fmt, Targs... args) const
{
LogOutput(LogError, id, " TODO: ", fmt::Format(fmt, args...));
}
template<typename... Targs> __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)...);
}
};

View file

@ -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;
}
@ -477,12 +475,8 @@ u32 adecOpen(AudioDecoder* adec_ptr)
}
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<CellAdecType> type, vm::ptr<CellAdecResource> res, vm::
if (!adecCheckType(type->audioCodecType)) return CELL_ADEC_ERROR_ARG;
*handle = adecOpen(new AudioDecoder(type->audioCodecType, res->startAddr, res->totalMemSize, vm::ptr<CellAdecCbMsg>::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<CellAdecType> type, vm::ptr<CellAdecResourceEx> res,
if (!adecCheckType(type->audioCodecType)) return CELL_ADEC_ERROR_ARG;
*handle = adecOpen(new AudioDecoder(type->audioCodecType, res->startAddr, res->totalMemSize, vm::ptr<CellAdecCbMsg>::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<const CellAdecParamMP3>::make(param_addr);
cellAdec->Todo("*** CellAdecParamMP3: bw_pcm=%d", param->bw_pcm.ToLE());
cellAdec->Todo("*** CellAdecParamMP3: bw_pcm=%d", param->bw_pcm);
break;
}
default:

File diff suppressed because it is too large Load diff

View file

@ -72,51 +72,76 @@ struct CellAudioPortConfig
be_t<u32> 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<AudioPortState> 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<AudioState> 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<u64> m_keys;
std::vector<u64> 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;

View file

@ -82,7 +82,7 @@ int cellCameraGetDeviceGUID()
int cellCameraGetType(s32 dev_num, vm::ptr<CellCameraType> 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;

View file

@ -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<CellDmuxCbEsMsg> 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<CellDmuxMsg>::make(a128(dmux.memAddr) + (cb_add ^= 16));
auto dmuxMsg = vm::ptr<CellDmuxMsg>::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<u64>*)data)->ToLE());
DMUX_ERROR("ATX: 0x0fd0 header not found (ats=0x%llx)", *(be_t<u64>*)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<u64>*)data)->ToLE(), frame_size);
//cellDmux->Notice("ATX AU pushed (ats=0x%llx, frame_size=%d)", *(be_t<u64>*)data, frame_size);
auto esMsg = vm::ptr<CellDmuxEsMsg>::make(a128(dmux.memAddr) + (cb_add ^= 16));
auto esMsg = vm::ptr<CellDmuxEsMsg>::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<CellDmuxEsMsg>::make(a128(dmux.memAddr) + (cb_add ^= 16));
auto esMsg = vm::ptr<CellDmuxEsMsg>::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<CellDmuxMsg>::make(a128(dmux.memAddr) + (cb_add ^= 16));
auto dmuxMsg = vm::ptr<CellDmuxMsg>::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<CellDmuxEsMsg>::make(a128(dmux.memAddr) + (cb_add ^= 16));
auto esMsg = vm::ptr<CellDmuxEsMsg>::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<CellDmuxEsMsg>::make(a128(dmux.memAddr) + (cb_add ^= 16));
auto esMsg = vm::ptr<CellDmuxEsMsg>::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<const CellDmuxType> demuxerType, vm::ptr<const CellDmux
// TODO: check demuxerResource and demuxerCb arguments
*demuxerHandle = dmuxOpen(new Demuxer(demuxerResource->memAddr, demuxerResource->memSize, vm::ptr<CellDmuxCbMsg>::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<const CellDmuxType> demuxerType, vm::ptr<const CellDm
// TODO: check demuxerResourceEx and demuxerCb arguments
*demuxerHandle = dmuxOpen(new Demuxer(demuxerResourceEx->memAddr, demuxerResourceEx->memSize, vm::ptr<CellDmuxCbMsg>::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<const CellDmuxType2> demuxerType2, vm::ptr<const CellD
// TODO: check demuxerType2, demuxerResource2 and demuxerCb arguments
*demuxerHandle = dmuxOpen(new Demuxer(demuxerResource2->memAddr, demuxerResource2->memSize, vm::ptr<CellDmuxCbMsg>::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<const CellCodecEsFilterId> esFil
std::shared_ptr<ElementaryStream> es(new ElementaryStream(dmux.get(), esResourceInfo->memAddr, esResourceInfo->memSize,
esFilterId->filterIdMajor, esFilterId->filterIdMinor, esFilterId->supplementalInfo1, esFilterId->supplementalInfo2,
vm::ptr<CellDmuxCbEsMsg>::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;

View file

@ -1,8 +1,5 @@
#pragma once
// align size or address to 128
#define a128(x) ((x + 127) & (~127))
// Error Codes
enum
{

View file

@ -36,11 +36,11 @@ int cellFontGetRevisionFlags(vm::ptr<be_t<u64>> revisionFlags)
return CELL_FONT_OK;
}
int cellFontInit(vm::ptr<CellFontConfig> config)
int cellFontInit(PPUThread& CPU, vm::ptr<CellFontConfig> config)
{
cellFont->Log("cellFontInit(config=0x%x)", config.addr());
vm::var<be_t<u64>> revisionFlags;
vm::stackvar<be_t<u64>> revisionFlags(CPU);
revisionFlags.value() = 0;
cellFontGetRevisionFlags(revisionFlags);
return cellFontInitializeWithRevision(revisionFlags.value(), config);
@ -101,7 +101,7 @@ int cellFontOpenFontFile(vm::ptr<CellFontLibrary> library, vm::ptr<const char> f
return ret;
}
int cellFontOpenFontset(vm::ptr<CellFontLibrary> library, vm::ptr<CellFontType> fontType, vm::ptr<CellFont> font)
int cellFontOpenFontset(PPUThread& CPU, vm::ptr<CellFontLibrary> library, vm::ptr<CellFontType> fontType, vm::ptr<CellFont> 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<CellFontLibrary> library, vm::ptr<CellFontType>
return CELL_FONT_ERROR_NO_SUPPORT_FONTSET;
}
vm::var<char> f((u32)file.length() + 1, 1);
vm::stackvar<char> 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;

View file

@ -201,7 +201,7 @@ int cellGameContentPermit(vm::ptr<char[CELL_GAME_PATH_MAX]> contentInfoPath, vm:
return CELL_GAME_RET_OK;
}
int cellGameDataCheckCreate2(u32 version, vm::ptr<const char> dirName, u32 errDialog,
int cellGameDataCheckCreate2(PPUThread& CPU, u32 version, vm::ptr<const char> dirName, u32 errDialog,
vm::ptr<void(*)(vm::ptr<CellGameDataCBResult> cbResult, vm::ptr<CellGameDataStatGet> get, vm::ptr<CellGameDataStatSet> 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<const char> dirName, u32 errDi
return CELL_GAMEDATA_ERROR_BROKEN;
}
// TODO: use memory container
vm::var<CellGameDataCBResult> cbResult;
vm::var<CellGameDataStatGet> cbGet;
vm::var<CellGameDataStatSet> cbSet;
vm::stackvar<CellGameDataCBResult> cbResult(CPU);
vm::stackvar<CellGameDataStatGet> cbGet(CPU);
vm::stackvar<CellGameDataStatSet> cbSet(CPU);
cbGet.value() = {};
@ -273,7 +272,7 @@ int cellGameDataCheckCreate2(u32 version, vm::ptr<const char> 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<const char> dirName, u32 errDi
}
}
int cellGameDataCheckCreate(u32 version, vm::ptr<const char> dirName, u32 errDialog,
int cellGameDataCheckCreate(PPUThread& CPU, u32 version, vm::ptr<const char> dirName, u32 errDialog,
vm::ptr<void(*)(vm::ptr<CellGameDataCBResult> cbResult, vm::ptr<CellGameDataStatGet> get, vm::ptr<CellGameDataStatSet> 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<CellGameSetInitParams> init, vm::ptr<char> tmp_contentInfoPath, vm::ptr<char> tmp_usrdirPath)
@ -444,11 +443,11 @@ int cellGameContentErrorDialog(s32 type, s32 errNeedSizeKB, vm::ptr<const char>
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)

View file

@ -190,10 +190,9 @@ int cellGemGetInfo()
return CELL_OK;
}
// Should int be used, even when type is int_32t (s32)?
s32 cellGemGetMemorySize(be_t<s32> 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;

View file

@ -30,17 +30,17 @@ int cellGifDecOpen(u32 mainHandle, vm::ptr<u32> subHandle, vm::ptr<CellGifDecSrc
current_subHandle->fd = 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<be_t<u32>> fd;
int ret = cellFsOpen(vm::ptr<const char>::make(src->fileName.addr()), 0, fd, vm::ptr<u32>::make(0), 0);
current_subHandle->fd = fd->ToLE();
int ret = cellFsOpen(src->fileName.to_le(), 0, fd, vm::ptr<const void>::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<CellGifDecInfo>
vm::var<u8[13]> buffer; // Alloc buffer for GIF header
vm::var<be_t<u64>> 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<void>(subHandle_data->src.streamPtr), buffer.size());
@ -156,7 +156,7 @@ int cellGifDecDecodeData(u32 mainHandle, u32 subHandle, vm::ptr<u8> data, vm::pt
vm::var<unsigned char[]> gif((u32)fileSize);
vm::var<be_t<u64>> 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<void>(subHandle_data->src.streamPtr), gif.size());

View file

@ -36,17 +36,17 @@ int cellJpgDecOpen(u32 mainHandle, vm::ptr<u32> subHandle, vm::ptr<CellJpgDecSrc
current_subHandle->fd = 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<be_t<u32>> fd;
int ret = cellFsOpen(vm::ptr<const char>::make(src->fileName.addr()), 0, fd, vm::ptr<u32>::make(0), 0);
current_subHandle->fd = fd->ToLE();
int ret = cellFsOpen(src->fileName.to_le(), 0, fd, vm::ptr<const void>::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<CellJpgDecInfo>
vm::var<u8[]> buffer((u32)fileSize);
vm::var<be_t<u64>> 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<void>(subHandle_data->src.streamPtr), buffer.size());
@ -163,7 +163,7 @@ int cellJpgDecDecodeData(u32 mainHandle, u32 subHandle, vm::ptr<u8> data, vm::pt
vm::var<unsigned char[]> jpg((u32)fileSize);
vm::var<be_t<u64>> 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<void>(subHandle_data->src.streamPtr), jpg.size());
@ -261,7 +261,7 @@ int cellJpgDecDecodeData(u32 mainHandle, u32 subHandle, vm::ptr<u8> 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:

View file

@ -123,7 +123,7 @@ s32 cellMsgDialogOpen2(u32 type, vm::ptr<const char> msgString, vm::ptr<CellMsgD
std::string msg = msgString.get_ptr();
thread t("MsgDialog thread", [type, msg, callback, userData, extParam]()
thread_t t("MsgDialog Thread", [type, msg, callback, userData, extParam]()
{
switch (type & CELL_MSGDIALOG_TYPE_SE_TYPE)
{
@ -171,10 +171,10 @@ s32 cellMsgDialogOpen2(u32 type, vm::ptr<const char> msgString, vm::ptr<CellMsgD
if (callback && (g_msg_dialog_state != msgDialogAbort))
{
s32 status = (s32)g_msg_dialog_status;
Emu.GetCallbackManager().Register([callback, userData, status]() -> 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<const char> msgString, vm::ptr<CellMsgD
g_msg_dialog_state = msgDialogNone;
});
});
t.detach();
return CELL_OK;
}

View file

@ -386,7 +386,7 @@ int cellPadInfoSensorMode(u32 port_no)
int cellPadSetPressMode(u32 port_no, u32 mode)
{
sys_io->Log("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();

View file

@ -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<be_t<u32>> fd;
int ret = cellFsOpen(vm::ptr<const char>::make(src->fileName.addr()), 0, fd, vm::ptr<u32>::make(0), 0);
stream->fd = fd->ToLE();
int ret = cellFsOpen(src->fileName.to_le(), 0, fd, vm::ptr<const void>::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<be_t<u32>>();
vm::var<be_t<u64>> 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<unsigned char[]> png((u32)fileSize);
vm::var<be_t<u64>> 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;
}

View file

@ -970,11 +970,11 @@ int cellRescSetSrc(s32 idx, vm::ptr<CellRescSrc> 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<u32> colorBuffers, vm::ptr<u32> vertexArray
for (int i=0; i<GetNumColorBuffers(); i++)
{
s_rescInternalInstance->m_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; i<GetNumColorBuffers(); i++)
@ -1212,7 +1212,7 @@ int CreateInterlaceTable(u32 ea_addr, float srcH, float dstH, CellRescTableEleme
int cellRescCreateInterlaceTable(u32 ea_addr, float srcH, CellRescTableElement depth, int length)
{
cellResc->Warning("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)
{

View file

@ -81,7 +81,7 @@ int cellRtcFormatRfc2822(vm::ptr<char> pszDateTime, vm::ptr<CellRtcTick> 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<char> pszDateTime, vm::ptr<CellRtcTick
rDateTime date = rDateTime((time_t)pUtc->tick);
// 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<char> pszDateTime, vm::ptr<CellRtcTick> 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<char> pszDateTime, vm::ptr<CellRtcTick
rDateTime date = rDateTime((time_t) pUtc->tick);
// 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<CellRtcDateTime> pTime, vm::ptr<CellRtcTick> 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<CellRtcDateTime> pDateTime, vm::ptr<u32> 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<CellRtcDateTime> pDateTime, vm::ptr<s64> 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<CellRtcDateTime> pDateTime, vm::ptr<u64> 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<CellRtcDateTime> pDateTime, u64 iTime)
int cellRtcSetWin32FileTime(vm::ptr<CellRtcDateTime> 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);

View file

@ -94,7 +94,7 @@ int cellSailDescriptorIsAutoSelection(vm::ptr<CellSailDescriptor> pSelf)
return CELL_OK;
}
int cellSailDescriptorCreateDatabase(vm::ptr<CellSailDescriptor> pSelf, vm::ptr<void> pDatabase, be_t<u32> size, be_t<u64> arg)
int cellSailDescriptorCreateDatabase(vm::ptr<CellSailDescriptor> pSelf, vm::ptr<void> 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<CellSailPlayer> pSelf)
int cellSailPlayerSetRepeatMode(vm::ptr<CellSailPlayer> pSelf, s32 repeatMode, vm::ptr<CellSailStartCommand> 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;

View file

@ -205,7 +205,7 @@ void getSaveDataStat(SaveDataEntry entry, vm::ptr<CellSaveDataStatGet> statGet)
strcpy_trunc(statGet->getParam.listParam, entry.listParam);
statGet->fileNum = 0;
statGet->fileList.set(be_t<u32>::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<CellSaveDataStatGet> statGet)
}
}
statGet->fileList = vm::ptr<CellSaveDataFileStat>::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<CellSaveDataFileCallback> funcFile, vm::ptr<Cell
break;
case CELL_SAVEDATA_FILEOP_WRITE_NOTRUNC:
cellSysutil->Warning("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<CellSaveDataFileCallback> funcFile, vm::ptr<Cell
if (file && file->IsOpened())
file->Close();
}
return CELL_SAVEDATA_RET_OK;
return CELL_OK;
}
// Functions
int cellSaveDataListSave2(u32 version, vm::ptr<CellSaveDataSetList> setList, vm::ptr<CellSaveDataSetBuf> setBuf,
vm::ptr<CellSaveDataListCallback> funcList, vm::ptr<CellSaveDataStatCallback> funcStat, vm::ptr<CellSaveDataFileCallback> funcFile,
u32 container, vm::ptr<void> userdata)
s32 cellSaveDataListSave2(
u32 version,
vm::ptr<CellSaveDataSetList> setList,
vm::ptr<CellSaveDataSetBuf> setBuf,
vm::ptr<CellSaveDataListCallback> funcList,
vm::ptr<CellSaveDataStatCallback> funcStat,
vm::ptr<CellSaveDataFileCallback> funcFile,
u32 container,
vm::ptr<void> 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<CellSaveDataCBResult> result;
@ -360,8 +366,8 @@ int cellSaveDataListSave2(u32 version, vm::ptr<CellSaveDataSetList> 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<CellSaveDataDirList>::make(setBuf->buf.addr());
auto dirList = vm::get_ptr<CellSaveDataDirList>(listGet->dirList.addr());
listGet->dirList.set(setBuf->buf.addr());
auto dirList = listGet->dirList.get_ptr();
for (u32 i=0; i<saveEntries.size(); i++) {
strcpy_trunc(dirList[i].dirName, saveEntries[i].dirName);
@ -376,12 +382,12 @@ int cellSaveDataListSave2(u32 version, vm::ptr<CellSaveDataSetList> setList, vm:
return CELL_SAVEDATA_ERROR_CBRESULT;
}
setSaveDataList(saveEntries, vm::ptr<CellSaveDataDirList>::make(listSet->fixedList.addr()), listSet->fixedListNum);
setSaveDataList(saveEntries, listSet->fixedList.to_le(), listSet->fixedListNum);
if (listSet->newData)
addNewSaveDataEntry(saveEntries, vm::ptr<CellSaveDataListNewData>::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<CellSaveDataSetList> setList, vm:
return ret;
}
int cellSaveDataListLoad2(u32 version, vm::ptr<CellSaveDataSetList> setList, vm::ptr<CellSaveDataSetBuf> setBuf,
vm::ptr<CellSaveDataListCallback> funcList, vm::ptr<CellSaveDataStatCallback> funcStat, vm::ptr<CellSaveDataFileCallback> funcFile,
u32 container, vm::ptr<void> userdata)
s32 cellSaveDataListLoad2(
u32 version,
vm::ptr<CellSaveDataSetList> setList,
vm::ptr<CellSaveDataSetBuf> setBuf,
vm::ptr<CellSaveDataListCallback> funcList,
vm::ptr<CellSaveDataStatCallback> funcStat,
vm::ptr<CellSaveDataFileCallback> funcFile,
u32 container,
vm::ptr<void> 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<CellSaveDataCBResult> result;
@ -446,8 +458,8 @@ int cellSaveDataListLoad2(u32 version, vm::ptr<CellSaveDataSetList> 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<CellSaveDataDirList>::make(setBuf->buf.addr());
auto dirList = vm::get_ptr<CellSaveDataDirList>(listGet->dirList.addr());
listGet->dirList.set(setBuf->buf.addr());
auto dirList = listGet->dirList.get_ptr();
for (u32 i=0; i<saveEntries.size(); i++) {
strcpy_trunc(dirList[i].dirName, saveEntries[i].dirName);
@ -462,12 +474,12 @@ int cellSaveDataListLoad2(u32 version, vm::ptr<CellSaveDataSetList> setList, vm:
return CELL_SAVEDATA_ERROR_CBRESULT;
}
setSaveDataList(saveEntries, vm::ptr<CellSaveDataDirList>::make(listSet->fixedList.addr()), listSet->fixedListNum);
setSaveDataList(saveEntries, listSet->fixedList.to_le(), listSet->fixedListNum);
if (listSet->newData)
addNewSaveDataEntry(saveEntries, vm::ptr<CellSaveDataListNewData>::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<CellSaveDataSetList> setList, vm:
return ret;
}
int cellSaveDataFixedSave2(u32 version, vm::ptr<CellSaveDataSetList> setList, vm::ptr<CellSaveDataSetBuf> setBuf,
vm::ptr<CellSaveDataFixedCallback> funcFixed, vm::ptr<CellSaveDataStatCallback> funcStat, vm::ptr<CellSaveDataFileCallback> funcFile,
u32 container, vm::ptr<void> userdata)
s32 cellSaveDataFixedSave2(
u32 version,
vm::ptr<CellSaveDataSetList> setList,
vm::ptr<CellSaveDataSetBuf> setBuf,
vm::ptr<CellSaveDataFixedCallback> funcFixed,
vm::ptr<CellSaveDataStatCallback> funcStat,
vm::ptr<CellSaveDataFileCallback> funcFile,
u32 container,
vm::ptr<void> 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<CellSaveDataCBResult> result;
@ -530,8 +548,8 @@ int cellSaveDataFixedSave2(u32 version, vm::ptr<CellSaveDataSetList> 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<CellSaveDataDirList>::make(setBuf->buf.addr());
auto dirList = vm::get_ptr<CellSaveDataDirList>(listGet->dirList.addr());
listGet->dirList.set(setBuf->buf.addr());
auto dirList = listGet->dirList.get_ptr();
for (u32 i = 0; i<saveEntries.size(); i++) {
strcpy_trunc(dirList[i].dirName, saveEntries[i].dirName);
strcpy_trunc(dirList[i].listParam, saveEntries[i].listParam);
@ -563,11 +581,17 @@ int cellSaveDataFixedSave2(u32 version, vm::ptr<CellSaveDataSetList> setList, v
return ret;
}
int cellSaveDataFixedLoad2(u32 version, vm::ptr<CellSaveDataSetList> setList, vm::ptr<CellSaveDataSetBuf> setBuf,
vm::ptr<CellSaveDataFixedCallback> funcFixed, vm::ptr<CellSaveDataStatCallback> funcStat, vm::ptr<CellSaveDataFileCallback> funcFile,
u32 container, vm::ptr<void> userdata)
s32 cellSaveDataFixedLoad2(
u32 version,
vm::ptr<CellSaveDataSetList> setList,
vm::ptr<CellSaveDataSetBuf> setBuf,
vm::ptr<CellSaveDataFixedCallback> funcFixed,
vm::ptr<CellSaveDataStatCallback> funcStat,
vm::ptr<CellSaveDataFileCallback> funcFile,
u32 container,
vm::ptr<void> 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<CellSaveDataCBResult> result;
@ -600,8 +624,8 @@ int cellSaveDataFixedLoad2(u32 version, vm::ptr<CellSaveDataSetList> 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<CellSaveDataDirList>::make(setBuf->buf.addr());
auto dirList = vm::get_ptr<CellSaveDataDirList>(listGet->dirList.addr());
listGet->dirList.set(setBuf->buf.addr());
auto dirList = listGet->dirList.get_ptr();
for (u32 i = 0; i<saveEntries.size(); i++) {
strcpy_trunc(dirList[i].dirName, saveEntries[i].dirName);
strcpy_trunc(dirList[i].listParam, saveEntries[i].listParam);
@ -633,11 +657,17 @@ int cellSaveDataFixedLoad2(u32 version, vm::ptr<CellSaveDataSetList> setList, v
return ret;
}
int cellSaveDataAutoSave2(u32 version, vm::ptr<const char> dirName, u32 errDialog, vm::ptr<CellSaveDataSetBuf> setBuf,
vm::ptr<CellSaveDataStatCallback> funcStat, vm::ptr<CellSaveDataFileCallback> funcFile,
u32 container, vm::ptr<void> userdata)
s32 cellSaveDataAutoSave2(
u32 version,
vm::ptr<const char> dirName,
u32 errDialog,
vm::ptr<CellSaveDataSetBuf> setBuf,
vm::ptr<CellSaveDataStatCallback> funcStat,
vm::ptr<CellSaveDataFileCallback> funcFile,
u32 container,
vm::ptr<void> 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<CellSaveDataCBResult> result;
@ -685,14 +715,20 @@ int cellSaveDataAutoSave2(u32 version, vm::ptr<const char> 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<const char> dirName, u32 errDialog, vm::ptr<CellSaveDataSetBuf> setBuf,
vm::ptr<CellSaveDataStatCallback> funcStat, vm::ptr<CellSaveDataFileCallback> funcFile,
u32 container, vm::ptr<void> userdata)
s32 cellSaveDataAutoLoad2(
u32 version,
vm::ptr<const char> dirName,
u32 errDialog,
vm::ptr<CellSaveDataSetBuf> setBuf,
vm::ptr<CellSaveDataStatCallback> funcStat,
vm::ptr<CellSaveDataFileCallback> funcFile,
u32 container,
vm::ptr<void> 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<CellSaveDataCBResult> result;
@ -715,7 +751,7 @@ int cellSaveDataAutoLoad2(u32 version, vm::ptr<const char> 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<const char> 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<CellSaveDataSetList> setList, vm::ptr<CellSaveDataSetBuf> setBuf, vm::ptr<CellSaveDataFixedCallback> funcFixed,
vm::ptr<CellSaveDataStatCallback> funcStat, vm::ptr<CellSaveDataFileCallback> funcFile, u32 container, vm::ptr<void> userdata)
s32 cellSaveDataListAutoSave(
u32 version,
u32 errDialog,
vm::ptr<CellSaveDataSetList> setList,
vm::ptr<CellSaveDataSetBuf> setBuf,
vm::ptr<CellSaveDataFixedCallback> funcFixed,
vm::ptr<CellSaveDataStatCallback> funcStat,
vm::ptr<CellSaveDataFileCallback> funcFile,
u32 container,
vm::ptr<void> 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<CellSaveDataCBResult> result;
@ -792,19 +836,10 @@ int cellSaveDataListAutoSave(u32 version, u32 errDialog, vm::ptr<CellSaveDataSet
// return CELL_SAVEDATA_ERROR_CBRESULT;
//}
//setSaveDataList(saveEntries, (u32)listSet->fixedList.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,18 +849,26 @@ int cellSaveDataListAutoSave(u32 version, u32 errDialog, vm::ptr<CellSaveDataSet
//}
///*if (statSet->setParam)
//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<CellSaveDataSetList> setList, vm::ptr<CellSaveDataSetBuf> setBuf, vm::ptr<CellSaveDataFixedCallback> funcFixed,
vm::ptr<CellSaveDataStatCallback> funcStat, vm::ptr<CellSaveDataFileCallback> funcFile, u32 container, vm::ptr<void> userdata)
s32 cellSaveDataListAutoLoad(
u32 version,
u32 errDialog,
vm::ptr<CellSaveDataSetList> setList,
vm::ptr<CellSaveDataSetBuf> setBuf,
vm::ptr<CellSaveDataFixedCallback> funcFixed,
vm::ptr<CellSaveDataStatCallback> funcStat,
vm::ptr<CellSaveDataFileCallback> funcFile,
u32 container,
vm::ptr<void> 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)",
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<CellSaveDataCBResult> result;
@ -876,193 +919,411 @@ int cellSaveDataListAutoLoad(u32 version, u32 errDialog, vm::ptr<CellSaveDataSet
// return CELL_SAVEDATA_ERROR_CBRESULT;
//}
//setSaveDataList(saveEntries, (u32)listSet->fixedList.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<CellSaveDataSetList> setList, vm::ptr<CellSaveDataSetBuf> setBuf, vm::ptr<CellSaveDataFixedCallback> funcFixed, vm::ptr<CellSaveDataDoneCallback> funcDone,
u32 container, u32 userdata_addr)
s32 cellSaveDataFixedDelete(
vm::ptr<CellSaveDataSetList> setList,
vm::ptr<CellSaveDataSetBuf> setBuf,
vm::ptr<CellSaveDataFixedCallback> funcFixed,
vm::ptr<CellSaveDataDoneCallback> funcDone,
u32 container,
vm::ptr<void> 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<CellSaveDataSetList> setList, vm::ptr<CellSaveDataSetBuf> setBuf, vm::ptr<CellSaveDataListCallback> funcList,
vm::ptr<CellSaveDataStatCallback> funcStat, vm::ptr<CellSaveDataFileCallback> funcFile, u32 container, u32 userdata_addr)
s32 cellSaveDataUserListSave(
u32 version,
u32 userId,
vm::ptr<CellSaveDataSetList> setList,
vm::ptr<CellSaveDataSetBuf> setBuf,
vm::ptr<CellSaveDataListCallback> funcList,
vm::ptr<CellSaveDataStatCallback> funcStat,
vm::ptr<CellSaveDataFileCallback> funcFile,
u32 container,
vm::ptr<void> 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<CellSaveDataSetList> setList, vm::ptr<CellSaveDataSetBuf> setBuf, vm::ptr<CellSaveDataListCallback> funcList,
vm::ptr<CellSaveDataStatCallback> funcStat, vm::ptr<CellSaveDataFileCallback> funcFile, u32 container, u32 userdata_addr)
s32 cellSaveDataUserListLoad(
u32 version,
u32 userId,
vm::ptr<CellSaveDataSetList> setList,
vm::ptr<CellSaveDataSetBuf> setBuf,
vm::ptr<CellSaveDataListCallback> funcList,
vm::ptr<CellSaveDataStatCallback> funcStat,
vm::ptr<CellSaveDataFileCallback> funcFile,
u32 container,
vm::ptr<void> 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<CellSaveDataSetList> setList, vm::ptr<CellSaveDataSetBuf> setBuf, vm::ptr<CellSaveDataFixedCallback> funcFixed,
vm::ptr<CellSaveDataStatCallback> funcStat, vm::ptr<CellSaveDataFileCallback> funcFile, u32 container, u32 userdata_addr)
s32 cellSaveDataUserFixedSave(
u32 version,
u32 userId,
vm::ptr<CellSaveDataSetList> setList,
vm::ptr<CellSaveDataSetBuf> setBuf,
vm::ptr<CellSaveDataFixedCallback> funcFixed,
vm::ptr<CellSaveDataStatCallback> funcStat,
vm::ptr<CellSaveDataFileCallback> funcFile,
u32 container,
vm::ptr<void> 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<CellSaveDataSetList> setList, vm::ptr<CellSaveDataSetBuf> setBuf, vm::ptr<CellSaveDataFixedCallback> funcFixed,
vm::ptr<CellSaveDataStatCallback> funcStat, vm::ptr<CellSaveDataFileCallback> funcFile, u32 container, u32 userdata_addr)
s32 cellSaveDataUserFixedLoad(
u32 version,
u32 userId,
vm::ptr<CellSaveDataSetList> setList,
vm::ptr<CellSaveDataSetBuf> setBuf,
vm::ptr<CellSaveDataFixedCallback> funcFixed,
vm::ptr<CellSaveDataStatCallback> funcStat,
vm::ptr<CellSaveDataFileCallback> funcFile,
u32 container,
vm::ptr<void> 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<CellSaveDataSetBuf> setBuf, vm::ptr<CellSaveDataStatCallback> funcStat,
vm::ptr<CellSaveDataFileCallback> funcFile, u32 container, u32 userdata_addr)
s32 cellSaveDataUserAutoSave(
u32 version,
u32 userId,
vm::ptr<const char> dirName,
u32 errDialog,
vm::ptr<CellSaveDataSetBuf> setBuf,
vm::ptr<CellSaveDataStatCallback> funcStat,
vm::ptr<CellSaveDataFileCallback> funcFile,
u32 container,
vm::ptr<void> 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<CellSaveDataSetBuf> setBuf, vm::ptr<CellSaveDataStatCallback> funcStat,
vm::ptr<CellSaveDataFileCallback> funcFile, u32 container, u32 userdata_addr)
s32 cellSaveDataUserAutoLoad(
u32 version,
u32 userId,
vm::ptr<const char> dirName,
u32 errDialog,
vm::ptr<CellSaveDataSetBuf> setBuf,
vm::ptr<CellSaveDataStatCallback> funcStat,
vm::ptr<CellSaveDataFileCallback> funcFile,
u32 container,
vm::ptr<void> 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<CellSaveDataSetList> setList, vm::ptr<CellSaveDataSetBuf> setBuf, vm::ptr<CellSaveDataFixedCallback> funcFixed,
vm::ptr<CellSaveDataStatCallback> funcStat, vm::ptr<CellSaveDataFileCallback> funcFile, u32 container, u32 userdata_addr)
s32 cellSaveDataUserListAutoSave(
u32 version,
u32 userId,
u32 errDialog,
vm::ptr<CellSaveDataSetList> setList,
vm::ptr<CellSaveDataSetBuf> setBuf,
vm::ptr<CellSaveDataFixedCallback> funcFixed,
vm::ptr<CellSaveDataStatCallback> funcStat,
vm::ptr<CellSaveDataFileCallback> funcFile,
u32 container,
vm::ptr<void> 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<CellSaveDataSetList> setList, vm::ptr<CellSaveDataSetBuf> setBuf, vm::ptr<CellSaveDataFixedCallback> funcFixed,
vm::ptr<CellSaveDataStatCallback> funcStat, vm::ptr<CellSaveDataFileCallback> funcFile, u32 container, u32 userdata_addr)
s32 cellSaveDataUserListAutoLoad(
u32 version,
u32 userId,
u32 errDialog,
vm::ptr<CellSaveDataSetList> setList,
vm::ptr<CellSaveDataSetBuf> setBuf,
vm::ptr<CellSaveDataFixedCallback> funcFixed,
vm::ptr<CellSaveDataStatCallback> funcStat,
vm::ptr<CellSaveDataFileCallback> funcFile,
u32 container,
vm::ptr<void> 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<CellSaveDataSetList> setList,
vm::ptr<CellSaveDataSetBuf> setBuf,
vm::ptr<CellSaveDataFixedCallback> funcFixed,
vm::ptr<CellSaveDataDoneCallback> funcDone,
u32 container,
vm::ptr<void> 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<CellSaveDataSetList> setList,
vm::ptr<CellSaveDataSetBuf> setBuf,
vm::ptr<CellSaveDataListCallback> funcList,
vm::ptr<CellSaveDataDoneCallback> funcDone,
u32 container,
vm::ptr<void> 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<CellSaveDataSetList> setList,
u32 maxSizeKB,
vm::ptr<CellSaveDataDoneCallback> funcDone,
u32 container,
vm::ptr<void> 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<CellSaveDataSetList> setList,
u32 maxSizeKB,
vm::ptr<CellSaveDataDoneCallback> funcDone,
u32 container,
vm::ptr<void> 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<const char> dirName,
u32 maxSizeKB,
vm::ptr<CellSaveDataDoneCallback> funcDone,
u32 container,
vm::ptr<void> 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<const char> dirName,
u32 maxSizeKB,
vm::ptr<CellSaveDataDoneCallback> funcDone,
u32 container,
vm::ptr<void> userdata)
{
UNIMPLEMENTED_FUNC(cellSysutil);
return CELL_SAVEDATA_RET_OK;
return CELL_OK;
}
int cellSaveDataGetListItem() //const char *dirName, CellSaveDataDirStat *dir, CellSaveDataSystemFileParam *sysFileParam, vm::ptr<u32> bind, vm::ptr<u32> sizeKB
s32 cellSaveDataGetListItem(
vm::ptr<const char> dirName,
vm::ptr<CellSaveDataDirStat> dir,
vm::ptr<CellSaveDataSystemFileParam> sysFileParam,
vm::ptr<u32> bind,
vm::ptr<u32> 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<CellSaveDataSetList> setList,
vm::ptr<CellSaveDataSetBuf> setBuf,
vm::ptr<CellSaveDataListCallback> funcList,
vm::ptr<CellSaveDataDoneCallback> funcDone,
u32 container,
vm::ptr<void> 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<CellSaveDataSetList> setList,
u32 maxSizeKB,
vm::ptr<CellSaveDataDoneCallback> funcDone,
u32 container,
vm::ptr<void> 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<CellSaveDataSetList> setList,
u32 maxSizeKB,
vm::ptr<CellSaveDataDoneCallback> funcDone,
u32 container,
vm::ptr<void> 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<const char> dirName,
u32 maxSizeKB,
vm::ptr<CellSaveDataDoneCallback> funcDone,
u32 container,
vm::ptr<void> 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<const char> dirName,
u32 maxSizeKB,
vm::ptr<CellSaveDataDoneCallback> funcDone,
u32 container,
vm::ptr<void> 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<u32> bind, vm::ptr<u32> sizeKB
s32 cellSaveDataUserGetListItem(
u32 userId,
vm::ptr<const char> dirName,
vm::ptr<CellSaveDataDirStat> dir,
vm::ptr<CellSaveDataSystemFileParam> sysFileParam,
vm::ptr<u32> bind,
vm::ptr<u32> 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:
}

View file

@ -279,35 +279,3 @@ struct SaveDataEntry
u32 iconBufSize;
bool isNew;
};
// Function declarations
int cellSaveDataListSave2(u32 version, vm::ptr<CellSaveDataSetList> setList, vm::ptr<CellSaveDataSetBuf> setBuf,
vm::ptr<CellSaveDataListCallback> funcList, vm::ptr<CellSaveDataStatCallback> funcStat, vm::ptr<CellSaveDataFileCallback> funcFile,
u32 container, vm::ptr<void> userdata);
int cellSaveDataListLoad2(u32 version, vm::ptr<CellSaveDataSetList> setList, vm::ptr<CellSaveDataSetBuf> setBuf,
vm::ptr<CellSaveDataListCallback> funcList, vm::ptr<CellSaveDataStatCallback> funcStat, vm::ptr<CellSaveDataFileCallback> funcFile,
u32 container, vm::ptr<void> userdata);
int cellSaveDataFixedSave2(u32 version, vm::ptr<CellSaveDataSetList> setList, vm::ptr<CellSaveDataSetBuf> setBuf,
vm::ptr<CellSaveDataFixedCallback> funcFixed, vm::ptr<CellSaveDataStatCallback> funcStat, vm::ptr<CellSaveDataFileCallback> funcFile,
u32 container, vm::ptr<void> userdata);
int cellSaveDataFixedLoad2(u32 version, vm::ptr<CellSaveDataSetList> setList, vm::ptr<CellSaveDataSetBuf> setBuf,
vm::ptr<CellSaveDataFixedCallback> funcFixed, vm::ptr<CellSaveDataStatCallback> funcStat, vm::ptr<CellSaveDataFileCallback> funcFile,
u32 container, vm::ptr<void> userdata);
int cellSaveDataAutoSave2(u32 version, vm::ptr<const char> dirName, u32 errDialog, vm::ptr<CellSaveDataSetBuf> setBuf,
vm::ptr<CellSaveDataStatCallback> funcStat, vm::ptr<CellSaveDataFileCallback> funcFile,
u32 container, vm::ptr<void> userdata);
int cellSaveDataAutoLoad2(u32 version, vm::ptr<const char> dirName, u32 errDialog, vm::ptr<CellSaveDataSetBuf> setBuf,
vm::ptr<CellSaveDataStatCallback> funcStat, vm::ptr<CellSaveDataFileCallback> funcFile,
u32 container, vm::ptr<void> userdata);
int cellSaveDataListAutoSave(u32 version, u32 errDialog, vm::ptr<CellSaveDataSetList> setList, vm::ptr<CellSaveDataSetBuf> setBuf, vm::ptr<CellSaveDataFixedCallback> funcFixed,
vm::ptr<CellSaveDataStatCallback> funcStat, vm::ptr<CellSaveDataFileCallback> funcFile, u32 container, vm::ptr<void> userdata);
int cellSaveDataListAutoLoad(u32 version, u32 errDialog, vm::ptr<CellSaveDataSetList> setList, vm::ptr<CellSaveDataSetBuf> setBuf, vm::ptr<CellSaveDataFixedCallback> funcFixed,
vm::ptr<CellSaveDataStatCallback> funcStat, vm::ptr<CellSaveDataFileCallback> funcFile, u32 container, vm::ptr<void> userdata);

View file

@ -34,7 +34,7 @@ s64 spursCreateLv2EventQueue(vm::ptr<CellSpurs> spurs, u32& queue_id, vm::ptr<u8
vm::var<be_t<u32>> queue;
s32 res = cb_call<s32, vm::ptr<CellSpurs>, vm::ptr<u32>, vm::ptr<u8>, 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<s32, vm::ptr<CellSpurs>, 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<s32, vm::ptr<CellSpurs>, 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<CellSpurs> spurs, vm::ptr<const Cel
attr->m.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<CellSpurs> spurs, vm::ptr<const Ce
attr->m.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<CellSpursAttribute>
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<CellSpursAttribute> 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<CellSpursAttribute> 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<CellSpurs> spurs, u32 queue, vm::ptr<u8> 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<CellSpurs> 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<s32, vm::ptr<CellSpurs>, vm::ptr<u32>, vm::ptr<const void>, 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<u32>& 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<CellSpurs> 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<CellSpurs> spurs, vm::ptr<vm::bptr<CellSpur
return CELL_SPURS_POLICY_MODULE_ERROR_ALIGN;
}
flag->set(Memory.RealToVirtualAddr(&spurs->m.wklFlag));
flag->set(vm::get_addr(&spurs->m.wklFlag));
return CELL_OK;
}
@ -1551,11 +1551,11 @@ s64 cellSpursReadyCountStore(vm::ptr<CellSpurs> 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<CellSpurs> spurs, vm::ptr<CellSpursTaskset> 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

View file

@ -499,12 +499,12 @@ struct CellSpurs
__forceinline vm::ptr<sys_lwmutex_t> get_lwmutex()
{
return vm::ptr<sys_lwmutex_t>::make(Memory.RealToVirtualAddr(&m.mutex));
return vm::ptr<sys_lwmutex_t>::make(vm::get_addr(&m.mutex));
}
__forceinline vm::ptr<sys_lwcond_t> get_lwcond()
{
return vm::ptr<sys_lwcond_t>::make(Memory.RealToVirtualAddr(&m.cond));
return vm::ptr<sys_lwcond_t>::make(vm::get_addr(&m.cond));
}
};

View file

@ -308,7 +308,7 @@ s32 cellSyncRwmInitialize(vm::ptr<CellSyncRwm> rwm, vm::ptr<void> 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<CellSyncRwm> rwm, vm::ptr<void> 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<CellSyncRwm> rwm, vm::ptr<void> 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<CellSyncRwm> rwm, vm::ptr<const void> 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<CellSyncLFQueue> queue, vm::ptr<u8> 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<CellSyncLFQueue> 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<CellSyncLFQueue> 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<CellSyncLFQueue> 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<CellSyncLFQueue> queue, s32 poi
return syncLFQueueCompletePushPointer2(queue, pointer, fpSendSignal);
}
s32 _cellSyncLFQueuePushBody(vm::ptr<CellSyncLFQueue> queue, vm::ptr<const void> buffer, u32 isBlocking)
s32 _cellSyncLFQueuePushBody(PPUThread& CPU, vm::ptr<CellSyncLFQueue> queue, vm::ptr<const void> 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<CellSyncLFQueue> queue, vm::ptr<const void>
}
s32 position;
//syncLFQueueDump(queue);
#ifdef PRX_DEBUG
vm::var<be_t<s32>> position_v;
vm::stackvar<be_t<s32>> position_v(CPU);
#endif
while (true)
{
@ -1314,9 +1312,9 @@ s32 _cellSyncLFQueuePushBody(vm::ptr<CellSyncLFQueue> queue, vm::ptr<const void>
if (queue->m_direction != CELL_SYNC_QUEUE_ANY2ANY)
{
#ifdef PRX_DEBUG_XXX
res = cb_caller<s32, vm::ptr<CellSyncLFQueue>, u32, u32, u64>::call(GetCurrentPPUThread(), libsre + 0x24B0, libsre_rtoc,
res = cb_call<s32, vm::ptr<CellSyncLFQueue>, 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<CellSyncLFQueue> queue, vm::ptr<const void>
else
{
#ifdef PRX_DEBUG
res = cb_call<s32, vm::ptr<CellSyncLFQueue>, u32, u32, u64>(GetCurrentPPUThread(), libsre + 0x3050, libsre_rtoc,
res = cb_call<s32, vm::ptr<CellSyncLFQueue>, 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<CellSyncLFQueue> queue, vm::ptr<const void>
}
}
s32 depth = (u32)queue->m_depth;
s32 size = (u32)queue->m_size;
memcpy(vm::get_ptr<void>((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<u64>((queue->m_buffer.addr() & ~1ull) + size * (position >= depth ? position - depth : position));
memcpy(vm::get_ptr<void>(addr), buffer.get_ptr(), size);
s32 res;
if (queue->m_direction != CELL_SYNC_QUEUE_ANY2ANY)
{
#ifdef PRX_DEBUG_XXX
res = cb_caller<s32, vm::ptr<CellSyncLFQueue>, s32, u64>::call(GetCurrentPPUThread(), libsre + 0x26C0, libsre_rtoc,
res = cb_call<s32, vm::ptr<CellSyncLFQueue>, s32, u64>(CPU, libsre + 0x26C0, libsre_rtoc,
queue, position, 0);
#else
res = syncLFQueueCompletePushPointer(queue, position, nullptr);
@ -1369,14 +1365,13 @@ s32 _cellSyncLFQueuePushBody(vm::ptr<CellSyncLFQueue> queue, vm::ptr<const void>
else
{
#ifdef PRX_DEBUG
res = cb_call<s32, vm::ptr<CellSyncLFQueue>, s32, u64>(GetCurrentPPUThread(), libsre + 0x355C, libsre_rtoc,
res = cb_call<s32, vm::ptr<CellSyncLFQueue>, 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<CellSyncLFQueue> 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<CellSyncLFQueue> 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<CellSyncLFQueue> 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<CellSyncLFQueue> queue, s32 poin
return syncLFQueueCompletePopPointer2(queue, pointer, fpSendSignal, noQueueFull);
}
s32 _cellSyncLFQueuePopBody(vm::ptr<CellSyncLFQueue> queue, vm::ptr<void> buffer, u32 isBlocking)
s32 _cellSyncLFQueuePopBody(PPUThread& CPU, vm::ptr<CellSyncLFQueue> queue, vm::ptr<void> 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<CellSyncLFQueue> queue, vm::ptr<void> buffer
s32 position;
#ifdef PRX_DEBUG
vm::var<be_t<s32>> position_v;
vm::stackvar<be_t<s32>> position_v(CPU);
#endif
while (true)
{
@ -1693,9 +1688,9 @@ s32 _cellSyncLFQueuePopBody(vm::ptr<CellSyncLFQueue> queue, vm::ptr<void> buffer
if (queue->m_direction != CELL_SYNC_QUEUE_ANY2ANY)
{
#ifdef PRX_DEBUG_XXX
res = cb_caller<s32, vm::ptr<CellSyncLFQueue>, u32, u32, u64, u64>::call(GetCurrentPPUThread(), libsre + 0x2A90, libsre_rtoc,
res = cb_call<s32, vm::ptr<CellSyncLFQueue>, 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<CellSyncLFQueue> queue, vm::ptr<void> buffer
else
{
#ifdef PRX_DEBUG
res = cb_call<s32, vm::ptr<CellSyncLFQueue>, u32, u32, u64>(GetCurrentPPUThread(), libsre + 0x39AC, libsre_rtoc,
res = cb_call<s32, vm::ptr<CellSyncLFQueue>, 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<CellSyncLFQueue> queue, vm::ptr<void> buffer
}
}
s32 depth = (u32)queue->m_depth;
s32 size = (u32)queue->m_size;
memcpy(buffer.get_ptr(), vm::get_ptr<void>((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<u64>((queue->m_buffer.addr() & ~1) + size * (position >= depth ? position - depth : position));
memcpy(buffer.get_ptr(), vm::get_ptr<void>(addr), size);
s32 res;
if (queue->m_direction != CELL_SYNC_QUEUE_ANY2ANY)
{
#ifdef PRX_DEBUG_XXX
res = cb_caller<s32, vm::ptr<CellSyncLFQueue>, s32, u64, u64>::call(GetCurrentPPUThread(), libsre + 0x2CA8, libsre_rtoc,
res = cb_call<s32, vm::ptr<CellSyncLFQueue>, 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<CellSyncLFQueue> queue, vm::ptr<void> buffer
else
{
#ifdef PRX_DEBUG
res = cb_call<s32, vm::ptr<CellSyncLFQueue>, s32, u64, u64>(GetCurrentPPUThread(), libsre + 0x3EB8, libsre_rtoc,
res = cb_call<s32, vm::ptr<CellSyncLFQueue>, s32, u64, u64>(CPU, libsre + 0x3EB8, libsre_rtoc,
queue, position, 0, 0);
#else
res = syncLFQueueCompletePopPointer2(queue, position, nullptr, 0);

View file

@ -18,7 +18,6 @@
#include "cellMsgDialog.h"
#include "cellGame.h"
#include "cellSysutil.h"
#include "cellSaveData.h"
typedef void (*CellHddGameStatCallback)(vm::ptr<CellHddGameCBResult> cbResult, vm::ptr<CellHddGameStatGet> get, vm::ptr<CellHddGameStatSet> set);
@ -241,7 +240,7 @@ int cellVideoOutGetConfiguration(u32 videoOut, vm::ptr<CellVideoOutConfiguration
int cellVideoOutGetDeviceInfo(u32 videoOut, u32 deviceIndex, vm::ptr<CellVideoOutDeviceInfo> 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::ptr<CellAudioOu
info->state = 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<const char> 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<const CellWebBrowserConfig2> config, v
return CELL_OK;
}
extern int cellGameDataCheckCreate2(u32 version, vm::ptr<const char> dirName, u32 errDialog,
extern int cellGameDataCheckCreate2(PPUThread& CPU, u32 version, vm::ptr<const char> dirName, u32 errDialog,
vm::ptr<void(*)(vm::ptr<CellGameDataCBResult> cbResult, vm::ptr<CellGameDataStatGet> get, vm::ptr<CellGameDataStatSet> set)> funcStat, u32 container);
extern int cellGameDataCheckCreate(u32 version, vm::ptr<const char> dirName, u32 errDialog,
extern int cellGameDataCheckCreate(PPUThread& CPU, u32 version, vm::ptr<const char> dirName, u32 errDialog,
vm::ptr<void(*)(vm::ptr<CellGameDataCBResult> cbResult, vm::ptr<CellGameDataStatGet> get, vm::ptr<CellGameDataStatSet> 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);

View file

@ -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;
}
@ -545,12 +551,8 @@ u32 vdecOpen(VideoDecoder* vdec_ptr)
}
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<const CellVdecType> type, vm::ptr<const CellVdecResourc
cellVdec->Warning("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<CellVdecCbMsg>::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<const CellVdecTypeEx> type, vm::ptr<const CellVdecRes
cellVdec->Warning("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<CellVdecCbMsg>::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<const CellVdecPicFormat> 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<u32> 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;

View file

@ -1,7 +1,5 @@
#pragma once
#define a128(x) ((x + 127) & (~127))
// Error Codes
enum
{

View file

@ -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<CellSurMixerNotifyCallbackFunction> surMixerCb;
vm::ptr<void> surMixerCbArg;
std::mutex mixer_mutex;
@ -23,8 +21,7 @@ std::vector<SSPlayer> ssp;
int cellAANAddData(u32 aan_handle, u32 aan_port, u32 offset, vm::ptr<float> 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<float> 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<const CellSurMixerConfig> 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<const CellSurMixerConfig> 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<const CellSurMixerConfig> config)
//u64 stamp2 = get_system_time();
auto buf = vm::get_ptr<be_t<float>>(m_config.m_buffer + (128 * 1024 * SUR_PORT) + (mixcount % port.block) * port.channel * 256 * sizeof(float));
auto buf = vm::get_ptr<be_t<float>>(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<const CellSurMixerConfig> 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<float> 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<u64> 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,

View file

@ -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<s32> 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

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