mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-20 19:45:20 +00:00
Fixed conflicts
This commit is contained in:
commit
339e40d423
458 changed files with 52441 additions and 34033 deletions
10
.gitignore
vendored
10
.gitignore
vendored
|
@ -30,6 +30,8 @@
|
|||
*.dump
|
||||
*.wav
|
||||
|
||||
/build
|
||||
|
||||
/libs
|
||||
/ipch
|
||||
/rpcs3/Debug
|
||||
|
@ -61,4 +63,10 @@ rpcs3/git-version.h
|
|||
!/bin/dev_hdd0/game/TEST12345/
|
||||
|
||||
# Ignore other system generated files
|
||||
bin/dev_hdd0/log.txt
|
||||
bin/dev_hdd0/*.txt
|
||||
x64/Debug/emucore.lib
|
||||
x64/Release/emucore.lib
|
||||
rpcs3/x64/*
|
||||
|
||||
.DS_Store
|
||||
rpcs3/Emu/SysCalls/Modules/prx_*.h
|
||||
|
|
18
.travis.yml
18
.travis.yml
|
@ -8,28 +8,30 @@ branches:
|
|||
only:
|
||||
- master
|
||||
|
||||
git:
|
||||
submodules: false
|
||||
|
||||
before_install:
|
||||
- echo "yes" | sudo apt-key adv --fetch-keys http://repos.codelite.org/CodeLite.asc
|
||||
- echo "yes" | sudo apt-add-repository 'deb http://repos.codelite.org/wx3.0/ubuntu/ precise universe'
|
||||
- sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
|
||||
- sudo apt-get update
|
||||
- sudo apt-get install libwxgtk3.0-dev libopenal-dev freeglut3-dev libglew-dev
|
||||
- sudo apt-get install libwxgtk3.0-dev libopenal-dev freeglut3-dev libglew-dev libc6-dev
|
||||
- sudo apt-get install aria2 -qq
|
||||
- download_extract() { aria2c -x 16 $1 -o $2 && tar -xf $2; }
|
||||
- if [ "$CXX" = "g++" ]; then sudo apt-get install -qq g++-4.8; export CXX="g++-4.8" CC="gcc-4.8"; else sudo apt-get install libstdc++-4.8-dev; fi
|
||||
# Travis uses CMake 2.8.7. We require 2.8.8. Grab latest
|
||||
- sudo apt-get install -qq g++-4.8
|
||||
- if [ "$CXX" = "g++" ]; then export CXX="g++-4.8" CC="gcc-4.8"; fi
|
||||
- sudo apt-get install lib32stdc++6 -qq &&
|
||||
aria2c -x 16 http://www.cmake.org/files/v2.8/cmake-2.8.12.1-Linux-i386.sh &&
|
||||
chmod a+x cmake-2.8.12.1-Linux-i386.sh &&
|
||||
sudo ./cmake-2.8.12.1-Linux-i386.sh --skip-license --prefix=/usr;
|
||||
aria2c -x 16 http://www.cmake.org/files/v3.0/cmake-3.0.0-Linux-i386.sh &&
|
||||
chmod a+x cmake-3.0.0-Linux-i386.sh &&
|
||||
sudo ./cmake-3.0.0-Linux-i386.sh --skip-license --prefix=/usr;
|
||||
|
||||
before_script:
|
||||
- git submodule update --init --recursive
|
||||
- git submodule update --init asmjit ffmpeg
|
||||
- mkdir build
|
||||
- cd build
|
||||
- cmake ..
|
||||
|
||||
script:
|
||||
- make
|
||||
- make -j 4
|
||||
|
||||
|
|
|
@ -2,5 +2,14 @@ cmake_minimum_required(VERSION 2.8)
|
|||
|
||||
set(ASMJIT_STATIC TRUE)
|
||||
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
message(STATUS "No build type selected, default to Release")
|
||||
set(CMAKE_BUILD_TYPE "Release")
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
message( FATAL_ERROR "RPCS3 can only be compiled on 64-bit platforms." )
|
||||
endif()
|
||||
|
||||
add_subdirectory( asmjit )
|
||||
add_subdirectory( rpcs3 )
|
||||
|
|
Binary file not shown.
|
@ -17,7 +17,6 @@ If you want to contribute please take a took at the [Coding Style](https://githu
|
|||
|
||||
__Windows__
|
||||
* [Visual C++ Redistributable Packages for Visual Studio 2013](http://www.microsoft.com/en-us/download/details.aspx?id=40784)
|
||||
* [OpenAL binaries](http://kcat.strangesoft.net/openal.html): download and copy `Win64\soft_oal.dll` to `rpcs3\bin\`
|
||||
|
||||
__Linux__
|
||||
* Debian & Ubuntu: `sudo apt-get install libopenal-dev libwxgtk3.0-dev build-essential`
|
||||
|
|
|
@ -1,88 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
template<typename T, size_t size> class SizedStack
|
||||
{
|
||||
T m_ptr[size];
|
||||
uint m_count;
|
||||
|
||||
public:
|
||||
SizedStack()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
~SizedStack()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
m_count = 0;
|
||||
}
|
||||
|
||||
bool Pop(T& dst)
|
||||
{
|
||||
if(!m_count)
|
||||
return false;
|
||||
|
||||
dst = m_ptr[--m_count];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Push(const T& src)
|
||||
{
|
||||
if(m_count + 1 > size)
|
||||
return false;
|
||||
|
||||
m_ptr[m_count++] = src;
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t GetFreeCount() const
|
||||
{
|
||||
return size - m_count;
|
||||
}
|
||||
|
||||
size_t GetCount() const
|
||||
{
|
||||
return m_count;
|
||||
}
|
||||
|
||||
size_t GetMaxCount() const
|
||||
{
|
||||
return size;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T> struct ScopedPtr
|
||||
{
|
||||
private:
|
||||
T* m_ptr;
|
||||
|
||||
public:
|
||||
ScopedPtr() : m_ptr(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
ScopedPtr(T* ptr) : m_ptr(ptr)
|
||||
{
|
||||
}
|
||||
|
||||
~ScopedPtr()
|
||||
{
|
||||
Swap(nullptr);
|
||||
}
|
||||
|
||||
operator T*() { return m_ptr; }
|
||||
operator const T*() const { return m_ptr; }
|
||||
|
||||
T* operator ->() { return m_ptr; }
|
||||
const T* operator ->() const { return m_ptr; }
|
||||
|
||||
void Swap(T* ptr)
|
||||
{
|
||||
delete m_ptr;
|
||||
m_ptr = ptr;
|
||||
}
|
||||
};
|
128
Utilities/AutoPause.cpp
Normal file
128
Utilities/AutoPause.cpp
Normal file
|
@ -0,0 +1,128 @@
|
|||
#include "stdafx.h"
|
||||
#include "rpcs3/Ini.h"
|
||||
#include "AutoPause.h"
|
||||
#include "Utilities/Log.h"
|
||||
#include "Utilities/rFile.h"
|
||||
#include "Emu/System.h"
|
||||
|
||||
using namespace Debug;
|
||||
|
||||
//Even different from those tutorials on webpages, i use the method similiar from Log.h
|
||||
//TODO:: Question: Does such a Singleton struct get fully deallocated after its pointer?
|
||||
AutoPause* gAutoPause = nullptr;
|
||||
|
||||
AutoPause& AutoPause::getInstance(void)
|
||||
{
|
||||
if (!gAutoPause)
|
||||
{
|
||||
gAutoPause = new AutoPause();
|
||||
}
|
||||
return *gAutoPause;
|
||||
}
|
||||
|
||||
//Still use binary format. Default Setting should be "disable all auto pause".
|
||||
AutoPause::AutoPause(void)
|
||||
{
|
||||
m_pause_function.reserve(16);
|
||||
m_pause_syscall.reserve(16);
|
||||
initialized = false;
|
||||
//Reload(false, false);
|
||||
Reload();
|
||||
}
|
||||
|
||||
//Notice: I would not allow to write the binary to file in this command.
|
||||
AutoPause::~AutoPause(void)
|
||||
{
|
||||
initialized = false;
|
||||
m_pause_function.clear();
|
||||
m_pause_syscall.clear();
|
||||
m_pause_function_enable = false;
|
||||
m_pause_syscall_enable = false;
|
||||
}
|
||||
|
||||
//Load Auto Pause Configuration from file "pause.bin"
|
||||
//This would be able to create in a GUI window.
|
||||
void AutoPause::Reload(void)
|
||||
{
|
||||
if (rExists("pause.bin"))
|
||||
{
|
||||
m_pause_function.clear();
|
||||
m_pause_function.reserve(16);
|
||||
m_pause_syscall.clear();
|
||||
m_pause_syscall.reserve(16);
|
||||
|
||||
rFile list;
|
||||
list.Open("pause.bin", rFile::read);
|
||||
//System calls ID and Function calls ID are all u32 iirc.
|
||||
u32 num;
|
||||
size_t fmax = list.Length();
|
||||
size_t fcur = 0;
|
||||
list.Seek(0);
|
||||
while (fcur <= fmax - sizeof(u32))
|
||||
{
|
||||
list.Read(&num, sizeof(u32));
|
||||
fcur += sizeof(u32);
|
||||
if (num == 0xFFFFFFFF) break;
|
||||
|
||||
if (num < 1024)
|
||||
{
|
||||
//Less than 1024 - be regarded as a system call.
|
||||
//emplace_back may not cause reductant move/copy operation.
|
||||
m_pause_syscall.emplace_back(num);
|
||||
LOG_WARNING(HLE, "Auto Pause: Find System Call ID %x", num);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pause_function.emplace_back(num);
|
||||
LOG_WARNING(HLE, "Auto Pause: Find Function Call ID %x", num);
|
||||
}
|
||||
}
|
||||
list.Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_WARNING(HLE, "No pause.bin found, Auto Pause will not work.");
|
||||
}
|
||||
m_pause_syscall_enable = Ini.DBGAutoPauseSystemCall.GetValue();
|
||||
m_pause_function_enable = Ini.DBGAutoPauseFunctionCall.GetValue();
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
void AutoPause::TryPause(u32 code) {
|
||||
if (code < 1024)
|
||||
{
|
||||
//Would first check Enable setting. Then the list length.
|
||||
if ((!m_pause_syscall_enable)
|
||||
|| (m_pause_syscall.size() <= 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < m_pause_syscall.size(); ++i)
|
||||
{
|
||||
if (code == m_pause_syscall[i])
|
||||
{
|
||||
Emu.Pause();
|
||||
LOG_ERROR(HLE, "Auto Pause Triggered: System call %x", code); //Used Error
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Well similiar.. Seperate the list caused by possible setting difference.
|
||||
if ((!m_pause_function_enable)
|
||||
|| (m_pause_function.size() <= 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < m_pause_function.size(); ++i)
|
||||
{
|
||||
if (code == m_pause_function[i])
|
||||
{
|
||||
Emu.Pause();
|
||||
LOG_ERROR(HLE, "Auto Pause Triggered: Function call %x", code); //Used Error
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
24
Utilities/AutoPause.h
Normal file
24
Utilities/AutoPause.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
//Regarded as a Debugger Enchantment
|
||||
namespace Debug {
|
||||
//To store the pause function/call id, and let those pause there.
|
||||
//Would be with a GUI to configure those.
|
||||
struct AutoPause
|
||||
{
|
||||
std::vector<u32> m_pause_syscall;
|
||||
std::vector<u32> m_pause_function;
|
||||
bool initialized;
|
||||
bool m_pause_syscall_enable;
|
||||
bool m_pause_function_enable;
|
||||
|
||||
AutoPause();
|
||||
~AutoPause();
|
||||
public:
|
||||
static AutoPause& getInstance(void);
|
||||
|
||||
void Reload(void);
|
||||
|
||||
void TryPause(u32 code);
|
||||
};
|
||||
}
|
|
@ -1,26 +1,242 @@
|
|||
#pragma once
|
||||
|
||||
#include "Utilities/GNU.h"
|
||||
#include <emmintrin.h>
|
||||
|
||||
union u128
|
||||
{
|
||||
struct
|
||||
{
|
||||
u64 hi;
|
||||
u64 lo;
|
||||
};
|
||||
|
||||
u64 _u64[2];
|
||||
s64 _s64[2];
|
||||
u32 _u32[4];
|
||||
s32 _s32[4];
|
||||
u16 _u16[8];
|
||||
s16 _s16[8];
|
||||
u8 _u8[16];
|
||||
s8 _s8[16];
|
||||
float _f[4];
|
||||
double _d[2];
|
||||
__m128 xmm;
|
||||
|
||||
class bit_array_128
|
||||
{
|
||||
u64 data[2];
|
||||
|
||||
public:
|
||||
class bit_element
|
||||
{
|
||||
u64& data;
|
||||
const u64 mask;
|
||||
|
||||
public:
|
||||
bit_element(u64& data, const u64 mask)
|
||||
: data(data)
|
||||
, mask(mask)
|
||||
{
|
||||
}
|
||||
|
||||
__forceinline operator bool() const
|
||||
{
|
||||
return (data & mask) != 0;
|
||||
}
|
||||
|
||||
__forceinline bit_element& operator = (const bool right)
|
||||
{
|
||||
if (right)
|
||||
{
|
||||
data |= mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
data &= ~mask;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
__forceinline bit_element& operator = (const bit_element& right)
|
||||
{
|
||||
if (right)
|
||||
{
|
||||
data |= mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
data &= ~mask;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
bit_element operator [] (u32 index)
|
||||
{
|
||||
assert(index < 128);
|
||||
return bit_element(data[index / 64], 1ull << (index % 64));
|
||||
}
|
||||
|
||||
const bool operator [] (u32 index) const
|
||||
{
|
||||
assert(index < 128);
|
||||
return (data[index / 64] & (1ull << (index % 64))) != 0;
|
||||
}
|
||||
|
||||
} _bit;
|
||||
|
||||
//operator u64() const { return _u64[0]; }
|
||||
//operator u32() const { return _u32[0]; }
|
||||
//operator u16() const { return _u16[0]; }
|
||||
//operator u8() const { return _u8[0]; }
|
||||
|
||||
//operator bool() const { return _u64[0] != 0 || _u64[1] != 0; }
|
||||
|
||||
static u128 from128(u64 hi, u64 lo)
|
||||
{
|
||||
u128 ret = { hi, lo };
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u128 from64(u64 src)
|
||||
{
|
||||
u128 ret = { 0, src };
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u128 from32(u32 src)
|
||||
{
|
||||
u128 ret;
|
||||
ret._u32[0] = src;
|
||||
ret._u32[1] = 0;
|
||||
ret._u32[2] = 0;
|
||||
ret._u32[3] = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u128 fromBit(u32 bit)
|
||||
{
|
||||
u128 ret;
|
||||
ret._bit[bit] = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void setBit(u32 bit)
|
||||
{
|
||||
_bit[bit] = true;
|
||||
}
|
||||
|
||||
bool operator == (const u128& right) const
|
||||
{
|
||||
return (lo == right.lo) && (hi == right.hi);
|
||||
}
|
||||
|
||||
bool operator != (const u128& right) const
|
||||
{
|
||||
return (lo != right.lo) || (hi != right.hi);
|
||||
}
|
||||
|
||||
u128 operator | (const u128& right) const
|
||||
{
|
||||
return from128(hi | right.hi, lo | right.lo);
|
||||
}
|
||||
|
||||
u128 operator & (const u128& right) const
|
||||
{
|
||||
return from128(hi & right.hi, lo & right.lo);
|
||||
}
|
||||
|
||||
u128 operator ^ (const u128& right) const
|
||||
{
|
||||
return from128(hi ^ right.hi, lo ^ right.lo);
|
||||
}
|
||||
|
||||
u128 operator ~ () const
|
||||
{
|
||||
return from128(~hi, ~lo);
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
hi = lo = 0;
|
||||
}
|
||||
|
||||
std::string to_hex() const
|
||||
{
|
||||
return fmt::Format("%08x%08x%08x%08x", _u32[3], _u32[2], _u32[1], _u32[0]);
|
||||
}
|
||||
|
||||
std::string to_xyzw() const
|
||||
{
|
||||
return fmt::Format("x: %g y: %g z: %g w: %g", _f[3], _f[2], _f[1], _f[0]);
|
||||
}
|
||||
|
||||
static __forceinline u128 byteswap(const u128 val)
|
||||
{
|
||||
u128 ret;
|
||||
ret.lo = _byteswap_uint64(val.hi);
|
||||
ret.hi = _byteswap_uint64(val.lo);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
#define re16(val) _byteswap_ushort(val)
|
||||
#define re32(val) _byteswap_ulong(val)
|
||||
#define re64(val) _byteswap_uint64(val)
|
||||
#define re128(val) u128::byteswap(val)
|
||||
|
||||
template<typename T, int size = sizeof(T)> struct se_t;
|
||||
template<typename T> struct se_t<T, 1> { static __forceinline void func(T& dst, const T src) { (u8&)dst = (u8&)src; } };
|
||||
template<typename T> struct se_t<T, 2> { static __forceinline void func(T& dst, const T src) { (u16&)dst = _byteswap_ushort((u16&)src); } };
|
||||
template<typename T> struct se_t<T, 4> { static __forceinline void func(T& dst, const T src) { (u32&)dst = _byteswap_ulong((u32&)src); } };
|
||||
template<typename T> struct se_t<T, 8> { static __forceinline void func(T& dst, const T src) { (u64&)dst = _byteswap_uint64((u64&)src); } };
|
||||
|
||||
template<typename T> struct se_t<T, 1>
|
||||
{
|
||||
static __forceinline T func(const T src)
|
||||
{
|
||||
return src;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, s64 _value, int size = sizeof(T)> struct const_se_t;
|
||||
template<typename T, s64 _value> struct const_se_t<T, _value, 1>
|
||||
template<typename T> struct se_t<T, 2>
|
||||
{
|
||||
static __forceinline T func(const T src)
|
||||
{
|
||||
const u16 res = _byteswap_ushort((u16&)src);
|
||||
return (T&)res;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T> struct se_t<T, 4>
|
||||
{
|
||||
static __forceinline T func(const T src)
|
||||
{
|
||||
const u32 res = _byteswap_ulong((u32&)src);
|
||||
return (T&)res;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T> struct se_t<T, 8>
|
||||
{
|
||||
static __forceinline T func(const T src)
|
||||
{
|
||||
const u64 res = _byteswap_uint64((u64&)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>
|
||||
{
|
||||
static const T value = (T)_value;
|
||||
};
|
||||
|
||||
template<typename T, s64 _value> struct const_se_t<T, _value, 2>
|
||||
template<typename T, u64 _value> struct const_se_t<T, _value, 2>
|
||||
{
|
||||
static const T value = ((_value >> 8) & 0xff) | ((_value << 8) & 0xff00);
|
||||
};
|
||||
|
||||
template<typename T, s64 _value> struct const_se_t<T, _value, 4>
|
||||
template<typename T, u64 _value> struct const_se_t<T, _value, 4>
|
||||
{
|
||||
static const T value =
|
||||
((_value >> 24) & 0x000000ff) |
|
||||
|
@ -29,7 +245,7 @@ template<typename T, s64 _value> struct const_se_t<T, _value, 4>
|
|||
((_value << 24) & 0xff000000);
|
||||
};
|
||||
|
||||
template<typename T, s64 _value> struct const_se_t<T, _value, 8>
|
||||
template<typename T, u64 _value> struct const_se_t<T, _value, 8>
|
||||
{
|
||||
static const T value =
|
||||
((_value >> 56) & 0x00000000000000ff) |
|
||||
|
@ -42,32 +258,14 @@ template<typename T, s64 _value> struct const_se_t<T, _value, 8>
|
|||
((_value << 56) & 0xff00000000000000);
|
||||
};
|
||||
|
||||
template<typename T, int size=sizeof(T)>
|
||||
template<typename T, typename T2 = T>
|
||||
class be_t
|
||||
{
|
||||
static_assert(size == 1 || size == 2 || size == 4 || size == 8, "Bad be_t type");
|
||||
static_assert(sizeof(T2) == 1 || sizeof(T2) == 2 || sizeof(T2) == 4 || sizeof(T2) == 8, "Bad be_t type");
|
||||
T m_data;
|
||||
|
||||
public:
|
||||
typedef T type;
|
||||
|
||||
#ifdef _WIN32
|
||||
be_t(){}
|
||||
#else
|
||||
be_t() noexcept = default;
|
||||
#endif
|
||||
|
||||
be_t(const be_t<T,size>& value) = default;
|
||||
be_t(const T& value)
|
||||
{
|
||||
FromLE(value);
|
||||
}
|
||||
|
||||
template<typename T1>
|
||||
explicit be_t(const be_t<T1>& value)
|
||||
{
|
||||
FromBE(value.ToBE());
|
||||
}
|
||||
|
||||
const T& ToBE() const
|
||||
{
|
||||
|
@ -76,11 +274,7 @@ public:
|
|||
|
||||
T ToLE() const
|
||||
{
|
||||
T res;
|
||||
|
||||
se_t<T>::func(res, m_data);
|
||||
|
||||
return res;
|
||||
return se_t<T, sizeof(T2)>::func(m_data);
|
||||
}
|
||||
|
||||
void FromBE(const T& value)
|
||||
|
@ -90,21 +284,18 @@ public:
|
|||
|
||||
void FromLE(const T& value)
|
||||
{
|
||||
se_t<T>::func(m_data, value);
|
||||
m_data = se_t<T, sizeof(T2)>::func(value);
|
||||
}
|
||||
|
||||
static be_t MakeFromLE(const T value)
|
||||
{
|
||||
be_t res;
|
||||
res.FromLE(value);
|
||||
return res;
|
||||
T data = se_t<T, sizeof(T2)>::func(value);
|
||||
return (be_t&)data;
|
||||
}
|
||||
|
||||
static be_t MakeFromBE(const T value)
|
||||
{
|
||||
be_t res;
|
||||
res.FromBE(value);
|
||||
return res;
|
||||
return (be_t&)value;
|
||||
}
|
||||
|
||||
//template<typename T1>
|
||||
|
@ -116,18 +307,36 @@ public:
|
|||
template<typename T1>
|
||||
operator const be_t<T1>() const
|
||||
{
|
||||
be_t<T1> res;
|
||||
res.FromBE(ToBE());
|
||||
return res;
|
||||
if (sizeof(T1) > sizeof(T) || std::is_floating_point<T>::value || std::is_floating_point<T1>::value)
|
||||
{
|
||||
T1 res = se_t<T1, sizeof(T1)>::func(ToLE());
|
||||
return (be_t<T1>&)res;
|
||||
}
|
||||
else if (sizeof(T1) < sizeof(T))
|
||||
{
|
||||
T1 res = ToBE() >> ((sizeof(T) - sizeof(T1)) * 8);
|
||||
return (be_t<T1>&)res;
|
||||
}
|
||||
else
|
||||
{
|
||||
T1 res = ToBE();
|
||||
return (be_t<T1>&)res;
|
||||
}
|
||||
}
|
||||
|
||||
be_t& operator = (const T& right)
|
||||
{
|
||||
FromLE(right);
|
||||
m_data = se_t<T, sizeof(T2)>::func(right);
|
||||
return *this;
|
||||
}
|
||||
|
||||
be_t<T,size>& operator = (const be_t<T,size>& right) = default;
|
||||
be_t& operator = (const be_t& right) = default;
|
||||
|
||||
be_t& operator = (const be_t<const T, const T2>& right)
|
||||
{
|
||||
m_data = right.ToBE();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T1> be_t& operator += (T1 right) { return *this = T(*this) + right; }
|
||||
template<typename T1> be_t& operator -= (T1 right) { return *this = T(*this) - right; }
|
||||
|
@ -173,10 +382,244 @@ public:
|
|||
be_t& operator-- () { *this -= 1; return *this; }
|
||||
};
|
||||
|
||||
template<typename T, typename T2>
|
||||
class be_t<const T, T2>
|
||||
{
|
||||
static_assert(sizeof(T2) == 1 || sizeof(T2) == 2 || sizeof(T2) == 4 || sizeof(T2) == 8, "Bad be_t type");
|
||||
const T m_data;
|
||||
|
||||
public:
|
||||
typedef const T type;
|
||||
|
||||
const T& ToBE() const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
const T ToLE() const
|
||||
{
|
||||
return se_t<const T, sizeof(T2)>::func(m_data);
|
||||
}
|
||||
|
||||
static be_t MakeFromLE(const T value)
|
||||
{
|
||||
const T data = se_t<const T, sizeof(T2)>::func(value);
|
||||
return (be_t&)data;
|
||||
}
|
||||
|
||||
static be_t MakeFromBE(const T value)
|
||||
{
|
||||
return (be_t&)value;
|
||||
}
|
||||
|
||||
//template<typename T1>
|
||||
operator const T() const
|
||||
{
|
||||
return ToLE();
|
||||
}
|
||||
|
||||
template<typename T1>
|
||||
operator const be_t<T1>() const
|
||||
{
|
||||
if (sizeof(T1) > sizeof(T) || std::is_floating_point<T>::value || std::is_floating_point<T1>::value)
|
||||
{
|
||||
T1 res = se_t<T1, sizeof(T1)>::func(ToLE());
|
||||
return (be_t<T1>&)res;
|
||||
}
|
||||
else if (sizeof(T1) < sizeof(T))
|
||||
{
|
||||
T1 res = ToBE() >> ((sizeof(T) - sizeof(T1)) * 8);
|
||||
return (be_t<T1>&)res;
|
||||
}
|
||||
else
|
||||
{
|
||||
T1 res = ToBE();
|
||||
return (be_t<T1>&)res;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T1> be_t operator & (const be_t<T1>& right) const { const T res; res = ToBE() & right.ToBE(); return (be_t&)res; }
|
||||
template<typename T1> be_t operator | (const be_t<T1>& right) const { const T res; res = ToBE() | right.ToBE(); return (be_t&)res; }
|
||||
template<typename T1> be_t operator ^ (const be_t<T1>& right) const { const T res; res = ToBE() ^ right.ToBE(); return (be_t&)res; }
|
||||
|
||||
template<typename T1> bool operator == (T1 right) const { return (T1)ToLE() == right; }
|
||||
template<typename T1> bool operator != (T1 right) const { return !(*this == right); }
|
||||
template<typename T1> bool operator > (T1 right) const { return (T1)ToLE() > right; }
|
||||
template<typename T1> bool operator < (T1 right) const { return (T1)ToLE() < right; }
|
||||
template<typename T1> bool operator >= (T1 right) const { return (T1)ToLE() >= right; }
|
||||
template<typename T1> bool operator <= (T1 right) const { return (T1)ToLE() <= right; }
|
||||
|
||||
template<typename T1> bool operator == (const be_t<T1>& right) const { return ToBE() == right.ToBE(); }
|
||||
template<typename T1> bool operator != (const be_t<T1>& right) const { return !(*this == right); }
|
||||
template<typename T1> bool operator > (const be_t<T1>& right) const { return (T1)ToLE() > right.ToLE(); }
|
||||
template<typename T1> bool operator < (const be_t<T1>& right) const { return (T1)ToLE() < right.ToLE(); }
|
||||
template<typename T1> bool operator >= (const be_t<T1>& right) const { return (T1)ToLE() >= right.ToLE(); }
|
||||
template<typename T1> bool operator <= (const be_t<T1>& right) const { return (T1)ToLE() <= right.ToLE(); }
|
||||
};
|
||||
|
||||
template<typename T, typename T2 = T>
|
||||
struct is_be_t : public std::integral_constant<bool, false> {};
|
||||
|
||||
template<typename T, typename T2>
|
||||
struct is_be_t<be_t<T, T2>, T2> : public std::integral_constant<bool, true> {};
|
||||
|
||||
template<typename T, typename T2 = T>
|
||||
struct remove_be_t
|
||||
{
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<typename T, typename T2>
|
||||
struct remove_be_t<be_t<T, T2>>
|
||||
{
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<typename T, typename T2 = T>
|
||||
class to_be_t
|
||||
{
|
||||
template<typename TT, typename TT2, bool is_need_swap>
|
||||
struct _be_type_selector
|
||||
{
|
||||
typedef TT type;
|
||||
};
|
||||
|
||||
template<typename TT, typename TT2>
|
||||
struct _be_type_selector<TT, TT2, true>
|
||||
{
|
||||
typedef be_t<TT, TT2> type;
|
||||
};
|
||||
|
||||
public:
|
||||
//true if need swap endianes for be
|
||||
static const bool value = (sizeof(T2) > 1) && std::is_arithmetic<T>::value;
|
||||
|
||||
//be_t<T, size> if need swap endianes, T otherwise
|
||||
typedef typename _be_type_selector< T, T2, value >::type type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class to_be_t<T, void>
|
||||
{
|
||||
public:
|
||||
//true if need swap endianes for be
|
||||
static const bool value = false;
|
||||
|
||||
//be_t<T, size> if need swap endianes, T otherwise
|
||||
typedef void type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class to_be_t<T, const void>
|
||||
{
|
||||
public:
|
||||
//true if need swap endianes for be
|
||||
static const bool value = false;
|
||||
|
||||
//be_t<T, size> if need swap endianes, T otherwise
|
||||
typedef const void type;
|
||||
};
|
||||
|
||||
template<typename T, typename T2 = T>
|
||||
struct invert_be_t
|
||||
{
|
||||
typedef typename to_be_t<T, T2>::type type;
|
||||
};
|
||||
|
||||
template<typename T, typename T2>
|
||||
struct invert_be_t<be_t<T, T2>>
|
||||
{
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<typename T, typename T1, T1 value> struct _se : public const_se_t<T, value> {};
|
||||
template<typename T, typename T1, T1 value> struct _se<be_t<T>, T1, value> : public const_se_t<T, value> {};
|
||||
|
||||
#define se(t, x) _se<decltype(t), decltype(x), x>::value
|
||||
//#define se(t, x) _se<decltype(t), decltype(x), x>::value
|
||||
#define se16(x) _se<u16, decltype(x), x>::value
|
||||
#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)
|
||||
{
|
||||
u8 ret;
|
||||
f.Read(&ret, sizeof(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T> __forceinline static u16 Read16(T& f)
|
||||
{
|
||||
be_t<u16> ret;
|
||||
f.Read(&ret, sizeof(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T> __forceinline static u32 Read32(T& f)
|
||||
{
|
||||
be_t<u32> ret;
|
||||
f.Read(&ret, sizeof(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T> __forceinline static u64 Read64(T& f)
|
||||
{
|
||||
be_t<u64> ret;
|
||||
f.Read(&ret, sizeof(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T> __forceinline static u16 Read16LE(T& f)
|
||||
{
|
||||
u16 ret;
|
||||
f.Read(&ret, sizeof(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T> __forceinline static u32 Read32LE(T& f)
|
||||
{
|
||||
u32 ret;
|
||||
f.Read(&ret, sizeof(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
template<typename T> __forceinline static 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)
|
||||
{
|
||||
f.Write(&data, sizeof(data));
|
||||
}
|
||||
|
||||
template<typename T> __forceinline static void Write16LE(T& f, const u16 data)
|
||||
{
|
||||
f.Write(&data, sizeof(data));
|
||||
}
|
||||
|
||||
template<typename T> __forceinline static void Write32LE(T& f, const u32 data)
|
||||
{
|
||||
f.Write(&data, sizeof(data));
|
||||
}
|
||||
|
||||
template<typename T> __forceinline static void Write64LE(T& f, const u64 data)
|
||||
{
|
||||
f.Write(&data, sizeof(data));
|
||||
}
|
||||
|
||||
template<typename T> __forceinline static void Write16(T& f, const u16 data)
|
||||
{
|
||||
Write16LE(f, re16(data));
|
||||
}
|
||||
|
||||
template<typename T> __forceinline static void Write32(T& f, const u32 data)
|
||||
{
|
||||
Write32LE(f, re32(data));
|
||||
}
|
||||
|
||||
template<typename T> __forceinline static void Write64(T& f, const u64 data)
|
||||
{
|
||||
Write64LE(f, re64(data));
|
||||
}
|
|
@ -1,20 +1,23 @@
|
|||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include "GNU.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
void * _aligned_malloc(size_t size, size_t alignment) {
|
||||
void *buffer;
|
||||
posix_memalign(&buffer, alignment, size);
|
||||
return buffer;
|
||||
}
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
int clock_gettime(int foo, struct timespec *ts) {
|
||||
struct timeval tv;
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
ts->tv_sec = tv.tv_sec;
|
||||
ts->tv_nsec = tv.tv_usec * 1000;
|
||||
return(0);
|
||||
gettimeofday(&tv, NULL);
|
||||
ts->tv_sec = tv.tv_sec;
|
||||
ts->tv_nsec = tv.tv_usec * 1000;
|
||||
return(0);
|
||||
}
|
||||
#endif /* !__APPLE__ */
|
||||
#endif /* __APPLE__ */
|
||||
#if defined(__GNUG__)
|
||||
|
||||
void * _aligned_malloc(size_t size, size_t alignment) {
|
||||
void *buffer;
|
||||
return (posix_memalign(&buffer, alignment, size) == 0) ? buffer : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -1,5 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef _WIN32
|
||||
#define thread_local __declspec(thread)
|
||||
#elif __APPLE__
|
||||
#define thread_local __thread
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define __noinline __declspec(noinline)
|
||||
#else
|
||||
#define __noinline __attribute__((noinline))
|
||||
#endif
|
||||
|
||||
template<size_t size>
|
||||
void strcpy_trunc(char (&dst)[size], const std::string& src)
|
||||
{
|
||||
const size_t count = (src.size() >= size) ? size - 1 /* truncation */ : src.size();
|
||||
memcpy(dst, src.c_str(), count);
|
||||
dst[count] = 0;
|
||||
}
|
||||
|
||||
#if defined(__GNUG__)
|
||||
#include <cmath>
|
||||
#include <stdlib.h>
|
||||
|
@ -14,8 +34,6 @@
|
|||
#define _byteswap_ushort(x) __builtin_bswap16(x)
|
||||
#define _byteswap_ulong(x) __builtin_bswap32(x)
|
||||
#define _byteswap_uint64(x) __builtin_bswap64(x)
|
||||
#define Sleep(x) usleep(x * 1000)
|
||||
#define mkdir(x) mkdir(x, 0777)
|
||||
#define INFINITE 0xFFFFFFFF
|
||||
#define _CRT_ALIGN(x) __attribute__((aligned(x)))
|
||||
#define InterlockedCompareExchange(ptr,new_val,old_val) __sync_val_compare_and_swap(ptr,old_val,new_val)
|
||||
|
@ -47,10 +65,10 @@ inline int64_t __mulh(int64_t a, int64_t b)
|
|||
return result;
|
||||
}
|
||||
|
||||
#ifndef __APPLE__
|
||||
#define _aligned_malloc(size,alignment) memalign(alignment,size)
|
||||
#else
|
||||
|
||||
void * _aligned_malloc(size_t size, size_t alignment);
|
||||
|
||||
#ifdef __APPLE__
|
||||
int clock_gettime(int foo, struct timespec *ts);
|
||||
#define wxIsNaN(x) ((x) != (x))
|
||||
|
||||
|
@ -58,9 +76,20 @@ int clock_gettime(int foo, struct timespec *ts);
|
|||
#define CLOCK_MONOTONIC 0
|
||||
#endif /* !CLOCK_MONOTONIC */
|
||||
|
||||
#endif /* !__APPLE__ */
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
#define _aligned_free free
|
||||
|
||||
#define DWORD int32_t
|
||||
#endif
|
||||
|
||||
#ifndef InterlockedCompareExchange
|
||||
static __forceinline uint32_t InterlockedCompareExchange(volatile uint32_t* dest, uint32_t exch, uint32_t comp)
|
||||
{
|
||||
return _InterlockedCompareExchange((volatile long*)dest, exch, comp);
|
||||
}
|
||||
static __forceinline uint64_t InterlockedCompareExchange(volatile uint64_t* dest, uint64_t exch, uint64_t comp)
|
||||
{
|
||||
return _InterlockedCompareExchange64((volatile long long*)dest, exch, comp);
|
||||
}
|
||||
#endif
|
42
Utilities/Interval.h
Normal file
42
Utilities/Interval.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
#pragma once
|
||||
|
||||
template<typename T>
|
||||
struct BaseInterval
|
||||
{
|
||||
static const uint64_t zero = 0ull;
|
||||
static const uint64_t notz = 0xffffffffffffffffull;
|
||||
|
||||
T m_min, m_max;
|
||||
|
||||
static BaseInterval<T> make(T min_value, T max_value)
|
||||
{
|
||||
BaseInterval<T> res = { min_value, max_value };
|
||||
return res;
|
||||
}
|
||||
|
||||
static BaseInterval<T> make()
|
||||
{
|
||||
return make((T&)zero, (T&)notz);
|
||||
}
|
||||
|
||||
bool getconst(T& result)
|
||||
{
|
||||
if (m_min == m_max)
|
||||
{
|
||||
result = m_min;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool isindef()
|
||||
{
|
||||
if (T == float)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
};
|
235
Utilities/Log.cpp
Normal file
235
Utilities/Log.cpp
Normal file
|
@ -0,0 +1,235 @@
|
|||
#include "stdafx.h"
|
||||
#include "rPlatform.h"
|
||||
#include "Log.h"
|
||||
#include "rMsgBox.h"
|
||||
#include <iostream>
|
||||
#include <cinttypes>
|
||||
#include "Thread.h"
|
||||
#include "rFile.h"
|
||||
|
||||
using namespace Log;
|
||||
|
||||
LogManager *gLogManager = nullptr;
|
||||
|
||||
u32 LogMessage::size()
|
||||
{
|
||||
//1 byte for NULL terminator
|
||||
return (u32)(sizeof(LogMessage::size_type) + sizeof(LogType) + sizeof(LogSeverity) + sizeof(std::string::value_type) * mText.size() + 1);
|
||||
}
|
||||
|
||||
void LogMessage::serialize(char *output)
|
||||
{
|
||||
LogMessage::size_type size = this->size();
|
||||
memcpy(output, &size, sizeof(LogMessage::size_type));
|
||||
output += sizeof(LogMessage::size_type);
|
||||
memcpy(output, &mType, sizeof(LogType));
|
||||
output += sizeof(LogType);
|
||||
memcpy(output, &mServerity, sizeof(LogSeverity));
|
||||
output += sizeof(LogSeverity);
|
||||
memcpy(output, mText.c_str(), mText.size() );
|
||||
output += sizeof(std::string::value_type)*mText.size();
|
||||
*output = '\0';
|
||||
|
||||
}
|
||||
LogMessage LogMessage::deserialize(char *input, u32* size_out)
|
||||
{
|
||||
LogMessage msg;
|
||||
LogMessage::size_type msgSize = *(reinterpret_cast<LogMessage::size_type*>(input));
|
||||
input += sizeof(LogMessage::size_type);
|
||||
msg.mType = *(reinterpret_cast<LogType*>(input));
|
||||
input += sizeof(LogType);
|
||||
msg.mServerity = *(reinterpret_cast<LogSeverity*>(input));
|
||||
input += sizeof(LogSeverity);
|
||||
if (msgSize > 9000)
|
||||
{
|
||||
int wtf = 6;
|
||||
}
|
||||
msg.mText.append(input, msgSize - 1 - sizeof(LogSeverity) - sizeof(LogType));
|
||||
if (size_out){(*size_out) = msgSize;}
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
LogChannel::LogChannel() : LogChannel("unknown")
|
||||
{}
|
||||
|
||||
LogChannel::LogChannel(const std::string& name) :
|
||||
name(name)
|
||||
, mEnabled(true)
|
||||
, mLogLevel(Warning)
|
||||
{}
|
||||
|
||||
void LogChannel::log(LogMessage msg)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mListenerLock);
|
||||
for (auto &listener : mListeners)
|
||||
{
|
||||
listener->log(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void LogChannel::addListener(std::shared_ptr<LogListener> listener)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mListenerLock);
|
||||
mListeners.insert(listener);
|
||||
}
|
||||
void LogChannel::removeListener(std::shared_ptr<LogListener> listener)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mListenerLock);
|
||||
mListeners.erase(listener);
|
||||
}
|
||||
|
||||
struct CoutListener : LogListener
|
||||
{
|
||||
void log(LogMessage msg)
|
||||
{
|
||||
std::cerr << msg.mText << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
struct FileListener : LogListener
|
||||
{
|
||||
rFile mFile;
|
||||
bool mPrependChannelName;
|
||||
|
||||
FileListener(const std::string& name = _PRGNAME_, bool prependChannel = true)
|
||||
: mFile(std::string(rPlatform::getConfigDir() + name + ".log").c_str(), rFile::write),
|
||||
mPrependChannelName(prependChannel)
|
||||
{
|
||||
if (!mFile.IsOpened())
|
||||
{
|
||||
rMessageBox("Can't create log file! (" + name + ".log)", "Error", rICON_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
void log(LogMessage msg)
|
||||
{
|
||||
if (mPrependChannelName)
|
||||
{
|
||||
msg.mText.insert(0, gTypeNameTable[static_cast<u32>(msg.mType)].mName);
|
||||
}
|
||||
mFile.Write(msg.mText);
|
||||
}
|
||||
};
|
||||
|
||||
LogManager::LogManager()
|
||||
#ifdef BUFFERED_LOGGING
|
||||
: mExiting(false), mLogConsumer()
|
||||
#endif
|
||||
{
|
||||
auto it = mChannels.begin();
|
||||
std::shared_ptr<LogListener> listener(new FileListener());
|
||||
for (const LogTypeName& name : gTypeNameTable)
|
||||
{
|
||||
it->name = name.mName;
|
||||
it->addListener(listener);
|
||||
it++;
|
||||
}
|
||||
std::shared_ptr<LogListener> TTYListener(new FileListener("TTY",false));
|
||||
getChannel(TTY).addListener(TTYListener);
|
||||
#ifdef BUFFERED_LOGGING
|
||||
mLogConsumer = std::thread(&LogManager::consumeLog, this);
|
||||
#endif
|
||||
}
|
||||
|
||||
LogManager::~LogManager()
|
||||
{
|
||||
#ifdef BUFFERED_LOGGING
|
||||
mExiting = true;
|
||||
mBufferReady.notify_all();
|
||||
mLogConsumer.join();
|
||||
}
|
||||
|
||||
void LogManager::consumeLog()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mStatusMut);
|
||||
while (!mExiting)
|
||||
{
|
||||
mBufferReady.wait(lock);
|
||||
mBuffer.lockGet();
|
||||
size_t size = mBuffer.size();
|
||||
std::vector<char> local_messages(size);
|
||||
mBuffer.popN(&local_messages.front(), size);
|
||||
mBuffer.unlockGet();
|
||||
|
||||
u32 cursor = 0;
|
||||
u32 removed = 0;
|
||||
while (cursor < size)
|
||||
{
|
||||
Log::LogMessage msg = Log::LogMessage::deserialize(local_messages.data() + cursor, &removed);
|
||||
cursor += removed;
|
||||
getChannel(msg.mType).log(msg);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void LogManager::log(LogMessage msg)
|
||||
{
|
||||
//don't do any formatting changes or filtering to the TTY output since we
|
||||
//use the raw output to do diffs with the output of a real PS3 and some
|
||||
//programs write text in single bytes to the console
|
||||
if (msg.mType != TTY)
|
||||
{
|
||||
std::string prefix;
|
||||
switch (msg.mServerity)
|
||||
{
|
||||
case Success:
|
||||
prefix = "S ";
|
||||
break;
|
||||
case Notice:
|
||||
prefix = "! ";
|
||||
break;
|
||||
case Warning:
|
||||
prefix = "W ";
|
||||
break;
|
||||
case Error:
|
||||
prefix = "E ";
|
||||
break;
|
||||
}
|
||||
if (NamedThreadBase* thr = GetCurrentNamedThread())
|
||||
{
|
||||
prefix += "{" + thr->GetThreadName() + "} ";
|
||||
}
|
||||
msg.mText.insert(0, prefix);
|
||||
msg.mText.append(1,'\n');
|
||||
}
|
||||
#ifdef BUFFERED_LOGGING
|
||||
size_t size = msg.size();
|
||||
std::vector<char> temp_buffer(size);
|
||||
msg.serialize(temp_buffer.data());
|
||||
mBuffer.pushRange(temp_buffer.begin(), temp_buffer.end());
|
||||
mBufferReady.notify_one();
|
||||
#else
|
||||
mChannels[static_cast<u32>(msg.mType)].log(msg);
|
||||
#endif
|
||||
}
|
||||
|
||||
void LogManager::addListener(std::shared_ptr<LogListener> listener)
|
||||
{
|
||||
for (auto& channel : mChannels)
|
||||
{
|
||||
channel.addListener(listener);
|
||||
}
|
||||
}
|
||||
void LogManager::removeListener(std::shared_ptr<LogListener> listener)
|
||||
{
|
||||
for (auto& channel : mChannels)
|
||||
{
|
||||
channel.removeListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
LogManager& LogManager::getInstance()
|
||||
{
|
||||
if (!gLogManager)
|
||||
{
|
||||
gLogManager = new LogManager();
|
||||
}
|
||||
return *gLogManager;
|
||||
}
|
||||
LogChannel &LogManager::getChannel(LogType type)
|
||||
{
|
||||
return mChannels[static_cast<u32>(type)];
|
||||
}
|
141
Utilities/Log.h
Normal file
141
Utilities/Log.h
Normal file
|
@ -0,0 +1,141 @@
|
|||
#pragma once
|
||||
#include <array>
|
||||
#include "Utilities/MTRingbuffer.h"
|
||||
|
||||
//#define BUFFERED_LOGGING 1
|
||||
|
||||
//first parameter is of type Log::LogType and text is of type std::string
|
||||
|
||||
#define LOG_SUCCESS(logType, text, ...) log_message(logType, Log::Success, text, ##__VA_ARGS__)
|
||||
#define LOG_NOTICE(logType, text, ...) log_message(logType, Log::Notice, text, ##__VA_ARGS__)
|
||||
#define LOG_WARNING(logType, text, ...) log_message(logType, Log::Warning, text, ##__VA_ARGS__)
|
||||
#define LOG_ERROR(logType, text, ...) log_message(logType, Log::Error, text, ##__VA_ARGS__)
|
||||
|
||||
namespace Log
|
||||
{
|
||||
const unsigned int MAX_LOG_BUFFER_LENGTH = 1024*1024;
|
||||
const unsigned int gBuffSize = 1000;
|
||||
|
||||
enum LogType : u32
|
||||
{
|
||||
GENERAL = 0,
|
||||
LOADER,
|
||||
MEMORY,
|
||||
RSX,
|
||||
HLE,
|
||||
PPU,
|
||||
SPU,
|
||||
TTY,
|
||||
};
|
||||
|
||||
|
||||
struct LogTypeName
|
||||
{
|
||||
LogType mType;
|
||||
std::string mName;
|
||||
};
|
||||
|
||||
//well I'd love make_array() but alas manually counting is not the end of the world
|
||||
static const std::array<LogTypeName, 8> gTypeNameTable = { {
|
||||
{ GENERAL, "G: " },
|
||||
{ LOADER, "LDR: " },
|
||||
{ MEMORY, "MEM: " },
|
||||
{ RSX, "RSX: " },
|
||||
{ HLE, "HLE: " },
|
||||
{ PPU, "PPU: " },
|
||||
{ SPU, "SPU: " },
|
||||
{ TTY, "TTY: " }
|
||||
} };
|
||||
|
||||
enum LogSeverity : u32
|
||||
{
|
||||
Success = 0,
|
||||
Notice,
|
||||
Warning,
|
||||
Error,
|
||||
};
|
||||
|
||||
struct LogMessage
|
||||
{
|
||||
using size_type = u32;
|
||||
LogType mType;
|
||||
LogSeverity mServerity;
|
||||
std::string mText;
|
||||
|
||||
u32 size();
|
||||
void serialize(char *output);
|
||||
static LogMessage deserialize(char *input, u32* size_out=nullptr);
|
||||
};
|
||||
|
||||
struct LogListener
|
||||
{
|
||||
virtual ~LogListener() {};
|
||||
virtual void log(LogMessage msg) = 0;
|
||||
};
|
||||
|
||||
struct LogChannel
|
||||
{
|
||||
LogChannel();
|
||||
LogChannel(const std::string& name);
|
||||
LogChannel(LogChannel& other) = delete;
|
||||
LogChannel& operator = (LogChannel& other) = delete;
|
||||
void log(LogMessage msg);
|
||||
void addListener(std::shared_ptr<LogListener> listener);
|
||||
void removeListener(std::shared_ptr<LogListener> listener);
|
||||
std::string name;
|
||||
private:
|
||||
bool mEnabled;
|
||||
LogSeverity mLogLevel;
|
||||
std::mutex mListenerLock;
|
||||
std::set<std::shared_ptr<LogListener>> mListeners;
|
||||
};
|
||||
|
||||
struct LogManager
|
||||
{
|
||||
LogManager();
|
||||
~LogManager();
|
||||
static LogManager& getInstance();
|
||||
LogChannel& getChannel(LogType type);
|
||||
void log(LogMessage msg);
|
||||
void addListener(std::shared_ptr<LogListener> listener);
|
||||
void removeListener(std::shared_ptr<LogListener> listener);
|
||||
#ifdef BUFFERED_LOGGING
|
||||
void consumeLog();
|
||||
#endif
|
||||
private:
|
||||
#ifdef BUFFERED_LOGGING
|
||||
MTRingbuffer<char, MAX_LOG_BUFFER_LENGTH> mBuffer;
|
||||
std::condition_variable mBufferReady;
|
||||
std::mutex mStatusMut;
|
||||
std::atomic<bool> mExiting;
|
||||
std::thread mLogConsumer;
|
||||
#endif
|
||||
std::array<LogChannel, std::tuple_size<decltype(gTypeNameTable)>::value> mChannels;
|
||||
//std::array<LogChannel,gTypeNameTable.size()> mChannels; //TODO: use this once Microsoft sorts their shit out
|
||||
};
|
||||
}
|
||||
|
||||
static struct { inline operator Log::LogType() { return Log::LogType::GENERAL; } } GENERAL;
|
||||
static struct { inline operator Log::LogType() { return Log::LogType::LOADER; } } LOADER;
|
||||
static struct { inline operator Log::LogType() { return Log::LogType::MEMORY; } } MEMORY;
|
||||
static struct { inline operator Log::LogType() { return Log::LogType::RSX; } } RSX;
|
||||
static struct { inline operator Log::LogType() { return Log::LogType::HLE; } } HLE;
|
||||
static struct { inline operator Log::LogType() { return Log::LogType::PPU; } } PPU;
|
||||
static struct { inline operator Log::LogType() { return Log::LogType::SPU; } } SPU;
|
||||
static struct { inline operator Log::LogType() { return Log::LogType::TTY; } } TTY;
|
||||
|
||||
inline 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, text};
|
||||
Log::LogManager::getInstance().log(msg);
|
||||
}
|
||||
|
||||
template<typename T, typename ...Ts>
|
||||
inline void log_message(Log::LogType type, Log::LogSeverity sev, std::string text, T arg, Ts... args)
|
||||
{
|
||||
Log::LogMessage msg{type, sev, fmt::Format(text,arg,args...)};
|
||||
Log::LogManager::getInstance().log(msg);
|
||||
}
|
155
Utilities/MTRingbuffer.h
Normal file
155
Utilities/MTRingbuffer.h
Normal file
|
@ -0,0 +1,155 @@
|
|||
#pragma once
|
||||
|
||||
//Simple non-resizable FIFO Ringbuffer that can be simultaneously be read from and written to
|
||||
//if we ever get to use boost please replace this with boost::circular_buffer, there's no reason
|
||||
//why we would have to keep this amateur attempt at such a fundamental data-structure around
|
||||
template< typename T, unsigned int MAX_MTRINGBUFFER_BUFFER_SIZE>
|
||||
class MTRingbuffer{
|
||||
std::array<T, MAX_MTRINGBUFFER_BUFFER_SIZE> mBuffer;
|
||||
//this is a recursive mutex because the get methods lock it but the only
|
||||
//way to be sure that they do not block is to check the size and the only
|
||||
//way to check the size and use get atomically is to lock this mutex,
|
||||
//so it goes:
|
||||
//lock get mutex-->check size-->call get-->lock get mutex-->unlock get mutex-->return from get-->unlock get mutex
|
||||
std::recursive_mutex mMutGet;
|
||||
std::mutex mMutPut;
|
||||
|
||||
size_t mGet;
|
||||
size_t mPut;
|
||||
size_t moveGet(size_t by = 1){ return (mGet + by) % MAX_MTRINGBUFFER_BUFFER_SIZE; }
|
||||
size_t movePut(size_t by = 1){ return (mPut + by) % MAX_MTRINGBUFFER_BUFFER_SIZE; }
|
||||
public:
|
||||
MTRingbuffer() : mGet(0), mPut(0){}
|
||||
|
||||
//blocks until there's something to get, so check "spaceLeft()" if you want to avoid blocking
|
||||
//also lock the get mutex around the spaceLeft() check and the pop if you want to avoid racing
|
||||
T pop()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(mMutGet);
|
||||
while (mGet == mPut)
|
||||
{
|
||||
//wait until there's actually something to get
|
||||
//throwing an exception might be better, blocking here is a little awkward
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
size_t ret = mGet;
|
||||
mGet = moveGet();
|
||||
return mBuffer[ret];
|
||||
}
|
||||
|
||||
//blocks if the buffer is full until there's enough room
|
||||
void push(T &putEle)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mMutPut);
|
||||
while (movePut() == mGet)
|
||||
{
|
||||
//if this is reached a lot it's time to increase the buffer size
|
||||
//or implement dynamic re-sizing
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
mBuffer[mPut] = std::forward(putEle);
|
||||
mPut = movePut();
|
||||
}
|
||||
|
||||
bool empty()
|
||||
{
|
||||
return mGet == mPut;
|
||||
}
|
||||
|
||||
//returns the amount of free places, this is the amount of actual free spaces-1
|
||||
//since mGet==mPut signals an empty buffer we can't actually use the last free
|
||||
//space, so we shouldn't report it as free.
|
||||
size_t spaceLeft() //apparently free() is a macro definition in msvc in some conditions
|
||||
{
|
||||
if (mGet < mPut)
|
||||
{
|
||||
return mBuffer.size() - (mPut - mGet) - 1;
|
||||
}
|
||||
else if (mGet > mPut)
|
||||
{
|
||||
return mGet - mPut - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return mBuffer.size() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
size_t size()
|
||||
{
|
||||
//the magic -1 is the same magic 1 that is explained in the spaceLeft() function
|
||||
return mBuffer.size() - spaceLeft() - 1;
|
||||
}
|
||||
|
||||
//takes random access iterator to T
|
||||
template<typename IteratorType>
|
||||
void pushRange(IteratorType from, IteratorType until)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mMutPut);
|
||||
size_t length = until - from;
|
||||
|
||||
//if whatever we're trying to store is greater than the entire buffer the following loop will be infinite
|
||||
assert(mBuffer.size() > length);
|
||||
while (spaceLeft() < length)
|
||||
{
|
||||
//if this is reached a lot it's time to increase the buffer size
|
||||
//or implement dynamic re-sizing
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
if (mPut + length <= mBuffer.size())
|
||||
{
|
||||
std::copy(from, until, mBuffer.begin() + mPut);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t tillEnd = mBuffer.size() - mPut;
|
||||
std::copy(from, from + tillEnd, mBuffer.begin() + mPut);
|
||||
std::copy(from + tillEnd, until, mBuffer.begin());
|
||||
}
|
||||
mPut = movePut(length);
|
||||
|
||||
}
|
||||
|
||||
//takes output iterator to T
|
||||
template<typename IteratorType>
|
||||
void popN(IteratorType output, size_t n)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(mMutGet);
|
||||
//make sure we're not trying to retrieve more than is in
|
||||
assert(n <= size());
|
||||
peekN<IteratorType>(output, n);
|
||||
mGet = moveGet(n);
|
||||
}
|
||||
|
||||
//takes output iterator to T
|
||||
template<typename IteratorType>
|
||||
void peekN(IteratorType output, size_t n)
|
||||
{
|
||||
size_t lGet = mGet;
|
||||
if (lGet + n <= mBuffer.size())
|
||||
{
|
||||
std::copy_n(mBuffer.begin() + lGet, n, output);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto next = std::copy(mBuffer.begin() + lGet, mBuffer.end(), output);
|
||||
std::copy_n(mBuffer.begin(), n - (mBuffer.size() - lGet), next);
|
||||
}
|
||||
}
|
||||
|
||||
//well this is just asking for trouble
|
||||
//but the comment above the declaration of mMutGet explains why it's there
|
||||
//if there's a better way please remove this
|
||||
void lockGet()
|
||||
{
|
||||
mMutGet.lock();
|
||||
}
|
||||
|
||||
//well this is just asking for trouble
|
||||
//but the comment above the declaration of mMutGet explains why it's there
|
||||
//if there's a better way please remove this
|
||||
void unlockGet()
|
||||
{
|
||||
mMutGet.unlock();
|
||||
}
|
||||
};
|
|
@ -1,26 +1,34 @@
|
|||
#include <stdafx.h>
|
||||
#include <Utilities/SMutex.h>
|
||||
#include "stdafx.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/CPU/CPUThread.h"
|
||||
|
||||
__forceinline void SM_Sleep()
|
||||
#include "Utilities/SMutex.h"
|
||||
|
||||
bool SM_IsAborted()
|
||||
{
|
||||
Sleep(1);
|
||||
return Emu.IsStopped();
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(thread)
|
||||
#elif __APPLE__
|
||||
__thread
|
||||
#else
|
||||
thread_local
|
||||
#endif
|
||||
size_t g_this_thread_id = 0;
|
||||
void SM_Sleep()
|
||||
{
|
||||
if (NamedThreadBase* t = GetCurrentNamedThread())
|
||||
{
|
||||
t->WaitForAnySignal();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
}
|
||||
|
||||
__forceinline size_t SM_GetCurrentThreadId()
|
||||
thread_local size_t g_this_thread_id = 0;
|
||||
|
||||
size_t SM_GetCurrentThreadId()
|
||||
{
|
||||
return g_this_thread_id ? g_this_thread_id : g_this_thread_id = std::hash<std::thread::id>()(std::this_thread::get_id());
|
||||
}
|
||||
|
||||
__forceinline u32 SM_GetCurrentCPUThreadId()
|
||||
u32 SM_GetCurrentCPUThreadId()
|
||||
{
|
||||
if (CPUThread* t = GetCurrentCPUThread())
|
||||
{
|
||||
|
@ -29,7 +37,7 @@ __forceinline u32 SM_GetCurrentCPUThreadId()
|
|||
return 0;
|
||||
}
|
||||
|
||||
__forceinline be_t<u32> SM_GetCurrentCPUThreadIdBE()
|
||||
be_t<u32> SM_GetCurrentCPUThreadIdBE()
|
||||
{
|
||||
return SM_GetCurrentCPUThreadId();
|
||||
return be_t<u32>::MakeFromLE(SM_GetCurrentCPUThreadId());
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
extern void SM_Sleep();
|
||||
extern size_t SM_GetCurrentThreadId();
|
||||
extern u32 SM_GetCurrentCPUThreadId();
|
||||
extern be_t<u32> SM_GetCurrentCPUThreadIdBE();
|
||||
bool SM_IsAborted();
|
||||
void SM_Sleep();
|
||||
size_t SM_GetCurrentThreadId();
|
||||
u32 SM_GetCurrentCPUThreadId();
|
||||
be_t<u32> SM_GetCurrentCPUThreadIdBE();
|
||||
|
||||
enum SMutexResult
|
||||
{
|
||||
|
@ -20,8 +21,8 @@ enum SMutexResult
|
|||
template
|
||||
<
|
||||
typename T,
|
||||
u64 free_value = 0,
|
||||
u64 dead_value = 0xffffffff,
|
||||
const u64 free_value = 0,
|
||||
const u64 dead_value = 0xffffffffffffffffull,
|
||||
void (*wait)() = SM_Sleep
|
||||
>
|
||||
class SMutexBase
|
||||
|
@ -30,20 +31,31 @@ class SMutexBase
|
|||
std::atomic<T> owner;
|
||||
|
||||
public:
|
||||
SMutexBase()
|
||||
: owner((T)free_value)
|
||||
static const T GetFreeValue()
|
||||
{
|
||||
static const u64 value = free_value;
|
||||
return (const T&)value;
|
||||
}
|
||||
|
||||
static const T GetDeadValue()
|
||||
{
|
||||
static const u64 value = dead_value;
|
||||
return (const T&)value;
|
||||
}
|
||||
|
||||
void initialize()
|
||||
{
|
||||
(T&)owner = free_value;
|
||||
owner = GetFreeValue();
|
||||
}
|
||||
|
||||
~SMutexBase()
|
||||
SMutexBase()
|
||||
{
|
||||
lock((T)dead_value);
|
||||
owner = (T)dead_value;
|
||||
initialize();
|
||||
}
|
||||
|
||||
void finalize()
|
||||
{
|
||||
owner = GetDeadValue();
|
||||
}
|
||||
|
||||
__forceinline T GetOwner() const
|
||||
|
@ -51,23 +63,13 @@ public:
|
|||
return (T&)owner;
|
||||
}
|
||||
|
||||
__forceinline T GetFreeValue() const
|
||||
{
|
||||
return (T)free_value;
|
||||
}
|
||||
|
||||
__forceinline T GetDeadValue() const
|
||||
{
|
||||
return (T)dead_value;
|
||||
}
|
||||
|
||||
SMutexResult trylock(T tid)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
if (SM_IsAborted())
|
||||
{
|
||||
return SMR_ABORT;
|
||||
}
|
||||
T old = (T)free_value;
|
||||
T old = GetFreeValue();
|
||||
|
||||
if (!owner.compare_exchange_strong(old, tid))
|
||||
{
|
||||
|
@ -75,7 +77,7 @@ public:
|
|||
{
|
||||
return SMR_DEADLOCK;
|
||||
}
|
||||
if (old == (T)dead_value)
|
||||
if (old == GetDeadValue())
|
||||
{
|
||||
return SMR_DESTROYED;
|
||||
}
|
||||
|
@ -85,9 +87,9 @@ public:
|
|||
return SMR_OK;
|
||||
}
|
||||
|
||||
SMutexResult unlock(T tid, T to = (T)free_value)
|
||||
SMutexResult unlock(T tid, T to = GetFreeValue())
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
if (SM_IsAborted())
|
||||
{
|
||||
return SMR_ABORT;
|
||||
}
|
||||
|
@ -95,11 +97,11 @@ public:
|
|||
|
||||
if (!owner.compare_exchange_strong(old, to))
|
||||
{
|
||||
if (old == (T)free_value)
|
||||
if (old == GetFreeValue())
|
||||
{
|
||||
return SMR_FAILED;
|
||||
}
|
||||
if (old == (T)dead_value)
|
||||
if (old == GetDeadValue())
|
||||
{
|
||||
return SMR_DESTROYED;
|
||||
}
|
||||
|
@ -122,7 +124,7 @@ public:
|
|||
default: return res;
|
||||
}
|
||||
|
||||
wait();
|
||||
if (wait != nullptr) wait();
|
||||
|
||||
if (timeout && counter++ > timeout)
|
||||
{
|
||||
|
@ -132,23 +134,22 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
template<typename T, T (get_tid)()>
|
||||
template<typename T, typename Tid, Tid (get_tid)()>
|
||||
class SMutexLockerBase
|
||||
{
|
||||
SMutexBase<T>& sm;
|
||||
T& sm;
|
||||
public:
|
||||
const T tid;
|
||||
const Tid tid;
|
||||
|
||||
__forceinline SMutexLockerBase(SMutexBase<T>& _sm)
|
||||
__forceinline SMutexLockerBase(T& _sm)
|
||||
: sm(_sm)
|
||||
, tid(get_tid())
|
||||
{
|
||||
if (!tid)
|
||||
{
|
||||
if (!Emu.IsStopped())
|
||||
if (!SM_IsAborted())
|
||||
{
|
||||
ConLog.Error("SMutexLockerBase: thread id == 0");
|
||||
Emu.Pause();
|
||||
assert(!"SMutexLockerBase: thread id == 0");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -168,9 +169,9 @@ typedef SMutexBase<u32>
|
|||
typedef SMutexBase<be_t<u32>>
|
||||
SMutexBE;
|
||||
|
||||
typedef SMutexLockerBase<size_t, SM_GetCurrentThreadId>
|
||||
typedef SMutexLockerBase<SMutexGeneral, size_t, SM_GetCurrentThreadId>
|
||||
SMutexGeneralLocker;
|
||||
typedef SMutexLockerBase<u32, SM_GetCurrentCPUThreadId>
|
||||
typedef SMutexLockerBase<SMutex, u32, SM_GetCurrentCPUThreadId>
|
||||
SMutexLocker;
|
||||
typedef SMutexLockerBase<be_t<u32>, SM_GetCurrentCPUThreadIdBE>
|
||||
typedef SMutexLockerBase<SMutexBE, be_t<u32>, SM_GetCurrentCPUThreadIdBE>
|
||||
SMutexBELocker;
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include "Utilities/SMutex.h"
|
||||
|
||||
template<typename T, u32 SQSize = 666>
|
||||
class SQueue
|
||||
{
|
||||
SMutexGeneral m_mutex;
|
||||
std::mutex m_mutex;
|
||||
u32 m_pos;
|
||||
u32 m_count;
|
||||
T m_data[SQSize];
|
||||
|
@ -24,23 +26,19 @@ public:
|
|||
{
|
||||
while (true)
|
||||
{
|
||||
if (m_mutex.GetOwner() == m_mutex.GetDeadValue())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_count >= SQSize)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Sleep(1);
|
||||
|
||||
SM_Sleep();
|
||||
continue;
|
||||
}
|
||||
|
||||
{
|
||||
SMutexGeneralLocker lock(m_mutex);
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
if (m_count >= SQSize) continue;
|
||||
|
||||
|
@ -55,23 +53,19 @@ public:
|
|||
{
|
||||
while (true)
|
||||
{
|
||||
if (m_mutex.GetOwner() == m_mutex.GetDeadValue())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_count)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Sleep(1);
|
||||
|
||||
SM_Sleep();
|
||||
continue;
|
||||
}
|
||||
|
||||
{
|
||||
SMutexGeneralLocker lock(m_mutex);
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
if (!m_count) continue;
|
||||
|
||||
|
@ -84,19 +78,26 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
volatile u32 GetCount() // may be not safe
|
||||
u32 GetCount()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
return m_count;
|
||||
}
|
||||
|
||||
u32 GetCountUnsafe()
|
||||
{
|
||||
return m_count;
|
||||
}
|
||||
|
||||
volatile bool IsEmpty() // may be not safe
|
||||
bool IsEmpty()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
return !m_count;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
SMutexGeneralLocker lock(m_mutex);
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
m_count = 0;
|
||||
}
|
||||
|
||||
|
@ -104,26 +105,40 @@ public:
|
|||
{
|
||||
while (true)
|
||||
{
|
||||
if (m_mutex.GetOwner() == m_mutex.GetDeadValue())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (!m_count)
|
||||
if (m_count <= pos)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
break;
|
||||
}
|
||||
Sleep(1);
|
||||
|
||||
SM_Sleep();
|
||||
continue;
|
||||
}
|
||||
|
||||
{
|
||||
SMutexGeneralLocker lock(m_mutex);
|
||||
if (m_count) break;
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
if (m_count > pos)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return m_data[(m_pos + pos) % SQSize];
|
||||
}
|
||||
|
||||
T& PeekIfExist(u32 pos = 0)
|
||||
{
|
||||
static T def_value;
|
||||
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
if (m_count <= pos)
|
||||
{
|
||||
return def_value;
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_data[(m_pos + pos) % SQSize];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
88
Utilities/SSemaphore.cpp
Normal file
88
Utilities/SSemaphore.cpp
Normal file
|
@ -0,0 +1,88 @@
|
|||
#include "stdafx.h"
|
||||
#include "Utilities/SSemaphore.h"
|
||||
#include "Emu/System.h"
|
||||
|
||||
void SSemaphore::wait()
|
||||
{
|
||||
u32 order;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
if (m_count && m_out_order == m_in_order)
|
||||
{
|
||||
m_count--;
|
||||
return;
|
||||
}
|
||||
order = m_in_order++;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> cv_lock(m_cv_mutex);
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_cond.wait_for(cv_lock, std::chrono::milliseconds(1));
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
if (m_count)
|
||||
{
|
||||
if (m_out_order == order)
|
||||
{
|
||||
m_count--;
|
||||
m_out_order++;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cond.notify_one();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SSemaphore::try_wait()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
if (m_count && m_in_order == m_out_order)
|
||||
{
|
||||
m_count--;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void SSemaphore::post()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
if (m_count < m_max)
|
||||
{
|
||||
m_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_cond.notify_one();
|
||||
}
|
||||
|
||||
bool SSemaphore::post_and_wait()
|
||||
{
|
||||
// TODO: merge these functions? Probably has a race condition.
|
||||
if (try_wait()) return false;
|
||||
|
||||
post();
|
||||
wait();
|
||||
|
||||
return true;
|
||||
}
|
41
Utilities/SSemaphore.h
Normal file
41
Utilities/SSemaphore.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
|
||||
class SSemaphore
|
||||
{
|
||||
const u32 m_max;
|
||||
u32 m_count;
|
||||
u32 m_in_order;
|
||||
u32 m_out_order;
|
||||
std::mutex m_cv_mutex;
|
||||
std::mutex m_mutex;
|
||||
std::condition_variable m_cond;
|
||||
|
||||
public:
|
||||
SSemaphore(u32 value, u32 max = 1)
|
||||
: m_max(max > 0 ? max : 0xffffffff)
|
||||
, m_count(value > m_max ? m_max : value)
|
||||
, m_in_order(0)
|
||||
, m_out_order(0)
|
||||
{
|
||||
}
|
||||
|
||||
SSemaphore()
|
||||
: m_max(0xffffffff)
|
||||
, m_count(0)
|
||||
, m_in_order(0)
|
||||
, m_out_order(0)
|
||||
{
|
||||
}
|
||||
|
||||
~SSemaphore()
|
||||
{
|
||||
}
|
||||
|
||||
void wait();
|
||||
|
||||
bool try_wait();
|
||||
|
||||
void post();
|
||||
|
||||
bool post_and_wait();
|
||||
};
|
|
@ -1,5 +1,6 @@
|
|||
#include "stdafx.h"
|
||||
#include "StrFmt.h"
|
||||
#include <wx/string.h>
|
||||
|
||||
extern const std::string fmt::placeholder = "???";
|
||||
|
||||
|
@ -14,7 +15,11 @@ std::string fmt::FormatV(const char *fmt, va_list args)
|
|||
for (;;)
|
||||
{
|
||||
std::vector<char> buffptr(length);
|
||||
#if !defined(_MSC_VER)
|
||||
size_t printlen = vsnprintf(buffptr.data(), length, fmt, args);
|
||||
#else
|
||||
size_t printlen = vsnprintf_s(buffptr.data(), length, length - 1, fmt, args);
|
||||
#endif
|
||||
if (printlen < length)
|
||||
{
|
||||
str = std::string(buffptr.data(), printlen);
|
||||
|
@ -31,11 +36,35 @@ std::string fmt::FormatV(std::string fmt, va_list args)
|
|||
return str;
|
||||
}
|
||||
|
||||
std::string replace_first(const std::string& src, const std::string& from, const std::string& to)
|
||||
{
|
||||
auto pos = src.find(from);
|
||||
|
||||
if (pos == std::string::npos)
|
||||
{
|
||||
return src;
|
||||
}
|
||||
|
||||
return (pos ? src.substr(0, pos) + to : to) + std::string(src.c_str() + pos + from.length());
|
||||
}
|
||||
|
||||
std::string replace_all(std::string src, const std::string& from, const std::string& to)
|
||||
{
|
||||
for (auto pos = src.find(from); pos != std::string::npos; src.find(from, pos + 1))
|
||||
{
|
||||
src = (pos ? src.substr(0, pos) + to : to) + std::string(src.c_str() + pos + from.length());
|
||||
pos += to.length();
|
||||
}
|
||||
|
||||
return src;
|
||||
}
|
||||
|
||||
//TODO: move this wx Stuff somewhere else
|
||||
//convert a wxString to a std::string encoded in utf8
|
||||
//CAUTION, only use this to interface with wxWidgets classes
|
||||
std::string fmt::ToUTF8(const wxString& right)
|
||||
{
|
||||
auto ret = std::string(((const char *) right.utf8_str()));
|
||||
auto ret = std::string(((const char *)right.utf8_str()));
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -63,4 +92,46 @@ int fmt::CmpNoCase(const std::string& a, const std::string& b)
|
|||
[](const char& a, const char& b){return tolower(a) == tolower(b); })
|
||||
? 0 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: remove this after every snippet that uses it is gone
|
||||
//WARNING: not fully compatible with CmpNoCase from wxString
|
||||
void fmt::Replace(std::string &str, const std::string &searchterm, const std::string& replaceterm)
|
||||
{
|
||||
size_t cursor = 0;
|
||||
do
|
||||
{
|
||||
cursor = str.find(searchterm, cursor);
|
||||
if (cursor != std::string::npos)
|
||||
{
|
||||
str.replace(cursor, searchterm.size(), replaceterm);
|
||||
cursor += replaceterm.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
|
||||
std::vector<std::string> fmt::rSplit(const std::string& source, const std::string& delim)
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
size_t cursor = 0;
|
||||
do
|
||||
{
|
||||
size_t prevcurs = cursor;
|
||||
cursor = source.find(delim, cursor);
|
||||
if (cursor != std::string::npos)
|
||||
{
|
||||
ret.push_back(source.substr(prevcurs,cursor-prevcurs));
|
||||
cursor += delim.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.push_back(source.substr(prevcurs));
|
||||
break;
|
||||
}
|
||||
} while (true);
|
||||
return ret;
|
||||
}
|
|
@ -1,9 +1,5 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#include <cstdio>
|
||||
class wxString;
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define snprintf _snprintf
|
||||
|
@ -18,6 +14,38 @@ namespace fmt{
|
|||
|
||||
extern const string placeholder;
|
||||
|
||||
template <typename T>
|
||||
std::string AfterLast(const std::string& source, T searchstr)
|
||||
{
|
||||
size_t search_pos = source.rfind(searchstr);
|
||||
search_pos = search_pos == std::string::npos ? 0 : search_pos;
|
||||
return source.substr(search_pos);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string BeforeLast(const std::string& source, T searchstr)
|
||||
{
|
||||
size_t search_pos = source.rfind(searchstr);
|
||||
search_pos = search_pos == std::string::npos ? 0 : search_pos;
|
||||
return source.substr(0, search_pos);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string AfterFirst(const std::string& source, T searchstr)
|
||||
{
|
||||
size_t search_pos = source.find(searchstr);
|
||||
search_pos = search_pos == std::string::npos ? 0 : search_pos;
|
||||
return source.substr(search_pos);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string BeforeFirst(const std::string& source, T searchstr)
|
||||
{
|
||||
size_t search_pos = source.find(searchstr);
|
||||
search_pos = search_pos == std::string::npos ? 0 : search_pos;
|
||||
return source.substr(0, search_pos);
|
||||
}
|
||||
|
||||
// write `fmt` from `pos` to the first occurence of `fmt::placeholder` to
|
||||
// the stream `os`. Then write `arg` to to the stream. If there's no
|
||||
// `fmt::placeholder` after `pos` everything in `fmt` after pos is written
|
||||
|
@ -76,7 +104,7 @@ namespace fmt{
|
|||
|
||||
//wrapper to deal with advance sprintf formating options with automatic length finding
|
||||
template<typename ... Args>
|
||||
string Format(const string &fmt, Args&& ... parameters)
|
||||
string Format(const string &fmt, Args ... parameters)
|
||||
{
|
||||
size_t length = 256;
|
||||
string str;
|
||||
|
@ -84,10 +112,14 @@ namespace fmt{
|
|||
for (;;)
|
||||
{
|
||||
std::vector<char> buffptr(length);
|
||||
#if !defined(_MSC_VER)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wformat-security"
|
||||
size_t printlen = snprintf(buffptr.data(), length, fmt.c_str(), std::forward<Args>(parameters)...);
|
||||
#pragma clang diagnostic pop
|
||||
#else
|
||||
size_t printlen = _snprintf_s(buffptr.data(), length, length - 1, fmt.c_str(), std::forward<Args>(parameters)...);
|
||||
#endif
|
||||
if (printlen < length)
|
||||
{
|
||||
str = string(buffptr.data(), printlen);
|
||||
|
@ -98,6 +130,57 @@ namespace fmt{
|
|||
return str;
|
||||
}
|
||||
|
||||
std::string replace_first(const std::string& src, const std::string& from, const std::string& to);
|
||||
std::string replace_all(std::string src, const std::string& from, const std::string& to);
|
||||
|
||||
template<size_t list_size>
|
||||
std::string replace_all(std::string src, const std::pair<std::string, std::string>(&list)[list_size])
|
||||
{
|
||||
for (size_t pos = 0; pos < src.length(); ++pos)
|
||||
{
|
||||
for (size_t i = 0; i < list_size; ++i)
|
||||
{
|
||||
const size_t comp_length = list[i].first.length();
|
||||
|
||||
if (src.length() - pos < comp_length)
|
||||
continue;
|
||||
|
||||
if (src.substr(pos, comp_length) == list[i].first)
|
||||
{
|
||||
src = (pos ? src.substr(0, pos) + list[i].second : list[i].second) + std::string(src.c_str() + pos + comp_length);
|
||||
pos += list[i].second.length() - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return src;
|
||||
}
|
||||
|
||||
template<size_t list_size>
|
||||
std::string replace_all(std::string src, const std::pair<std::string, std::function<std::string()>>(&list)[list_size])
|
||||
{
|
||||
for (size_t pos = 0; pos < src.length(); ++pos)
|
||||
{
|
||||
for (size_t i = 0; i < list_size; ++i)
|
||||
{
|
||||
const size_t comp_length = list[i].first.length();
|
||||
|
||||
if (src.length() - pos < comp_length)
|
||||
continue;
|
||||
|
||||
if (src.substr(pos, comp_length) == list[i].first)
|
||||
{
|
||||
src = (pos ? src.substr(0, pos) + list[i].second() : list[i].second()) + std::string(src.c_str() + pos + comp_length);
|
||||
pos += list[i].second().length() - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return src;
|
||||
}
|
||||
|
||||
//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);
|
||||
|
@ -110,4 +193,9 @@ namespace fmt{
|
|||
//WARNING: not fully compatible with CmpNoCase from wxString
|
||||
int CmpNoCase(const std::string& a, const std::string& b);
|
||||
|
||||
//TODO: remove this after every snippet that uses it is gone
|
||||
//WARNING: not fully compatible with Replace from wxString
|
||||
void Replace(std::string &str, const std::string &searchterm, const std::string& replaceterm);
|
||||
|
||||
std::vector<std::string> rSplit(const std::string& source, const std::string& delim);
|
||||
}
|
||||
|
|
|
@ -1,20 +1,19 @@
|
|||
#include "stdafx.h"
|
||||
#include "Thread.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(thread)
|
||||
#elif __APPLE__
|
||||
__thread
|
||||
#else
|
||||
thread_local
|
||||
#endif
|
||||
NamedThreadBase* g_tls_this_thread = nullptr;
|
||||
thread_local NamedThreadBase* g_tls_this_thread = nullptr;
|
||||
std::atomic<u32> g_thread_count(0);
|
||||
|
||||
NamedThreadBase* GetCurrentNamedThread()
|
||||
{
|
||||
return g_tls_this_thread;
|
||||
}
|
||||
|
||||
void SetCurrentNamedThread(NamedThreadBase* value)
|
||||
{
|
||||
g_tls_this_thread = value;
|
||||
}
|
||||
|
||||
std::string NamedThreadBase::GetThreadName() const
|
||||
{
|
||||
return m_name;
|
||||
|
@ -25,6 +24,17 @@ void NamedThreadBase::SetThreadName(const std::string& name)
|
|||
m_name = name;
|
||||
}
|
||||
|
||||
void NamedThreadBase::WaitForAnySignal() // wait 1 ms for something
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_signal_mtx);
|
||||
m_signal_cv.wait_for(lock, std::chrono::milliseconds(1));
|
||||
}
|
||||
|
||||
void NamedThreadBase::Notify() // wake up waiting thread or nothing
|
||||
{
|
||||
m_signal_cv.notify_one();
|
||||
}
|
||||
|
||||
ThreadBase::ThreadBase(const std::string& name)
|
||||
: NamedThreadBase(name)
|
||||
, m_executor(nullptr)
|
||||
|
@ -38,7 +48,8 @@ ThreadBase::~ThreadBase()
|
|||
if(IsAlive())
|
||||
Stop(false);
|
||||
|
||||
safe_delete(m_executor);
|
||||
delete m_executor;
|
||||
m_executor = nullptr;
|
||||
}
|
||||
|
||||
void ThreadBase::Start()
|
||||
|
@ -50,15 +61,16 @@ void ThreadBase::Start()
|
|||
m_destroy = false;
|
||||
m_alive = true;
|
||||
|
||||
m_executor = new std::thread(
|
||||
[this]()
|
||||
{
|
||||
g_tls_this_thread = this;
|
||||
m_executor = new std::thread([this]()
|
||||
{
|
||||
SetCurrentNamedThread(this);
|
||||
g_thread_count++;
|
||||
|
||||
Task();
|
||||
Task();
|
||||
|
||||
m_alive = false;
|
||||
});
|
||||
m_alive = false;
|
||||
g_thread_count--;
|
||||
});
|
||||
}
|
||||
|
||||
void ThreadBase::Stop(bool wait, bool send_destroy)
|
||||
|
@ -127,17 +139,12 @@ void thread::start(std::function<void()> func)
|
|||
m_thr = std::thread([func, name]()
|
||||
{
|
||||
NamedThreadBase info(name);
|
||||
g_tls_this_thread = &info;
|
||||
SetCurrentNamedThread(&info);
|
||||
g_thread_count++;
|
||||
|
||||
try
|
||||
{
|
||||
func();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
ConLog.Error("Crash :(");
|
||||
//std::terminate();
|
||||
}
|
||||
func();
|
||||
|
||||
g_thread_count--;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,18 +1,14 @@
|
|||
#pragma once
|
||||
#include "Array.h"
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
|
||||
class ThreadExec;
|
||||
static std::thread::id main_thread;
|
||||
|
||||
class NamedThreadBase
|
||||
{
|
||||
std::string m_name;
|
||||
|
||||
std::condition_variable m_signal_cv;
|
||||
std::mutex m_signal_mtx;
|
||||
|
||||
public:
|
||||
NamedThreadBase(const std::string& name) : m_name(name)
|
||||
{
|
||||
|
@ -24,9 +20,14 @@ public:
|
|||
|
||||
virtual std::string GetThreadName() const;
|
||||
virtual void SetThreadName(const std::string& name);
|
||||
|
||||
void WaitForAnySignal();
|
||||
|
||||
void Notify();
|
||||
};
|
||||
|
||||
NamedThreadBase* GetCurrentNamedThread();
|
||||
void SetCurrentNamedThread(NamedThreadBase* value);
|
||||
|
||||
class ThreadBase : public NamedThreadBase
|
||||
{
|
||||
|
@ -67,142 +68,4 @@ public:
|
|||
void detach();
|
||||
void join();
|
||||
bool joinable() const;
|
||||
};
|
||||
|
||||
template<typename T> class MTPacketBuffer
|
||||
{
|
||||
protected:
|
||||
volatile bool m_busy;
|
||||
volatile u32 m_put, m_get;
|
||||
std::vector<u8> m_buffer;
|
||||
u32 m_max_buffer_size;
|
||||
mutable std::recursive_mutex m_cs_main;
|
||||
|
||||
void CheckBusy()
|
||||
{
|
||||
m_busy = m_put >= m_max_buffer_size;
|
||||
}
|
||||
|
||||
public:
|
||||
MTPacketBuffer(u32 max_buffer_size)
|
||||
: m_max_buffer_size(max_buffer_size)
|
||||
{
|
||||
Flush();
|
||||
}
|
||||
|
||||
~MTPacketBuffer()
|
||||
{
|
||||
Flush();
|
||||
}
|
||||
|
||||
void Flush()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(m_cs_main);
|
||||
m_put = m_get = 0;
|
||||
m_buffer.clear();
|
||||
m_busy = false;
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void _push(const T& v) = 0;
|
||||
virtual T _pop() = 0;
|
||||
|
||||
public:
|
||||
void Push(const T& v)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(m_cs_main);
|
||||
_push(v);
|
||||
}
|
||||
|
||||
T Pop()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(m_cs_main);
|
||||
return _pop();
|
||||
}
|
||||
|
||||
bool HasNewPacket() const { std::lock_guard<std::recursive_mutex> lock(m_cs_main); return m_put != m_get; }
|
||||
bool IsBusy() const { return m_busy; }
|
||||
};
|
||||
|
||||
static __forceinline bool SemaphorePostAndWait(wxSemaphore& sem)
|
||||
{
|
||||
if(sem.TryWait() != wxSEMA_BUSY) return false;
|
||||
|
||||
sem.Post();
|
||||
sem.Wait();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
class StepThread : public ThreadBase
|
||||
{
|
||||
wxSemaphore m_main_sem;
|
||||
wxSemaphore m_destroy_sem;
|
||||
volatile bool m_exit;
|
||||
|
||||
protected:
|
||||
StepThread(const std::string& name = "Unknown StepThread")
|
||||
: ThreadBase(true, name)
|
||||
, m_exit(false)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~StepThread() throw()
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void Task()
|
||||
{
|
||||
m_exit = false;
|
||||
|
||||
while(!TestDestroy())
|
||||
{
|
||||
m_main_sem.Wait();
|
||||
|
||||
if(TestDestroy() || m_exit) break;
|
||||
|
||||
Step();
|
||||
}
|
||||
|
||||
while(!TestDestroy()) Sleep(0);
|
||||
if(m_destroy_sem.TryWait() != wxSEMA_NO_ERROR) m_destroy_sem.Post();
|
||||
}
|
||||
|
||||
virtual void Step()=0;
|
||||
|
||||
public:
|
||||
void DoStep()
|
||||
{
|
||||
if(IsRunning()) m_main_sem.Post();
|
||||
}
|
||||
|
||||
void WaitForExit()
|
||||
{
|
||||
if(TestDestroy()) m_destroy_sem.Wait();
|
||||
}
|
||||
|
||||
void WaitForNextStep()
|
||||
{
|
||||
if(!IsRunning()) return;
|
||||
|
||||
while(m_main_sem.TryWait() != wxSEMA_NO_ERROR) Sleep(0);
|
||||
}
|
||||
|
||||
void Exit(bool wait = false)
|
||||
{
|
||||
if(!IsAlive()) return;
|
||||
|
||||
if(m_main_sem.TryWait() != wxSEMA_NO_ERROR)
|
||||
{
|
||||
m_exit = true;
|
||||
m_main_sem.Post();
|
||||
}
|
||||
|
||||
Delete();
|
||||
|
||||
if(wait) WaitForExit();
|
||||
}
|
||||
};
|
||||
*/
|
||||
};
|
403
Utilities/rFile.cpp
Normal file
403
Utilities/rFile.cpp
Normal file
|
@ -0,0 +1,403 @@
|
|||
#include "stdafx.h"
|
||||
#include "Log.h"
|
||||
#include <wx/dir.h>
|
||||
#include <wx/file.h>
|
||||
#include <wx/filename.h>
|
||||
#include "rFile.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
|
||||
// Maybe in StrFmt?
|
||||
std::wstring ConvertUTF8ToWString(const std::string &source) {
|
||||
int len = (int)source.size();
|
||||
int size = (int)MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, NULL, 0);
|
||||
std::wstring str;
|
||||
str.resize(size);
|
||||
if (size > 0) {
|
||||
MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, &str[0], size);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool getFileInfo(const char *path, FileInfo *fileInfo) {
|
||||
// TODO: Expand relative paths?
|
||||
fileInfo->fullName = path;
|
||||
|
||||
#ifdef _WIN32
|
||||
WIN32_FILE_ATTRIBUTE_DATA attrs;
|
||||
if (!GetFileAttributesExW(ConvertUTF8ToWString(path).c_str(), GetFileExInfoStandard, &attrs)) {
|
||||
fileInfo->size = 0;
|
||||
fileInfo->isDirectory = false;
|
||||
fileInfo->exists = false;
|
||||
return false;
|
||||
}
|
||||
fileInfo->size = (uint64_t)attrs.nFileSizeLow | ((uint64_t)attrs.nFileSizeHigh << 32);
|
||||
fileInfo->isDirectory = (attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
fileInfo->isWritable = (attrs.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0;
|
||||
fileInfo->exists = true;
|
||||
#else
|
||||
struct stat64 file_info;
|
||||
int result = stat64(path, &file_info);
|
||||
|
||||
if (result < 0) {
|
||||
LOG_NOTICE(GENERAL, "IsDirectory: stat failed on %s", path);
|
||||
fileInfo->exists = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
fileInfo->isDirectory = S_ISDIR(file_info.st_mode);
|
||||
fileInfo->isWritable = false;
|
||||
fileInfo->size = file_info.st_size;
|
||||
fileInfo->exists = true;
|
||||
// HACK: approximation
|
||||
if (file_info.st_mode & 0200)
|
||||
fileInfo->isWritable = true;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rIsDir(const std::string &filename) {
|
||||
FileInfo info;
|
||||
getFileInfo(filename.c_str(), &info);
|
||||
return info.isDirectory;
|
||||
}
|
||||
|
||||
bool rMkdir(const std::string &dir)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return !_mkdir(dir.c_str());
|
||||
#else
|
||||
return !mkdir(dir.c_str(), 0777);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool rMkpath(const std::string &path)
|
||||
{
|
||||
size_t start=0, pos;
|
||||
std::string dir;
|
||||
bool ret;
|
||||
|
||||
while (true) {
|
||||
if ((pos = path.find_first_of("/\\", start)) == std::string::npos)
|
||||
pos = path.length();
|
||||
|
||||
dir = path.substr(0,pos++);
|
||||
start = pos;
|
||||
if(dir.size() == 0)
|
||||
continue;
|
||||
#ifdef _WIN32
|
||||
if((ret = _mkdir(dir.c_str())) && errno != EEXIST){
|
||||
#else
|
||||
if((ret = mkdir(dir.c_str(), 0777)) && errno != EEXIST){
|
||||
#endif
|
||||
return !ret;
|
||||
}
|
||||
if (pos >= path.length())
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rRmdir(const std::string &dir)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (!RemoveDirectory(ConvertUTF8ToWString(dir).c_str())) {
|
||||
LOG_ERROR(GENERAL, "Error deleting directory %s: %i", dir.c_str(), GetLastError());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
rmdir(dir.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
bool rRename(const std::string &from, const std::string &to)
|
||||
{
|
||||
// TODO: Deal with case-sensitivity
|
||||
#ifdef _WIN32
|
||||
return (MoveFile(ConvertUTF8ToWString(from).c_str(), ConvertUTF8ToWString(to).c_str()) == TRUE);
|
||||
#else
|
||||
return (0 == rename(from.c_str(), to.c_str()));
|
||||
#endif
|
||||
}
|
||||
|
||||
bool rExists(const std::string &file)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
std::wstring wstr = ConvertUTF8ToWString(file);
|
||||
return GetFileAttributes(wstr.c_str()) != 0xFFFFFFFF;
|
||||
#else
|
||||
struct stat buffer;
|
||||
return (stat (file.c_str(), &buffer) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool rRemoveFile(const std::string &file)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (!DeleteFile(ConvertUTF8ToWString(file).c_str())) {
|
||||
LOG_ERROR(GENERAL, "Error deleting %s: %i", file.c_str(), GetLastError());
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
int err = unlink(file.c_str());
|
||||
if (err) {
|
||||
LOG_ERROR(GENERAL, "Error unlinking %s: %i", file.c_str(), err);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
wxFile::OpenMode convertOpenMode(rFile::OpenMode open)
|
||||
{
|
||||
wxFile::OpenMode mode;
|
||||
switch (open)
|
||||
{
|
||||
case rFile::read:
|
||||
mode = wxFile::read;
|
||||
break;
|
||||
case rFile::write:
|
||||
mode = wxFile::write;
|
||||
break;
|
||||
case rFile::read_write:
|
||||
mode = wxFile::read_write;
|
||||
break;
|
||||
case rFile::write_append:
|
||||
mode = wxFile::write_append;
|
||||
break;
|
||||
case rFile::write_excl:
|
||||
mode = wxFile::write_excl;
|
||||
break;
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
rFile::OpenMode rConvertOpenMode(wxFile::OpenMode open)
|
||||
{
|
||||
rFile::OpenMode mode;
|
||||
switch (open)
|
||||
{
|
||||
case wxFile::read:
|
||||
mode = rFile::read;
|
||||
break;
|
||||
case wxFile::write:
|
||||
mode = rFile::write;
|
||||
break;
|
||||
case wxFile::read_write:
|
||||
mode = rFile::read_write;
|
||||
break;
|
||||
case wxFile::write_append:
|
||||
mode = rFile::write_append;
|
||||
break;
|
||||
case wxFile::write_excl:
|
||||
mode = rFile::write_excl;
|
||||
break;
|
||||
}
|
||||
return mode;
|
||||
}
|
||||
|
||||
wxSeekMode convertSeekMode(rSeekMode mode)
|
||||
{
|
||||
wxSeekMode ret;
|
||||
switch (mode)
|
||||
{
|
||||
case rFromStart:
|
||||
ret = wxFromStart;
|
||||
break;
|
||||
case rFromCurrent:
|
||||
ret = wxFromCurrent;
|
||||
break;
|
||||
case rFromEnd:
|
||||
ret = wxFromEnd;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
rSeekMode rConvertSeekMode(wxSeekMode mode)
|
||||
{
|
||||
rSeekMode ret;
|
||||
switch (mode)
|
||||
{
|
||||
case wxFromStart:
|
||||
ret = rFromStart;
|
||||
break;
|
||||
case wxFromCurrent:
|
||||
ret = rFromCurrent;
|
||||
break;
|
||||
case wxFromEnd:
|
||||
ret = rFromEnd;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
rFile::rFile()
|
||||
{
|
||||
handle = reinterpret_cast<void*>(new wxFile());
|
||||
}
|
||||
|
||||
rFile::rFile(const std::string& filename, rFile::OpenMode open)
|
||||
{
|
||||
|
||||
handle = reinterpret_cast<void*>(new wxFile(fmt::FromUTF8(filename), convertOpenMode(open)));
|
||||
}
|
||||
|
||||
rFile::rFile(int fd)
|
||||
{
|
||||
handle = reinterpret_cast<void*>(new wxFile(fd));
|
||||
}
|
||||
|
||||
rFile::~rFile()
|
||||
{
|
||||
delete reinterpret_cast<wxFile*>(handle);
|
||||
}
|
||||
|
||||
bool rFile::Access(const std::string &filename, rFile::OpenMode mode)
|
||||
{
|
||||
return wxFile::Access(fmt::FromUTF8(filename), convertOpenMode(mode));
|
||||
}
|
||||
|
||||
size_t rFile::Write(const void *buffer, size_t count)
|
||||
{
|
||||
return reinterpret_cast<wxFile*>(handle)->Write(buffer,count);
|
||||
}
|
||||
|
||||
bool rFile::Write(const std::string &text)
|
||||
{
|
||||
return reinterpret_cast<wxFile*>(handle)->Write(reinterpret_cast<const void*>(text.c_str()),text.size());
|
||||
}
|
||||
|
||||
bool rFile::Close()
|
||||
{
|
||||
return reinterpret_cast<wxFile*>(handle)->Close();
|
||||
}
|
||||
|
||||
bool rFile::Create(const std::string &filename, bool overwrite, int access)
|
||||
{
|
||||
return reinterpret_cast<wxFile*>(handle)->Create(fmt::FromUTF8(filename), overwrite, access);
|
||||
}
|
||||
|
||||
bool rFile::Open(const std::string &filename, rFile::OpenMode mode, int access)
|
||||
{
|
||||
return reinterpret_cast<wxFile*>(handle)->Open(fmt::FromUTF8(filename), convertOpenMode(mode), access);
|
||||
}
|
||||
|
||||
bool rFile::IsOpened() const
|
||||
{
|
||||
return reinterpret_cast<wxFile*>(handle)->IsOpened();
|
||||
}
|
||||
|
||||
size_t rFile::Length() const
|
||||
{
|
||||
return reinterpret_cast<wxFile*>(handle)->Length();
|
||||
}
|
||||
|
||||
size_t rFile::Read(void *buffer, size_t count)
|
||||
{
|
||||
return reinterpret_cast<wxFile*>(handle)->Read(buffer,count);
|
||||
}
|
||||
|
||||
size_t rFile::Seek(size_t ofs, rSeekMode mode)
|
||||
{
|
||||
return reinterpret_cast<wxFile*>(handle)->Seek(ofs, convertSeekMode(mode));
|
||||
}
|
||||
|
||||
size_t rFile::Tell() const
|
||||
{
|
||||
return reinterpret_cast<wxFile*>(handle)->Tell();
|
||||
}
|
||||
|
||||
rDir::rDir()
|
||||
{
|
||||
handle = reinterpret_cast<void*>(new wxDir());
|
||||
}
|
||||
|
||||
rDir::~rDir()
|
||||
{
|
||||
delete reinterpret_cast<wxDir*>(handle);
|
||||
}
|
||||
|
||||
rDir::rDir(const std::string &path)
|
||||
{
|
||||
handle = reinterpret_cast<void*>(new wxDir(fmt::FromUTF8(path)));
|
||||
}
|
||||
|
||||
bool rDir::Open(const std::string& path)
|
||||
{
|
||||
return reinterpret_cast<wxDir*>(handle)->Open(fmt::FromUTF8(path));
|
||||
}
|
||||
|
||||
bool rDir::IsOpened() const
|
||||
{
|
||||
return reinterpret_cast<wxDir*>(handle)->IsOpened();
|
||||
}
|
||||
|
||||
bool rDir::GetFirst(std::string *filename) const
|
||||
{
|
||||
wxString str;
|
||||
bool res;
|
||||
res = reinterpret_cast<wxDir*>(handle)->GetFirst(&str);
|
||||
*filename = str.ToStdString();
|
||||
return res;
|
||||
}
|
||||
|
||||
bool rDir::GetNext(std::string *filename) const
|
||||
{
|
||||
wxString str;
|
||||
bool res;
|
||||
res = reinterpret_cast<wxDir*>(handle)->GetNext(&str);
|
||||
*filename = str.ToStdString();
|
||||
return res;
|
||||
}
|
||||
|
||||
rFileName::rFileName()
|
||||
{
|
||||
handle = reinterpret_cast<void*>(new wxFileName());
|
||||
}
|
||||
|
||||
rFileName::~rFileName()
|
||||
{
|
||||
delete reinterpret_cast<wxFileName*>(handle);
|
||||
}
|
||||
|
||||
rFileName::rFileName(const rFileName& filename)
|
||||
{
|
||||
handle = reinterpret_cast<void*>(new wxFileName(*reinterpret_cast<wxFileName*>(filename.handle)));
|
||||
}
|
||||
|
||||
|
||||
rFileName::rFileName(const std::string& name)
|
||||
{
|
||||
handle = reinterpret_cast<void*>(new wxFileName(fmt::FromUTF8(name)));
|
||||
}
|
||||
|
||||
std::string rFileName::GetFullPath()
|
||||
{
|
||||
return fmt::ToUTF8(reinterpret_cast<wxFileName*>(handle)->GetFullPath());
|
||||
}
|
||||
|
||||
std::string rFileName::GetPath()
|
||||
{
|
||||
return fmt::ToUTF8(reinterpret_cast<wxFileName*>(handle)->GetPath());
|
||||
}
|
||||
|
||||
std::string rFileName::GetName()
|
||||
{
|
||||
return fmt::ToUTF8(reinterpret_cast<wxFileName*>(handle)->GetName());
|
||||
}
|
||||
|
||||
std::string rFileName::GetFullName()
|
||||
{
|
||||
return fmt::ToUTF8(reinterpret_cast<wxFileName*>(handle)->GetFullName());
|
||||
}
|
||||
|
||||
bool rFileName::Normalize()
|
||||
{
|
||||
return reinterpret_cast<wxFileName*>(handle)->Normalize();
|
||||
}
|
||||
|
87
Utilities/rFile.h
Normal file
87
Utilities/rFile.h
Normal file
|
@ -0,0 +1,87 @@
|
|||
#pragma once
|
||||
|
||||
struct FileInfo {
|
||||
std::string name;
|
||||
std::string fullName;
|
||||
bool exists;
|
||||
bool isDirectory;
|
||||
bool isWritable;
|
||||
uint64_t size;
|
||||
};
|
||||
|
||||
bool getFileInfo(const char *path, FileInfo *fileInfo);
|
||||
bool rIsDir(const std::string& filename);
|
||||
bool rRmdir(const std::string& dir);
|
||||
bool rMkdir(const std::string& dir);
|
||||
bool rMkpath(const std::string& path);
|
||||
bool rRename(const std::string &from, const std::string &to);
|
||||
bool rExists(const std::string &path);
|
||||
bool rRemoveFile(const std::string &path);
|
||||
|
||||
enum rSeekMode
|
||||
{
|
||||
rFromStart,
|
||||
rFromCurrent,
|
||||
rFromEnd
|
||||
};
|
||||
|
||||
class rFile
|
||||
{
|
||||
public:
|
||||
enum OpenMode
|
||||
{
|
||||
read,
|
||||
write,
|
||||
read_write,
|
||||
write_append,
|
||||
write_excl
|
||||
};
|
||||
rFile();
|
||||
rFile(const rFile& other) = delete;
|
||||
~rFile();
|
||||
rFile(const std::string& filename, rFile::OpenMode open = rFile::read);
|
||||
rFile(int fd);
|
||||
static bool Access(const std::string &filename, rFile::OpenMode mode);
|
||||
size_t Write(const void *buffer, size_t count);
|
||||
bool Write(const std::string &text);
|
||||
bool Close();
|
||||
bool Create(const std::string &filename, bool overwrite = false, int access = 0666);
|
||||
bool Open(const std::string &filename, rFile::OpenMode mode = rFile::read, int access = 0666);
|
||||
static bool Exists(const std::string&);
|
||||
bool IsOpened() const;
|
||||
size_t Length() const;
|
||||
size_t Read(void *buffer, size_t count);
|
||||
size_t Seek(size_t ofs, rSeekMode mode = rFromStart);
|
||||
size_t Tell() const;
|
||||
|
||||
void *handle;
|
||||
};
|
||||
|
||||
struct rDir
|
||||
{
|
||||
rDir();
|
||||
~rDir();
|
||||
rDir(const rDir& other) = delete;
|
||||
rDir(const std::string &path);
|
||||
bool Open(const std::string& path);
|
||||
bool IsOpened() const;
|
||||
static bool Exists(const std::string &path);
|
||||
bool GetFirst(std::string *filename) const;
|
||||
bool GetNext(std::string *filename) const;
|
||||
|
||||
void *handle;
|
||||
};
|
||||
struct rFileName
|
||||
{
|
||||
rFileName();
|
||||
rFileName(const rFileName& other);
|
||||
~rFileName();
|
||||
rFileName(const std::string& name);
|
||||
std::string GetFullPath();
|
||||
std::string GetPath();
|
||||
std::string GetName();
|
||||
std::string GetFullName();
|
||||
bool Normalize();
|
||||
|
||||
void *handle;
|
||||
};
|
34
Utilities/rMsgBox.cpp
Normal file
34
Utilities/rMsgBox.cpp
Normal file
|
@ -0,0 +1,34 @@
|
|||
#include "stdafx.h"
|
||||
#include "restore_new.h"
|
||||
#include <wx/msgdlg.h>
|
||||
#include "define_new_memleakdetect.h"
|
||||
#include "rMsgBox.h"
|
||||
|
||||
#ifndef QT_UI
|
||||
rMessageDialog::rMessageDialog(void *parent, const std::string& msg, const std::string& title , long style )
|
||||
{
|
||||
handle = reinterpret_cast<void*>(new wxMessageDialog(
|
||||
reinterpret_cast<wxWindow*>(parent)
|
||||
, fmt::FromUTF8(msg)
|
||||
, fmt::FromUTF8(title)
|
||||
, style
|
||||
));
|
||||
}
|
||||
|
||||
rMessageDialog::~rMessageDialog()
|
||||
{
|
||||
delete reinterpret_cast<wxMessageDialog*>(handle);
|
||||
}
|
||||
|
||||
long rMessageDialog::ShowModal()
|
||||
{
|
||||
return reinterpret_cast<wxMessageDialog*>(handle)->ShowModal();
|
||||
}
|
||||
|
||||
long rMessageBox(const std::string& message, const std::string& title, long style)
|
||||
{
|
||||
return wxMessageBox(fmt::FromUTF8(message), fmt::FromUTF8(title),style);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
38
Utilities/rMsgBox.h
Normal file
38
Utilities/rMsgBox.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
#pragma once
|
||||
|
||||
enum MsgBoxParams : unsigned long
|
||||
{
|
||||
rYES_DEFAULT = 0x0,
|
||||
rOK_DEFAULT = 0x0,
|
||||
rCENTRE = 0x1,
|
||||
rYES = 0x2, //res
|
||||
rOK = 0x4,
|
||||
rNO = 0x8, //res
|
||||
rCANCEL = 0x10,
|
||||
rYES_NO = 0xA,
|
||||
rNO_DEFAULT = 0x80,
|
||||
rICON_EXCLAMATION = 0x100,
|
||||
rICON_ERROR = 0x200,
|
||||
rICON_HAND = 0x200,
|
||||
rICON_QUESTION = 0x400,
|
||||
rICON_INFORMATION = 0x800,
|
||||
rHELP = 0x1000,
|
||||
rID_CANCEL = 0x13ED,
|
||||
rID_YES = 0x13EF, //resDialog
|
||||
rSTAY_ON_TOP = 0x8000,
|
||||
rICON_NONE = 0x40000,
|
||||
rICON_AUTH_NEEDED = 0x80000,
|
||||
rCANCEL_DEFAULT = 0x80000000,
|
||||
};
|
||||
|
||||
struct rMessageDialog
|
||||
{
|
||||
rMessageDialog(void *parent, const std::string& msg, const std::string& title = "RPCS3", long style = rOK | rCENTRE);
|
||||
rMessageDialog(const rMessageDialog& other) = delete;
|
||||
~rMessageDialog();
|
||||
long ShowModal();
|
||||
void *handle;
|
||||
};
|
||||
|
||||
long rMessageBox(const std::string& message, const std::string& title,long style);
|
||||
|
57
Utilities/rPlatform.cpp
Normal file
57
Utilities/rPlatform.cpp
Normal file
|
@ -0,0 +1,57 @@
|
|||
#include "stdafx.h"
|
||||
#include "restore_new.h"
|
||||
#include <wx/image.h>
|
||||
#include "define_new_memleakdetect.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
|
||||
#include "rPlatform.h"
|
||||
|
||||
rImage::rImage()
|
||||
{
|
||||
handle = static_cast<void*>(new wxImage());
|
||||
}
|
||||
|
||||
rImage::~rImage()
|
||||
{
|
||||
delete static_cast<wxImage*>(handle);
|
||||
}
|
||||
|
||||
void rImage::Create(int width, int height, void *data, void *alpha)
|
||||
{
|
||||
static_cast<wxImage*>(handle)->Create(width, height, static_cast<unsigned char*>(data), static_cast<unsigned char*>(alpha));
|
||||
}
|
||||
void rImage::SaveFile(const std::string& name, rImageType type)
|
||||
{
|
||||
if (type == rBITMAP_TYPE_PNG)
|
||||
{
|
||||
static_cast<wxImage*>(handle)->SaveFile(fmt::FromUTF8(name),wxBITMAP_TYPE_PNG);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::string("unsupported type");
|
||||
}
|
||||
}
|
||||
|
||||
std::string rPlatform::getConfigDir()
|
||||
{
|
||||
static std::string dir = ".";
|
||||
if (dir == ".") {
|
||||
#ifdef _WIN32
|
||||
dir = "";
|
||||
//mkdir(dir.c_str());
|
||||
#else
|
||||
if (getenv("XDG_CONFIG_HOME") != NULL)
|
||||
dir = getenv("XDG_CONFIG_HOME");
|
||||
else if (getenv("HOME") != NULL)
|
||||
dir = getenv("HOME") + std::string("/.config");
|
||||
else // Just in case
|
||||
dir = "./config";
|
||||
dir = dir + "/rpcs3/";
|
||||
mkdir(dir.c_str(), 0777);
|
||||
#endif
|
||||
}
|
||||
return dir;
|
||||
}
|
45
Utilities/rPlatform.h
Normal file
45
Utilities/rPlatform.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
#pragma once
|
||||
|
||||
struct rPlatform
|
||||
{
|
||||
static std::string getConfigDir();
|
||||
};
|
||||
|
||||
/**********************************************************************
|
||||
*********** RSX Debugger
|
||||
************************************************************************/
|
||||
|
||||
struct RSXDebuggerProgram
|
||||
{
|
||||
u32 id;
|
||||
u32 vp_id;
|
||||
u32 fp_id;
|
||||
std::string vp_shader;
|
||||
std::string fp_shader;
|
||||
bool modified;
|
||||
|
||||
RSXDebuggerProgram()
|
||||
: modified(false)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
extern std::vector<RSXDebuggerProgram> m_debug_programs;
|
||||
|
||||
/**********************************************************************
|
||||
*********** Image stuff
|
||||
************************************************************************/
|
||||
enum rImageType
|
||||
{
|
||||
rBITMAP_TYPE_PNG
|
||||
};
|
||||
struct rImage
|
||||
{
|
||||
rImage();
|
||||
rImage(const rImage &) = delete;
|
||||
~rImage();
|
||||
void Create(int width , int height, void *data, void *alpha);
|
||||
void SaveFile(const std::string& name, rImageType type);
|
||||
|
||||
void *handle;
|
||||
};
|
232
Utilities/rTime.cpp
Normal file
232
Utilities/rTime.cpp
Normal file
|
@ -0,0 +1,232 @@
|
|||
#include "stdafx.h"
|
||||
#include "rTime.h"
|
||||
|
||||
#include <wx/datetime.h>
|
||||
|
||||
std::string rDefaultDateTimeFormat = "%c";
|
||||
|
||||
rTimeSpan::rTimeSpan()
|
||||
{
|
||||
handle = static_cast<void *>(new wxTimeSpan());
|
||||
}
|
||||
|
||||
rTimeSpan::~rTimeSpan()
|
||||
{
|
||||
delete static_cast<wxTimeSpan*>(handle);
|
||||
}
|
||||
|
||||
rTimeSpan::rTimeSpan(const rTimeSpan& other)
|
||||
|
||||
{
|
||||
handle = static_cast<void *>(new wxTimeSpan(*static_cast<wxTimeSpan*>(other.handle)));
|
||||
|
||||
}
|
||||
|
||||
rTimeSpan::rTimeSpan(int a, int b , int c, int d)
|
||||
{
|
||||
handle = static_cast<void *>(new wxTimeSpan(a,b,c,d));
|
||||
}
|
||||
|
||||
|
||||
rDateSpan::rDateSpan()
|
||||
{
|
||||
handle = static_cast<void *>(new wxDateSpan());
|
||||
}
|
||||
|
||||
rDateSpan::~rDateSpan()
|
||||
{
|
||||
delete static_cast<wxDateSpan*>(handle);
|
||||
}
|
||||
|
||||
rDateSpan::rDateSpan(const rDateSpan& other)
|
||||
{
|
||||
handle = static_cast<void *>(new wxDateSpan(*static_cast<wxDateSpan*>(other.handle)));
|
||||
}
|
||||
|
||||
rDateSpan::rDateSpan(int a, int b, int c, int d)
|
||||
{
|
||||
handle = static_cast<void *>(new wxDateSpan(a,b,c,d));
|
||||
}
|
||||
|
||||
rDateTime::rDateTime()
|
||||
{
|
||||
handle = static_cast<void *>(new wxDateTime());
|
||||
}
|
||||
|
||||
rDateTime::~rDateTime()
|
||||
{
|
||||
delete static_cast<wxDateTime*>(handle);
|
||||
}
|
||||
|
||||
rDateTime::rDateTime(const rDateTime& other)
|
||||
{
|
||||
handle = static_cast<void *>(new wxDateTime(*static_cast<wxDateTime*>(other.handle)));
|
||||
}
|
||||
|
||||
rDateTime::rDateTime(const time_t& time)
|
||||
{
|
||||
handle = static_cast<void *>(new wxDateTime(time));
|
||||
}
|
||||
|
||||
rDateTime::rDateTime(u16 day, rDateTime::Month month, u16 year, u16 hour, u16 minute, u16 second, u32 millisecond)
|
||||
{
|
||||
handle = static_cast<void *>(new wxDateTime(day,(wxDateTime::Month)month,year,hour,minute,second,millisecond));
|
||||
}
|
||||
|
||||
rDateTime rDateTime::UNow()
|
||||
{
|
||||
rDateTime time;
|
||||
delete static_cast<wxDateTime*>(time.handle);
|
||||
time.handle = static_cast<void *>(new wxDateTime(wxDateTime::UNow()));
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
rDateTime rDateTime::FromUTC(bool val)
|
||||
{
|
||||
rDateTime time(*this);
|
||||
void *temp = time.handle;
|
||||
|
||||
time.handle = static_cast<void *>(new wxDateTime(static_cast<wxDateTime*>(temp)->FromTimezone(wxDateTime::GMT0, val)));
|
||||
delete static_cast<wxDateTime*>(temp);
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
rDateTime rDateTime::ToUTC(bool val)
|
||||
{
|
||||
rDateTime time(*this);
|
||||
void *temp = time.handle;
|
||||
|
||||
time.handle = static_cast<void *>(new wxDateTime(static_cast<wxDateTime*>(temp)->ToTimezone(wxDateTime::GMT0, val)));
|
||||
delete static_cast<wxDateTime*>(temp);
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
time_t rDateTime::GetTicks()
|
||||
{
|
||||
return static_cast<wxDateTime*>(handle)->GetTicks();
|
||||
}
|
||||
|
||||
void rDateTime::Add(const rTimeSpan& span)
|
||||
{
|
||||
static_cast<wxDateTime*>(handle)->Add(*static_cast<wxTimeSpan*>(span.handle));
|
||||
}
|
||||
|
||||
void rDateTime::Add(const rDateSpan& span)
|
||||
{
|
||||
static_cast<wxDateTime*>(handle)->Add(*static_cast<wxDateSpan*>(span.handle));
|
||||
}
|
||||
|
||||
wxDateTime::TimeZone convertTZ(rDateTime::rTimeZone tz)
|
||||
{
|
||||
switch (tz)
|
||||
{
|
||||
case rDateTime::Local:
|
||||
return wxDateTime::Local;
|
||||
case rDateTime::GMT0:
|
||||
return wxDateTime::GMT0;
|
||||
case rDateTime::UTC:
|
||||
return wxDateTime::UTC;
|
||||
default:
|
||||
throw std::string("WRONG DATETIME");
|
||||
}
|
||||
}
|
||||
|
||||
std::string rDateTime::Format(const std::string &format, const rTimeZone &tz) const
|
||||
{
|
||||
return fmt::ToUTF8(static_cast<wxDateTime*>(handle)->Format(fmt::FromUTF8(format),convertTZ(tz)));
|
||||
}
|
||||
|
||||
void rDateTime::ParseDateTime(const char* format)
|
||||
{
|
||||
static_cast<wxDateTime*>(handle)->ParseDateTime(format);
|
||||
}
|
||||
|
||||
u32 rDateTime::GetAsDOS()
|
||||
{
|
||||
return static_cast<wxDateTime*>(handle)->GetAsDOS();
|
||||
}
|
||||
|
||||
rDateTime &rDateTime::SetFromDOS(u32 fromdos)
|
||||
{
|
||||
static_cast<wxDateTime*>(handle)->SetFromDOS(fromdos);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool rDateTime::IsLeapYear(int year, rDateTime::Calender cal)
|
||||
{
|
||||
if (cal == Gregorian)
|
||||
{
|
||||
return wxDateTime::IsLeapYear(year, wxDateTime::Gregorian);
|
||||
}
|
||||
else
|
||||
{
|
||||
return wxDateTime::IsLeapYear(year, wxDateTime::Julian);
|
||||
}
|
||||
}
|
||||
|
||||
int rDateTime::GetNumberOfDays(rDateTime::Month month, int year, rDateTime::Calender cal)
|
||||
{
|
||||
if (cal == Gregorian)
|
||||
{
|
||||
return wxDateTime::GetNumberOfDays(static_cast<wxDateTime::Month>(month), year, wxDateTime::Gregorian);
|
||||
}
|
||||
else
|
||||
{
|
||||
return wxDateTime::GetNumberOfDays(static_cast<wxDateTime::Month>(month), year, wxDateTime::Julian);
|
||||
}
|
||||
}
|
||||
|
||||
void rDateTime::SetToWeekDay(rDateTime::WeekDay day, int n, rDateTime::Month month, int year)
|
||||
{
|
||||
static_cast<wxDateTime*>(handle)->SetToWeekDay(
|
||||
static_cast<wxDateTime::WeekDay>(day)
|
||||
, n
|
||||
, static_cast<wxDateTime::Month>(month)
|
||||
, year
|
||||
);
|
||||
}
|
||||
|
||||
int rDateTime::GetWeekDay()
|
||||
{
|
||||
return static_cast<wxDateTime*>(handle)->GetWeekDay();
|
||||
}
|
||||
|
||||
u16 rDateTime::GetYear(rDateTime::TZ timezone)
|
||||
{
|
||||
return static_cast<wxDateTime*>(handle)->GetYear(convertTZ(timezone));
|
||||
}
|
||||
|
||||
u16 rDateTime::GetMonth(rDateTime::TZ timezone)
|
||||
{
|
||||
return static_cast<wxDateTime*>(handle)->GetMonth(convertTZ(timezone));
|
||||
}
|
||||
|
||||
u16 rDateTime::GetDay(rDateTime::TZ timezone)
|
||||
{
|
||||
return static_cast<wxDateTime*>(handle)->GetDay(convertTZ(timezone));
|
||||
}
|
||||
|
||||
u16 rDateTime::GetHour(rDateTime::TZ timezone)
|
||||
{
|
||||
return static_cast<wxDateTime*>(handle)->GetHour(convertTZ(timezone));
|
||||
}
|
||||
|
||||
u16 rDateTime::GetMinute(rDateTime::TZ timezone)
|
||||
{
|
||||
return static_cast<wxDateTime*>(handle)->GetMinute(convertTZ(timezone));
|
||||
}
|
||||
|
||||
u16 rDateTime::GetSecond(rDateTime::TZ timezone)
|
||||
{
|
||||
return static_cast<wxDateTime*>(handle)->GetSecond(convertTZ(timezone));
|
||||
}
|
||||
|
||||
u32 rDateTime::GetMillisecond(rDateTime::TZ timezone)
|
||||
{
|
||||
return static_cast<wxDateTime*>(handle)->GetMillisecond(convertTZ(timezone));
|
||||
}
|
||||
|
||||
|
102
Utilities/rTime.h
Normal file
102
Utilities/rTime.h
Normal file
|
@ -0,0 +1,102 @@
|
|||
#pragma once
|
||||
|
||||
extern std::string rDefaultDateTimeFormat;
|
||||
|
||||
|
||||
struct rTimeSpan
|
||||
{
|
||||
rTimeSpan();
|
||||
~rTimeSpan();
|
||||
rTimeSpan(const rTimeSpan& other);
|
||||
rTimeSpan(int, int, int, int);
|
||||
|
||||
void *handle;
|
||||
};
|
||||
|
||||
struct rDateSpan
|
||||
{
|
||||
rDateSpan();
|
||||
~rDateSpan();
|
||||
rDateSpan(const rDateSpan& other);
|
||||
rDateSpan(int, int, int, int);
|
||||
|
||||
void *handle;
|
||||
};
|
||||
|
||||
struct rDateTime
|
||||
{
|
||||
enum TZ
|
||||
{
|
||||
Local, GMT0,UTC
|
||||
};
|
||||
enum Calender
|
||||
{
|
||||
Gregorian, Julian
|
||||
};
|
||||
|
||||
using rTimeZone = TZ;
|
||||
|
||||
enum WeekDay
|
||||
{
|
||||
Sun = 0,
|
||||
Mon,
|
||||
Tue,
|
||||
Wed,
|
||||
Thu,
|
||||
Fri,
|
||||
Sat,
|
||||
Inv_WeekDay
|
||||
};
|
||||
|
||||
enum Month {
|
||||
Jan = 0,
|
||||
Feb = 1,
|
||||
Mar = 2,
|
||||
Apr = 3,
|
||||
May = 4,
|
||||
Jun = 5,
|
||||
Jul = 6,
|
||||
Aug = 7,
|
||||
Sep = 8,
|
||||
Oct = 9,
|
||||
Nov = 10,
|
||||
Dec = 11,
|
||||
Inv_Month = 12
|
||||
};
|
||||
|
||||
rDateTime();
|
||||
~rDateTime();
|
||||
rDateTime(const rDateTime& other);
|
||||
rDateTime(const time_t &time);
|
||||
rDateTime(u16 day, rDateTime::Month month, u16 year, u16 hour, u16 minute, u16 second, u32 millisecond);
|
||||
|
||||
static rDateTime UNow();
|
||||
rDateTime FromUTC(bool val);
|
||||
rDateTime ToUTC(bool val);
|
||||
time_t GetTicks();
|
||||
void Add(const rTimeSpan& span);
|
||||
void Add(const rDateSpan& span);
|
||||
void Close();
|
||||
std::string Format(const std::string &format = rDefaultDateTimeFormat, const rTimeZone &tz = Local) const;
|
||||
|
||||
void ParseDateTime(const char* format);
|
||||
|
||||
u32 GetAsDOS();
|
||||
rDateTime &SetFromDOS(u32 fromdos);
|
||||
|
||||
static bool IsLeapYear(int year, rDateTime::Calender cal);
|
||||
static int GetNumberOfDays(rDateTime::Month month, int year, rDateTime::Calender cal);
|
||||
void SetToWeekDay(rDateTime::WeekDay day, int n, rDateTime::Month month, int year);
|
||||
int GetWeekDay();
|
||||
|
||||
u16 GetYear( rDateTime::TZ timezone);
|
||||
u16 GetMonth(rDateTime::TZ timezone);
|
||||
u16 GetDay(rDateTime::TZ timezone);
|
||||
u16 GetHour(rDateTime::TZ timezone);
|
||||
u16 GetMinute(rDateTime::TZ timezone);
|
||||
u16 GetSecond(rDateTime::TZ timezone);
|
||||
u32 GetMillisecond(rDateTime::TZ timezone);
|
||||
|
||||
void *handle;
|
||||
};
|
||||
|
113
Utilities/rXml.cpp
Normal file
113
Utilities/rXml.cpp
Normal file
|
@ -0,0 +1,113 @@
|
|||
#include "stdafx.h"
|
||||
#include "Utilities/rXml.h"
|
||||
#include <wx/xml/xml.h>
|
||||
|
||||
rXmlNode::rXmlNode()
|
||||
{
|
||||
ownPtr = true;
|
||||
handle = reinterpret_cast<void *>(new wxXmlNode());
|
||||
}
|
||||
|
||||
rXmlNode::rXmlNode(void *ptr)
|
||||
{
|
||||
ownPtr = false;
|
||||
handle = ptr;
|
||||
}
|
||||
|
||||
rXmlNode::rXmlNode(const rXmlNode& other)
|
||||
{
|
||||
ownPtr = true;
|
||||
handle = reinterpret_cast<void *>(new wxXmlNode(*reinterpret_cast<wxXmlNode*>(other.handle)));
|
||||
}
|
||||
|
||||
rXmlNode &rXmlNode::operator=(const rXmlNode& other)
|
||||
{
|
||||
if (ownPtr)
|
||||
{
|
||||
delete reinterpret_cast<wxXmlNode*>(handle);
|
||||
}
|
||||
handle = reinterpret_cast<void *>(new wxXmlNode(*reinterpret_cast<wxXmlNode*>(other.handle)));
|
||||
ownPtr = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
rXmlNode::~rXmlNode()
|
||||
{
|
||||
if (ownPtr)
|
||||
{
|
||||
delete reinterpret_cast<wxXmlNode*>(handle);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<rXmlNode> rXmlNode::GetChildren()
|
||||
{
|
||||
wxXmlNode* result = reinterpret_cast<wxXmlNode*>(handle)->GetChildren();
|
||||
if (result)
|
||||
{
|
||||
return std::make_shared<rXmlNode>(reinterpret_cast<void*>(result));
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::shared_ptr<rXmlNode>(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<rXmlNode> rXmlNode::GetNext()
|
||||
{
|
||||
wxXmlNode* result = reinterpret_cast<wxXmlNode*>(handle)->GetNext();
|
||||
if (result)
|
||||
{
|
||||
return std::make_shared<rXmlNode>(reinterpret_cast<void*>(result));
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::shared_ptr<rXmlNode>(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
std::string rXmlNode::GetName()
|
||||
{
|
||||
return fmt::ToUTF8(reinterpret_cast<wxXmlNode*>(handle)->GetName());
|
||||
}
|
||||
|
||||
std::string rXmlNode::GetAttribute(const std::string &name)
|
||||
{
|
||||
return fmt::ToUTF8(reinterpret_cast<wxXmlNode*>(handle)->GetAttribute(fmt::FromUTF8(name)));
|
||||
}
|
||||
|
||||
std::string rXmlNode::GetNodeContent()
|
||||
{
|
||||
return fmt::ToUTF8(reinterpret_cast<wxXmlNode*>(handle)->GetNodeContent());
|
||||
}
|
||||
|
||||
rXmlDocument::rXmlDocument()
|
||||
{
|
||||
handle = reinterpret_cast<void *>(new wxXmlDocument());
|
||||
}
|
||||
|
||||
rXmlDocument::rXmlDocument(const rXmlDocument& other)
|
||||
{
|
||||
handle = reinterpret_cast<void *>(new wxXmlDocument(*reinterpret_cast<wxXmlDocument*>(other.handle)));
|
||||
}
|
||||
|
||||
rXmlDocument &rXmlDocument::operator = (const rXmlDocument& other)
|
||||
{
|
||||
delete reinterpret_cast<wxXmlDocument*>(handle);
|
||||
handle = reinterpret_cast<void *>(new wxXmlDocument(*reinterpret_cast<wxXmlDocument*>(other.handle)));
|
||||
return *this;
|
||||
}
|
||||
|
||||
rXmlDocument::~rXmlDocument()
|
||||
{
|
||||
delete reinterpret_cast<wxXmlDocument*>(handle);
|
||||
}
|
||||
|
||||
void rXmlDocument::Load(const std::string & path)
|
||||
{
|
||||
reinterpret_cast<wxXmlDocument*>(handle)->Load(fmt::FromUTF8(path));
|
||||
}
|
||||
|
||||
std::shared_ptr<rXmlNode> rXmlDocument::GetRoot()
|
||||
{
|
||||
return std::make_shared<rXmlNode>(reinterpret_cast<void*>(reinterpret_cast<wxXmlDocument*>(handle)->GetRoot()));
|
||||
}
|
30
Utilities/rXml.h
Normal file
30
Utilities/rXml.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
struct rXmlNode
|
||||
{
|
||||
rXmlNode();
|
||||
rXmlNode(void *);
|
||||
rXmlNode(const rXmlNode& other);
|
||||
rXmlNode &operator=(const rXmlNode& other);
|
||||
~rXmlNode();
|
||||
std::shared_ptr<rXmlNode> GetChildren();
|
||||
std::shared_ptr<rXmlNode> GetNext();
|
||||
std::string GetName();
|
||||
std::string GetAttribute( const std::string &name);
|
||||
std::string GetNodeContent();
|
||||
|
||||
void *handle;
|
||||
bool ownPtr;
|
||||
};
|
||||
|
||||
struct rXmlDocument
|
||||
{
|
||||
rXmlDocument();
|
||||
rXmlDocument(const rXmlDocument& other);
|
||||
rXmlDocument &operator=(const rXmlDocument& other);
|
||||
~rXmlDocument();
|
||||
void Load(const std::string & path);
|
||||
std::shared_ptr<rXmlNode> GetRoot();
|
||||
|
||||
void *handle;
|
||||
};
|
|
@ -1,3 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
/*
|
||||
* Copyright 2001-2004 Unicode, Inc.
|
||||
*
|
||||
|
|
56
appveyor.yml
Normal file
56
appveyor.yml
Normal file
|
@ -0,0 +1,56 @@
|
|||
|
||||
|
||||
# version format
|
||||
version: 0.1.{build}
|
||||
|
||||
branches:
|
||||
only:
|
||||
- appveyorbuild
|
||||
# blacklist
|
||||
#except:
|
||||
# - gh-pages
|
||||
|
||||
#---------------------------------#
|
||||
# environment configuration #
|
||||
#---------------------------------#
|
||||
|
||||
# clone directory
|
||||
clone_folder: c:\projects\rpcs3
|
||||
|
||||
platform:
|
||||
- x64
|
||||
|
||||
configuration:
|
||||
- Release
|
||||
|
||||
install:
|
||||
- cmd: cinst wget -x86
|
||||
- cmd: cinst 7zip.commandline -x86
|
||||
- cmd: git submodule update --init --recursive .\ffmpeg .\asmjit
|
||||
- cmd: wget -q --no-check-certificate https://googledrive.com/host/0B3tDmChwjRbRTTdhaTFOeGN1eEU/wxWidgets.7z -O c:\projects\rpcs3\wxwidgets.7z
|
||||
- cmd: 7z x C:\projects\rpcs3\wxwidgets.7z -oc:\projects\rpcs3\wxWidgets
|
||||
|
||||
build:
|
||||
|
||||
build_script:
|
||||
- msbuild /m /p:Configuration=Release rpcs3_buildbot.sln
|
||||
|
||||
after_build:
|
||||
- cmd: package.bat
|
||||
|
||||
artifacts:
|
||||
- path: .\rpcs3*.7z
|
||||
|
||||
deploy: OFF
|
||||
# - provider: FTP
|
||||
# server:
|
||||
# secure: kZT7rsbEPGQ0fC2GFRBGfL2vPwUgih2JkwjbSuw00T8=
|
||||
# username:
|
||||
# secure: YJzwsi4wfSezFLqaB9uiww==
|
||||
# password:
|
||||
# secure: EQ3xa2LoRgelAdE57+qakQ==
|
||||
# folder: .\rpcs3\
|
||||
# enable_ssl: false
|
||||
|
||||
test: OFF
|
||||
|
2
asmjit
2
asmjit
|
@ -1 +1 @@
|
|||
Subproject commit b76922fde96232030be302b3bdd9673e9bcec568
|
||||
Subproject commit d7fc62d9e905859579f5965eee6f7f99b65c2246
|
|
@ -1,4 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
|
@ -23,30 +23,55 @@
|
|||
<ClCompile Include="..\asmjit\src\asmjit\base\codegen.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\compiler.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\constpool.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\containers.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\context.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\cpuinfo.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\cputicks.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\defs.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\error.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\func.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\globals.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\intutil.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\logger.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\memorymanager.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\podvector.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\operand.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\runtime.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\string.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\vmem.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\zone.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\contrib\winremoteruntime.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\x86\x86assembler.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\x86\x86compiler.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\x86\x86context.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\x86\x86cpuinfo.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\x86\x86defs.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\x86\x86func.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\x86\x86inst.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\x86\x86operand.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\x86\x86operand_regs.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\x86\x86scheduler.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\assembler.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\codegen.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\compiler.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\constpool.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\containers.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\context_p.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\cpuinfo.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\cputicks.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\error.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\globals.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\intutil.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\lock.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\logger.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\operand.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\runtime.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\string.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\vectypes.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\vmem.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\zone.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\x86\x86assembler.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\x86\x86compiler.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\x86\x86context_p.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\x86\x86cpuinfo.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\x86\x86inst.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\x86\x86operand.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\x86\x86scheduler_p.h" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{AC40FF01-426E-4838-A317-66354CEFAE88}</ProjectGuid>
|
||||
|
|
|
@ -1,33 +1,58 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\asmjit\src\asmjit\x86\x86assembler.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\x86\x86compiler.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\x86\x86context.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\x86\x86cpuinfo.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\x86\x86defs.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\x86\x86func.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\contrib\winremoteruntime.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\assembler.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\codegen.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\compiler.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\constpool.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\containers.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\context.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\cpuinfo.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\cputicks.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\defs.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\error.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\func.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\globals.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\intutil.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\logger.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\memorymanager.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\podvector.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\operand.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\runtime.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\string.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\vmem.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\zone.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\base\constpool.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\x86\x86assembler.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\x86\x86compiler.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\x86\x86context.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\x86\x86cpuinfo.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\x86\x86inst.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\x86\x86operand.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\x86\x86operand_regs.cpp" />
|
||||
<ClCompile Include="..\asmjit\src\asmjit\x86\x86scheduler.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\asmjit\src\asmjit\x86\x86assembler.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\x86\x86compiler.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\x86\x86context_p.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\x86\x86cpuinfo.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\x86\x86inst.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\x86\x86operand.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\x86\x86scheduler_p.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\assembler.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\codegen.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\compiler.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\constpool.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\containers.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\context_p.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\cpuinfo.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\cputicks.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\error.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\globals.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\intutil.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\lock.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\logger.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\operand.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\runtime.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\string.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\vectypes.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\vmem.h" />
|
||||
<ClInclude Include="..\asmjit\src\asmjit\base\zone.h" />
|
||||
</ItemGroup>
|
||||
</Project>
|
BIN
bin/soft_oal.dll
Normal file
BIN
bin/soft_oal.dll
Normal file
Binary file not shown.
23
package.bat
Normal file
23
package.bat
Normal file
|
@ -0,0 +1,23 @@
|
|||
mkdir build
|
||||
mkdir build\rpcs3
|
||||
copy bin\rpcs3-*.exe build\rpcs3
|
||||
copy bin\soft_oal.dll build\rpcs3
|
||||
copy bin\make_fself.cmd build\rpcs3
|
||||
|
||||
mkdir build\rpcs3\dev_hdd1
|
||||
xcopy /Y /e bin\dev_hdd1 build\rpcs3\dev_hdd1
|
||||
|
||||
mkdir build\rpcs3\dev_hdd0
|
||||
xcopy /Y /e bin\dev_hdd0 build\rpcs3\dev_hdd0
|
||||
|
||||
mkdir build\rpcs3\dev_flash
|
||||
xcopy /Y /e bin\dev_flash build\rpcs3\dev_flash
|
||||
|
||||
mkdir build\rpcs3\dev_usb000
|
||||
xcopy /Y /e bin\dev_usb000 build\rpcs3\dev_usb000
|
||||
|
||||
for /f "delims=" %%a in ('git describe') do @set gitrev=%%a
|
||||
|
||||
cd build
|
||||
7z a -mx9 ..\rpcs3-%gitrev%-windows-x86_64.7z rpcs3
|
||||
cd ..
|
12
rpcs3.sln
12
rpcs3.sln
|
@ -4,8 +4,10 @@ VisualStudioVersion = 12.0.21005.1
|
|||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rpcs3", "rpcs3\rpcs3.vcxproj", "{70CD65B0-91D6-4FAE-9A7B-4AF55D0D1B12}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88} = {AC40FF01-426E-4838-A317-66354CEFAE88}
|
||||
{CD478F02-7550-58A5-E085-CE4BC0C0AD23} = {CD478F02-7550-58A5-E085-CE4BC0C0AD23}
|
||||
{067D9406-2A93-DACA-9449-93A2D356357D} = {067D9406-2A93-DACA-9449-93A2D356357D}
|
||||
{C4A10229-4712-4BD2-B63E-50D93C67A038} = {C4A10229-4712-4BD2-B63E-50D93C67A038}
|
||||
{5C363C34-4741-7036-861C-2E2279CF552E} = {5C363C34-4741-7036-861C-2E2279CF552E}
|
||||
{23E1C437-A951-5943-8639-A17F3CF2E606} = {23E1C437-A951-5943-8639-A17F3CF2E606}
|
||||
{22B14659-C5B6-B775-868D-A49198FEAD4A} = {22B14659-C5B6-B775-868D-A49198FEAD4A}
|
||||
|
@ -135,6 +137,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "asmjit", "asmjitsrc\asmjit.
|
|||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "asmjit", "asmjit", "{E2A982F2-4B1A-48B1-8D77-A17A589C58D7}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "emucore", "rpcs3\emucore.vcxproj", "{C4A10229-4712-4BD2-B63E-50D93C67A038}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug - MemLeak|x64 = Debug - MemLeak|x64
|
||||
|
@ -186,6 +190,7 @@ Global
|
|||
{99C9EB95-DB4C-1996-490E-5212EFBF07C3}.Release|x64.Build.0 = Release|x64
|
||||
{6EDC3B79-D217-F11A-406F-F11D856493F9}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
|
||||
{6EDC3B79-D217-F11A-406F-F11D856493F9}.Debug - MemLeak|x64.Build.0 = Debug|x64
|
||||
{6EDC3B79-D217-F11A-406F-F11D856493F9}.Debug - MemLeak|x64.Deploy.0 = Debug|x64
|
||||
{6EDC3B79-D217-F11A-406F-F11D856493F9}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6EDC3B79-D217-F11A-406F-F11D856493F9}.Debug|x64.Build.0 = Debug|x64
|
||||
{6EDC3B79-D217-F11A-406F-F11D856493F9}.Release|x64.ActiveCfg = Release|x64
|
||||
|
@ -281,10 +286,17 @@ Global
|
|||
{74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Release|x64.ActiveCfg = Release|x64
|
||||
{74827EBD-93DC-5110-BA95-3F2AB029B6B0}.Release|x64.Build.0 = Release|x64
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.Debug - MemLeak|x64.ActiveCfg = Debug|x64
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.Debug - MemLeak|x64.Build.0 = Debug|x64
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.Debug|x64.Build.0 = Debug|x64
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.Release|x64.ActiveCfg = Release|x64
|
||||
{AC40FF01-426E-4838-A317-66354CEFAE88}.Release|x64.Build.0 = Release|x64
|
||||
{C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug - MemLeak|x64.ActiveCfg = Debug - MemLeak|x64
|
||||
{C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug - MemLeak|x64.Build.0 = Debug - MemLeak|x64
|
||||
{C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{C4A10229-4712-4BD2-B63E-50D93C67A038}.Debug|x64.Build.0 = Debug|x64
|
||||
{C4A10229-4712-4BD2-B63E-50D93C67A038}.Release|x64.ActiveCfg = Release|x64
|
||||
{C4A10229-4712-4BD2-B63E-50D93C67A038}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -1,22 +1,38 @@
|
|||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
set (CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake_modules")
|
||||
include(cotire)
|
||||
|
||||
project(rpcs3)
|
||||
|
||||
if (CMAKE_COMPILER_IS_GNUCXX)
|
||||
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7.0)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
message(FATAL_ERROR "GCC ${CMAKE_CXX_COMPILER_VERSION} is too old.")
|
||||
endif()
|
||||
#add_definitions(-D__WXGTK__)
|
||||
#add_definitions(-Wfatal-errors)
|
||||
add_definitions(-w) # TODO: remove me
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions")
|
||||
add_definitions(-fpermissive) # TODO: remove me
|
||||
add_definitions(-g) # Debugging!!
|
||||
add_definitions(-msse2)
|
||||
# Warnings
|
||||
add_definitions(-Wno-attributes -Wno-enum-compare)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-invalid-offsetof")
|
||||
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions")
|
||||
# TODO: stdlib?
|
||||
endif()
|
||||
|
||||
if (NOT MSVC)
|
||||
add_definitions(-DwxGUI)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fexceptions")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -D_DEBUG")
|
||||
set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -Os -D_NDEBUG")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O1 -D_NDEBUG")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -O1 -g -D_NDEBUG")
|
||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g -D_DEBUG")
|
||||
set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} -Os -D_NDEBUG")
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O1 -D_NDEBUG")
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -O1 -g -D_NDEBUG")
|
||||
add_definitions(-msse2)
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I/opt/X11/include")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I/opt/X11/include")
|
||||
endif()
|
||||
|
||||
If( NOT RPCS3_SRC_DIR)
|
||||
|
@ -27,7 +43,8 @@ Else()
|
|||
EndIf()
|
||||
|
||||
set(CMAKE_MODULE_PATH "${RPCS3_SRC_DIR}/cmake_modules")
|
||||
set(EXECUTABLE_OUTPUT_PATH "${RPCS3_SRC_DIR}/../bin") # TODO: do real installation, including copying directory structure
|
||||
# TODO: do real installation, including copying directory structure
|
||||
set(EXECUTABLE_OUTPUT_PATH "${PROJECT_BINARY_DIR}/../bin")
|
||||
#include(cotire)
|
||||
|
||||
add_definitions(-DGL_GLEXT_PROTOTYPES)
|
||||
|
@ -41,11 +58,6 @@ find_package(OpenAL REQUIRED)
|
|||
|
||||
include("${wxWidgets_USE_FILE}")
|
||||
|
||||
if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
message( FATAL_ERROR "RPCS3 can only be compiled on 64-bit platforms." )
|
||||
endif()
|
||||
|
||||
|
||||
if(APPLE)
|
||||
set(PLATFORM_ARCH "macosx/x86_64")
|
||||
elseif(WIN32)
|
||||
|
@ -59,8 +71,6 @@ ${wxWidgets_INCLUDE_DIRS}
|
|||
${OPENAL_INCLUDE_DIR}
|
||||
"${RPCS3_SRC_DIR}/../ffmpeg/${PLATFORM_ARCH}/include"
|
||||
"${RPCS3_SRC_DIR}"
|
||||
"${RPCS3_SRC_DIR}/Emu"
|
||||
"${RPCS3_SRC_DIR}/Gui"
|
||||
"${RPCS3_SRC_DIR}/Loader"
|
||||
"${RPCS3_SRC_DIR}/Crypto"
|
||||
"${RPCS3_SRC_DIR}/.."
|
||||
|
@ -92,5 +102,6 @@ add_executable(rpcs3 ${RPCS3_SRC})
|
|||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_CURRENT_BINARY_DIR}/../asmjit/") #hack because the asmjit cmake file force fno exceptions
|
||||
target_link_libraries(rpcs3 asmjit.a ${wxWidgets_LIBRARIES} ${OPENAL_LIBRARY} ${GLEW_LIBRARY} ${OPENGL_LIBRARIES} libavformat.a libavcodec.a libavutil.a libswresample.a libswscale.a ${ZLIB_LIBRARIES})
|
||||
|
||||
#set_target_properties(rpcs3 PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "${RPCS3_SRC_DIR}/stdafx.h")
|
||||
#cotire(rpcs3)
|
||||
set_target_properties(rpcs3 PROPERTIES COTIRE_CXX_PREFIX_HEADER_INIT "${RPCS3_SRC_DIR}/stdafx.h")
|
||||
cotire(rpcs3)
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
/**
|
||||
* \file aes.h
|
||||
*
|
||||
|
@ -174,4 +176,4 @@ void aes_cmac(aes_context *ctx, int length, unsigned char *input, unsigned char
|
|||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,20 @@
|
|||
#include "stdafx.h"
|
||||
#include "utils.h"
|
||||
#include "aes.h"
|
||||
#include "key_vault.h"
|
||||
|
||||
SELF_KEY::SELF_KEY(u64 ver, u16 rev, u32 type, const std::string& e, const std::string& r, const std::string& pb, const std::string& pr, u32 ct)
|
||||
{
|
||||
version = ver;
|
||||
revision = rev;
|
||||
self_type = type;
|
||||
hex_to_bytes(erk, e.c_str());
|
||||
hex_to_bytes(riv, r.c_str());
|
||||
hex_to_bytes(pub, pb.c_str());
|
||||
hex_to_bytes(priv, pr.c_str());
|
||||
curve_type = ct;
|
||||
}
|
||||
|
||||
KeyVault::KeyVault()
|
||||
{
|
||||
}
|
||||
|
@ -579,17 +593,17 @@ void KeyVault::LoadSelfUNK7Keys()
|
|||
0x0F);
|
||||
}
|
||||
|
||||
SELF_KEY KeyVault::GetSelfLV0Key()
|
||||
SELF_KEY KeyVault::GetSelfLV0Key() const
|
||||
{
|
||||
return sk_LV0_arr[0];
|
||||
}
|
||||
|
||||
SELF_KEY KeyVault::GetSelfLDRKey()
|
||||
SELF_KEY KeyVault::GetSelfLDRKey() const
|
||||
{
|
||||
return sk_LDR_arr[0];
|
||||
}
|
||||
|
||||
SELF_KEY KeyVault::GetSelfLV1Key(u64 version)
|
||||
SELF_KEY KeyVault::GetSelfLV1Key(u64 version) const
|
||||
{
|
||||
SELF_KEY key(0, 0, 0, "", "", "", "", 0);
|
||||
|
||||
|
@ -605,7 +619,7 @@ SELF_KEY KeyVault::GetSelfLV1Key(u64 version)
|
|||
return key;
|
||||
}
|
||||
|
||||
SELF_KEY KeyVault::GetSelfLV2Key(u64 version)
|
||||
SELF_KEY KeyVault::GetSelfLV2Key(u64 version) const
|
||||
{
|
||||
SELF_KEY key(0, 0, 0, "", "", "", "", 0);
|
||||
|
||||
|
@ -621,7 +635,7 @@ SELF_KEY KeyVault::GetSelfLV2Key(u64 version)
|
|||
return key;
|
||||
}
|
||||
|
||||
SELF_KEY KeyVault::GetSelfISOKey(u16 revision, u64 version)
|
||||
SELF_KEY KeyVault::GetSelfISOKey(u16 revision, u64 version) const
|
||||
{
|
||||
SELF_KEY key(0, 0, 0, "", "", "", "", 0);
|
||||
|
||||
|
@ -638,7 +652,7 @@ SELF_KEY KeyVault::GetSelfISOKey(u16 revision, u64 version)
|
|||
return key;
|
||||
}
|
||||
|
||||
SELF_KEY KeyVault::GetSelfAPPKey(u16 revision)
|
||||
SELF_KEY KeyVault::GetSelfAPPKey(u16 revision) const
|
||||
{
|
||||
SELF_KEY key(0, 0, 0, "", "", "", "", 0);
|
||||
|
||||
|
@ -654,7 +668,7 @@ SELF_KEY KeyVault::GetSelfAPPKey(u16 revision)
|
|||
return key;
|
||||
}
|
||||
|
||||
SELF_KEY KeyVault::GetSelfUNK7Key(u64 version)
|
||||
SELF_KEY KeyVault::GetSelfUNK7Key(u64 version) const
|
||||
{
|
||||
SELF_KEY key(0, 0, 0, "", "", "", "", 0);
|
||||
|
||||
|
@ -670,7 +684,7 @@ SELF_KEY KeyVault::GetSelfUNK7Key(u64 version)
|
|||
return key;
|
||||
}
|
||||
|
||||
SELF_KEY KeyVault::GetSelfNPDRMKey(u16 revision)
|
||||
SELF_KEY KeyVault::GetSelfNPDRMKey(u16 revision) const
|
||||
{
|
||||
SELF_KEY key(0, 0, 0, "", "", "", "", 0);
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#pragma once
|
||||
#include "utils.h"
|
||||
|
||||
enum SELF_KEY_TYPE {
|
||||
KEY_LV0 = 1,
|
||||
|
@ -22,17 +21,7 @@ struct SELF_KEY {
|
|||
u8 priv[0x15];
|
||||
u32 curve_type;
|
||||
|
||||
SELF_KEY(u64 ver, u16 rev, u32 type, const std::string& e, const std::string& r, const std::string& pb, const std::string& pr, u32 ct)
|
||||
{
|
||||
version = ver;
|
||||
revision = rev;
|
||||
self_type = type;
|
||||
hex_to_bytes(erk, e.c_str());
|
||||
hex_to_bytes(riv, r.c_str());
|
||||
hex_to_bytes(pub, pb.c_str());
|
||||
hex_to_bytes(priv, pr.c_str());
|
||||
curve_type = ct;
|
||||
}
|
||||
SELF_KEY(u64 ver, u16 rev, u32 type, const std::string& e, const std::string& r, const std::string& pb, const std::string& pr, u32 ct);
|
||||
};
|
||||
|
||||
static u8 PKG_AES_KEY[0x10] = {
|
||||
|
@ -142,14 +131,14 @@ private:
|
|||
void LoadSelfAPPKeys();
|
||||
void LoadSelfUNK7Keys();
|
||||
void LoadSelfNPDRMKeys();
|
||||
SELF_KEY GetSelfLV0Key();
|
||||
SELF_KEY GetSelfLDRKey();
|
||||
SELF_KEY GetSelfLV1Key(u64 version);
|
||||
SELF_KEY GetSelfLV2Key(u64 version);
|
||||
SELF_KEY GetSelfISOKey(u16 revision, u64 version);
|
||||
SELF_KEY GetSelfAPPKey(u16 revision);
|
||||
SELF_KEY GetSelfUNK7Key(u64 version);
|
||||
SELF_KEY GetSelfNPDRMKey(u16 revision);
|
||||
SELF_KEY GetSelfLV0Key() const;
|
||||
SELF_KEY GetSelfLDRKey() const;
|
||||
SELF_KEY GetSelfLV1Key(u64 version) const;
|
||||
SELF_KEY GetSelfLV2Key(u64 version) const;
|
||||
SELF_KEY GetSelfISOKey(u16 revision, u64 version) const;
|
||||
SELF_KEY GetSelfAPPKey(u16 revision) const;
|
||||
SELF_KEY GetSelfUNK7Key(u64 version) const;
|
||||
SELF_KEY GetSelfNPDRMKey(u16 revision) const;
|
||||
};
|
||||
|
||||
// RAP to RIF function.
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#pragma once
|
||||
#include <string.h>
|
||||
|
||||
int decode_range(unsigned int *range, unsigned int *code, unsigned char **src);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#pragma once
|
||||
/**
|
||||
* \file sha1.h
|
||||
*
|
||||
|
@ -158,4 +159,4 @@ void sha1_hmac( const unsigned char *key, size_t keylen,
|
|||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
#include "stdafx.h"
|
||||
#include "utils.h"
|
||||
#include "key_vault.h"
|
||||
#include "unedat.h"
|
||||
#include "Utilities/Log.h"
|
||||
#include "Utilities/rFile.h"
|
||||
|
||||
void generate_key(int crypto_mode, int version, unsigned char *key_final, unsigned char *iv_final, unsigned char *key, unsigned char *iv)
|
||||
{
|
||||
|
@ -73,7 +77,7 @@ bool crypto(int hash_mode, int crypto_mode, int version, unsigned char *in, unsi
|
|||
}
|
||||
else
|
||||
{
|
||||
ConLog.Error("EDAT: Unknown crypto algorithm!\n");
|
||||
LOG_ERROR(LOADER, "EDAT: Unknown crypto algorithm!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -91,7 +95,7 @@ bool crypto(int hash_mode, int crypto_mode, int version, unsigned char *in, unsi
|
|||
}
|
||||
else
|
||||
{
|
||||
ConLog.Error("EDAT: Unknown hashing algorithm!\n");
|
||||
LOG_ERROR(LOADER, "EDAT: Unknown hashing algorithm!\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -132,7 +136,7 @@ unsigned char* get_block_key(int block, NPD_HEADER *npd)
|
|||
}
|
||||
|
||||
// EDAT/SDAT functions.
|
||||
int decrypt_data(wxFile *in, wxFile *out, EDAT_SDAT_HEADER *edat, NPD_HEADER *npd, unsigned char* crypt_key, bool verbose)
|
||||
int decrypt_data(rFile *in, rFile *out, EDAT_SDAT_HEADER *edat, NPD_HEADER *npd, unsigned char* crypt_key, bool verbose)
|
||||
{
|
||||
// Get metadata info and setup buffers.
|
||||
int block_num = (int) ((edat->file_size + edat->block_size - 1) / edat->block_size);
|
||||
|
@ -155,6 +159,12 @@ int decrypt_data(wxFile *in, wxFile *out, EDAT_SDAT_HEADER *edat, NPD_HEADER *np
|
|||
int length = 0;
|
||||
int compression_end = 0;
|
||||
|
||||
if ((edat->flags & EDAT_FLAG_0x04) != 0)
|
||||
{
|
||||
LOG_ERROR(LOADER, "EDAT: Flag 0x04 is not yet supported");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((edat->flags & EDAT_COMPRESSED_FLAG) != 0)
|
||||
{
|
||||
unsigned char metadata[0x20];
|
||||
|
@ -261,15 +271,15 @@ int decrypt_data(wxFile *in, wxFile *out, EDAT_SDAT_HEADER *edat, NPD_HEADER *np
|
|||
memset(decomp_data, 0, decomp_size);
|
||||
|
||||
if (verbose)
|
||||
ConLog.Write("EDAT: Decompressing...\n");
|
||||
LOG_NOTICE(LOADER, "EDAT: Decompressing...\n");
|
||||
|
||||
int res = lz_decompress(decomp_data, dec_data, decomp_size);
|
||||
out->Write(decomp_data, res);
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
ConLog.Write("EDAT: Compressed block size: %d\n", pad_length);
|
||||
ConLog.Write("EDAT: Decompressed block size: %d\n", res);
|
||||
LOG_NOTICE(LOADER, "EDAT: Compressed block size: %d\n", pad_length);
|
||||
LOG_NOTICE(LOADER, "EDAT: Decompressed block size: %d\n", res);
|
||||
}
|
||||
|
||||
edat->file_size -= res;
|
||||
|
@ -278,11 +288,11 @@ int decrypt_data(wxFile *in, wxFile *out, EDAT_SDAT_HEADER *edat, NPD_HEADER *np
|
|||
{
|
||||
if (res < 0)
|
||||
{
|
||||
ConLog.Error("EDAT: Decompression failed!\n");
|
||||
LOG_ERROR(LOADER, "EDAT: Decompression failed!\n");
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
ConLog.Success("EDAT: Data successfully decompressed!\n");
|
||||
LOG_SUCCESS(LOADER, "EDAT: Data successfully decompressed!\n");
|
||||
}
|
||||
|
||||
delete[] decomp_data;
|
||||
|
@ -308,7 +318,7 @@ static bool check_flags(EDAT_SDAT_HEADER *edat, NPD_HEADER *npd)
|
|||
{
|
||||
if (edat->flags & 0x7EFFFFFE)
|
||||
{
|
||||
ConLog.Error("EDAT: Bad header flags!\n");
|
||||
LOG_ERROR(LOADER, "EDAT: Bad header flags!\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -316,7 +326,7 @@ static bool check_flags(EDAT_SDAT_HEADER *edat, NPD_HEADER *npd)
|
|||
{
|
||||
if (edat->flags & 0x7EFFFFE0)
|
||||
{
|
||||
ConLog.Error("EDAT: Bad header flags!\n");
|
||||
LOG_ERROR(LOADER, "EDAT: Bad header flags!\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -324,20 +334,20 @@ static bool check_flags(EDAT_SDAT_HEADER *edat, NPD_HEADER *npd)
|
|||
{
|
||||
if (edat->flags & 0x7EFFFFC0)
|
||||
{
|
||||
ConLog.Error("EDAT: Bad header flags!\n");
|
||||
LOG_ERROR(LOADER, "EDAT: Bad header flags!\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (npd->version > 4)
|
||||
{
|
||||
ConLog.Error("EDAT: Unknown version - %d\n", npd->version);
|
||||
LOG_ERROR(LOADER, "EDAT: Unknown version - %d\n", npd->version);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int check_data(unsigned char *key, EDAT_SDAT_HEADER *edat, NPD_HEADER *npd, wxFile *f, bool verbose)
|
||||
int check_data(unsigned char *key, EDAT_SDAT_HEADER *edat, NPD_HEADER *npd, rFile *f, bool verbose)
|
||||
{
|
||||
f->Seek(0);
|
||||
unsigned char *header = new unsigned char[0xA0];
|
||||
|
@ -363,7 +373,7 @@ int check_data(unsigned char *key, EDAT_SDAT_HEADER *edat, NPD_HEADER *npd, wxFi
|
|||
int hash_mode = ((edat->flags & EDAT_ENCRYPTED_KEY_FLAG) == 0) ? 0x00000002 : 0x10000002;
|
||||
if ((edat->flags & EDAT_DEBUG_DATA_FLAG) != 0)
|
||||
{
|
||||
ConLog.Warning("EDAT: DEBUG data detected!\n");
|
||||
LOG_ERROR(LOADER, "EDAT: DEBUG data detected!\n");
|
||||
hash_mode |= 0x01000000;
|
||||
}
|
||||
|
||||
|
@ -375,14 +385,14 @@ int check_data(unsigned char *key, EDAT_SDAT_HEADER *edat, NPD_HEADER *npd, wxFi
|
|||
if (!crypto(hash_mode, crypto_mode, (npd->version == 4), header, tmp, 0xA0, header_key, header_iv, key, hash_result))
|
||||
{
|
||||
if (verbose)
|
||||
ConLog.Warning("EDAT: Header hash is invalid!\n");
|
||||
LOG_WARNING(LOADER, "EDAT: Header hash is invalid!\n");
|
||||
}
|
||||
|
||||
// Parse the metadata info.
|
||||
int metadata_section_size = 0x10;
|
||||
if (((edat->flags & EDAT_COMPRESSED_FLAG) != 0))
|
||||
{
|
||||
ConLog.Warning("EDAT: COMPRESSED data detected!\n");
|
||||
LOG_WARNING(LOADER, "EDAT: COMPRESSED data detected!\n");
|
||||
metadata_section_size = 0x20;
|
||||
}
|
||||
|
||||
|
@ -411,7 +421,7 @@ int check_data(unsigned char *key, EDAT_SDAT_HEADER *edat, NPD_HEADER *npd, wxFi
|
|||
if (!crypto(hash_mode, crypto_mode, (npd->version == 4), data, tmp, block_size, header_key, header_iv, key, hash_result))
|
||||
{
|
||||
if (verbose)
|
||||
ConLog.Warning("EDAT: Metadata hash from block 0x%08x is invalid!\n", metadata_offset + bytes_read);
|
||||
LOG_WARNING(LOADER, "EDAT: Metadata hash from block 0x%08x is invalid!\n", metadata_offset + bytes_read);
|
||||
}
|
||||
|
||||
// Adjust sizes.
|
||||
|
@ -448,9 +458,9 @@ void validate_data(const char* file_name, unsigned char *klicensee, NPD_HEADER *
|
|||
if (verbose)
|
||||
{
|
||||
if (title_hash_result)
|
||||
ConLog.Success("EDAT: NPD title hash is valid!\n");
|
||||
LOG_SUCCESS(LOADER, "EDAT: NPD title hash is valid!\n");
|
||||
else
|
||||
ConLog.Warning("EDAT: NPD title hash is invalid!\n");
|
||||
LOG_WARNING(LOADER, "EDAT: NPD title hash is invalid!\n");
|
||||
}
|
||||
|
||||
// Check for an empty dev_hash (can't validate if devklic is NULL);
|
||||
|
@ -467,7 +477,7 @@ void validate_data(const char* file_name, unsigned char *klicensee, NPD_HEADER *
|
|||
if (isDevklicEmpty)
|
||||
{
|
||||
if (verbose)
|
||||
ConLog.Warning("EDAT: NPD dev hash is empty!\n");
|
||||
LOG_WARNING(LOADER, "EDAT: NPD dev hash is empty!\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -480,16 +490,16 @@ void validate_data(const char* file_name, unsigned char *klicensee, NPD_HEADER *
|
|||
if (verbose)
|
||||
{
|
||||
if (dev_hash_result)
|
||||
ConLog.Success("EDAT: NPD dev hash is valid!\n");
|
||||
LOG_SUCCESS(LOADER, "EDAT: NPD dev hash is valid!\n");
|
||||
else
|
||||
ConLog.Warning("EDAT: NPD dev hash is invalid!\n");
|
||||
LOG_WARNING(LOADER, "EDAT: NPD dev hash is invalid!\n");
|
||||
}
|
||||
}
|
||||
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
bool extract_data(wxFile *input, wxFile *output, const char* input_file_name, unsigned char* devklic, unsigned char* rifkey, bool verbose)
|
||||
bool extract_data(rFile *input, rFile *output, const char* input_file_name, unsigned char* devklic, unsigned char* rifkey, bool verbose)
|
||||
{
|
||||
// Setup NPD and EDAT/SDAT structs.
|
||||
NPD_HEADER *NPD = new NPD_HEADER();
|
||||
|
@ -515,7 +525,7 @@ bool extract_data(wxFile *input, wxFile *output, const char* input_file_name, un
|
|||
unsigned char npd_magic[4] = {0x4E, 0x50, 0x44, 0x00}; //NPD0
|
||||
if(memcmp(NPD->magic, npd_magic, 4))
|
||||
{
|
||||
ConLog.Error("EDAT: File has invalid NPD header.");
|
||||
LOG_ERROR(LOADER, "EDAT: %s has invalid NPD header or already decrypted.", input_file_name);
|
||||
delete NPD;
|
||||
delete EDAT;
|
||||
return 1;
|
||||
|
@ -527,16 +537,16 @@ bool extract_data(wxFile *input, wxFile *output, const char* input_file_name, un
|
|||
|
||||
if (verbose)
|
||||
{
|
||||
ConLog.Write("NPD HEADER\n");
|
||||
ConLog.Write("NPD version: %d\n", NPD->version);
|
||||
ConLog.Write("NPD license: %d\n", NPD->license);
|
||||
ConLog.Write("NPD type: %d\n", NPD->type);
|
||||
ConLog.Write("\n");
|
||||
ConLog.Write("EDAT HEADER\n");
|
||||
ConLog.Write("EDAT flags: 0x%08X\n", EDAT->flags);
|
||||
ConLog.Write("EDAT block size: 0x%08X\n", EDAT->block_size);
|
||||
ConLog.Write("EDAT file size: 0x%08X\n", EDAT->file_size);
|
||||
ConLog.Write("\n");
|
||||
LOG_NOTICE(LOADER, "NPD HEADER\n");
|
||||
LOG_NOTICE(LOADER, "NPD version: %d\n", NPD->version);
|
||||
LOG_NOTICE(LOADER, "NPD license: %d\n", NPD->license);
|
||||
LOG_NOTICE(LOADER, "NPD type: %d\n", NPD->type);
|
||||
LOG_NOTICE(LOADER, "\n");
|
||||
LOG_NOTICE(LOADER, "EDAT HEADER\n");
|
||||
LOG_NOTICE(LOADER, "EDAT flags: 0x%08X\n", EDAT->flags);
|
||||
LOG_NOTICE(LOADER, "EDAT block size: 0x%08X\n", EDAT->block_size);
|
||||
LOG_NOTICE(LOADER, "EDAT file size: 0x%08X\n", EDAT->file_size);
|
||||
LOG_NOTICE(LOADER, "\n");
|
||||
}
|
||||
|
||||
// Set decryption key.
|
||||
|
@ -545,7 +555,7 @@ bool extract_data(wxFile *input, wxFile *output, const char* input_file_name, un
|
|||
|
||||
if((EDAT->flags & SDAT_FLAG) == SDAT_FLAG)
|
||||
{
|
||||
ConLog.Warning("EDAT: SDAT detected!\n");
|
||||
LOG_WARNING(LOADER, "EDAT: SDAT detected!\n");
|
||||
xor_(key, NPD->dev_hash, SDAT_KEY, 0x10);
|
||||
}
|
||||
else
|
||||
|
@ -572,7 +582,7 @@ bool extract_data(wxFile *input, wxFile *output, const char* input_file_name, un
|
|||
|
||||
if (!test)
|
||||
{
|
||||
ConLog.Error("EDAT: A valid RAP file is needed!");
|
||||
LOG_ERROR(LOADER, "EDAT: A valid RAP file is needed!");
|
||||
delete NPD;
|
||||
delete EDAT;
|
||||
return 1;
|
||||
|
@ -580,19 +590,19 @@ bool extract_data(wxFile *input, wxFile *output, const char* input_file_name, un
|
|||
}
|
||||
}
|
||||
|
||||
ConLog.Write("EDAT: Parsing data...\n");
|
||||
LOG_NOTICE(LOADER, "EDAT: Parsing data...\n");
|
||||
if (check_data(key, EDAT, NPD, input, verbose))
|
||||
ConLog.Error("EDAT: Data parsing failed!\n");
|
||||
LOG_ERROR(LOADER, "EDAT: Data parsing failed!\n");
|
||||
else
|
||||
ConLog.Success("EDAT: Data successfully parsed!\n");
|
||||
LOG_SUCCESS(LOADER, "EDAT: Data successfully parsed!\n");
|
||||
|
||||
printf("\n");
|
||||
|
||||
ConLog.Write("EDAT: Decrypting data...\n");
|
||||
LOG_NOTICE(LOADER, "EDAT: Decrypting data...\n");
|
||||
if (decrypt_data(input, output, EDAT, NPD, key, verbose))
|
||||
ConLog.Error("EDAT: Data decryption failed!");
|
||||
LOG_ERROR(LOADER, "EDAT: Data decryption failed!");
|
||||
else
|
||||
ConLog.Success("EDAT: Data successfully decrypted!");
|
||||
LOG_SUCCESS(LOADER, "EDAT: Data successfully decrypted!");
|
||||
|
||||
delete NPD;
|
||||
delete EDAT;
|
||||
|
@ -603,9 +613,9 @@ bool extract_data(wxFile *input, wxFile *output, const char* input_file_name, un
|
|||
int DecryptEDAT(const std::string& input_file_name, const std::string& output_file_name, int mode, const std::string& rap_file_name, unsigned char *custom_klic, bool verbose)
|
||||
{
|
||||
// Prepare the files.
|
||||
wxFile input(input_file_name.c_str());
|
||||
wxFile output(output_file_name.c_str(), wxFile::write);
|
||||
wxFile rap(rap_file_name.c_str());
|
||||
rFile input(input_file_name.c_str());
|
||||
rFile output(output_file_name.c_str(), rFile::write);
|
||||
rFile rap(rap_file_name.c_str());
|
||||
|
||||
// Set keys (RIF and DEVKLIC).
|
||||
unsigned char rifkey[0x10];
|
||||
|
@ -645,21 +655,21 @@ int DecryptEDAT(const std::string& input_file_name, const std::string& output_fi
|
|||
memcpy(devklic, custom_klic, 0x10);
|
||||
else
|
||||
{
|
||||
ConLog.Error("EDAT: Invalid custom klic!\n");
|
||||
LOG_ERROR(LOADER, "EDAT: Invalid custom klic!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ConLog.Error("EDAT: Invalid mode!\n");
|
||||
LOG_ERROR(LOADER, "EDAT: Invalid mode!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check the input/output files.
|
||||
if (!input.IsOpened() || !output.IsOpened())
|
||||
{
|
||||
ConLog.Error("EDAT: Failed to open files!\n");
|
||||
LOG_ERROR(LOADER, "EDAT: Failed to open files!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -681,7 +691,7 @@ int DecryptEDAT(const std::string& input_file_name, const std::string& output_fi
|
|||
{
|
||||
input.Close();
|
||||
output.Close();
|
||||
wxRemoveFile(output_file_name);
|
||||
rRemoveFile(output_file_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
#pragma once
|
||||
#include "utils.h"
|
||||
#include "key_vault.h"
|
||||
|
||||
#define SDAT_FLAG 0x01000000
|
||||
#define EDAT_COMPRESSED_FLAG 0x00000001
|
||||
#define EDAT_FLAG_0x02 0x00000002
|
||||
#define EDAT_FLAG_0x04 0x00000004
|
||||
#define EDAT_ENCRYPTED_KEY_FLAG 0x00000008
|
||||
#define EDAT_FLAG_0x10 0x00000010
|
||||
#define EDAT_FLAG_0x20 0x00000020
|
||||
|
@ -31,4 +30,4 @@ typedef struct
|
|||
unsigned long long file_size;
|
||||
} EDAT_SDAT_HEADER;
|
||||
|
||||
int DecryptEDAT(const std::string& input_file_name, const std::string& output_file_name, int mode, const std::string& rap_file_name, unsigned char *custom_klic, bool verbose);
|
||||
int DecryptEDAT(const std::string& input_file_name, const std::string& output_file_name, int mode, const std::string& rap_file_name, unsigned char *custom_klic, bool verbose);
|
||||
|
|
|
@ -1,12 +1,21 @@
|
|||
#include "stdafx.h"
|
||||
#include "utils.h"
|
||||
#include "aes.h"
|
||||
#include "sha1.h"
|
||||
#include "key_vault.h"
|
||||
#include "unpkg.h"
|
||||
#include "restore_new.h"
|
||||
#include <wx/progdlg.h>
|
||||
#include "define_new_memleakdetect.h"
|
||||
|
||||
#include "Utilities/Log.h"
|
||||
#include "Utilities/rFile.h"
|
||||
|
||||
// Decryption.
|
||||
bool CheckHeader(wxFile& pkg_f, PKGHeader* m_header)
|
||||
bool CheckHeader(rFile& pkg_f, PKGHeader* m_header)
|
||||
{
|
||||
if (m_header->pkg_magic != 0x7F504B47) {
|
||||
ConLog.Error("PKG: Not a package file!");
|
||||
LOG_ERROR(LOADER, "PKG: Not a package file!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -15,7 +24,7 @@ bool CheckHeader(wxFile& pkg_f, PKGHeader* m_header)
|
|||
case PKG_RELEASE_TYPE_DEBUG: break;
|
||||
case PKG_RELEASE_TYPE_RELEASE: break;
|
||||
default:
|
||||
ConLog.Error("PKG: Unknown PKG type!");
|
||||
LOG_ERROR(LOADER, "PKG: Unknown PKG type!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -24,34 +33,34 @@ bool CheckHeader(wxFile& pkg_f, PKGHeader* m_header)
|
|||
case PKG_PLATFORM_TYPE_PS3: break;
|
||||
case PKG_PLATFORM_TYPE_PSP: break;
|
||||
default:
|
||||
ConLog.Error("PKG: Unknown PKG type!");
|
||||
LOG_ERROR(LOADER, "PKG: Unknown PKG type!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_header->header_size != PKG_HEADER_SIZE) {
|
||||
ConLog.Error("PKG: Wrong header size!");
|
||||
LOG_ERROR(LOADER, "PKG: Wrong header size!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_header->pkg_size != pkg_f.Length()) {
|
||||
ConLog.Error("PKG: File size mismatch.");
|
||||
LOG_ERROR(LOADER, "PKG: File size mismatch.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_header->data_size + m_header->data_offset + 0x60 != pkg_f.Length()) {
|
||||
ConLog.Error("PKG: Data size mismatch.");
|
||||
LOG_ERROR(LOADER, "PKG: Data size mismatch.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadHeader(wxFile& pkg_f, PKGHeader* m_header)
|
||||
bool LoadHeader(rFile& pkg_f, PKGHeader* m_header)
|
||||
{
|
||||
pkg_f.Seek(0);
|
||||
|
||||
if (pkg_f.Read(m_header, sizeof(PKGHeader)) != sizeof(PKGHeader)) {
|
||||
ConLog.Error("PKG: Package file is too short!");
|
||||
LOG_ERROR(LOADER, "PKG: Package file is too short!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -61,7 +70,7 @@ bool LoadHeader(wxFile& pkg_f, PKGHeader* m_header)
|
|||
return true;
|
||||
}
|
||||
|
||||
int Decrypt(wxFile& pkg_f, wxFile& dec_pkg_f, PKGHeader* m_header)
|
||||
int Decrypt(rFile& pkg_f, rFile& dec_pkg_f, PKGHeader* m_header)
|
||||
{
|
||||
if (!LoadHeader(pkg_f, m_header))
|
||||
return -1;
|
||||
|
@ -111,8 +120,9 @@ int Decrypt(wxFile& pkg_f, wxFile& dec_pkg_f, PKGHeader* m_header)
|
|||
{
|
||||
aes_crypt_ecb(&c, AES_ENCRYPT, iv, ctr+j*HASH_LEN);
|
||||
|
||||
be_t<u64> hi = *(be_t<u64>*)&iv[0];
|
||||
be_t<u64> lo = *(be_t<u64>*)&iv[8] + 1;
|
||||
be_t<u64> hi = be_t<u64>::MakeFromBE(*(u64*)&iv[0]);
|
||||
be_t<u64> lo = be_t<u64>::MakeFromBE(*(u64*)&iv[8]);
|
||||
lo++;
|
||||
|
||||
if (lo == 0)
|
||||
hi += 1;
|
||||
|
@ -133,20 +143,20 @@ int Decrypt(wxFile& pkg_f, wxFile& dec_pkg_f, PKGHeader* m_header)
|
|||
}
|
||||
|
||||
// Unpacking.
|
||||
bool LoadEntries(wxFile& dec_pkg_f, PKGHeader* m_header, PKGEntry *m_entries)
|
||||
bool LoadEntries(rFile& dec_pkg_f, PKGHeader* m_header, PKGEntry *m_entries)
|
||||
{
|
||||
dec_pkg_f.Seek(0);
|
||||
dec_pkg_f.Read(m_entries, sizeof(PKGEntry) * m_header->file_count);
|
||||
|
||||
if (m_entries->name_offset / sizeof(PKGEntry) != m_header->file_count) {
|
||||
ConLog.Error("PKG: Entries are damaged!");
|
||||
LOG_ERROR(LOADER, "PKG: Entries are damaged!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UnpackEntry(wxFile& dec_pkg_f, const PKGEntry& entry, std::string dir)
|
||||
bool UnpackEntry(rFile& dec_pkg_f, const PKGEntry& entry, std::string dir)
|
||||
{
|
||||
u8 buf[BUF_SIZE];
|
||||
|
||||
|
@ -161,8 +171,8 @@ bool UnpackEntry(wxFile& dec_pkg_f, const PKGEntry& entry, std::string dir)
|
|||
case PKG_FILE_ENTRY_SDAT:
|
||||
case PKG_FILE_ENTRY_REGULAR:
|
||||
{
|
||||
wxFile out;
|
||||
out.Create(dir + buf);
|
||||
rFile out;
|
||||
out.Create(dir + std::string(reinterpret_cast<char *>(buf), entry.name_size));
|
||||
dec_pkg_f.Seek(entry.file_offset);
|
||||
|
||||
for (u64 size = 0; size < entry.file_size; ) {
|
||||
|
@ -177,18 +187,19 @@ bool UnpackEntry(wxFile& dec_pkg_f, const PKGEntry& entry, std::string dir)
|
|||
break;
|
||||
|
||||
case PKG_FILE_ENTRY_FOLDER:
|
||||
wxMkdir(dir + buf);
|
||||
rMkdir(dir + std::string(reinterpret_cast<char *>(buf), entry.name_size));
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int Unpack(wxFile& pkg_f, std::string src, std::string dst)
|
||||
int Unpack(rFile& pkg_f, std::string src, std::string dst)
|
||||
{
|
||||
PKGHeader* m_header = (PKGHeader*) malloc (sizeof(PKGHeader));
|
||||
|
||||
wxFile dec_pkg_f;
|
||||
std::string decryptedFile = wxGetCwd().ToStdString() + "/dev_hdd1/" + src + ".dec";
|
||||
rFile dec_pkg_f;
|
||||
// TODO: This shouldn't use current dir
|
||||
std::string decryptedFile = "./dev_hdd1/" + src + ".dec";
|
||||
|
||||
dec_pkg_f.Create(decryptedFile, true);
|
||||
|
||||
|
@ -197,7 +208,7 @@ int Unpack(wxFile& pkg_f, std::string src, std::string dst)
|
|||
|
||||
dec_pkg_f.Close();
|
||||
|
||||
wxFile n_dec_pkg_f(decryptedFile, wxFile::read);
|
||||
rFile n_dec_pkg_f(decryptedFile, rFile::read);
|
||||
|
||||
std::vector<PKGEntry> m_entries;
|
||||
m_entries.resize(m_header->file_count);
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#pragma once
|
||||
#include "utils.h"
|
||||
#include "key_vault.h"
|
||||
|
||||
// Constants
|
||||
#define PKG_HEADER_SIZE 0xC0 //sizeof(pkg_header) + sizeof(pkg_unk_checksum)
|
||||
|
@ -47,4 +45,6 @@ struct PKGEntry
|
|||
be_t<u32> pad; // Padding (zeros)
|
||||
};
|
||||
|
||||
extern int Unpack(wxFile& dec_pkg_f, std::string src, std::string dst);
|
||||
class rFile;
|
||||
|
||||
extern int Unpack(rFile& dec_pkg_f, std::string src, std::string dst);
|
|
@ -1,6 +1,318 @@
|
|||
#include "stdafx.h"
|
||||
#include "Utilities/Log.h"
|
||||
#include "Utilities/rFile.h"
|
||||
#include "aes.h"
|
||||
#include "sha1.h"
|
||||
#include "utils.h"
|
||||
#include "Emu/FS/vfsLocalFile.h"
|
||||
#include "unself.h"
|
||||
|
||||
#include <wx/mstream.h>
|
||||
#include <wx/zstream.h>
|
||||
|
||||
void AppInfo::Load(vfsStream& f)
|
||||
{
|
||||
authid = Read64(f);
|
||||
vendor_id = Read32(f);
|
||||
self_type = Read32(f);
|
||||
version = Read64(f);
|
||||
padding = Read64(f);
|
||||
}
|
||||
|
||||
void AppInfo::Show()
|
||||
{
|
||||
LOG_NOTICE(LOADER, "AuthID: 0x%llx", authid);
|
||||
LOG_NOTICE(LOADER, "VendorID: 0x%08x", vendor_id);
|
||||
LOG_NOTICE(LOADER, "SELF type: 0x%08x", self_type);
|
||||
LOG_NOTICE(LOADER, "Version: 0x%llx", version);
|
||||
}
|
||||
|
||||
void SectionInfo::Load(vfsStream& f)
|
||||
{
|
||||
offset = Read64(f);
|
||||
size = Read64(f);
|
||||
compressed = Read32(f);
|
||||
unknown1 = Read32(f);
|
||||
unknown2 = Read32(f);
|
||||
encrypted = Read32(f);
|
||||
}
|
||||
|
||||
void SectionInfo::Show()
|
||||
{
|
||||
LOG_NOTICE(LOADER, "Offset: 0x%llx", offset);
|
||||
LOG_NOTICE(LOADER, "Size: 0x%llx", size);
|
||||
LOG_NOTICE(LOADER, "Compressed: 0x%08x", compressed);
|
||||
LOG_NOTICE(LOADER, "Unknown1: 0x%08x", unknown1);
|
||||
LOG_NOTICE(LOADER, "Unknown2: 0x%08x", unknown2);
|
||||
LOG_NOTICE(LOADER, "Encrypted: 0x%08x", encrypted);
|
||||
}
|
||||
|
||||
void SCEVersionInfo::Load(vfsStream& f)
|
||||
{
|
||||
subheader_type = Read32(f);
|
||||
present = Read32(f);
|
||||
size = Read32(f);
|
||||
unknown = Read32(f);
|
||||
}
|
||||
|
||||
void SCEVersionInfo::Show()
|
||||
{
|
||||
LOG_NOTICE(LOADER, "Sub-header type: 0x%08x", subheader_type);
|
||||
LOG_NOTICE(LOADER, "Present: 0x%08x", present);
|
||||
LOG_NOTICE(LOADER, "Size: 0x%08x", size);
|
||||
LOG_NOTICE(LOADER, "Unknown: 0x%08x", unknown);
|
||||
}
|
||||
|
||||
void ControlInfo::Load(vfsStream& f)
|
||||
{
|
||||
type = Read32(f);
|
||||
size = Read32(f);
|
||||
next = Read64(f);
|
||||
|
||||
if (type == 1)
|
||||
{
|
||||
control_flags.ctrl_flag1 = Read32(f);
|
||||
control_flags.unknown1 = Read32(f);
|
||||
control_flags.unknown2 = Read32(f);
|
||||
control_flags.unknown3 = Read32(f);
|
||||
control_flags.unknown4 = Read32(f);
|
||||
control_flags.unknown5 = Read32(f);
|
||||
control_flags.unknown6 = Read32(f);
|
||||
control_flags.unknown7 = Read32(f);
|
||||
}
|
||||
else if (type == 2)
|
||||
{
|
||||
if (size == 0x30)
|
||||
{
|
||||
f.Read(file_digest_30.digest, 20);
|
||||
file_digest_30.unknown = Read64(f);
|
||||
}
|
||||
else if (size == 0x40)
|
||||
{
|
||||
f.Read(file_digest_40.digest1, 20);
|
||||
f.Read(file_digest_40.digest2, 20);
|
||||
file_digest_40.unknown = Read64(f);
|
||||
}
|
||||
}
|
||||
else if (type == 3)
|
||||
{
|
||||
npdrm.magic = Read32(f);
|
||||
npdrm.unknown1 = Read32(f);
|
||||
npdrm.license = Read32(f);
|
||||
npdrm.type = Read32(f);
|
||||
f.Read(npdrm.content_id, 48);
|
||||
f.Read(npdrm.digest, 16);
|
||||
f.Read(npdrm.invdigest, 16);
|
||||
f.Read(npdrm.xordigest, 16);
|
||||
npdrm.unknown2 = Read64(f);
|
||||
npdrm.unknown3 = Read64(f);
|
||||
}
|
||||
}
|
||||
|
||||
void ControlInfo::Show()
|
||||
{
|
||||
LOG_NOTICE(LOADER, "Type: 0x%08x", type);
|
||||
LOG_NOTICE(LOADER, "Size: 0x%08x", size);
|
||||
LOG_NOTICE(LOADER, "Next: 0x%llx", next);
|
||||
|
||||
if (type == 1)
|
||||
{
|
||||
LOG_NOTICE(LOADER, "Control flag 1: 0x%08x", control_flags.ctrl_flag1);
|
||||
LOG_NOTICE(LOADER, "Unknown1: 0x%08x", control_flags.unknown1);
|
||||
LOG_NOTICE(LOADER, "Unknown2: 0x%08x", control_flags.unknown2);
|
||||
LOG_NOTICE(LOADER, "Unknown3: 0x%08x", control_flags.unknown3);
|
||||
LOG_NOTICE(LOADER, "Unknown4: 0x%08x", control_flags.unknown4);
|
||||
LOG_NOTICE(LOADER, "Unknown5: 0x%08x", control_flags.unknown5);
|
||||
LOG_NOTICE(LOADER, "Unknown6: 0x%08x", control_flags.unknown6);
|
||||
LOG_NOTICE(LOADER, "Unknown7: 0x%08x", control_flags.unknown7);
|
||||
}
|
||||
else if (type == 2)
|
||||
{
|
||||
if (size == 0x30)
|
||||
{
|
||||
std::string digest_str;
|
||||
for (int i = 0; i < 20; i++)
|
||||
digest_str += fmt::Format("%02x", file_digest_30.digest[i]);
|
||||
|
||||
LOG_NOTICE(LOADER, "Digest: %s", digest_str.c_str());
|
||||
LOG_NOTICE(LOADER, "Unknown: 0x%llx", file_digest_30.unknown);
|
||||
}
|
||||
else if (size == 0x40)
|
||||
{
|
||||
std::string digest_str1;
|
||||
std::string digest_str2;
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
digest_str1 += fmt::Format("%02x", file_digest_40.digest1[i]);
|
||||
digest_str2 += fmt::Format("%02x", file_digest_40.digest2[i]);
|
||||
}
|
||||
|
||||
LOG_NOTICE(LOADER, "Digest1: %s", digest_str1.c_str());
|
||||
LOG_NOTICE(LOADER, "Digest2: %s", digest_str2.c_str());
|
||||
LOG_NOTICE(LOADER, "Unknown: 0x%llx", file_digest_40.unknown);
|
||||
}
|
||||
}
|
||||
else if (type == 3)
|
||||
{
|
||||
std::string contentid_str;
|
||||
std::string digest_str;
|
||||
std::string invdigest_str;
|
||||
std::string xordigest_str;
|
||||
for (int i = 0; i < 48; i++)
|
||||
contentid_str += fmt::Format("%02x", npdrm.content_id[i]);
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
digest_str += fmt::Format("%02x", npdrm.digest[i]);
|
||||
invdigest_str += fmt::Format("%02x", npdrm.invdigest[i]);
|
||||
xordigest_str += fmt::Format("%02x", npdrm.xordigest[i]);
|
||||
}
|
||||
|
||||
LOG_NOTICE(LOADER, "Magic: 0x%08x", npdrm.magic);
|
||||
LOG_NOTICE(LOADER, "Unknown1: 0x%08x", npdrm.unknown1);
|
||||
LOG_NOTICE(LOADER, "License: 0x%08x", npdrm.license);
|
||||
LOG_NOTICE(LOADER, "Type: 0x%08x", npdrm.type);
|
||||
LOG_NOTICE(LOADER, "ContentID: %s", contentid_str.c_str());
|
||||
LOG_NOTICE(LOADER, "Digest: %s", digest_str.c_str());
|
||||
LOG_NOTICE(LOADER, "Inverse digest: %s", invdigest_str.c_str());
|
||||
LOG_NOTICE(LOADER, "XOR digest: %s", xordigest_str.c_str());
|
||||
LOG_NOTICE(LOADER, "Unknown2: 0x%llx", npdrm.unknown2);
|
||||
LOG_NOTICE(LOADER, "Unknown3: 0x%llx", npdrm.unknown3);
|
||||
}
|
||||
}
|
||||
|
||||
void MetadataInfo::Load(u8* in)
|
||||
{
|
||||
memcpy(key, in, 0x10);
|
||||
memcpy(key_pad, in + 0x10, 0x10);
|
||||
memcpy(iv, in + 0x20, 0x10);
|
||||
memcpy(iv_pad, in + 0x30, 0x10);
|
||||
}
|
||||
|
||||
void MetadataInfo::Show()
|
||||
{
|
||||
std::string key_str;
|
||||
std::string key_pad_str;
|
||||
std::string iv_str;
|
||||
std::string iv_pad_str;
|
||||
for (int i = 0; i < 0x10; i++)
|
||||
{
|
||||
key_str += fmt::Format("%02x", key[i]);
|
||||
key_pad_str += fmt::Format("%02x", key_pad[i]);
|
||||
iv_str += fmt::Format("%02x", iv[i]);
|
||||
iv_pad_str += fmt::Format("%02x", iv_pad[i]);
|
||||
}
|
||||
|
||||
LOG_NOTICE(LOADER, "Key: %s", key_str.c_str());
|
||||
LOG_NOTICE(LOADER, "Key pad: %s", key_pad_str.c_str());
|
||||
LOG_NOTICE(LOADER, "IV: %s", iv_str.c_str());
|
||||
LOG_NOTICE(LOADER, "IV pad: %s", iv_pad_str.c_str());
|
||||
}
|
||||
|
||||
void MetadataHeader::Load(u8* in)
|
||||
{
|
||||
memcpy(&signature_input_length, in, 8);
|
||||
memcpy(&unknown1, in + 8, 4);
|
||||
memcpy(§ion_count, in + 12, 4);
|
||||
memcpy(&key_count, in + 16, 4);
|
||||
memcpy(&opt_header_size, in + 20, 4);
|
||||
memcpy(&unknown2, in + 24, 4);
|
||||
memcpy(&unknown3, in + 28, 4);
|
||||
|
||||
// Endian swap.
|
||||
signature_input_length = swap64(signature_input_length);
|
||||
unknown1 = swap32(unknown1);
|
||||
section_count = swap32(section_count);
|
||||
key_count = swap32(key_count);
|
||||
opt_header_size = swap32(opt_header_size);
|
||||
unknown2 = swap32(unknown2);
|
||||
unknown3 = swap32(unknown3);
|
||||
}
|
||||
|
||||
void MetadataHeader::Show()
|
||||
{
|
||||
LOG_NOTICE(LOADER, "Signature input length: 0x%llx", signature_input_length);
|
||||
LOG_NOTICE(LOADER, "Unknown1: 0x%08x", unknown1);
|
||||
LOG_NOTICE(LOADER, "Section count: 0x%08x", section_count);
|
||||
LOG_NOTICE(LOADER, "Key count: 0x%08x", key_count);
|
||||
LOG_NOTICE(LOADER, "Optional header size: 0x%08x", opt_header_size);
|
||||
LOG_NOTICE(LOADER, "Unknown2: 0x%08x", unknown2);
|
||||
LOG_NOTICE(LOADER, "Unknown3: 0x%08x", unknown3);
|
||||
}
|
||||
|
||||
void MetadataSectionHeader::Load(u8* in)
|
||||
{
|
||||
memcpy(&data_offset, in, 8);
|
||||
memcpy(&data_size, in + 8, 8);
|
||||
memcpy(&type, in + 16, 4);
|
||||
memcpy(&program_idx, in + 20, 4);
|
||||
memcpy(&hashed, in + 24, 4);
|
||||
memcpy(&sha1_idx, in + 28, 4);
|
||||
memcpy(&encrypted, in + 32, 4);
|
||||
memcpy(&key_idx, in + 36, 4);
|
||||
memcpy(&iv_idx, in + 40, 4);
|
||||
memcpy(&compressed, in + 44, 4);
|
||||
|
||||
// Endian swap.
|
||||
data_offset = swap64(data_offset);
|
||||
data_size = swap64(data_size);
|
||||
type = swap32(type);
|
||||
program_idx = swap32(program_idx);
|
||||
hashed = swap32(hashed);
|
||||
sha1_idx = swap32(sha1_idx);
|
||||
encrypted = swap32(encrypted);
|
||||
key_idx = swap32(key_idx);
|
||||
iv_idx = swap32(iv_idx);
|
||||
compressed = swap32(compressed);
|
||||
}
|
||||
|
||||
void MetadataSectionHeader::Show()
|
||||
{
|
||||
LOG_NOTICE(LOADER, "Data offset: 0x%llx", data_offset);
|
||||
LOG_NOTICE(LOADER, "Data size: 0x%llx", data_size);
|
||||
LOG_NOTICE(LOADER, "Type: 0x%08x", type);
|
||||
LOG_NOTICE(LOADER, "Program index: 0x%08x", program_idx);
|
||||
LOG_NOTICE(LOADER, "Hashed: 0x%08x", hashed);
|
||||
LOG_NOTICE(LOADER, "SHA1 index: 0x%08x", sha1_idx);
|
||||
LOG_NOTICE(LOADER, "Encrypted: 0x%08x", encrypted);
|
||||
LOG_NOTICE(LOADER, "Key index: 0x%08x", key_idx);
|
||||
LOG_NOTICE(LOADER, "IV index: 0x%08x", iv_idx);
|
||||
LOG_NOTICE(LOADER, "Compressed: 0x%08x", compressed);
|
||||
}
|
||||
|
||||
void SectionHash::Load(vfsStream& f)
|
||||
{
|
||||
f.Read(sha1, 20);
|
||||
f.Read(padding, 12);
|
||||
f.Read(hmac_key, 64);
|
||||
}
|
||||
|
||||
void CapabilitiesInfo::Load(vfsStream& f)
|
||||
{
|
||||
type = Read32(f);
|
||||
capabilities_size = Read32(f);
|
||||
next = Read32(f);
|
||||
unknown1 = Read32(f);
|
||||
unknown2 = Read64(f);
|
||||
unknown3 = Read64(f);
|
||||
flags = Read64(f);
|
||||
unknown4 = Read32(f);
|
||||
unknown5 = Read32(f);
|
||||
}
|
||||
|
||||
void Signature::Load(vfsStream& f)
|
||||
{
|
||||
f.Read(r, 21);
|
||||
f.Read(s, 21);
|
||||
f.Read(padding, 6);
|
||||
}
|
||||
|
||||
void SelfSection::Load(vfsStream& f)
|
||||
{
|
||||
*data = Read32(f);
|
||||
size = Read64(f);
|
||||
offset = Read64(f);
|
||||
}
|
||||
|
||||
SELFDecrypter::SELFDecrypter(vfsStream& s)
|
||||
: self_f(s), key_v(), data_buf_length(0)
|
||||
{
|
||||
|
@ -15,7 +327,7 @@ bool SELFDecrypter::LoadHeaders(bool isElf32)
|
|||
// Check SCE magic.
|
||||
if (!sce_hdr.CheckMagic())
|
||||
{
|
||||
ConLog.Error("SELF: Not a SELF file!");
|
||||
LOG_ERROR(LOADER, "SELF: Not a SELF file!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -39,7 +351,7 @@ bool SELFDecrypter::LoadHeaders(bool isElf32)
|
|||
phdr32_arr.clear();
|
||||
if(elf32_hdr.e_phoff == 0 && elf32_hdr.e_phnum)
|
||||
{
|
||||
ConLog.Error("SELF: ELF program header offset is null!");
|
||||
LOG_ERROR(LOADER, "SELF: ELF program header offset is null!");
|
||||
return false;
|
||||
}
|
||||
self_f.Seek(self_hdr.se_phdroff);
|
||||
|
@ -54,7 +366,7 @@ bool SELFDecrypter::LoadHeaders(bool isElf32)
|
|||
phdr64_arr.clear();
|
||||
if(elf64_hdr.e_phoff == 0 && elf64_hdr.e_phnum)
|
||||
{
|
||||
ConLog.Error("SELF: ELF program header offset is null!");
|
||||
LOG_ERROR(LOADER, "SELF: ELF program header offset is null!");
|
||||
return false;
|
||||
}
|
||||
self_f.Seek(self_hdr.se_phdroff);
|
||||
|
@ -99,7 +411,7 @@ bool SELFDecrypter::LoadHeaders(bool isElf32)
|
|||
shdr32_arr.clear();
|
||||
if(elf32_hdr.e_shoff == 0 && elf32_hdr.e_shnum)
|
||||
{
|
||||
ConLog.Warning("SELF: ELF section header offset is null!");
|
||||
LOG_WARNING(LOADER, "SELF: ELF section header offset is null!");
|
||||
return true;
|
||||
}
|
||||
self_f.Seek(self_hdr.se_shdroff);
|
||||
|
@ -114,7 +426,7 @@ bool SELFDecrypter::LoadHeaders(bool isElf32)
|
|||
shdr64_arr.clear();
|
||||
if(elf64_hdr.e_shoff == 0 && elf64_hdr.e_shnum)
|
||||
{
|
||||
ConLog.Warning("SELF: ELF section header offset is null!");
|
||||
LOG_WARNING(LOADER, "SELF: ELF section header offset is null!");
|
||||
return true;
|
||||
}
|
||||
self_f.Seek(self_hdr.se_shdroff);
|
||||
|
@ -130,46 +442,46 @@ bool SELFDecrypter::LoadHeaders(bool isElf32)
|
|||
|
||||
void SELFDecrypter::ShowHeaders(bool isElf32)
|
||||
{
|
||||
ConLog.Write("SCE header");
|
||||
ConLog.Write("----------------------------------------------------");
|
||||
LOG_NOTICE(LOADER, "SCE header");
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
sce_hdr.Show();
|
||||
ConLog.Write("----------------------------------------------------");
|
||||
ConLog.Write("SELF header");
|
||||
ConLog.Write("----------------------------------------------------");
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
LOG_NOTICE(LOADER, "SELF header");
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
self_hdr.Show();
|
||||
ConLog.Write("----------------------------------------------------");
|
||||
ConLog.Write("APP INFO");
|
||||
ConLog.Write("----------------------------------------------------");
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
LOG_NOTICE(LOADER, "APP INFO");
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
app_info.Show();
|
||||
ConLog.Write("----------------------------------------------------");
|
||||
ConLog.Write("ELF header");
|
||||
ConLog.Write("----------------------------------------------------");
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
LOG_NOTICE(LOADER, "ELF header");
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
isElf32 ? elf32_hdr.Show() : elf64_hdr.Show();
|
||||
ConLog.Write("----------------------------------------------------");
|
||||
ConLog.Write("ELF program headers");
|
||||
ConLog.Write("----------------------------------------------------");
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
LOG_NOTICE(LOADER, "ELF program headers");
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
for(unsigned int i = 0; i < ((isElf32) ? phdr32_arr.size() : phdr64_arr.size()); i++)
|
||||
isElf32 ? phdr32_arr[i].Show() : phdr64_arr[i].Show();
|
||||
ConLog.Write("----------------------------------------------------");
|
||||
ConLog.Write("Section info");
|
||||
ConLog.Write("----------------------------------------------------");
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
LOG_NOTICE(LOADER, "Section info");
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
for(unsigned int i = 0; i < secinfo_arr.size(); i++)
|
||||
secinfo_arr[i].Show();
|
||||
ConLog.Write("----------------------------------------------------");
|
||||
ConLog.Write("SCE version info");
|
||||
ConLog.Write("----------------------------------------------------");
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
LOG_NOTICE(LOADER, "SCE version info");
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
scev_info.Show();
|
||||
ConLog.Write("----------------------------------------------------");
|
||||
ConLog.Write("Control info");
|
||||
ConLog.Write("----------------------------------------------------");
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
LOG_NOTICE(LOADER, "Control info");
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
for(unsigned int i = 0; i < ctrlinfo_arr.size(); i++)
|
||||
ctrlinfo_arr[i].Show();
|
||||
ConLog.Write("----------------------------------------------------");
|
||||
ConLog.Write("ELF section headers");
|
||||
ConLog.Write("----------------------------------------------------");
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
LOG_NOTICE(LOADER, "ELF section headers");
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
for(unsigned int i = 0; i < ((isElf32) ? shdr32_arr.size() : shdr64_arr.size()); i++)
|
||||
isElf32 ? shdr32_arr[i].Show() : shdr64_arr[i].Show();
|
||||
ConLog.Write("----------------------------------------------------");
|
||||
LOG_NOTICE(LOADER, "----------------------------------------------------");
|
||||
}
|
||||
|
||||
bool SELFDecrypter::DecryptNPDRM(u8 *metadata, u32 metadata_size)
|
||||
|
@ -193,7 +505,7 @@ bool SELFDecrypter::DecryptNPDRM(u8 *metadata, u32 metadata_size)
|
|||
// If not, the data has no NPDRM layer.
|
||||
if (!ctrl)
|
||||
{
|
||||
ConLog.Warning("SELF: No NPDRM control info found!");
|
||||
LOG_WARNING(LOADER, "SELF: No NPDRM control info found!");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -206,7 +518,7 @@ bool SELFDecrypter::DecryptNPDRM(u8 *metadata, u32 metadata_size)
|
|||
|
||||
if (ctrl->npdrm.license == 1) // Network license.
|
||||
{
|
||||
ConLog.Error("SELF: Can't decrypt network NPDRM!");
|
||||
LOG_ERROR(LOADER, "SELF: Can't decrypt network NPDRM!");
|
||||
return false;
|
||||
}
|
||||
else if (ctrl->npdrm.license == 2) // Local license.
|
||||
|
@ -214,7 +526,7 @@ bool SELFDecrypter::DecryptNPDRM(u8 *metadata, u32 metadata_size)
|
|||
// Try to find a RAP file to get the key.
|
||||
if (!GetKeyFromRap(ctrl->npdrm.content_id, npdrm_key))
|
||||
{
|
||||
ConLog.Error("SELF: Can't find RAP file for NPDRM decryption!");
|
||||
LOG_ERROR(LOADER, "SELF: Can't find RAP file for NPDRM decryption!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -225,7 +537,7 @@ bool SELFDecrypter::DecryptNPDRM(u8 *metadata, u32 metadata_size)
|
|||
}
|
||||
else
|
||||
{
|
||||
ConLog.Error("SELF: Invalid NPDRM license type!");
|
||||
LOG_ERROR(LOADER, "SELF: Invalid NPDRM license type!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -288,7 +600,7 @@ bool SELFDecrypter::LoadMetadata()
|
|||
if ((meta_info.key_pad[0] != 0x00) ||
|
||||
(meta_info.iv_pad[0] != 0x00))
|
||||
{
|
||||
ConLog.Error("SELF: Failed to decrypt metadata info!");
|
||||
LOG_ERROR(LOADER, "SELF: Failed to decrypt metadata info!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -387,10 +699,10 @@ bool SELFDecrypter::DecryptData()
|
|||
bool SELFDecrypter::MakeElf(const std::string& elf, bool isElf32)
|
||||
{
|
||||
// Create a new ELF file.
|
||||
wxFile e(elf.c_str(), wxFile::write);
|
||||
rFile e(elf.c_str(), rFile::write);
|
||||
if(!e.IsOpened())
|
||||
{
|
||||
ConLog.Error("Could not create ELF file! (%s)", elf.c_str());
|
||||
LOG_ERROR(LOADER, "Could not create ELF file! (%s)", elf.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -503,25 +815,26 @@ bool SELFDecrypter::GetKeyFromRap(u8 *content_id, u8 *npdrm_key)
|
|||
|
||||
// Try to find a matching RAP file under dev_usb000.
|
||||
std::string ci_str((const char *)content_id);
|
||||
std::string rap_path(fmt::ToUTF8(wxGetCwd()) + "/dev_usb000/" + ci_str + ".rap");
|
||||
// TODO: This shouldn't use current dir
|
||||
std::string rap_path("./dev_usb000/" + ci_str + ".rap");
|
||||
|
||||
// Check if we have a valid RAP file.
|
||||
if (!wxFile::Exists(fmt::FromUTF8(rap_path)))
|
||||
if (!rExists(rap_path))
|
||||
{
|
||||
ConLog.Error("This application requires a valid RAP file for decryption!");
|
||||
LOG_ERROR(LOADER, "This application requires a valid RAP file for decryption!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Open the RAP file and read the key.
|
||||
wxFile rap_file(fmt::FromUTF8(rap_path), wxFile::read);
|
||||
rFile rap_file(rap_path, rFile::read);
|
||||
|
||||
if (!rap_file.IsOpened())
|
||||
{
|
||||
ConLog.Error("Failed to load RAP file!");
|
||||
LOG_ERROR(LOADER, "Failed to load RAP file!");
|
||||
return false;
|
||||
}
|
||||
|
||||
ConLog.Write("Loading RAP file %s", (ci_str + ".rap").c_str());
|
||||
LOG_NOTICE(LOADER, "Loading RAP file %s", (ci_str + ".rap").c_str());
|
||||
rap_file.Read(rap_key, 0x10);
|
||||
rap_file.Close();
|
||||
|
||||
|
@ -567,11 +880,11 @@ bool IsSelfElf32(const std::string& path)
|
|||
bool CheckDebugSelf(const std::string& self, const std::string& elf)
|
||||
{
|
||||
// Open the SELF file.
|
||||
wxFile s(fmt::FromUTF8(self));
|
||||
rFile s(self);
|
||||
|
||||
if(!s.IsOpened())
|
||||
{
|
||||
ConLog.Error("Could not open SELF file! (%s)", self.c_str());
|
||||
LOG_ERROR(LOADER, "Could not open SELF file! (%s)", self.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -583,7 +896,7 @@ bool CheckDebugSelf(const std::string& self, const std::string& elf)
|
|||
// Check for DEBUG version.
|
||||
if(swap16(key_version) == 0x8000)
|
||||
{
|
||||
ConLog.Warning("Debug SELF detected! Removing fake header...");
|
||||
LOG_WARNING(LOADER, "Debug SELF detected! Removing fake header...");
|
||||
|
||||
// Get the real elf offset.
|
||||
s.Seek(0x10);
|
||||
|
@ -595,10 +908,10 @@ bool CheckDebugSelf(const std::string& self, const std::string& elf)
|
|||
s.Seek(elf_offset);
|
||||
|
||||
// Write the real ELF file back.
|
||||
wxFile e(fmt::FromUTF8(elf), wxFile::write);
|
||||
rFile e(elf, rFile::write);
|
||||
if(!e.IsOpened())
|
||||
{
|
||||
ConLog.Error("Could not create ELF file! (%s)", elf.c_str());
|
||||
LOG_ERROR(LOADER, "Could not create ELF file! (%s)", elf.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -638,28 +951,28 @@ bool DecryptSelf(const std::string& elf, const std::string& self)
|
|||
// Load the SELF file headers.
|
||||
if (!self_dec.LoadHeaders(isElf32))
|
||||
{
|
||||
ConLog.Error("SELF: Failed to load SELF file headers!");
|
||||
LOG_ERROR(LOADER, "SELF: Failed to load SELF file headers!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load and decrypt the SELF file metadata.
|
||||
if (!self_dec.LoadMetadata())
|
||||
{
|
||||
ConLog.Error("SELF: Failed to load SELF file metadata!");
|
||||
LOG_ERROR(LOADER, "SELF: Failed to load SELF file metadata!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Decrypt the SELF file data.
|
||||
if (!self_dec.DecryptData())
|
||||
{
|
||||
ConLog.Error("SELF: Failed to decrypt SELF file data!");
|
||||
LOG_ERROR(LOADER, "SELF: Failed to decrypt SELF file data!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make a new ELF file from this SELF.
|
||||
if (!self_dec.MakeElf(elf, isElf32))
|
||||
{
|
||||
ConLog.Error("SELF: Failed to make ELF file from SELF!");
|
||||
LOG_ERROR(LOADER, "SELF: Failed to make ELF file from SELF!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
#pragma once
|
||||
#include "utils.h"
|
||||
#include "key_vault.h"
|
||||
#include "Loader/ELF.h"
|
||||
|
||||
#include "Loader/SELF.h"
|
||||
#include <wx/mstream.h>
|
||||
#include <wx/zstream.h>
|
||||
#include "Loader/ELF.h"
|
||||
#include "key_vault.h"
|
||||
|
||||
struct AppInfo
|
||||
{
|
||||
|
@ -14,22 +12,9 @@ struct AppInfo
|
|||
u64 version;
|
||||
u64 padding;
|
||||
|
||||
void Load(vfsStream& f)
|
||||
{
|
||||
authid = Read64(f);
|
||||
vendor_id = Read32(f);
|
||||
self_type = Read32(f);
|
||||
version = Read64(f);
|
||||
padding = Read64(f);
|
||||
}
|
||||
void Load(vfsStream& f);
|
||||
|
||||
void Show()
|
||||
{
|
||||
ConLog.Write("AuthID: 0x%llx", authid);
|
||||
ConLog.Write("VendorID: 0x%08x", vendor_id);
|
||||
ConLog.Write("SELF type: 0x%08x", self_type);
|
||||
ConLog.Write("Version: 0x%llx", version);
|
||||
}
|
||||
void Show();
|
||||
};
|
||||
|
||||
struct SectionInfo
|
||||
|
@ -41,25 +26,9 @@ struct SectionInfo
|
|||
u32 unknown2;
|
||||
u32 encrypted;
|
||||
|
||||
void Load(vfsStream& f)
|
||||
{
|
||||
offset = Read64(f);
|
||||
size = Read64(f);
|
||||
compressed = Read32(f);
|
||||
unknown1 = Read32(f);
|
||||
unknown2 = Read32(f);
|
||||
encrypted = Read32(f);
|
||||
}
|
||||
void Load(vfsStream& f);
|
||||
|
||||
void Show()
|
||||
{
|
||||
ConLog.Write("Offset: 0x%llx", offset);
|
||||
ConLog.Write("Size: 0x%llx", size);
|
||||
ConLog.Write("Compressed: 0x%08x", compressed);
|
||||
ConLog.Write("Unknown1: 0x%08x", unknown1);
|
||||
ConLog.Write("Unknown2: 0x%08x", unknown2);
|
||||
ConLog.Write("Encrypted: 0x%08x", encrypted);
|
||||
}
|
||||
void Show();
|
||||
};
|
||||
|
||||
struct SCEVersionInfo
|
||||
|
@ -69,21 +38,9 @@ struct SCEVersionInfo
|
|||
u32 size;
|
||||
u32 unknown;
|
||||
|
||||
void Load(vfsStream& f)
|
||||
{
|
||||
subheader_type = Read32(f);
|
||||
present = Read32(f);
|
||||
size = Read32(f);
|
||||
unknown = Read32(f);
|
||||
}
|
||||
void Load(vfsStream& f);
|
||||
|
||||
void Show()
|
||||
{
|
||||
ConLog.Write("Sub-header type: 0x%08x", subheader_type);
|
||||
ConLog.Write("Present: 0x%08x", present);
|
||||
ConLog.Write("Size: 0x%08x", size);
|
||||
ConLog.Write("Unknown: 0x%08x", unknown);
|
||||
}
|
||||
void Show();
|
||||
};
|
||||
|
||||
struct ControlInfo
|
||||
|
@ -133,122 +90,9 @@ struct ControlInfo
|
|||
} npdrm;
|
||||
};
|
||||
|
||||
void Load(vfsStream& f)
|
||||
{
|
||||
type = Read32(f);
|
||||
size = Read32(f);
|
||||
next = Read64(f);
|
||||
void Load(vfsStream& f);
|
||||
|
||||
if (type == 1)
|
||||
{
|
||||
control_flags.ctrl_flag1 = Read32(f);
|
||||
control_flags.unknown1 = Read32(f);
|
||||
control_flags.unknown2 = Read32(f);
|
||||
control_flags.unknown3 = Read32(f);
|
||||
control_flags.unknown4 = Read32(f);
|
||||
control_flags.unknown5 = Read32(f);
|
||||
control_flags.unknown6 = Read32(f);
|
||||
control_flags.unknown7 = Read32(f);
|
||||
}
|
||||
else if (type == 2)
|
||||
{
|
||||
if (size == 0x30)
|
||||
{
|
||||
f.Read(file_digest_30.digest, 20);
|
||||
file_digest_30.unknown = Read64(f);
|
||||
}
|
||||
else if (size == 0x40)
|
||||
{
|
||||
f.Read(file_digest_40.digest1, 20);
|
||||
f.Read(file_digest_40.digest2, 20);
|
||||
file_digest_40.unknown = Read64(f);
|
||||
}
|
||||
}
|
||||
else if (type == 3)
|
||||
{
|
||||
npdrm.magic = Read32(f);
|
||||
npdrm.unknown1 = Read32(f);
|
||||
npdrm.license = Read32(f);
|
||||
npdrm.type = Read32(f);
|
||||
f.Read(npdrm.content_id, 48);
|
||||
f.Read(npdrm.digest, 16);
|
||||
f.Read(npdrm.invdigest, 16);
|
||||
f.Read(npdrm.xordigest, 16);
|
||||
npdrm.unknown2 = Read64(f);
|
||||
npdrm.unknown3 = Read64(f);
|
||||
}
|
||||
}
|
||||
|
||||
void Show()
|
||||
{
|
||||
ConLog.Write("Type: 0x%08x", type);
|
||||
ConLog.Write("Size: 0x%08x", size);
|
||||
ConLog.Write("Next: 0x%llx", next);
|
||||
|
||||
if (type == 1)
|
||||
{
|
||||
ConLog.Write("Control flag 1: 0x%08x", control_flags.ctrl_flag1);
|
||||
ConLog.Write("Unknown1: 0x%08x", control_flags.unknown1);
|
||||
ConLog.Write("Unknown2: 0x%08x", control_flags.unknown2);
|
||||
ConLog.Write("Unknown3: 0x%08x", control_flags.unknown3);
|
||||
ConLog.Write("Unknown4: 0x%08x", control_flags.unknown4);
|
||||
ConLog.Write("Unknown5: 0x%08x", control_flags.unknown5);
|
||||
ConLog.Write("Unknown6: 0x%08x", control_flags.unknown6);
|
||||
ConLog.Write("Unknown7: 0x%08x", control_flags.unknown7);
|
||||
}
|
||||
else if (type == 2)
|
||||
{
|
||||
if (size == 0x30)
|
||||
{
|
||||
std::string digest_str;
|
||||
for (int i = 0; i < 20; i++)
|
||||
digest_str += fmt::Format("%02x", file_digest_30.digest[i]);
|
||||
|
||||
ConLog.Write("Digest: %s", digest_str.c_str());
|
||||
ConLog.Write("Unknown: 0x%llx", file_digest_30.unknown);
|
||||
}
|
||||
else if (size == 0x40)
|
||||
{
|
||||
std::string digest_str1;
|
||||
std::string digest_str2;
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
digest_str1 += fmt::Format("%02x", file_digest_40.digest1[i]);
|
||||
digest_str2 += fmt::Format("%02x", file_digest_40.digest2[i]);
|
||||
}
|
||||
|
||||
ConLog.Write("Digest1: %s", digest_str1.c_str());
|
||||
ConLog.Write("Digest2: %s", digest_str2.c_str());
|
||||
ConLog.Write("Unknown: 0x%llx", file_digest_40.unknown);
|
||||
}
|
||||
}
|
||||
else if (type == 3)
|
||||
{
|
||||
std::string contentid_str;
|
||||
std::string digest_str;
|
||||
std::string invdigest_str;
|
||||
std::string xordigest_str;
|
||||
for (int i = 0; i < 48; i++)
|
||||
contentid_str += fmt::Format("%02x", npdrm.content_id[i]);
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
digest_str += fmt::Format("%02x", npdrm.digest[i]);
|
||||
invdigest_str += fmt::Format("%02x", npdrm.invdigest[i]);
|
||||
xordigest_str += fmt::Format("%02x", npdrm.xordigest[i]);
|
||||
}
|
||||
|
||||
ConLog.Write("Magic: 0x%08x", npdrm.magic);
|
||||
ConLog.Write("Unknown1: 0x%08x", npdrm.unknown1);
|
||||
ConLog.Write("License: 0x%08x", npdrm.license);
|
||||
ConLog.Write("Type: 0x%08x", npdrm.type);
|
||||
ConLog.Write("ContentID: %s", contentid_str.c_str());
|
||||
ConLog.Write("Digest: %s", digest_str.c_str());
|
||||
ConLog.Write("Inverse digest: %s", invdigest_str.c_str());
|
||||
ConLog.Write("XOR digest: %s", xordigest_str.c_str());
|
||||
ConLog.Write("Unknown2: 0x%llx", npdrm.unknown2);
|
||||
ConLog.Write("Unknown3: 0x%llx", npdrm.unknown3);
|
||||
}
|
||||
}
|
||||
void Show();
|
||||
};
|
||||
|
||||
|
||||
|
@ -259,33 +103,9 @@ struct MetadataInfo
|
|||
u8 iv[0x10];
|
||||
u8 iv_pad[0x10];
|
||||
|
||||
void Load(u8* in)
|
||||
{
|
||||
memcpy(key, in, 0x10);
|
||||
memcpy(key_pad, in + 0x10, 0x10);
|
||||
memcpy(iv, in + 0x20, 0x10);
|
||||
memcpy(iv_pad, in + 0x30, 0x10);
|
||||
}
|
||||
void Load(u8* in);
|
||||
|
||||
void Show()
|
||||
{
|
||||
std::string key_str;
|
||||
std::string key_pad_str;
|
||||
std::string iv_str;
|
||||
std::string iv_pad_str;
|
||||
for (int i = 0; i < 0x10; i++)
|
||||
{
|
||||
key_str += fmt::Format("%02x", key[i]);
|
||||
key_pad_str += fmt::Format("%02x", key_pad[i]);
|
||||
iv_str += fmt::Format("%02x", iv[i]);
|
||||
iv_pad_str += fmt::Format("%02x", iv_pad[i]);
|
||||
}
|
||||
|
||||
ConLog.Write("Key: %s", key_str.c_str());
|
||||
ConLog.Write("Key pad: %s", key_pad_str.c_str());
|
||||
ConLog.Write("IV: %s", iv_str.c_str());
|
||||
ConLog.Write("IV pad: %s", iv_pad_str.c_str());
|
||||
}
|
||||
void Show();
|
||||
};
|
||||
|
||||
struct MetadataHeader
|
||||
|
@ -298,36 +118,9 @@ struct MetadataHeader
|
|||
u32 unknown2;
|
||||
u32 unknown3;
|
||||
|
||||
void Load(u8* in)
|
||||
{
|
||||
memcpy(&signature_input_length, in, 8);
|
||||
memcpy(&unknown1, in + 8, 4);
|
||||
memcpy(§ion_count, in + 12, 4);
|
||||
memcpy(&key_count, in + 16, 4);
|
||||
memcpy(&opt_header_size, in + 20, 4);
|
||||
memcpy(&unknown2, in + 24, 4);
|
||||
memcpy(&unknown3, in + 28, 4);
|
||||
void Load(u8* in);
|
||||
|
||||
// Endian swap.
|
||||
signature_input_length = swap64(signature_input_length);
|
||||
unknown1 = swap32(unknown1);
|
||||
section_count = swap32(section_count);
|
||||
key_count = swap32(key_count);
|
||||
opt_header_size = swap32(opt_header_size);
|
||||
unknown2 = swap32(unknown2);
|
||||
unknown3 = swap32(unknown3);
|
||||
}
|
||||
|
||||
void Show()
|
||||
{
|
||||
ConLog.Write("Signature input length: 0x%llx", signature_input_length);
|
||||
ConLog.Write("Unknown1: 0x%08x", unknown1);
|
||||
ConLog.Write("Section count: 0x%08x", section_count);
|
||||
ConLog.Write("Key count: 0x%08x", key_count);
|
||||
ConLog.Write("Optional header size: 0x%08x", opt_header_size);
|
||||
ConLog.Write("Unknown2: 0x%08x", unknown2);
|
||||
ConLog.Write("Unknown3: 0x%08x", unknown3);
|
||||
}
|
||||
void Show();
|
||||
};
|
||||
|
||||
struct MetadataSectionHeader
|
||||
|
@ -343,45 +136,9 @@ struct MetadataSectionHeader
|
|||
u32 iv_idx;
|
||||
u32 compressed;
|
||||
|
||||
void Load(u8* in)
|
||||
{
|
||||
memcpy(&data_offset, in, 8);
|
||||
memcpy(&data_size, in + 8, 8);
|
||||
memcpy(&type, in + 16, 4);
|
||||
memcpy(&program_idx, in + 20, 4);
|
||||
memcpy(&hashed, in + 24, 4);
|
||||
memcpy(&sha1_idx, in + 28, 4);
|
||||
memcpy(&encrypted, in + 32, 4);
|
||||
memcpy(&key_idx, in + 36, 4);
|
||||
memcpy(&iv_idx, in + 40, 4);
|
||||
memcpy(&compressed, in + 44, 4);
|
||||
void Load(u8* in);
|
||||
|
||||
// Endian swap.
|
||||
data_offset = swap64(data_offset);
|
||||
data_size = swap64(data_size);
|
||||
type = swap32(type);
|
||||
program_idx = swap32(program_idx);
|
||||
hashed = swap32(hashed);
|
||||
sha1_idx = swap32(sha1_idx);
|
||||
encrypted = swap32(encrypted);
|
||||
key_idx = swap32(key_idx);
|
||||
iv_idx = swap32(iv_idx);
|
||||
compressed = swap32(compressed);
|
||||
}
|
||||
|
||||
void Show()
|
||||
{
|
||||
ConLog.Write("Data offset: 0x%llx", data_offset);
|
||||
ConLog.Write("Data size: 0x%llx", data_size);
|
||||
ConLog.Write("Type: 0x%08x", type);
|
||||
ConLog.Write("Program index: 0x%08x", program_idx);
|
||||
ConLog.Write("Hashed: 0x%08x", hashed);
|
||||
ConLog.Write("SHA1 index: 0x%08x", sha1_idx);
|
||||
ConLog.Write("Encrypted: 0x%08x", encrypted);
|
||||
ConLog.Write("Key index: 0x%08x", key_idx);
|
||||
ConLog.Write("IV index: 0x%08x", iv_idx);
|
||||
ConLog.Write("Compressed: 0x%08x", compressed);
|
||||
}
|
||||
void Show();
|
||||
};
|
||||
|
||||
struct SectionHash {
|
||||
|
@ -389,12 +146,7 @@ struct SectionHash {
|
|||
u8 padding[12];
|
||||
u8 hmac_key[64];
|
||||
|
||||
void Load(vfsStream& f)
|
||||
{
|
||||
f.Read(sha1, 20);
|
||||
f.Read(padding, 12);
|
||||
f.Read(hmac_key, 64);
|
||||
}
|
||||
void Load(vfsStream& f);
|
||||
};
|
||||
|
||||
struct CapabilitiesInfo
|
||||
|
@ -409,18 +161,7 @@ struct CapabilitiesInfo
|
|||
u32 unknown4;
|
||||
u32 unknown5;
|
||||
|
||||
void Load(vfsStream& f)
|
||||
{
|
||||
type = Read32(f);
|
||||
capabilities_size = Read32(f);
|
||||
next = Read32(f);
|
||||
unknown1 = Read32(f);
|
||||
unknown2 = Read64(f);
|
||||
unknown3 = Read64(f);
|
||||
flags = Read64(f);
|
||||
unknown4 = Read32(f);
|
||||
unknown5 = Read32(f);
|
||||
}
|
||||
void Load(vfsStream& f);
|
||||
};
|
||||
|
||||
struct Signature
|
||||
|
@ -429,12 +170,7 @@ struct Signature
|
|||
u8 s[21];
|
||||
u8 padding[6];
|
||||
|
||||
void Load(vfsStream& f)
|
||||
{
|
||||
f.Read(r, 21);
|
||||
f.Read(s, 21);
|
||||
f.Read(padding, 6);
|
||||
}
|
||||
void Load(vfsStream& f);
|
||||
};
|
||||
|
||||
struct SelfSection
|
||||
|
@ -443,12 +179,7 @@ struct SelfSection
|
|||
u64 size;
|
||||
u64 offset;
|
||||
|
||||
void Load(vfsStream& f)
|
||||
{
|
||||
*data = Read32(f);
|
||||
size = Read64(f);
|
||||
offset = Read64(f);
|
||||
}
|
||||
void Load(vfsStream& f);
|
||||
};
|
||||
|
||||
class SELFDecrypter
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#include "stdafx.h"
|
||||
#include "aes.h"
|
||||
#include "sha1.h"
|
||||
#include "utils.h"
|
||||
|
||||
// Endian swap auxiliary functions.
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
#pragma once
|
||||
#include "aes.h"
|
||||
#include "sha1.h"
|
||||
|
||||
// Auxiliary functions (endian swap and xor).
|
||||
u16 swap16(u16 i);
|
||||
|
|
|
@ -21,8 +21,8 @@ public:
|
|||
virtual u8 DecodeMemory(const u64 address)
|
||||
{
|
||||
using namespace ARMv7_opcodes;
|
||||
const u16 code0 = Memory.Read16(address);
|
||||
const u16 code1 = Memory.Read16(address + 2);
|
||||
const u16 code0 = vm::psv::read16((u32)address);
|
||||
const u16 code1 = vm::psv::read16((u32)address + 2);
|
||||
|
||||
switch(code0 >> 12) //15 - 12
|
||||
{
|
||||
|
@ -33,7 +33,7 @@ public:
|
|||
switch((code0 >> 8) & 0x1)
|
||||
{
|
||||
case 1:
|
||||
m_op.CBZ((code0 >> 11) & 0x1, branchTarget((((code0 >> 9) & 0x1) << 5) | (code0 >> 3) & 0x1f), code0 & 0x7, 2);
|
||||
m_op.CBZ((code0 >> 11) & 0x1, branchTarget((((code0 >> 9) & 0x1) << 5) | ((code0 >> 3) & 0x1f)), code0 & 0x7, 2);
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#pragma once
|
||||
#include "Emu/ARMv7/ARMv7Opcodes.h"
|
||||
#include "Emu/CPU/CPUDisAsm.h"
|
||||
#include "Gui/DisAsmFrame.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
|
||||
static const char* g_arm_cond_name[16] =
|
||||
{
|
||||
|
@ -24,7 +22,7 @@ public:
|
|||
protected:
|
||||
virtual u32 DisAsmBranchTarget(const s32 imm)
|
||||
{
|
||||
return dump_pc + imm;
|
||||
return (u32)dump_pc + imm;
|
||||
}
|
||||
|
||||
std::string GetRegsListString(u16 regs_list)
|
||||
|
|
|
@ -233,7 +233,7 @@ public:
|
|||
return result;
|
||||
}
|
||||
|
||||
bool ConditionPassed(u8 cond)
|
||||
bool ConditionPassed(u8 cond) const
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
|
@ -260,7 +260,7 @@ public:
|
|||
protected:
|
||||
void NULL_OP()
|
||||
{
|
||||
ConLog.Error("null");
|
||||
LOG_ERROR(HLE, "null");
|
||||
Emu.Pause();
|
||||
}
|
||||
|
||||
|
@ -275,7 +275,7 @@ protected:
|
|||
if(regs_list & mask)
|
||||
{
|
||||
CPU.SP -= 4;
|
||||
Memory.Write32(CPU.SP, CPU.read_gpr(i));
|
||||
vm::psv::write32(CPU.SP, CPU.read_gpr(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -286,7 +286,7 @@ protected:
|
|||
{
|
||||
if(regs_list & mask)
|
||||
{
|
||||
CPU.write_gpr(i, Memory.Read32(CPU.SP));
|
||||
CPU.write_gpr(i, vm::psv::read32(CPU.SP));
|
||||
CPU.SP += 4;
|
||||
}
|
||||
}
|
||||
|
@ -310,13 +310,13 @@ protected:
|
|||
|
||||
void BL(u32 imm, u8 intstr_size)
|
||||
{
|
||||
CPU.LR = (CPU.PC + intstr_size) | 1;
|
||||
CPU.LR = ((u32)CPU.PC + intstr_size) | 1;
|
||||
CPU.SetBranch(CPU.PC + intstr_size + imm);
|
||||
}
|
||||
|
||||
void UNK(const u16 code0, const u16 code1)
|
||||
{
|
||||
ConLog.Error("Unknown/Illegal opcode! (0x%04x : 0x%04x)", code0, code1);
|
||||
LOG_ERROR(HLE, "Unknown/Illegal opcode! (0x%04x : 0x%04x)", code0, code1);
|
||||
Emu.Pause();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
#include "stdafx.h"
|
||||
#include "rpcs3/Ini.h"
|
||||
#include "Utilities/Log.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
|
||||
#include "ARMv7Thread.h"
|
||||
#include "ARMv7Decoder.h"
|
||||
#include "ARMv7DisAsm.h"
|
||||
|
@ -13,7 +18,7 @@ void ARMv7Thread::InitRegs()
|
|||
memset(GPR, 0, sizeof(GPR[0]) * 15);
|
||||
APSR.APSR = 0;
|
||||
IPSR.IPSR = 0;
|
||||
SP = m_stack_point;
|
||||
SP = (u32)m_stack_point;
|
||||
}
|
||||
|
||||
void ARMv7Thread::InitStack()
|
||||
|
@ -99,4 +104,4 @@ void ARMv7Thread::DoStop()
|
|||
|
||||
void ARMv7Thread::DoCode()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ public:
|
|||
u32 IPSR;
|
||||
} IPSR;
|
||||
|
||||
void write_gpr(u8 n, u32 value)
|
||||
void write_gpr(u32 n, u32 value)
|
||||
{
|
||||
assert(n < 16);
|
||||
|
||||
|
@ -65,7 +65,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
u32 read_gpr(u8 n)
|
||||
u32 read_gpr(u32 n)
|
||||
{
|
||||
assert(n < 16);
|
||||
|
||||
|
@ -74,7 +74,7 @@ public:
|
|||
return GPR[n];
|
||||
}
|
||||
|
||||
return PC;
|
||||
return (u32)PC;
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
#include "stdafx.h"
|
||||
#include "Utilities/Log.h"
|
||||
#include "Emu/System.h"
|
||||
#include "rpcs3/Ini.h"
|
||||
|
||||
#include "OpenALThread.h"
|
||||
|
||||
ALenum g_last_al_error = AL_NO_ERROR;
|
||||
|
@ -13,7 +17,7 @@ void printAlError(ALenum err, const char* situation)
|
|||
{
|
||||
if(err != AL_NO_ERROR)
|
||||
{
|
||||
ConLog.Error("%s: OpenAL error 0x%04x", situation, err);
|
||||
LOG_ERROR(HLE, "%s: OpenAL error 0x%04x", situation, err);
|
||||
Emu.Pause();
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +26,7 @@ void printAlcError(ALCenum err, const char* situation)
|
|||
{
|
||||
if(err != ALC_NO_ERROR)
|
||||
{
|
||||
ConLog.Error("%s: OpenALC error 0x%04x", situation, err);
|
||||
LOG_ERROR(HLE, "%s: OpenALC error 0x%04x", situation, err);
|
||||
Emu.Pause();
|
||||
}
|
||||
}
|
||||
|
@ -132,7 +136,7 @@ void OpenALThread::AddData(const void* src, ALsizei size)
|
|||
|
||||
int bsize = size < m_buffer_size ? size : m_buffer_size;
|
||||
if (!AddBlock(buffer, bsize, bsrc))
|
||||
ConLog.Error("OpenALThread::AddBlock: invalid block size: %d", bsize);
|
||||
LOG_ERROR(HLE, "OpenALThread::AddBlock: invalid block size: %d", bsize);
|
||||
|
||||
alSourceQueueBuffers(m_source, 1, &buffer);
|
||||
checkForAlError("alSourceQueueBuffers");
|
||||
|
@ -152,4 +156,4 @@ bool OpenALThread::AddBlock(const ALuint buffer_id, const ALsizei size, const vo
|
|||
checkForAlError("alBufferData");
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ AudioDumper::~AudioDumper()
|
|||
|
||||
bool AudioDumper::Init()
|
||||
{
|
||||
return m_output.Open("audio.wav", wxFile::write);
|
||||
return m_output.Open("audio.wav", rFile::write);
|
||||
}
|
||||
|
||||
void AudioDumper::WriteHeader()
|
||||
|
@ -34,8 +34,8 @@ size_t AudioDumper::WriteData(const void* buffer, size_t size)
|
|||
if (!do_save) return size; // ignore empty data
|
||||
#endif
|
||||
size_t ret = m_output.Write(buffer, size);
|
||||
m_header.Size += ret;
|
||||
m_header.RIFF.Size += ret;
|
||||
m_header.Size += (u32)ret;
|
||||
m_header.RIFF.Size += (u32)ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "Utilities/rFile.h"
|
||||
|
||||
struct WAVHeader
|
||||
{
|
||||
struct RIFFHeader
|
||||
|
@ -55,7 +57,7 @@ class AudioDumper
|
|||
{
|
||||
private:
|
||||
WAVHeader m_header;
|
||||
wxFile m_output;
|
||||
rFile m_output;
|
||||
|
||||
public:
|
||||
AudioDumper(u8 ch);
|
||||
|
@ -65,5 +67,5 @@ public:
|
|||
void WriteHeader();
|
||||
size_t WriteData(const void* buffer, size_t size);
|
||||
void Finalize();
|
||||
const u8 GetCh() const { return m_header.FMT.NumChannels; }
|
||||
const u8 GetCh() const { return (u8)m_header.FMT.NumChannels; }
|
||||
};
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "stdafx.h"
|
||||
#include "rpcs3/Ini.h"
|
||||
#include "AudioManager.h"
|
||||
|
||||
OpenALThread* m_audio_out;
|
||||
|
|
|
@ -257,23 +257,38 @@ struct CellAudioInDeviceConfiguration
|
|||
u8 reserved[31];
|
||||
};
|
||||
|
||||
enum CellBgmPlaybackStatusState
|
||||
enum CellSysutilBgmPlaybackStatusState
|
||||
{
|
||||
CELL_BGMPLAYBACK_STATUS_PLAY = 0,
|
||||
CELL_BGMPLAYBACK_STATUS_STOP = 1
|
||||
CELL_SYSUTIL_BGMPLAYBACK_STATUS_PLAY = 0,
|
||||
CELL_SYSUTIL_BGMPLAYBACK_STATUS_STOP = 1
|
||||
};
|
||||
|
||||
enum CellBgmPlaybackStatusEnabled
|
||||
enum CellSysutilBgmPlaybackStatusEnabled
|
||||
{
|
||||
CELL_BGMPLAYBACK_STATUS_ENABLE = 0,
|
||||
CELL_BGMPLAYBACK_STATUS_DISABLE = 1
|
||||
CELL_SYSUTIL_BGMPLAYBACK_STATUS_ENABLE = 0,
|
||||
CELL_SYSUTIL_BGMPLAYBACK_STATUS_DISABLE = 1
|
||||
};
|
||||
|
||||
struct CellBgmPlaybackStatus
|
||||
struct CellSysutilBgmPlaybackStatus
|
||||
{
|
||||
u8 playbackState;
|
||||
u8 enabled;
|
||||
u8 playerState;
|
||||
u8 enableState;
|
||||
char contentId[16];
|
||||
u8 fadeRatio;
|
||||
u8 currentFadeRatio;
|
||||
char reserved[13];
|
||||
};
|
||||
|
||||
struct CellSysutilBgmPlaybackStatus2
|
||||
{
|
||||
u8 playerState;
|
||||
char reserved[7];
|
||||
};
|
||||
|
||||
struct CellSysutilBgmPlaybackExtraParam
|
||||
{
|
||||
be_t<s32> systemBgmFadeInTime;
|
||||
be_t<s32> systemBgmFadeOutTime;
|
||||
be_t<s32> gameBgmFadeInTime;
|
||||
be_t<s32> gameBgmFadeOutTime;
|
||||
char reserved[8];
|
||||
};
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#pragma once
|
||||
#include <algorithm>
|
||||
#include "CPUInstrTable.h"
|
||||
#pragma warning( disable : 4800 )
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include "Emu/Memory/Memory.h"
|
||||
|
||||
enum CPUDisAsmMode
|
||||
{
|
||||
CPUDisAsm_DumpMode,
|
||||
|
@ -21,18 +19,18 @@ protected:
|
|||
{
|
||||
case CPUDisAsm_DumpMode:
|
||||
last_opcode = fmt::Format("\t%08llx:\t%02x %02x %02x %02x\t%s\n", dump_pc,
|
||||
Memory.Read8(offset + dump_pc),
|
||||
Memory.Read8(offset + dump_pc + 1),
|
||||
Memory.Read8(offset + dump_pc + 2),
|
||||
Memory.Read8(offset + dump_pc + 3), value.c_str());
|
||||
offset[dump_pc],
|
||||
offset[dump_pc + 1],
|
||||
offset[dump_pc + 2],
|
||||
offset[dump_pc + 3], value.c_str());
|
||||
break;
|
||||
|
||||
case CPUDisAsm_InterpreterMode:
|
||||
last_opcode = fmt::Format("[%08llx] %02x %02x %02x %02x: %s", dump_pc,
|
||||
Memory.Read8(offset + dump_pc),
|
||||
Memory.Read8(offset + dump_pc + 1),
|
||||
Memory.Read8(offset + dump_pc + 2),
|
||||
Memory.Read8(offset + dump_pc + 3), value.c_str());
|
||||
offset[dump_pc],
|
||||
offset[dump_pc + 1],
|
||||
offset[dump_pc + 2],
|
||||
offset[dump_pc + 3], value.c_str());
|
||||
break;
|
||||
|
||||
case CPUDisAsm_CompilerElfMode:
|
||||
|
@ -44,7 +42,7 @@ protected:
|
|||
public:
|
||||
std::string last_opcode;
|
||||
u64 dump_pc;
|
||||
u64 offset;
|
||||
u8* offset;
|
||||
|
||||
protected:
|
||||
CPUDisAsm(CPUDisAsmMode mode)
|
||||
|
@ -57,7 +55,7 @@ protected:
|
|||
|
||||
std::string FixOp(std::string op)
|
||||
{
|
||||
op.append(max<int>(10 - (int)op.length(), 0),' ');
|
||||
op.append(std::max<int>(10 - (int)op.length(), 0),' ');
|
||||
return op;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
#include "stdafx.h"
|
||||
#include "CPUThread.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"
|
||||
|
||||
reservation_struct reservation;
|
||||
#include "CPUDecoder.h"
|
||||
#include "CPUThread.h"
|
||||
|
||||
CPUThread* GetCurrentCPUThread()
|
||||
{
|
||||
|
@ -21,6 +27,7 @@ CPUThread::CPUThread(CPUThreadType type)
|
|||
, m_is_step(false)
|
||||
, m_is_branch(false)
|
||||
, m_status(Stopped)
|
||||
, m_last_syscall(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -29,6 +36,10 @@ CPUThread::~CPUThread()
|
|||
safe_delete(m_dec);
|
||||
}
|
||||
|
||||
bool CPUThread::IsRunning() const { return m_status == Running; }
|
||||
bool CPUThread::IsPaused() const { return m_status == Paused; }
|
||||
bool CPUThread::IsStopped() const { return m_status == Stopped; }
|
||||
|
||||
void CPUThread::Close()
|
||||
{
|
||||
ThreadBase::Stop(m_sync_wait);
|
||||
|
@ -79,13 +90,13 @@ void CPUThread::SetName(const std::string& name)
|
|||
|
||||
void CPUThread::Wait(bool wait)
|
||||
{
|
||||
wxCriticalSectionLocker lock(m_cs_sync);
|
||||
std::lock_guard<std::mutex> lock(m_cs_sync);
|
||||
m_sync_wait = wait;
|
||||
}
|
||||
|
||||
void CPUThread::Wait(const CPUThread& thr)
|
||||
{
|
||||
wxCriticalSectionLocker lock(m_cs_sync);
|
||||
std::lock_guard<std::mutex> lock(m_cs_sync);
|
||||
m_wait_thread_id = thr.GetId();
|
||||
m_sync_wait = true;
|
||||
}
|
||||
|
@ -141,12 +152,6 @@ void CPUThread::NextPc(u8 instr_size)
|
|||
|
||||
void CPUThread::SetBranch(const u64 pc, bool record_branch)
|
||||
{
|
||||
if(!Memory.IsGoodAddr(m_offset + pc))
|
||||
{
|
||||
ConLog.Error("%s branch error: bad address 0x%llx #pc: 0x%llx", GetFName().c_str(), m_offset + pc, m_offset + PC);
|
||||
Emu.Pause();
|
||||
}
|
||||
|
||||
m_is_branch = true;
|
||||
nPC = pc;
|
||||
|
||||
|
@ -171,13 +176,13 @@ void CPUThread::SetError(const u32 error)
|
|||
}
|
||||
}
|
||||
|
||||
wxArrayString CPUThread::ErrorToString(const u32 error)
|
||||
std::vector<std::string> CPUThread::ErrorToString(const u32 error)
|
||||
{
|
||||
wxArrayString earr;
|
||||
std::vector<std::string> earr;
|
||||
|
||||
if(error == 0) return earr;
|
||||
|
||||
earr.Add("Unknown error");
|
||||
earr.push_back("Unknown error");
|
||||
|
||||
return earr;
|
||||
}
|
||||
|
@ -189,9 +194,7 @@ void CPUThread::Run()
|
|||
|
||||
Reset();
|
||||
|
||||
#ifndef QT_UI
|
||||
wxGetApp().SendDbgCommand(DID_START_THREAD, this);
|
||||
#endif
|
||||
SendDbgCommand(DID_START_THREAD, this);
|
||||
|
||||
m_status = Running;
|
||||
|
||||
|
@ -201,18 +204,14 @@ void CPUThread::Run()
|
|||
DoRun();
|
||||
Emu.CheckStatus();
|
||||
|
||||
#ifndef QT_UI
|
||||
wxGetApp().SendDbgCommand(DID_STARTED_THREAD, this);
|
||||
#endif
|
||||
SendDbgCommand(DID_STARTED_THREAD, this);
|
||||
}
|
||||
|
||||
void CPUThread::Resume()
|
||||
{
|
||||
if(!IsPaused()) return;
|
||||
|
||||
#ifndef QT_UI
|
||||
wxGetApp().SendDbgCommand(DID_RESUME_THREAD, this);
|
||||
#endif
|
||||
SendDbgCommand(DID_RESUME_THREAD, this);
|
||||
|
||||
m_status = Running;
|
||||
DoResume();
|
||||
|
@ -220,36 +219,28 @@ void CPUThread::Resume()
|
|||
|
||||
ThreadBase::Start();
|
||||
|
||||
#ifndef QT_UI
|
||||
wxGetApp().SendDbgCommand(DID_RESUMED_THREAD, this);
|
||||
#endif
|
||||
SendDbgCommand(DID_RESUMED_THREAD, this);
|
||||
}
|
||||
|
||||
void CPUThread::Pause()
|
||||
{
|
||||
if(!IsRunning()) return;
|
||||
|
||||
#ifndef QT_UI
|
||||
wxGetApp().SendDbgCommand(DID_PAUSE_THREAD, this);
|
||||
#endif
|
||||
SendDbgCommand(DID_PAUSE_THREAD, this);
|
||||
|
||||
m_status = Paused;
|
||||
DoPause();
|
||||
Emu.CheckStatus();
|
||||
|
||||
// ThreadBase::Stop(); // "Abort() called" exception
|
||||
#ifndef QT_UI
|
||||
wxGetApp().SendDbgCommand(DID_PAUSED_THREAD, this);
|
||||
#endif
|
||||
SendDbgCommand(DID_PAUSED_THREAD, this);
|
||||
}
|
||||
|
||||
void CPUThread::Stop()
|
||||
{
|
||||
if(IsStopped()) return;
|
||||
|
||||
#ifndef QT_UI
|
||||
wxGetApp().SendDbgCommand(DID_STOP_THREAD, this);
|
||||
#endif
|
||||
SendDbgCommand(DID_STOP_THREAD, this);
|
||||
|
||||
m_status = Stopped;
|
||||
|
||||
|
@ -263,17 +254,13 @@ void CPUThread::Stop()
|
|||
|
||||
Emu.CheckStatus();
|
||||
|
||||
#ifndef QT_UI
|
||||
wxGetApp().SendDbgCommand(DID_STOPED_THREAD, this);
|
||||
#endif
|
||||
SendDbgCommand(DID_STOPED_THREAD, this);
|
||||
}
|
||||
|
||||
void CPUThread::Exec()
|
||||
{
|
||||
m_is_step = false;
|
||||
#ifndef QT_UI
|
||||
wxGetApp().SendDbgCommand(DID_EXEC_THREAD, this);
|
||||
#endif
|
||||
SendDbgCommand(DID_EXEC_THREAD, this);
|
||||
|
||||
if(IsRunning())
|
||||
ThreadBase::Start();
|
||||
|
@ -282,63 +269,89 @@ void CPUThread::Exec()
|
|||
void CPUThread::ExecOnce()
|
||||
{
|
||||
m_is_step = true;
|
||||
#ifndef QT_UI
|
||||
wxGetApp().SendDbgCommand(DID_EXEC_THREAD, this);
|
||||
#endif
|
||||
SendDbgCommand(DID_EXEC_THREAD, this);
|
||||
|
||||
m_status = Running;
|
||||
ThreadBase::Start();
|
||||
ThreadBase::Stop(true,false);
|
||||
m_status = Paused;
|
||||
#ifndef QT_UI
|
||||
wxGetApp().SendDbgCommand(DID_PAUSE_THREAD, this);
|
||||
wxGetApp().SendDbgCommand(DID_PAUSED_THREAD, this);
|
||||
#endif
|
||||
SendDbgCommand(DID_PAUSE_THREAD, this);
|
||||
SendDbgCommand(DID_PAUSED_THREAD, this);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
void _se_translator(unsigned int u, EXCEPTION_POINTERS* pExp)
|
||||
{
|
||||
const u64 addr = (u64)pExp->ExceptionRecord->ExceptionInformation[1] - (u64)Memory.GetBaseAddr();
|
||||
if (u == EXCEPTION_ACCESS_VIOLATION && addr < 0x100000000)
|
||||
{
|
||||
// TODO: allow recovering from a page fault
|
||||
throw fmt::Format("Access violation: addr = 0x%x (last_syscall=0x%llx (%s))",
|
||||
(u32)addr, (u64)GetCurrentCPUThread()->m_last_syscall, SysCalls::GetHLEFuncName((u32)GetCurrentCPUThread()->m_last_syscall).c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
// some fatal error (should crash)
|
||||
return;
|
||||
}
|
||||
}
|
||||
#else
|
||||
// TODO: linux version
|
||||
#endif
|
||||
|
||||
void CPUThread::Task()
|
||||
{
|
||||
if (Ini.LogAllSysCalls.GetValue()) ConLog.Write("%s enter", CPUThread::GetFName().c_str());
|
||||
if (Ini.HLELogging.GetValue()) LOG_NOTICE(PPU, "%s enter", CPUThread::GetFName().c_str());
|
||||
|
||||
const std::vector<u64>& bp = Emu.GetBreakPoints();
|
||||
|
||||
for (uint i = 0; i<bp.size(); ++i)
|
||||
{
|
||||
if (bp[i] == m_offset + PC)
|
||||
{
|
||||
Emu.Pause();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<u64> trace;
|
||||
|
||||
#ifdef _WIN32
|
||||
_set_se_translator(_se_translator);
|
||||
#else
|
||||
// TODO: linux version
|
||||
#endif
|
||||
|
||||
try
|
||||
{
|
||||
for(uint i=0; i<bp.size(); ++i)
|
||||
{
|
||||
if(bp[i] == m_offset + PC)
|
||||
{
|
||||
Emu.Pause();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while(true)
|
||||
while (true)
|
||||
{
|
||||
int status = ThreadStatus();
|
||||
|
||||
if(status == CPUThread_Stopped || status == CPUThread_Break)
|
||||
if (status == CPUThread_Stopped || status == CPUThread_Break)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if(status == CPUThread_Sleeping)
|
||||
if (status == CPUThread_Sleeping)
|
||||
{
|
||||
Sleep(1);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
continue;
|
||||
}
|
||||
|
||||
Step();
|
||||
//if (PC - 0x13ED4 < 0x288) trace.push_back(PC);
|
||||
NextPc(m_dec->DecodeMemory(PC + m_offset));
|
||||
|
||||
if(status == CPUThread_Step)
|
||||
if (status == CPUThread_Step)
|
||||
{
|
||||
m_is_step = false;
|
||||
break;
|
||||
}
|
||||
|
||||
for(uint i=0; i<bp.size(); ++i)
|
||||
for (uint i = 0; i < bp.size(); ++i)
|
||||
{
|
||||
if(bp[i] == PC)
|
||||
if (bp[i] == PC)
|
||||
{
|
||||
Emu.Pause();
|
||||
break;
|
||||
|
@ -346,20 +359,20 @@ void CPUThread::Task()
|
|||
}
|
||||
}
|
||||
}
|
||||
catch(const std::string& e)
|
||||
catch (const std::string& e)
|
||||
{
|
||||
ConLog.Error("Exception: %s", e.c_str());
|
||||
LOG_ERROR(GENERAL, "Exception: %s", e.c_str());
|
||||
Emu.Pause();
|
||||
}
|
||||
catch(const char* e)
|
||||
catch (const char* e)
|
||||
{
|
||||
ConLog.Error("Exception: %s", e);
|
||||
}
|
||||
catch(int exitcode)
|
||||
{
|
||||
ConLog.Success("Exit Code: %d", exitcode);
|
||||
LOG_ERROR(GENERAL, "Exception: %s", e);
|
||||
Emu.Pause();
|
||||
}
|
||||
|
||||
if (Ini.LogAllSysCalls.GetValue()) ConLog.Write("%s leave", CPUThread::GetFName().c_str());
|
||||
for (auto& v : trace) LOG_NOTICE(PPU, "PC = 0x%llx", v);
|
||||
|
||||
if (Ini.HLELogging.GetValue()) LOG_NOTICE(PPU, "%s leave", CPUThread::GetFName().c_str());
|
||||
}
|
||||
|
||||
s64 CPUThread::ExecAsCallback(u64 pc, bool wait, u64 a1, u64 a2, u64 a3, u64 a4) // not multithread-safe
|
||||
|
@ -368,10 +381,10 @@ s64 CPUThread::ExecAsCallback(u64 pc, bool wait, u64 a1, u64 a2, u64 a3, u64 a4)
|
|||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
ConLog.Warning("ExecAsCallback() aborted");
|
||||
LOG_WARNING(PPU, "ExecAsCallback() aborted");
|
||||
return CELL_ECANCELED; // doesn't mean anything
|
||||
}
|
||||
Sleep(1);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
|
||||
Stop();
|
||||
|
@ -394,11 +407,11 @@ s64 CPUThread::ExecAsCallback(u64 pc, bool wait, u64 a1, u64 a2, u64 a3, u64 a4)
|
|||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
ConLog.Warning("ExecAsCallback(wait=%s) aborted", wait ? "true" : "false");
|
||||
LOG_WARNING(PPU, "ExecAsCallback(wait=%s) aborted", wait ? "true" : "false");
|
||||
return CELL_EABORT; // doesn't mean anything
|
||||
}
|
||||
Sleep(1);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
|
||||
return wait * m_exit_status;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,25 +1,6 @@
|
|||
#pragma once
|
||||
#include "Emu/Memory/MemoryBlock.h"
|
||||
#include "Emu/CPU/CPUDecoder.h"
|
||||
#include "Utilities/SMutex.h"
|
||||
|
||||
struct reservation_struct
|
||||
{
|
||||
SMutex mutex; // mutex for updating reservation_owner and data
|
||||
u32 owner; // id of thread that got reservation
|
||||
u32 addr;
|
||||
u32 size;
|
||||
u32 data32;
|
||||
u64 data64;
|
||||
u128 data[8];
|
||||
|
||||
__forceinline void clear()
|
||||
{
|
||||
owner = 0;
|
||||
}
|
||||
};
|
||||
|
||||
extern reservation_struct reservation;
|
||||
#include "Utilities/Thread.h"
|
||||
|
||||
enum CPUThreadType :unsigned char
|
||||
{
|
||||
|
@ -40,6 +21,8 @@ enum CPUThreadStatus
|
|||
CPUThread_Step,
|
||||
};
|
||||
|
||||
class CPUDecoder;
|
||||
|
||||
class CPUThread : public ThreadBase
|
||||
{
|
||||
protected:
|
||||
|
@ -54,7 +37,7 @@ protected:
|
|||
bool m_is_step;
|
||||
|
||||
u64 m_stack_addr;
|
||||
u64 m_stack_size;
|
||||
u32 m_stack_size;
|
||||
u64 m_stack_point;
|
||||
|
||||
u64 m_exit_status;
|
||||
|
@ -68,11 +51,11 @@ public:
|
|||
virtual void CloseStack();
|
||||
|
||||
u64 GetStackAddr() const { return m_stack_addr; }
|
||||
u64 GetStackSize() const { return m_stack_size; }
|
||||
u32 GetStackSize() const { return m_stack_size; }
|
||||
virtual u64 GetFreeStackSize() const=0;
|
||||
|
||||
void SetStackAddr(u64 stack_addr) { m_stack_addr = stack_addr; }
|
||||
void SetStackSize(u64 stack_size) { m_stack_size = stack_size; }
|
||||
void SetStackSize(u32 stack_size) { m_stack_size = stack_size; }
|
||||
|
||||
virtual void SetArg(const uint pos, const u64 arg) = 0;
|
||||
|
||||
|
@ -125,6 +108,11 @@ public:
|
|||
u64 cycle;
|
||||
bool m_is_branch;
|
||||
|
||||
bool m_is_interrupt;
|
||||
bool m_has_interrupt;
|
||||
u64 m_interrupt_arg;
|
||||
u64 m_last_syscall;
|
||||
|
||||
protected:
|
||||
CPUThread(CPUThreadType type);
|
||||
|
||||
|
@ -133,7 +121,7 @@ public:
|
|||
|
||||
u32 m_wait_thread_id;
|
||||
|
||||
wxCriticalSection m_cs_sync;
|
||||
std::mutex m_cs_sync;
|
||||
bool m_sync_wait;
|
||||
void Wait(bool wait);
|
||||
void Wait(const CPUThread& thr);
|
||||
|
@ -144,7 +132,7 @@ public:
|
|||
{
|
||||
while(func(ThreadStatus()))
|
||||
{
|
||||
Sleep(1);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,16 +145,16 @@ public:
|
|||
|
||||
void SetError(const u32 error);
|
||||
|
||||
static wxArrayString ErrorToString(const u32 error);
|
||||
wxArrayString ErrorToString() { return ErrorToString(m_error); }
|
||||
static std::vector<std::string> ErrorToString(const u32 error);
|
||||
std::vector<std::string> ErrorToString() { return ErrorToString(m_error); }
|
||||
|
||||
bool IsOk() const { return m_error == 0; }
|
||||
bool IsRunning() const { return m_status == Running; }
|
||||
bool IsPaused() const { return m_status == Paused; }
|
||||
bool IsStopped() const { return m_status == Stopped; }
|
||||
bool IsOk() const { return m_error == 0; }
|
||||
bool IsRunning() const;
|
||||
bool IsPaused() const;
|
||||
bool IsStopped() const;
|
||||
|
||||
bool IsJoinable() const { return m_joinable; }
|
||||
bool IsJoining() const { return m_joining; }
|
||||
bool IsJoining() const { return m_joining; }
|
||||
void SetJoinable(bool joinable) { m_joinable = joinable; }
|
||||
void SetJoining(bool joining) { m_joining = joining; }
|
||||
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
#include "stdafx.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/DbgCommand.h"
|
||||
|
||||
#include "Emu/IdManager.h"
|
||||
#include "CPUThreadManager.h"
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
#include "Emu/Cell/SPUThread.h"
|
||||
|
@ -6,7 +11,6 @@
|
|||
#include "Emu/ARMv7/ARMv7Thread.h"
|
||||
|
||||
CPUThreadManager::CPUThreadManager()
|
||||
: m_raw_spu_num(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -17,7 +21,6 @@ CPUThreadManager::~CPUThreadManager()
|
|||
|
||||
void CPUThreadManager::Close()
|
||||
{
|
||||
m_raw_spu_num = 0;
|
||||
while(m_threads.size()) RemoveThread(m_threads[0]->GetId());
|
||||
}
|
||||
|
||||
|
@ -29,19 +32,33 @@ CPUThread& CPUThreadManager::AddThread(CPUThreadType type)
|
|||
|
||||
switch(type)
|
||||
{
|
||||
case CPU_THREAD_PPU: new_thread = new PPUThread(); break;
|
||||
case CPU_THREAD_SPU: new_thread = new SPUThread(); break;
|
||||
case CPU_THREAD_RAW_SPU: new_thread = new RawSPUThread(m_raw_spu_num++); break;
|
||||
case CPU_THREAD_ARMv7: new_thread = new ARMv7Thread(); break;
|
||||
case CPU_THREAD_PPU:
|
||||
{
|
||||
new_thread = new PPUThread();
|
||||
break;
|
||||
}
|
||||
case CPU_THREAD_SPU:
|
||||
{
|
||||
new_thread = new SPUThread();
|
||||
break;
|
||||
}
|
||||
case CPU_THREAD_RAW_SPU:
|
||||
{
|
||||
new_thread = new RawSPUThread();
|
||||
break;
|
||||
}
|
||||
case CPU_THREAD_ARMv7:
|
||||
{
|
||||
new_thread = new ARMv7Thread();
|
||||
break;
|
||||
}
|
||||
default: assert(0);
|
||||
}
|
||||
|
||||
new_thread->SetId(Emu.GetIdManager().GetNewID(fmt::Format("%s Thread", new_thread->GetTypeString().c_str()), new_thread));
|
||||
|
||||
m_threads.push_back(new_thread);
|
||||
#ifndef QT_UI
|
||||
wxGetApp().SendDbgCommand(DID_CREATE_THREAD, new_thread);
|
||||
#endif
|
||||
SendDbgCommand(DID_CREATE_THREAD, new_thread);
|
||||
|
||||
return *new_thread;
|
||||
}
|
||||
|
@ -69,9 +86,7 @@ void CPUThreadManager::RemoveThread(const u32 id)
|
|||
|
||||
if (thr)
|
||||
{
|
||||
#ifndef QT_UI
|
||||
wxGetApp().SendDbgCommand(DID_REMOVE_THREAD, thr);
|
||||
#endif
|
||||
SendDbgCommand(DID_REMOVE_THREAD, thr);
|
||||
thr->Close();
|
||||
|
||||
m_threads.erase(m_threads.begin() + thread_index);
|
||||
|
@ -108,6 +123,34 @@ CPUThread* CPUThreadManager::GetThread(u32 id)
|
|||
return res;
|
||||
}
|
||||
|
||||
RawSPUThread* CPUThreadManager::GetRawSPUThread(u32 num)
|
||||
{
|
||||
if (num < sizeof(Memory.RawSPUMem) / sizeof(Memory.RawSPUMem[0]))
|
||||
{
|
||||
return (RawSPUThread*)Memory.RawSPUMem[num];
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void CPUThreadManager::NotifyThread(const u32 id)
|
||||
{
|
||||
if (!id) return;
|
||||
|
||||
std::lock_guard<std::mutex> lock(m_mtx_thread);
|
||||
|
||||
for (u32 i = 0; i < m_threads.size(); i++)
|
||||
{
|
||||
if (m_threads[i]->GetId() == id)
|
||||
{
|
||||
m_threads[i]->Notify();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CPUThreadManager::Exec()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mtx_thread);
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
class CPUThread;
|
||||
class RawSPUThread;
|
||||
enum CPUThreadType : unsigned char;
|
||||
|
||||
class CPUThreadManager
|
||||
{
|
||||
std::vector<CPUThread*> m_threads;
|
||||
std::mutex m_mtx_thread;
|
||||
wxSemaphore m_sem_task;
|
||||
u32 m_raw_spu_num;
|
||||
|
||||
public:
|
||||
CPUThreadManager();
|
||||
|
@ -17,10 +17,12 @@ public:
|
|||
|
||||
CPUThread& AddThread(CPUThreadType type);
|
||||
void RemoveThread(const u32 id);
|
||||
void NotifyThread(const u32 id);
|
||||
|
||||
std::vector<CPUThread*>& GetThreads() { return m_threads; }
|
||||
s32 GetThreadNumById(CPUThreadType type, u32 id);
|
||||
CPUThread* GetThread(u32 id);
|
||||
RawSPUThread* GetRawSPUThread(u32 num);
|
||||
|
||||
void Exec();
|
||||
void Task();
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#pragma once
|
||||
#include <atomic>
|
||||
|
||||
enum
|
||||
{
|
||||
|
@ -60,237 +59,7 @@ enum
|
|||
MFC_SPU_MAX_QUEUE_SPACE = 0x10,
|
||||
};
|
||||
|
||||
/*struct DMAC_Queue
|
||||
{
|
||||
bool is_valid;
|
||||
u64 ea;
|
||||
u32 lsa;
|
||||
u16 size;
|
||||
u32 op;
|
||||
u8 tag;
|
||||
u8 rt;
|
||||
u16 list_addr;
|
||||
u16 list_size;
|
||||
u32 dep_state;
|
||||
u32 cmd;
|
||||
u32 dep_type;
|
||||
};
|
||||
|
||||
struct DMAC_Proxy
|
||||
{
|
||||
u64 ea;
|
||||
u32 lsa;
|
||||
u16 size;
|
||||
u32 op;
|
||||
u8 tag;
|
||||
u8 rt;
|
||||
u16 list_addr;
|
||||
u16 list_size;
|
||||
u32 dep_state;
|
||||
u32 cmd;
|
||||
u32 dep_type;
|
||||
};
|
||||
|
||||
template<size_t _max_count>
|
||||
class SPUReg
|
||||
{
|
||||
u64 m_addr;
|
||||
u32 m_pos;
|
||||
|
||||
public:
|
||||
static const size_t max_count = _max_count;
|
||||
static const size_t size = max_count * 4;
|
||||
|
||||
SPUReg()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
m_pos = 0;
|
||||
}
|
||||
|
||||
void SetAddr(u64 addr)
|
||||
{
|
||||
m_addr = addr;
|
||||
}
|
||||
|
||||
u64 GetAddr() const
|
||||
{
|
||||
return m_addr;
|
||||
}
|
||||
|
||||
__forceinline bool Pop(u32& res)
|
||||
{
|
||||
if(!m_pos) return false;
|
||||
res = Memory.Read32(m_addr + m_pos--);
|
||||
return true;
|
||||
}
|
||||
|
||||
__forceinline bool Push(u32 value)
|
||||
{
|
||||
if(m_pos >= max_count) return false;
|
||||
Memory.Write32(m_addr + m_pos++, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
u32 GetCount() const
|
||||
{
|
||||
return m_pos;
|
||||
}
|
||||
|
||||
u32 GetFreeCount() const
|
||||
{
|
||||
return max_count - m_pos;
|
||||
}
|
||||
|
||||
void SetValue(u32 value)
|
||||
{
|
||||
Memory.Write32(m_addr, value);
|
||||
}
|
||||
|
||||
u32 GetValue() const
|
||||
{
|
||||
return Memory.Read32(m_addr);
|
||||
}
|
||||
};*/
|
||||
|
||||
struct DMAC
|
||||
{
|
||||
u64 ls_offset;
|
||||
|
||||
/*//DMAC_Queue queue[MFC_SPU_MAX_QUEUE_SPACE]; //not used yet
|
||||
DMAC_Proxy proxy[MFC_PPU_MAX_QUEUE_SPACE+MFC_SPU_MAX_QUEUE_SPACE]; //temporarily 24
|
||||
u32 queue_pos;
|
||||
u32 proxy_pos;
|
||||
long queue_lock;
|
||||
volatile std::atomic<int> proxy_lock;
|
||||
|
||||
bool ProcessCmd(u32 cmd, u32 tag, u32 lsa, u64 ea, u32 size)
|
||||
{
|
||||
//returns true if the command should be deleted from the queue
|
||||
if (cmd & (MFC_BARRIER_MASK | MFC_FENCE_MASK)) _mm_mfence();
|
||||
|
||||
switch(cmd & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK | MFC_LIST_MASK))
|
||||
{
|
||||
case MFC_PUT_CMD:
|
||||
Memory.Copy(ea, ls_offset + lsa, size);
|
||||
return true;
|
||||
|
||||
case MFC_GET_CMD:
|
||||
Memory.Copy(ls_offset + lsa, ea, size);
|
||||
return true;
|
||||
|
||||
default:
|
||||
ConLog.Error("DMAC::ProcessCmd(): Unknown DMA cmd.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
u32 Cmd(u32 cmd, u32 tag, u32 lsa, u64 ea, u32 size)
|
||||
{
|
||||
if(!Memory.IsGoodAddr(ls_offset + lsa, size) || !Memory.IsGoodAddr(ea, size))
|
||||
{
|
||||
return MFC_PPU_DMA_CMD_SEQUENCE_ERROR;
|
||||
}
|
||||
|
||||
if(proxy_pos >= MFC_PPU_MAX_QUEUE_SPACE)
|
||||
{
|
||||
return MFC_PPU_DMA_QUEUE_FULL;
|
||||
}
|
||||
|
||||
ProcessCmd(cmd, tag, lsa, ea, size);
|
||||
|
||||
return MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL;
|
||||
}
|
||||
|
||||
void ClearCmd()
|
||||
{
|
||||
while (std::atomic_exchange(&proxy_lock, 1));
|
||||
_mm_lfence();
|
||||
memcpy(proxy, proxy + 1, --proxy_pos * sizeof(DMAC_Proxy));
|
||||
_mm_sfence();
|
||||
proxy_lock = 0; //release lock
|
||||
}
|
||||
|
||||
void DoCmd()
|
||||
{
|
||||
if(proxy_pos)
|
||||
{
|
||||
const DMAC_Proxy& p = proxy[0];
|
||||
if (ProcessCmd(p.cmd, p.tag, p.lsa, p.ea, p.size))
|
||||
{
|
||||
ClearCmd();
|
||||
}
|
||||
}
|
||||
}*/
|
||||
};
|
||||
|
||||
/*struct MFC
|
||||
{
|
||||
SPUReg<1> MFC_LSA;
|
||||
SPUReg<1> MFC_EAH;
|
||||
SPUReg<1> MFC_EAL;
|
||||
SPUReg<1> MFC_Size_Tag;
|
||||
SPUReg<1> MFC_CMDStatus;
|
||||
SPUReg<1> MFC_QStatus;
|
||||
SPUReg<1> Prxy_QueryType;
|
||||
SPUReg<1> Prxy_QueryMask;
|
||||
SPUReg<1> Prxy_TagStatus;
|
||||
SPUReg<1> SPU_Out_MBox;
|
||||
SPUReg<4> SPU_In_MBox;
|
||||
SPUReg<1> SPU_MBox_Status;
|
||||
SPUReg<1> SPU_RunCntl;
|
||||
SPUReg<1> SPU_Status;
|
||||
SPUReg<1> SPU_NPC;
|
||||
SPUReg<1> SPU_RdSigNotify1;
|
||||
SPUReg<1> SPU_RdSigNotify2;
|
||||
|
||||
DMAC dmac;
|
||||
|
||||
void Handle()
|
||||
{
|
||||
u32 cmd = MFC_CMDStatus.GetValue();
|
||||
|
||||
if(cmd)
|
||||
{
|
||||
u16 op = cmd & MFC_MASK_CMD;
|
||||
|
||||
switch(op)
|
||||
{
|
||||
case MFC_PUT_CMD:
|
||||
case MFC_GET_CMD:
|
||||
{
|
||||
u32 lsa = MFC_LSA.GetValue();
|
||||
u64 ea = (u64)MFC_EAL.GetValue() | ((u64)MFC_EAH.GetValue() << 32);
|
||||
u32 size_tag = MFC_Size_Tag.GetValue();
|
||||
u16 tag = (u16)size_tag;
|
||||
u16 size = size_tag >> 16;
|
||||
|
||||
ConLog.Warning("RawSPU DMA %s:", op == MFC_PUT_CMD ? "PUT" : "GET");
|
||||
ConLog.Warning("*** lsa = 0x%x", lsa);
|
||||
ConLog.Warning("*** ea = 0x%llx", ea);
|
||||
ConLog.Warning("*** tag = 0x%x", tag);
|
||||
ConLog.Warning("*** size = 0x%x", size);
|
||||
ConLog.SkipLn();
|
||||
|
||||
MFC_CMDStatus.SetValue(dmac.Cmd(cmd, tag, lsa, ea, size));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
ConLog.Error("Unknown MFC cmd. (opcode=0x%x, cmd=0x%x)", op, cmd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(Prxy_QueryType.GetValue() == 2)
|
||||
{
|
||||
Prxy_QueryType.SetValue(0);
|
||||
u32 mask = Prxy_QueryMask.GetValue();
|
||||
//
|
||||
MFC_QStatus.SetValue(mask);
|
||||
}
|
||||
}
|
||||
};*/
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#include "stdafx.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "PPCDecoder.h"
|
||||
|
||||
u8 PPCDecoder::DecodeMemory(const u64 address)
|
||||
{
|
||||
u32 instr;
|
||||
Memory.Read32ByAddr(address, &instr);
|
||||
u32 instr = vm::read32(address);
|
||||
Decode(instr);
|
||||
|
||||
return 4;
|
||||
return sizeof(u32);
|
||||
}
|
|
@ -1,8 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "Emu/CPU/CPUDisAsm.h"
|
||||
#include "Gui/DisAsmFrame.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
|
||||
class PPCDisAsm : public CPUDisAsm
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "stdafx.h"
|
||||
#include "PPCThread.h"
|
||||
#include "Gui/InterpreterDisAsm.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
|
||||
PPCThread* GetCurrentPPCThread()
|
||||
{
|
||||
|
@ -37,9 +37,9 @@ void PPCThread::InitStack()
|
|||
/*
|
||||
m_stack_point += m_stack_size - 0x10;
|
||||
m_stack_point &= -0x10;
|
||||
Memory.Write64(m_stack_point, 0);
|
||||
vm::write64(m_stack_point, 0);
|
||||
m_stack_point -= 0x60;
|
||||
Memory.Write64(m_stack_point, m_stack_point + 0x60);
|
||||
vm::write64(m_stack_point, m_stack_point + 0x60);
|
||||
*/
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
#pragma once
|
||||
#include "Emu/Memory/MemoryBlock.h"
|
||||
#include "Emu/CPU/CPUThread.h"
|
||||
#include "Emu/Cell/PPCDecoder.h"
|
||||
|
||||
class PPCThread : public CPUThread
|
||||
{
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "Emu/Cell/PPUOpcodes.h"
|
||||
#include "Emu/Cell/PPCDisAsm.h"
|
||||
#include "Emu/Cell/PPCThread.h"
|
||||
#include "Gui/DisAsmFrame.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
|
||||
class PPUDisAsm
|
||||
: public PPUOpcodes
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,6 @@
|
|||
#include "stdafx.h"
|
||||
#include "stdafx_gui.h"
|
||||
#include "PPUProgramCompiler.h"
|
||||
#include "Utilities/rFile.h"
|
||||
|
||||
using namespace PPU_instr;
|
||||
|
||||
|
@ -80,7 +81,7 @@ SectionInfo::SectionInfo(const std::string& _name)
|
|||
void SectionInfo::SetDataSize(u32 size, u32 align)
|
||||
{
|
||||
if(align) shdr.sh_addralign = align;
|
||||
if(shdr.sh_addralign) size = Memory.AlignAddr(size, shdr.sh_addralign);
|
||||
if(shdr.sh_addralign) size = AlignAddr(size, shdr.sh_addralign);
|
||||
|
||||
if(!code.empty())
|
||||
{
|
||||
|
@ -527,7 +528,7 @@ void CompilePPUProgram::LoadArgs()
|
|||
m_end_args = m_args.size() > 0;
|
||||
}
|
||||
|
||||
u32 CompilePPUProgram::GetBranchValue(const std::string& branch_name)
|
||||
u32 CompilePPUProgram::GetBranchValue(const std::string& branch_name) const
|
||||
{
|
||||
for(const Branch& branch : m_branches)
|
||||
{
|
||||
|
@ -984,7 +985,7 @@ void CompilePPUProgram::Compile()
|
|||
elf_info.e_shnum = 15;
|
||||
elf_info.e_shstrndx = elf_info.e_shnum - 1;
|
||||
elf_info.e_phoff = elf_info.e_ehsize;
|
||||
u32 section_offset = Memory.AlignAddr(elf_info.e_phoff + elf_info.e_phnum * elf_info.e_phentsize, 0x100);
|
||||
u32 section_offset = AlignAddr(elf_info.e_phoff + elf_info.e_phnum * elf_info.e_phentsize, 0x100);
|
||||
|
||||
static const u32 sceStub_text_block = 8 * 4;
|
||||
|
||||
|
@ -1142,7 +1143,7 @@ void CompilePPUProgram::Compile()
|
|||
Elf64_Shdr s_sceStub_text;
|
||||
memset(&s_sceStub_text, 0, sizeof(Elf64_Shdr));
|
||||
s_sceStub_text.sh_addralign = 4;
|
||||
section_offset = Memory.AlignAddr(section_offset, s_sceStub_text.sh_addralign);
|
||||
section_offset = AlignAddr(section_offset, s_sceStub_text.sh_addralign);
|
||||
s_sceStub_text.sh_type = 1;
|
||||
s_sceStub_text.sh_offset = section_offset;
|
||||
s_sceStub_text.sh_addr = section_offset + 0x10000;
|
||||
|
@ -1166,7 +1167,7 @@ void CompilePPUProgram::Compile()
|
|||
Elf64_Shdr s_lib_stub_top;
|
||||
memset(&s_lib_stub_top, 0, sizeof(Elf64_Shdr));
|
||||
s_lib_stub_top.sh_addralign = 4;
|
||||
section_offset = Memory.AlignAddr(section_offset, s_lib_stub_top.sh_addralign);
|
||||
section_offset = AlignAddr(section_offset, s_lib_stub_top.sh_addralign);
|
||||
s_lib_stub_top.sh_type = 1;
|
||||
s_lib_stub_top.sh_name = section_name_offset;
|
||||
s_lib_stub_top.sh_offset = section_offset;
|
||||
|
@ -1206,7 +1207,7 @@ void CompilePPUProgram::Compile()
|
|||
Elf64_Shdr s_rodata_sceFNID;
|
||||
memset(&s_rodata_sceFNID, 0, sizeof(Elf64_Shdr));
|
||||
s_rodata_sceFNID.sh_addralign = 4;
|
||||
section_offset = Memory.AlignAddr(section_offset, s_rodata_sceFNID.sh_addralign);
|
||||
section_offset = AlignAddr(section_offset, s_rodata_sceFNID.sh_addralign);
|
||||
s_rodata_sceFNID.sh_type = 1;
|
||||
s_rodata_sceFNID.sh_name = section_name_offset;
|
||||
s_rodata_sceFNID.sh_offset = section_offset;
|
||||
|
@ -1220,7 +1221,7 @@ void CompilePPUProgram::Compile()
|
|||
Elf64_Shdr s_rodata_sceResident;
|
||||
memset(&s_rodata_sceResident, 0, sizeof(Elf64_Shdr));
|
||||
s_rodata_sceResident.sh_addralign = 4;
|
||||
section_offset = Memory.AlignAddr(section_offset, s_rodata_sceResident.sh_addralign);
|
||||
section_offset = AlignAddr(section_offset, s_rodata_sceResident.sh_addralign);
|
||||
s_rodata_sceResident.sh_type = 1;
|
||||
s_rodata_sceResident.sh_name = section_name_offset;
|
||||
s_rodata_sceResident.sh_offset = section_offset;
|
||||
|
@ -1231,7 +1232,7 @@ void CompilePPUProgram::Compile()
|
|||
{
|
||||
s_rodata_sceResident.sh_size += module.m_name.length() + 1;
|
||||
}
|
||||
s_rodata_sceResident.sh_size = Memory.AlignAddr(s_rodata_sceResident.sh_size, s_rodata_sceResident.sh_addralign);
|
||||
s_rodata_sceResident.sh_size = AlignAddr(s_rodata_sceResident.sh_size, s_rodata_sceResident.sh_addralign);
|
||||
sections_names.push_back(".rodata.sceResident");
|
||||
section_name_offset += std::string(".rodata.sceResident").length() + 1;
|
||||
section_offset += s_rodata_sceResident.sh_size;
|
||||
|
@ -1239,7 +1240,7 @@ void CompilePPUProgram::Compile()
|
|||
Elf64_Shdr s_lib_ent_top;
|
||||
memset(&s_lib_ent_top, 0, sizeof(Elf64_Shdr));
|
||||
s_lib_ent_top.sh_addralign = 4;
|
||||
section_offset = Memory.AlignAddr(section_offset, s_lib_ent_top.sh_addralign);
|
||||
section_offset = AlignAddr(section_offset, s_lib_ent_top.sh_addralign);
|
||||
s_lib_ent_top.sh_size = 4;
|
||||
s_lib_ent_top.sh_flags = 2;
|
||||
s_lib_ent_top.sh_type = 1;
|
||||
|
@ -1266,7 +1267,7 @@ void CompilePPUProgram::Compile()
|
|||
Elf64_Shdr s_sys_proc_prx_param;
|
||||
memset(&s_sys_proc_prx_param, 0, sizeof(Elf64_Shdr));
|
||||
s_sys_proc_prx_param.sh_addralign = 4;
|
||||
section_offset = Memory.AlignAddr(section_offset, s_sys_proc_prx_param.sh_addralign);
|
||||
section_offset = AlignAddr(section_offset, s_sys_proc_prx_param.sh_addralign);
|
||||
s_sys_proc_prx_param.sh_type = 1;
|
||||
s_sys_proc_prx_param.sh_size = sizeof(sys_proc_prx_param);
|
||||
s_sys_proc_prx_param.sh_name = section_name_offset;
|
||||
|
@ -1279,14 +1280,14 @@ void CompilePPUProgram::Compile()
|
|||
|
||||
const u32 prog_load_0_end = section_offset;
|
||||
|
||||
section_offset = Memory.AlignAddr(section_offset + 0x10000, 0x10000);
|
||||
section_offset = AlignAddr(section_offset + 0x10000, 0x10000);
|
||||
const u32 prog_load_1_start = section_offset;
|
||||
|
||||
Elf64_Shdr s_data_sceFStub;
|
||||
memset(&s_data_sceFStub, 0, sizeof(Elf64_Shdr));
|
||||
s_data_sceFStub.sh_name = section_name_offset;
|
||||
s_data_sceFStub.sh_addralign = 4;
|
||||
section_offset = Memory.AlignAddr(section_offset, s_data_sceFStub.sh_addralign);
|
||||
section_offset = AlignAddr(section_offset, s_data_sceFStub.sh_addralign);
|
||||
s_data_sceFStub.sh_flags = 3;
|
||||
s_data_sceFStub.sh_type = 1;
|
||||
s_data_sceFStub.sh_offset = section_offset;
|
||||
|
@ -1299,7 +1300,7 @@ void CompilePPUProgram::Compile()
|
|||
Elf64_Shdr s_tbss;
|
||||
memset(&s_tbss, 0, sizeof(Elf64_Shdr));
|
||||
s_tbss.sh_addralign = 4;
|
||||
section_offset = Memory.AlignAddr(section_offset, s_tbss.sh_addralign);
|
||||
section_offset = AlignAddr(section_offset, s_tbss.sh_addralign);
|
||||
s_tbss.sh_size = 4;
|
||||
s_tbss.sh_flags = 0x403;
|
||||
s_tbss.sh_type = 8;
|
||||
|
@ -1313,7 +1314,7 @@ void CompilePPUProgram::Compile()
|
|||
Elf64_Shdr s_opd;
|
||||
memset(&s_opd, 0, sizeof(Elf64_Shdr));
|
||||
s_opd.sh_addralign = 8;
|
||||
section_offset = Memory.AlignAddr(section_offset, s_opd.sh_addralign);
|
||||
section_offset = AlignAddr(section_offset, s_opd.sh_addralign);
|
||||
s_opd.sh_size = 2*4;
|
||||
s_opd.sh_type = 1;
|
||||
s_opd.sh_offset = section_offset;
|
||||
|
@ -1474,7 +1475,7 @@ void CompilePPUProgram::Compile()
|
|||
|
||||
if(!m_file_path.empty() && !m_analyze && !m_error)
|
||||
{
|
||||
s_opd.sh_size = Memory.AlignAddr(s_opd.sh_size, s_opd.sh_addralign);
|
||||
s_opd.sh_size = AlignAddr(s_opd.sh_size, s_opd.sh_addralign);
|
||||
section_offset += s_opd.sh_size;
|
||||
|
||||
const u32 prog_load_1_end = section_offset;
|
||||
|
@ -1482,7 +1483,7 @@ void CompilePPUProgram::Compile()
|
|||
Elf64_Shdr s_shstrtab;
|
||||
memset(&s_shstrtab, 0, sizeof(Elf64_Shdr));
|
||||
s_shstrtab.sh_addralign = 1;
|
||||
section_offset = Memory.AlignAddr(section_offset, s_shstrtab.sh_addralign);
|
||||
section_offset = AlignAddr(section_offset, s_shstrtab.sh_addralign);
|
||||
s_shstrtab.sh_name = section_name_offset;
|
||||
s_shstrtab.sh_type = 3;
|
||||
s_shstrtab.sh_offset = section_offset;
|
||||
|
@ -1492,7 +1493,7 @@ void CompilePPUProgram::Compile()
|
|||
s_shstrtab.sh_size = section_name_offset;
|
||||
section_offset += s_shstrtab.sh_size;
|
||||
|
||||
wxFile f(fmt::FromUTF8(m_file_path), wxFile::write);
|
||||
rFile f(m_file_path, rFile::write);
|
||||
|
||||
elf_info.e_magic = 0x7F454C46;
|
||||
elf_info.e_class = 2; //ELF64
|
||||
|
@ -1504,7 +1505,7 @@ void CompilePPUProgram::Compile()
|
|||
elf_info.e_machine = MACHINE_PPC64; //PowerPC64
|
||||
elf_info.e_version = 1; //ver 1
|
||||
elf_info.e_flags = 0x0;
|
||||
elf_info.e_shoff = Memory.AlignAddr(section_offset, 4);
|
||||
elf_info.e_shoff = AlignAddr(section_offset, 4);
|
||||
|
||||
u8* opd_data = new u8[s_opd.sh_size];
|
||||
u32 entry_point = s_text.sh_addr;
|
||||
|
@ -1582,7 +1583,7 @@ void CompilePPUProgram::Compile()
|
|||
}
|
||||
|
||||
f.Seek(s_lib_stub_top.sh_offset);
|
||||
f.Seek(s_lib_stub_top.sh_size, wxFromCurrent);
|
||||
f.Seek(s_lib_stub_top.sh_size, rFromCurrent);
|
||||
|
||||
f.Seek(s_lib_stub.sh_offset);
|
||||
for(u32 i=0, nameoffs=4, dataoffs=0; i<modules.size(); ++i)
|
||||
|
@ -1605,7 +1606,7 @@ void CompilePPUProgram::Compile()
|
|||
}
|
||||
|
||||
f.Seek(s_lib_stub_btm.sh_offset);
|
||||
f.Seek(s_lib_stub_btm.sh_size, wxFromCurrent);
|
||||
f.Seek(s_lib_stub_btm.sh_size, rFromCurrent);
|
||||
|
||||
f.Seek(s_data_sceFStub.sh_offset);
|
||||
for(const Module& module : modules)
|
||||
|
@ -1635,13 +1636,13 @@ void CompilePPUProgram::Compile()
|
|||
f.Write(&prx_param, sizeof(sys_proc_prx_param));
|
||||
|
||||
f.Seek(s_lib_ent_top.sh_offset);
|
||||
f.Seek(s_lib_ent_top.sh_size, wxFromCurrent);
|
||||
f.Seek(s_lib_ent_top.sh_size, rFromCurrent);
|
||||
|
||||
f.Seek(s_lib_ent_btm.sh_offset);
|
||||
f.Seek(s_lib_ent_btm.sh_size, wxFromCurrent);
|
||||
f.Seek(s_lib_ent_btm.sh_size, rFromCurrent);
|
||||
|
||||
f.Seek(s_tbss.sh_offset);
|
||||
f.Seek(s_tbss.sh_size, wxFromCurrent);
|
||||
f.Seek(s_tbss.sh_size, rFromCurrent);
|
||||
|
||||
f.Seek(s_shstrtab.sh_offset + 1);
|
||||
for(u32 i=0; i<sections_names.size(); ++i)
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#pragma once
|
||||
#include <vector>
|
||||
#include "PPUInstrTable.h"
|
||||
#include "Loader/ELF64.h"
|
||||
|
||||
|
@ -148,7 +147,7 @@ protected:
|
|||
|
||||
void DetectArgInfo(Arg& arg);
|
||||
void LoadArgs();
|
||||
u32 GetBranchValue(const std::string& branch);
|
||||
u32 GetBranchValue(const std::string& branch) const;
|
||||
|
||||
bool SetNextArgType(u32 types, bool show_err = true);
|
||||
bool SetNextArgBranch(u8 aa, bool show_err = true);
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
#include "stdafx.h"
|
||||
#include "rpcs3/Ini.h"
|
||||
#include "Utilities/Log.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
#include "Emu/SysCalls/Modules.h"
|
||||
#include "Emu/SysCalls/Static.h"
|
||||
#include "Emu/Cell/PPUDecoder.h"
|
||||
#include "Emu/Cell/PPUInterpreter.h"
|
||||
#include "Emu/Cell/PPUDisAsm.h"
|
||||
#include <thread>
|
||||
extern gcmInfo gcm_info;
|
||||
|
||||
PPUThread& GetCurrentPPUThread()
|
||||
{
|
||||
|
@ -50,15 +54,15 @@ void PPUThread::DoReset()
|
|||
void PPUThread::AddArgv(const std::string& arg)
|
||||
{
|
||||
m_stack_point -= arg.length() + 1;
|
||||
m_stack_point = Memory.AlignAddr(m_stack_point, 0x10) - 0x10;
|
||||
m_stack_point = AlignAddr(m_stack_point, 0x10) - 0x10;
|
||||
m_argv_addr.push_back(m_stack_point);
|
||||
Memory.WriteString(m_stack_point, arg);
|
||||
memcpy(vm::get_ptr<char>(m_stack_point), arg.c_str(), arg.size() + 1);
|
||||
}
|
||||
|
||||
void PPUThread::InitRegs()
|
||||
{
|
||||
const u32 pc = Memory.Read32(entry);
|
||||
const u32 rtoc = Memory.Read32(entry + 4);
|
||||
const u32 pc = vm::read32(entry);
|
||||
const u32 rtoc = vm::read32(entry + 4);
|
||||
|
||||
//ConLog.Write("entry = 0x%x", entry);
|
||||
//ConLog.Write("rtoc = 0x%x", rtoc);
|
||||
|
@ -70,7 +74,7 @@ void PPUThread::InitRegs()
|
|||
|
||||
if(thread_num < 0)
|
||||
{
|
||||
ConLog.Error("GetThreadNumById failed.");
|
||||
LOG_ERROR(PPU, "GetThreadNumById failed.");
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
|
@ -81,13 +85,13 @@ void PPUThread::InitRegs()
|
|||
|
||||
if(tls_size >= Emu.GetTLSMemsz())
|
||||
{
|
||||
ConLog.Error("Out of TLS memory.");
|
||||
LOG_ERROR(PPU, "Out of TLS memory.");
|
||||
Emu.Pause();
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
m_stack_point = Memory.AlignAddr(m_stack_point, 0x200) - 0x200;
|
||||
m_stack_point = AlignAddr(m_stack_point, 0x200) - 0x200;
|
||||
|
||||
GPR[1] = m_stack_point;
|
||||
GPR[2] = rtoc;
|
||||
|
@ -104,8 +108,8 @@ void PPUThread::InitRegs()
|
|||
m_stack_point -= 0xc + 4 * argc;
|
||||
u64 argv = m_stack_point;
|
||||
|
||||
mem64_ptr_t argv_list(argv);
|
||||
for(int i=0; i<argc; ++i) argv_list += m_argv_addr[i];
|
||||
auto argv_list = vm::ptr<be_t<u64>>::make((u32)argv);
|
||||
for(int i=0; i<argc; ++i) argv_list[i] = m_argv_addr[i];
|
||||
|
||||
GPR[3] = argc;
|
||||
GPR[4] = argv;
|
||||
|
@ -157,7 +161,7 @@ void PPUThread::DoRun()
|
|||
break;
|
||||
|
||||
default:
|
||||
ConLog.Error("Invalid CPU decoder mode: %d", Ini.CPUDecoderMode.GetValue());
|
||||
LOG_ERROR(PPU, "Invalid CPU decoder mode: %d", Ini.CPUDecoderMode.GetValue());
|
||||
Emu.Pause();
|
||||
}
|
||||
}
|
||||
|
@ -185,7 +189,7 @@ bool FPRdouble::IsINF(PPCdouble d)
|
|||
|
||||
bool FPRdouble::IsNaN(PPCdouble d)
|
||||
{
|
||||
return wxIsNaN(d) ? 1 : 0;
|
||||
return std::isnan((double)d) ? 1 : 0;
|
||||
}
|
||||
|
||||
bool FPRdouble::IsQNaN(PPCdouble d)
|
||||
|
@ -212,3 +216,52 @@ int FPRdouble::Cmp(PPCdouble a, PPCdouble b)
|
|||
|
||||
return CR_SO;
|
||||
}
|
||||
|
||||
u64 PPUThread::GetStackArg(s32 i)
|
||||
{
|
||||
return vm::read64(GPR[1] + 0x70 + 0x8 * (i - 9));
|
||||
}
|
||||
|
||||
u64 PPUThread::FastCall(u64 addr, u64 rtoc, u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, u64 arg6, u64 arg7, u64 arg8)
|
||||
{
|
||||
GPR[3] = arg1;
|
||||
GPR[4] = arg2;
|
||||
GPR[5] = arg3;
|
||||
GPR[6] = arg4;
|
||||
GPR[7] = arg5;
|
||||
GPR[8] = arg6;
|
||||
GPR[9] = arg7;
|
||||
GPR[10] = arg8;
|
||||
|
||||
return FastCall2(addr, rtoc);
|
||||
}
|
||||
|
||||
u64 PPUThread::FastCall2(u64 addr, u64 rtoc)
|
||||
{
|
||||
auto old_status = m_status;
|
||||
auto old_PC = PC;
|
||||
auto old_rtoc = GPR[2];
|
||||
auto old_LR = LR;
|
||||
auto old_thread = GetCurrentNamedThread();
|
||||
|
||||
m_status = Running;
|
||||
PC = addr;
|
||||
GPR[2] = rtoc;
|
||||
LR = Emu.m_ppu_thr_stop;
|
||||
SetCurrentNamedThread(this);
|
||||
|
||||
Task();
|
||||
|
||||
m_status = old_status;
|
||||
PC = old_PC;
|
||||
GPR[2] = old_rtoc;
|
||||
LR = old_LR;
|
||||
SetCurrentNamedThread(old_thread);
|
||||
|
||||
return GPR[3];
|
||||
}
|
||||
|
||||
void PPUThread::FastStop()
|
||||
{
|
||||
m_status = Stopped;
|
||||
}
|
|
@ -1,8 +1,5 @@
|
|||
#pragma once
|
||||
#pragma once
|
||||
#include "Emu/Cell/PPCThread.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
#include "rpcs3.h"
|
||||
#include <cmath>
|
||||
|
||||
enum
|
||||
{
|
||||
|
@ -77,15 +74,15 @@ union FPSCRhdr
|
|||
u32 RN :2; //Floating-point rounding control
|
||||
u32 NI :1; //Floating-point non-IEEE mode
|
||||
u32 XE :1; //Floating-point inexact exception enable
|
||||
u32 ZE :1; //IEEE floating-point zero divide exception enable
|
||||
u32 UE :1; //IEEE floating-point underflow exception enable
|
||||
u32 OE :1; //IEEE floating-point overflow exception enable
|
||||
u32 ZE :1; //IEEE floating-point zero divide exception enable
|
||||
u32 UE :1; //IEEE floating-point underflow exception enable
|
||||
u32 OE :1; //IEEE floating-point overflow exception enable
|
||||
u32 VE :1; //Floating-point invalid operation exception enable
|
||||
u32 VXCVI :1; //Floating-point invalid operation exception for invalid integer convert
|
||||
u32 VXSQRT :1; //Floating-point invalid operation exception for invalid square root
|
||||
u32 VXSOFT :1; //Floating-point invalid operation exception for software request
|
||||
u32 :1; //Reserved
|
||||
u32 FPRF :5; //Floating-point result flags
|
||||
u32 FPRF :5; //Floating-point result flags
|
||||
u32 FI :1; //Floating-point fraction inexact
|
||||
u32 FR :1; //Floating-point fraction rounded
|
||||
u32 VXVC :1; //Floating-point invalid operation exception for invalid compare
|
||||
|
@ -96,8 +93,8 @@ union FPSCRhdr
|
|||
u32 VXSNAN :1; //Floating-point invalid operation exception for SNaN
|
||||
u32 XX :1; //Floating-point inexact exception
|
||||
u32 ZX :1; //Floating-point zero divide exception
|
||||
u32 UX :1; //Floating-point underflow exception
|
||||
u32 OX :1; //Floating-point overflow exception
|
||||
u32 UX :1; //Floating-point underflow exception
|
||||
u32 OX :1; //Floating-point overflow exception
|
||||
u32 VX :1; //Floating-point invalid operation exception summary
|
||||
u32 FEX :1; //Floating-point enabled exception summary
|
||||
u32 FX :1; //Floating-point exception summary
|
||||
|
@ -133,7 +130,7 @@ union MSRhdr
|
|||
//1 Instruction address translation is enabled.
|
||||
u64 IR : 1;
|
||||
|
||||
//Exception prefix. The setting of this bit specifies whether an exception vector offset
|
||||
//Exception prefix. The setting of this bit specifies whether an exception vector offset
|
||||
//is prepended with Fs or 0s. In the following description, nnnnn is the offset of the
|
||||
//exception.
|
||||
//0 Exceptions are vectored to the physical address 0x0000_0000_000n_nnnn in 64-bit implementations.
|
||||
|
@ -170,9 +167,9 @@ union MSRhdr
|
|||
u64 ME : 1;
|
||||
|
||||
//Floating-point available
|
||||
//0 The processor prevents dispatch of floating-point instructions, including
|
||||
//floating-point loads, stores, and moves.
|
||||
//1 The processor can execute floating-point instructions.
|
||||
//0 The processor prevents dispatch of floating-point instructions, including
|
||||
//floating-point loads, stores, and moves.
|
||||
//1 The processor can execute floating-point instructions.
|
||||
u64 FP : 1;
|
||||
|
||||
//Privilege level
|
||||
|
@ -247,10 +244,11 @@ union XERhdr
|
|||
|
||||
struct
|
||||
{
|
||||
u64 L : 61;
|
||||
u64 CA : 1;
|
||||
u64 OV : 1;
|
||||
u64 SO : 1;
|
||||
u32 L : 29;
|
||||
u32 CA : 1;
|
||||
u32 OV : 1;
|
||||
u32 SO : 1;
|
||||
u32 : 32;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -262,7 +260,7 @@ union VSCRhdr
|
|||
{
|
||||
/*
|
||||
Saturation. A sticky status bit indicating that some field in a saturating instruction saturated since the last
|
||||
time SAT was cleared. In other words when SAT = ‘1’ it remains set to ‘1’ until it is cleared to ‘0’ by an
|
||||
time SAT was cleared. In other words when SAT = '1' it remains set to '1' until it is cleared to '0' by an
|
||||
mtvscr instruction.
|
||||
1 The vector saturate instruction implicitly sets when saturation has occurred on the results one of
|
||||
the vector instructions having saturate in its name:
|
||||
|
@ -284,12 +282,12 @@ union VSCRhdr
|
|||
|
||||
/*
|
||||
Non-Java. A mode control bit that determines whether vector floating-point operations will be performed
|
||||
in a Java-IEEE-C9X–compliant mode or a possibly faster non-Java/non-IEEE mode.
|
||||
0 The Java-IEEE-C9X–compliant mode is selected. Denormalized values are handled as specified
|
||||
in a Java-IEEE-C9X-compliant mode or a possibly faster non-Java/non-IEEE mode.
|
||||
0 The Java-IEEE-C9X-compliant mode is selected. Denormalized values are handled as specified
|
||||
by Java, IEEE, and C9X standard.
|
||||
1 The non-Java/non-IEEE–compliant mode is selected. If an element in a source vector register
|
||||
contains a denormalized value, the value ‘0’ is used instead. If an instruction causes an underflow
|
||||
exception, the corresponding element in the target VR is cleared to ‘0’. In both cases, the ‘0’
|
||||
1 The non-Java/non-IEEE-compliant mode is selected. If an element in a source vector register
|
||||
contains a denormalized value, the value '0' is used instead. If an instruction causes an underflow
|
||||
exception, the corresponding element in the target VR is cleared to '0'. In both cases, the '0'
|
||||
has the same sign as the denormalized or underflowing value.
|
||||
*/
|
||||
u32 NJ : 1;
|
||||
|
@ -391,7 +389,7 @@ struct PPCdouble
|
|||
|
||||
u32 To32() const
|
||||
{
|
||||
float res = _double;
|
||||
float res = (float)_double;
|
||||
|
||||
return (u32&)res;
|
||||
}
|
||||
|
@ -470,59 +468,6 @@ struct FPRdouble
|
|||
static int Cmp(PPCdouble a, PPCdouble b);
|
||||
};
|
||||
|
||||
union VPR_reg
|
||||
{
|
||||
//__m128i _m128i;
|
||||
u128 _u128;
|
||||
s128 _s128;
|
||||
u64 _u64[2];
|
||||
s64 _s64[2];
|
||||
u32 _u32[4];
|
||||
s32 _s32[4];
|
||||
u16 _u16[8];
|
||||
s16 _s16[8];
|
||||
u8 _u8[16];
|
||||
s8 _s8[16];
|
||||
float _f[4];
|
||||
double _d[2];
|
||||
|
||||
VPR_reg() { Clear(); }
|
||||
|
||||
std::string ToString(bool hex = false) const
|
||||
{
|
||||
if(hex) return fmt::Format("%08x%08x%08x%08x", _u32[3], _u32[2], _u32[1], _u32[0]);
|
||||
|
||||
return fmt::Format("x: %g y: %g z: %g w: %g", _f[3], _f[2], _f[1], _f[0]);
|
||||
}
|
||||
|
||||
u8 GetBit(u8 bit)
|
||||
{
|
||||
if(bit < 64) return (_u64[0] >> bit) & 0x1;
|
||||
|
||||
return (_u64[1] >> (bit - 64)) & 0x1;
|
||||
}
|
||||
|
||||
void SetBit(u8 bit, u8 value)
|
||||
{
|
||||
if(bit < 64)
|
||||
{
|
||||
_u64[0] &= ~(1 << bit);
|
||||
_u64[0] |= (value & 0x1) << bit;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bit -= 64;
|
||||
|
||||
_u64[1] &= ~(1 << bit);
|
||||
_u64[1] |= (value & 0x1) << bit;
|
||||
}
|
||||
|
||||
void Clear() { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
static const s32 MAX_INT_VALUE = 0x7fffffff;
|
||||
|
||||
class PPUThread : public PPCThread
|
||||
{
|
||||
public:
|
||||
|
@ -532,7 +477,7 @@ public:
|
|||
PPCdouble FPR[32]; //Floating Point Register
|
||||
FPSCRhdr FPSCR; //Floating Point Status and Control Register
|
||||
u64 GPR[32]; //General-Purpose Register
|
||||
VPR_reg VPR[32];
|
||||
u128 VPR[32];
|
||||
u32 vpcr;
|
||||
|
||||
CRhdr CR; //Condition Register
|
||||
|
@ -608,6 +553,9 @@ public:
|
|||
|
||||
u64 cycle;
|
||||
|
||||
u64 R_ADDR; // reservation address
|
||||
u64 R_VALUE; // reservation value (BE)
|
||||
|
||||
public:
|
||||
PPUThread();
|
||||
virtual ~PPUThread();
|
||||
|
@ -685,7 +633,7 @@ public:
|
|||
}
|
||||
else
|
||||
{
|
||||
UpdateCRn<u32>(n, a, b);
|
||||
UpdateCRn<u32>(n, (u32)a, (u32)b);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -693,11 +641,11 @@ public:
|
|||
{
|
||||
if(l)
|
||||
{
|
||||
UpdateCRn<s64>(n, a, b);
|
||||
UpdateCRn<s64>(n, (s64)a, (s64)b);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateCRn<s32>(n, a, b);
|
||||
UpdateCRn<s32>(n, (s32)a, (s32)b);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -721,7 +669,8 @@ public:
|
|||
|
||||
const u8 IsCR(const u32 bit) const { return (GetCR(bit >> 2) & GetCRBit(bit)) ? 1 : 0; }
|
||||
|
||||
bool IsCarry(const u64 a, const u64 b) { return a > (a + b); }
|
||||
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 SetFPSCRException(const FPSCR_EXP mask)
|
||||
{
|
||||
|
@ -741,7 +690,7 @@ public:
|
|||
|
||||
for(uint i=0; i<32; ++i) ret += fmt::Format("GPR[%d] = 0x%llx\n", i, GPR[i]);
|
||||
for(uint i=0; i<32; ++i) ret += fmt::Format("FPR[%d] = %.6G\n", i, (double)FPR[i]);
|
||||
for(uint i=0; i<32; ++i) ret += fmt::Format("VPR[%d] = 0x%s [%s]\n", i, (const char*)VPR[i].ToString(true).c_str(), (const char*)VPR[i].ToString().c_str());
|
||||
for(uint i=0; i<32; ++i) ret += fmt::Format("VPR[%d] = 0x%s [%s]\n", i, VPR[i].to_hex().c_str(), VPR[i].to_xyzw().c_str());
|
||||
ret += fmt::Format("CR = 0x%08x\n", CR.CR);
|
||||
ret += fmt::Format("LR = 0x%llx\n", LR);
|
||||
ret += fmt::Format("CTR = 0x%llx\n", CTR);
|
||||
|
@ -820,7 +769,7 @@ public:
|
|||
}
|
||||
if (reg == "CR" || reg == "FPSCR")
|
||||
{
|
||||
unsigned long reg_value;
|
||||
unsigned long long reg_value;
|
||||
reg_value = std::stoull(value.substr(24, 31), 0, 16);
|
||||
if (reg == "CR") CR.CR = (u32)reg_value;
|
||||
if (reg == "FPSCR") FPSCR.FPSCR = (u32)reg_value;
|
||||
|
@ -839,6 +788,10 @@ public:
|
|||
public:
|
||||
virtual void InitRegs();
|
||||
virtual u64 GetFreeStackSize() const;
|
||||
u64 GetStackArg(s32 i);
|
||||
u64 FastCall(u64 addr, u64 rtoc, u64 arg1 = 0, u64 arg2 = 0, u64 arg3 = 0, u64 arg4 = 0, u64 arg5 = 0, u64 arg6 = 0, u64 arg7 = 0, u64 arg8 = 0);
|
||||
u64 FastCall2(u64 addr, u64 rtoc);
|
||||
void FastStop();
|
||||
|
||||
protected:
|
||||
virtual void DoReset() override;
|
||||
|
@ -859,3 +812,5 @@ protected:
|
|||
};
|
||||
|
||||
PPUThread& GetCurrentPPUThread();
|
||||
|
||||
#define declCPU PPUThread& CPU = GetCurrentPPUThread
|
||||
|
|
|
@ -1,243 +1,193 @@
|
|||
#include "stdafx.h"
|
||||
#include "Utilities/Log.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
|
||||
#include "Emu/Cell/RawSPUThread.h"
|
||||
|
||||
RawSPUThread::RawSPUThread(u32 index, CPUThreadType type)
|
||||
RawSPUThread::RawSPUThread(CPUThreadType type)
|
||||
: SPUThread(type)
|
||||
, MemoryBlock()
|
||||
, m_index(index)
|
||||
{
|
||||
Memory.MemoryBlocks.push_back(SetRange(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index, RAW_SPU_OFFSET));
|
||||
m_index = Memory.InitRawSPU(this);
|
||||
Reset();
|
||||
}
|
||||
|
||||
RawSPUThread::~RawSPUThread()
|
||||
{
|
||||
for(int i=0; i<Memory.MemoryBlocks.size(); ++i)
|
||||
{
|
||||
if(Memory.MemoryBlocks[i]->GetStartAddr() == GetStartAddr())
|
||||
{
|
||||
Memory.MemoryBlocks.erase(Memory.MemoryBlocks.begin() + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Close();
|
||||
}
|
||||
|
||||
bool RawSPUThread::Read8(const u64 addr, u8* value)
|
||||
{
|
||||
if(addr < GetStartAddr() + RAW_SPU_PROB_OFFSET)
|
||||
{
|
||||
return MemoryBlock::Read8(addr, value);
|
||||
}
|
||||
|
||||
u32 offset = addr - GetStartAddr() - RAW_SPU_PROB_OFFSET;
|
||||
ConLog.Error("RawSPUThread[%d]: Read8(0x%x)", m_index, offset);
|
||||
Emu.Pause();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RawSPUThread::Read16(const u64 addr, u16* value)
|
||||
{
|
||||
if(addr < GetStartAddr() + RAW_SPU_PROB_OFFSET)
|
||||
{
|
||||
return MemoryBlock::Read16(addr, value);
|
||||
}
|
||||
|
||||
u32 offset = addr - GetStartAddr() - RAW_SPU_PROB_OFFSET;
|
||||
ConLog.Error("RawSPUThread[%d]: Read16(0x%x)", m_index, offset);
|
||||
Emu.Pause();
|
||||
return false;
|
||||
Memory.CloseRawSPU(this, m_index);
|
||||
}
|
||||
|
||||
bool RawSPUThread::Read32(const u64 addr, u32* value)
|
||||
{
|
||||
if(addr < GetStartAddr() + RAW_SPU_PROB_OFFSET)
|
||||
const u64 offset = addr - GetStartAddr() - RAW_SPU_PROB_OFFSET;
|
||||
|
||||
switch (offset)
|
||||
{
|
||||
return MemoryBlock::Read32(addr, value);
|
||||
case MFC_CMDStatus_offs:
|
||||
{
|
||||
*value = MFC2.CMDStatus.GetValue();
|
||||
break;
|
||||
}
|
||||
|
||||
u32 offset = addr - GetStartAddr() - RAW_SPU_PROB_OFFSET;
|
||||
switch(offset)
|
||||
{
|
||||
case MFC_LSA_offs: ConLog.Warning("RawSPUThread[%d]: Read32(MFC_LSA)", m_index); *value = MFC2.LSA.GetValue(); break;
|
||||
case MFC_EAH_offs: ConLog.Warning("RawSPUThread[%d]: Read32(MFC_EAH)", m_index); *value = MFC2.EAH.GetValue(); break;
|
||||
case MFC_EAL_offs: ConLog.Warning("RawSPUThread[%d]: Read32(MFC_EAL)", m_index); *value = MFC2.EAL.GetValue(); break;
|
||||
case MFC_Size_Tag_offs: ConLog.Warning("RawSPUThread[%d]: Read32(MFC_Size_Tag)", m_index); *value = MFC2.Size_Tag.GetValue(); break;
|
||||
case MFC_CMDStatus_offs: ConLog.Warning("RawSPUThread[%d]: Read32(MFC_CMDStatus)", m_index); *value = MFC2.CMDStatus.GetValue(); break;
|
||||
case MFC_QStatus_offs:
|
||||
ConLog.Warning("RawSPUThread[%d]: Read32(MFC_QStatus)", m_index);
|
||||
*value = MFC2.QStatus.GetValue();
|
||||
break;
|
||||
case Prxy_QueryType_offs: ConLog.Warning("RawSPUThread[%d]: Read32(Prxy_QueryType)", m_index); *value = Prxy.QueryType.GetValue(); break;
|
||||
case Prxy_QueryMask_offs: ConLog.Warning("RawSPUThread[%d]: Read32(Prxy_QueryMask)", m_index); *value = Prxy.QueryMask.GetValue(); break;
|
||||
case Prxy_TagStatus_offs: ConLog.Warning("RawSPUThread[%d]: Read32(Prxy_TagStatus)", m_index); *value = Prxy.TagStatus.GetValue(); break;
|
||||
case SPU_Out_MBox_offs:
|
||||
ConLog.Warning("RawSPUThread[%d]: Read32(SPU_Out_MBox)", m_index);
|
||||
SPU.Out_MBox.PopUncond(*value); //if Out_MBox is empty yet, the result will be undefined
|
||||
break;
|
||||
case SPU_In_MBox_offs: ConLog.Warning("RawSPUThread[%d]: Read32(SPU_In_MBox)", m_index); while(!SPU.In_MBox.Pop(*value) && !Emu.IsStopped()) Sleep(1); break;
|
||||
case SPU_MBox_Status_offs: //ConLog.Warning("RawSPUThread[%d]: Read32(SPU_MBox_Status)", m_index);
|
||||
//SPU.MBox_Status.SetValue(SPU.Out_MBox.GetCount() ? SPU.MBox_Status.GetValue() | 1 : SPU.MBox_Status.GetValue() & ~1);
|
||||
SPU.MBox_Status.SetValue((SPU.Out_MBox.GetCount() & 0xff) | (SPU.In_MBox.GetFreeCount() << 8));
|
||||
*value = SPU.MBox_Status.GetValue();
|
||||
{
|
||||
// TagStatus is not used: mask is written directly
|
||||
*value = MFC2.QueryMask.GetValue();
|
||||
break;
|
||||
case SPU_RunCntl_offs: ConLog.Warning("RawSPUThread[%d]: Read32(SPU_RunCntl)", m_index); *value = SPU.RunCntl.GetValue(); break;
|
||||
case SPU_Status_offs: ConLog.Warning("RawSPUThread[%d]: Read32(SPU_Status)", m_index); *value = SPU.Status.GetValue(); break;
|
||||
case SPU_NPC_offs: ConLog.Warning("RawSPUThread[%d]: Read32(SPU_NPC)", m_index); *value = SPU.NPC.GetValue(); break;
|
||||
case SPU_RdSigNotify1_offs: ConLog.Warning("RawSPUThread[%d]: Read32(SPU_RdSigNotify1)", m_index); *value = SPU.SNR[0].GetValue(); break;
|
||||
case SPU_RdSigNotify2_offs: ConLog.Warning("RawSPUThread[%d]: Read32(SPU_RdSigNotify2)", m_index); *value = SPU.SNR[1].GetValue(); break;
|
||||
}
|
||||
|
||||
case SPU_Out_MBox_offs:
|
||||
{
|
||||
// if Out_MBox is empty, the result is undefined
|
||||
SPU.Out_MBox.PopUncond(*value);
|
||||
break;
|
||||
}
|
||||
|
||||
case SPU_MBox_Status_offs:
|
||||
{
|
||||
*value = (SPU.Out_MBox.GetCount() & 0xff) | (SPU.In_MBox.GetFreeCount() << 8);
|
||||
break;
|
||||
}
|
||||
|
||||
case SPU_Status_offs:
|
||||
{
|
||||
*value = SPU.Status.GetValue();
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ConLog.Error("RawSPUThread[%d]: Read32(0x%x)", m_index, offset);
|
||||
Emu.Pause();
|
||||
break;
|
||||
{
|
||||
// TODO: read value from LS if necessary (not important)
|
||||
LOG_ERROR(Log::SPU, "RawSPUThread[%d]: Read32(0x%llx)", m_index, offset);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RawSPUThread::Read64(const u64 addr, u64* value)
|
||||
{
|
||||
if(addr < GetStartAddr() + RAW_SPU_PROB_OFFSET)
|
||||
{
|
||||
return MemoryBlock::Read64(addr, value);
|
||||
}
|
||||
|
||||
u32 offset = addr - GetStartAddr() - RAW_SPU_PROB_OFFSET;
|
||||
ConLog.Error("RawSPUThread[%d]: Read64(0x%x)", m_index, offset);
|
||||
Emu.Pause();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RawSPUThread::Read128(const u64 addr, u128* value)
|
||||
{
|
||||
if(addr < GetStartAddr() + RAW_SPU_PROB_OFFSET)
|
||||
{
|
||||
return MemoryBlock::Read128(addr, value);
|
||||
}
|
||||
|
||||
u32 offset = addr - GetStartAddr() - RAW_SPU_PROB_OFFSET;
|
||||
ConLog.Error("RawSPUThread[%d]: Read128(0x%x)", m_index, offset);
|
||||
Emu.Pause();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RawSPUThread::Write8(const u64 addr, const u8 value)
|
||||
{
|
||||
if(addr < GetStartAddr() + RAW_SPU_PROB_OFFSET)
|
||||
{
|
||||
return MemoryBlock::Write8(addr, value);
|
||||
}
|
||||
|
||||
u32 offset = addr - GetStartAddr() - RAW_SPU_PROB_OFFSET;
|
||||
ConLog.Error("RawSPUThread[%d]: Write8(0x%x, 0x%x)", m_index, offset, value);
|
||||
Emu.Pause();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RawSPUThread::Write16(const u64 addr, const u16 value)
|
||||
{
|
||||
if(addr < GetStartAddr() + RAW_SPU_PROB_OFFSET)
|
||||
{
|
||||
return MemoryBlock::Write16(addr, value);
|
||||
}
|
||||
|
||||
u32 offset = addr - GetStartAddr() - RAW_SPU_PROB_OFFSET;
|
||||
ConLog.Error("RawSPUThread[%d]: Write16(0x%x, 0x%x)", m_index, offset, value);
|
||||
Emu.Pause();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RawSPUThread::Write32(const u64 addr, const u32 value)
|
||||
{
|
||||
if(addr < GetStartAddr() + RAW_SPU_PROB_OFFSET)
|
||||
const u64 offset = addr - GetStartAddr() - RAW_SPU_PROB_OFFSET;
|
||||
|
||||
switch (offset)
|
||||
{
|
||||
return MemoryBlock::Write32(addr, value);
|
||||
case MFC_LSA_offs:
|
||||
{
|
||||
MFC2.LSA.SetValue(value);
|
||||
break;
|
||||
}
|
||||
|
||||
u32 offset = addr - GetStartAddr() - RAW_SPU_PROB_OFFSET;
|
||||
|
||||
switch(offset)
|
||||
case MFC_EAH_offs:
|
||||
{
|
||||
case MFC_LSA_offs: MFC2.LSA.SetValue(value); break;
|
||||
case MFC_EAH_offs: MFC2.EAH.SetValue(value); break;
|
||||
case MFC_EAL_offs: MFC2.EAL.SetValue(value); break;
|
||||
case MFC_Size_Tag_offs: MFC2.Size_Tag.SetValue(value); break;
|
||||
MFC2.EAH.SetValue(value);
|
||||
break;
|
||||
}
|
||||
|
||||
case MFC_EAL_offs:
|
||||
{
|
||||
MFC2.EAL.SetValue(value);
|
||||
break;
|
||||
}
|
||||
|
||||
case MFC_Size_Tag_offs:
|
||||
{
|
||||
MFC2.Size_Tag.SetValue(value);
|
||||
break;
|
||||
}
|
||||
|
||||
case MFC_CMDStatus_offs:
|
||||
{
|
||||
MFC2.CMDStatus.SetValue(value);
|
||||
EnqMfcCmd(MFC2);
|
||||
break;
|
||||
case MFC_QStatus_offs: ConLog.Warning("RawSPUThread[%d]: Write32(MFC_QStatus, 0x%x)", m_index, value); MFC2.QStatus.SetValue(value); break;
|
||||
break;
|
||||
}
|
||||
|
||||
case Prxy_QueryType_offs:
|
||||
{
|
||||
ConLog.Warning("RawSPUThread[%d]: Write32(Prxy_QueryType, 0x%x)", m_index, value);
|
||||
Prxy.QueryType.SetValue(value);
|
||||
|
||||
switch(value)
|
||||
{
|
||||
case 2:
|
||||
ConLog.Warning("RawSPUThread[%d]: Prxy Query Immediate.", m_index);
|
||||
break;
|
||||
case 2: break;
|
||||
|
||||
default:
|
||||
ConLog.Error("RawSPUThread[%d]: Unknown Prxy Query Type. (prxy_query=0x%x)", m_index, value);
|
||||
break;
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "RawSPUThread[%d]: Unknown Prxy Query Type. (prxy_query=0x%x)", m_index, value);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Prxy.QueryType.SetValue(0);
|
||||
MFC2.QStatus.SetValue(Prxy.QueryMask.GetValue());
|
||||
MFC2.QueryType.SetValue(value); // not used
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Prxy_QueryMask_offs: ConLog.Warning("RawSPUThread[%d]: Write32(Prxy_QueryMask, 0x%x)", m_index, value); Prxy.QueryMask.SetValue(value); break;
|
||||
case Prxy_TagStatus_offs: ConLog.Warning("RawSPUThread[%d]: Write32(Prxy_TagStatus, 0x%x)", m_index, value); Prxy.TagStatus.SetValue(value); break;
|
||||
case SPU_Out_MBox_offs: ConLog.Warning("RawSPUThread[%d]: Write32(SPU_Out_MBox, 0x%x)", m_index, value); while(!SPU.Out_MBox.Push(value) && !Emu.IsStopped()) Sleep(1); break;
|
||||
|
||||
case Prxy_QueryMask_offs:
|
||||
{
|
||||
MFC2.QueryMask.SetValue(value); // TagStatus is not used
|
||||
break;
|
||||
}
|
||||
|
||||
case SPU_In_MBox_offs:
|
||||
ConLog.Warning("RawSPUThread[%d]: Write32(SPU_In_MBox, 0x%x)", m_index, value);
|
||||
SPU.In_MBox.PushUncond(value); //if In_MBox is already full, the last message will be overwritten
|
||||
break;
|
||||
case SPU_MBox_Status_offs: ConLog.Warning("RawSPUThread[%d]: Write32(SPU_MBox_Status, 0x%x)", m_index, value); SPU.MBox_Status.SetValue(value); break;
|
||||
case SPU_RunCntl_offs: ConLog.Warning("RawSPUThread[%d]: Write32(SPU_RunCntl, 0x%x)", m_index, value); SPU.RunCntl.SetValue(value); break;
|
||||
case SPU_Status_offs: ConLog.Warning("RawSPUThread[%d]: Write32(SPU_Status, 0x%x)", m_index, value); SPU.Status.SetValue(value); break;
|
||||
case SPU_NPC_offs: ConLog.Warning("RawSPUThread[%d]: Write32(SPU_NPC, 0x%x)", m_index, value); SPU.NPC.SetValue(value); break;
|
||||
case SPU_RdSigNotify1_offs: ConLog.Warning("RawSPUThread[%d]: Write32(SPU_RdSigNotify1, 0x%x)", m_index, value); SPU.SNR[0].SetValue(value); break;
|
||||
case SPU_RdSigNotify2_offs: ConLog.Warning("RawSPUThread[%d]: Write32(SPU_RdSigNotify2, 0x%x)", m_index, value); SPU.SNR[1].SetValue(value); break;
|
||||
{
|
||||
// if In_MBox is already full, the last message is overwritten
|
||||
SPU.In_MBox.PushUncond(value);
|
||||
break;
|
||||
}
|
||||
|
||||
case SPU_RunCntl_offs:
|
||||
{
|
||||
if (value == SPU_RUNCNTL_RUNNABLE)
|
||||
{
|
||||
SPU.Status.SetValue(SPU_STATUS_RUNNING);
|
||||
Exec();
|
||||
}
|
||||
else if (value == SPU_RUNCNTL_STOP)
|
||||
{
|
||||
SPU.Status.SetValue(SPU_STATUS_STOPPED);
|
||||
Stop();
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "RawSPUThread[%d]: Write32(SPU_RunCtrl, 0x%x): unknown value", m_index, value);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SPU_NPC_offs:
|
||||
{
|
||||
if (value & 3)
|
||||
{
|
||||
// least significant bit contains some interrupt flag
|
||||
LOG_ERROR(Log::SPU, "RawSPUThread[%d]: Write32(SPU_NPC_offs, 0x%x): lowest bits set", m_index, value);
|
||||
return false;
|
||||
}
|
||||
SPU.NPC.SetValue(value);
|
||||
break;
|
||||
}
|
||||
|
||||
case SPU_RdSigNotify1_offs:
|
||||
{
|
||||
WriteSNR(0, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case SPU_RdSigNotify2_offs:
|
||||
{
|
||||
WriteSNR(1, value);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ConLog.Error("RawSPUThread[%d]: Write32(0x%x, 0x%x)", m_index, offset, value);
|
||||
Emu.Pause();
|
||||
break;
|
||||
{
|
||||
// TODO: write value to LS if necessary (not important)
|
||||
LOG_ERROR(Log::SPU, "RawSPUThread[%d]: Write32(0x%llx, 0x%x)", m_index, offset, value);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RawSPUThread::Write64(const u64 addr, const u64 value)
|
||||
{
|
||||
if(addr < GetStartAddr() + RAW_SPU_PROB_OFFSET)
|
||||
{
|
||||
return MemoryBlock::Write64(addr, value);
|
||||
}
|
||||
|
||||
u32 offset = addr - GetStartAddr() - RAW_SPU_PROB_OFFSET;
|
||||
ConLog.Error("RawSPUThread[%d]: Write64(0x%x, 0x%llx)", m_index, offset, value);
|
||||
Emu.Pause();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RawSPUThread::Write128(const u64 addr, const u128 value)
|
||||
{
|
||||
if(addr < GetStartAddr() + RAW_SPU_PROB_OFFSET)
|
||||
{
|
||||
return MemoryBlock::Write128(addr, value);
|
||||
}
|
||||
|
||||
u32 offset = addr - GetStartAddr() - RAW_SPU_PROB_OFFSET;
|
||||
ConLog.Error("RawSPUThread[%d]: Write128(0x%x, 0x%llx_%llx)", m_index, offset, value._u64[1], value._u64[0]);
|
||||
Emu.Pause();
|
||||
return false;
|
||||
}
|
||||
|
||||
void RawSPUThread::InitRegs()
|
||||
{
|
||||
dmac.ls_offset = m_offset = GetStartAddr() + RAW_SPU_LS_OFFSET;
|
||||
|
@ -251,88 +201,9 @@ u32 RawSPUThread::GetIndex() const
|
|||
|
||||
void RawSPUThread::Task()
|
||||
{
|
||||
if (Ini.LogAllSysCalls.GetValue()) ConLog.Write("%s enter", PPCThread::GetFName().c_str());
|
||||
PC = SPU.NPC.GetValue();
|
||||
|
||||
const std::vector<u64>& bp = Emu.GetBreakPoints();
|
||||
SPUThread::Task();
|
||||
|
||||
try
|
||||
{
|
||||
for(uint i=0; i<bp.size(); ++i)
|
||||
{
|
||||
if(bp[i] == m_offset + PC)
|
||||
{
|
||||
Emu.Pause();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_last_paused = true;
|
||||
|
||||
while(true)
|
||||
{
|
||||
int status = ThreadStatus();
|
||||
|
||||
if(status == CPUThread_Stopped || status == CPUThread_Break)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if(status == CPUThread_Sleeping)
|
||||
{
|
||||
Sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
//dmac.DoCmd();
|
||||
|
||||
if(SPU.RunCntl.GetValue() != SPU_RUNCNTL_RUNNABLE)
|
||||
{
|
||||
if(!is_last_paused)
|
||||
{
|
||||
is_last_paused = true;
|
||||
SPU.NPC.SetValue(PC);
|
||||
SPU.Status.SetValue(SPU_STATUS_WAITING_FOR_CHANNEL);
|
||||
}
|
||||
|
||||
Sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if(is_last_paused)
|
||||
{
|
||||
is_last_paused = false;
|
||||
PC = SPU.NPC.GetValue();
|
||||
SPU.Status.SetValue(SPU_STATUS_RUNNING);
|
||||
ConLog.Warning("Starting RawSPU...");
|
||||
}
|
||||
|
||||
Step();
|
||||
NextPc(m_dec->DecodeMemory(PC + m_offset));
|
||||
|
||||
if(status == CPUThread_Step)
|
||||
{
|
||||
m_is_step = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
for(uint i=0; i<bp.size(); ++i)
|
||||
{
|
||||
if(bp[i] == PC)
|
||||
{
|
||||
Emu.Pause();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(const std::string& e)
|
||||
{
|
||||
ConLog.Error("Exception: %s", e.c_str());
|
||||
}
|
||||
catch(const char* e)
|
||||
{
|
||||
ConLog.Error("Exception: %s", e);
|
||||
}
|
||||
|
||||
if (Ini.LogAllSysCalls.GetValue()) ConLog.Write("%s leave", PPCThread::GetFName().c_str());
|
||||
SPU.NPC.SetValue((u32)PC);
|
||||
}
|
||||
|
|
|
@ -1,47 +1,11 @@
|
|||
#pragma once
|
||||
#include "SPUThread.h"
|
||||
#include "Emu/event.h"
|
||||
|
||||
enum
|
||||
{
|
||||
MFC_LSA_offs = 0x3004,
|
||||
MFC_EAH_offs = 0x3008,
|
||||
MFC_EAL_offs = 0x300C,
|
||||
MFC_Size_Tag_offs = 0x3010,
|
||||
MFC_Class_CMD_offs = 0x3014,
|
||||
MFC_CMDStatus_offs = 0x3014,
|
||||
MFC_QStatus_offs = 0x3104,
|
||||
Prxy_QueryType_offs = 0x3204,
|
||||
Prxy_QueryMask_offs = 0x321C,
|
||||
Prxy_TagStatus_offs = 0x322C,
|
||||
SPU_Out_MBox_offs = 0x4004,
|
||||
SPU_In_MBox_offs = 0x400C,
|
||||
SPU_MBox_Status_offs = 0x4014,
|
||||
SPU_RunCntl_offs = 0x401C,
|
||||
SPU_Status_offs = 0x4024,
|
||||
SPU_NPC_offs = 0x4034,
|
||||
SPU_RdSigNotify1_offs = 0x1400C,
|
||||
SPU_RdSigNotify2_offs = 0x1C00C,
|
||||
};
|
||||
|
||||
enum : u64
|
||||
{
|
||||
RAW_SPU_OFFSET = 0x0000000000100000,
|
||||
RAW_SPU_BASE_ADDR = 0x00000000E0000000,
|
||||
RAW_SPU_LS_OFFSET = 0x0000000000000000,
|
||||
RAW_SPU_PROB_OFFSET = 0x0000000000040000,
|
||||
};
|
||||
|
||||
__forceinline static u32 GetRawSPURegAddrByNum(int num, int offset)
|
||||
{
|
||||
return RAW_SPU_OFFSET * num + RAW_SPU_BASE_ADDR + RAW_SPU_PROB_OFFSET + offset;
|
||||
}
|
||||
|
||||
__forceinline static u32 GetRawSPURegAddrById(int id, int offset)
|
||||
{
|
||||
return GetRawSPURegAddrByNum(Emu.GetCPU().GetThreadNumById(CPU_THREAD_RAW_SPU, id), offset);
|
||||
}
|
||||
|
||||
class RawSPUThread
|
||||
: public SPUThread
|
||||
, public MemoryBlock
|
||||
|
@ -49,20 +13,12 @@ class RawSPUThread
|
|||
u32 m_index;
|
||||
|
||||
public:
|
||||
RawSPUThread(u32 index, CPUThreadType type = CPU_THREAD_RAW_SPU);
|
||||
RawSPUThread(CPUThreadType type = CPU_THREAD_RAW_SPU);
|
||||
virtual ~RawSPUThread();
|
||||
|
||||
virtual bool Read8(const u64 addr, u8* value) override;
|
||||
virtual bool Read16(const u64 addr, u16* value) override;
|
||||
virtual bool Read32(const u64 addr, u32* value) override;
|
||||
virtual bool Read64(const u64 addr, u64* value) override;
|
||||
virtual bool Read128(const u64 addr, u128* value) override;
|
||||
bool Read32(const u64 addr, u32* value);
|
||||
|
||||
virtual bool Write8(const u64 addr, const u8 value) override;
|
||||
virtual bool Write16(const u64 addr, const u16 value) override;
|
||||
virtual bool Write32(const u64 addr, const u32 value) override;
|
||||
virtual bool Write64(const u64 addr, const u64 value) override;
|
||||
virtual bool Write128(const u64 addr, const u128 value) override;
|
||||
bool Write32(const u64 addr, const u32 value);
|
||||
|
||||
public:
|
||||
virtual void InitRegs();
|
||||
|
|
|
@ -2,9 +2,69 @@
|
|||
|
||||
#include "Emu/Cell/SPUOpcodes.h"
|
||||
#include "Emu/Cell/PPCDisAsm.h"
|
||||
#include "Emu/Cell/SPUThread.h"
|
||||
#include "Gui/DisAsmFrame.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
|
||||
static const char* spu_reg_name[128] =
|
||||
{
|
||||
"$LR", "$SP", "$2", "$3", "$4", "$5", "$6", "$7",
|
||||
"$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
|
||||
"$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
|
||||
"$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31",
|
||||
"$32", "$33", "$34", "$35", "$36", "$37", "$38", "$39",
|
||||
"$40", "$41", "$42", "$43", "$44", "$45", "$46", "$47",
|
||||
"$48", "$49", "$50", "$51", "$52", "$53", "$54", "$55",
|
||||
"$56", "$57", "$58", "$59", "$60", "$61", "$62", "$63",
|
||||
"$64", "$65", "$66", "$67", "$68", "$69", "$70", "$71",
|
||||
"$72", "$73", "$74", "$75", "$76", "$77", "$78", "$79",
|
||||
"$80", "$81", "$82", "$83", "$84", "$85", "$86", "$87",
|
||||
"$88", "$89", "$90", "$91", "$92", "$93", "$94", "$95",
|
||||
"$96", "$97", "$98", "$99", "$100", "$101", "$102", "$103",
|
||||
"$104", "$105", "$106", "$107", "$108", "$109", "$110", "$111",
|
||||
"$112", "$113", "$114", "$115", "$116", "$117", "$118", "$119",
|
||||
"$120", "$121", "$122", "$123", "$124", "$125", "$126", "$127",
|
||||
};
|
||||
|
||||
static const char* spu_spreg_name[128] =
|
||||
{
|
||||
"$sp0", "$sp1", "$sp2", "$sp3", "$sp4", "$sp5", "$sp6", "$sp7",
|
||||
"$sp8", "$sp9", "$sp10", "$sp11", "$sp12", "$sp13", "$sp14", "$sp15",
|
||||
"$sp16", "$sp17", "$sp18", "$sp19", "$sp20", "$sp21", "$sp22", "$sp23",
|
||||
"$sp24", "$sp25", "$sp26", "$sp27", "$sp28", "$sp29", "$sp30", "$sp31",
|
||||
"$sp32", "$sp33", "$sp34", "$sp35", "$sp36", "$sp37", "$sp38", "$sp39",
|
||||
"$sp40", "$sp41", "$sp42", "$sp43", "$sp44", "$sp45", "$sp46", "$sp47",
|
||||
"$sp48", "$sp49", "$sp50", "$sp51", "$sp52", "$sp53", "$sp54", "$sp55",
|
||||
"$sp56", "$sp57", "$sp58", "$sp59", "$sp60", "$sp61", "$sp62", "$sp63",
|
||||
"$sp64", "$sp65", "$sp66", "$sp67", "$sp68", "$sp69", "$sp70", "$sp71",
|
||||
"$sp72", "$sp73", "$sp74", "$sp75", "$sp76", "$sp77", "$sp78", "$sp79",
|
||||
"$sp80", "$sp81", "$sp82", "$sp83", "$sp84", "$sp85", "$sp86", "$sp87",
|
||||
"$sp88", "$sp89", "$sp90", "$sp91", "$sp92", "$sp93", "$sp94", "$sp95",
|
||||
"$sp96", "$sp97", "$sp98", "$sp99", "$sp100", "$sp101", "$sp102", "$sp103",
|
||||
"$sp104", "$sp105", "$sp106", "$sp107", "$sp108", "$sp109", "$sp110", "$sp111",
|
||||
"$sp112", "$sp113", "$sp114", "$sp115", "$sp116", "$sp117", "$sp118", "$sp119",
|
||||
"$sp120", "$sp121", "$sp122", "$sp123", "$sp124", "$sp125", "$sp126", "$sp127",
|
||||
};
|
||||
|
||||
static const char* spu_ch_name[128] =
|
||||
{
|
||||
"$SPU_RdEventStat", "$SPU_WrEventMask", "$SPU_WrEventAck", "$SPU_RdSigNotify1",
|
||||
"$SPU_RdSigNotify2", "$ch5", "$ch6", "$SPU_WrDec", "$SPU_RdDec",
|
||||
"$MFC_WrMSSyncReq", "$ch10", "$SPU_RdEventMask", "$MFC_RdTagMask", "$SPU_RdMachStat",
|
||||
"$SPU_WrSRR0", "$SPU_RdSRR0", "$MFC_LSA", "$MFC_EAH", "$MFC_EAL", "$MFC_Size",
|
||||
"$MFC_TagID", "$MFC_Cmd", "$MFC_WrTagMask", "$MFC_WrTagUpdate", "$MFC_RdTagStat",
|
||||
"$MFC_RdListStallStat", "$MFC_WrListStallAck", "$MFC_RdAtomicStat",
|
||||
"$SPU_WrOutMbox", "$SPU_RdInMbox", "$SPU_WrOutIntrMbox", "$ch31", "$ch32",
|
||||
"$ch33", "$ch34", "$ch35", "$ch36", "$ch37", "$ch38", "$ch39", "$ch40",
|
||||
"$ch41", "$ch42", "$ch43", "$ch44", "$ch45", "$ch46", "$ch47", "$ch48",
|
||||
"$ch49", "$ch50", "$ch51", "$ch52", "$ch53", "$ch54", "$ch55", "$ch56",
|
||||
"$ch57", "$ch58", "$ch59", "$ch60", "$ch61", "$ch62", "$ch63", "$ch64",
|
||||
"$ch65", "$ch66", "$ch67", "$ch68", "$ch69", "$ch70", "$ch71", "$ch72",
|
||||
"$ch73", "$ch74", "$ch75", "$ch76", "$ch77", "$ch78", "$ch79", "$ch80",
|
||||
"$ch81", "$ch82", "$ch83", "$ch84", "$ch85", "$ch86", "$ch87", "$ch88",
|
||||
"$ch89", "$ch90", "$ch91", "$ch92", "$ch93", "$ch94", "$ch95", "$ch96",
|
||||
"$ch97", "$ch98", "$ch99", "$ch100", "$ch101", "$ch102", "$ch103", "$ch104",
|
||||
"$ch105", "$ch106", "$ch107", "$ch108", "$ch109", "$ch110", "$ch111", "$ch112",
|
||||
"$ch113", "$ch114", "$ch115", "$ch116", "$ch117", "$ch118", "$ch119", "$ch120",
|
||||
"$ch121", "$ch122", "$ch123", "$ch124", "$ch125", "$ch126", "$ch127",
|
||||
};
|
||||
|
||||
class SPUDisAsm
|
||||
: public SPUOpcodes
|
||||
|
@ -28,7 +88,7 @@ private:
|
|||
private:
|
||||
std::string& FixOp(std::string& op)
|
||||
{
|
||||
op.append(max<int>(10 - (int)op.length(), 0),' ');
|
||||
op.append(std::max<int>(10 - (int)op.length(), 0),' ');
|
||||
return op;
|
||||
}
|
||||
void DisAsm(const char* op)
|
||||
|
@ -94,7 +154,7 @@ private:
|
|||
}
|
||||
void MFSPR(u32 rt, u32 sa)
|
||||
{
|
||||
DisAsm("mfspr", spu_reg_name[rt], spu_reg_name[sa]); // Are SPR mapped on the GPR or are there 128 additional registers ? Yes, there are also 128 SPR making 256 registers total
|
||||
DisAsm("mfspr", spu_reg_name[rt], spu_spreg_name[sa]);
|
||||
}
|
||||
void RDCH(u32 rt, u32 ra)
|
||||
{
|
||||
|
@ -218,25 +278,25 @@ private:
|
|||
}
|
||||
void MTSPR(u32 rt, u32 sa)
|
||||
{
|
||||
DisAsm("mtspr", spu_reg_name[rt], spu_reg_name[sa]);
|
||||
DisAsm("mtspr", spu_spreg_name[sa], spu_reg_name[rt]);
|
||||
}
|
||||
void WRCH(u32 ra, u32 rt)
|
||||
{
|
||||
DisAsm("wrch", spu_ch_name[ra], spu_reg_name[rt]);
|
||||
}
|
||||
void BIZ(u32 rt, u32 ra)
|
||||
void BIZ(u32 intr, u32 rt, u32 ra)
|
||||
{
|
||||
DisAsm("biz", spu_reg_name[rt], spu_reg_name[ra]);
|
||||
}
|
||||
void BINZ(u32 rt, u32 ra)
|
||||
void BINZ(u32 intr, u32 rt, u32 ra)
|
||||
{
|
||||
DisAsm("binz", spu_reg_name[rt], spu_reg_name[ra]);
|
||||
}
|
||||
void BIHZ(u32 rt, u32 ra)
|
||||
void BIHZ(u32 intr, u32 rt, u32 ra)
|
||||
{
|
||||
DisAsm("bihz", spu_reg_name[rt], spu_reg_name[ra]);
|
||||
}
|
||||
void BIHNZ(u32 rt, u32 ra)
|
||||
void BIHNZ(u32 intr, u32 rt, u32 ra)
|
||||
{
|
||||
DisAsm("bihnz", spu_reg_name[rt], spu_reg_name[ra]);
|
||||
}
|
||||
|
@ -248,11 +308,11 @@ private:
|
|||
{
|
||||
DisAsm("stqx", spu_reg_name[rt], spu_reg_name[ra], spu_reg_name[rb]);
|
||||
}
|
||||
void BI(u32 ra)
|
||||
void BI(u32 intr, u32 ra)
|
||||
{
|
||||
DisAsm("bi", spu_reg_name[ra]);
|
||||
}
|
||||
void BISL(u32 rt, u32 ra)
|
||||
void BISL(u32 intr, u32 rt, u32 ra)
|
||||
{
|
||||
DisAsm("bisl", spu_reg_name[rt], spu_reg_name[ra]);
|
||||
}
|
||||
|
@ -260,7 +320,7 @@ private:
|
|||
{
|
||||
DisAsm("iret", spu_reg_name[ra]);
|
||||
}
|
||||
void BISLED(u32 rt, u32 ra)
|
||||
void BISLED(u32 intr, u32 rt, u32 ra)
|
||||
{
|
||||
DisAsm("bisled", spu_reg_name[rt], spu_reg_name[ra]);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#pragma once
|
||||
#include "PPCInstrTable.h"
|
||||
#include "PPCDecoder.h"
|
||||
#include "SPUOpcodes.h"
|
||||
|
||||
|
@ -88,16 +87,16 @@ namespace SPU_instr
|
|||
bind_instr(ri7_list, AVGB, RT, RA, RB);
|
||||
bind_instr(ri7_list, MTSPR, RT, RA);
|
||||
bind_instr(ri7_list, WRCH, RA, RT);
|
||||
bind_instr(ri7_list, BIZ, RT, RA);
|
||||
bind_instr(ri7_list, BINZ, RT, RA);
|
||||
bind_instr(ri7_list, BIHZ, RT, RA);
|
||||
bind_instr(ri7_list, BIHNZ, RT, RA);
|
||||
bind_instr(ri7_list, BIZ, RB, RT, RA);
|
||||
bind_instr(ri7_list, BINZ, RB, RT, RA);
|
||||
bind_instr(ri7_list, BIHZ, RB, RT, RA);
|
||||
bind_instr(ri7_list, BIHNZ, RB, RT, RA);
|
||||
bind_instr(ri7_list, STOPD, RT, RA, RB);
|
||||
bind_instr(ri7_list, STQX, RT, RA, RB);
|
||||
bind_instr(ri7_list, BI, RA);
|
||||
bind_instr(ri7_list, BISL, RT, RA);
|
||||
bind_instr(ri7_list, BI, RB, RA);
|
||||
bind_instr(ri7_list, BISL, RB, RT, RA);
|
||||
bind_instr(ri7_list, IRET, RA);
|
||||
bind_instr(ri7_list, BISLED, RT, RA);
|
||||
bind_instr(ri7_list, BISLED, RB, RT, RA);
|
||||
bind_instr(ri7_list, HBR, L_11, RO, RA);
|
||||
bind_instr(ri7_list, GB, RT, RA);
|
||||
bind_instr(ri7_list, GBH, RT, RA);
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -272,16 +272,16 @@ public:
|
|||
virtual void AVGB(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void MTSPR(u32 rt, u32 sa) = 0;
|
||||
virtual void WRCH(u32 ra, u32 rt) = 0;
|
||||
virtual void BIZ(u32 rt, u32 ra) = 0;
|
||||
virtual void BINZ(u32 rt, u32 ra) = 0;
|
||||
virtual void BIHZ(u32 rt, u32 ra) = 0;
|
||||
virtual void BIHNZ(u32 rt, u32 ra) = 0;
|
||||
virtual void BIZ(u32 intr, u32 rt, u32 ra) = 0;
|
||||
virtual void BINZ(u32 intr, u32 rt, u32 ra) = 0;
|
||||
virtual void BIHZ(u32 intr, u32 rt, u32 ra) = 0;
|
||||
virtual void BIHNZ(u32 intr, u32 rt, u32 ra) = 0;
|
||||
virtual void STOPD(u32 rc, u32 ra, u32 rb) = 0;
|
||||
virtual void STQX(u32 rt, u32 ra, u32 rb) = 0;
|
||||
virtual void BI(u32 ra) = 0;
|
||||
virtual void BISL(u32 rt, u32 ra) = 0;
|
||||
virtual void BI(u32 intr, u32 ra) = 0;
|
||||
virtual void BISL(u32 intr, u32 rt, u32 ra) = 0;
|
||||
virtual void IRET(u32 ra) = 0;
|
||||
virtual void BISLED(u32 rt, u32 ra) = 0;
|
||||
virtual void BISLED(u32 intr, u32 rt, u32 ra) = 0;
|
||||
virtual void HBR(u32 p, u32 ro, u32 ra) = 0;
|
||||
virtual void GB(u32 rt, u32 ra) = 0;
|
||||
virtual void GBH(u32 rt, u32 ra) = 0;
|
||||
|
|
|
@ -1,6 +1,51 @@
|
|||
#include "stdafx.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
|
||||
#include "SPURSManager.h"
|
||||
|
||||
SPURSManagerAttribute::SPURSManagerAttribute(int nSpus, int spuPriority, int ppuPriority, bool exitIfNoWork)
|
||||
{
|
||||
this->nSpus = nSpus;
|
||||
this->spuThreadGroupPriority = spuPriority;
|
||||
this->ppuThreadPriority = ppuPriority;
|
||||
this->exitIfNoWork = exitIfNoWork;
|
||||
|
||||
memset(this->namePrefix, 0, CELL_SPURS_NAME_MAX_LENGTH + 1);
|
||||
this->threadGroupType = 0;
|
||||
this->container = 0;
|
||||
}
|
||||
|
||||
int SPURSManagerAttribute::_setNamePrefix(const char *name, u32 size)
|
||||
{
|
||||
strncpy(this->namePrefix, name, size);
|
||||
this->namePrefix[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SPURSManagerAttribute::_setSpuThreadGroupType(int type)
|
||||
{
|
||||
this->threadGroupType = type;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SPURSManagerAttribute::_setMemoryContainerForSpuThread(u32 container)
|
||||
{
|
||||
this->container = container;
|
||||
return 0;
|
||||
}
|
||||
|
||||
SPURSManagerEventFlag::SPURSManagerEventFlag(u32 flagClearMode, u32 flagDirection)
|
||||
{
|
||||
this->flagClearMode = flagClearMode;
|
||||
this->flagDirection = flagDirection;
|
||||
}
|
||||
|
||||
SPURSManagerTasksetAttribute::SPURSManagerTasksetAttribute(u64 args, vm::ptr<const u8> priority, u32 maxContention)
|
||||
{
|
||||
this->args = args;
|
||||
this->maxContention = maxContention;
|
||||
}
|
||||
|
||||
SPURSManager::SPURSManager(SPURSManagerAttribute *attr)
|
||||
{
|
||||
this->attr = attr;
|
||||
|
@ -9,4 +54,20 @@ SPURSManager::SPURSManager(SPURSManagerAttribute *attr)
|
|||
void SPURSManager::Finalize()
|
||||
{
|
||||
delete this->attr;
|
||||
}
|
||||
|
||||
void SPURSManager::AttachLv2EventQueue(u32 queue, vm::ptr<u8> port, int isDynamic)
|
||||
{
|
||||
//TODO:
|
||||
}
|
||||
|
||||
void SPURSManager::DetachLv2EventQueue(u8 port)
|
||||
{
|
||||
//TODO:
|
||||
}
|
||||
|
||||
SPURSManagerTaskset::SPURSManagerTaskset(u32 address, SPURSManagerTasksetAttribute *tattr)
|
||||
{
|
||||
this->tattr = tattr;
|
||||
this->address = address;
|
||||
}
|
|
@ -1,83 +1,18 @@
|
|||
#pragma once
|
||||
|
||||
// SPURS defines.
|
||||
enum SPURSKernelInterfaces
|
||||
{
|
||||
CELL_SPURS_MAX_SPU = 8,
|
||||
CELL_SPURS_MAX_WORKLOAD = 16,
|
||||
CELL_SPURS_MAX_WORKLOAD2 = 32,
|
||||
CELL_SPURS_MAX_PRIORITY = 16,
|
||||
CELL_SPURS_NAME_MAX_LENGTH = 15,
|
||||
CELL_SPURS_SIZE = 4096,
|
||||
CELL_SPURS_SIZE2 = 8192,
|
||||
CELL_SPURS_ALIGN = 128,
|
||||
CELL_SPURS_ATTRIBUTE_SIZE = 512,
|
||||
CELL_SPURS_ATTRIBUTE_ALIGN = 8,
|
||||
CELL_SPURS_INTERRUPT_VECTOR = 0x0,
|
||||
CELL_SPURS_LOCK_LINE = 0x80,
|
||||
CELL_SPURS_KERNEL_DMA_TAG_ID = 31,
|
||||
};
|
||||
|
||||
enum RangeofEventQueuePortNumbers
|
||||
{
|
||||
CELL_SPURS_STATIC_PORT_RANGE_BOTTOM = 15,
|
||||
CELL_SPURS_DYNAMIC_PORT_RANGE_TOP = 16,
|
||||
CELL_SPURS_DYNAMIC_PORT_RANGE_BOTTOM = 63,
|
||||
};
|
||||
|
||||
enum SPURSTraceTypes
|
||||
{
|
||||
CELL_SPURS_TRACE_TAG_LOAD = 0x2a,
|
||||
CELL_SPURS_TRACE_TAG_MAP = 0x2b,
|
||||
CELL_SPURS_TRACE_TAG_START = 0x2c,
|
||||
CELL_SPURS_TRACE_TAG_STOP = 0x2d,
|
||||
CELL_SPURS_TRACE_TAG_USER = 0x2e,
|
||||
CELL_SPURS_TRACE_TAG_GUID = 0x2f,
|
||||
};
|
||||
|
||||
// SPURS task defines.
|
||||
enum TaskConstants
|
||||
{
|
||||
CELL_SPURS_MAX_TASK = 128,
|
||||
CELL_SPURS_TASK_TOP = 0x3000,
|
||||
CELL_SPURS_TASK_BOTTOM = 0x40000,
|
||||
CELL_SPURS_MAX_TASK_NAME_LENGTH = 32,
|
||||
};
|
||||
#include "Emu/SysCalls/Modules/cellSpurs.h"
|
||||
|
||||
// Internal class to shape a SPURS attribute.
|
||||
class SPURSManagerAttribute
|
||||
{
|
||||
public:
|
||||
SPURSManagerAttribute(int nSpus, int spuPriority, int ppuPriority, bool exitIfNoWork)
|
||||
{
|
||||
this->nSpus = nSpus;
|
||||
this->spuThreadGroupPriority = spuPriority;
|
||||
this->ppuThreadPriority = ppuPriority;
|
||||
this->exitIfNoWork = exitIfNoWork;
|
||||
SPURSManagerAttribute(int nSpus, int spuPriority, int ppuPriority, bool exitIfNoWork);
|
||||
|
||||
memset(this->namePrefix, 0, CELL_SPURS_NAME_MAX_LENGTH + 1);
|
||||
this->threadGroupType = 0;
|
||||
this->container = 0;
|
||||
}
|
||||
int _setNamePrefix(const char *name, u32 size);
|
||||
|
||||
int _setNamePrefix(const char *name, u32 size)
|
||||
{
|
||||
strncpy(this->namePrefix, name, size);
|
||||
this->namePrefix[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
int _setSpuThreadGroupType(int type);
|
||||
|
||||
int _setSpuThreadGroupType(int type)
|
||||
{
|
||||
this->threadGroupType = type;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _setMemoryContainerForSpuThread(u32 container)
|
||||
{
|
||||
this->container = container;
|
||||
return 0;
|
||||
}
|
||||
int _setMemoryContainerForSpuThread(u32 container);
|
||||
|
||||
protected:
|
||||
be_t<int> nSpus;
|
||||
|
@ -89,12 +24,55 @@ protected:
|
|||
be_t<u32> container;
|
||||
};
|
||||
|
||||
class SPURSManagerEventFlag
|
||||
{
|
||||
public:
|
||||
SPURSManagerEventFlag(u32 flagClearMode, u32 flagDirection);
|
||||
|
||||
u32 _getDirection() const
|
||||
{
|
||||
return this->flagDirection;
|
||||
}
|
||||
|
||||
u32 _getClearMode() const
|
||||
{
|
||||
return this->flagClearMode;
|
||||
}
|
||||
|
||||
protected:
|
||||
be_t<u32> flagClearMode;
|
||||
be_t<u32> flagDirection;
|
||||
};
|
||||
|
||||
class SPURSManagerTasksetAttribute
|
||||
{
|
||||
public:
|
||||
SPURSManagerTasksetAttribute(u64 args, vm::ptr<const u8> priority, u32 maxContention);
|
||||
|
||||
protected:
|
||||
be_t<u64> args;
|
||||
be_t<u32> maxContention;
|
||||
};
|
||||
|
||||
class SPURSManagerTaskset
|
||||
{
|
||||
public:
|
||||
SPURSManagerTaskset(u32 address, SPURSManagerTasksetAttribute *tattr);
|
||||
|
||||
protected:
|
||||
u32 address;
|
||||
SPURSManagerTasksetAttribute *tattr;
|
||||
};
|
||||
|
||||
// Main SPURS manager class.
|
||||
class SPURSManager
|
||||
{
|
||||
public:
|
||||
SPURSManager(SPURSManagerAttribute *attr);
|
||||
|
||||
void Finalize();
|
||||
void AttachLv2EventQueue(u32 queue, vm::ptr<u8> port, int isDynamic);
|
||||
void DetachLv2EventQueue(u8 port);
|
||||
|
||||
protected:
|
||||
SPURSManagerAttribute *attr;
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
#pragma once
|
||||
#include "Emu/Cell/SPUOpcodes.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/Cell/SPUThread.h"
|
||||
#include "Emu/SysCalls/SysCalls.h"
|
||||
|
||||
#define ASMJIT_STATIC
|
||||
|
||||
|
@ -89,6 +85,9 @@ public:
|
|||
u16 count; // count of instructions compiled from current point (and to be checked)
|
||||
u32 valid; // copy of valid opcode for validation
|
||||
void* pointer; // pointer to executable memory object
|
||||
#ifdef _WIN32
|
||||
//_IMAGE_RUNTIME_FUNCTION_ENTRY info;
|
||||
#endif
|
||||
};
|
||||
|
||||
SPURecEntry entry[0x10000];
|
||||
|
@ -109,14 +108,14 @@ public:
|
|||
#define c (*compiler)
|
||||
|
||||
#ifdef _WIN32
|
||||
#define cpu_xmm(x) oword_ptr(*cpu_var, (sizeof((*(SPUThread*)nullptr).x) == 16) ? offsetof(SPUThread, x) : throw "sizeof("#x") != 16")
|
||||
#define cpu_qword(x) qword_ptr(*cpu_var, (sizeof((*(SPUThread*)nullptr).x) == 8) ? offsetof(SPUThread, x) : throw "sizeof("#x") != 8")
|
||||
#define cpu_dword(x) dword_ptr(*cpu_var, (sizeof((*(SPUThread*)nullptr).x) == 4) ? offsetof(SPUThread, x) : throw "sizeof("#x") != 4")
|
||||
#define cpu_word(x) word_ptr(*cpu_var, (sizeof((*(SPUThread*)nullptr).x) == 2) ? offsetof(SPUThread, x) : throw "sizeof("#x") != 2")
|
||||
#define cpu_byte(x) byte_ptr(*cpu_var, (sizeof((*(SPUThread*)nullptr).x) == 1) ? offsetof(SPUThread, x) : throw "sizeof("#x") != 1")
|
||||
#define cpu_xmm(x) oword_ptr(*cpu_var, (sizeof((*(SPUThread*)nullptr).x) == 16) ? (s32)offsetof(SPUThread, x) : throw "sizeof("#x") != 16")
|
||||
#define cpu_qword(x) qword_ptr(*cpu_var, (sizeof((*(SPUThread*)nullptr).x) == 8) ? (s32)offsetof(SPUThread, x) : throw "sizeof("#x") != 8")
|
||||
#define cpu_dword(x) dword_ptr(*cpu_var, (sizeof((*(SPUThread*)nullptr).x) == 4) ? (s32)offsetof(SPUThread, x) : throw "sizeof("#x") != 4")
|
||||
#define cpu_word(x) word_ptr(*cpu_var, (sizeof((*(SPUThread*)nullptr).x) == 2) ? (s32)offsetof(SPUThread, x) : throw "sizeof("#x") != 2")
|
||||
#define cpu_byte(x) byte_ptr(*cpu_var, (sizeof((*(SPUThread*)nullptr).x) == 1) ? (s32)offsetof(SPUThread, x) : throw "sizeof("#x") != 1")
|
||||
|
||||
#define g_imm_xmm(x) oword_ptr(*g_imm_var, offsetof(g_imm_table_struct, x))
|
||||
#define g_imm2_xmm(x, y) oword_ptr(*g_imm_var, y, 0, offsetof(g_imm_table_struct, x))
|
||||
#define g_imm_xmm(x) oword_ptr(*g_imm_var, (s32)offsetof(g_imm_table_struct, x))
|
||||
#define g_imm2_xmm(x, y) oword_ptr(*g_imm_var, y, 0, (s32)offsetof(g_imm_table_struct, x))
|
||||
#else
|
||||
#define cpu_xmm(x) oword_ptr(*cpu_var, reinterpret_cast<uintptr_t>(&(((SPUThread*)0)->x)) )
|
||||
#define cpu_qword(x) qword_ptr(*cpu_var, reinterpret_cast<uintptr_t>(&(((SPUThread*)0)->x)) )
|
||||
|
@ -148,7 +147,7 @@ public:
|
|||
if (#a1[0] == 'r') XmmInvalidate(a1); \
|
||||
if (#a2[0] == 'r') XmmInvalidate(a2); \
|
||||
if (#a3[0] == 'r') XmmInvalidate(a3); \
|
||||
X86X64CallNode* call##a0 = c.call(imm_ptr(reinterpret_cast<void*>(&opwr_##a0::opcode)), kFuncConvHost, FuncBuilder4<FnVoid, u32, u32, u32, u32>()); \
|
||||
X86CallNode* call##a0 = c.call(imm_ptr(reinterpret_cast<void*>(&opwr_##a0::opcode)), kFuncConvHost, FuncBuilder4<void, u32, u32, u32, u32>()); \
|
||||
call##a0->setArg(0, imm_u(a0)); \
|
||||
call##a0->setArg(1, imm_u(a1)); \
|
||||
call##a0->setArg(2, imm_u(a2)); \
|
||||
|
@ -163,24 +162,24 @@ private:
|
|||
SPURecompilerCore& rec;
|
||||
|
||||
public:
|
||||
Compiler* compiler;
|
||||
X86Compiler* compiler;
|
||||
bool do_finalize;
|
||||
// input:
|
||||
GpVar* cpu_var;
|
||||
GpVar* ls_var;
|
||||
GpVar* imm_var;
|
||||
GpVar* g_imm_var;
|
||||
X86GpVar* cpu_var;
|
||||
X86GpVar* ls_var;
|
||||
X86GpVar* imm_var;
|
||||
X86GpVar* g_imm_var;
|
||||
// output:
|
||||
GpVar* pos_var;
|
||||
X86GpVar* pos_var;
|
||||
// temporary:
|
||||
GpVar* addr;
|
||||
GpVar* qw0;
|
||||
GpVar* qw1;
|
||||
GpVar* qw2;
|
||||
X86GpVar* addr;
|
||||
X86GpVar* qw0;
|
||||
X86GpVar* qw1;
|
||||
X86GpVar* qw2;
|
||||
|
||||
struct XmmLink
|
||||
{
|
||||
XmmVar* data;
|
||||
X86XmmVar* data;
|
||||
s8 reg;
|
||||
bool taken;
|
||||
mutable bool got;
|
||||
|
@ -419,9 +418,9 @@ public:
|
|||
return oword_ptr(*imm_var, i * sizeof(__m128i));
|
||||
}
|
||||
}
|
||||
const int shift = rec.imm_table.size() * sizeof(__m128i);
|
||||
const size_t shift = rec.imm_table.size() * sizeof(__m128i);
|
||||
rec.imm_table.push_back(data);
|
||||
return oword_ptr(*imm_var, shift);
|
||||
return oword_ptr(*imm_var, (s32)shift);
|
||||
}
|
||||
|
||||
Mem XmmConst(const __m128& data)
|
||||
|
@ -438,12 +437,12 @@ private:
|
|||
static void STOP(u32 code)
|
||||
{
|
||||
SPUThread& CPU = *(SPUThread*)GetCurrentCPUThread();
|
||||
CPU.DoStop(code);
|
||||
CPU.StopAndSignal(code);
|
||||
LOG2_OPCODE();
|
||||
}
|
||||
};
|
||||
c.mov(cpu_qword(PC), (u32)CPU.PC);
|
||||
X86X64CallNode* call = c.call(imm_ptr(reinterpret_cast<void*>(&STOP_wrapper::STOP)), kFuncConvHost, FuncBuilder1<FnVoid, u32>());
|
||||
X86CallNode* call = c.call(imm_ptr(reinterpret_cast<void*>(&STOP_wrapper::STOP)), kFuncConvHost, FuncBuilder1<void, u32>());
|
||||
call->setArg(0, imm_u(code));
|
||||
c.mov(*pos_var, (CPU.PC >> 2) + 1);
|
||||
do_finalize = true;
|
||||
|
@ -471,17 +470,6 @@ private:
|
|||
void MFSPR(u32 rt, u32 sa)
|
||||
{
|
||||
UNIMPLEMENTED();
|
||||
//If register is a dummy register (register labeled 0x0)
|
||||
if(sa == 0x0)
|
||||
{
|
||||
CPU.GPR[rt]._u128.hi = 0x0;
|
||||
CPU.GPR[rt]._u128.lo = 0x0;
|
||||
}
|
||||
else
|
||||
{
|
||||
CPU.GPR[rt]._u128.hi = CPU.SPR[sa]._u128.hi;
|
||||
CPU.GPR[rt]._u128.lo = CPU.SPR[sa]._u128.lo;
|
||||
}
|
||||
}
|
||||
void RDCH(u32 rt, u32 ra)
|
||||
{
|
||||
|
@ -495,7 +483,7 @@ private:
|
|||
{
|
||||
c.mov(cpu_qword(PC), (u32)CPU.PC);
|
||||
WRAPPER_BEGIN(rt, ra, yy, zz);
|
||||
CPU.GPR[rt].Reset();
|
||||
CPU.GPR[rt].clear();
|
||||
CPU.GPR[rt]._u32[3] = CPU.GetChannelCount(ra);
|
||||
WRAPPER_END(rt, ra, 0, 0);
|
||||
// TODO
|
||||
|
@ -1098,11 +1086,6 @@ private:
|
|||
void MTSPR(u32 rt, u32 sa)
|
||||
{
|
||||
UNIMPLEMENTED();
|
||||
if(sa != 0)
|
||||
{
|
||||
CPU.SPR[sa]._u128.hi = CPU.GPR[rt]._u128.hi;
|
||||
CPU.SPR[sa]._u128.lo = CPU.GPR[rt]._u128.lo;
|
||||
}
|
||||
}
|
||||
void WRCH(u32 ra, u32 rt)
|
||||
{
|
||||
|
@ -1114,7 +1097,7 @@ private:
|
|||
|
||||
/*XmmInvalidate(rt);
|
||||
|
||||
GpVar v(c, kVarTypeUInt32);
|
||||
X86GpVar v(c, kVarTypeUInt32);
|
||||
c.mov(v, cpu_dword(GPR[rt]._u32[3]));
|
||||
switch (ra)
|
||||
{
|
||||
|
@ -1146,8 +1129,14 @@ private:
|
|||
}
|
||||
}*/
|
||||
}
|
||||
void BIZ(u32 rt, u32 ra)
|
||||
void BIZ(u32 intr, u32 rt, u32 ra)
|
||||
{
|
||||
if (intr)
|
||||
{
|
||||
UNIMPLEMENTED();
|
||||
return;
|
||||
}
|
||||
|
||||
c.mov(cpu_qword(PC), (u32)CPU.PC);
|
||||
do_finalize = true;
|
||||
|
||||
|
@ -1158,8 +1147,14 @@ private:
|
|||
c.shr(*pos_var, 2);
|
||||
LOG_OPCODE();
|
||||
}
|
||||
void BINZ(u32 rt, u32 ra)
|
||||
void BINZ(u32 intr, u32 rt, u32 ra)
|
||||
{
|
||||
if (intr)
|
||||
{
|
||||
UNIMPLEMENTED();
|
||||
return;
|
||||
}
|
||||
|
||||
c.mov(cpu_qword(PC), (u32)CPU.PC);
|
||||
do_finalize = true;
|
||||
|
||||
|
@ -1170,8 +1165,14 @@ private:
|
|||
c.shr(*pos_var, 2);
|
||||
LOG_OPCODE();
|
||||
}
|
||||
void BIHZ(u32 rt, u32 ra)
|
||||
void BIHZ(u32 intr, u32 rt, u32 ra)
|
||||
{
|
||||
if (intr)
|
||||
{
|
||||
UNIMPLEMENTED();
|
||||
return;
|
||||
}
|
||||
|
||||
c.mov(cpu_qword(PC), (u32)CPU.PC);
|
||||
do_finalize = true;
|
||||
|
||||
|
@ -1182,8 +1183,14 @@ private:
|
|||
c.shr(*pos_var, 2);
|
||||
LOG_OPCODE();
|
||||
}
|
||||
void BIHNZ(u32 rt, u32 ra)
|
||||
void BIHNZ(u32 intr, u32 rt, u32 ra)
|
||||
{
|
||||
if (intr)
|
||||
{
|
||||
UNIMPLEMENTED();
|
||||
return;
|
||||
}
|
||||
|
||||
c.mov(cpu_qword(PC), (u32)CPU.PC);
|
||||
do_finalize = true;
|
||||
|
||||
|
@ -1197,7 +1204,6 @@ private:
|
|||
void STOPD(u32 rc, u32 ra, u32 rb)
|
||||
{
|
||||
UNIMPLEMENTED();
|
||||
Emu.Pause();
|
||||
}
|
||||
void STQX(u32 rt, u32 ra, u32 rb)
|
||||
{
|
||||
|
@ -1211,16 +1217,29 @@ private:
|
|||
c.add(*addr, cpu_dword(GPR[rb]._u32[3]));
|
||||
}
|
||||
c.and_(*addr, 0x3fff0);
|
||||
|
||||
/*const XmmLink& vt = XmmGet(rt);
|
||||
c.pshufb(vt.get(), XmmConst(_mm_set_epi32(0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f)));
|
||||
c.movdqa(oword_ptr(*ls_var, *addr), vt.get());
|
||||
XmmFinalize(vt);*/
|
||||
|
||||
c.mov(*qw0, cpu_qword(GPR[rt]._u64[0]));
|
||||
c.mov(*qw1, cpu_qword(GPR[rt]._u64[1]));
|
||||
c.bswap(*qw0);
|
||||
c.bswap(*qw1);
|
||||
c.mov(qword_ptr(*ls_var, *addr, 0, 0), *qw1);
|
||||
c.mov(qword_ptr(*ls_var, *addr, 0, 8), *qw0);
|
||||
|
||||
LOG_OPCODE();
|
||||
}
|
||||
void BI(u32 ra)
|
||||
void BI(u32 intr, u32 ra)
|
||||
{
|
||||
if (intr)
|
||||
{
|
||||
UNIMPLEMENTED();
|
||||
return;
|
||||
}
|
||||
|
||||
c.mov(cpu_qword(PC), (u32)CPU.PC);
|
||||
do_finalize = true;
|
||||
|
||||
|
@ -1228,8 +1247,14 @@ private:
|
|||
c.shr(*pos_var, 2);
|
||||
LOG_OPCODE();
|
||||
}
|
||||
void BISL(u32 rt, u32 ra)
|
||||
void BISL(u32 intr, u32 rt, u32 ra)
|
||||
{
|
||||
if (intr)
|
||||
{
|
||||
UNIMPLEMENTED();
|
||||
return;
|
||||
}
|
||||
|
||||
XmmInvalidate(rt);
|
||||
|
||||
c.mov(cpu_qword(PC), (u32)CPU.PC);
|
||||
|
@ -1247,9 +1272,8 @@ private:
|
|||
void IRET(u32 ra)
|
||||
{
|
||||
UNIMPLEMENTED();
|
||||
//SetBranch(SRR0);
|
||||
}
|
||||
void BISLED(u32 rt, u32 ra)
|
||||
void BISLED(u32 intr, u32 rt, u32 ra)
|
||||
{
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
@ -1350,12 +1374,19 @@ private:
|
|||
c.add(*addr, cpu_dword(GPR[rb]._u32[3]));
|
||||
}
|
||||
c.and_(*addr, 0x3fff0);
|
||||
|
||||
/*const XmmLink& vt = XmmAlloc(rt);
|
||||
c.movdqa(vt.get(), oword_ptr(*ls_var, *addr));
|
||||
c.pshufb(vt.get(), XmmConst(_mm_set_epi32(0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f)));
|
||||
XmmFinalize(vt, rt);*/
|
||||
|
||||
c.mov(*qw0, qword_ptr(*ls_var, *addr, 0, 0));
|
||||
c.mov(*qw1, qword_ptr(*ls_var, *addr, 0, 8));
|
||||
c.bswap(*qw0);
|
||||
c.bswap(*qw1);
|
||||
c.mov(cpu_qword(GPR[rt]._u64[0]), *qw1);
|
||||
c.mov(cpu_qword(GPR[rt]._u64[1]), *qw0);
|
||||
|
||||
LOG_OPCODE();
|
||||
}
|
||||
void ROTQBYBI(u32 rt, u32 ra, u32 rb)
|
||||
|
@ -1408,7 +1439,7 @@ private:
|
|||
c.movdqa(vr.get(), XmmConst(_mm_set_epi32(0x10111213, 0x14151617, 0x18191a1b, 0x1c1d1e1f)));
|
||||
XmmFinalize(vr, rt);
|
||||
XmmInvalidate(rt);
|
||||
c.mov(byte_ptr(*cpu_var, *addr, 0, offsetof(SPUThread, GPR[rt]._u8[0])), 0x03);
|
||||
c.mov(byte_ptr(*cpu_var, *addr, 0, (s32)offsetof(SPUThread, GPR[rt]._u8[0])), 0x03);
|
||||
LOG_OPCODE();
|
||||
}
|
||||
void CHX(u32 rt, u32 ra, u32 rb)
|
||||
|
@ -1429,7 +1460,7 @@ private:
|
|||
c.movdqa(vr.get(), XmmConst(_mm_set_epi32(0x10111213, 0x14151617, 0x18191a1b, 0x1c1d1e1f)));
|
||||
XmmFinalize(vr, rt);
|
||||
XmmInvalidate(rt);
|
||||
c.mov(word_ptr(*cpu_var, *addr, 0, offsetof(SPUThread, GPR[rt]._u16[0])), 0x0203);
|
||||
c.mov(word_ptr(*cpu_var, *addr, 0, (s32)offsetof(SPUThread, GPR[rt]._u16[0])), 0x0203);
|
||||
LOG_OPCODE();
|
||||
}
|
||||
void CWX(u32 rt, u32 ra, u32 rb)
|
||||
|
@ -1450,7 +1481,7 @@ private:
|
|||
c.movdqa(vr.get(), XmmConst(_mm_set_epi32(0x10111213, 0x14151617, 0x18191a1b, 0x1c1d1e1f)));
|
||||
XmmFinalize(vr, rt);
|
||||
XmmInvalidate(rt);
|
||||
c.mov(dword_ptr(*cpu_var, *addr, 0, offsetof(SPUThread, GPR[rt]._u32[0])), 0x00010203);
|
||||
c.mov(dword_ptr(*cpu_var, *addr, 0, (s32)offsetof(SPUThread, GPR[rt]._u32[0])), 0x00010203);
|
||||
LOG_OPCODE();
|
||||
}
|
||||
void CDX(u32 rt, u32 ra, u32 rb)
|
||||
|
@ -1471,8 +1502,8 @@ private:
|
|||
c.movdqa(vr.get(), XmmConst(_mm_set_epi32(0x10111213, 0x14151617, 0x18191a1b, 0x1c1d1e1f)));
|
||||
XmmFinalize(vr, rt);
|
||||
XmmInvalidate(rt);
|
||||
c.mov(dword_ptr(*cpu_var, *addr, 0, offsetof(SPUThread, GPR[rt]._u32[0])), 0x00010203);
|
||||
c.mov(dword_ptr(*cpu_var, *addr, 0, offsetof(SPUThread, GPR[rt]._u32[1])), 0x04050607);
|
||||
c.mov(dword_ptr(*cpu_var, *addr, 0, (s32)offsetof(SPUThread, GPR[rt]._u32[0])), 0x04050607);
|
||||
c.mov(dword_ptr(*cpu_var, *addr, 0, (s32)offsetof(SPUThread, GPR[rt]._u32[1])), 0x00010203);
|
||||
LOG_OPCODE();
|
||||
}
|
||||
void ROTQBI(u32 rt, u32 ra, u32 rb)
|
||||
|
@ -1572,7 +1603,7 @@ private:
|
|||
c.movdqa(vr.get(), XmmConst(_mm_set_epi32(0x10111213, 0x14151617, 0x18191a1b, 0x1c1d1e1f)));
|
||||
XmmFinalize(vr, rt);
|
||||
XmmInvalidate(rt);
|
||||
c.mov(byte_ptr(*cpu_var, *addr, 0, offsetof(SPUThread, GPR[rt]._u8[0])), 0x03);
|
||||
c.mov(byte_ptr(*cpu_var, *addr, 0, (s32)offsetof(SPUThread, GPR[rt]._u8[0])), 0x03);
|
||||
LOG_OPCODE();
|
||||
}
|
||||
void CHD(u32 rt, u32 ra, s32 i7)
|
||||
|
@ -1586,7 +1617,7 @@ private:
|
|||
c.movdqa(vr.get(), XmmConst(_mm_set_epi32(0x10111213, 0x14151617, 0x18191a1b, 0x1c1d1e1f)));
|
||||
XmmFinalize(vr, rt);
|
||||
XmmInvalidate(rt);
|
||||
c.mov(word_ptr(*cpu_var, *addr, 0, offsetof(SPUThread, GPR[rt]._u16[0])), 0x0203);
|
||||
c.mov(word_ptr(*cpu_var, *addr, 0, (s32)offsetof(SPUThread, GPR[rt]._u16[0])), 0x0203);
|
||||
LOG_OPCODE();
|
||||
}
|
||||
void CWD(u32 rt, u32 ra, s32 i7)
|
||||
|
@ -1600,7 +1631,7 @@ private:
|
|||
c.movdqa(vr.get(), XmmConst(_mm_set_epi32(0x10111213, 0x14151617, 0x18191a1b, 0x1c1d1e1f)));
|
||||
XmmFinalize(vr, rt);
|
||||
XmmInvalidate(rt);
|
||||
c.mov(dword_ptr(*cpu_var, *addr, 0, offsetof(SPUThread, GPR[rt]._u32[0])), 0x00010203);
|
||||
c.mov(dword_ptr(*cpu_var, *addr, 0, (s32)offsetof(SPUThread, GPR[rt]._u32[0])), 0x00010203);
|
||||
LOG_OPCODE();
|
||||
}
|
||||
void CDD(u32 rt, u32 ra, s32 i7)
|
||||
|
@ -1614,8 +1645,8 @@ private:
|
|||
c.movdqa(vr.get(), XmmConst(_mm_set_epi32(0x10111213, 0x14151617, 0x18191a1b, 0x1c1d1e1f)));
|
||||
XmmFinalize(vr, rt);
|
||||
XmmInvalidate(rt);
|
||||
c.mov(dword_ptr(*cpu_var, *addr, 0, offsetof(SPUThread, GPR[rt]._u32[0])), 0x00010203);
|
||||
c.mov(dword_ptr(*cpu_var, *addr, 0, offsetof(SPUThread, GPR[rt]._u32[1])), 0x04050607);
|
||||
c.mov(dword_ptr(*cpu_var, *addr, 0, (s32)offsetof(SPUThread, GPR[rt]._u32[0])), 0x04050607);
|
||||
c.mov(dword_ptr(*cpu_var, *addr, 0, (s32)offsetof(SPUThread, GPR[rt]._u32[1])), 0x00010203);
|
||||
LOG_OPCODE();
|
||||
}
|
||||
void ROTQBII(u32 rt, u32 ra, s32 i7)
|
||||
|
@ -1914,10 +1945,10 @@ private:
|
|||
//HGT uses signed values. HLGT uses unsigned values
|
||||
void HGT(u32 rt, s32 ra, s32 rb)
|
||||
{
|
||||
c.mov(*addr, cpu_dword(GPR[ra]._i32[3]));
|
||||
c.cmp(*addr, cpu_dword(GPR[rb]._i32[3]));
|
||||
c.mov(*addr, cpu_dword(GPR[ra]._s32[3]));
|
||||
c.cmp(*addr, cpu_dword(GPR[rb]._s32[3]));
|
||||
c.mov(*addr, 0);
|
||||
c.setg(*addr);
|
||||
c.setg(addr->r8());
|
||||
c.neg(*addr);
|
||||
c.mov(*pos_var, (CPU.PC >> 2) + 1);
|
||||
c.xor_(*pos_var, *addr);
|
||||
|
@ -1930,7 +1961,7 @@ private:
|
|||
for (u32 i = 0; i < 4; i++)
|
||||
{
|
||||
c.bsr(*addr, cpu_dword(GPR[ra]._u32[i]));
|
||||
c.cmovz(*addr, dword_ptr(*g_imm_var, offsetof(g_imm_table_struct, fsmb_table[0xffff]))); // load 0xffffffff
|
||||
c.cmovz(*addr, dword_ptr(*g_imm_var, (s32)offsetof(g_imm_table_struct, fsmb_table[0xffff]))); // load 0xffffffff
|
||||
c.neg(*addr);
|
||||
c.add(*addr, 31);
|
||||
c.mov(cpu_dword(GPR[rt]._u32[i]), *addr);
|
||||
|
@ -1939,10 +1970,10 @@ private:
|
|||
}
|
||||
void XSWD(u32 rt, u32 ra)
|
||||
{
|
||||
c.movsxd(*qw0, cpu_dword(GPR[ra]._i32[0]));
|
||||
c.movsxd(*qw1, cpu_dword(GPR[ra]._i32[2]));
|
||||
c.mov(cpu_qword(GPR[rt]._i64[0]), *qw0);
|
||||
c.mov(cpu_qword(GPR[rt]._i64[1]), *qw1);
|
||||
c.movsxd(*qw0, cpu_dword(GPR[ra]._s32[0]));
|
||||
c.movsxd(*qw1, cpu_dword(GPR[ra]._s32[2]));
|
||||
c.mov(cpu_qword(GPR[rt]._s64[0]), *qw0);
|
||||
c.mov(cpu_qword(GPR[rt]._s64[1]), *qw1);
|
||||
XmmInvalidate(rt);
|
||||
LOG_OPCODE();
|
||||
}
|
||||
|
@ -1960,7 +1991,7 @@ private:
|
|||
for (u32 i = 0; i < 8; i++)
|
||||
{
|
||||
c.movzx(*addr, cpu_word(GPR[ra]._u16[i]));
|
||||
c.movzx(*addr, word_ptr(*g_imm_var, *addr, 1, offsetof(g_imm_table_struct, cntb_table[0])));
|
||||
c.movzx(*addr, word_ptr(*g_imm_var, *addr, 1, (s32)offsetof(g_imm_table_struct, cntb_table[0])));
|
||||
c.mov(cpu_word(GPR[rt]._u16[i]), addr->r16());
|
||||
}*/
|
||||
const XmmLink& va = XmmGet(ra, rt);
|
||||
|
@ -2051,18 +2082,7 @@ private:
|
|||
}
|
||||
void DFCGT(u32 rt, u32 ra, u32 rb)
|
||||
{
|
||||
// reverted less-than
|
||||
const XmmLink& vb = XmmGet(rb, rt);
|
||||
if (const XmmLink* va = XmmRead(ra))
|
||||
{
|
||||
c.cmppd(vb.get(), va->read(), 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
c.cmppd(vb.get(), cpu_xmm(GPR[ra]), 1);
|
||||
}
|
||||
XmmFinalize(vb, rt);
|
||||
LOG_OPCODE();
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
void FA(u32 rt, u32 ra, u32 rb)
|
||||
{
|
||||
|
@ -2192,15 +2212,7 @@ private:
|
|||
}
|
||||
void DFCMGT(u32 rt, u32 ra, u32 rb)
|
||||
{
|
||||
// reverted less-than
|
||||
const XmmLink& vb = XmmGet(rb, rt);
|
||||
const XmmLink& va = XmmGet(ra);
|
||||
c.andpd(vb.get(), XmmConst(_mm_set_epi32(0x7fffffff, 0xffffffff, 0x7fffffff, 0xffffffff))); // abs
|
||||
c.andpd(va.get(), XmmConst(_mm_set_epi32(0x7fffffff, 0xffffffff, 0x7fffffff, 0xffffffff))); // abs
|
||||
c.cmppd(vb.get(), va.get(), 1);
|
||||
XmmFinalize(vb, rt);
|
||||
XmmFinalize(va);
|
||||
LOG_OPCODE();
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
void DFA(u32 rt, u32 ra, u32 rb)
|
||||
{
|
||||
|
@ -2297,7 +2309,7 @@ private:
|
|||
c.mov(*addr, cpu_dword(GPR[ra]._u32[3]));
|
||||
c.cmp(*addr, cpu_dword(GPR[rb]._u32[3]));
|
||||
c.mov(*addr, 0);
|
||||
c.seta(*addr);
|
||||
c.seta(addr->r8());
|
||||
c.neg(*addr);
|
||||
c.mov(*pos_var, (CPU.PC >> 2) + 1);
|
||||
c.xor_(*pos_var, *addr);
|
||||
|
@ -2462,7 +2474,11 @@ private:
|
|||
}
|
||||
void FSCRRD(u32 rt)
|
||||
{
|
||||
UNIMPLEMENTED();
|
||||
// zero (hack)
|
||||
const XmmLink& v0 = XmmAlloc(rt);
|
||||
c.pxor(v0.get(), v0.get());
|
||||
XmmFinalize(v0, rt);
|
||||
LOG_OPCODE();
|
||||
}
|
||||
void FESD(u32 rt, u32 ra)
|
||||
{
|
||||
|
@ -2482,62 +2498,12 @@ private:
|
|||
}
|
||||
void FSCRWR(u32 rt, u32 ra)
|
||||
{
|
||||
UNIMPLEMENTED();
|
||||
// nop (not implemented)
|
||||
LOG_OPCODE();
|
||||
}
|
||||
void DFTSV(u32 rt, u32 ra, s32 i7) //nf
|
||||
void DFTSV(u32 rt, u32 ra, s32 i7)
|
||||
{
|
||||
WRAPPER_BEGIN(rt, ra, i7, zz);
|
||||
const u64 DoubleExpMask = 0x7ff0000000000000;
|
||||
const u64 DoubleFracMask = 0x000fffffffffffff;
|
||||
const u64 DoubleSignMask = 0x8000000000000000;
|
||||
const SPU_GPR_hdr temp = CPU.GPR[ra];
|
||||
CPU.GPR[rt].Reset();
|
||||
if (i7 & 1) //Negative Denorm Check (-, exp is zero, frac is non-zero)
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (temp._u64[i] & DoubleFracMask)
|
||||
if ((temp._u64[i] & (DoubleSignMask | DoubleExpMask)) == DoubleSignMask)
|
||||
CPU.GPR[rt]._u64[i] = 0xffffffffffffffff;
|
||||
}
|
||||
if (i7 & 2) //Positive Denorm Check (+, exp is zero, frac is non-zero)
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (temp._u64[i] & DoubleFracMask)
|
||||
if ((temp._u64[i] & (DoubleSignMask | DoubleExpMask)) == 0)
|
||||
CPU.GPR[rt]._u64[i] = 0xffffffffffffffff;
|
||||
}
|
||||
if (i7 & 4) //Negative Zero Check (-, exp is zero, frac is zero)
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (temp._u64[i] == DoubleSignMask)
|
||||
CPU.GPR[rt]._u64[i] = 0xffffffffffffffff;
|
||||
}
|
||||
if (i7 & 8) //Positive Zero Check (+, exp is zero, frac is zero)
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (temp._u64[i] == 0)
|
||||
CPU.GPR[rt]._u64[i] = 0xffffffffffffffff;
|
||||
}
|
||||
if (i7 & 16) //Negative Infinity Check (-, exp is 0x7ff, frac is zero)
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (temp._u64[i] == (DoubleSignMask | DoubleExpMask))
|
||||
CPU.GPR[rt]._u64[i] = 0xffffffffffffffff;
|
||||
}
|
||||
if (i7 & 32) //Positive Infinity Check (+, exp is 0x7ff, frac is zero)
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (temp._u64[i] == DoubleExpMask)
|
||||
CPU.GPR[rt]._u64[i] = 0xffffffffffffffff;
|
||||
}
|
||||
if (i7 & 64) //Not-a-Number Check (any sign, exp is 0x7ff, frac is non-zero)
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (temp._u64[i] & DoubleFracMask)
|
||||
if ((temp._u64[i] & DoubleExpMask) == DoubleExpMask)
|
||||
CPU.GPR[rt]._u64[i] = 0xffffffffffffffff;
|
||||
}
|
||||
WRAPPER_END(rt, ra, i7, 0);
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
void FCEQ(u32 rt, u32 ra, u32 rb)
|
||||
{
|
||||
|
@ -2556,18 +2522,7 @@ private:
|
|||
}
|
||||
void DFCEQ(u32 rt, u32 ra, u32 rb)
|
||||
{
|
||||
// compare equal
|
||||
const XmmLink& vb = XmmGet(rb, rt);
|
||||
if (const XmmLink* va = XmmRead(ra))
|
||||
{
|
||||
c.cmppd(vb.get(), va->read(), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
c.cmppd(vb.get(), cpu_xmm(GPR[ra]), 0);
|
||||
}
|
||||
XmmFinalize(vb, rt);
|
||||
LOG_OPCODE();
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
void MPY(u32 rt, u32 ra, u32 rb)
|
||||
{
|
||||
|
@ -2651,14 +2606,7 @@ private:
|
|||
}
|
||||
void DFCMEQ(u32 rt, u32 ra, u32 rb)
|
||||
{
|
||||
const XmmLink& vb = XmmGet(rb, rt);
|
||||
const XmmLink& va = XmmGet(ra);
|
||||
c.andpd(vb.get(), XmmConst(_mm_set_epi32(0x7fffffff, 0xffffffff, 0x7fffffff, 0xffffffff))); // abs
|
||||
c.andpd(va.get(), XmmConst(_mm_set_epi32(0x7fffffff, 0xffffffff, 0x7fffffff, 0xffffffff))); // abs
|
||||
c.cmppd(vb.get(), va.get(), 0); // ==
|
||||
XmmFinalize(vb, rt);
|
||||
XmmFinalize(va);
|
||||
LOG_OPCODE();
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
void MPYU(u32 rt, u32 ra, u32 rb)
|
||||
{
|
||||
|
@ -2712,10 +2660,10 @@ private:
|
|||
}
|
||||
void HEQ(u32 rt, u32 ra, u32 rb)
|
||||
{
|
||||
c.mov(*addr, cpu_dword(GPR[ra]._i32[3]));
|
||||
c.cmp(*addr, cpu_dword(GPR[rb]._i32[3]));
|
||||
c.mov(*addr, cpu_dword(GPR[ra]._s32[3]));
|
||||
c.cmp(*addr, cpu_dword(GPR[rb]._s32[3]));
|
||||
c.mov(*addr, 0);
|
||||
c.sete(*addr);
|
||||
c.sete(addr->r8());
|
||||
c.neg(*addr);
|
||||
c.mov(*pos_var, (CPU.PC >> 2) + 1);
|
||||
c.xor_(*pos_var, *addr);
|
||||
|
@ -2729,9 +2677,9 @@ private:
|
|||
const XmmLink& va = XmmGet(ra, rt);
|
||||
if (i8 != 173)
|
||||
{
|
||||
c.mulps(va.get(), XmmConst(_mm_set1_ps(pow(2, 173 - (i8 & 0xff))))); // scale
|
||||
c.mulps(va.get(), XmmConst(_mm_set1_ps((float)pow(2, 173 - (i8 & 0xff))))); // scale
|
||||
}
|
||||
c.maxps(va.get(), XmmConst(_mm_set1_ps(-pow(2, 31)))); // saturate
|
||||
c.maxps(va.get(), XmmConst(_mm_set1_ps((float)-pow(2, 31)))); // saturate
|
||||
c.minps(va.get(), XmmConst(_mm_set1_ps((float)0x7fffffff)));
|
||||
c.cvttps2dq(va.get(), va.get()); // convert to ints with truncation
|
||||
XmmFinalize(va, rt);
|
||||
|
@ -2742,13 +2690,13 @@ private:
|
|||
const XmmLink& va = XmmGet(ra, rt);
|
||||
if (i8 != 173)
|
||||
{
|
||||
c.mulps(va.get(), XmmConst(_mm_set1_ps(pow(2, 173 - (i8 & 0xff))))); // scale
|
||||
c.mulps(va.get(), XmmConst(_mm_set1_ps((float)pow(2, 173 - (i8 & 0xff))))); // scale
|
||||
}
|
||||
c.maxps(va.get(), XmmConst(_mm_set1_ps(0.0f))); // saturate
|
||||
c.minps(va.get(), XmmConst(_mm_set1_ps((float)0xffffffff)));
|
||||
const XmmLink& v1 = XmmCopy(va);
|
||||
c.cmpps(v1.get(), XmmConst(_mm_set1_ps(pow(2, 31))), 5); // generate mask of big values
|
||||
c.andps(v1.get(), XmmConst(_mm_set1_ps(pow(2, 32)))); // generate correction component
|
||||
c.cmpps(v1.get(), XmmConst(_mm_set1_ps((float)pow(2, 31))), 5); // generate mask of big values
|
||||
c.andps(v1.get(), XmmConst(_mm_set1_ps((float)pow(2, 32)))); // generate correction component
|
||||
c.subps(va.get(), v1.get()); // subtract correction component
|
||||
c.cvttps2dq(va.get(), va.get()); // convert to ints with truncation
|
||||
XmmFinalize(va, rt);
|
||||
|
@ -2761,7 +2709,7 @@ private:
|
|||
c.cvtdq2ps(va.get(), va.get()); // convert to floats
|
||||
if (i8 != 155)
|
||||
{
|
||||
c.mulps(va.get(), XmmConst(_mm_set1_ps(pow(2, (i8 & 0xff) - 155)))); // scale
|
||||
c.mulps(va.get(), XmmConst(_mm_set1_ps((float)pow(2, (i8 & 0xff) - 155)))); // scale
|
||||
}
|
||||
XmmFinalize(va, rt);
|
||||
LOG_OPCODE();
|
||||
|
@ -2772,11 +2720,11 @@ private:
|
|||
const XmmLink& v1 = XmmCopy(va);
|
||||
c.cvtdq2ps(va.get(), va.get()); // convert to floats
|
||||
c.psrad(v1.get(), 32); // generate mask from sign bit
|
||||
c.andps(v1.get(), XmmConst(_mm_set1_ps(pow(2, 32)))); // generate correction component
|
||||
c.andps(v1.get(), XmmConst(_mm_set1_ps((float)pow(2, 32)))); // generate correction component
|
||||
c.addps(va.get(), v1.get()); // add correction component
|
||||
if (i8 != 155)
|
||||
{
|
||||
c.mulps(va.get(), XmmConst(_mm_set1_ps(pow(2, (i8 & 0xff) - 155)))); // scale
|
||||
c.mulps(va.get(), XmmConst(_mm_set1_ps((float)pow(2, (i8 & 0xff) - 155)))); // scale
|
||||
}
|
||||
XmmFinalize(va, rt);
|
||||
XmmFinalize(v1);
|
||||
|
@ -2798,12 +2746,19 @@ private:
|
|||
void STQA(u32 rt, s32 i16)
|
||||
{
|
||||
const u32 lsa = (i16 << 2) & 0x3fff0;
|
||||
|
||||
/*const XmmLink& vt = XmmGet(rt);
|
||||
c.pshufb(vt.get(), XmmConst(_mm_set_epi32(0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f)));
|
||||
c.movdqa(oword_ptr(*ls_var, lsa), vt.get());
|
||||
XmmFinalize(vt);*/
|
||||
|
||||
c.mov(*qw0, cpu_qword(GPR[rt]._u64[0]));
|
||||
c.mov(*qw1, cpu_qword(GPR[rt]._u64[1]));
|
||||
c.bswap(*qw0);
|
||||
c.bswap(*qw1);
|
||||
c.mov(qword_ptr(*ls_var, lsa), *qw1);
|
||||
c.mov(qword_ptr(*ls_var, lsa + 8), *qw0);
|
||||
|
||||
LOG_OPCODE();
|
||||
}
|
||||
void BRNZ(u32 rt, s32 i16)
|
||||
|
@ -2842,12 +2797,19 @@ private:
|
|||
void STQR(u32 rt, s32 i16)
|
||||
{
|
||||
const u32 lsa = branchTarget(CPU.PC, i16) & 0x3fff0;
|
||||
|
||||
/*const XmmLink& vt = XmmGet(rt);
|
||||
c.pshufb(vt.get(), XmmConst(_mm_set_epi32(0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f)));
|
||||
c.movdqa(oword_ptr(*ls_var, lsa), vt.get());
|
||||
XmmFinalize(vt);*/
|
||||
|
||||
c.mov(*qw0, cpu_qword(GPR[rt]._u64[0]));
|
||||
c.mov(*qw1, cpu_qword(GPR[rt]._u64[1]));
|
||||
c.bswap(*qw0);
|
||||
c.bswap(*qw1);
|
||||
c.mov(qword_ptr(*ls_var, lsa), *qw1);
|
||||
c.mov(qword_ptr(*ls_var, lsa + 8), *qw0);
|
||||
|
||||
LOG_OPCODE();
|
||||
}
|
||||
void BRA(s32 i16)
|
||||
|
@ -2863,12 +2825,19 @@ private:
|
|||
XmmInvalidate(rt);
|
||||
|
||||
const u32 lsa = (i16 << 2) & 0x3fff0;
|
||||
|
||||
/*const XmmLink& vt = XmmAlloc(rt);
|
||||
c.movdqa(vt.get(), oword_ptr(*ls_var, lsa));
|
||||
c.pshufb(vt.get(), XmmConst(_mm_set_epi32(0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f)));
|
||||
XmmFinalize(vt, rt);*/
|
||||
|
||||
c.mov(*qw0, qword_ptr(*ls_var, lsa));
|
||||
c.mov(*qw1, qword_ptr(*ls_var, lsa + 8));
|
||||
c.bswap(*qw0);
|
||||
c.bswap(*qw1);
|
||||
c.mov(cpu_qword(GPR[rt]._u64[0]), *qw1);
|
||||
c.mov(cpu_qword(GPR[rt]._u64[1]), *qw0);
|
||||
|
||||
LOG_OPCODE();
|
||||
}
|
||||
void BRASL(u32 rt, s32 i16)
|
||||
|
@ -2931,12 +2900,19 @@ private:
|
|||
XmmInvalidate(rt);
|
||||
|
||||
const u32 lsa = branchTarget(CPU.PC, i16) & 0x3fff0;
|
||||
|
||||
/*const XmmLink& vt = XmmAlloc(rt);
|
||||
c.movdqa(vt.get(), oword_ptr(*ls_var, lsa));
|
||||
c.pshufb(vt.get(), XmmConst(_mm_set_epi32(0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f)));
|
||||
XmmFinalize(vt, rt);*/
|
||||
|
||||
c.mov(*qw0, qword_ptr(*ls_var, lsa));
|
||||
c.mov(*qw1, qword_ptr(*ls_var, lsa + 8));
|
||||
c.bswap(*qw0);
|
||||
c.bswap(*qw1);
|
||||
c.mov(cpu_qword(GPR[rt]._u64[0]), *qw1);
|
||||
c.mov(cpu_qword(GPR[rt]._u64[1]), *qw0);
|
||||
|
||||
LOG_OPCODE();
|
||||
}
|
||||
void IL(u32 rt, s32 i16)
|
||||
|
@ -3265,12 +3241,19 @@ private:
|
|||
c.mov(*addr, cpu_dword(GPR[ra]._u32[3]));
|
||||
if (i10) c.add(*addr, i10);
|
||||
c.and_(*addr, 0x3fff0);
|
||||
|
||||
/*const XmmLink& vt = XmmGet(rt);
|
||||
c.pshufb(vt.get(), XmmConst(_mm_set_epi32(0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f)));
|
||||
c.movdqa(oword_ptr(*ls_var, *addr), vt.get());
|
||||
XmmFinalize(vt);*/
|
||||
|
||||
c.mov(*qw0, cpu_qword(GPR[rt]._u64[0]));
|
||||
c.mov(*qw1, cpu_qword(GPR[rt]._u64[1]));
|
||||
c.bswap(*qw0);
|
||||
c.bswap(*qw1);
|
||||
c.mov(qword_ptr(*ls_var, *addr, 0, 0), *qw1);
|
||||
c.mov(qword_ptr(*ls_var, *addr, 0, 8), *qw0);
|
||||
|
||||
LOG_OPCODE();
|
||||
}
|
||||
void LQD(u32 rt, s32 i10, u32 ra) // i10 is shifted left by 4 while decoding
|
||||
|
@ -3280,12 +3263,19 @@ private:
|
|||
c.mov(*addr, cpu_dword(GPR[ra]._u32[3]));
|
||||
if (i10) c.add(*addr, i10);
|
||||
c.and_(*addr, 0x3fff0);
|
||||
|
||||
/*const XmmLink& vt = XmmAlloc(rt);
|
||||
c.movdqa(vt.get(), oword_ptr(*ls_var, *addr));
|
||||
c.pshufb(vt.get(), XmmConst(_mm_set_epi32(0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f)));
|
||||
XmmFinalize(vt, rt);*/
|
||||
|
||||
c.mov(*qw0, qword_ptr(*ls_var, *addr, 0, 0));
|
||||
c.mov(*qw1, qword_ptr(*ls_var, *addr, 0, 8));
|
||||
c.bswap(*qw0);
|
||||
c.bswap(*qw1);
|
||||
c.mov(cpu_qword(GPR[rt]._u64[0]), *qw1);
|
||||
c.mov(cpu_qword(GPR[rt]._u64[1]), *qw0);
|
||||
|
||||
LOG_OPCODE();
|
||||
}
|
||||
void XORI(u32 rt, u32 ra, s32 i10)
|
||||
|
@ -3332,10 +3322,10 @@ private:
|
|||
}
|
||||
void HGTI(u32 rt, u32 ra, s32 i10)
|
||||
{
|
||||
c.mov(*addr, cpu_dword(GPR[ra]._i32[3]));
|
||||
c.mov(*addr, cpu_dword(GPR[ra]._s32[3]));
|
||||
c.cmp(*addr, i10);
|
||||
c.mov(*addr, 0);
|
||||
c.setg(*addr);
|
||||
c.setg(addr->r8());
|
||||
c.neg(*addr);
|
||||
c.mov(*pos_var, (CPU.PC >> 2) + 1);
|
||||
c.xor_(*pos_var, *addr);
|
||||
|
@ -3401,7 +3391,7 @@ private:
|
|||
c.mov(*addr, cpu_dword(GPR[ra]._u32[3]));
|
||||
c.cmp(*addr, i10);
|
||||
c.mov(*addr, 0);
|
||||
c.seta(*addr);
|
||||
c.seta(addr->r8());
|
||||
c.neg(*addr);
|
||||
c.mov(*pos_var, (CPU.PC >> 2) + 1);
|
||||
c.xor_(*pos_var, *addr);
|
||||
|
@ -3452,7 +3442,7 @@ private:
|
|||
c.mov(*addr, cpu_dword(GPR[ra]._u32[3]));
|
||||
c.cmp(*addr, i10);
|
||||
c.mov(*addr, 0);
|
||||
c.sete(*addr);
|
||||
c.sete(addr->r8());
|
||||
c.neg(*addr);
|
||||
c.mov(*pos_var, (CPU.PC >> 2) + 1);
|
||||
c.xor_(*pos_var, *addr);
|
||||
|
@ -3784,12 +3774,12 @@ private:
|
|||
|
||||
void UNK(u32 code, u32 opcode, u32 gcode)
|
||||
{
|
||||
UNK(fmt::Format("(SPURecompiler) Unimplemented opcode! (0x%08x, 0x%x, 0x%x)", code, opcode, gcode));
|
||||
UNK(fmt::Format("Unimplemented opcode! (0x%08x, 0x%x, 0x%x)", code, opcode, gcode));
|
||||
}
|
||||
|
||||
void UNK(const std::string& err)
|
||||
{
|
||||
ConLog.Error(err + fmt::Format(" #pc: 0x%x", CPU.PC));
|
||||
LOG_ERROR(Log::SPU, err + fmt::Format(" #pc: 0x%x", CPU.PC));
|
||||
c.mov(cpu_qword(PC), (u32)CPU.PC);
|
||||
do_finalize = true;
|
||||
Emu.Pause();
|
||||
|
|
|
@ -1,18 +1,34 @@
|
|||
#include "stdafx.h"
|
||||
#include "Utilities/Log.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Utilities/rFile.h"
|
||||
|
||||
#include "Emu/SysCalls/lv2/sys_time.h"
|
||||
|
||||
#include "SPUInstrTable.h"
|
||||
#include "SPUDisAsm.h"
|
||||
|
||||
#include "SPUThread.h"
|
||||
#include "SPUInterpreter.h"
|
||||
#include "SPURecompiler.h"
|
||||
|
||||
static const g_imm_table_struct g_imm_table;
|
||||
|
||||
SPURecompilerCore::SPURecompilerCore(SPUThread& cpu)
|
||||
: m_enc(new SPURecompiler(cpu, *this))
|
||||
, inter(new SPUInterpreter(cpu))
|
||||
, CPU(cpu)
|
||||
, first(true)
|
||||
: m_enc(new SPURecompiler(cpu, *this))
|
||||
, inter(new SPUInterpreter(cpu))
|
||||
, CPU(cpu)
|
||||
, first(true)
|
||||
{
|
||||
memset(entry, 0, sizeof(entry));
|
||||
X86CpuInfo inf;
|
||||
X86CpuUtil::detect(&inf);
|
||||
if (!inf.hasFeature(kX86CpuFeatureSse41))
|
||||
{
|
||||
LOG_ERROR(SPU, "SPU JIT requires SSE4.1 instruction set support");
|
||||
Emu.Pause();
|
||||
}
|
||||
}
|
||||
|
||||
SPURecompilerCore::~SPURecompilerCore()
|
||||
|
@ -32,11 +48,12 @@ void SPURecompilerCore::Compile(u16 pos)
|
|||
u64 time0 = 0;
|
||||
|
||||
SPUDisAsm dis_asm(CPUDisAsm_InterpreterMode);
|
||||
dis_asm.offset = vm::get_ptr<u8>(CPU.dmac.ls_offset);
|
||||
|
||||
StringLogger stringLogger;
|
||||
stringLogger.setOption(kLoggerOptionBinaryForm, true);
|
||||
|
||||
Compiler compiler(&runtime);
|
||||
X86Compiler compiler(&runtime);
|
||||
m_enc->compiler = &compiler;
|
||||
compiler.setLogger(&stringLogger);
|
||||
|
||||
|
@ -45,53 +62,53 @@ void SPURecompilerCore::Compile(u16 pos)
|
|||
u32 excess = 0;
|
||||
entry[start].count = 0;
|
||||
|
||||
GpVar cpu_var(compiler, kVarTypeIntPtr, "cpu");
|
||||
X86GpVar cpu_var(compiler, kVarTypeIntPtr, "cpu");
|
||||
compiler.setArg(0, cpu_var);
|
||||
compiler.alloc(cpu_var);
|
||||
m_enc->cpu_var = &cpu_var;
|
||||
|
||||
GpVar ls_var(compiler, kVarTypeIntPtr, "ls");
|
||||
X86GpVar ls_var(compiler, kVarTypeIntPtr, "ls");
|
||||
compiler.setArg(1, ls_var);
|
||||
compiler.alloc(ls_var);
|
||||
m_enc->ls_var = &ls_var;
|
||||
|
||||
GpVar imm_var(compiler, kVarTypeIntPtr, "imm");
|
||||
X86GpVar imm_var(compiler, kVarTypeIntPtr, "imm");
|
||||
compiler.setArg(2, imm_var);
|
||||
compiler.alloc(imm_var);
|
||||
m_enc->imm_var = &imm_var;
|
||||
|
||||
GpVar g_imm_var(compiler, kVarTypeIntPtr, "g_imm");
|
||||
X86GpVar g_imm_var(compiler, kVarTypeIntPtr, "g_imm");
|
||||
compiler.setArg(3, g_imm_var);
|
||||
compiler.alloc(g_imm_var);
|
||||
m_enc->g_imm_var = &g_imm_var;
|
||||
|
||||
GpVar pos_var(compiler, kVarTypeUInt32, "pos");
|
||||
X86GpVar pos_var(compiler, kVarTypeUInt32, "pos");
|
||||
m_enc->pos_var = &pos_var;
|
||||
GpVar addr_var(compiler, kVarTypeUInt32, "addr");
|
||||
X86GpVar addr_var(compiler, kVarTypeUInt32, "addr");
|
||||
m_enc->addr = &addr_var;
|
||||
GpVar qw0_var(compiler, kVarTypeUInt64, "qw0");
|
||||
X86GpVar qw0_var(compiler, kVarTypeUInt64, "qw0");
|
||||
m_enc->qw0 = &qw0_var;
|
||||
GpVar qw1_var(compiler, kVarTypeUInt64, "qw1");
|
||||
X86GpVar qw1_var(compiler, kVarTypeUInt64, "qw1");
|
||||
m_enc->qw1 = &qw1_var;
|
||||
GpVar qw2_var(compiler, kVarTypeUInt64, "qw2");
|
||||
X86GpVar qw2_var(compiler, kVarTypeUInt64, "qw2");
|
||||
m_enc->qw2 = &qw2_var;
|
||||
|
||||
for (u32 i = 0; i < 16; i++)
|
||||
{
|
||||
m_enc->xmm_var[i].data = new XmmVar(compiler, kVarTypeXmm, fmt::Format("reg_%d", i).c_str());
|
||||
m_enc->xmm_var[i].data = new X86XmmVar(compiler, kX86VarTypeXmm, fmt::Format("reg_%d", i).c_str());
|
||||
}
|
||||
|
||||
compiler.xor_(pos_var, pos_var);
|
||||
|
||||
while (true)
|
||||
{
|
||||
const u32 opcode = Memory.Read32(CPU.dmac.ls_offset + pos * 4);
|
||||
const u32 opcode = vm::read32(CPU.dmac.ls_offset + pos * 4);
|
||||
m_enc->do_finalize = false;
|
||||
if (opcode)
|
||||
{
|
||||
const u64 stamp1 = get_system_time();
|
||||
// disasm for logging:
|
||||
dis_asm.dump_pc = CPU.dmac.ls_offset + pos * 4;
|
||||
dis_asm.dump_pc = pos * 4;
|
||||
(*SPU_instr::rrr_list)(&dis_asm, opcode);
|
||||
compiler.addComment(fmt::Format("SPU data: PC=0x%05x %s", pos * 4, dis_asm.last_opcode.c_str()).c_str());
|
||||
// compile single opcode:
|
||||
|
@ -110,11 +127,11 @@ void SPURecompilerCore::Compile(u16 pos)
|
|||
m_enc->do_finalize = true;
|
||||
}
|
||||
bool fin = m_enc->do_finalize;
|
||||
if (entry[pos].valid == re(opcode))
|
||||
if (entry[pos].valid == re32(opcode))
|
||||
{
|
||||
excess++;
|
||||
}
|
||||
entry[pos].valid = re(opcode);
|
||||
entry[pos].valid = re32(opcode);
|
||||
|
||||
if (fin) break;
|
||||
CPU.PC += 4;
|
||||
|
@ -136,12 +153,27 @@ void SPURecompilerCore::Compile(u16 pos)
|
|||
entry[start].pointer = compiler.make();
|
||||
compiler.setLogger(nullptr); // crashes without it
|
||||
|
||||
wxFile log;
|
||||
log.Open(wxString::Format("SPUjit_%d.log", GetCurrentSPUThread().GetId()), first ? wxFile::write : wxFile::write_append);
|
||||
log.Write(wxString::Format("========== START POSITION 0x%x ==========\n\n", start * 4));
|
||||
log.Write(wxString(stringLogger.getString()));
|
||||
log.Write(wxString::Format("========== COMPILED %d (excess %d), time: [start=%lld (decoding=%lld), finalize=%lld]\n\n",
|
||||
entry[start].count, excess, stamp1 - stamp0, time0, get_system_time() - stamp1));
|
||||
rFile log;
|
||||
log.Open(fmt::Format("SPUjit_%d.log", GetCurrentSPUThread().GetId()), first ? rFile::write : rFile::write_append);
|
||||
log.Write(fmt::Format("========== START POSITION 0x%x ==========\n\n", start * 4));
|
||||
log.Write(std::string(stringLogger.getString()));
|
||||
if (!entry[start].pointer)
|
||||
{
|
||||
LOG_ERROR(Log::SPU, "SPURecompilerCore::Compile(pos=0x%x) failed", start * sizeof(u32));
|
||||
log.Write("========== FAILED ============\n\n");
|
||||
Emu.Pause();
|
||||
}
|
||||
else
|
||||
{
|
||||
log.Write(fmt::Format("========== COMPILED %d (excess %d), time: [start=%lld (decoding=%lld), finalize=%lld]\n\n",
|
||||
entry[start].count, excess, stamp1 - stamp0, time0, get_system_time() - stamp1));
|
||||
#ifdef _WIN32
|
||||
//if (!RtlAddFunctionTable(&info, 1, (u64)entry[start].pointer))
|
||||
//{
|
||||
// LOG_ERROR(Log::SPU, "RtlAddFunctionTable() failed");
|
||||
//}
|
||||
#endif
|
||||
}
|
||||
log.Close();
|
||||
m_enc->compiler = nullptr;
|
||||
first = false;
|
||||
|
@ -151,37 +183,40 @@ u8 SPURecompilerCore::DecodeMemory(const u64 address)
|
|||
{
|
||||
assert(CPU.dmac.ls_offset == address - CPU.PC);
|
||||
const u64 m_offset = CPU.dmac.ls_offset;
|
||||
const u16 pos = (CPU.PC >> 2);
|
||||
const u16 pos = (u16)(CPU.PC >> 2);
|
||||
|
||||
//ConLog.Write("DecodeMemory: pos=%d", pos);
|
||||
u32* ls = (u32*)&Memory[m_offset];
|
||||
|
||||
if (!pos)
|
||||
{
|
||||
ConLog.Error("SPURecompilerCore::DecodeMemory(): ls_addr = 0");
|
||||
Emu.Pause();
|
||||
return 0;
|
||||
}
|
||||
u32* ls = vm::get_ptr<u32>(m_offset);
|
||||
|
||||
if (entry[pos].pointer)
|
||||
{
|
||||
// check data (hard way)
|
||||
bool is_valid = true;
|
||||
/*for (u32 i = pos; i < (u32)(entry[pos].count + pos); i++)
|
||||
{
|
||||
if (entry[i].valid != ls[i])
|
||||
{
|
||||
is_valid = false;
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
//for (u32 i = pos; i < (u32)(entry[pos].count + pos); i++)
|
||||
//{
|
||||
// if (entry[i].valid != ls[i])
|
||||
// {
|
||||
// is_valid = false;
|
||||
// break;
|
||||
// }
|
||||
//}
|
||||
// invalidate if necessary
|
||||
if (!is_valid)
|
||||
{
|
||||
// TODO
|
||||
ConLog.Error("SPURecompilerCore::DecodeMemory(ls_addr=0x%x): code has changed", pos * sizeof(u32));
|
||||
Emu.Pause();
|
||||
return 0;
|
||||
for (u32 i = 0; i < 0x10000; i++)
|
||||
{
|
||||
if (entry[i].pointer &&
|
||||
i + (u32)entry[i].count > (u32)pos &&
|
||||
i < (u32)pos + (u32)entry[pos].count)
|
||||
{
|
||||
runtime.release(entry[i].pointer);
|
||||
#ifdef _WIN32
|
||||
//RtlDeleteFunctionTable(&entry[i].info);
|
||||
#endif
|
||||
entry[i].pointer = nullptr;
|
||||
}
|
||||
}
|
||||
//LOG_ERROR(Log::SPU, "SPURecompilerCore::DecodeMemory(ls_addr=0x%x): code has changed", pos * sizeof(u32));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -192,18 +227,13 @@ u8 SPURecompilerCore::DecodeMemory(const u64 address)
|
|||
did_compile = true;
|
||||
if (entry[pos].valid == 0)
|
||||
{
|
||||
ConLog.Error("SPURecompilerCore::Compile(ls_addr=0x%x): branch to 0x0 opcode", pos * sizeof(u32));
|
||||
LOG_ERROR(Log::SPU, "SPURecompilerCore::Compile(ls_addr=0x%x): branch to 0x0 opcode", pos * sizeof(u32));
|
||||
Emu.Pause();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!entry[pos].pointer)
|
||||
{
|
||||
ConLog.Error("SPURecompilerCore::DecodeMemory(ls_addr=0x%x): compilation failed", pos * sizeof(u32));
|
||||
Emu.Pause();
|
||||
return 0;
|
||||
}
|
||||
if (!entry[pos].pointer) return 0;
|
||||
|
||||
typedef u32(*Func)(const void* _cpu, const void* _ls, const void* _imm, const void* _g_imm);
|
||||
|
||||
|
@ -217,15 +247,16 @@ u8 SPURecompilerCore::DecodeMemory(const u64 address)
|
|||
//if (pos == 0x19c >> 2)
|
||||
{
|
||||
//Emu.Pause();
|
||||
//for (uint i = 0; i < 128; ++i) ConLog.Write("r%d = 0x%s", i, CPU.GPR[i].ToString().c_str());
|
||||
//for (uint i = 0; i < 128; ++i) LOG_NOTICE(Log::SPU, "r%d = 0x%s", i, CPU.GPR[i].ToString().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
u32 res = pos;
|
||||
res = func(cpu, &Memory[m_offset], imm_table.data(), &g_imm_table);
|
||||
res = func(cpu, vm::get_ptr<void>(m_offset), imm_table.data(), &g_imm_table);
|
||||
|
||||
if (res > 0xffff)
|
||||
{
|
||||
CPU.SPU.Status.SetValue(SPU_STATUS_STOPPED_BY_HALT);
|
||||
CPU.Stop();
|
||||
res = ~res;
|
||||
}
|
||||
|
@ -236,7 +267,7 @@ u8 SPURecompilerCore::DecodeMemory(const u64 address)
|
|||
//if (pos == 0x340 >> 2)
|
||||
{
|
||||
//Emu.Pause();
|
||||
//for (uint i = 0; i < 128; ++i) ConLog.Write("r%d = 0x%s", i, CPU.GPR[i].ToString().c_str());
|
||||
//for (uint i = 0; i < 128; ++i) LOG_NOTICE(Log::SPU, "r%d = 0x%s", i, CPU.GPR[i].ToString().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
14
rpcs3/Emu/DbgCommand.cpp
Normal file
14
rpcs3/Emu/DbgCommand.cpp
Normal file
|
@ -0,0 +1,14 @@
|
|||
#include "stdafx.h"
|
||||
#include "DbgCommand.h"
|
||||
|
||||
SendDbgCommandCb SendDbgCommandFunc = nullptr;
|
||||
|
||||
void SendDbgCommand(DbgCommand id, CPUThread* t)
|
||||
{
|
||||
SendDbgCommandFunc(id, t);
|
||||
}
|
||||
|
||||
void SetSendDbgCommandCallback(SendDbgCommandCb cb)
|
||||
{
|
||||
SendDbgCommandFunc = cb;
|
||||
}
|
44
rpcs3/Emu/DbgCommand.h
Normal file
44
rpcs3/Emu/DbgCommand.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
#pragma once
|
||||
|
||||
class CPUThread;
|
||||
|
||||
enum DbgCommand
|
||||
{
|
||||
DID_FIRST_COMMAND = 0x500,
|
||||
|
||||
DID_START_EMU,
|
||||
DID_STARTED_EMU,
|
||||
DID_STOP_EMU,
|
||||
DID_STOPPED_EMU,
|
||||
DID_PAUSE_EMU,
|
||||
DID_PAUSED_EMU,
|
||||
DID_RESUME_EMU,
|
||||
DID_RESUMED_EMU,
|
||||
DID_READY_EMU,
|
||||
DID_CREATE_THREAD,
|
||||
DID_CREATED_THREAD,
|
||||
DID_REMOVE_THREAD,
|
||||
DID_REMOVED_THREAD,
|
||||
DID_RENAME_THREAD,
|
||||
DID_RENAMED_THREAD,
|
||||
DID_START_THREAD,
|
||||
DID_STARTED_THREAD,
|
||||
DID_STOP_THREAD,
|
||||
DID_STOPED_THREAD,
|
||||
DID_PAUSE_THREAD,
|
||||
DID_PAUSED_THREAD,
|
||||
DID_RESUME_THREAD,
|
||||
DID_RESUMED_THREAD,
|
||||
DID_EXEC_THREAD,
|
||||
DID_REGISTRED_CALLBACK,
|
||||
DID_UNREGISTRED_CALLBACK,
|
||||
DID_EXIT_THR_SYSCALL,
|
||||
|
||||
DID_LAST_COMMAND,
|
||||
};
|
||||
|
||||
typedef void(*SendDbgCommandCb)(DbgCommand id, CPUThread* t);
|
||||
|
||||
void SetSendDbgCommandCallback(SendDbgCommandCb value);
|
||||
|
||||
void SendDbgCommand(DbgCommand id, CPUThread* thr = nullptr);
|
|
@ -1,94 +0,0 @@
|
|||
#include "stdafx.h"
|
||||
#include "DbgConsole.h"
|
||||
|
||||
BEGIN_EVENT_TABLE(DbgConsole, FrameBase)
|
||||
EVT_CLOSE(DbgConsole::OnQuit)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
DbgConsole::DbgConsole()
|
||||
: FrameBase(nullptr, wxID_ANY, "Debug Console", "", wxDefaultSize, wxDefaultPosition, wxDEFAULT_FRAME_STYLE, true)
|
||||
, ThreadBase("DbgConsole thread")
|
||||
, m_output(nullptr)
|
||||
{
|
||||
m_console = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition,
|
||||
wxSize(500, 500), wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH2);
|
||||
m_console->SetBackgroundColour(wxColor("Black"));
|
||||
m_console->SetFont(wxFont(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));
|
||||
|
||||
m_color_white = new wxTextAttr(wxColour(255, 255, 255));
|
||||
m_color_red = new wxTextAttr(wxColour(255, 0, 0));
|
||||
|
||||
if (Ini.HLESaveTTY.GetValue())
|
||||
m_output = new wxFile("tty.log", wxFile::write);
|
||||
}
|
||||
|
||||
DbgConsole::~DbgConsole()
|
||||
{
|
||||
ThreadBase::Stop();
|
||||
m_dbg_buffer.Flush();
|
||||
|
||||
safe_delete(m_console);
|
||||
safe_delete(m_color_white);
|
||||
safe_delete(m_color_red);
|
||||
safe_delete(m_output);
|
||||
}
|
||||
|
||||
void DbgConsole::Write(int ch, const std::string& text)
|
||||
{
|
||||
while (m_dbg_buffer.IsBusy())
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
return;
|
||||
}
|
||||
Sleep(1);
|
||||
}
|
||||
m_dbg_buffer.Push(DbgPacket(ch, text));
|
||||
|
||||
if(!IsAlive()) Start();
|
||||
}
|
||||
|
||||
void DbgConsole::Clear()
|
||||
{
|
||||
m_console->Clear();
|
||||
}
|
||||
|
||||
void DbgConsole::Task()
|
||||
{
|
||||
while(!TestDestroy())
|
||||
{
|
||||
if(!m_dbg_buffer.HasNewPacket())
|
||||
{
|
||||
if (Emu.IsStopped())
|
||||
{
|
||||
break;
|
||||
}
|
||||
Sleep(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
DbgPacket packet = m_dbg_buffer.Pop();
|
||||
m_console->SetDefaultStyle(packet.m_ch == 1 ? *m_color_red : *m_color_white);
|
||||
m_console->SetInsertionPointEnd();
|
||||
m_console->WriteText(fmt::FromUTF8(packet.m_text));
|
||||
|
||||
if (m_output && Ini.HLESaveTTY.GetValue())
|
||||
m_output->Write(fmt::FromUTF8(packet.m_text));
|
||||
|
||||
if(!DbgConsole::IsShown()) Show();
|
||||
}
|
||||
}
|
||||
|
||||
void DbgConsole::OnQuit(wxCloseEvent& event)
|
||||
{
|
||||
ThreadBase::Stop(false);
|
||||
Hide();
|
||||
|
||||
if (m_output)
|
||||
{
|
||||
m_output->Close();
|
||||
m_output = nullptr;
|
||||
}
|
||||
|
||||
//event.Skip();
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
struct DbgPacket
|
||||
{
|
||||
int m_ch;
|
||||
std::string m_text;
|
||||
|
||||
DbgPacket(int ch, const std::string& text)
|
||||
: m_ch(ch)
|
||||
, m_text(text)
|
||||
{
|
||||
}
|
||||
|
||||
DbgPacket()
|
||||
{
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
m_text.clear();
|
||||
}
|
||||
};
|
||||
|
||||
struct _DbgBuffer : public MTPacketBuffer<DbgPacket>
|
||||
{
|
||||
_DbgBuffer() : MTPacketBuffer<DbgPacket>(1024)
|
||||
{
|
||||
}
|
||||
|
||||
void _push(const DbgPacket& data)
|
||||
{
|
||||
const u32 stext = data.m_text.length();
|
||||
|
||||
m_buffer.resize(m_buffer.size() + sizeof(int) + sizeof(u32) + stext);
|
||||
|
||||
u32 c_put = m_put;
|
||||
|
||||
memcpy(&m_buffer[c_put], &data.m_ch, sizeof(int));
|
||||
c_put += sizeof(int);
|
||||
|
||||
memcpy(&m_buffer[c_put], &stext, sizeof(u32));
|
||||
c_put += sizeof(u32);
|
||||
memcpy(&m_buffer[c_put], data.m_text.data(), stext);
|
||||
c_put += stext;
|
||||
|
||||
m_put = c_put;
|
||||
CheckBusy();
|
||||
}
|
||||
|
||||
DbgPacket _pop()
|
||||
{
|
||||
DbgPacket ret;
|
||||
|
||||
u32 c_get = m_get;
|
||||
|
||||
ret.m_ch = *(int*)&m_buffer[c_get];
|
||||
c_get += sizeof(int);
|
||||
|
||||
const u32& stext = *(u32*)&m_buffer[c_get];
|
||||
c_get += sizeof(u32);
|
||||
if (stext) ret.m_text = std::string(reinterpret_cast<const char*>(&m_buffer[c_get]), stext );
|
||||
c_get += stext;
|
||||
|
||||
m_get = c_get;
|
||||
if(!HasNewPacket()) Flush();
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
class DbgConsole
|
||||
: public FrameBase
|
||||
, public ThreadBase
|
||||
{
|
||||
wxFile* m_output;
|
||||
wxTextCtrl* m_console;
|
||||
wxTextAttr* m_color_white;
|
||||
wxTextAttr* m_color_red;
|
||||
_DbgBuffer m_dbg_buffer;
|
||||
|
||||
public:
|
||||
DbgConsole();
|
||||
~DbgConsole();
|
||||
void Write(int ch, const std::string& text);
|
||||
void Clear();
|
||||
virtual void Task();
|
||||
|
||||
private:
|
||||
void OnQuit(wxCloseEvent& event);
|
||||
DECLARE_EVENT_TABLE();
|
||||
};
|
|
@ -1,9 +1,10 @@
|
|||
#include "stdafx.h"
|
||||
#include "event.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
//#include "Emu/System.h"
|
||||
#include "Event.h"
|
||||
|
||||
void EventManager::Init()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void EventManager::Clear()
|
||||
|
@ -14,7 +15,7 @@ void EventManager::Clear()
|
|||
bool EventManager::CheckKey(u64 key)
|
||||
{
|
||||
if (!key) return true;
|
||||
SMutexLocker lock(m_lock);
|
||||
std::lock_guard<std::mutex> lock(m_lock);
|
||||
|
||||
return key_map.find(key) != key_map.end();
|
||||
}
|
||||
|
@ -22,7 +23,7 @@ bool EventManager::CheckKey(u64 key)
|
|||
bool EventManager::RegisterKey(EventQueue* data, u64 key)
|
||||
{
|
||||
if (!key) return true;
|
||||
SMutexLocker lock(m_lock);
|
||||
std::lock_guard<std::mutex> lock(m_lock);
|
||||
|
||||
if (key_map.find(key) != key_map.end()) return false;
|
||||
|
||||
|
@ -40,7 +41,7 @@ bool EventManager::GetEventQueue(u64 key, EventQueue*& data)
|
|||
{
|
||||
data = nullptr;
|
||||
if (!key) return false;
|
||||
SMutexLocker lock(m_lock);
|
||||
std::lock_guard<std::mutex> lock(m_lock);
|
||||
|
||||
auto f = key_map.find(key);
|
||||
if (f != key_map.end())
|
||||
|
@ -54,7 +55,7 @@ bool EventManager::GetEventQueue(u64 key, EventQueue*& data)
|
|||
bool EventManager::UnregisterKey(u64 key)
|
||||
{
|
||||
if (!key) return false;
|
||||
SMutexLocker lock(m_lock);
|
||||
std::lock_guard<std::mutex> lock(m_lock);
|
||||
|
||||
auto f = key_map.find(key);
|
||||
if (f != key_map.end())
|
||||
|
@ -68,7 +69,7 @@ bool EventManager::UnregisterKey(u64 key)
|
|||
bool EventManager::SendEvent(u64 key, u64 source, u64 d1, u64 d2, u64 d3)
|
||||
{
|
||||
if (!key) return false;
|
||||
SMutexLocker lock(m_lock);
|
||||
std::lock_guard<std::mutex> lock(m_lock);
|
||||
|
||||
auto f = key_map.find(key);
|
||||
if (f == key_map.end())
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue