Merge pull request #775 from Nekotekina/master

Many changez
This commit is contained in:
Alexandro Sánchez Bach 2014-08-24 01:00:16 +02:00
commit 6f0531b3f7
233 changed files with 8712 additions and 6671 deletions

View file

@ -1,5 +1,8 @@
#include "stdafx.h" #include "stdafx.h"
#include "rpcs3/Ini.h"
#include "AutoPause.h" #include "AutoPause.h"
#include "Utilities/Log.h"
#include "Emu/System.h"
using namespace Debug; using namespace Debug;

View file

@ -1,7 +1,4 @@
#pragma once #pragma once
#include "Utilities/Log.h"
#include "Utilities/rFile.h"
#include "Emu/System.h"
//Regarded as a Debugger Enchantment //Regarded as a Debugger Enchantment
namespace Debug { namespace Debug {

View file

@ -1,17 +1,14 @@
#pragma once #pragma once
#include "Utilities/GNU.h"
#include <algorithm> #include <algorithm>
using std::min; using std::min;
using std::max; using std::max;
//#define re(val) MemoryBase::Reverse(val) #define re16(val) _byteswap_ushort(val)
#define re64(val) MemoryBase::Reverse64(val) #define re32(val) _byteswap_ulong(val)
#define re32(val) MemoryBase::Reverse32(val) #define re64(val) _byteswap_uint64(val)
#define re16(val) MemoryBase::Reverse16(val) #define re128(val) u128::byteswap(val)
#define re128(val) MemoryBase::Reverse128(val)
template<typename T, int size = sizeof(T)> struct se_t; 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, 1> { static __forceinline void func(T& dst, const T src) { (u8&)dst = (u8&)src; } };

View file

@ -7,9 +7,9 @@
#endif #endif
#ifdef _WIN32 #ifdef _WIN32
#define noinline __declspec(noinline) #define __noinline __declspec(noinline)
#else #else
#define noinline __attribute__((noinline)) #define __noinline __attribute__((noinline))
#endif #endif
template<size_t size> template<size_t size>

View file

@ -1,6 +1,7 @@
#include "stdafx.h" #include "stdafx.h"
#include "rPlatform.h" #include "rPlatform.h"
#include "Log.h" #include "Log.h"
#include "rMsgBox.h"
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <cinttypes> #include <cinttypes>

View file

@ -1,12 +1,15 @@
#include <stdafx.h> #include <stdafx.h>
#include "Utilities/Log.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/CPU/CPUThread.h" #include "Emu/CPU/CPUThread.h"
#include "Utilities/SMutex.h" #include "Utilities/SMutex.h"
__forceinline void SM_Sleep() bool SM_IsAborted()
{
return Emu.IsStopped();
}
void SM_Sleep()
{ {
if (NamedThreadBase* t = GetCurrentNamedThread()) if (NamedThreadBase* t = GetCurrentNamedThread())
{ {
@ -20,12 +23,12 @@ __forceinline void SM_Sleep()
thread_local size_t g_this_thread_id = 0; thread_local size_t g_this_thread_id = 0;
__forceinline size_t SM_GetCurrentThreadId() 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()); 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()) if (CPUThread* t = GetCurrentCPUThread())
{ {
@ -34,7 +37,7 @@ __forceinline u32 SM_GetCurrentCPUThreadId()
return 0; return 0;
} }
__forceinline be_t<u32> SM_GetCurrentCPUThreadIdBE() be_t<u32> SM_GetCurrentCPUThreadIdBE()
{ {
return be_t<u32>::MakeFromLE(SM_GetCurrentCPUThreadId()); return be_t<u32>::MakeFromLE(SM_GetCurrentCPUThreadId());
} }

View file

@ -1,11 +1,10 @@
#pragma once #pragma once
#include "BEType.h"
#include "Emu/System.h"
extern void SM_Sleep(); bool SM_IsAborted();
extern size_t SM_GetCurrentThreadId(); void SM_Sleep();
extern u32 SM_GetCurrentCPUThreadId(); size_t SM_GetCurrentThreadId();
extern be_t<u32> SM_GetCurrentCPUThreadIdBE(); u32 SM_GetCurrentCPUThreadId();
be_t<u32> SM_GetCurrentCPUThreadIdBE();
enum SMutexResult enum SMutexResult
{ {
@ -66,7 +65,7 @@ public:
SMutexResult trylock(T tid) SMutexResult trylock(T tid)
{ {
if (Emu.IsStopped()) if (SM_IsAborted())
{ {
return SMR_ABORT; return SMR_ABORT;
} }
@ -90,7 +89,7 @@ public:
SMutexResult unlock(T tid, T to = GetFreeValue()) SMutexResult unlock(T tid, T to = GetFreeValue())
{ {
if (Emu.IsStopped()) if (SM_IsAborted())
{ {
return SMR_ABORT; return SMR_ABORT;
} }
@ -148,10 +147,9 @@ public:
{ {
if (!tid) if (!tid)
{ {
if (!Emu.IsStopped()) if (!SM_IsAborted())
{ {
LOG_ERROR(HLE, "SMutexLockerBase: thread id == 0"); assert(!"SMutexLockerBase: thread id == 0");
Emu.Pause();
} }
return; return;
} }

View file

@ -1,5 +1,7 @@
#pragma once #pragma once
#include "Utilities/SMutex.h"
template<typename T, u32 SQSize = 666> template<typename T, u32 SQSize = 666>
class SQueue class SQueue
{ {

View file

@ -12,6 +12,11 @@ NamedThreadBase* GetCurrentNamedThread()
return g_tls_this_thread; return g_tls_this_thread;
} }
void SetCurrentNamedThread(NamedThreadBase* value)
{
g_tls_this_thread = value;
}
std::string NamedThreadBase::GetThreadName() const std::string NamedThreadBase::GetThreadName() const
{ {
return m_name; return m_name;
@ -47,32 +52,27 @@ void ThreadBase::Start()
m_destroy = false; m_destroy = false;
m_alive = true; m_alive = true;
m_executor = new std::thread( m_executor = new std::thread([this]()
[this]() {
SetCurrentNamedThread(this);
g_thread_count++;
try
{ {
g_tls_this_thread = this; Task();
g_thread_count++; }
catch (const std::string& e)
{
LOG_ERROR(GENERAL, "Exception: %s", e.c_str());
}
catch (const char* e)
{
LOG_ERROR(GENERAL, "Exception: %s", e);
}
try m_alive = false;
{ g_thread_count--;
Task(); });
}
catch (const std::string& e)
{
LOG_ERROR(GENERAL, "Exception: %s", e.c_str());
}
catch (const char* e)
{
LOG_ERROR(GENERAL, "Exception: %s", e);
}
catch (int exitcode)
{
LOG_SUCCESS(GENERAL, "Exit Code: %d", exitcode);
}
m_alive = false;
g_thread_count--;
});
} }
void ThreadBase::Stop(bool wait, bool send_destroy) void ThreadBase::Stop(bool wait, bool send_destroy)
@ -141,7 +141,7 @@ void thread::start(std::function<void()> func)
m_thr = std::thread([func, name]() m_thr = std::thread([func, name]()
{ {
NamedThreadBase info(name); NamedThreadBase info(name);
g_tls_this_thread = &info; SetCurrentNamedThread(&info);
g_thread_count++; g_thread_count++;
try try

View file

@ -5,7 +5,7 @@
#include <mutex> #include <mutex>
#include <atomic> #include <atomic>
#include <condition_variable> #include <condition_variable>
#include <Utilities/SSemaphore.h> //#include <Utilities/SSemaphore.h>
static std::thread::id main_thread; static std::thread::id main_thread;
@ -48,6 +48,7 @@ public:
}; };
NamedThreadBase* GetCurrentNamedThread(); NamedThreadBase* GetCurrentNamedThread();
void SetCurrentNamedThread(NamedThreadBase* value);
class ThreadBase : public NamedThreadBase class ThreadBase : public NamedThreadBase
{ {

View file

@ -1,4 +1,5 @@
#include "stdafx.h" #include "stdafx.h"
#include "Log.h"
#include <wx/dir.h> #include <wx/dir.h>
#ifdef _WIN32 #ifdef _WIN32

View file

@ -1,4 +1,5 @@
#include "stdafx.h" #include "stdafx.h"
#include "rMsgBox.h"
#ifndef QT_UI #ifndef QT_UI
rMessageDialog::rMessageDialog(void *parent, const std::string& msg, const std::string& title , long style ) rMessageDialog::rMessageDialog(void *parent, const std::string& msg, const std::string& title , long style )

View file

@ -1,4 +1,5 @@
#include "stdafx.h" #include "stdafx.h"
#include "rTime.h"
#include <wx/datetime.h> #include <wx/datetime.h>

View file

@ -1,6 +1,20 @@
#include "stdafx.h" #include "stdafx.h"
#include "utils.h"
#include "aes.h"
#include "key_vault.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() KeyVault::KeyVault()
{ {
} }

View file

@ -1,5 +1,4 @@
#pragma once #pragma once
#include "utils.h"
enum SELF_KEY_TYPE { enum SELF_KEY_TYPE {
KEY_LV0 = 1, KEY_LV0 = 1,
@ -22,17 +21,7 @@ struct SELF_KEY {
u8 priv[0x15]; u8 priv[0x15];
u32 curve_type; 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) 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;
}
}; };
static u8 PKG_AES_KEY[0x10] = { static u8 PKG_AES_KEY[0x10] = {

View file

@ -1,4 +1,6 @@
#include "stdafx.h" #include "stdafx.h"
#include "utils.h"
#include "key_vault.h"
#include "unedat.h" #include "unedat.h"
#include "Utilities/Log.h" #include "Utilities/Log.h"

View file

@ -1,6 +1,4 @@
#pragma once #pragma once
#include "utils.h"
#include "key_vault.h"
#define SDAT_FLAG 0x01000000 #define SDAT_FLAG 0x01000000
#define EDAT_COMPRESSED_FLAG 0x00000001 #define EDAT_COMPRESSED_FLAG 0x00000001

View file

@ -1,4 +1,8 @@
#include "stdafx.h" #include "stdafx.h"
#include "utils.h"
#include "aes.h"
#include "sha1.h"
#include "key_vault.h"
#include "unpkg.h" #include "unpkg.h"
#include <wx/progdlg.h> #include <wx/progdlg.h>

View file

@ -1,6 +1,4 @@
#pragma once #pragma once
#include "utils.h"
#include "key_vault.h"
// Constants // Constants
#define PKG_HEADER_SIZE 0xC0 //sizeof(pkg_header) + sizeof(pkg_unk_checksum) #define PKG_HEADER_SIZE 0xC0 //sizeof(pkg_header) + sizeof(pkg_unk_checksum)

View file

@ -1,8 +1,317 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h" #include "Utilities/Log.h"
#include "aes.h"
#include "sha1.h"
#include "utils.h"
#include "Emu/FS/vfsLocalFile.h" #include "Emu/FS/vfsLocalFile.h"
#include "unself.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(&section_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) SELFDecrypter::SELFDecrypter(vfsStream& s)
: self_f(s), key_v(), data_buf_length(0) : self_f(s), key_v(), data_buf_length(0)
{ {

View file

@ -1,10 +1,8 @@
#pragma once #pragma once
#include "utils.h"
#include "key_vault.h"
#include "Loader/ELF.h"
#include "Loader/SELF.h" #include "Loader/SELF.h"
#include <wx/mstream.h> #include "Loader/ELF.h"
#include <wx/zstream.h> #include "key_vault.h"
struct AppInfo struct AppInfo
{ {
@ -14,22 +12,9 @@ struct AppInfo
u64 version; u64 version;
u64 padding; u64 padding;
void Load(vfsStream& f) void Load(vfsStream& f);
{
authid = Read64(f);
vendor_id = Read32(f);
self_type = Read32(f);
version = Read64(f);
padding = Read64(f);
}
void Show() void 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);
}
}; };
struct SectionInfo struct SectionInfo
@ -41,25 +26,9 @@ struct SectionInfo
u32 unknown2; u32 unknown2;
u32 encrypted; u32 encrypted;
void Load(vfsStream& f) void Load(vfsStream& f);
{
offset = Read64(f);
size = Read64(f);
compressed = Read32(f);
unknown1 = Read32(f);
unknown2 = Read32(f);
encrypted = Read32(f);
}
void Show() void 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);
}
}; };
struct SCEVersionInfo struct SCEVersionInfo
@ -69,21 +38,9 @@ struct SCEVersionInfo
u32 size; u32 size;
u32 unknown; u32 unknown;
void Load(vfsStream& f) void Load(vfsStream& f);
{
subheader_type = Read32(f);
present = Read32(f);
size = Read32(f);
unknown = Read32(f);
}
void Show() void 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);
}
}; };
struct ControlInfo struct ControlInfo
@ -133,122 +90,9 @@ struct ControlInfo
} npdrm; } npdrm;
}; };
void Load(vfsStream& f) void Load(vfsStream& f);
{
type = Read32(f);
size = Read32(f);
next = Read64(f);
if (type == 1) void Show();
{
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()
{
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);
}
}
}; };
@ -259,33 +103,9 @@ struct MetadataInfo
u8 iv[0x10]; u8 iv[0x10];
u8 iv_pad[0x10]; u8 iv_pad[0x10];
void Load(u8* in) 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 Show() 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]);
}
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());
}
}; };
struct MetadataHeader struct MetadataHeader
@ -298,36 +118,9 @@ struct MetadataHeader
u32 unknown2; u32 unknown2;
u32 unknown3; u32 unknown3;
void Load(u8* in) void Load(u8* in);
{
memcpy(&signature_input_length, in, 8);
memcpy(&unknown1, in + 8, 4);
memcpy(&section_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. void Show();
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()
{
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);
}
}; };
struct MetadataSectionHeader struct MetadataSectionHeader
@ -343,45 +136,9 @@ struct MetadataSectionHeader
u32 iv_idx; u32 iv_idx;
u32 compressed; u32 compressed;
void Load(u8* in) 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);
// Endian swap. void Show();
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()
{
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);
}
}; };
struct SectionHash { struct SectionHash {
@ -389,12 +146,7 @@ struct SectionHash {
u8 padding[12]; u8 padding[12];
u8 hmac_key[64]; u8 hmac_key[64];
void Load(vfsStream& f) void Load(vfsStream& f);
{
f.Read(sha1, 20);
f.Read(padding, 12);
f.Read(hmac_key, 64);
}
}; };
struct CapabilitiesInfo struct CapabilitiesInfo
@ -409,18 +161,7 @@ struct CapabilitiesInfo
u32 unknown4; u32 unknown4;
u32 unknown5; u32 unknown5;
void Load(vfsStream& f) 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);
}
}; };
struct Signature struct Signature
@ -429,12 +170,7 @@ struct Signature
u8 s[21]; u8 s[21];
u8 padding[6]; u8 padding[6];
void Load(vfsStream& f) void Load(vfsStream& f);
{
f.Read(r, 21);
f.Read(s, 21);
f.Read(padding, 6);
}
}; };
struct SelfSection struct SelfSection
@ -443,12 +179,7 @@ struct SelfSection
u64 size; u64 size;
u64 offset; u64 offset;
void Load(vfsStream& f) void Load(vfsStream& f);
{
*data = Read32(f);
size = Read64(f);
offset = Read64(f);
}
}; };
class SELFDecrypter class SELFDecrypter

View file

@ -1,4 +1,6 @@
#include "stdafx.h" #include "stdafx.h"
#include "aes.h"
#include "sha1.h"
#include "utils.h" #include "utils.h"
// Endian swap auxiliary functions. // Endian swap auxiliary functions.

View file

@ -1,6 +1,4 @@
#pragma once #pragma once
#include "aes.h"
#include "sha1.h"
// Auxiliary functions (endian swap and xor). // Auxiliary functions (endian swap and xor).
u16 swap16(u16 i); u16 swap16(u16 i);

View file

@ -1,7 +1,6 @@
#pragma once #pragma once
#include "Emu/ARMv7/ARMv7Opcodes.h" #include "Emu/ARMv7/ARMv7Opcodes.h"
#include "Emu/CPU/CPUDisAsm.h" #include "Emu/CPU/CPUDisAsm.h"
#include "Emu/Memory/Memory.h"
static const char* g_arm_cond_name[16] = static const char* g_arm_cond_name[16] =
{ {

View file

@ -1,8 +1,8 @@
#include "stdafx.h" #include "stdafx.h"
#include "rpcs3/Ini.h"
#include "Utilities/Log.h" #include "Utilities/Log.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/Cell/PPCThread.h"
#include "ARMv7Thread.h" #include "ARMv7Thread.h"
#include "ARMv7Decoder.h" #include "ARMv7Decoder.h"

View file

@ -1,7 +1,5 @@
#pragma once #pragma once
#include "Emu/Memory/Memory.h"
enum CPUDisAsmMode enum CPUDisAsmMode
{ {
CPUDisAsm_DumpMode, CPUDisAsm_DumpMode,
@ -21,18 +19,18 @@ protected:
{ {
case CPUDisAsm_DumpMode: case CPUDisAsm_DumpMode:
last_opcode = fmt::Format("\t%08llx:\t%02x %02x %02x %02x\t%s\n", dump_pc, last_opcode = fmt::Format("\t%08llx:\t%02x %02x %02x %02x\t%s\n", dump_pc,
Memory.Read8(offset + dump_pc), offset[dump_pc],
Memory.Read8(offset + dump_pc + 1), offset[dump_pc + 1],
Memory.Read8(offset + dump_pc + 2), offset[dump_pc + 2],
Memory.Read8(offset + dump_pc + 3), value.c_str()); offset[dump_pc + 3], value.c_str());
break; break;
case CPUDisAsm_InterpreterMode: case CPUDisAsm_InterpreterMode:
last_opcode = fmt::Format("[%08llx] %02x %02x %02x %02x: %s", dump_pc, last_opcode = fmt::Format("[%08llx] %02x %02x %02x %02x: %s", dump_pc,
Memory.Read8(offset + dump_pc), offset[dump_pc],
Memory.Read8(offset + dump_pc + 1), offset[dump_pc + 1],
Memory.Read8(offset + dump_pc + 2), offset[dump_pc + 2],
Memory.Read8(offset + dump_pc + 3), value.c_str()); offset[dump_pc + 3], value.c_str());
break; break;
case CPUDisAsm_CompilerElfMode: case CPUDisAsm_CompilerElfMode:
@ -44,7 +42,7 @@ protected:
public: public:
std::string last_opcode; std::string last_opcode;
u64 dump_pc; u64 dump_pc;
u64 offset; u8* offset;
protected: protected:
CPUDisAsm(CPUDisAsmMode mode) CPUDisAsm(CPUDisAsmMode mode)

View file

@ -1,16 +1,14 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/SysCalls/ErrorCodes.h" #include "rpcs3/Ini.h"
#include "Emu/SysCalls/SysCalls.h" #include "Emu/SysCalls/SysCalls.h"
#include "Utilities/Log.h" #include "Utilities/Log.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/DbgCommand.h" #include "Emu/DbgCommand.h"
#include "rpcs3/Ini.h"
#include "CPUDecoder.h"
#include "CPUThread.h" #include "CPUThread.h"
reservation_struct reservation;
CPUThread* GetCurrentCPUThread() CPUThread* GetCurrentCPUThread()
{ {
return (CPUThread*)GetCurrentNamedThread(); return (CPUThread*)GetCurrentNamedThread();
@ -38,6 +36,10 @@ CPUThread::~CPUThread()
safe_delete(m_dec); 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() void CPUThread::Close()
{ {
ThreadBase::Stop(m_sync_wait); ThreadBase::Stop(m_sync_wait);

View file

@ -1,30 +1,4 @@
#pragma once #pragma once
#include "Emu/Memory/MemoryBlock.h"
#include "Emu/CPU/CPUDecoder.h"
#include "Utilities/SMutex.h"
typedef SMutexBase<u32, 0, 0xffffffff, /* busy wait: specify nullptr */ SM_Sleep> SMutexR;
typedef SMutexLockerBase<SMutexR, u32, SM_GetCurrentCPUThreadId> SMutexLockerR;
struct reservation_struct
{
SMutexR mutex; // mutex for updating reservation_owner and data
// std::mutex doesn't work because it probably wakes up waiting threads in the most unwanted order
// and doesn't give a chance to finish some work before losing the reservation
u32 owner; // id of thread that got reservation
u64 addr;
u32 size;
u32 data32;
u64 data64;
u128 data[8];
__forceinline void clear()
{
owner = 0;
}
};
extern reservation_struct reservation;
enum CPUThreadType :unsigned char enum CPUThreadType :unsigned char
{ {
@ -45,6 +19,8 @@ enum CPUThreadStatus
CPUThread_Step, CPUThread_Step,
}; };
class CPUDecoder;
class CPUThread : public ThreadBase class CPUThread : public ThreadBase
{ {
protected: protected:
@ -170,13 +146,13 @@ public:
static std::vector<std::string> ErrorToString(const u32 error); static std::vector<std::string> ErrorToString(const u32 error);
std::vector<std::string> ErrorToString() { return ErrorToString(m_error); } std::vector<std::string> ErrorToString() { return ErrorToString(m_error); }
bool IsOk() const { return m_error == 0; } bool IsOk() const { return m_error == 0; }
bool IsRunning() const { return m_status == Running; } bool IsRunning() const;
bool IsPaused() const { return m_status == Paused; } bool IsPaused() const;
bool IsStopped() const { return m_status == Stopped; } bool IsStopped() const;
bool IsJoinable() const { return m_joinable; } 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 SetJoinable(bool joinable) { m_joinable = joinable; }
void SetJoining(bool joining) { m_joining = joining; } void SetJoining(bool joining) { m_joining = joining; }

View file

@ -1,5 +1,4 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/DbgCommand.h" #include "Emu/DbgCommand.h"

View file

@ -1,5 +1,4 @@
#pragma once #pragma once
#include <atomic>
enum enum
{ {

View file

@ -1,5 +1,4 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "PPCDecoder.h" #include "PPCDecoder.h"

View file

@ -1,7 +1,6 @@
#pragma once #pragma once
#include "Emu/CPU/CPUDisAsm.h" #include "Emu/CPU/CPUDisAsm.h"
#include "Emu/Memory/Memory.h"
class PPCDisAsm : public CPUDisAsm class PPCDisAsm : public CPUDisAsm
{ {

View file

@ -1,8 +1,6 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "PPCThread.h" #include "PPCThread.h"
#include "Emu/Memory/Memory.h"
PPCThread* GetCurrentPPCThread() PPCThread* GetCurrentPPCThread()
{ {

View file

@ -1,7 +1,5 @@
#pragma once #pragma once
#include "Emu/Memory/MemoryBlock.h"
#include "Emu/CPU/CPUThread.h" #include "Emu/CPU/CPUThread.h"
#include "Emu/Cell/PPCDecoder.h"
class PPCThread : public CPUThread class PPCThread : public CPUThread
{ {

View file

@ -1,9 +1,6 @@
#pragma once #pragma once
#include "Emu/Cell/PPUOpcodes.h"
#include "Emu/Cell/PPCDisAsm.h" #include "Emu/Cell/PPCDisAsm.h"
#include "Emu/Cell/PPCThread.h"
#include "Emu/Memory/Memory.h"
class PPUDisAsm class PPUDisAsm
: public PPUOpcodes : public PPUOpcodes

View file

@ -1,9 +1,7 @@
#pragma once #pragma once
#include "Emu/Cell/PPUOpcodes.h" #include "Emu/Cell/PPUOpcodes.h"
#include "Emu/Memory/Memory.h"
#include "Emu/Cell/PPUThread.h"
#include "Emu/SysCalls/SysCalls.h"
#include <stdint.h> #include <stdint.h>
#ifdef _MSC_VER #ifdef _MSC_VER
#include <intrin.h> #include <intrin.h>
@ -2104,6 +2102,7 @@ private:
Emu.GetSFuncManager()[CPU.GPR[11]]->name, CPU.GPR[3], CPU.PC); Emu.GetSFuncManager()[CPU.GPR[11]]->name, CPU.GPR[3], CPU.PC);
} }
break; break;
case 0x4: CPU.FastStop(); break;
case 0x22: UNK("HyperCall LV1"); break; case 0x22: UNK("HyperCall LV1"); break;
default: UNK(fmt::Format("Unknown sc: %x", sc_code)); default: UNK(fmt::Format("Unknown sc: %x", sc_code));
} }
@ -2368,13 +2367,9 @@ private:
} }
void LWARX(u32 rd, u32 ra, u32 rb) void LWARX(u32 rd, u32 ra, u32 rb)
{ {
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; CPU.R_ADDR = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
CPU.R_VALUE = (u32&)Memory[CPU.R_ADDR];
SMutexLockerR lock(reservation.mutex); CPU.GPR[rd] = re32((u32)CPU.R_VALUE);
reservation.owner = lock.tid;
reservation.addr = addr;
reservation.size = 4;
reservation.data32 = CPU.GPR[rd] = Memory.Read32(addr);
} }
void LDX(u32 rd, u32 ra, u32 rb) void LDX(u32 rd, u32 ra, u32 rb)
{ {
@ -2523,13 +2518,9 @@ private:
} }
void LDARX(u32 rd, u32 ra, u32 rb) void LDARX(u32 rd, u32 ra, u32 rb)
{ {
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; CPU.R_ADDR = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
CPU.R_VALUE = (u64&)Memory[CPU.R_ADDR];
SMutexLockerR lock(reservation.mutex); CPU.GPR[rd] = re64(CPU.R_VALUE);
reservation.owner = lock.tid;
reservation.addr = addr;
reservation.size = 8;
reservation.data64 = CPU.GPR[rd] = Memory.Read64(addr);
} }
void DCBF(u32 ra, u32 rb) void DCBF(u32 ra, u32 rb)
{ {
@ -2644,17 +2635,13 @@ private:
{ {
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
SMutexLockerR lock(reservation.mutex); if (CPU.R_ADDR == addr)
if (lock.tid == reservation.owner && reservation.addr == addr && reservation.size == 4)
{ {
// Memory.Write32(addr, CPU.GPR[rs]); CPU.SetCR_EQ(0, InterlockedCompareExchange((volatile u32*)(Memory + addr), re32((u32)CPU.GPR[rs]), (u32)CPU.R_VALUE) == (u32)CPU.R_VALUE);
CPU.SetCR_EQ(0, InterlockedCompareExchange((volatile long*) (Memory + addr), re((u32) CPU.GPR[rs]), re(reservation.data32)) == re(reservation.data32));
reservation.clear();
} }
else else
{ {
CPU.SetCR_EQ(0, false); CPU.SetCR_EQ(0, false);
if (lock.tid == reservation.owner) reservation.clear();
} }
} }
void STWX(u32 rs, u32 ra, u32 rb) void STWX(u32 rs, u32 ra, u32 rb)
@ -2705,17 +2692,13 @@ private:
{ {
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
SMutexLockerR lock(reservation.mutex); if (CPU.R_ADDR == addr)
if (lock.tid == reservation.owner && reservation.addr == addr && reservation.size == 8)
{ {
// Memory.Write64(addr, CPU.GPR[rs]); CPU.SetCR_EQ(0, InterlockedCompareExchange((volatile u64*)(Memory + addr), re64(CPU.GPR[rs]), CPU.R_VALUE) == CPU.R_VALUE);
CPU.SetCR_EQ(0, InterlockedCompareExchange64((volatile long long*)(Memory + addr), re(CPU.GPR[rs]), re(reservation.data64)) == re(reservation.data64));
reservation.clear();
} }
else else
{ {
CPU.SetCR_EQ(0, false); CPU.SetCR_EQ(0, false);
if (lock.tid == reservation.owner) reservation.clear();
} }
} }
void STBX(u32 rs, u32 ra, u32 rb) void STBX(u32 rs, u32 ra, u32 rb)

View file

@ -1,7 +1,4 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h"
#include "Emu/Memory/Memory.h"
#include "PPUProgramCompiler.h" #include "PPUProgramCompiler.h"
using namespace PPU_instr; using namespace PPU_instr;
@ -83,7 +80,7 @@ SectionInfo::SectionInfo(const std::string& _name)
void SectionInfo::SetDataSize(u32 size, u32 align) void SectionInfo::SetDataSize(u32 size, u32 align)
{ {
if(align) shdr.sh_addralign = 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()) if(!code.empty())
{ {
@ -987,7 +984,7 @@ void CompilePPUProgram::Compile()
elf_info.e_shnum = 15; elf_info.e_shnum = 15;
elf_info.e_shstrndx = elf_info.e_shnum - 1; elf_info.e_shstrndx = elf_info.e_shnum - 1;
elf_info.e_phoff = elf_info.e_ehsize; 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; static const u32 sceStub_text_block = 8 * 4;
@ -1145,7 +1142,7 @@ void CompilePPUProgram::Compile()
Elf64_Shdr s_sceStub_text; Elf64_Shdr s_sceStub_text;
memset(&s_sceStub_text, 0, sizeof(Elf64_Shdr)); memset(&s_sceStub_text, 0, sizeof(Elf64_Shdr));
s_sceStub_text.sh_addralign = 4; 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_type = 1;
s_sceStub_text.sh_offset = section_offset; s_sceStub_text.sh_offset = section_offset;
s_sceStub_text.sh_addr = section_offset + 0x10000; s_sceStub_text.sh_addr = section_offset + 0x10000;
@ -1169,7 +1166,7 @@ void CompilePPUProgram::Compile()
Elf64_Shdr s_lib_stub_top; Elf64_Shdr s_lib_stub_top;
memset(&s_lib_stub_top, 0, sizeof(Elf64_Shdr)); memset(&s_lib_stub_top, 0, sizeof(Elf64_Shdr));
s_lib_stub_top.sh_addralign = 4; 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_type = 1;
s_lib_stub_top.sh_name = section_name_offset; s_lib_stub_top.sh_name = section_name_offset;
s_lib_stub_top.sh_offset = section_offset; s_lib_stub_top.sh_offset = section_offset;
@ -1209,7 +1206,7 @@ void CompilePPUProgram::Compile()
Elf64_Shdr s_rodata_sceFNID; Elf64_Shdr s_rodata_sceFNID;
memset(&s_rodata_sceFNID, 0, sizeof(Elf64_Shdr)); memset(&s_rodata_sceFNID, 0, sizeof(Elf64_Shdr));
s_rodata_sceFNID.sh_addralign = 4; 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_type = 1;
s_rodata_sceFNID.sh_name = section_name_offset; s_rodata_sceFNID.sh_name = section_name_offset;
s_rodata_sceFNID.sh_offset = section_offset; s_rodata_sceFNID.sh_offset = section_offset;
@ -1223,7 +1220,7 @@ void CompilePPUProgram::Compile()
Elf64_Shdr s_rodata_sceResident; Elf64_Shdr s_rodata_sceResident;
memset(&s_rodata_sceResident, 0, sizeof(Elf64_Shdr)); memset(&s_rodata_sceResident, 0, sizeof(Elf64_Shdr));
s_rodata_sceResident.sh_addralign = 4; 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_type = 1;
s_rodata_sceResident.sh_name = section_name_offset; s_rodata_sceResident.sh_name = section_name_offset;
s_rodata_sceResident.sh_offset = section_offset; s_rodata_sceResident.sh_offset = section_offset;
@ -1234,7 +1231,7 @@ void CompilePPUProgram::Compile()
{ {
s_rodata_sceResident.sh_size += module.m_name.length() + 1; 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"); sections_names.push_back(".rodata.sceResident");
section_name_offset += std::string(".rodata.sceResident").length() + 1; section_name_offset += std::string(".rodata.sceResident").length() + 1;
section_offset += s_rodata_sceResident.sh_size; section_offset += s_rodata_sceResident.sh_size;
@ -1242,7 +1239,7 @@ void CompilePPUProgram::Compile()
Elf64_Shdr s_lib_ent_top; Elf64_Shdr s_lib_ent_top;
memset(&s_lib_ent_top, 0, sizeof(Elf64_Shdr)); memset(&s_lib_ent_top, 0, sizeof(Elf64_Shdr));
s_lib_ent_top.sh_addralign = 4; 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_size = 4;
s_lib_ent_top.sh_flags = 2; s_lib_ent_top.sh_flags = 2;
s_lib_ent_top.sh_type = 1; s_lib_ent_top.sh_type = 1;
@ -1269,7 +1266,7 @@ void CompilePPUProgram::Compile()
Elf64_Shdr s_sys_proc_prx_param; Elf64_Shdr s_sys_proc_prx_param;
memset(&s_sys_proc_prx_param, 0, sizeof(Elf64_Shdr)); memset(&s_sys_proc_prx_param, 0, sizeof(Elf64_Shdr));
s_sys_proc_prx_param.sh_addralign = 4; 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_type = 1;
s_sys_proc_prx_param.sh_size = sizeof(sys_proc_prx_param); s_sys_proc_prx_param.sh_size = sizeof(sys_proc_prx_param);
s_sys_proc_prx_param.sh_name = section_name_offset; s_sys_proc_prx_param.sh_name = section_name_offset;
@ -1282,14 +1279,14 @@ void CompilePPUProgram::Compile()
const u32 prog_load_0_end = section_offset; 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; const u32 prog_load_1_start = section_offset;
Elf64_Shdr s_data_sceFStub; Elf64_Shdr s_data_sceFStub;
memset(&s_data_sceFStub, 0, sizeof(Elf64_Shdr)); memset(&s_data_sceFStub, 0, sizeof(Elf64_Shdr));
s_data_sceFStub.sh_name = section_name_offset; s_data_sceFStub.sh_name = section_name_offset;
s_data_sceFStub.sh_addralign = 4; 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_flags = 3;
s_data_sceFStub.sh_type = 1; s_data_sceFStub.sh_type = 1;
s_data_sceFStub.sh_offset = section_offset; s_data_sceFStub.sh_offset = section_offset;
@ -1302,7 +1299,7 @@ void CompilePPUProgram::Compile()
Elf64_Shdr s_tbss; Elf64_Shdr s_tbss;
memset(&s_tbss, 0, sizeof(Elf64_Shdr)); memset(&s_tbss, 0, sizeof(Elf64_Shdr));
s_tbss.sh_addralign = 4; 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_size = 4;
s_tbss.sh_flags = 0x403; s_tbss.sh_flags = 0x403;
s_tbss.sh_type = 8; s_tbss.sh_type = 8;
@ -1316,7 +1313,7 @@ void CompilePPUProgram::Compile()
Elf64_Shdr s_opd; Elf64_Shdr s_opd;
memset(&s_opd, 0, sizeof(Elf64_Shdr)); memset(&s_opd, 0, sizeof(Elf64_Shdr));
s_opd.sh_addralign = 8; 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_size = 2*4;
s_opd.sh_type = 1; s_opd.sh_type = 1;
s_opd.sh_offset = section_offset; s_opd.sh_offset = section_offset;
@ -1477,7 +1474,7 @@ void CompilePPUProgram::Compile()
if(!m_file_path.empty() && !m_analyze && !m_error) 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; section_offset += s_opd.sh_size;
const u32 prog_load_1_end = section_offset; const u32 prog_load_1_end = section_offset;
@ -1485,7 +1482,7 @@ void CompilePPUProgram::Compile()
Elf64_Shdr s_shstrtab; Elf64_Shdr s_shstrtab;
memset(&s_shstrtab, 0, sizeof(Elf64_Shdr)); memset(&s_shstrtab, 0, sizeof(Elf64_Shdr));
s_shstrtab.sh_addralign = 1; 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_name = section_name_offset;
s_shstrtab.sh_type = 3; s_shstrtab.sh_type = 3;
s_shstrtab.sh_offset = section_offset; s_shstrtab.sh_offset = section_offset;
@ -1507,7 +1504,7 @@ void CompilePPUProgram::Compile()
elf_info.e_machine = MACHINE_PPC64; //PowerPC64 elf_info.e_machine = MACHINE_PPC64; //PowerPC64
elf_info.e_version = 1; //ver 1 elf_info.e_version = 1; //ver 1
elf_info.e_flags = 0x0; 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]; u8* opd_data = new u8[s_opd.sh_size];
u32 entry_point = s_text.sh_addr; u32 entry_point = s_text.sh_addr;

View file

@ -1,12 +1,14 @@
#include "stdafx.h" #include "stdafx.h"
#include "rpcs3/Ini.h"
#include "Utilities/Log.h" #include "Utilities/Log.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/Cell/PPUThread.h" #include "Emu/Cell/PPUThread.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/Static.h"
#include "Emu/Cell/PPUDecoder.h" #include "Emu/Cell/PPUDecoder.h"
#include "Emu/Cell/PPUInterpreter.h" #include "Emu/Cell/PPUInterpreter.h"
#include "Emu/Cell/PPUDisAsm.h"
#include <thread> #include <thread>
#include <cmath> #include <cmath>
@ -57,7 +59,7 @@ void PPUThread::DoReset()
void PPUThread::AddArgv(const std::string& arg) void PPUThread::AddArgv(const std::string& arg)
{ {
m_stack_point -= arg.length() + 1; 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); m_argv_addr.push_back(m_stack_point);
Memory.WriteString(m_stack_point, arg); Memory.WriteString(m_stack_point, arg);
} }
@ -94,7 +96,7 @@ void PPUThread::InitRegs()
} }
*/ */
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[1] = m_stack_point;
GPR[2] = rtoc; GPR[2] = rtoc;
@ -219,3 +221,52 @@ int FPRdouble::Cmp(PPCdouble a, PPCdouble b)
return CR_SO; return CR_SO;
} }
u64 PPUThread::GetStackArg(s32 i)
{
return Memory.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;
}

View file

@ -607,6 +607,9 @@ public:
u64 cycle; u64 cycle;
u64 R_ADDR; // reservation address
u64 R_VALUE; // reservation value (BE)
public: public:
PPUThread(); PPUThread();
virtual ~PPUThread(); virtual ~PPUThread();
@ -839,6 +842,10 @@ public:
public: public:
virtual void InitRegs(); virtual void InitRegs();
virtual u64 GetFreeStackSize() const; 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: protected:
virtual void DoReset() override; virtual void DoReset() override;
@ -860,3 +867,4 @@ protected:
PPUThread& GetCurrentPPUThread(); PPUThread& GetCurrentPPUThread();
#define declCPU PPUThread& CPU = GetCurrentPPUThread

View file

@ -1,7 +1,6 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h" #include "Utilities/Log.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/Cell/RawSPUThread.h" #include "Emu/Cell/RawSPUThread.h"
@ -149,7 +148,7 @@ bool RawSPUThread::Write32(const u64 addr, const u32 value)
else else
{ {
LOG_ERROR(Log::SPU, "RawSPUThread[%d]: Write32(SPU_RunCtrl, 0x%x): unknown value", m_index, value); LOG_ERROR(Log::SPU, "RawSPUThread[%d]: Write32(SPU_RunCtrl, 0x%x): unknown value", m_index, value);
Emu.Pause(); return false;
} }
break; break;
} }

View file

@ -6,11 +6,6 @@ __forceinline static u32 GetRawSPURegAddrByNum(int num, int offset)
return RAW_SPU_OFFSET * num + RAW_SPU_BASE_ADDR + RAW_SPU_PROB_OFFSET + 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 class RawSPUThread
: public SPUThread : public SPUThread
, public MemoryBlock , public MemoryBlock

View file

@ -2,8 +2,49 @@
#include "Emu/Cell/SPUOpcodes.h" #include "Emu/Cell/SPUOpcodes.h"
#include "Emu/Cell/PPCDisAsm.h" #include "Emu/Cell/PPCDisAsm.h"
#include "Emu/Cell/SPUThread.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_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 class SPUDisAsm
: public SPUOpcodes : public SPUOpcodes
@ -93,7 +134,7 @@ private:
} }
void MFSPR(u32 rt, u32 sa) 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_reg_name[sa]);
} }
void RDCH(u32 rt, u32 ra) void RDCH(u32 rt, u32 ra)
{ {
@ -223,19 +264,19 @@ private:
{ {
DisAsm("wrch", spu_ch_name[ra], spu_reg_name[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]); 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]); 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]); 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]); DisAsm("bihnz", spu_reg_name[rt], spu_reg_name[ra]);
} }
@ -247,11 +288,11 @@ private:
{ {
DisAsm("stqx", spu_reg_name[rt], spu_reg_name[ra], spu_reg_name[rb]); 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]); 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]); DisAsm("bisl", spu_reg_name[rt], spu_reg_name[ra]);
} }
@ -259,7 +300,7 @@ private:
{ {
DisAsm("iret", spu_reg_name[ra]); 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]); DisAsm("bisled", spu_reg_name[rt], spu_reg_name[ra]);
} }

View file

@ -1,5 +1,4 @@
#pragma once #pragma once
#include "PPCInstrTable.h"
#include "PPCDecoder.h" #include "PPCDecoder.h"
#include "SPUOpcodes.h" #include "SPUOpcodes.h"
@ -88,16 +87,16 @@ namespace SPU_instr
bind_instr(ri7_list, AVGB, RT, RA, RB); bind_instr(ri7_list, AVGB, RT, RA, RB);
bind_instr(ri7_list, MTSPR, RT, RA); bind_instr(ri7_list, MTSPR, RT, RA);
bind_instr(ri7_list, WRCH, RA, RT); bind_instr(ri7_list, WRCH, RA, RT);
bind_instr(ri7_list, BIZ, RT, RA); bind_instr(ri7_list, BIZ, RB, RT, RA);
bind_instr(ri7_list, BINZ, RT, RA); bind_instr(ri7_list, BINZ, RB, RT, RA);
bind_instr(ri7_list, BIHZ, RT, RA); bind_instr(ri7_list, BIHZ, RB, RT, RA);
bind_instr(ri7_list, BIHNZ, RT, RA); bind_instr(ri7_list, BIHNZ, RB, RT, RA);
bind_instr(ri7_list, STOPD, RT, RA, RB); bind_instr(ri7_list, STOPD, RT, RA, RB);
bind_instr(ri7_list, STQX, RT, RA, RB); bind_instr(ri7_list, STQX, RT, RA, RB);
bind_instr(ri7_list, BI, RA); bind_instr(ri7_list, BI, RB, RA);
bind_instr(ri7_list, BISL, RT, RA); bind_instr(ri7_list, BISL, RB, RT, RA);
bind_instr(ri7_list, IRET, 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, HBR, L_11, RO, RA);
bind_instr(ri7_list, GB, RT, RA); bind_instr(ri7_list, GB, RT, RA);
bind_instr(ri7_list, GBH, RT, RA); bind_instr(ri7_list, GBH, RT, RA);

View file

@ -1,20 +1,7 @@
#pragma once #pragma once
#include "Emu/Cell/SPUOpcodes.h"
#include "Emu/Memory/Memory.h"
#include "Emu/Cell/SPUThread.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Crypto/sha1.h"
#define UNIMPLEMENTED() UNK(__FUNCTION__) #define UNIMPLEMENTED() UNK(__FUNCTION__)
/* typedef union _CRT_ALIGN(16) __u32x4 {
u32 _u32[4];
__m128i m128i;
__m128 m128;
__m128d m128d;
} __u32x4; */
#define MEM_AND_REG_HASH() \ #define MEM_AND_REG_HASH() \
unsigned char mem_h[20]; sha1(&Memory[CPU.dmac.ls_offset], 256*1024, mem_h); \ unsigned char mem_h[20]; sha1(&Memory[CPU.dmac.ls_offset], 256*1024, mem_h); \
unsigned char reg_h[20]; sha1((const unsigned char*)CPU.GPR, sizeof(CPU.GPR), reg_h); \ unsigned char reg_h[20]; sha1((const unsigned char*)CPU.GPR, sizeof(CPU.GPR), reg_h); \
@ -42,7 +29,7 @@ private:
//0 - 10 //0 - 10
void STOP(u32 code) void STOP(u32 code)
{ {
CPU.DoStop(code); CPU.StopAndSignal(code);
LOG2_OPCODE(); LOG2_OPCODE();
} }
void LNOP() void LNOP()
@ -60,18 +47,7 @@ private:
} }
void MFSPR(u32 rt, u32 sa) void MFSPR(u32 rt, u32 sa)
{ {
UNIMPLEMENTED(); UNIMPLEMENTED(); // not used
//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) void RDCH(u32 rt, u32 ra)
{ {
@ -267,18 +243,20 @@ private:
} }
void MTSPR(u32 rt, u32 sa) void MTSPR(u32 rt, u32 sa)
{ {
if(sa != 0) UNIMPLEMENTED(); // not used
{
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) void WRCH(u32 ra, u32 rt)
{ {
CPU.WriteChannel(ra, CPU.GPR[rt]); CPU.WriteChannel(ra, CPU.GPR[rt]);
} }
void BIZ(u32 rt, u32 ra) void BIZ(u32 intr, u32 rt, u32 ra)
{ {
if (intr)
{
UNIMPLEMENTED();
return;
}
u64 target = branchTarget(CPU.GPR[ra]._u32[3], 0); u64 target = branchTarget(CPU.GPR[ra]._u32[3], 0);
if (CPU.GPR[rt]._u32[3] == 0) if (CPU.GPR[rt]._u32[3] == 0)
{ {
@ -290,8 +268,14 @@ private:
LOG5_OPCODE("not taken (0x%llx)", target); LOG5_OPCODE("not taken (0x%llx)", target);
} }
} }
void BINZ(u32 rt, u32 ra) void BINZ(u32 intr, u32 rt, u32 ra)
{ {
if (intr)
{
UNIMPLEMENTED();
return;
}
u64 target = branchTarget(CPU.GPR[ra]._u32[3], 0); u64 target = branchTarget(CPU.GPR[ra]._u32[3], 0);
if (CPU.GPR[rt]._u32[3] != 0) if (CPU.GPR[rt]._u32[3] != 0)
{ {
@ -303,8 +287,14 @@ private:
LOG5_OPCODE("not taken (0x%llx)", target); LOG5_OPCODE("not taken (0x%llx)", target);
} }
} }
void BIHZ(u32 rt, u32 ra) void BIHZ(u32 intr, u32 rt, u32 ra)
{ {
if (intr)
{
UNIMPLEMENTED();
return;
}
u64 target = branchTarget(CPU.GPR[ra]._u32[3], 0); u64 target = branchTarget(CPU.GPR[ra]._u32[3], 0);
if (CPU.GPR[rt]._u16[6] == 0) if (CPU.GPR[rt]._u16[6] == 0)
{ {
@ -316,8 +306,14 @@ private:
LOG5_OPCODE("not taken (0x%llx)", target); LOG5_OPCODE("not taken (0x%llx)", target);
} }
} }
void BIHNZ(u32 rt, u32 ra) void BIHNZ(u32 intr, u32 rt, u32 ra)
{ {
if (intr)
{
UNIMPLEMENTED();
return;
}
u64 target = branchTarget(CPU.GPR[ra]._u32[3], 0); u64 target = branchTarget(CPU.GPR[ra]._u32[3], 0);
if (CPU.GPR[rt]._u16[6] != 0) if (CPU.GPR[rt]._u16[6] != 0)
{ {
@ -331,8 +327,7 @@ private:
} }
void STOPD(u32 rc, u32 ra, u32 rb) void STOPD(u32 rc, u32 ra, u32 rb)
{ {
UNIMPLEMENTED(); UNIMPLEMENTED(); // not used
Emu.Pause();
} }
void STQX(u32 rt, u32 ra, u32 rb) void STQX(u32 rt, u32 ra, u32 rb)
{ {
@ -340,14 +335,26 @@ private:
CPU.WriteLS128(lsa, CPU.GPR[rt]._u128); CPU.WriteLS128(lsa, CPU.GPR[rt]._u128);
} }
void BI(u32 ra) void BI(u32 intr, u32 ra)
{ {
if (intr)
{
UNIMPLEMENTED();
return;
}
u64 target = branchTarget(CPU.GPR[ra]._u32[3], 0); u64 target = branchTarget(CPU.GPR[ra]._u32[3], 0);
LOG5_OPCODE("branch (0x%llx)", target); LOG5_OPCODE("branch (0x%llx)", target);
CPU.SetBranch(target); CPU.SetBranch(target);
} }
void BISL(u32 rt, u32 ra) void BISL(u32 intr, u32 rt, u32 ra)
{ {
if (intr)
{
UNIMPLEMENTED();
return;
}
u64 target = branchTarget(CPU.GPR[ra]._u32[3], 0); u64 target = branchTarget(CPU.GPR[ra]._u32[3], 0);
CPU.GPR[rt].Reset(); CPU.GPR[rt].Reset();
CPU.GPR[rt]._u32[3] = CPU.PC + 4; CPU.GPR[rt]._u32[3] = CPU.PC + 4;
@ -356,12 +363,11 @@ private:
} }
void IRET(u32 ra) void IRET(u32 ra)
{ {
UNIMPLEMENTED(); UNIMPLEMENTED(); // not used
//SetBranch(SRR0);
} }
void BISLED(u32 rt, u32 ra) void BISLED(u32 intr, u32 rt, u32 ra)
{ {
UNIMPLEMENTED(); UNIMPLEMENTED(); // not used
} }
void HBR(u32 p, u32 ro, u32 ra) void HBR(u32 p, u32 ro, u32 ra)
{ {
@ -771,8 +777,7 @@ private:
} }
void DFCGT(u32 rt, u32 ra, u32 rb) void DFCGT(u32 rt, u32 ra, u32 rb)
{ {
CPU.GPR[rt]._u64[0] = CPU.GPR[ra]._d[0] > CPU.GPR[rb]._d[0] ? 0xffffffffffffffff : 0; UNIMPLEMENTED(); // cannot be used
CPU.GPR[rt]._u64[1] = CPU.GPR[ra]._d[1] > CPU.GPR[rb]._d[1] ? 0xffffffffffffffff : 0;
} }
void FA(u32 rt, u32 ra, u32 rb) void FA(u32 rt, u32 ra, u32 rb)
{ {
@ -817,8 +822,7 @@ private:
} }
void DFCMGT(u32 rt, u32 ra, u32 rb) void DFCMGT(u32 rt, u32 ra, u32 rb)
{ {
CPU.GPR[rt]._u64[0] = fabs(CPU.GPR[ra]._d[0]) > fabs(CPU.GPR[rb]._d[0]) ? 0xffffffffffffffff : 0; UNIMPLEMENTED(); // cannot be used
CPU.GPR[rt]._u64[1] = fabs(CPU.GPR[ra]._d[1]) > fabs(CPU.GPR[rb]._d[1]) ? 0xffffffffffffffff : 0;
} }
void DFA(u32 rt, u32 ra, u32 rb) void DFA(u32 rt, u32 ra, u32 rb)
{ {
@ -890,11 +894,13 @@ private:
} }
void CGX(u32 rt, u32 ra, u32 rb) void CGX(u32 rt, u32 ra, u32 rb)
{ {
// rarely used
for (int w = 0; w < 4; w++) for (int w = 0; w < 4; w++)
CPU.GPR[rt]._u32[w] = ((u64)CPU.GPR[ra]._u32[w] + (u64)CPU.GPR[rb]._u32[w] + (u64)(CPU.GPR[rt]._u32[w] & 1)) >> 32; CPU.GPR[rt]._u32[w] = ((u64)CPU.GPR[ra]._u32[w] + (u64)CPU.GPR[rb]._u32[w] + (u64)(CPU.GPR[rt]._u32[w] & 1)) >> 32;
} }
void BGX(u32 rt, u32 ra, u32 rb) void BGX(u32 rt, u32 ra, u32 rb)
{ {
// rarely used
s64 nResult; s64 nResult;
for (int w = 0; w < 4; w++) for (int w = 0; w < 4; w++)
@ -917,10 +923,8 @@ private:
void FSCRRD(u32 rt) void FSCRRD(u32 rt)
{ {
/*CPU.GPR[rt]._u128.lo = // TODO (rarely used)
CPU.FPSCR.Exception0 << 20 & CPU.GPR[rt].Reset();
CPU.FPSCR.*/
UNIMPLEMENTED();
} }
void FESD(u32 rt, u32 ra) void FESD(u32 rt, u32 ra)
{ {
@ -936,60 +940,16 @@ private:
} }
void FSCRWR(u32 rt, u32 ra) void FSCRWR(u32 rt, u32 ra)
{ {
UNIMPLEMENTED(); // TODO (rarely used)
if (CPU.GPR[ra]._u128)
{
LOG_ERROR(SPU, "FSCRWR(%d,%d): value = %s", rt, ra, CPU.GPR[ra].ToString().c_str());
UNIMPLEMENTED();
}
} }
void DFTSV(u32 rt, u32 ra, s32 i7) void DFTSV(u32 rt, u32 ra, s32 i7)
{ {
const u64 DoubleExpMask = 0x7ff0000000000000; UNIMPLEMENTED(); // cannot be used
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;
}
} }
void FCEQ(u32 rt, u32 ra, u32 rb) void FCEQ(u32 rt, u32 ra, u32 rb)
{ {
@ -1000,8 +960,7 @@ private:
} }
void DFCEQ(u32 rt, u32 ra, u32 rb) void DFCEQ(u32 rt, u32 ra, u32 rb)
{ {
CPU.GPR[rt]._u64[0] = CPU.GPR[ra]._d[0] == CPU.GPR[rb]._d[0] ? 0xffffffffffffffff : 0; UNIMPLEMENTED(); // cannot be used
CPU.GPR[rt]._u64[1] = CPU.GPR[ra]._d[1] == CPU.GPR[rb]._d[1] ? 0xffffffffffffffff : 0;
} }
void MPY(u32 rt, u32 ra, u32 rb) void MPY(u32 rt, u32 ra, u32 rb)
{ {
@ -1037,8 +996,7 @@ private:
} }
void DFCMEQ(u32 rt, u32 ra, u32 rb) void DFCMEQ(u32 rt, u32 ra, u32 rb)
{ {
CPU.GPR[rt]._u64[0] = fabs(CPU.GPR[ra]._d[0]) == fabs(CPU.GPR[rb]._d[0]) ? 0xffffffffffffffff : 0; UNIMPLEMENTED(); // cannot be used
CPU.GPR[rt]._u64[1] = fabs(CPU.GPR[ra]._d[1]) == fabs(CPU.GPR[rb]._d[1]) ? 0xffffffffffffffff : 0;
} }
void MPYU(u32 rt, u32 ra, u32 rb) void MPYU(u32 rt, u32 ra, u32 rb)
{ {
@ -1052,8 +1010,8 @@ private:
} }
void FI(u32 rt, u32 ra, u32 rb) void FI(u32 rt, u32 ra, u32 rb)
{ {
//Floating Interpolation: ra will be ignored. // TODO: Floating Interpolation: ra will be ignored.
//It should work correctly if result of preceding FREST or FRSQEST is sufficiently exact // It should work correctly if result of preceding FREST or FRSQEST is sufficiently exact
CPU.GPR[rt] = CPU.GPR[rb]; CPU.GPR[rt] = CPU.GPR[rb];
} }
void HEQ(u32 rt, u32 ra, u32 rb) void HEQ(u32 rt, u32 ra, u32 rb)

View file

@ -272,16 +272,16 @@ public:
virtual void AVGB(u32 rt, u32 ra, u32 rb) = 0; virtual void AVGB(u32 rt, u32 ra, u32 rb) = 0;
virtual void MTSPR(u32 rt, u32 sa) = 0; virtual void MTSPR(u32 rt, u32 sa) = 0;
virtual void WRCH(u32 ra, u32 rt) = 0; virtual void WRCH(u32 ra, u32 rt) = 0;
virtual void BIZ(u32 rt, u32 ra) = 0; virtual void BIZ(u32 intr, u32 rt, u32 ra) = 0;
virtual void BINZ(u32 rt, u32 ra) = 0; virtual void BINZ(u32 intr, u32 rt, u32 ra) = 0;
virtual void BIHZ(u32 rt, u32 ra) = 0; virtual void BIHZ(u32 intr, u32 rt, u32 ra) = 0;
virtual void BIHNZ(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 STOPD(u32 rc, u32 ra, u32 rb) = 0;
virtual void STQX(u32 rt, u32 ra, u32 rb) = 0; virtual void STQX(u32 rt, u32 ra, u32 rb) = 0;
virtual void BI(u32 ra) = 0; virtual void BI(u32 intr, u32 ra) = 0;
virtual void BISL(u32 rt, u32 ra) = 0; virtual void BISL(u32 intr, u32 rt, u32 ra) = 0;
virtual void IRET(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 HBR(u32 p, u32 ro, u32 ra) = 0;
virtual void GB(u32 rt, u32 ra) = 0; virtual void GB(u32 rt, u32 ra) = 0;
virtual void GBH(u32 rt, u32 ra) = 0; virtual void GBH(u32 rt, u32 ra) = 0;

View file

@ -1,7 +1,51 @@
#include "stdafx.h" #include "stdafx.h"
#include "SPURSManager.h"
#include "Emu/Memory/Memory.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, mem8_t priority, u32 maxContention)
{
this->args = args;
this->maxContention = maxContention;
}
SPURSManager::SPURSManager(SPURSManagerAttribute *attr) SPURSManager::SPURSManager(SPURSManagerAttribute *attr)
{ {
this->attr = attr; this->attr = attr;
@ -26,4 +70,4 @@ SPURSManagerTaskset::SPURSManagerTaskset(u32 address, SPURSManagerTasksetAttribu
{ {
this->tattr = tattr; this->tattr = tattr;
this->address = address; this->address = address;
} }

View file

@ -1,85 +1,18 @@
#pragma once #pragma once
#include "Emu/Memory/Memory.h" #include "Emu/SysCalls/Modules/cellSpurs.h"
// 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,
};
// Internal class to shape a SPURS attribute. // Internal class to shape a SPURS attribute.
class SPURSManagerAttribute class SPURSManagerAttribute
{ {
public: public:
SPURSManagerAttribute(int nSpus, int spuPriority, int ppuPriority, bool exitIfNoWork) 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); int _setNamePrefix(const char *name, u32 size);
this->threadGroupType = 0;
this->container = 0;
}
int _setNamePrefix(const char *name, u32 size) int _setSpuThreadGroupType(int type);
{
strncpy(this->namePrefix, name, size);
this->namePrefix[0] = 0;
return 0;
}
int _setSpuThreadGroupType(int type) int _setMemoryContainerForSpuThread(u32 container);
{
this->threadGroupType = type;
return 0;
}
int _setMemoryContainerForSpuThread(u32 container)
{
this->container = container;
return 0;
}
protected: protected:
be_t<int> nSpus; be_t<int> nSpus;
@ -94,11 +27,7 @@ protected:
class SPURSManagerEventFlag class SPURSManagerEventFlag
{ {
public: public:
SPURSManagerEventFlag(u32 flagClearMode, u32 flagDirection) SPURSManagerEventFlag(u32 flagClearMode, u32 flagDirection);
{
this->flagClearMode = flagClearMode;
this->flagDirection = flagDirection;
}
u32 _getDirection() u32 _getDirection()
{ {
@ -118,11 +47,7 @@ protected:
class SPURSManagerTasksetAttribute class SPURSManagerTasksetAttribute
{ {
public: public:
SPURSManagerTasksetAttribute(u64 args, mem8_t priority, u32 maxContention) SPURSManagerTasksetAttribute(u64 args, mem8_t priority, u32 maxContention);
{
this->args = args;
this->maxContention = maxContention;
}
protected: protected:
be_t<u64> args; be_t<u64> args;

View file

@ -1,8 +1,4 @@
#pragma once #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 #define ASMJIT_STATIC
@ -438,7 +434,7 @@ private:
static void STOP(u32 code) static void STOP(u32 code)
{ {
SPUThread& CPU = *(SPUThread*)GetCurrentCPUThread(); SPUThread& CPU = *(SPUThread*)GetCurrentCPUThread();
CPU.DoStop(code); CPU.StopAndSignal(code);
LOG2_OPCODE(); LOG2_OPCODE();
} }
}; };
@ -471,17 +467,6 @@ private:
void MFSPR(u32 rt, u32 sa) void MFSPR(u32 rt, u32 sa)
{ {
UNIMPLEMENTED(); 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) void RDCH(u32 rt, u32 ra)
{ {
@ -1098,11 +1083,6 @@ private:
void MTSPR(u32 rt, u32 sa) void MTSPR(u32 rt, u32 sa)
{ {
UNIMPLEMENTED(); 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) void WRCH(u32 ra, u32 rt)
{ {
@ -1146,8 +1126,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); c.mov(cpu_qword(PC), (u32)CPU.PC);
do_finalize = true; do_finalize = true;
@ -1158,8 +1144,14 @@ private:
c.shr(*pos_var, 2); c.shr(*pos_var, 2);
LOG_OPCODE(); 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); c.mov(cpu_qword(PC), (u32)CPU.PC);
do_finalize = true; do_finalize = true;
@ -1170,8 +1162,14 @@ private:
c.shr(*pos_var, 2); c.shr(*pos_var, 2);
LOG_OPCODE(); 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); c.mov(cpu_qword(PC), (u32)CPU.PC);
do_finalize = true; do_finalize = true;
@ -1182,8 +1180,14 @@ private:
c.shr(*pos_var, 2); c.shr(*pos_var, 2);
LOG_OPCODE(); 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); c.mov(cpu_qword(PC), (u32)CPU.PC);
do_finalize = true; do_finalize = true;
@ -1197,7 +1201,6 @@ private:
void STOPD(u32 rc, u32 ra, u32 rb) void STOPD(u32 rc, u32 ra, u32 rb)
{ {
UNIMPLEMENTED(); UNIMPLEMENTED();
Emu.Pause();
} }
void STQX(u32 rt, u32 ra, u32 rb) void STQX(u32 rt, u32 ra, u32 rb)
{ {
@ -1226,8 +1229,14 @@ private:
LOG_OPCODE(); LOG_OPCODE();
} }
void BI(u32 ra) void BI(u32 intr, u32 ra)
{ {
if (intr)
{
UNIMPLEMENTED();
return;
}
c.mov(cpu_qword(PC), (u32)CPU.PC); c.mov(cpu_qword(PC), (u32)CPU.PC);
do_finalize = true; do_finalize = true;
@ -1235,8 +1244,14 @@ private:
c.shr(*pos_var, 2); c.shr(*pos_var, 2);
LOG_OPCODE(); LOG_OPCODE();
} }
void BISL(u32 rt, u32 ra) void BISL(u32 intr, u32 rt, u32 ra)
{ {
if (intr)
{
UNIMPLEMENTED();
return;
}
XmmInvalidate(rt); XmmInvalidate(rt);
c.mov(cpu_qword(PC), (u32)CPU.PC); c.mov(cpu_qword(PC), (u32)CPU.PC);
@ -1254,9 +1269,8 @@ private:
void IRET(u32 ra) void IRET(u32 ra)
{ {
UNIMPLEMENTED(); UNIMPLEMENTED();
//SetBranch(SRR0);
} }
void BISLED(u32 rt, u32 ra) void BISLED(u32 intr, u32 rt, u32 ra)
{ {
UNIMPLEMENTED(); UNIMPLEMENTED();
} }
@ -2065,18 +2079,7 @@ private:
} }
void DFCGT(u32 rt, u32 ra, u32 rb) void DFCGT(u32 rt, u32 ra, u32 rb)
{ {
// reverted less-than UNIMPLEMENTED();
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();
} }
void FA(u32 rt, u32 ra, u32 rb) void FA(u32 rt, u32 ra, u32 rb)
{ {
@ -2206,15 +2209,7 @@ private:
} }
void DFCMGT(u32 rt, u32 ra, u32 rb) void DFCMGT(u32 rt, u32 ra, u32 rb)
{ {
// reverted less-than UNIMPLEMENTED();
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();
} }
void DFA(u32 rt, u32 ra, u32 rb) void DFA(u32 rt, u32 ra, u32 rb)
{ {
@ -2476,7 +2471,11 @@ private:
} }
void FSCRRD(u32 rt) 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) void FESD(u32 rt, u32 ra)
{ {
@ -2496,62 +2495,12 @@ private:
} }
void FSCRWR(u32 rt, u32 ra) 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); UNIMPLEMENTED();
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);
} }
void FCEQ(u32 rt, u32 ra, u32 rb) void FCEQ(u32 rt, u32 ra, u32 rb)
{ {
@ -2570,18 +2519,7 @@ private:
} }
void DFCEQ(u32 rt, u32 ra, u32 rb) void DFCEQ(u32 rt, u32 ra, u32 rb)
{ {
// compare equal UNIMPLEMENTED();
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();
} }
void MPY(u32 rt, u32 ra, u32 rb) void MPY(u32 rt, u32 ra, u32 rb)
{ {
@ -2665,14 +2603,7 @@ private:
} }
void DFCMEQ(u32 rt, u32 ra, u32 rb) void DFCMEQ(u32 rt, u32 ra, u32 rb)
{ {
const XmmLink& vb = XmmGet(rb, rt); UNIMPLEMENTED();
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();
} }
void MPYU(u32 rt, u32 ra, u32 rb) void MPYU(u32 rt, u32 ra, u32 rb)
{ {

View file

@ -3,8 +3,12 @@
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/lv2/sys_time.h"
#include "SPUInstrTable.h" #include "SPUInstrTable.h"
#include "SPUDisAsm.h" #include "SPUDisAsm.h"
#include "SPUThread.h"
#include "SPUInterpreter.h" #include "SPUInterpreter.h"
#include "SPURecompiler.h" #include "SPURecompiler.h"
@ -43,6 +47,7 @@ void SPURecompilerCore::Compile(u16 pos)
u64 time0 = 0; u64 time0 = 0;
SPUDisAsm dis_asm(CPUDisAsm_InterpreterMode); SPUDisAsm dis_asm(CPUDisAsm_InterpreterMode);
dis_asm.offset = Memory.GetMemFromAddr(CPU.dmac.ls_offset);
StringLogger stringLogger; StringLogger stringLogger;
stringLogger.setOption(kLoggerOptionBinaryForm, true); stringLogger.setOption(kLoggerOptionBinaryForm, true);
@ -102,7 +107,7 @@ void SPURecompilerCore::Compile(u16 pos)
{ {
const u64 stamp1 = get_system_time(); const u64 stamp1 = get_system_time();
// disasm for logging: // 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); (*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()); compiler.addComment(fmt::Format("SPU data: PC=0x%05x %s", pos * 4, dis_asm.last_opcode.c_str()).c_str());
// compile single opcode: // compile single opcode:
@ -171,21 +176,28 @@ u8 SPURecompilerCore::DecodeMemory(const u64 address)
{ {
// check data (hard way) // check data (hard way)
bool is_valid = true; bool is_valid = true;
/*for (u32 i = pos; i < (u32)(entry[pos].count + pos); i++) //for (u32 i = pos; i < (u32)(entry[pos].count + pos); i++)
{ //{
if (entry[i].valid != ls[i]) // if (entry[i].valid != ls[i])
{ // {
is_valid = false; // is_valid = false;
break; // break;
} // }
}*/ //}
// invalidate if necessary // invalidate if necessary
if (!is_valid) if (!is_valid)
{ {
// TODO for (u32 i = 0; i < 0x10000; i++)
LOG_ERROR(Log::SPU, "SPURecompilerCore::DecodeMemory(ls_addr=0x%x): code has changed", pos * sizeof(u32)); {
Emu.Pause(); if (entry[i].pointer &&
return 0; i + (u32)entry[i].count > (u32)pos &&
i < (u32)pos + (u32)entry[pos].count)
{
runtime.release(entry[i].pointer);
entry[i].pointer = nullptr;
}
}
//LOG_ERROR(Log::SPU, "SPURecompilerCore::DecodeMemory(ls_addr=0x%x): code has changed", pos * sizeof(u32));
} }
} }

View file

@ -1,7 +1,16 @@
#include "stdafx.h" #include "stdafx.h"
#include "rpcs3/Ini.h"
#include "Utilities/Log.h" #include "Utilities/Log.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/ErrorCodes.h"
#include "Emu/SysCalls/lv2/sys_spu.h"
#include "Emu/SysCalls/lv2/sys_event_flag.h"
#include "Emu/SysCalls/lv2/sys_time.h"
#include "Emu/Event.h"
#include "Emu/Cell/PPUThread.h"
#include "Emu/Cell/SPUThread.h" #include "Emu/Cell/SPUThread.h"
#include "Emu/Cell/SPUDecoder.h" #include "Emu/Cell/SPUDecoder.h"
#include "Emu/Cell/SPUInterpreter.h" #include "Emu/Cell/SPUInterpreter.h"
@ -81,6 +90,9 @@ void SPUThread::InitRegs()
MFC1.TagStatus.SetValue(0); MFC1.TagStatus.SetValue(0);
MFC2.TagStatus.SetValue(0); MFC2.TagStatus.SetValue(0);
//PC = SPU.NPC.GetValue(); //PC = SPU.NPC.GetValue();
m_event_mask = 0;
m_events = 0;
} }
u64 SPUThread::GetFreeStackSize() const u64 SPUThread::GetFreeStackSize() const
@ -137,3 +149,908 @@ void SPUThread::DoClose()
} }
} }
} }
void SPUThread::WriteSNR(bool number, u32 value)
{
if (cfg.value & ((u64)1 << (u64)number))
{
SPU.SNR[number].PushUncond_OR(value); // logical OR
}
else
{
SPU.SNR[number].PushUncond(value); // overwrite
}
}
#define LOG_DMAC(type, text) type(Log::SPU, "DMAC::ProcessCmd(cmd=0x%x, tag=0x%x, lsa=0x%x, ea=0x%llx, size=0x%x): " text, cmd, tag, lsa, ea, size)
void SPUThread::ProcessCmd(u32 cmd, u32 tag, u32 lsa, u64 ea, u32 size)
{
if (cmd & (MFC_BARRIER_MASK | MFC_FENCE_MASK)) _mm_mfence();
if (ea >= SYS_SPU_THREAD_BASE_LOW)
{
if (ea >= 0x100000000)
{
LOG_DMAC(LOG_ERROR, "Invalid external address");
Emu.Pause();
return;
}
else if (group)
{
// SPU Thread Group MMIO (LS and SNR)
u32 num = (ea & SYS_SPU_THREAD_BASE_MASK) / SYS_SPU_THREAD_OFFSET; // thread number in group
if (num >= group->list.size() || !group->list[num])
{
LOG_DMAC(LOG_ERROR, "Invalid thread (SPU Thread Group MMIO)");
Emu.Pause();
return;
}
SPUThread* spu = (SPUThread*)Emu.GetCPU().GetThread(group->list[num]);
u32 addr = (ea & SYS_SPU_THREAD_BASE_MASK) % SYS_SPU_THREAD_OFFSET;
if ((addr <= 0x3ffff) && (addr + size <= 0x40000))
{
// LS access
ea = spu->dmac.ls_offset + addr;
}
else if ((cmd & MFC_PUT_CMD) && size == 4 && (addr == SYS_SPU_THREAD_SNR1 || addr == SYS_SPU_THREAD_SNR2))
{
spu->WriteSNR(SYS_SPU_THREAD_SNR2 == addr, Memory.Read32(dmac.ls_offset + lsa));
return;
}
else
{
LOG_DMAC(LOG_ERROR, "Invalid register (SPU Thread Group MMIO)");
Emu.Pause();
return;
}
}
else
{
LOG_DMAC(LOG_ERROR, "Thread group not set (SPU Thread Group MMIO)");
Emu.Pause();
return;
}
}
else if (ea >= RAW_SPU_BASE_ADDR && size == 4)
{
switch (cmd & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK | MFC_LIST_MASK | MFC_RESULT_MASK))
{
case MFC_PUT_CMD:
{
Memory.Write32(ea, ReadLS32(lsa));
return;
}
case MFC_GET_CMD:
{
WriteLS32(lsa, Memory.Read32(ea));
return;
}
default:
{
LOG_DMAC(LOG_ERROR, "Unknown DMA command");
Emu.Pause();
return;
}
}
}
switch (cmd & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK | MFC_LIST_MASK | MFC_RESULT_MASK))
{
case MFC_PUT_CMD:
{
memcpy(Memory + ea, Memory + (dmac.ls_offset + lsa), size);
return;
}
case MFC_GET_CMD:
{
memcpy(Memory + (dmac.ls_offset + lsa), Memory + ea, size);
return;
}
default:
{
LOG_DMAC(LOG_ERROR, "Unknown DMA command");
Emu.Pause();
return;
}
}
}
#undef LOG_CMD
void SPUThread::ListCmd(u32 lsa, u64 ea, u16 tag, u16 size, u32 cmd, MFCReg& MFCArgs)
{
u32 list_addr = ea & 0x3ffff;
u32 list_size = size / 8;
lsa &= 0x3fff0;
struct list_element
{
be_t<u16> s; // Stall-and-Notify bit (0x8000)
be_t<u16> ts; // List Transfer Size
be_t<u32> ea; // External Address Low
};
u32 result = MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL;
for (u32 i = 0; i < list_size; i++)
{
mem_ptr_t<list_element> rec(dmac.ls_offset + list_addr + i * 8);
u32 size = rec->ts;
if (size < 16 && size != 1 && size != 2 && size != 4 && size != 8)
{
LOG_ERROR(Log::SPU, "DMA List: invalid transfer size(%d)", size);
result = MFC_PPU_DMA_CMD_SEQUENCE_ERROR;
break;
}
u32 addr = rec->ea;
ProcessCmd(cmd, tag, lsa | (addr & 0xf), addr, size);
if (Ini.HLELogging.GetValue() || rec->s)
LOG_NOTICE(Log::SPU, "*** list element(%d/%d): s = 0x%x, ts = 0x%x, low ea = 0x%x (lsa = 0x%x)",
i, list_size, (u16)rec->s, (u16)rec->ts, (u32)rec->ea, lsa | (addr & 0xf));
lsa += std::max(size, (u32)16);
if (rec->s & se16(0x8000))
{
StallStat.PushUncond_OR(1 << tag);
if (StallList[tag].MFCArgs)
{
LOG_ERROR(Log::SPU, "DMA List: existing stalled list found (tag=%d)", tag);
result = MFC_PPU_DMA_CMD_SEQUENCE_ERROR;
break;
}
StallList[tag].MFCArgs = &MFCArgs;
StallList[tag].cmd = cmd;
StallList[tag].ea = (ea & ~0xffffffff) | (list_addr + (i + 1) * 8);
StallList[tag].lsa = lsa;
StallList[tag].size = (list_size - i - 1) * 8;
break;
}
}
MFCArgs.CMDStatus.SetValue(result);
}
void SPUThread::EnqMfcCmd(MFCReg& MFCArgs)
{
u32 cmd = MFCArgs.CMDStatus.GetValue();
u16 op = cmd & MFC_MASK_CMD;
u32 lsa = MFCArgs.LSA.GetValue();
u64 ea = (u64)MFCArgs.EAL.GetValue() | ((u64)MFCArgs.EAH.GetValue() << 32);
u32 size_tag = MFCArgs.Size_Tag.GetValue();
u16 tag = (u16)size_tag;
u16 size = size_tag >> 16;
switch (op & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK))
{
case MFC_PUT_CMD:
case MFC_PUTR_CMD: // ???
case MFC_GET_CMD:
{
if (Ini.HLELogging.GetValue()) LOG_NOTICE(Log::SPU, "DMA %s%s%s%s: lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x, cmd = 0x%x",
(op & MFC_PUT_CMD ? "PUT" : "GET"),
(op & MFC_RESULT_MASK ? "R" : ""),
(op & MFC_BARRIER_MASK ? "B" : ""),
(op & MFC_FENCE_MASK ? "F" : ""),
lsa, ea, tag, size, cmd);
ProcessCmd(cmd, tag, lsa, ea, size);
MFCArgs.CMDStatus.SetValue(MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL);
}
break;
case MFC_PUTL_CMD:
case MFC_PUTRL_CMD: // ???
case MFC_GETL_CMD:
{
if (Ini.HLELogging.GetValue()) LOG_NOTICE(Log::SPU, "DMA %s%s%s%s: lsa = 0x%x, list = 0x%llx, tag = 0x%x, size = 0x%x, cmd = 0x%x",
(op & MFC_PUT_CMD ? "PUT" : "GET"),
(op & MFC_RESULT_MASK ? "RL" : "L"),
(op & MFC_BARRIER_MASK ? "B" : ""),
(op & MFC_FENCE_MASK ? "F" : ""),
lsa, ea, tag, size, cmd);
ListCmd(lsa, ea, tag, size, cmd, MFCArgs);
}
break;
case MFC_GETLLAR_CMD:
case MFC_PUTLLC_CMD:
case MFC_PUTLLUC_CMD:
case MFC_PUTQLLUC_CMD:
{
if (Ini.HLELogging.GetValue() || size != 128) LOG_NOTICE(Log::SPU, "DMA %s: lsa=0x%x, ea = 0x%llx, (tag) = 0x%x, (size) = 0x%x, cmd = 0x%x",
(op == MFC_GETLLAR_CMD ? "GETLLAR" :
op == MFC_PUTLLC_CMD ? "PUTLLC" :
op == MFC_PUTLLUC_CMD ? "PUTLLUC" : "PUTQLLUC"),
lsa, ea, tag, size, cmd);
if (op == MFC_GETLLAR_CMD) // get reservation
{
if (R_ADDR)
{
m_events |= SPU_EVENT_LR;
}
R_ADDR = ea;
for (u32 i = 0; i < 16; i++)
{
R_DATA[i] = *(u64*)&Memory[R_ADDR + i * 8];
*(u64*)&Memory[dmac.ls_offset + lsa + i * 8] = R_DATA[i];
}
MFCArgs.AtomicStat.PushUncond(MFC_GETLLAR_SUCCESS);
}
else if (op == MFC_PUTLLC_CMD) // store conditional
{
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS);
if (R_ADDR == ea)
{
u32 changed = 0, mask = 0;
u64 buf[16];
for (u32 i = 0; i < 16; i++)
{
buf[i] = *(u64*)&Memory[dmac.ls_offset + lsa + i * 8];
if (buf[i] != R_DATA[i])
{
changed++;
mask |= (0x3 << (i * 2));
if (*(u64*)&Memory[R_ADDR + i * 8] != R_DATA[i])
{
m_events |= SPU_EVENT_LR;
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE);
R_ADDR = 0;
return;
}
}
}
for (u32 i = 0; i < 16; i++)
{
if (buf[i] != R_DATA[i])
{
if (InterlockedCompareExchange64((volatile long long*)(Memory + (ea + i * 8)), buf[i], R_DATA[i]) != R_DATA[i])
{
m_events |= SPU_EVENT_LR;
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE);
if (changed > 1)
{
LOG_ERROR(Log::SPU, "MFC_PUTLLC_CMD: Memory corrupted (~x%d (mask=0x%x)) (opcode=0x%x, cmd=0x%x, lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x)",
changed, mask, op, cmd, lsa, ea, tag, size);
Emu.Pause();
}
break;
}
}
}
if (changed > 1)
{
LOG_WARNING(Log::SPU, "MFC_PUTLLC_CMD: Reservation impossibru (~x%d (mask=0x%x)) (opcode=0x%x, cmd=0x%x, lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x)",
changed, mask, op, cmd, lsa, ea, tag, size);
SPUDisAsm dis_asm(CPUDisAsm_InterpreterMode);
for (s32 i = PC; i < PC + 4 * 7; i += 4)
{
dis_asm.dump_pc = i;
dis_asm.offset = Memory.GetMemFromAddr(dmac.ls_offset);
const u32 opcode = Memory.Read32(i + dmac.ls_offset);
(*SPU_instr::rrr_list)(&dis_asm, opcode);
if (i >= 0 && i < 0x40000)
{
LOG_NOTICE(Log::SPU, "*** %s", dis_asm.last_opcode.c_str());
}
}
}
}
else
{
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE);
}
R_ADDR = 0;
}
else // store unconditional
{
if (R_ADDR)
{
m_events |= SPU_EVENT_LR;
}
ProcessCmd(MFC_PUT_CMD, tag, lsa, ea, 128);
if (op == MFC_PUTLLUC_CMD)
{
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLUC_SUCCESS);
}
R_ADDR = 0;
}
}
break;
default:
LOG_ERROR(Log::SPU, "Unknown MFC cmd. (opcode=0x%x, cmd=0x%x, lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x)",
op, cmd, lsa, ea, tag, size);
break;
}
}
bool SPUThread::CheckEvents()
{
// checks events:
// SPU_EVENT_LR:
{
for (u32 i = 0; i < 16; i++)
{
if (*(u64*)&Memory[R_ADDR + i * 8] != R_DATA[i])
{
m_events |= SPU_EVENT_LR;
R_ADDR = 0;
break;
}
}
}
return (m_events & m_event_mask) != 0;
}
u32 SPUThread::GetChannelCount(u32 ch)
{
switch (ch)
{
case SPU_WrOutMbox: return SPU.Out_MBox.GetFreeCount();
case SPU_WrOutIntrMbox: return SPU.Out_IntrMBox.GetFreeCount();
case SPU_RdInMbox: return SPU.In_MBox.GetCount();
case MFC_RdTagStat: return MFC1.TagStatus.GetCount();
case MFC_RdListStallStat: return StallStat.GetCount();
case MFC_WrTagUpdate: return MFC1.TagStatus.GetCount(); // hack
case SPU_RdSigNotify1: return SPU.SNR[0].GetCount();
case SPU_RdSigNotify2: return SPU.SNR[1].GetCount();
case MFC_RdAtomicStat: return MFC1.AtomicStat.GetCount();
case SPU_RdEventStat: return CheckEvents() ? 1 : 0;
default:
{
LOG_ERROR(Log::SPU, "%s error: unknown/illegal channel (%d [%s]).",
__FUNCTION__, ch, spu_ch_name[ch]);
return 0;
}
}
}
void SPUThread::WriteChannel(u32 ch, const SPU_GPR_hdr& r)
{
const u32 v = r._u32[3];
switch (ch)
{
case SPU_WrOutIntrMbox:
{
if (!group) // if RawSPU
{
if (Ini.HLELogging.GetValue()) LOG_NOTICE(Log::SPU, "SPU_WrOutIntrMbox: interrupt(v=0x%x)", v);
while (!SPU.Out_IntrMBox.Push(v))
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
if (Emu.IsStopped())
{
LOG_WARNING(Log::SPU, "%s(%s) aborted", __FUNCTION__, spu_ch_name[ch]);
return;
}
}
m_intrtag[2].stat |= 1;
if (CPUThread* t = Emu.GetCPU().GetThread(m_intrtag[2].thread))
{
if (t->GetType() == CPU_THREAD_PPU && !t->IsAlive())
{
PPUThread& ppu = *(PPUThread*)t;
ppu.FastStop();
ppu.Run();
ppu.FastCall(ppu.PC, ppu.GPR[2], ppu.m_interrupt_arg);
}
}
}
else
{
const u8 code = v >> 24;
if (code < 64)
{
/* ===== sys_spu_thread_send_event (used by spu_printf) ===== */
u8 spup = code & 63;
u32 data;
if (!SPU.Out_MBox.Pop(data))
{
LOG_ERROR(Log::SPU, "sys_spu_thread_send_event(v=0x%x, spup=%d): Out_MBox is empty", v, spup);
return;
}
if (Ini.HLELogging.GetValue())
{
LOG_NOTICE(Log::SPU, "sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x)", spup, v & 0x00ffffff, data);
}
EventPort& port = SPUPs[spup];
std::lock_guard<std::mutex> lock(port.m_mutex);
if (!port.eq)
{
LOG_WARNING(Log::SPU, "sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x): event queue not connected", spup, (v & 0x00ffffff), data);
SPU.In_MBox.PushUncond(CELL_ENOTCONN); // TODO: check error passing
return;
}
if (!port.eq->events.push(SYS_SPU_THREAD_EVENT_USER_KEY, GetCurrentCPUThread()->GetId(), ((u64)spup << 32) | (v & 0x00ffffff), data))
{
SPU.In_MBox.PushUncond(CELL_EBUSY);
return;
}
SPU.In_MBox.PushUncond(CELL_OK);
return;
}
else if (code < 128)
{
/* ===== sys_spu_thread_throw_event ===== */
const u8 spup = code & 63;
u32 data;
if (!SPU.Out_MBox.Pop(data))
{
LOG_ERROR(Log::SPU, "sys_spu_thread_throw_event(v=0x%x, spup=%d): Out_MBox is empty", v, spup);
return;
}
//if (Ini.HLELogging.GetValue())
{
LOG_WARNING(Log::SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x)", spup, v & 0x00ffffff, data);
}
EventPort& port = SPUPs[spup];
std::lock_guard<std::mutex> lock(port.m_mutex);
if (!port.eq)
{
LOG_WARNING(Log::SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x): event queue not connected", spup, (v & 0x00ffffff), data);
return;
}
// TODO: check passing spup value
if (!port.eq->events.push(SYS_SPU_THREAD_EVENT_USER_KEY, GetCurrentCPUThread()->GetId(), ((u64)spup << 32) | (v & 0x00ffffff), data))
{
LOG_WARNING(Log::SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x) failed (queue is full)", spup, (v & 0x00ffffff), data);
return;
}
return;
}
else if (code == 128)
{
/* ===== sys_event_flag_set_bit ===== */
u32 flag = v & 0xffffff;
u32 data;
if (!SPU.Out_MBox.Pop(data))
{
LOG_ERROR(Log::SPU, "sys_event_flag_set_bit(v=0x%x (flag=%d)): Out_MBox is empty", v, flag);
return;
}
if (flag > 63)
{
LOG_ERROR(Log::SPU, "sys_event_flag_set_bit(id=%d, v=0x%x): flag > 63", data, v, flag);
return;
}
//if (Ini.HLELogging.GetValue())
{
LOG_WARNING(Log::SPU, "sys_event_flag_set_bit(id=%d, v=0x%x (flag=%d))", data, v, flag);
}
EventFlag* ef;
if (!Emu.GetIdManager().GetIDData(data, ef))
{
LOG_ERROR(Log::SPU, "sys_event_flag_set_bit(id=%d, v=0x%x (flag=%d)): EventFlag not found", data, v, flag);
SPU.In_MBox.PushUncond(CELL_ESRCH);
return;
}
u32 tid = GetCurrentCPUThread()->GetId();
ef->m_mutex.lock(tid);
ef->flags |= (u64)1 << flag;
if (u32 target = ef->check())
{
// if signal, leave both mutexes locked...
ef->signal.lock(target);
ef->m_mutex.unlock(tid, target);
}
else
{
ef->m_mutex.unlock(tid);
}
SPU.In_MBox.PushUncond(CELL_OK);
return;
}
else if (code == 192)
{
/* ===== sys_event_flag_set_bit_impatient ===== */
u32 flag = v & 0xffffff;
u32 data;
if (!SPU.Out_MBox.Pop(data))
{
LOG_ERROR(Log::SPU, "sys_event_flag_set_bit_impatient(v=0x%x (flag=%d)): Out_MBox is empty", v, flag);
return;
}
if (flag > 63)
{
LOG_ERROR(Log::SPU, "sys_event_flag_set_bit_impatient(id=%d, v=0x%x): flag > 63", data, v, flag);
return;
}
//if (Ini.HLELogging.GetValue())
{
LOG_WARNING(Log::SPU, "sys_event_flag_set_bit_impatient(id=%d, v=0x%x (flag=%d))", data, v, flag);
}
EventFlag* ef;
if (!Emu.GetIdManager().GetIDData(data, ef))
{
LOG_WARNING(Log::SPU, "sys_event_flag_set_bit_impatient(id=%d, v=0x%x (flag=%d)): EventFlag not found", data, v, flag);
return;
}
u32 tid = GetCurrentCPUThread()->GetId();
ef->m_mutex.lock(tid);
ef->flags |= (u64)1 << flag;
if (u32 target = ef->check())
{
// if signal, leave both mutexes locked...
ef->signal.lock(target);
ef->m_mutex.unlock(tid, target);
}
else
{
ef->m_mutex.unlock(tid);
}
return;
}
else
{
u32 data;
if (SPU.Out_MBox.Pop(data))
{
LOG_ERROR(Log::SPU, "SPU_WrOutIntrMbox: unknown data (v=0x%x); Out_MBox = 0x%x", v, data);
}
else
{
LOG_ERROR(Log::SPU, "SPU_WrOutIntrMbox: unknown data (v=0x%x)", v);
}
SPU.In_MBox.PushUncond(CELL_EINVAL); // ???
return;
}
}
break;
}
case SPU_WrOutMbox:
{
while (!SPU.Out_MBox.Push(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
break;
}
case MFC_WrTagMask:
{
MFC1.QueryMask.SetValue(v);
break;
}
case MFC_WrTagUpdate:
{
MFC1.TagStatus.PushUncond(MFC1.QueryMask.GetValue());
break;
}
case MFC_LSA:
{
MFC1.LSA.SetValue(v);
break;
}
case MFC_EAH:
{
MFC1.EAH.SetValue(v);
break;
}
case MFC_EAL:
{
MFC1.EAL.SetValue(v);
break;
}
case MFC_Size:
{
MFC1.Size_Tag.SetValue((MFC1.Size_Tag.GetValue() & 0xffff) | (v << 16));
break;
}
case MFC_TagID:
{
MFC1.Size_Tag.SetValue((MFC1.Size_Tag.GetValue() & ~0xffff) | (v & 0xffff));
break;
}
case MFC_Cmd:
{
MFC1.CMDStatus.SetValue(v);
EnqMfcCmd(MFC1);
break;
}
case MFC_WrListStallAck:
{
if (v >= 32)
{
LOG_ERROR(Log::SPU, "MFC_WrListStallAck error: invalid tag(%d)", v);
return;
}
StalledList temp = StallList[v];
if (!temp.MFCArgs)
{
LOG_ERROR(Log::SPU, "MFC_WrListStallAck error: empty tag(%d)", v);
return;
}
StallList[v].MFCArgs = nullptr;
ListCmd(temp.lsa, temp.ea, temp.tag, temp.size, temp.cmd, *temp.MFCArgs);
break;
}
case SPU_WrDec:
{
m_dec_start = get_time();
m_dec_value = v;
break;
}
case SPU_WrEventMask:
{
m_event_mask = v;
if (v & ~(SPU_EVENT_IMPLEMENTED)) LOG_ERROR(Log::SPU, "SPU_WrEventMask: unsupported event masked (0x%x)");
break;
}
case SPU_WrEventAck:
{
m_events &= ~v;
break;
}
default:
{
LOG_ERROR(Log::SPU, "%s error (v=0x%x): unknown/illegal channel (%d [%s]).", __FUNCTION__, v, ch, spu_ch_name[ch]);
break;
}
}
if (Emu.IsStopped()) LOG_WARNING(Log::SPU, "%s(%s) aborted", __FUNCTION__, spu_ch_name[ch]);
}
void SPUThread::ReadChannel(SPU_GPR_hdr& r, u32 ch)
{
r.Reset();
u32& v = r._u32[3];
switch (ch)
{
case SPU_RdInMbox:
{
while (!SPU.In_MBox.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
break;
}
case MFC_RdTagStat:
{
while (!MFC1.TagStatus.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
break;
}
case MFC_RdTagMask:
{
v = MFC1.QueryMask.GetValue();
break;
}
case SPU_RdSigNotify1:
{
while (!SPU.SNR[0].Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
break;
}
case SPU_RdSigNotify2:
{
while (!SPU.SNR[1].Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
break;
}
case MFC_RdAtomicStat:
{
while (!MFC1.AtomicStat.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
break;
}
case MFC_RdListStallStat:
{
while (!StallStat.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
break;
}
case SPU_RdDec:
{
v = m_dec_value - (u32)(get_time() - m_dec_start);
break;
}
case SPU_RdEventMask:
{
v = m_event_mask;
break;
}
case SPU_RdEventStat:
{
while (!CheckEvents() && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
v = m_events & m_event_mask;
break;
}
case SPU_RdMachStat:
{
v = 1; // hack (not isolated, interrupts enabled)
// TODO: check value
break;
}
default:
{
LOG_ERROR(Log::SPU, "%s error: unknown/illegal channel (%d [%s]).", __FUNCTION__, ch, spu_ch_name[ch]);
break;
}
}
if (Emu.IsStopped()) LOG_WARNING(Log::SPU, "%s(%s) aborted", __FUNCTION__, spu_ch_name[ch]);
}
void SPUThread::StopAndSignal(u32 code)
{
SetExitStatus(code); // exit code (not status)
switch (code)
{
case 0x110: /* ===== sys_spu_thread_receive_event ===== */
{
u32 spuq = 0;
if (!SPU.Out_MBox.Pop(spuq))
{
LOG_ERROR(Log::SPU, "sys_spu_thread_receive_event: cannot read Out_MBox");
SPU.In_MBox.PushUncond(CELL_EINVAL); // ???
return;
}
if (SPU.In_MBox.GetCount())
{
LOG_ERROR(Log::SPU, "sys_spu_thread_receive_event(spuq=0x%x): In_MBox is not empty", spuq);
SPU.In_MBox.PushUncond(CELL_EBUSY); // ???
return;
}
if (Ini.HLELogging.GetValue())
{
LOG_NOTICE(Log::SPU, "sys_spu_thread_receive_event(spuq=0x%x)", spuq);
}
EventQueue* eq;
if (!SPUQs.GetEventQueue(FIX_SPUQ(spuq), eq))
{
SPU.In_MBox.PushUncond(CELL_EINVAL); // TODO: check error value
return;
}
u32 tid = GetId();
eq->sq.push(tid); // add thread to sleep queue
while (true)
{
switch (eq->owner.trylock(tid))
{
case SMR_OK:
if (!eq->events.count())
{
eq->owner.unlock(tid);
break;
}
else
{
u32 next = (eq->protocol == SYS_SYNC_FIFO) ? eq->sq.pop() : eq->sq.pop_prio();
if (next != tid)
{
eq->owner.unlock(tid, next);
break;
}
}
case SMR_SIGNAL:
{
sys_event_data event;
eq->events.pop(event);
eq->owner.unlock(tid);
SPU.In_MBox.PushUncond(CELL_OK);
SPU.In_MBox.PushUncond(event.data1);
SPU.In_MBox.PushUncond(event.data2);
SPU.In_MBox.PushUncond(event.data3);
return;
}
case SMR_FAILED: break;
default: eq->sq.invalidate(tid); SPU.In_MBox.PushUncond(CELL_ECANCELED); return;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
if (Emu.IsStopped())
{
LOG_WARNING(Log::SPU, "sys_spu_thread_receive_event(spuq=0x%x) aborted", spuq);
eq->sq.invalidate(tid);
return;
}
}
}
break;
case 0x102:
if (!SPU.Out_MBox.GetCount())
{
LOG_ERROR(Log::SPU, "sys_spu_thread_exit (no status, code 0x102)");
}
else if (Ini.HLELogging.GetValue())
{
// the real exit status
LOG_NOTICE(Log::SPU, "sys_spu_thread_exit (status=0x%x)", SPU.Out_MBox.GetValue());
}
SPU.Status.SetValue(SPU_STATUS_STOPPED_BY_STOP);
Stop();
break;
default:
if (!SPU.Out_MBox.GetCount())
{
LOG_ERROR(Log::SPU, "Unknown STOP code: 0x%x (no message)", code);
}
else
{
LOG_ERROR(Log::SPU, "Unknown STOP code: 0x%x (message=0x%x)", code, SPU.Out_MBox.GetValue());
}
SPU.Status.SetValue(SPU_STATUS_STOPPED_BY_STOP);
Stop();
break;
}
}

View file

@ -1,75 +1,9 @@
#pragma once #pragma once
#include "PPCThread.h" #include "PPCThread.h"
#include "Emu/Event.h" #include "Emu/Event.h"
#include "Emu/SysCalls/lv2/sys_spu.h"
#include "Emu/SysCalls/lv2/sys_event_flag.h"
#include "Emu/SysCalls/lv2/sys_time.h"
#include "MFC.h" #include "MFC.h"
#include "Emu/SysCalls/ErrorCodes.h"
#include <mutex> #include <mutex>
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",
};
//SPU reg $0 is a dummy reg, and is used for certain instructions.
static const char* spu_specialreg_name[128] = {
"$0", "$1", "$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_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",
};
enum SPUchannels enum SPUchannels
{ {
SPU_RdEventStat = 0, //Read event status with mask applied SPU_RdEventStat = 0, //Read event status with mask applied
@ -106,6 +40,24 @@ enum MFCchannels
MFC_RdAtomicStat = 27, //Read completion status of last completed immediate MFC atomic update command MFC_RdAtomicStat = 27, //Read completion status of last completed immediate MFC atomic update command
}; };
enum SPUEvents
{
SPU_EVENT_MS = 0x1000, // multisource synchronization event
SPU_EVENT_A = 0x800, // privileged attention event
SPU_EVENT_LR = 0x400, // lock line reservation lost event
SPU_EVENT_S1 = 0x200, // signal notification register 1 available
SPU_EVENT_S2 = 0x100, // signal notification register 2 available
SPU_EVENT_LE = 0x80, // SPU outbound mailbox available
SPU_EVENT_ME = 0x40, // SPU outbound interrupt mailbox available
SPU_EVENT_TM = 0x20, // SPU decrementer became negative (?)
SPU_EVENT_MB = 0x10, // SPU inbound mailbox available
SPU_EVENT_QV = 0x4, // MFC SPU command queue available
SPU_EVENT_SN = 0x2, // MFC list command stall-and-notify event
SPU_EVENT_TG = 0x1, // MFC tag-group status update event
SPU_EVENT_IMPLEMENTED = SPU_EVENT_LR,
};
enum enum
{ {
SPU_RUNCNTL_STOP = 0, SPU_RUNCNTL_STOP = 0,
@ -205,7 +157,7 @@ public:
return this->low >> 22 & 0x3; return this->low >> 22 & 0x3;
default: default:
LOG_ERROR(SPU, "Unexpected slice value in FPSCR::checkSliceRounding(): %d", slice); throw fmt::Format("Unexpected slice value in FPSCR::checkSliceRounding(): %d", slice);
return 0; return 0;
} }
} }
@ -271,25 +223,6 @@ union SPU_GPR_hdr
} }
}; };
union SPU_SPR_hdr
{
u32 _u32[4];
u128 _u128;
s128 _i128;
SPU_SPR_hdr() {}
std::string ToString() const
{
return fmt::Format("%08x%08x%08x%08x", _u32[3], _u32[2], _u32[1], _u32[0]);
}
void Reset()
{
memset(this, 0, sizeof(*this));
}
};
union SPU_SNRConfig_hdr union SPU_SNRConfig_hdr
{ {
u64 value; u64 value;
@ -307,13 +240,17 @@ union SPU_SNRConfig_hdr
} }
}; };
struct SpuGroupInfo;
class SPUThread : public PPCThread class SPUThread : public PPCThread
{ {
public: public:
SPU_GPR_hdr GPR[128]; //General-Purpose Register SPU_GPR_hdr GPR[128]; // General-Purpose Registers
SPU_SPR_hdr SPR[128]; //Special-Purpose Registers
//FPSCR FPSCR; //FPSCR FPSCR;
SPU_SNRConfig_hdr cfg; //Signal Notification Registers Configuration (OR-mode enabled: 0x1 for SNR1, 0x2 for SNR2) SPU_SNRConfig_hdr cfg; // Signal Notification Registers Configuration (OR-mode enabled: 0x1 for SNR1, 0x2 for SNR2)
u64 R_ADDR; // reservation address
u64 R_DATA[16]; // lock line data (BE)
EventPort SPUPs[64]; // SPU Thread Event Ports EventPort SPUPs[64]; // SPU Thread Event Ports
EventManager SPUQs; // SPU Queue Mapping EventManager SPUQs; // SPU Queue Mapping
@ -322,6 +259,9 @@ public:
u64 m_dec_start; // timestamp of writing decrementer value u64 m_dec_start; // timestamp of writing decrementer value
u32 m_dec_value; // written decrementer value u32 m_dec_value; // written decrementer value
u32 m_event_mask;
u32 m_events;
struct IntrTag struct IntrTag
{ {
u32 enabled; // 1 == true u32 enabled; // 1 == true
@ -555,17 +495,7 @@ public:
Channel<1> SNR[2]; Channel<1> SNR[2];
} SPU; } SPU;
void WriteSNR(bool number, u32 value) void WriteSNR(bool number, u32 value);
{
if (cfg.value & ((u64)1 << (u64)number))
{
SPU.SNR[number].PushUncond_OR(value); // logical OR
}
else
{
SPU.SNR[number].PushUncond(value); // overwrite
}
}
u32 LSA; u32 LSA;
@ -577,761 +507,21 @@ public:
DMAC dmac; DMAC dmac;
#define LOG_DMAC(type, text) type(Log::SPU, "DMAC::ProcessCmd(cmd=0x%x, tag=0x%x, lsa=0x%x, ea=0x%llx, size=0x%x): " text, cmd, tag, lsa, ea, size) void ProcessCmd(u32 cmd, u32 tag, u32 lsa, u64 ea, u32 size);
void ProcessCmd(u32 cmd, u32 tag, u32 lsa, u64 ea, u32 size) void ListCmd(u32 lsa, u64 ea, u16 tag, u16 size, u32 cmd, MFCReg& MFCArgs);
{
if (cmd & (MFC_BARRIER_MASK | MFC_FENCE_MASK)) _mm_mfence();
if (ea >= SYS_SPU_THREAD_BASE_LOW) void EnqMfcCmd(MFCReg& MFCArgs);
{
if (ea >= 0x100000000)
{
LOG_DMAC(LOG_ERROR, "Invalid external address");
Emu.Pause();
return;
}
else if (group)
{
// SPU Thread Group MMIO (LS and SNR)
u32 num = (ea & SYS_SPU_THREAD_BASE_MASK) / SYS_SPU_THREAD_OFFSET; // thread number in group
if (num >= group->list.size() || !group->list[num])
{
LOG_DMAC(LOG_ERROR, "Invalid thread (SPU Thread Group MMIO)");
Emu.Pause();
return;
}
SPUThread* spu = (SPUThread*)Emu.GetCPU().GetThread(group->list[num]); bool CheckEvents();
u32 addr = (ea & SYS_SPU_THREAD_BASE_MASK) % SYS_SPU_THREAD_OFFSET; u32 GetChannelCount(u32 ch);
if ((addr <= 0x3ffff) && (addr + size <= 0x40000))
{
// LS access
ea = spu->dmac.ls_offset + addr;
}
else if ((cmd & MFC_PUT_CMD) && size == 4 && (addr == SYS_SPU_THREAD_SNR1 || addr == SYS_SPU_THREAD_SNR2))
{
spu->WriteSNR(SYS_SPU_THREAD_SNR2 == addr, Memory.Read32(dmac.ls_offset + lsa));
return;
}
else
{
LOG_DMAC(LOG_ERROR, "Invalid register (SPU Thread Group MMIO)");
Emu.Pause();
return;
}
}
else
{
LOG_DMAC(LOG_ERROR, "Thread group not set (SPU Thread Group MMIO)");
Emu.Pause();
return;
}
}
else if (ea >= RAW_SPU_BASE_ADDR && size == 4)
{
switch (cmd & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK | MFC_LIST_MASK | MFC_RESULT_MASK))
{
case MFC_PUT_CMD:
{
Memory.Write32(ea, ReadLS32(lsa));
return;
}
case MFC_GET_CMD: void WriteChannel(u32 ch, const SPU_GPR_hdr& r);
{
WriteLS32(lsa, Memory.Read32(ea));
return;
}
default: void ReadChannel(SPU_GPR_hdr& r, u32 ch);
{
LOG_DMAC(LOG_ERROR, "Unknown DMA command");
Emu.Pause();
return;
}
}
}
switch (cmd & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK | MFC_LIST_MASK | MFC_RESULT_MASK)) void StopAndSignal(u32 code);
{
case MFC_PUT_CMD:
{
memcpy(Memory + ea, Memory + dmac.ls_offset + lsa, size);
return;
}
case MFC_GET_CMD:
{
memcpy(Memory + dmac.ls_offset + lsa, Memory + ea, size);
return;
}
default:
{
LOG_DMAC(LOG_ERROR, "Unknown DMA command");
Emu.Pause();
return;
}
}
}
#undef LOG_CMD
void ListCmd(u32 lsa, u64 ea, u16 tag, u16 size, u32 cmd, MFCReg& MFCArgs)
{
u32 list_addr = ea & 0x3ffff;
u32 list_size = size / 8;
lsa &= 0x3fff0;
struct list_element
{
be_t<u16> s; // Stall-and-Notify bit (0x8000)
be_t<u16> ts; // List Transfer Size
be_t<u32> ea; // External Address Low
};
u32 result = MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL;
for (u32 i = 0; i < list_size; i++)
{
mem_ptr_t<list_element> rec(dmac.ls_offset + list_addr + i * 8);
u32 size = rec->ts;
if (size < 16 && size != 1 && size != 2 && size != 4 && size != 8)
{
LOG_ERROR(Log::SPU, "DMA List: invalid transfer size(%d)", size);
result = MFC_PPU_DMA_CMD_SEQUENCE_ERROR;
break;
}
u32 addr = rec->ea;
ProcessCmd(cmd, tag, lsa | (addr & 0xf), addr, size);
if (Ini.HLELogging.GetValue() || rec->s)
LOG_NOTICE(Log::SPU, "*** list element(%d/%d): s = 0x%x, ts = 0x%x, low ea = 0x%x (lsa = 0x%x)",
i, list_size, (u16)rec->s, (u16)rec->ts, (u32)rec->ea, lsa | (addr & 0xf));
lsa += std::max(size, (u32)16);
if (rec->s & se16(0x8000))
{
StallStat.PushUncond_OR(1 << tag);
if (StallList[tag].MFCArgs)
{
LOG_ERROR(Log::SPU, "DMA List: existing stalled list found (tag=%d)", tag);
result = MFC_PPU_DMA_CMD_SEQUENCE_ERROR;
break;
}
StallList[tag].MFCArgs = &MFCArgs;
StallList[tag].cmd = cmd;
StallList[tag].ea = (ea & ~0xffffffff) | (list_addr + (i + 1) * 8);
StallList[tag].lsa = lsa;
StallList[tag].size = (list_size - i - 1) * 8;
break;
}
}
MFCArgs.CMDStatus.SetValue(result);
}
void EnqMfcCmd(MFCReg& MFCArgs)
{
u32 cmd = MFCArgs.CMDStatus.GetValue();
u16 op = cmd & MFC_MASK_CMD;
u32 lsa = MFCArgs.LSA.GetValue();
u64 ea = (u64)MFCArgs.EAL.GetValue() | ((u64)MFCArgs.EAH.GetValue() << 32);
u32 size_tag = MFCArgs.Size_Tag.GetValue();
u16 tag = (u16)size_tag;
u16 size = size_tag >> 16;
switch(op & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK))
{
case MFC_PUT_CMD:
case MFC_PUTR_CMD: // ???
case MFC_GET_CMD:
{
if (Ini.HLELogging.GetValue()) LOG_NOTICE(Log::SPU, "DMA %s%s%s%s: lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x, cmd = 0x%x",
(op & MFC_PUT_CMD ? "PUT" : "GET"),
(op & MFC_RESULT_MASK ? "R" : ""),
(op & MFC_BARRIER_MASK ? "B" : ""),
(op & MFC_FENCE_MASK ? "F" : ""),
lsa, ea, tag, size, cmd);
ProcessCmd(cmd, tag, lsa, ea, size);
MFCArgs.CMDStatus.SetValue(MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL);
}
break;
case MFC_PUTL_CMD:
case MFC_PUTRL_CMD: // ???
case MFC_GETL_CMD:
{
if (Ini.HLELogging.GetValue()) LOG_NOTICE(Log::SPU, "DMA %s%s%s%s: lsa = 0x%x, list = 0x%llx, tag = 0x%x, size = 0x%x, cmd = 0x%x",
(op & MFC_PUT_CMD ? "PUT" : "GET"),
(op & MFC_RESULT_MASK ? "RL" : "L"),
(op & MFC_BARRIER_MASK ? "B" : ""),
(op & MFC_FENCE_MASK ? "F" : ""),
lsa, ea, tag, size, cmd);
ListCmd(lsa, ea, tag, size, cmd, MFCArgs);
}
break;
case MFC_GETLLAR_CMD:
case MFC_PUTLLC_CMD:
case MFC_PUTLLUC_CMD:
case MFC_PUTQLLUC_CMD:
{
if (Ini.HLELogging.GetValue() || size != 128) LOG_NOTICE(Log::SPU, "DMA %s: lsa=0x%x, ea = 0x%llx, (tag) = 0x%x, (size) = 0x%x, cmd = 0x%x",
(op == MFC_GETLLAR_CMD ? "GETLLAR" :
op == MFC_PUTLLC_CMD ? "PUTLLC" :
op == MFC_PUTLLUC_CMD ? "PUTLLUC" : "PUTQLLUC"),
lsa, ea, tag, size, cmd);
if (op == MFC_GETLLAR_CMD) // get reservation
{
SMutexLockerR lock(reservation.mutex);
reservation.owner = lock.tid;
reservation.addr = ea;
reservation.size = 128;
for (u32 i = 0; i < 8; i++)
{
reservation.data[i] = *(u128*)&Memory[(u32)ea + i * 16];
*(u128*)&Memory[dmac.ls_offset + lsa + i * 16] = reservation.data[i];
}
MFCArgs.AtomicStat.PushUncond(MFC_GETLLAR_SUCCESS);
}
else if (op == MFC_PUTLLC_CMD) // store conditional
{
SMutexLockerR lock(reservation.mutex);
if (reservation.owner == lock.tid) // succeeded
{
if (reservation.addr == ea && reservation.size == 128)
{
u128 buf[8]; // data being written newly
u32 changed = 0, mask = 0, last = 0;
for (u32 i = 0; i < 8; i++)
{
buf[i] = *(u128*)&Memory[dmac.ls_offset + lsa + i * 16];
if (buf[i] != reservation.data[i])
{
changed++;
last = i;
mask |= (0xf << (i * 4));
}
}
if (changed == 0) // nothing changed?
{
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS);
}
else if (changed == 1)
{
if (buf[last].hi != reservation.data[last].hi && buf[last].lo != reservation.data[last].lo)
{
LOG_ERROR(Log::SPU, "MFC_PUTLLC_CMD: TODO: 128bit compare and swap");
Emu.Pause();
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS);
}
else
{
const u32 last_q = (buf[last].hi == reservation.data[last].hi);
if (InterlockedCompareExchange64((volatile long long*)(Memory + (u32)ea + last * 16 + last_q * 8),
buf[last]._u64[last_q], reservation.data[last]._u64[last_q]) == reservation.data[last]._u64[last_q])
{
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS);
}
else
{
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE);
}
}
}
else
{
ProcessCmd(MFC_PUT_CMD, tag, lsa, ea, 128);
LOG_ERROR(Log::SPU, "MFC_PUTLLC_CMD: Reservation Error: impossibru (~ 16x%d (mask=0x%x)) (opcode=0x%x, cmd=0x%x, lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x)",
changed, mask, op, cmd, lsa, ea, tag, size);
Emu.Pause();
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_SUCCESS);
}
}
else
{
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE);
}
reservation.clear();
}
else // failed
{
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLC_FAILURE);
}
}
else // store unconditional
{
SMutexLockerR lock(reservation.mutex);
ProcessCmd(MFC_PUT_CMD, tag, lsa, ea, 128);
if (op == MFC_PUTLLUC_CMD)
{
MFCArgs.AtomicStat.PushUncond(MFC_PUTLLUC_SUCCESS);
}
if ((reservation.addr + reservation.size > ea && reservation.addr <= ea + size) ||
(ea + size > reservation.addr && ea <= reservation.addr + reservation.size))
{
reservation.clear();
}
}
}
break;
default:
LOG_ERROR( Log::SPU, "Unknown MFC cmd. (opcode=0x%x, cmd=0x%x, lsa = 0x%x, ea = 0x%llx, tag = 0x%x, size = 0x%x)",
op, cmd, lsa, ea, tag, size);
break;
}
}
u32 GetChannelCount(u32 ch)
{
switch(ch)
{
case SPU_WrOutMbox: return SPU.Out_MBox.GetFreeCount();
case SPU_WrOutIntrMbox: return SPU.Out_IntrMBox.GetFreeCount();
case SPU_RdInMbox: return SPU.In_MBox.GetCount();
case MFC_RdTagStat: return MFC1.TagStatus.GetCount();
case MFC_RdListStallStat: return StallStat.GetCount();
case MFC_WrTagUpdate: return MFC1.TagStatus.GetCount(); // hack
case SPU_RdSigNotify1: return SPU.SNR[0].GetCount();
case SPU_RdSigNotify2: return SPU.SNR[1].GetCount();
case MFC_RdAtomicStat: return MFC1.AtomicStat.GetCount();
default:
{
LOG_ERROR(Log::SPU, "%s error: unknown/illegal channel (%d [%s]).",
__FUNCTION__, ch, spu_ch_name[ch]);
return 0;
}
}
}
void WriteChannel(u32 ch, const SPU_GPR_hdr& r)
{
const u32 v = r._u32[3];
switch(ch)
{
case SPU_WrOutIntrMbox:
{
if (!group) // if RawSPU
{
if (Ini.HLELogging.GetValue()) LOG_NOTICE(Log::SPU, "SPU_WrOutIntrMbox: interrupt(v=0x%x)", v);
while (!SPU.Out_IntrMBox.Push(v))
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
if (Emu.IsStopped())
{
LOG_WARNING(Log::SPU, "%s(%s) aborted (I)", __FUNCTION__, spu_ch_name[ch]);
return;
}
}
m_intrtag[2].stat |= 1;
if (CPUThread* t = Emu.GetCPU().GetThread(m_intrtag[2].thread))
{
while (t->IsAlive()) // TODO: ???
{
std::this_thread::sleep_for(std::chrono::milliseconds(1));
if (Emu.IsStopped())
{
LOG_WARNING(Log::SPU, "%s(%s) aborted (II)", __FUNCTION__, spu_ch_name[ch]);
return;
}
}
t->SetArg(0, t->m_interrupt_arg);
t->Run();
t->Exec();
}
}
else
{
u8 code = v >> 24;
if (code < 64)
{
/* ===== sys_spu_thread_send_event ===== */
u8 spup = code & 63;
u32 data;
if (!SPU.Out_MBox.Pop(data))
{
LOG_ERROR(Log::SPU, "sys_spu_thread_send_event(v=0x%x, spup=%d): Out_MBox is empty", v, spup);
return;
}
if (SPU.In_MBox.GetCount())
{
LOG_ERROR(Log::SPU, "sys_spu_thread_send_event(v=0x%x, spup=%d): In_MBox is not empty", v, spup);
SPU.In_MBox.PushUncond(CELL_EBUSY); // ???
return;
}
if (Ini.HLELogging.GetValue())
{
LOG_NOTICE(Log::SPU, "sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x)", spup, v & 0x00ffffff, data);
}
EventPort& port = SPUPs[spup];
std::lock_guard<std::mutex> lock(port.m_mutex);
if (!port.eq)
{
// spu_printf fails there
LOG_WARNING(Log::SPU, "sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x): event queue not connected", spup, (v & 0x00ffffff), data);
SPU.In_MBox.PushUncond(CELL_ENOTCONN); // TODO: check error passing
return;
}
if (!port.eq->events.push(SYS_SPU_THREAD_EVENT_USER_KEY, GetCurrentCPUThread()->GetId(), ((u64)code << 32) | (v & 0x00ffffff), data))
{
SPU.In_MBox.PushUncond(CELL_EBUSY);
return;
}
SPU.In_MBox.PushUncond(CELL_OK);
return;
}
else if (code == 128)
{
/* ===== sys_event_flag_set_bit ===== */
u32 flag = v & 0xffffff;
u32 data;
if (!SPU.Out_MBox.Pop(data))
{
LOG_ERROR(Log::SPU, "sys_event_flag_set_bit(v=0x%x (flag=%d)): Out_MBox is empty", v, flag);
return;
}
if (flag > 63)
{
LOG_ERROR(Log::SPU, "sys_event_flag_set_bit(id=%d, v=0x%x): flag > 63", data, v, flag);
return;
}
//if (Ini.HLELogging.GetValue())
{
LOG_WARNING(Log::SPU, "sys_event_flag_set_bit(id=%d, v=0x%x (flag=%d))", data, v, flag);
}
EventFlag* ef;
if (!Emu.GetIdManager().GetIDData(data, ef))
{
LOG_ERROR(Log::SPU, "sys_event_flag_set_bit(id=%d, v=0x%x (flag=%d)): EventFlag not found", data, v, flag);
SPU.In_MBox.PushUncond(CELL_ESRCH);
return;
}
u32 tid = GetCurrentCPUThread()->GetId();
ef->m_mutex.lock(tid);
ef->flags |= (u64)1 << flag;
if (u32 target = ef->check())
{
// if signal, leave both mutexes locked...
ef->signal.lock(target);
ef->m_mutex.unlock(tid, target);
}
else
{
ef->m_mutex.unlock(tid);
}
SPU.In_MBox.PushUncond(CELL_OK);
return;
}
else
{
u32 data;
if (SPU.Out_MBox.Pop(data))
{
LOG_ERROR(Log::SPU, "SPU_WrOutIntrMbox: unknown data (v=0x%x); Out_MBox = 0x%x", v, data);
}
else
{
LOG_ERROR(Log::SPU, "SPU_WrOutIntrMbox: unknown data (v=0x%x)", v);
}
SPU.In_MBox.PushUncond(CELL_EINVAL); // ???
return;
}
}
break;
}
case SPU_WrOutMbox:
{
while (!SPU.Out_MBox.Push(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
break;
}
case MFC_WrTagMask:
{
MFC1.QueryMask.SetValue(v);
break;
}
case MFC_WrTagUpdate:
{
MFC1.TagStatus.PushUncond(MFC1.QueryMask.GetValue());
break;
}
case MFC_LSA:
{
MFC1.LSA.SetValue(v);
break;
}
case MFC_EAH:
{
MFC1.EAH.SetValue(v);
break;
}
case MFC_EAL:
{
MFC1.EAL.SetValue(v);
break;
}
case MFC_Size:
{
MFC1.Size_Tag.SetValue((MFC1.Size_Tag.GetValue() & 0xffff) | (v << 16));
break;
}
case MFC_TagID:
{
MFC1.Size_Tag.SetValue((MFC1.Size_Tag.GetValue() & ~0xffff) | (v & 0xffff));
break;
}
case MFC_Cmd:
{
MFC1.CMDStatus.SetValue(v);
EnqMfcCmd(MFC1);
break;
}
case MFC_WrListStallAck:
{
if (v >= 32)
{
LOG_ERROR(Log::SPU, "MFC_WrListStallAck error: invalid tag(%d)", v);
return;
}
StalledList temp = StallList[v];
if (!temp.MFCArgs)
{
LOG_ERROR(Log::SPU, "MFC_WrListStallAck error: empty tag(%d)", v);
return;
}
StallList[v].MFCArgs = nullptr;
ListCmd(temp.lsa, temp.ea, temp.tag, temp.size, temp.cmd, *temp.MFCArgs);
break;
}
case SPU_WrDec:
{
m_dec_start = get_time();
m_dec_value = v;
break;
}
default:
{
LOG_ERROR(Log::SPU, "%s error: unknown/illegal channel (%d [%s]).", __FUNCTION__, ch, spu_ch_name[ch]);
break;
}
}
if (Emu.IsStopped()) LOG_WARNING(Log::SPU, "%s(%s) aborted", __FUNCTION__, spu_ch_name[ch]);
}
void ReadChannel(SPU_GPR_hdr& r, u32 ch)
{
r.Reset();
u32& v = r._u32[3];
switch(ch)
{
case SPU_RdInMbox:
{
while (!SPU.In_MBox.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
break;
}
case MFC_RdTagStat:
{
while (!MFC1.TagStatus.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
break;
}
case SPU_RdSigNotify1:
{
while (!SPU.SNR[0].Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
break;
}
case SPU_RdSigNotify2:
{
while (!SPU.SNR[1].Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
break;
}
case MFC_RdAtomicStat:
{
while (!MFC1.AtomicStat.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
break;
}
case MFC_RdListStallStat:
{
while (!StallStat.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1));
break;
}
case SPU_RdDec:
{
v = m_dec_value - (u32)(get_time() - m_dec_start);
break;
}
default:
{
LOG_ERROR(Log::SPU, "%s error: unknown/illegal channel (%d [%s]).", __FUNCTION__, ch, spu_ch_name[ch]);
break;
}
}
if (Emu.IsStopped()) LOG_WARNING(Log::SPU, "%s(%s) aborted", __FUNCTION__, spu_ch_name[ch]);
}
void DoStop(u32 code)
{
SetExitStatus(code); // exit code (not status)
switch (code)
{
case 0x110: /* ===== sys_spu_thread_receive_event ===== */
{
u32 spuq = 0;
if (!SPU.Out_MBox.Pop(spuq))
{
LOG_ERROR(Log::SPU, "sys_spu_thread_receive_event: cannot read Out_MBox");
SPU.In_MBox.PushUncond(CELL_EINVAL); // ???
return;
}
if (SPU.In_MBox.GetCount())
{
LOG_ERROR(Log::SPU, "sys_spu_thread_receive_event(spuq=0x%x): In_MBox is not empty", spuq);
SPU.In_MBox.PushUncond(CELL_EBUSY); // ???
return;
}
if (Ini.HLELogging.GetValue())
{
LOG_NOTICE(Log::SPU, "sys_spu_thread_receive_event(spuq=0x%x)", spuq);
}
EventQueue* eq;
if (!SPUQs.GetEventQueue(FIX_SPUQ(spuq), eq))
{
SPU.In_MBox.PushUncond(CELL_EINVAL); // TODO: check error value
return;
}
u32 tid = GetId();
eq->sq.push(tid); // add thread to sleep queue
while (true)
{
switch (eq->owner.trylock(tid))
{
case SMR_OK:
if (!eq->events.count())
{
eq->owner.unlock(tid);
break;
}
else
{
u32 next = (eq->protocol == SYS_SYNC_FIFO) ? eq->sq.pop() : eq->sq.pop_prio();
if (next != tid)
{
eq->owner.unlock(tid, next);
break;
}
}
case SMR_SIGNAL:
{
sys_event_data event;
eq->events.pop(event);
eq->owner.unlock(tid);
SPU.In_MBox.PushUncond(CELL_OK);
SPU.In_MBox.PushUncond(event.data1);
SPU.In_MBox.PushUncond(event.data2);
SPU.In_MBox.PushUncond(event.data3);
return;
}
case SMR_FAILED: break;
default: eq->sq.invalidate(tid); SPU.In_MBox.PushUncond(CELL_ECANCELED); return;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
if (Emu.IsStopped())
{
LOG_WARNING(Log::SPU, "sys_spu_thread_receive_event(spuq=0x%x) aborted", spuq);
eq->sq.invalidate(tid);
return;
}
}
}
break;
case 0x102:
if (!SPU.Out_MBox.GetCount())
{
LOG_ERROR(Log::SPU, "sys_spu_thread_exit (no status, code 0x102)");
}
else if (Ini.HLELogging.GetValue())
{
// the real exit status
LOG_NOTICE(Log::SPU, "sys_spu_thread_exit (status=0x%x)", SPU.Out_MBox.GetValue());
}
SPU.Status.SetValue(SPU_STATUS_STOPPED_BY_STOP);
Stop();
break;
default:
if (!SPU.Out_MBox.GetCount())
{
LOG_ERROR(Log::SPU, "Unknown STOP code: 0x%x (no message)", code);
}
else
{
LOG_ERROR(Log::SPU, "Unknown STOP code: 0x%x (message=0x%x)", code, SPU.Out_MBox.GetValue());
}
SPU.Status.SetValue(SPU_STATUS_STOPPED_BY_STOP);
Stop();
break;
}
}
virtual u8 ReadLS8 (const u32 lsa) const { return Memory.Read8 (lsa + m_offset); } virtual u8 ReadLS8 (const u32 lsa) const { return Memory.Read8 (lsa + m_offset); }
virtual u16 ReadLS16 (const u32 lsa) const { return Memory.Read16 (lsa + m_offset); } virtual u16 ReadLS16 (const u32 lsa) const { return Memory.Read16 (lsa + m_offset); }

View file

@ -1,7 +1,6 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" //#include "Emu/System.h"
#include "Event.h" #include "Event.h"
void EventManager::Init() void EventManager::Init()

View file

@ -1,5 +1,5 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h" #include <memory>
#include "VFS.h" #include "VFS.h"
#include "Emu/HDD/HDD.h" #include "Emu/HDD/HDD.h"

View file

@ -1,5 +1,4 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "vfsDir.h" #include "vfsDir.h"

View file

@ -1,5 +1,4 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "vfsFile.h" #include "vfsFile.h"

View file

@ -1,5 +1,4 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "vfsStreamMemory.h" #include "vfsStreamMemory.h"
@ -32,7 +31,7 @@ u64 vfsStreamMemory::Write(const void* src, u64 size)
size = GetSize() - Tell(); size = GetSize() - Tell();
} }
memcpy(Memory + m_addr + Tell(), (void*)src, size); memcpy(Memory + (m_addr + Tell()), (void*)src, size);
return vfsStream::Write(src, size); return vfsStream::Write(src, size);
} }
@ -44,7 +43,7 @@ u64 vfsStreamMemory::Read(void* dst, u64 size)
size = GetSize() - Tell(); size = GetSize() - Tell();
} }
memcpy(dst, Memory + m_addr + Tell(), size); memcpy(dst, Memory + (m_addr + Tell()), size);
return vfsStream::Read(dst, size); return vfsStream::Read(dst, size);
} }

View file

@ -2,6 +2,337 @@
#include "Utilities/Log.h" #include "Utilities/Log.h"
#include "HDD.h" #include "HDD.h"
void vfsHDDManager::CreateBlock(vfsHDD_Block& block)
{
block.is_used = true;
block.next_block = 0;
}
void vfsHDDManager::CreateEntry(vfsHDD_Entry& entry)
{
memset(&entry, 0, sizeof(vfsHDD_Entry));
u64 ctime = time(nullptr);
entry.atime = ctime;
entry.ctime = ctime;
entry.mtime = ctime;
entry.access = vfsReadWrite;
CreateBlock(entry);
}
void vfsHDDManager::CreateHDD(const std::string& path, u64 size, u64 block_size)
{
rFile f(path, rFile::write);
static const u64 cur_dir_block = 1;
vfsHDD_Hdr hdr;
CreateBlock(hdr);
hdr.next_block = cur_dir_block;
hdr.magic = g_hdd_magic;
hdr.version = g_hdd_version;
hdr.block_count = (size + block_size) / block_size;
hdr.block_size = block_size;
f.Write(&hdr, sizeof(vfsHDD_Hdr));
{
vfsHDD_Entry entry;
CreateEntry(entry);
entry.type = vfsHDD_Entry_Dir;
entry.data_block = hdr.next_block;
entry.next_block = 0;
f.Seek(cur_dir_block * hdr.block_size);
f.Write(&entry, sizeof(vfsHDD_Entry));
f.Write(".");
}
u8 null = 0;
f.Seek(hdr.block_count * hdr.block_size - sizeof(null));
f.Write(&null, sizeof(null));
}
void vfsHDDManager::Format()
{
}
void vfsHDDManager::AppendEntry(vfsHDD_Entry entry)
{
}
bool vfsHDDFile::goto_block(u64 n)
{
vfsHDD_Block block_info;
if (m_info.data_block >= m_hdd_info.block_count)
{
return false;
}
m_hdd.Seek(m_info.data_block * m_hdd_info.block_size);
block_info.next_block = m_info.data_block;
for (u64 i = 0; i<n; ++i)
{
if (!block_info.next_block || !block_info.is_used || block_info.next_block >= m_hdd_info.block_count)
{
return false;
}
m_hdd.Seek(block_info.next_block * m_hdd_info.block_size);
m_hdd.Read(&block_info, sizeof(vfsHDD_Block));
}
return true;
}
void vfsHDDFile::RemoveBlocks(u64 start_block)
{
vfsHDD_Block block_info;
block_info.next_block = start_block;
while (block_info.next_block && block_info.is_used)
{
u64 offset = block_info.next_block * m_hdd_info.block_size;
ReadBlock(offset, block_info);
WriteBlock(offset, g_null_block);
}
}
void vfsHDDFile::WriteBlock(u64 block, const vfsHDD_Block& data)
{
m_hdd.Seek(block * m_hdd_info.block_size);
m_hdd.Write(&data, sizeof(vfsHDD_Block));
}
void vfsHDDFile::ReadBlock(u64 block, vfsHDD_Block& data)
{
m_hdd.Seek(block * m_hdd_info.block_size);
m_hdd.Read(&data, sizeof(vfsHDD_Block));
}
void vfsHDDFile::WriteEntry(u64 block, const vfsHDD_Entry& data)
{
m_hdd.Seek(block * m_hdd_info.block_size);
m_hdd.Write(&data, sizeof(vfsHDD_Entry));
}
void vfsHDDFile::ReadEntry(u64 block, vfsHDD_Entry& data)
{
m_hdd.Seek(block * m_hdd_info.block_size);
m_hdd.Read(&data, sizeof(vfsHDD_Entry));
}
void vfsHDDFile::ReadEntry(u64 block, vfsHDD_Entry& data, std::string& name)
{
m_hdd.Seek(block * m_hdd_info.block_size);
m_hdd.Read(&data, sizeof(vfsHDD_Entry));
name.resize(GetMaxNameLen());
m_hdd.Read(&name.front(), GetMaxNameLen());
}
void vfsHDDFile::ReadEntry(u64 block, std::string& name)
{
m_hdd.Seek(block * m_hdd_info.block_size + sizeof(vfsHDD_Entry));
name.resize(GetMaxNameLen());
m_hdd.Read(&name.front(), GetMaxNameLen());
}
void vfsHDDFile::WriteEntry(u64 block, const vfsHDD_Entry& data, const std::string& name)
{
m_hdd.Seek(block * m_hdd_info.block_size);
m_hdd.Write(&data, sizeof(vfsHDD_Entry));
m_hdd.Write(name.c_str(), std::min<size_t>(GetMaxNameLen() - 1, name.length() + 1));
}
void vfsHDDFile::Open(u64 info_block)
{
m_info_block = info_block;
ReadEntry(m_info_block, m_info);
m_position = 0;
m_cur_block = m_info.data_block;
}
u64 vfsHDDFile::FindFreeBlock()
{
vfsHDD_Block block_info;
for (u64 i = 0; i<m_hdd_info.block_count; ++i)
{
ReadBlock(i, block_info);
if (!block_info.is_used)
{
return i;
}
}
return 0;
}
bool vfsHDDFile::Seek(u64 pos)
{
if (!goto_block(pos / m_hdd_info.block_size))
{
return false;
}
m_position = pos % m_hdd_info.block_size;
return true;
}
void vfsHDDFile::SaveInfo()
{
m_hdd.Seek(m_info_block * m_hdd_info.block_size);
m_hdd.Write(&m_info, sizeof(vfsHDD_Entry));
}
u64 vfsHDDFile::Read(void* dst, u64 size)
{
if (!size)
return 0;
//vfsDeviceLocker lock(m_hdd);
const u32 block_size = m_hdd_info.block_size - sizeof(vfsHDD_Block);
u64 rsize = std::min<u64>(block_size - m_position, size);
vfsHDD_Block cur_block_info;
m_hdd.Seek(m_cur_block * m_hdd_info.block_size);
m_hdd.Read(&cur_block_info, sizeof(vfsHDD_Block));
m_hdd.Seek(m_cur_block * m_hdd_info.block_size + sizeof(vfsHDD_Block)+m_position);
m_hdd.Read(dst, rsize);
size -= rsize;
m_position += rsize;
if (!size)
{
return rsize;
}
u64 offset = rsize;
for (; size; size -= rsize, offset += rsize)
{
if (!cur_block_info.is_used || !cur_block_info.next_block || cur_block_info.next_block >= m_hdd_info.block_count)
{
return offset;
}
m_cur_block = cur_block_info.next_block;
rsize = std::min<u64>(block_size, size);
m_hdd.Seek(cur_block_info.next_block * m_hdd_info.block_size);
m_hdd.Read(&cur_block_info, sizeof(vfsHDD_Block));
if (m_hdd.Read((u8*)dst + offset, rsize) != rsize)
{
return offset;
}
}
m_position = rsize;
return offset;
}
u64 vfsHDDFile::Write(const void* src, u64 size)
{
if (!size)
return 0;
//vfsDeviceLocker lock(m_hdd);
const u32 block_size = m_hdd_info.block_size - sizeof(vfsHDD_Block);
if (!m_cur_block)
{
if (!m_info.data_block)
{
u64 new_block = FindFreeBlock();
if (!new_block)
{
return 0;
}
WriteBlock(new_block, g_used_block);
m_info.data_block = new_block;
m_info.size = 0;
SaveInfo();
}
m_cur_block = m_info.data_block;
m_position = 0;
}
u64 wsize = std::min<u64>(block_size - m_position, size);
vfsHDD_Block block_info;
ReadBlock(m_cur_block, block_info);
if (wsize)
{
m_hdd.Seek(m_cur_block * m_hdd_info.block_size + sizeof(vfsHDD_Block)+m_position);
m_hdd.Write(src, wsize);
size -= wsize;
m_info.size += wsize;
m_position += wsize;
SaveInfo();
if (!size)
return wsize;
}
u64 last_block = m_cur_block;
block_info.is_used = true;
u64 offset = wsize;
for (; size; size -= wsize, offset += wsize, m_info.size += wsize)
{
u64 new_block = FindFreeBlock();
if (!new_block)
{
m_position = 0;
SaveInfo();
return offset;
}
m_cur_block = new_block;
wsize = std::min<u64>(block_size, size);
block_info.next_block = m_cur_block;
m_hdd.Seek(last_block * m_hdd_info.block_size);
if (m_hdd.Write(&block_info, sizeof(vfsHDD_Block)) != sizeof(vfsHDD_Block))
{
m_position = 0;
SaveInfo();
return offset;
}
block_info.next_block = 0;
m_hdd.Seek(m_cur_block * m_hdd_info.block_size);
if (m_hdd.Write(&block_info, sizeof(vfsHDD_Block)) != sizeof(vfsHDD_Block))
{
m_position = 0;
SaveInfo();
return offset;
}
if ((m_position = m_hdd.Write((u8*)src + offset, wsize)) != wsize)
{
m_info.size += wsize;
SaveInfo();
return offset;
}
last_block = m_cur_block;
}
SaveInfo();
m_position = wsize;
return offset;
}
vfsDeviceHDD::vfsDeviceHDD(const std::string& hdd_path) : m_hdd_path(hdd_path) vfsDeviceHDD::vfsDeviceHDD(const std::string& hdd_path) : m_hdd_path(hdd_path)
{ {
} }
@ -15,3 +346,438 @@ vfsDirBase* vfsDeviceHDD::GetNewDirStream()
{ {
return nullptr; return nullptr;
} }
vfsHDD::vfsHDD(vfsDevice* device, const std::string& hdd_path)
: m_hdd_file(device)
, m_file(m_hdd_file, m_hdd_info)
, m_hdd_path(hdd_path)
, vfsFileBase(device)
{
m_hdd_file.Open(hdd_path, vfsReadWrite);
m_hdd_file.Read(&m_hdd_info, sizeof(vfsHDD_Hdr));
m_cur_dir_block = m_hdd_info.next_block;
if (!m_hdd_info.block_size)
{
LOG_ERROR(HLE, "Bad block size!");
m_hdd_info.block_size = 2048;
}
m_hdd_file.Seek(m_cur_dir_block * m_hdd_info.block_size);
m_hdd_file.Read(&m_cur_dir, sizeof(vfsHDD_Entry));
}
bool vfsHDD::SearchEntry(const std::string& name, u64& entry_block, u64* parent_block)
{
u64 last_block = 0;
u64 block = m_cur_dir_block;
vfsHDD_Entry entry;
std::string buf;
while (block)
{
ReadEntry(block, entry, buf);
if (fmt::CmpNoCase(name, buf) == 0)
{
entry_block = block;
if (parent_block)
*parent_block = last_block;
return true;
}
last_block = block;
block = entry.is_used ? entry.next_block : 0ULL;
}
return false;
}
int vfsHDD::OpenDir(const std::string& name)
{
LOG_WARNING(HLE, "OpenDir(%s)", name.c_str());
u64 entry_block;
if (!SearchEntry(name, entry_block))
return -1;
m_hdd_file.Seek(entry_block * m_hdd_info.block_size);
vfsHDD_Entry entry;
m_hdd_file.Read(&entry, sizeof(vfsHDD_Entry));
if (entry.type == vfsHDD_Entry_File)
return 1;
m_cur_dir_block = entry.data_block;
ReadEntry(m_cur_dir_block, m_cur_dir);
return 0;
}
bool vfsHDD::Rename(const std::string& from, const std::string& to)
{
u64 entry_block;
if (!SearchEntry(from, entry_block))
{
return false;
}
vfsHDD_Entry entry;
ReadEntry(entry_block, entry);
WriteEntry(entry_block, entry, to);
return true;
}
u64 vfsHDD::FindFreeBlock()
{
vfsHDD_Block block_info;
for (u64 i = 0; i<m_hdd_info.block_count; ++i)
{
ReadBlock(i, block_info);
if (!block_info.is_used)
{
return i;
}
}
return 0;
}
void vfsHDD::WriteBlock(u64 block, const vfsHDD_Block& data)
{
m_hdd_file.Seek(block * m_hdd_info.block_size);
m_hdd_file.Write(&data, sizeof(vfsHDD_Block));
}
void vfsHDD::ReadBlock(u64 block, vfsHDD_Block& data)
{
m_hdd_file.Seek(block * m_hdd_info.block_size);
m_hdd_file.Read(&data, sizeof(vfsHDD_Block));
}
void vfsHDD::WriteEntry(u64 block, const vfsHDD_Entry& data)
{
m_hdd_file.Seek(block * m_hdd_info.block_size);
m_hdd_file.Write(&data, sizeof(vfsHDD_Entry));
}
void vfsHDD::ReadEntry(u64 block, vfsHDD_Entry& data)
{
m_hdd_file.Seek(block * m_hdd_info.block_size);
m_hdd_file.Read(&data, sizeof(vfsHDD_Entry));
}
void vfsHDD::ReadEntry(u64 block, vfsHDD_Entry& data, std::string& name)
{
m_hdd_file.Seek(block * m_hdd_info.block_size);
m_hdd_file.Read(&data, sizeof(vfsHDD_Entry));
name.resize(GetMaxNameLen());
m_hdd_file.Read(&name.front(), GetMaxNameLen());
}
void vfsHDD::ReadEntry(u64 block, std::string& name)
{
m_hdd_file.Seek(block * m_hdd_info.block_size + sizeof(vfsHDD_Entry));
name.resize(GetMaxNameLen());
m_hdd_file.Read(&name.front(), GetMaxNameLen());
}
void vfsHDD::WriteEntry(u64 block, const vfsHDD_Entry& data, const std::string& name)
{
m_hdd_file.Seek(block * m_hdd_info.block_size);
m_hdd_file.Write(&data, sizeof(vfsHDD_Entry));
m_hdd_file.Write(name.c_str(), std::min<size_t>(GetMaxNameLen() - 1, name.length() + 1));
}
bool vfsHDD::Create(vfsHDD_EntryType type, const std::string& name)
{
if (HasEntry(name))
{
return false;
}
u64 new_block = FindFreeBlock();
if (!new_block)
{
return false;
}
LOG_NOTICE(HLE, "CREATING ENTRY AT 0x%llx", new_block);
WriteBlock(new_block, g_used_block);
{
vfsHDD_Entry new_entry;
vfsHDDManager::CreateEntry(new_entry);
new_entry.next_block = 0;
new_entry.type = type;
if (type == vfsHDD_Entry_Dir)
{
u64 block_cur = FindFreeBlock();
if (!block_cur)
{
return false;
}
WriteBlock(block_cur, g_used_block);
u64 block_last = FindFreeBlock();
if (!block_last)
{
return false;
}
WriteBlock(block_last, g_used_block);
vfsHDD_Entry entry_cur, entry_last;
vfsHDDManager::CreateEntry(entry_cur);
vfsHDDManager::CreateEntry(entry_last);
entry_cur.type = vfsHDD_Entry_Dir;
entry_cur.data_block = block_cur;
entry_cur.next_block = block_last;
entry_last.type = vfsHDD_Entry_Dir;
entry_last.data_block = m_cur_dir_block;
entry_last.next_block = 0;
new_entry.data_block = block_cur;
WriteEntry(block_cur, entry_cur, ".");
WriteEntry(block_last, entry_last, "..");
}
WriteEntry(new_block, new_entry, name);
}
{
u64 block = m_cur_dir_block;
vfsHDD_Block tmp;
while (block)
{
ReadBlock(block, tmp);
if (!tmp.next_block)
break;
block = tmp.next_block;
}
tmp.next_block = new_block;
WriteBlock(block, tmp);
}
return true;
}
bool vfsHDD::GetFirstEntry(u64& block, vfsHDD_Entry& entry, std::string& name)
{
if (!m_cur_dir_block)
{
return false;
}
ReadEntry(m_cur_dir_block, entry, name);
block = entry.is_used ? entry.next_block : 0;
return true;
}
bool vfsHDD::GetNextEntry(u64& block, vfsHDD_Entry& entry, std::string& name)
{
if (!block)
{
return false;
}
ReadEntry(block, entry, name);
block = entry.is_used ? entry.next_block : 0;
return true;
}
bool vfsHDD::Open(const std::string& path, vfsOpenMode mode)
{
const char* s = path.c_str();
u64 from = 0;
u64 pos = 0;
u64 file_pos = -1;
do
{
if (s[pos] == '\\' || s[pos] == '/' || s[pos] == '\0') // ???
{
if (file_pos != -1)
{
return false;
}
if (from != -1)
{
if (pos - from > 1)
{
int res = OpenDir(std::string(s + from, pos));
if (res == -1)
{
return false;
}
if (res == 1)
{
file_pos = from;
}
}
from = pos;
}
else
{
from = pos;
}
}
} while (s[pos++] != '\0');
if (file_pos == -1)
{
return false;
}
u64 file_block;
if (!SearchEntry(std::string(s + file_pos), file_block))
{
return false;
}
LOG_NOTICE(HLE, "ENTRY FOUND AT 0x%llx", file_block);
m_file.Open(file_block);
return vfsFileBase::Open(path, mode);
}
bool vfsHDD::HasEntry(const std::string& name)
{
u64 file_block;
if (!SearchEntry(name, file_block))
{
return false;
}
return true;
}
void vfsHDD::RemoveBlocksDir(u64 start_block)
{
std::string name;
u64 block = start_block;
vfsHDD_Entry entry;
while (block)
{
ReadEntry(block, entry, name);
WriteBlock(block, g_null_block);
if (entry.type == vfsHDD_Entry_Dir && name != "." && name != "..")
{
LOG_WARNING(HLE, "Removing sub folder '%s'", name.c_str());
RemoveBlocksDir(entry.data_block);
}
else if (entry.type == vfsHDD_Entry_File)
{
RemoveBlocksFile(entry.data_block);
}
block = entry.next_block;
}
}
void vfsHDD::RemoveBlocksFile(u64 start_block)
{
u64 block = start_block;
vfsHDD_Block block_data;
while (block)
{
ReadBlock(block, block_data);
WriteBlock(block, g_null_block);
block = block_data.next_block;
}
}
bool vfsHDD::RemoveEntry(const std::string& name)
{
u64 entry_block, parent_entry;
if (!SearchEntry(name, entry_block, &parent_entry))
{
return false;
}
vfsHDD_Entry entry;
ReadEntry(entry_block, entry);
if (entry.type == vfsHDD_Entry_Dir)
{
RemoveBlocksDir(entry.data_block);
}
else if (entry.type == vfsHDD_Entry_File)
{
RemoveBlocksFile(entry.data_block);
}
if (parent_entry)
{
u64 next = entry.next_block;
ReadEntry(parent_entry, entry);
entry.next_block = next;
WriteEntry(parent_entry, entry);
}
WriteBlock(entry_block, g_null_block);
return true;
}
bool vfsHDD::Create(const std::string& path)
{
return false;
}
u32 vfsHDD::Write(const void* src, u32 size)
{
return vfsFileBase::Write(src, m_file.Write(src, size));
}
u32 vfsHDD::Read(void* dst, u32 size)
{
return vfsFileBase::Read(dst, m_file.Read(dst, size));
}
u64 vfsHDD::Seek(s64 offset, vfsSeekMode mode)
{
switch (mode)
{
case vfsSeekCur:
m_file.Seek(Tell() + offset);
break;
case vfsSeekSet:
m_file.Seek(offset);
break;
case vfsSeekEnd:
m_file.Seek(m_file.GetSize() + offset);
break;
}
return vfsFileBase::Seek(offset, mode);
}
bool vfsHDD::Eof()
{
return m_file.Eof();
}
u64 vfsHDD::GetSize()
{
return m_file.GetSize();
}

View file

@ -44,62 +44,15 @@ struct vfsHDD_Entry : public vfsHDD_Block
class vfsHDDManager class vfsHDDManager
{ {
public: public:
static void CreateBlock(vfsHDD_Block& block) static void CreateBlock(vfsHDD_Block& block);
{
block.is_used = true;
block.next_block = 0;
}
static void CreateEntry(vfsHDD_Entry& entry) static void CreateEntry(vfsHDD_Entry& entry);
{
memset(&entry, 0, sizeof(vfsHDD_Entry));
u64 ctime = time(nullptr);
entry.atime = ctime;
entry.ctime = ctime;
entry.mtime = ctime;
entry.access = vfsReadWrite;
CreateBlock(entry);
}
static void CreateHDD(const std::string& path, u64 size, u64 block_size) static void CreateHDD(const std::string& path, u64 size, u64 block_size);
{
rFile f(path, rFile::write);
static const u64 cur_dir_block = 1; void Format();
vfsHDD_Hdr hdr; void AppendEntry(vfsHDD_Entry entry);
CreateBlock(hdr);
hdr.next_block = cur_dir_block;
hdr.magic = g_hdd_magic;
hdr.version = g_hdd_version;
hdr.block_count = (size + block_size) / block_size;
hdr.block_size = block_size;
f.Write(&hdr, sizeof(vfsHDD_Hdr));
{
vfsHDD_Entry entry;
CreateEntry(entry);
entry.type = vfsHDD_Entry_Dir;
entry.data_block = hdr.next_block;
entry.next_block = 0;
f.Seek(cur_dir_block * hdr.block_size);
f.Write(&entry, sizeof(vfsHDD_Entry));
f.Write(".");
}
u8 null = 0;
f.Seek(hdr.block_count * hdr.block_size - sizeof(null));
f.Write(&null, sizeof(null));
}
void Format()
{
}
void AppendEntry(vfsHDD_Entry entry)
{
}
}; };
@ -112,91 +65,23 @@ class vfsHDDFile
u32 m_position; u32 m_position;
u64 m_cur_block; u64 m_cur_block;
bool goto_block(u64 n) bool goto_block(u64 n);
{
vfsHDD_Block block_info;
if(m_info.data_block >= m_hdd_info.block_count) void RemoveBlocks(u64 start_block);
{
return false;
}
m_hdd.Seek(m_info.data_block * m_hdd_info.block_size); void WriteBlock(u64 block, const vfsHDD_Block& data);
block_info.next_block = m_info.data_block;
for(u64 i=0; i<n; ++i) void ReadBlock(u64 block, vfsHDD_Block& data);
{
if(!block_info.next_block || !block_info.is_used || block_info.next_block >= m_hdd_info.block_count)
{
return false;
}
m_hdd.Seek(block_info.next_block * m_hdd_info.block_size); void WriteEntry(u64 block, const vfsHDD_Entry& data);
m_hdd.Read(&block_info, sizeof(vfsHDD_Block));
}
return true; void ReadEntry(u64 block, vfsHDD_Entry& data);
}
void RemoveBlocks(u64 start_block) void ReadEntry(u64 block, vfsHDD_Entry& data, std::string& name);
{
vfsHDD_Block block_info;
block_info.next_block = start_block;
while(block_info.next_block && block_info.is_used) void ReadEntry(u64 block, std::string& name);
{
u64 offset = block_info.next_block * m_hdd_info.block_size;
ReadBlock(offset, block_info); void WriteEntry(u64 block, const vfsHDD_Entry& data, const std::string& name);
WriteBlock(offset, g_null_block);
}
}
void WriteBlock(u64 block, const vfsHDD_Block& data)
{
m_hdd.Seek(block * m_hdd_info.block_size);
m_hdd.Write(&data, sizeof(vfsHDD_Block));
}
void ReadBlock(u64 block, vfsHDD_Block& data)
{
m_hdd.Seek(block * m_hdd_info.block_size);
m_hdd.Read(&data, sizeof(vfsHDD_Block));
}
void WriteEntry(u64 block, const vfsHDD_Entry& data)
{
m_hdd.Seek(block * m_hdd_info.block_size);
m_hdd.Write(&data, sizeof(vfsHDD_Entry));
}
void ReadEntry(u64 block, vfsHDD_Entry& data)
{
m_hdd.Seek(block * m_hdd_info.block_size);
m_hdd.Read(&data, sizeof(vfsHDD_Entry));
}
void ReadEntry(u64 block, vfsHDD_Entry& data, std::string& name)
{
m_hdd.Seek(block * m_hdd_info.block_size);
m_hdd.Read(&data, sizeof(vfsHDD_Entry));
name.resize(GetMaxNameLen());
m_hdd.Read(&name.front(), GetMaxNameLen());
}
void ReadEntry(u64 block, std::string& name)
{
m_hdd.Seek(block * m_hdd_info.block_size + sizeof(vfsHDD_Entry));
name.resize(GetMaxNameLen());
m_hdd.Read(&name.front(), GetMaxNameLen());
}
void WriteEntry(u64 block, const vfsHDD_Entry& data, const std::string& name)
{
m_hdd.Seek(block * m_hdd_info.block_size);
m_hdd.Write(&data, sizeof(vfsHDD_Entry));
m_hdd.Write(name.c_str(), std::min<size_t>(GetMaxNameLen() - 1, name.length() + 1));
}
__forceinline u32 GetMaxNameLen() const __forceinline u32 GetMaxNameLen() const
{ {
@ -214,198 +99,22 @@ public:
{ {
} }
void Open(u64 info_block) void Open(u64 info_block);
{
m_info_block = info_block;
ReadEntry(m_info_block, m_info);
m_position = 0;
m_cur_block = m_info.data_block;
}
u64 FindFreeBlock() u64 FindFreeBlock();
{
vfsHDD_Block block_info;
for(u64 i = 0; i<m_hdd_info.block_count; ++i)
{
ReadBlock(i, block_info);
if(!block_info.is_used)
{
return i;
}
}
return 0;
}
u64 GetSize() const u64 GetSize() const
{ {
return m_info.size; return m_info.size;
} }
bool Seek(u64 pos) bool Seek(u64 pos);
{
if(!goto_block(pos / m_hdd_info.block_size))
{
return false;
}
m_position = pos % m_hdd_info.block_size; void SaveInfo();
return true;
}
void SaveInfo() u64 Read(void* dst, u64 size);
{
m_hdd.Seek(m_info_block * m_hdd_info.block_size);
m_hdd.Write(&m_info, sizeof(vfsHDD_Entry));
}
u64 Read(void* dst, u64 size) u64 Write(const void* src, u64 size);
{
if(!size)
return 0;
//vfsDeviceLocker lock(m_hdd);
const u32 block_size = m_hdd_info.block_size - sizeof(vfsHDD_Block);
u64 rsize = std::min<u64>(block_size - m_position, size);
vfsHDD_Block cur_block_info;
m_hdd.Seek(m_cur_block * m_hdd_info.block_size);
m_hdd.Read(&cur_block_info, sizeof(vfsHDD_Block));
m_hdd.Seek(m_cur_block * m_hdd_info.block_size + sizeof(vfsHDD_Block) + m_position);
m_hdd.Read(dst, rsize);
size -= rsize;
m_position += rsize;
if(!size)
{
return rsize;
}
u64 offset = rsize;
for(; size; size -= rsize, offset += rsize)
{
if(!cur_block_info.is_used || !cur_block_info.next_block || cur_block_info.next_block >= m_hdd_info.block_count)
{
return offset;
}
m_cur_block = cur_block_info.next_block;
rsize = std::min<u64>(block_size, size);
m_hdd.Seek(cur_block_info.next_block * m_hdd_info.block_size);
m_hdd.Read(&cur_block_info, sizeof(vfsHDD_Block));
if(m_hdd.Read((u8*)dst + offset, rsize) != rsize)
{
return offset;
}
}
m_position = rsize;
return offset;
}
u64 Write(const void* src, u64 size)
{
if(!size)
return 0;
//vfsDeviceLocker lock(m_hdd);
const u32 block_size = m_hdd_info.block_size - sizeof(vfsHDD_Block);
if(!m_cur_block)
{
if(!m_info.data_block)
{
u64 new_block = FindFreeBlock();
if(!new_block)
{
return 0;
}
WriteBlock(new_block, g_used_block);
m_info.data_block = new_block;
m_info.size = 0;
SaveInfo();
}
m_cur_block = m_info.data_block;
m_position = 0;
}
u64 wsize = std::min<u64>(block_size - m_position, size);
vfsHDD_Block block_info;
ReadBlock(m_cur_block, block_info);
if(wsize)
{
m_hdd.Seek(m_cur_block * m_hdd_info.block_size + sizeof(vfsHDD_Block) + m_position);
m_hdd.Write(src, wsize);
size -= wsize;
m_info.size += wsize;
m_position += wsize;
SaveInfo();
if(!size)
return wsize;
}
u64 last_block = m_cur_block;
block_info.is_used = true;
u64 offset = wsize;
for(; size; size -= wsize, offset += wsize, m_info.size += wsize)
{
u64 new_block = FindFreeBlock();
if(!new_block)
{
m_position = 0;
SaveInfo();
return offset;
}
m_cur_block = new_block;
wsize = std::min<u64>(block_size, size);
block_info.next_block = m_cur_block;
m_hdd.Seek(last_block * m_hdd_info.block_size);
if(m_hdd.Write(&block_info, sizeof(vfsHDD_Block)) != sizeof(vfsHDD_Block))
{
m_position = 0;
SaveInfo();
return offset;
}
block_info.next_block = 0;
m_hdd.Seek(m_cur_block * m_hdd_info.block_size);
if(m_hdd.Write(&block_info, sizeof(vfsHDD_Block)) != sizeof(vfsHDD_Block))
{
m_position = 0;
SaveInfo();
return offset;
}
if((m_position = m_hdd.Write((u8*)src + offset, wsize)) != wsize)
{
m_info.size += wsize;
SaveInfo();
return offset;
}
last_block = m_cur_block;
}
SaveInfo();
m_position = wsize;
return offset;
}
bool Eof() const bool Eof() const
{ {
@ -434,444 +143,60 @@ class vfsHDD : public vfsFileBase
vfsHDDFile m_file; vfsHDDFile m_file;
public: public:
vfsHDD(vfsDevice* device, const std::string& hdd_path) vfsHDD(vfsDevice* device, const std::string& hdd_path);
: m_hdd_file(device)
, m_file(m_hdd_file, m_hdd_info)
, m_hdd_path(hdd_path)
, vfsFileBase(device)
{
m_hdd_file.Open(hdd_path, vfsReadWrite);
m_hdd_file.Read(&m_hdd_info, sizeof(vfsHDD_Hdr));
m_cur_dir_block = m_hdd_info.next_block;
if(!m_hdd_info.block_size)
{
LOG_ERROR(HLE, "Bad block size!");
m_hdd_info.block_size = 2048;
}
m_hdd_file.Seek(m_cur_dir_block * m_hdd_info.block_size);
m_hdd_file.Read(&m_cur_dir, sizeof(vfsHDD_Entry));
}
__forceinline u32 GetMaxNameLen() const __forceinline u32 GetMaxNameLen() const
{ {
return m_hdd_info.block_size - sizeof(vfsHDD_Entry); return m_hdd_info.block_size - sizeof(vfsHDD_Entry);
} }
bool SearchEntry(const std::string& name, u64& entry_block, u64* parent_block = nullptr) bool SearchEntry(const std::string& name, u64& entry_block, u64* parent_block = nullptr);
{
u64 last_block = 0;
u64 block = m_cur_dir_block;
vfsHDD_Entry entry;
std::string buf;
while(block) int OpenDir(const std::string& name);
{
ReadEntry(block, entry, buf);
if (fmt::CmpNoCase(name,buf) == 0) bool Rename(const std::string& from, const std::string& to);
{
entry_block = block;
if(parent_block)
*parent_block = last_block;
return true; u64 FindFreeBlock();
}
last_block = block; void WriteBlock(u64 block, const vfsHDD_Block& data);
block = entry.is_used ? entry.next_block : 0ULL;
}
return false; void ReadBlock(u64 block, vfsHDD_Block& data);
}
int OpenDir(const std::string& name) void WriteEntry(u64 block, const vfsHDD_Entry& data);
{
LOG_WARNING(HLE, "OpenDir(%s)", name.c_str());
u64 entry_block;
if(!SearchEntry(name, entry_block))
return -1;
m_hdd_file.Seek(entry_block * m_hdd_info.block_size); void ReadEntry(u64 block, vfsHDD_Entry& data);
vfsHDD_Entry entry;
m_hdd_file.Read(&entry, sizeof(vfsHDD_Entry));
if(entry.type == vfsHDD_Entry_File)
return 1;
m_cur_dir_block = entry.data_block; void ReadEntry(u64 block, vfsHDD_Entry& data, std::string& name);
ReadEntry(m_cur_dir_block, m_cur_dir);
return 0; void ReadEntry(u64 block, std::string& name);
}
bool Rename(const std::string& from, const std::string& to) void WriteEntry(u64 block, const vfsHDD_Entry& data, const std::string& name);
{
u64 entry_block;
if(!SearchEntry(from, entry_block))
{
return false;
}
vfsHDD_Entry entry; bool Create(vfsHDD_EntryType type, const std::string& name);
ReadEntry(entry_block, entry);
WriteEntry(entry_block, entry, to);
return true; bool GetFirstEntry(u64& block, vfsHDD_Entry& entry, std::string& name);
}
u64 FindFreeBlock() bool GetNextEntry(u64& block, vfsHDD_Entry& entry, std::string& name);
{
vfsHDD_Block block_info;
for(u64 i = 0; i<m_hdd_info.block_count; ++i) virtual bool Open(const std::string& path, vfsOpenMode mode = vfsRead);
{
ReadBlock(i, block_info);
if(!block_info.is_used) bool HasEntry(const std::string& name);
{
return i;
}
}
return 0; void RemoveBlocksDir(u64 start_block);
}
void WriteBlock(u64 block, const vfsHDD_Block& data) void RemoveBlocksFile(u64 start_block);
{
m_hdd_file.Seek(block * m_hdd_info.block_size);
m_hdd_file.Write(&data, sizeof(vfsHDD_Block));
}
void ReadBlock(u64 block, vfsHDD_Block& data) bool RemoveEntry(const std::string& name);
{
m_hdd_file.Seek(block * m_hdd_info.block_size);
m_hdd_file.Read(&data, sizeof(vfsHDD_Block));
}
void WriteEntry(u64 block, const vfsHDD_Entry& data) virtual bool Create(const std::string& path);
{
m_hdd_file.Seek(block * m_hdd_info.block_size);
m_hdd_file.Write(&data, sizeof(vfsHDD_Entry));
}
void ReadEntry(u64 block, vfsHDD_Entry& data) virtual u32 Write(const void* src, u32 size);
{
m_hdd_file.Seek(block * m_hdd_info.block_size);
m_hdd_file.Read(&data, sizeof(vfsHDD_Entry));
}
void ReadEntry(u64 block, vfsHDD_Entry& data, std::string& name) virtual u32 Read(void* dst, u32 size);
{
m_hdd_file.Seek(block * m_hdd_info.block_size);
m_hdd_file.Read(&data, sizeof(vfsHDD_Entry));
name.resize(GetMaxNameLen());
m_hdd_file.Read(&name.front(), GetMaxNameLen());
}
void ReadEntry(u64 block, std::string& name) virtual u64 Seek(s64 offset, vfsSeekMode mode = vfsSeekSet);
{
m_hdd_file.Seek(block * m_hdd_info.block_size + sizeof(vfsHDD_Entry));
name.resize(GetMaxNameLen());
m_hdd_file.Read(&name.front(), GetMaxNameLen());
}
void WriteEntry(u64 block, const vfsHDD_Entry& data, const std::string& name) virtual bool Eof();
{
m_hdd_file.Seek(block * m_hdd_info.block_size);
m_hdd_file.Write(&data, sizeof(vfsHDD_Entry));
m_hdd_file.Write(name.c_str(), std::min<size_t>(GetMaxNameLen() - 1, name.length() + 1));
}
bool Create(vfsHDD_EntryType type, const std::string& name) virtual u64 GetSize();
{
if(HasEntry(name))
{
return false;
}
u64 new_block = FindFreeBlock();
if(!new_block)
{
return false;
}
LOG_NOTICE(HLE, "CREATING ENTRY AT 0x%llx", new_block);
WriteBlock(new_block, g_used_block);
{
vfsHDD_Entry new_entry;
vfsHDDManager::CreateEntry(new_entry);
new_entry.next_block = 0;
new_entry.type = type;
if(type == vfsHDD_Entry_Dir)
{
u64 block_cur = FindFreeBlock();
if(!block_cur)
{
return false;
}
WriteBlock(block_cur, g_used_block);
u64 block_last = FindFreeBlock();
if(!block_last)
{
return false;
}
WriteBlock(block_last, g_used_block);
vfsHDD_Entry entry_cur, entry_last;
vfsHDDManager::CreateEntry(entry_cur);
vfsHDDManager::CreateEntry(entry_last);
entry_cur.type = vfsHDD_Entry_Dir;
entry_cur.data_block = block_cur;
entry_cur.next_block = block_last;
entry_last.type = vfsHDD_Entry_Dir;
entry_last.data_block = m_cur_dir_block;
entry_last.next_block = 0;
new_entry.data_block = block_cur;
WriteEntry(block_cur, entry_cur, ".");
WriteEntry(block_last, entry_last, "..");
}
WriteEntry(new_block, new_entry, name);
}
{
u64 block = m_cur_dir_block;
vfsHDD_Block tmp;
while(block)
{
ReadBlock(block, tmp);
if(!tmp.next_block)
break;
block = tmp.next_block;
}
tmp.next_block = new_block;
WriteBlock(block, tmp);
}
return true;
}
bool GetFirstEntry(u64& block, vfsHDD_Entry& entry, std::string& name)
{
if(!m_cur_dir_block)
{
return false;
}
ReadEntry(m_cur_dir_block, entry, name);
block = entry.is_used ? entry.next_block : 0;
return true;
}
bool GetNextEntry(u64& block, vfsHDD_Entry& entry, std::string& name)
{
if(!block)
{
return false;
}
ReadEntry(block, entry, name);
block = entry.is_used ? entry.next_block : 0;
return true;
}
virtual bool Open(const std::string& path, vfsOpenMode mode = vfsRead)
{
const char* s = path.c_str();
u64 from = 0;
u64 pos = 0;
u64 file_pos = -1;
do
{
if(s[pos] == '\\' || s[pos] == '/' || s[pos] == '\0') // ???
{
if(file_pos != -1)
{
return false;
}
if(from != -1)
{
if(pos - from > 1)
{
int res = OpenDir(std::string(s + from, pos));
if(res == -1)
{
return false;
}
if(res == 1)
{
file_pos = from;
}
}
from = pos;
}
else
{
from = pos;
}
}
}
while(s[pos++] != '\0');
if(file_pos == -1)
{
return false;
}
u64 file_block;
if(!SearchEntry(std::string(s + file_pos), file_block))
{
return false;
}
LOG_NOTICE(HLE, "ENTRY FOUND AT 0x%llx", file_block);
m_file.Open(file_block);
return vfsFileBase::Open(path, mode);
}
bool HasEntry(const std::string& name)
{
u64 file_block;
if(!SearchEntry(name, file_block))
{
return false;
}
return true;
}
void RemoveBlocksDir(u64 start_block)
{
std::string name;
u64 block = start_block;
vfsHDD_Entry entry;
while(block)
{
ReadEntry(block, entry, name);
WriteBlock(block, g_null_block);
if(entry.type == vfsHDD_Entry_Dir && name != "." && name != "..")
{
LOG_WARNING(HLE, "Removing sub folder '%s'", name.c_str());
RemoveBlocksDir(entry.data_block);
}
else if(entry.type == vfsHDD_Entry_File)
{
RemoveBlocksFile(entry.data_block);
}
block = entry.next_block;
}
}
void RemoveBlocksFile(u64 start_block)
{
u64 block = start_block;
vfsHDD_Block block_data;
while(block)
{
ReadBlock(block, block_data);
WriteBlock(block, g_null_block);
block = block_data.next_block;
}
}
bool RemoveEntry(const std::string& name)
{
u64 entry_block, parent_entry;
if(!SearchEntry(name, entry_block, &parent_entry))
{
return false;
}
vfsHDD_Entry entry;
ReadEntry(entry_block, entry);
if(entry.type == vfsHDD_Entry_Dir)
{
RemoveBlocksDir(entry.data_block);
}
else if(entry.type == vfsHDD_Entry_File)
{
RemoveBlocksFile(entry.data_block);
}
if(parent_entry)
{
u64 next = entry.next_block;
ReadEntry(parent_entry, entry);
entry.next_block = next;
WriteEntry(parent_entry, entry);
}
WriteBlock(entry_block, g_null_block);
return true;
}
virtual bool Create(const std::string& path)
{
return false;
}
virtual u32 Write(const void* src, u32 size)
{
return vfsFileBase::Write(src, m_file.Write(src, size));
}
virtual u32 Read(void* dst, u32 size)
{
return vfsFileBase::Read(dst, m_file.Read(dst, size));
}
virtual u64 Seek(s64 offset, vfsSeekMode mode = vfsSeekSet)
{
switch(mode)
{
case vfsSeekCur:
m_file.Seek(Tell() + offset);
break;
case vfsSeekSet:
m_file.Seek(offset);
break;
case vfsSeekEnd:
m_file.Seek(m_file.GetSize() + offset);
break;
}
return vfsFileBase::Seek(offset, mode);
}
virtual bool Eof()
{
return m_file.Eof();
}
virtual u64 GetSize()
{
return m_file.GetSize();
}
}; };

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <unordered_map> #include <unordered_map>
#include <set>
#define rID_ANY -1 // was wxID_ANY #define rID_ANY -1 // was wxID_ANY

View file

@ -1,5 +1,4 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h"
#include "rpcs3/Ini.h" #include "rpcs3/Ini.h"
#include "Keyboard.h" #include "Keyboard.h"
#include "Null/NullKeyboardHandler.h" #include "Null/NullKeyboardHandler.h"

View file

@ -1,5 +1,4 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h"
#include "rpcs3/Ini.h" #include "rpcs3/Ini.h"
#include "Mouse.h" #include "Mouse.h"
#include "Null/NullMouseHandler.h" #include "Null/NullMouseHandler.h"

View file

@ -1,5 +1,4 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h"
#include "rpcs3/Ini.h" #include "rpcs3/Ini.h"
#include "Pad.h" #include "Pad.h"
#include "Null/NullPadHandler.h" #include "Null/NullPadHandler.h"

View file

@ -170,12 +170,12 @@ bool DynamicMemoryBlockBase<PT>::Free(u64 addr)
} }
} }
LOG_ERROR(MEMORY, "DynamicMemoryBlock::Free(addr=0x%llx): failed", addr); //LOG_ERROR(MEMORY, "DynamicMemoryBlock::Free(addr=0x%llx): failed", addr);
for (u32 i = 0; i < m_allocated.size(); i++) //for (u32 i = 0; i < m_allocated.size(); i++)
{ //{
LOG_NOTICE(MEMORY, "*** Memory Block: addr = 0x%llx, size = 0x%x", m_allocated[i].addr, m_allocated[i].size); // LOG_NOTICE(MEMORY, "*** Memory Block: addr = 0x%llx, size = 0x%x", m_allocated[i].addr, m_allocated[i].size);
} //}
assert(0); assert(!"DynamicMemoryBlock::Free() failed");
return false; return false;
} }
@ -189,7 +189,6 @@ template<typename PT>
bool DynamicMemoryBlockBase<PT>::IsLocked(u64 addr) bool DynamicMemoryBlockBase<PT>::IsLocked(u64 addr)
{ {
// TODO // TODO
LOG_ERROR(MEMORY, "IsLocked(0x%llx) not implemented", addr);
assert(0); assert(0);
return false; return false;
} }
@ -198,7 +197,6 @@ template<typename PT>
bool DynamicMemoryBlockBase<PT>::Lock(u64 addr, u32 size) bool DynamicMemoryBlockBase<PT>::Lock(u64 addr, u32 size)
{ {
// TODO // TODO
LOG_ERROR(MEMORY, "Lock(0x%llx, 0x%x) not implemented", addr, size);
assert(0); assert(0);
return false; return false;
} }
@ -207,7 +205,6 @@ template<typename PT>
bool DynamicMemoryBlockBase<PT>::Unlock(u64 addr, u32 size) bool DynamicMemoryBlockBase<PT>::Unlock(u64 addr, u32 size)
{ {
// TODO // TODO
LOG_ERROR(MEMORY, "Unlock(0x%llx, 0x%x) not implemented", addr, size);
assert(0); assert(0);
return false; return false;
} }

View file

@ -4,10 +4,219 @@
#include "Utilities/Log.h" #include "Utilities/Log.h"
#include "Memory.h" #include "Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Ini.h"
#ifndef _WIN32
#include <sys/mman.h>
#endif
/* OS X uses MAP_ANON instead of MAP_ANONYMOUS */
#ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
#endif
MemoryBase Memory; MemoryBase Memory;
void MemoryBase::InvalidAddress(const char* func, const u64 addr)
{
LOG_ERROR(MEMORY, "%s(): invalid address (0x%llx)", func, addr);
}
void MemoryBase::RegisterPages(u64 addr, u32 size)
{
std::lock_guard<std::recursive_mutex> lock(m_mutex);
//LOG_NOTICE(MEMORY, "RegisterPages(addr=0x%llx, size=0x%x)", addr, size);
for (u64 i = addr / 4096; i < (addr + size) / 4096; i++)
{
if (i >= sizeof(m_pages) / sizeof(m_pages[0]))
{
InvalidAddress(__FUNCTION__, i * 4096);
break;
}
if (m_pages[i])
{
LOG_ERROR(MEMORY, "Page already registered (addr=0x%llx)", i * 4096);
}
m_pages[i] = 1; // TODO: define page parameters
}
}
void MemoryBase::UnregisterPages(u64 addr, u32 size)
{
std::lock_guard<std::recursive_mutex> lock(m_mutex);
//LOG_NOTICE(MEMORY, "UnregisterPages(addr=0x%llx, size=0x%x)", addr, size);
for (u64 i = addr / 4096; i < (addr + size) / 4096; i++)
{
if (i >= sizeof(m_pages) / sizeof(m_pages[0]))
{
InvalidAddress(__FUNCTION__, i * 4096);
break;
}
if (!m_pages[i])
{
LOG_ERROR(MEMORY, "Page not registered (addr=0x%llx)", i * 4096);
}
m_pages[i] = 0; // TODO: define page parameters
}
}
u32 MemoryBase::InitRawSPU(MemoryBlock* raw_spu)
{
std::lock_guard<std::recursive_mutex> lock(m_mutex);
u32 index;
for (index = 0; index < sizeof(RawSPUMem) / sizeof(RawSPUMem[0]); index++)
{
if (!RawSPUMem[index])
{
RawSPUMem[index] = raw_spu;
break;
}
}
MemoryBlocks.push_back(raw_spu->SetRange(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index, RAW_SPU_PROB_OFFSET));
return index;
}
void MemoryBase::CloseRawSPU(MemoryBlock* raw_spu, const u32 num)
{
std::lock_guard<std::recursive_mutex> lock(m_mutex);
for (int i = 0; i < MemoryBlocks.size(); ++i)
{
if (MemoryBlocks[i] == raw_spu)
{
MemoryBlocks.erase(MemoryBlocks.begin() + i);
break;
}
}
if (num < sizeof(RawSPUMem) / sizeof(RawSPUMem[0])) RawSPUMem[num] = nullptr;
}
void MemoryBase::Init(MemoryType type)
{
std::lock_guard<std::recursive_mutex> lock(m_mutex);
if (m_inited) return;
m_inited = true;
memset(m_pages, 0, sizeof(m_pages));
memset(RawSPUMem, 0, sizeof(RawSPUMem));
#ifdef _WIN32
m_base_addr = VirtualAlloc(nullptr, 0x100000000, MEM_RESERVE, PAGE_NOACCESS);
if (!m_base_addr)
#else
m_base_addr = ::mmap(nullptr, 0x100000000, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
if (m_base_addr == (void*)-1)
#endif
{
m_base_addr = nullptr;
LOG_ERROR(MEMORY, "Initializing memory failed");
assert(0);
return;
}
else
{
LOG_NOTICE(MEMORY, "Initializing memory: m_base_addr = 0x%llx", (u64)m_base_addr);
}
switch (type)
{
case Memory_PS3:
MemoryBlocks.push_back(MainMem.SetRange(0x00010000, 0x2FFF0000));
MemoryBlocks.push_back(UserMemory = PRXMem.SetRange(0x30000000, 0x10000000));
MemoryBlocks.push_back(RSXCMDMem.SetRange(0x40000000, 0x10000000));
MemoryBlocks.push_back(MmaperMem.SetRange(0xB0000000, 0x10000000));
MemoryBlocks.push_back(RSXFBMem.SetRange(0xC0000000, 0x10000000));
MemoryBlocks.push_back(StackMem.SetRange(0xD0000000, 0x10000000));
break;
case Memory_PSV:
MemoryBlocks.push_back(PSV.RAM.SetRange(0x81000000, 0x10000000));
MemoryBlocks.push_back(UserMemory = PSV.Userspace.SetRange(0x91000000, 0x10000000));
PSV.Init(GetBaseAddr());
break;
case Memory_PSP:
MemoryBlocks.push_back(PSP.Scratchpad.SetRange(0x00010000, 0x00004000));
MemoryBlocks.push_back(PSP.VRAM.SetRange(0x04000000, 0x00200000));
MemoryBlocks.push_back(PSP.RAM.SetRange(0x08000000, 0x02000000));
MemoryBlocks.push_back(PSP.Kernel.SetRange(0x88000000, 0x00800000));
MemoryBlocks.push_back(UserMemory = PSP.Userspace.SetRange(0x08800000, 0x01800000));
PSP.Init(GetBaseAddr());
break;
}
LOG_NOTICE(MEMORY, "Memory initialized.");
}
void MemoryBase::Close()
{
std::lock_guard<std::recursive_mutex> lock(m_mutex);
if (!m_inited) return;
m_inited = false;
LOG_NOTICE(MEMORY, "Closing memory...");
for (auto block : MemoryBlocks)
{
block->Delete();
}
RSXIOMem.Delete();
MemoryBlocks.clear();
#ifdef _WIN32
if (!VirtualFree(m_base_addr, 0, MEM_RELEASE))
{
LOG_ERROR(MEMORY, "VirtualFree(0x%llx) failed", (u64)m_base_addr);
}
#else
if (::munmap(m_base_addr, 0x100000000))
{
LOG_ERROR(MEMORY, "::munmap(0x%llx) failed", (u64)m_base_addr);
}
#endif
}
bool MemoryBase::Map(const u64 dst_addr, const u64 src_addr, const u32 size)
{
std::lock_guard<std::recursive_mutex> lock(m_mutex);
if (IsGoodAddr(dst_addr) || !IsGoodAddr(src_addr))
{
return false;
}
MemoryBlocks.push_back((new MemoryMirror())->SetRange(GetMemFromAddr(src_addr), dst_addr, size));
LOG_WARNING(MEMORY, "memory mapped 0x%llx to 0x%llx size=0x%x", src_addr, dst_addr, size);
return true;
}
bool MemoryBase::Unmap(const u64 addr)
{
std::lock_guard<std::recursive_mutex> lock(m_mutex);
bool result = false;
for (uint i = 0; i<MemoryBlocks.size(); ++i)
{
if (MemoryBlocks[i]->IsMirror())
{
if (MemoryBlocks[i]->GetStartAddr() == addr)
{
delete MemoryBlocks[i];
MemoryBlocks.erase(MemoryBlocks.begin() + i);
return true;
}
}
}
return false;
}
MemBlockInfo::MemBlockInfo(u64 _addr, u32 _size) MemBlockInfo::MemBlockInfo(u64 _addr, u32 _size)
: MemInfo(_addr, PAGE_4K(_size)) : MemInfo(_addr, PAGE_4K(_size))
{ {
@ -334,12 +543,6 @@ bool MemoryBlockLE::Write128(const u64 addr, const u128 value)
return true; return true;
} }
// MemoryBase
template<> __forceinline u64 MemoryBase::ReverseData<1>(u64 val) { return val; }
template<> __forceinline u64 MemoryBase::ReverseData<2>(u64 val) { return Reverse16(val); }
template<> __forceinline u64 MemoryBase::ReverseData<4>(u64 val) { return Reverse32(val); }
template<> __forceinline u64 MemoryBase::ReverseData<8>(u64 val) { return Reverse64(val); }
VirtualMemoryBlock::VirtualMemoryBlock() : MemoryBlock(), m_reserve_size(0) VirtualMemoryBlock::VirtualMemoryBlock() : MemoryBlock(), m_reserve_size(0)
{ {
} }

View file

@ -1,17 +1,7 @@
#pragma once #pragma once
#ifndef _WIN32
#include <sys/mman.h>
#endif
#include "MemoryBlock.h" #include "MemoryBlock.h"
#include "Emu/SysCalls/Callback.h" #include "Emu/SysCalls/Callback.h"
#include <vector>
/* OS X uses MAP_ANON instead of MAP_ANONYMOUS */
#ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
#endif
using std::nullptr_t; using std::nullptr_t;
@ -107,80 +97,11 @@ public:
return m_base_addr; return m_base_addr;
} }
noinline void InvalidAddress(const char* func, const u64 addr) __noinline void InvalidAddress(const char* func, const u64 addr);
{
LOG_ERROR(MEMORY, "%s(): invalid address (0x%llx)", func, addr);
}
void RegisterPages(u64 addr, u32 size) void RegisterPages(u64 addr, u32 size);
{
std::lock_guard<std::recursive_mutex> lock(m_mutex);
//LOG_NOTICE(MEMORY, "RegisterPages(addr=0x%llx, size=0x%x)", addr, size); void UnregisterPages(u64 addr, u32 size);
for (u64 i = addr / 4096; i < (addr + size) / 4096; i++)
{
if (i >= sizeof(m_pages) / sizeof(m_pages[0]))
{
InvalidAddress(__FUNCTION__, i * 4096);
break;
}
if (m_pages[i])
{
LOG_ERROR(MEMORY, "Page already registered (addr=0x%llx)", i * 4096);
}
m_pages[i] = 1; // TODO: define page parameters
}
}
void UnregisterPages(u64 addr, u32 size)
{
std::lock_guard<std::recursive_mutex> lock(m_mutex);
//LOG_NOTICE(MEMORY, "UnregisterPages(addr=0x%llx, size=0x%x)", addr, size);
for (u64 i = addr / 4096; i < (addr + size) / 4096; i++)
{
if (i >= sizeof(m_pages) / sizeof(m_pages[0]))
{
InvalidAddress(__FUNCTION__, i * 4096);
break;
}
if (!m_pages[i])
{
LOG_ERROR(MEMORY, "Page not registered (addr=0x%llx)", i * 4096);
}
m_pages[i] = 0; // TODO: define page parameters
}
}
static __forceinline u16 Reverse16(const u16 val)
{
return _byteswap_ushort(val);
}
static __forceinline u32 Reverse32(const u32 val)
{
return _byteswap_ulong(val);
}
static __forceinline u64 Reverse64(const u64 val)
{
return _byteswap_uint64(val);
}
static __forceinline u128 Reverse128(const u128 val)
{
u128 ret;
ret.lo = _byteswap_uint64(val.hi);
ret.hi = _byteswap_uint64(val.lo);
return ret;
}
template<int size> static __forceinline u64 ReverseData(u64 val);
template<typename T> static __forceinline T Reverse(T val)
{
return (T)ReverseData<sizeof(T)>(val);
};
template<typename T> u8* GetMemFromAddr(const T addr) template<typename T> u8* GetMemFromAddr(const T addr)
{ {
@ -210,100 +131,16 @@ public:
} }
else else
{ {
assert(!addr);
return 0; return 0;
} }
} }
u32 InitRawSPU(MemoryBlock* raw_spu) u32 InitRawSPU(MemoryBlock* raw_spu);
{
std::lock_guard<std::recursive_mutex> lock(m_mutex);
u32 index; void CloseRawSPU(MemoryBlock* raw_spu, const u32 num);
for (index = 0; index < sizeof(RawSPUMem) / sizeof(RawSPUMem[0]); index++)
{
if (!RawSPUMem[index])
{
RawSPUMem[index] = raw_spu;
break;
}
}
MemoryBlocks.push_back(raw_spu->SetRange(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index, RAW_SPU_PROB_OFFSET)); void Init(MemoryType type);
return index;
}
void CloseRawSPU(MemoryBlock* raw_spu, const u32 num)
{
std::lock_guard<std::recursive_mutex> lock(m_mutex);
for (int i = 0; i < MemoryBlocks.size(); ++i)
{
if (MemoryBlocks[i] == raw_spu)
{
MemoryBlocks.erase(MemoryBlocks.begin() + i);
break;
}
}
if (num < sizeof(RawSPUMem) / sizeof(RawSPUMem[0])) RawSPUMem[num] = nullptr;
}
void Init(MemoryType type)
{
std::lock_guard<std::recursive_mutex> lock(m_mutex);
if(m_inited) return;
m_inited = true;
memset(m_pages, 0, sizeof(m_pages));
memset(RawSPUMem, 0, sizeof(RawSPUMem));
#ifdef _WIN32
m_base_addr = VirtualAlloc(nullptr, 0x100000000, MEM_RESERVE, PAGE_NOACCESS);
if (!m_base_addr)
#else
m_base_addr = ::mmap(nullptr, 0x100000000, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
if (m_base_addr == (void*)-1)
#endif
{
m_base_addr = nullptr;
LOG_ERROR(MEMORY, "Initializing memory failed");
assert(0);
return;
}
else
{
LOG_NOTICE(MEMORY, "Initializing memory: m_base_addr = 0x%llx", (u64)m_base_addr);
}
switch(type)
{
case Memory_PS3:
MemoryBlocks.push_back(MainMem.SetRange(0x00010000, 0x2FFF0000));
MemoryBlocks.push_back(UserMemory = PRXMem.SetRange(0x30000000, 0x10000000));
MemoryBlocks.push_back(RSXCMDMem.SetRange(0x40000000, 0x10000000));
MemoryBlocks.push_back(MmaperMem.SetRange(0xB0000000, 0x10000000));
MemoryBlocks.push_back(RSXFBMem.SetRange(0xC0000000, 0x10000000));
MemoryBlocks.push_back(StackMem.SetRange(0xD0000000, 0x10000000));
break;
case Memory_PSV:
MemoryBlocks.push_back(PSV.RAM.SetRange(0x81000000, 0x10000000));
MemoryBlocks.push_back(UserMemory = PSV.Userspace.SetRange(0x91000000, 0x10000000));
PSV.Init(GetBaseAddr());
break;
case Memory_PSP:
MemoryBlocks.push_back(PSP.Scratchpad.SetRange(0x00010000, 0x00004000));
MemoryBlocks.push_back(PSP.VRAM.SetRange(0x04000000, 0x00200000));
MemoryBlocks.push_back(PSP.RAM.SetRange(0x08000000, 0x02000000));
MemoryBlocks.push_back(PSP.Kernel.SetRange(0x88000000, 0x00800000));
MemoryBlocks.push_back(UserMemory = PSP.Userspace.SetRange(0x08800000, 0x01800000));
PSP.Init(GetBaseAddr());
break;
}
LOG_NOTICE(MEMORY, "Memory initialized.");
}
template<typename T> bool IsGoodAddr(const T addr) template<typename T> bool IsGoodAddr(const T addr)
{ {
@ -333,36 +170,7 @@ public:
} }
} }
void Close() void Close();
{
std::lock_guard<std::recursive_mutex> lock(m_mutex);
if(!m_inited) return;
m_inited = false;
LOG_NOTICE(MEMORY, "Closing memory...");
for (auto block : MemoryBlocks)
{
block->Delete();
}
RSXIOMem.Delete();
MemoryBlocks.clear();
#ifdef _WIN32
if (!VirtualFree(m_base_addr, 0, MEM_RELEASE))
{
LOG_ERROR(MEMORY, "VirtualFree(0x%llx) failed", (u64)m_base_addr);
}
#else
if (::munmap(m_base_addr, 0x100000000))
{
LOG_ERROR(MEMORY, "::munmap(0x%llx) failed", (u64)m_base_addr);
}
#endif
}
//MemoryBase //MemoryBase
template<typename T> void Write8(T addr, const u8 data) template<typename T> void Write8(T addr, const u8 data)
@ -391,7 +199,7 @@ public:
} }
} }
noinline void WriteMMIO32(u32 addr, const u32 data) __noinline void WriteMMIO32(u32 addr, const u32 data)
{ {
{ {
std::lock_guard<std::recursive_mutex> lock(m_mutex); std::lock_guard<std::recursive_mutex> lock(m_mutex);
@ -478,7 +286,7 @@ public:
} }
} }
noinline u32 ReadMMIO32(u32 addr) __noinline u32 ReadMMIO32(u32 addr)
{ {
u32 res; u32 res;
{ {
@ -588,11 +396,6 @@ public:
strcpy((char*)GetMemFromAddr<T>(addr), str.c_str()); strcpy((char*)GetMemFromAddr<T>(addr), str.c_str());
} }
static u64 AlignAddr(const u64 addr, const u64 align)
{
return (addr + (align-1)) & ~(align-1);
}
u32 GetUserMemTotalSize() u32 GetUserMemTotalSize()
{ {
return UserMemory->GetSize(); return UserMemory->GetSize();
@ -623,49 +426,18 @@ public:
return UserMemory->Unlock(addr, size); return UserMemory->Unlock(addr, size);
} }
bool Map(const u64 dst_addr, const u64 src_addr, const u32 size) bool Map(const u64 dst_addr, const u64 src_addr, const u32 size);
bool Unmap(const u64 addr);
template<typename T> void* operator + (const T vaddr)
{ {
std::lock_guard<std::recursive_mutex> lock(m_mutex); return GetMemFromAddr<T>(vaddr);
if(IsGoodAddr(dst_addr) || !IsGoodAddr(src_addr))
{
return false;
}
MemoryBlocks.push_back((new MemoryMirror())->SetRange(GetMemFromAddr(src_addr), dst_addr, size));
LOG_WARNING(MEMORY, "memory mapped 0x%llx to 0x%llx size=0x%x", src_addr, dst_addr, size);
return true;
}
bool Unmap(const u64 addr)
{
std::lock_guard<std::recursive_mutex> lock(m_mutex);
bool result = false;
for(uint i=0; i<MemoryBlocks.size(); ++i)
{
if(MemoryBlocks[i]->IsMirror())
{
if(MemoryBlocks[i]->GetStartAddr() == addr)
{
delete MemoryBlocks[i];
MemoryBlocks.erase(MemoryBlocks.begin() + i);
return true;
}
}
}
return false;
}
template<typename T> u8* operator + (const T vaddr)
{
u8* ret = GetMemFromAddr<T>(vaddr);
return ret;
} }
template<typename T> u8& operator[] (const T vaddr) template<typename T> u8& operator[] (const T vaddr)
{ {
return *(*this + vaddr); return *GetMemFromAddr<T>(vaddr);
} }
}; };

View file

@ -2,193 +2,9 @@
#define PAGE_4K(x) (x + 4095) & ~(4095) #define PAGE_4K(x) (x + 4095) & ~(4095)
union u128
{
struct
{
u64 hi;
u64 lo;
};
u64 _u64[2];
u32 _u32[4];
u16 _u16[8];
u8 _u8[16];
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;
if (bit < 64)
{
ret.hi = 0;
ret.lo = (u64)1 << bit;
}
else if (bit < 128)
{
ret.hi = (u64)1 << (bit - 64);
ret.lo = 0;
}
else
{
ret.hi = 0;
ret.lo = 0;
}
return ret;
}
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);
}
};
union s128
{
struct
{
s64 hi;
s64 lo;
};
u64 _i64[2];
u32 _i32[4];
u16 _i16[8];
u8 _i8[16];
operator s64() const { return _i64[0]; }
operator s32() const { return _i32[0]; }
operator s16() const { return _i16[0]; }
operator s8() const { return _i8[0]; }
operator bool() const { return _i64[0] != 0 || _i64[1] != 0; }
static s128 From64( s64 src )
{
s128 ret = {src, 0};
return ret;
}
static s128 From32( s32 src )
{
s128 ret;
ret._i32[0] = src;
ret._i32[1] = 0;
ret.hi = 0;
return ret;
}
bool operator == ( const s128& right ) const
{
return (lo == right.lo) && (hi == right.hi);
}
bool operator != ( const s128& right ) const
{
return (lo != right.lo) || (hi != right.hi);
}
};
#include <memory> #include <memory>
#include <emmintrin.h> #include <emmintrin.h>
//TODO: SSE style
/*
struct u128
{
__m128 m_val;
u128 GetValue128()
{
u128 ret;
_mm_store_ps( (float*)&ret, m_val );
return ret;
}
u64 GetValue64()
{
u64 ret;
_mm_store_ps( (float*)&ret, m_val );
return ret;
}
u32 GetValue32()
{
u32 ret;
_mm_store_ps( (float*)&ret, m_val );
return ret;
}
u16 GetValue16()
{
u16 ret;
_mm_store_ps( (float*)&ret, m_val );
return ret;
}
u8 GetValue8()
{
u8 ret;
_mm_store_ps( (float*)&ret, m_val );
return ret;
}
};
*/
struct MemInfo struct MemInfo
{ {
u64 addr; u64 addr;

View file

@ -1,8 +1,5 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h"
#include "Emu/Memory/Memory.h"
#include "GLBuffers.h" #include "GLBuffers.h"
#include "GLGSRender.h"
GLBufferObject::GLBufferObject() GLBufferObject::GLBufferObject()
{ {

View file

@ -1,9 +1,9 @@
#include "stdafx.h" #include "stdafx.h"
#include "rpcs3/Ini.h"
#include "Utilities/Log.h" #include "Utilities/Log.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "GLGSRender.h" #include "GLGSRender.h"
#include "Emu/Cell/PPCInstrTable.h"
#define CMD_DEBUG 0 #define CMD_DEBUG 0
#define DUMP_VERTEX_DATA 0 #define DUMP_VERTEX_DATA 0
@ -35,6 +35,731 @@ void printGlError(GLenum err, const std::string& situation)
#define checkForGlError(x) /*x*/ #define checkForGlError(x) /*x*/
#endif #endif
void GLTexture::Create()
{
if (m_id)
{
Delete();
}
if (!m_id)
{
glGenTextures(1, &m_id);
checkForGlError("GLTexture::Init() -> glGenTextures");
Bind();
}
}
int GLTexture::GetGlWrap(int wrap)
{
switch (wrap)
{
case CELL_GCM_TEXTURE_WRAP: return GL_REPEAT;
case CELL_GCM_TEXTURE_MIRROR: return GL_MIRRORED_REPEAT;
case CELL_GCM_TEXTURE_CLAMP_TO_EDGE: return GL_CLAMP_TO_EDGE;
case CELL_GCM_TEXTURE_BORDER: return GL_CLAMP_TO_BORDER;
case CELL_GCM_TEXTURE_CLAMP: return GL_CLAMP_TO_EDGE;
case CELL_GCM_TEXTURE_MIRROR_ONCE_CLAMP_TO_EDGE: return GL_MIRROR_CLAMP_TO_EDGE_EXT;
case CELL_GCM_TEXTURE_MIRROR_ONCE_BORDER: return GL_MIRROR_CLAMP_TO_BORDER_EXT;
case CELL_GCM_TEXTURE_MIRROR_ONCE_CLAMP: return GL_MIRROR_CLAMP_EXT;
}
LOG_ERROR(RSX, "Texture wrap error: bad wrap (%d).", wrap);
return GL_REPEAT;
}
float GLTexture::GetMaxAniso(int aniso)
{
switch (aniso)
{
case CELL_GCM_TEXTURE_MAX_ANISO_1: return 1.0f;
case CELL_GCM_TEXTURE_MAX_ANISO_2: return 2.0f;
case CELL_GCM_TEXTURE_MAX_ANISO_4: return 4.0f;
case CELL_GCM_TEXTURE_MAX_ANISO_6: return 6.0f;
case CELL_GCM_TEXTURE_MAX_ANISO_8: return 8.0f;
case CELL_GCM_TEXTURE_MAX_ANISO_10: return 10.0f;
case CELL_GCM_TEXTURE_MAX_ANISO_12: return 12.0f;
case CELL_GCM_TEXTURE_MAX_ANISO_16: return 16.0f;
}
LOG_ERROR(RSX, "Texture anisotropy error: bad max aniso (%d).", aniso);
return 1.0f;
}
void GLTexture::Init(RSXTexture& tex)
{
if (tex.GetLocation() > 1)
return;
Bind();
const u64 texaddr = GetAddress(tex.GetOffset(), tex.GetLocation());
if (!Memory.IsGoodAddr(texaddr))
{
LOG_ERROR(RSX, "Bad texture address=0x%x", texaddr);
return;
}
//ConLog.Warning("texture addr = 0x%x, width = %d, height = %d, max_aniso=%d, mipmap=%d, remap=0x%x, zfunc=0x%x, wraps=0x%x, wrapt=0x%x, wrapr=0x%x, minlod=0x%x, maxlod=0x%x",
// m_offset, m_width, m_height, m_maxaniso, m_mipmap, m_remap, m_zfunc, m_wraps, m_wrapt, m_wrapr, m_minlod, m_maxlod);
//TODO: safe init
checkForGlError("GLTexture::Init() -> glBindTexture");
int format = tex.GetFormat() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN);
bool is_swizzled = !(tex.GetFormat() & CELL_GCM_TEXTURE_LN);
const u8 *pixels = const_cast<const u8 *>(Memory.GetMemFromAddr(texaddr));
u8 *unswizzledPixels;
static const GLint glRemapStandard[4] = { GL_ALPHA, GL_RED, GL_GREEN, GL_BLUE };
// NOTE: This must be in ARGB order in all forms below.
const GLint *glRemap = glRemapStandard;
switch (format)
{
case CELL_GCM_TEXTURE_B8: // One 8-bit fixed-point number
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_BLUE, GL_UNSIGNED_BYTE, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_B8)");
static const GLint swizzleMaskB8[] = { GL_BLUE, GL_BLUE, GL_BLUE, GL_BLUE };
glRemap = swizzleMaskB8;
}
break;
case CELL_GCM_TEXTURE_A1R5G5B5:
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
checkForGlError("GLTexture::Init() -> glPixelStorei");
// TODO: texture swizzling
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_A1R5G5B5)");
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_A1R5G5B5)");
break;
case CELL_GCM_TEXTURE_A4R4G4B4:
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_A4R4G4B4)");
// We read it in as R4G4B4A4, so we need to remap each component.
static const GLint swizzleMaskA4R4G4B4[] = { GL_BLUE, GL_ALPHA, GL_RED, GL_GREEN };
glRemap = swizzleMaskA4R4G4B4;
}
break;
case CELL_GCM_TEXTURE_R5G6B5:
{
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_R5G6B5)");
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex.GetWidth(), tex.GetHeight(), 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_R5G6B5)");
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_R5G6B5)");
}
break;
case CELL_GCM_TEXTURE_A8R8G8B8:
if (is_swizzled)
{
u32 *src, *dst;
u32 log2width, log2height;
unswizzledPixels = (u8*)malloc(tex.GetWidth() * tex.GetHeight() * 4);
src = (u32*)pixels;
dst = (u32*)unswizzledPixels;
log2width = log(tex.GetWidth()) / log(2);
log2height = log(tex.GetHeight()) / log(2);
for (int i = 0; i<tex.GetHeight(); i++)
{
for (int j = 0; j<tex.GetWidth(); j++)
{
dst[(i*tex.GetHeight()) + j] = src[LinearToSwizzleAddress(j, i, 0, log2width, log2height, 0)];
}
}
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, is_swizzled ? unswizzledPixels : pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_A8R8G8B8)");
break;
case CELL_GCM_TEXTURE_COMPRESSED_DXT1: // Compressed 4x4 pixels into 8 bytes
{
u32 size = ((tex.GetWidth() + 3) / 4) * ((tex.GetHeight() + 3) / 4) * 8;
glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, tex.GetWidth(), tex.GetHeight(), 0, size, pixels);
checkForGlError("GLTexture::Init() -> glCompressedTexImage2D(CELL_GCM_TEXTURE_COMPRESSED_DXT1)");
}
break;
case CELL_GCM_TEXTURE_COMPRESSED_DXT23: // Compressed 4x4 pixels into 16 bytes
{
u32 size = ((tex.GetWidth() + 3) / 4) * ((tex.GetHeight() + 3) / 4) * 16;
glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, tex.GetWidth(), tex.GetHeight(), 0, size, pixels);
checkForGlError("GLTexture::Init() -> glCompressedTexImage2D(CELL_GCM_TEXTURE_COMPRESSED_DXT23)");
}
break;
case CELL_GCM_TEXTURE_COMPRESSED_DXT45: // Compressed 4x4 pixels into 16 bytes
{
u32 size = ((tex.GetWidth() + 3) / 4) * ((tex.GetHeight() + 3) / 4) * 16;
glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, tex.GetWidth(), tex.GetHeight(), 0, size, pixels);
checkForGlError("GLTexture::Init() -> glCompressedTexImage2D(CELL_GCM_TEXTURE_COMPRESSED_DXT45)");
}
break;
case CELL_GCM_TEXTURE_G8B8:
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_RG, GL_UNSIGNED_BYTE, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_G8B8)");
static const GLint swizzleMaskG8B8[] = { GL_RED, GL_GREEN, GL_RED, GL_GREEN };
glRemap = swizzleMaskG8B8;
}
break;
case CELL_GCM_TEXTURE_R6G5B5:
{
// TODO: Probably need to actually unswizzle if is_swizzled.
const u32 numPixels = tex.GetWidth() * tex.GetHeight();
unswizzledPixels = (u8 *)malloc(numPixels * 4);
// TODO: Speed.
for (u32 i = 0; i < numPixels; ++i) {
u16 c = reinterpret_cast<const be_t<u16> *>(pixels)[i];
unswizzledPixels[i * 4 + 0] = Convert6To8((c >> 10) & 0x3F);
unswizzledPixels[i * 4 + 1] = Convert5To8((c >> 5) & 0x1F);
unswizzledPixels[i * 4 + 2] = Convert5To8((c >> 0) & 0x1F);
unswizzledPixels[i * 4 + 3] = 255;
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, unswizzledPixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_R6G5B5)");
free(unswizzledPixels);
}
break;
case CELL_GCM_TEXTURE_DEPTH24_D8: // 24-bit unsigned fixed-point number and 8 bits of garbage
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, tex.GetWidth(), tex.GetHeight(), 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_DEPTH24_D8)");
break;
case CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT: // 24-bit unsigned float and 8 bits of garbage
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, tex.GetWidth(), tex.GetHeight(), 0, GL_DEPTH_COMPONENT, GL_FLOAT, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT)");
break;
case CELL_GCM_TEXTURE_DEPTH16: // 16-bit unsigned fixed-point number
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, tex.GetWidth(), tex.GetHeight(), 0, GL_DEPTH_COMPONENT, GL_SHORT, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_DEPTH16)");
break;
case CELL_GCM_TEXTURE_DEPTH16_FLOAT: // 16-bit unsigned float
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, tex.GetWidth(), tex.GetHeight(), 0, GL_DEPTH_COMPONENT, GL_FLOAT, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_DEPTH16_FLOAT)");
break;
case CELL_GCM_TEXTURE_X16: // A 16-bit fixed-point number
{
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_X16)");
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_RED, GL_UNSIGNED_SHORT, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_X16)");
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_X16)");
static const GLint swizzleMaskX16[] = { GL_RED, GL_ONE, GL_RED, GL_ONE };
glRemap = swizzleMaskX16;
}
break;
case CELL_GCM_TEXTURE_Y16_X16: // Two 16-bit fixed-point numbers
{
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_Y16_X16)");
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_RG, GL_UNSIGNED_SHORT, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_Y16_X16)");
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_Y16_X16)");
static const GLint swizzleMaskX32_Y16_X16[] = { GL_GREEN, GL_RED, GL_GREEN, GL_RED };
glRemap = swizzleMaskX32_Y16_X16;
}
break;
case CELL_GCM_TEXTURE_R5G5B5A1:
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_R5G5B5A1)");
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_R5G5B5A1)");
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_R5G5B5A1)");
break;
case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT: // Four fp16 values
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT)");
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_RGBA, GL_HALF_FLOAT, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT)");
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT)");
break;
case CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT: // Four fp32 values
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_BGRA, GL_FLOAT, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT)");
break;
case CELL_GCM_TEXTURE_X32_FLOAT: // One 32-bit floating-point number
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_RED, GL_FLOAT, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_X32_FLOAT)");
static const GLint swizzleMaskX32_FLOAT[] = { GL_RED, GL_ONE, GL_ONE, GL_ONE };
glRemap = swizzleMaskX32_FLOAT;
}
break;
case CELL_GCM_TEXTURE_D1R5G5B5:
{
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_D1R5G5B5)");
// TODO: Texture swizzling
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_D1R5G5B5)");
static const GLint swizzleMaskX32_D1R5G5B5[] = { GL_ONE, GL_RED, GL_GREEN, GL_BLUE };
glRemap = swizzleMaskX32_D1R5G5B5;
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_D1R5G5B5)");
}
break;
case CELL_GCM_TEXTURE_D8R8G8B8: // 8 bits of garbage and three unsigned 8-bit fixed-point numbers
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_D8R8G8B8)");
static const GLint swizzleMaskX32_D8R8G8B8[] = { GL_ONE, GL_RED, GL_GREEN, GL_BLUE };
glRemap = swizzleMaskX32_D8R8G8B8;
}
break;
case CELL_GCM_TEXTURE_Y16_X16_FLOAT: // Two fp16 values
{
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_Y16_X16_FLOAT)");
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_RG, GL_HALF_FLOAT, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_Y16_X16_FLOAT)");
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_Y16_X16_FLOAT)");
static const GLint swizzleMaskX32_Y16_X16_FLOAT[] = { GL_RED, GL_GREEN, GL_RED, GL_GREEN };
glRemap = swizzleMaskX32_Y16_X16_FLOAT;
}
break;
case CELL_GCM_TEXTURE_COMPRESSED_B8R8_G8R8 & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN) :
{
const u32 numPixels = tex.GetWidth() * tex.GetHeight();
unswizzledPixels = (u8 *)malloc(numPixels * 4);
// TODO: Speed.
for (u32 i = 0; i < numPixels; i += 2) {
unswizzledPixels[i * 4 + 0 + 0] = pixels[i * 2 + 3];
unswizzledPixels[i * 4 + 0 + 1] = pixels[i * 2 + 2];
unswizzledPixels[i * 4 + 0 + 2] = pixels[i * 2 + 0];
unswizzledPixels[i * 4 + 0 + 3] = 255;
// The second pixel is the same, except for red.
unswizzledPixels[i * 4 + 4 + 0] = pixels[i * 2 + 1];
unswizzledPixels[i * 4 + 4 + 1] = pixels[i * 2 + 2];
unswizzledPixels[i * 4 + 4 + 2] = pixels[i * 2 + 0];
unswizzledPixels[i * 4 + 4 + 3] = 255;
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, unswizzledPixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_COMPRESSED_B8R8_G8R8 & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN)");
free(unswizzledPixels);
}
break;
case CELL_GCM_TEXTURE_COMPRESSED_R8B8_R8G8 & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN) :
{
const u32 numPixels = tex.GetWidth() * tex.GetHeight();
unswizzledPixels = (u8 *)malloc(numPixels * 4);
// TODO: Speed.
for (u32 i = 0; i < numPixels; i += 2) {
unswizzledPixels[i * 4 + 0 + 0] = pixels[i * 2 + 2];
unswizzledPixels[i * 4 + 0 + 1] = pixels[i * 2 + 3];
unswizzledPixels[i * 4 + 0 + 2] = pixels[i * 2 + 1];
unswizzledPixels[i * 4 + 0 + 3] = 255;
// The second pixel is the same, except for red.
unswizzledPixels[i * 4 + 4 + 0] = pixels[i * 2 + 0];
unswizzledPixels[i * 4 + 4 + 1] = pixels[i * 2 + 3];
unswizzledPixels[i * 4 + 4 + 2] = pixels[i * 2 + 1];
unswizzledPixels[i * 4 + 4 + 3] = 255;
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, unswizzledPixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_COMPRESSED_R8B8_R8G8 & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN)");
free(unswizzledPixels);
}
break;
default: LOG_ERROR(RSX, "Init tex error: Bad tex format (0x%x | %s | 0x%x)", format,
(is_swizzled ? "swizzled" : "linear"), tex.GetFormat() & 0x40); break;
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, tex.GetMipmap() - 1);
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, tex.GetMipmap() > 1);
if (format != CELL_GCM_TEXTURE_B8 && format != CELL_GCM_TEXTURE_X16 && format != CELL_GCM_TEXTURE_X32_FLOAT)
{
u8 remap_a = tex.GetRemap() & 0x3;
u8 remap_r = (tex.GetRemap() >> 2) & 0x3;
u8 remap_g = (tex.GetRemap() >> 4) & 0x3;
u8 remap_b = (tex.GetRemap() >> 6) & 0x3;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, glRemap[remap_a]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, glRemap[remap_r]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, glRemap[remap_g]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, glRemap[remap_b]);
}
else
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, glRemap[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, glRemap[1]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, glRemap[2]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, glRemap[3]);
}
checkForGlError("GLTexture::Init() -> remap");
static const int gl_tex_zfunc[] =
{
GL_NEVER,
GL_LESS,
GL_EQUAL,
GL_LEQUAL,
GL_GREATER,
GL_NOTEQUAL,
GL_GEQUAL,
GL_ALWAYS,
};
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GetGlWrap(tex.GetWrapS()));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GetGlWrap(tex.GetWrapT()));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GetGlWrap(tex.GetWrapR()));
checkForGlError("GLTexture::Init() -> wrap");
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, gl_tex_zfunc[tex.GetZfunc()]);
checkForGlError("GLTexture::Init() -> compare");
glTexEnvi(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, tex.GetBias());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, (tex.GetMinLOD() >> 8));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, (tex.GetMaxLOD() >> 8));
checkForGlError("GLTexture::Init() -> lod");
static const int gl_tex_min_filter[] =
{
GL_NEAREST, // unused
GL_NEAREST,
GL_LINEAR,
GL_NEAREST_MIPMAP_NEAREST,
GL_LINEAR_MIPMAP_NEAREST,
GL_NEAREST_MIPMAP_LINEAR,
GL_LINEAR_MIPMAP_LINEAR,
GL_NEAREST, // CELL_GCM_TEXTURE_CONVOLUTION_MIN
};
static const int gl_tex_mag_filter[] = {
GL_NEAREST, // unused
GL_NEAREST,
GL_LINEAR,
GL_NEAREST, // unused
GL_LINEAR // CELL_GCM_TEXTURE_CONVOLUTION_MAG
};
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_tex_min_filter[tex.GetMinFilter()]);
checkForGlError("GLTexture::Init() -> min filters");
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_tex_mag_filter[tex.GetMagFilter()]);
checkForGlError("GLTexture::Init() -> mag filters");
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, GetMaxAniso(tex.GetMaxAniso()));
checkForGlError("GLTexture::Init() -> max anisotropy");
//Unbind();
if (is_swizzled && format == CELL_GCM_TEXTURE_A8R8G8B8)
{
free(unswizzledPixels);
}
}
void GLTexture::Save(RSXTexture& tex, const std::string& name)
{
if (!m_id || !tex.GetOffset() || !tex.GetWidth() || !tex.GetHeight()) return;
const u32 texPixelCount = tex.GetWidth() * tex.GetHeight();
u32* alldata = new u32[texPixelCount];
Bind();
switch (tex.GetFormat() & ~(0x20 | 0x40))
{
case CELL_GCM_TEXTURE_B8:
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, alldata);
break;
case CELL_GCM_TEXTURE_A8R8G8B8:
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, alldata);
break;
default:
delete[] alldata;
return;
}
{
rFile f(name + ".raw", rFile::write);
f.Write(alldata, texPixelCount * 4);
}
u8* data = new u8[texPixelCount * 3];
u8* alpha = new u8[texPixelCount];
u8* src = (u8*)alldata;
u8* dst_d = data;
u8* dst_a = alpha;
for (u32 i = 0; i < texPixelCount; i++)
{
*dst_d++ = *src++;
*dst_d++ = *src++;
*dst_d++ = *src++;
*dst_a++ = *src++;
}
rImage out;
out.Create(tex.GetWidth(), tex.GetHeight(), data, alpha);
out.SaveFile(name, rBITMAP_TYPE_PNG);
delete[] alldata;
//free(data);
//free(alpha);
}
void GLTexture::Save(RSXTexture& tex)
{
static const std::string& dir_path = "textures";
static const std::string& file_fmt = dir_path + "/" + "tex[%d].png";
if (!rExists(dir_path)) rMkdir(dir_path);
u32 count = 0;
while (rExists(fmt::Format(file_fmt, count))) count++;
Save(tex, fmt::Format(file_fmt, count));
}
void GLTexture::Bind()
{
glBindTexture(GL_TEXTURE_2D, m_id);
}
void GLTexture::Unbind()
{
glBindTexture(GL_TEXTURE_2D, 0);
}
void GLTexture::Delete()
{
if (m_id)
{
glDeleteTextures(1, &m_id);
m_id = 0;
}
}
void PostDrawObj::Draw()
{
static bool s_is_initialized = false;
if (!s_is_initialized)
{
s_is_initialized = true;
Initialize();
}
else
{
m_program.Use();
}
}
void PostDrawObj::Initialize()
{
InitializeShaders();
m_fp.Compile();
m_vp.Compile();
m_program.Create(m_vp.id, m_fp.GetId());
m_program.Use();
InitializeLocations();
}
void DrawCursorObj::Draw()
{
checkForGlError("PostDrawObj : Unknown error.");
PostDrawObj::Draw();
checkForGlError("PostDrawObj::Draw");
if (!m_fbo.IsCreated())
{
m_fbo.Create();
checkForGlError("DrawCursorObj : m_fbo.Create");
m_fbo.Bind();
checkForGlError("DrawCursorObj : m_fbo.Bind");
m_rbo.Create();
checkForGlError("DrawCursorObj : m_rbo.Create");
m_rbo.Bind();
checkForGlError("DrawCursorObj : m_rbo.Bind");
m_rbo.Storage(GL_RGBA, m_width, m_height);
checkForGlError("DrawCursorObj : m_rbo.Storage");
m_fbo.Renderbuffer(GL_COLOR_ATTACHMENT0, m_rbo.GetId());
checkForGlError("DrawCursorObj : m_fbo.Renderbuffer");
}
m_fbo.Bind();
checkForGlError("DrawCursorObj : m_fbo.Bind");
glDrawBuffer(GL_COLOR_ATTACHMENT0);
checkForGlError("DrawCursorObj : glDrawBuffer");
m_program.Use();
checkForGlError("DrawCursorObj : m_program.Use");
if (m_update_texture)
{
//m_update_texture = false;
glUniform2f(m_program.GetLocation("in_tc"), m_width, m_height);
checkForGlError("DrawCursorObj : glUniform2f");
if (!m_tex_id)
{
glGenTextures(1, &m_tex_id);
checkForGlError("DrawCursorObj : glGenTextures");
}
glActiveTexture(GL_TEXTURE0);
checkForGlError("DrawCursorObj : glActiveTexture");
glBindTexture(GL_TEXTURE_2D, m_tex_id);
checkForGlError("DrawCursorObj : glBindTexture");
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_pixels);
checkForGlError("DrawCursorObj : glTexImage2D");
m_program.SetTex(0);
}
if (m_update_pos)
{
//m_update_pos = false;
glUniform4f(m_program.GetLocation("in_pos"), m_pos_x, m_pos_y, m_pos_z, 1.0f);
checkForGlError("DrawCursorObj : glUniform4f");
}
glDrawArrays(GL_QUADS, 0, 4);
checkForGlError("DrawCursorObj : glDrawArrays");
m_fbo.Bind(GL_READ_FRAMEBUFFER);
checkForGlError("DrawCursorObj : m_fbo.Bind(GL_READ_FRAMEBUFFER)");
GLfbo::Bind(GL_DRAW_FRAMEBUFFER, 0);
checkForGlError("DrawCursorObj : GLfbo::Bind(GL_DRAW_FRAMEBUFFER, 0)");
GLfbo::Blit(
0, 0, m_width, m_height,
0, 0, m_width, m_height,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
checkForGlError("DrawCursorObj : GLfbo::Blit");
m_fbo.Bind();
checkForGlError("DrawCursorObj : m_fbo.Bind");
}
void DrawCursorObj::InitializeShaders()
{
m_vp.shader =
"#version 330\n"
"\n"
"uniform vec4 in_pos;\n"
"uniform vec2 in_tc;\n"
"out vec2 tc;\n"
"\n"
"void main()\n"
"{\n"
" tc = in_tc;\n"
" gl_Position = in_pos;\n"
"}\n";
m_fp.SetShaderText(
"#version 330\n"
"\n"
"in vec2 tc;\n"
"uniform sampler2D tex0;\n"
"layout (location = 0) out vec4 res;\n"
"\n"
"void main()\n"
"{\n"
" res = texture(tex0, tc);\n"
"}\n");
}
void DrawCursorObj::SetTexture(void* pixels, int width, int height)
{
m_pixels = pixels;
m_width = width;
m_height = height;
m_update_texture = true;
}
void DrawCursorObj::SetPosition(float x, float y, float z)
{
m_pos_x = x;
m_pos_y = y;
m_pos_z = z;
m_update_pos = true;
}
void DrawCursorObj::InitializeLocations()
{
//ConLog.Warning("tex0 location = 0x%x", m_program.GetLocation("tex0"));
}
GLGSRender::GLGSRender() GLGSRender::GLGSRender()
: GSRender() : GSRender()
, m_frame(nullptr) , m_frame(nullptr)

View file

@ -1,6 +1,5 @@
#pragma once #pragma once
#include "Emu/RSX/GSRender.h" #include "Emu/RSX/GSRender.h"
#include "Emu/RSX/RSXThread.h"
#include "Utilities/rPlatform.h" #include "Utilities/rPlatform.h"
#include "GLBuffers.h" #include "GLBuffers.h"
#include "GLProgramBuffer.h" #include "GLProgramBuffer.h"
@ -29,56 +28,11 @@ public:
{ {
} }
void Create() void Create();
{
if(m_id)
{
Delete();
}
if(!m_id) int GetGlWrap(int wrap);
{
glGenTextures(1, &m_id);
checkForGlError("GLTexture::Init() -> glGenTextures");
Bind();
}
}
int GetGlWrap(int wrap) float GetMaxAniso(int aniso);
{
switch(wrap)
{
case CELL_GCM_TEXTURE_WRAP: return GL_REPEAT;
case CELL_GCM_TEXTURE_MIRROR: return GL_MIRRORED_REPEAT;
case CELL_GCM_TEXTURE_CLAMP_TO_EDGE: return GL_CLAMP_TO_EDGE;
case CELL_GCM_TEXTURE_BORDER: return GL_CLAMP_TO_BORDER;
case CELL_GCM_TEXTURE_CLAMP: return GL_CLAMP_TO_EDGE;
case CELL_GCM_TEXTURE_MIRROR_ONCE_CLAMP_TO_EDGE: return GL_MIRROR_CLAMP_TO_EDGE_EXT;
case CELL_GCM_TEXTURE_MIRROR_ONCE_BORDER: return GL_MIRROR_CLAMP_TO_BORDER_EXT;
case CELL_GCM_TEXTURE_MIRROR_ONCE_CLAMP: return GL_MIRROR_CLAMP_EXT;
}
LOG_ERROR(RSX, "Texture wrap error: bad wrap (%d).", wrap);
return GL_REPEAT;
}
float GetMaxAniso(int aniso)
{
switch (aniso)
{
case CELL_GCM_TEXTURE_MAX_ANISO_1: return 1.0f;
case CELL_GCM_TEXTURE_MAX_ANISO_2: return 2.0f;
case CELL_GCM_TEXTURE_MAX_ANISO_4: return 4.0f;
case CELL_GCM_TEXTURE_MAX_ANISO_6: return 6.0f;
case CELL_GCM_TEXTURE_MAX_ANISO_8: return 8.0f;
case CELL_GCM_TEXTURE_MAX_ANISO_10: return 10.0f;
case CELL_GCM_TEXTURE_MAX_ANISO_12: return 12.0f;
case CELL_GCM_TEXTURE_MAX_ANISO_16: return 16.0f;
}
LOG_ERROR(RSX, "Texture anisotropy error: bad max aniso (%d).", aniso);
return 1.0f;
}
inline static u8 Convert4To8(u8 v) inline static u8 Convert4To8(u8 v)
{ {
@ -98,526 +52,17 @@ public:
return (v << 2) | (v >> 4); return (v << 2) | (v >> 4);
} }
void Init(RSXTexture& tex) void Init(RSXTexture& tex);
{
if (tex.GetLocation() > 1)
return;
Bind(); void Save(RSXTexture& tex, const std::string& name);
const u64 texaddr = GetAddress(tex.GetOffset(), tex.GetLocation()); void Save(RSXTexture& tex);
if (!Memory.IsGoodAddr(texaddr))
{
LOG_ERROR(RSX, "Bad texture address=0x%x", texaddr);
return;
}
//ConLog.Warning("texture addr = 0x%x, width = %d, height = %d, max_aniso=%d, mipmap=%d, remap=0x%x, zfunc=0x%x, wraps=0x%x, wrapt=0x%x, wrapr=0x%x, minlod=0x%x, maxlod=0x%x",
// m_offset, m_width, m_height, m_maxaniso, m_mipmap, m_remap, m_zfunc, m_wraps, m_wrapt, m_wrapr, m_minlod, m_maxlod);
//TODO: safe init
checkForGlError("GLTexture::Init() -> glBindTexture");
int format = tex.GetFormat() & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN); void Bind();
bool is_swizzled = !(tex.GetFormat() & CELL_GCM_TEXTURE_LN);
const u8 *pixels = const_cast<const u8 *>(Memory.GetMemFromAddr(texaddr)); void Unbind();
u8 *unswizzledPixels;
static const GLint glRemapStandard[4] = {GL_ALPHA, GL_RED, GL_GREEN, GL_BLUE};
// NOTE: This must be in ARGB order in all forms below.
const GLint *glRemap = glRemapStandard;
switch(format) void Delete();
{
case CELL_GCM_TEXTURE_B8: // One 8-bit fixed-point number
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_BLUE, GL_UNSIGNED_BYTE, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_B8)");
static const GLint swizzleMaskB8[] = { GL_BLUE, GL_BLUE, GL_BLUE, GL_BLUE };
glRemap = swizzleMaskB8;
}
break;
case CELL_GCM_TEXTURE_A1R5G5B5:
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
checkForGlError("GLTexture::Init() -> glPixelStorei");
// TODO: texture swizzling
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_A1R5G5B5)");
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_A1R5G5B5)");
break;
case CELL_GCM_TEXTURE_A4R4G4B4:
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_A4R4G4B4)");
// We read it in as R4G4B4A4, so we need to remap each component.
static const GLint swizzleMaskA4R4G4B4[] = { GL_BLUE, GL_ALPHA, GL_RED, GL_GREEN };
glRemap = swizzleMaskA4R4G4B4;
}
break;
case CELL_GCM_TEXTURE_R5G6B5:
{
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_R5G6B5)");
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex.GetWidth(), tex.GetHeight(), 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_R5G6B5)");
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_R5G6B5)");
}
break;
case CELL_GCM_TEXTURE_A8R8G8B8:
if(is_swizzled)
{
u32 *src, *dst;
u32 log2width, log2height;
unswizzledPixels = (u8*)malloc(tex.GetWidth() * tex.GetHeight() * 4);
src = (u32*)pixels;
dst = (u32*)unswizzledPixels;
log2width = log(tex.GetWidth())/log(2);
log2height = log(tex.GetHeight())/log(2);
for(int i=0; i<tex.GetHeight(); i++)
{
for(int j=0; j<tex.GetWidth(); j++)
{
dst[(i*tex.GetHeight()) + j] = src[LinearToSwizzleAddress(j, i, 0, log2width, log2height, 0)];
}
}
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, is_swizzled ? unswizzledPixels : pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_A8R8G8B8)");
break;
case CELL_GCM_TEXTURE_COMPRESSED_DXT1: // Compressed 4x4 pixels into 8 bytes
{
u32 size = ((tex.GetWidth() + 3) / 4) * ((tex.GetHeight() + 3) / 4) * 8;
glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, tex.GetWidth(), tex.GetHeight(), 0, size, pixels);
checkForGlError("GLTexture::Init() -> glCompressedTexImage2D(CELL_GCM_TEXTURE_COMPRESSED_DXT1)");
}
break;
case CELL_GCM_TEXTURE_COMPRESSED_DXT23: // Compressed 4x4 pixels into 16 bytes
{
u32 size = ((tex.GetWidth() + 3) / 4) * ((tex.GetHeight() + 3) / 4) * 16;
glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, tex.GetWidth(), tex.GetHeight(), 0, size, pixels);
checkForGlError("GLTexture::Init() -> glCompressedTexImage2D(CELL_GCM_TEXTURE_COMPRESSED_DXT23)");
}
break;
case CELL_GCM_TEXTURE_COMPRESSED_DXT45: // Compressed 4x4 pixels into 16 bytes
{
u32 size = ((tex.GetWidth() + 3) / 4) * ((tex.GetHeight() + 3) / 4) * 16;
glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, tex.GetWidth(), tex.GetHeight(), 0, size, pixels);
checkForGlError("GLTexture::Init() -> glCompressedTexImage2D(CELL_GCM_TEXTURE_COMPRESSED_DXT45)");
}
break;
case CELL_GCM_TEXTURE_G8B8:
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_RG, GL_UNSIGNED_BYTE, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_G8B8)");
static const GLint swizzleMaskG8B8[] = { GL_RED, GL_GREEN, GL_RED, GL_GREEN };
glRemap = swizzleMaskG8B8;
}
break;
case CELL_GCM_TEXTURE_R6G5B5:
{
// TODO: Probably need to actually unswizzle if is_swizzled.
const u32 numPixels = tex.GetWidth() * tex.GetHeight();
unswizzledPixels = (u8 *)malloc(numPixels * 4);
// TODO: Speed.
for (u32 i = 0; i < numPixels; ++i) {
u16 c = reinterpret_cast<const be_t<u16> *>(pixels)[i];
unswizzledPixels[i * 4 + 0] = Convert6To8((c >> 10) & 0x3F);
unswizzledPixels[i * 4 + 1] = Convert5To8((c >> 5) & 0x1F);
unswizzledPixels[i * 4 + 2] = Convert5To8((c >> 0) & 0x1F);
unswizzledPixels[i * 4 + 3] = 255;
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, unswizzledPixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_R6G5B5)");
free(unswizzledPixels);
}
break;
case CELL_GCM_TEXTURE_DEPTH24_D8: // 24-bit unsigned fixed-point number and 8 bits of garbage
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, tex.GetWidth(), tex.GetHeight(), 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_DEPTH24_D8)");
break;
case CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT: // 24-bit unsigned float and 8 bits of garbage
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, tex.GetWidth(), tex.GetHeight(), 0, GL_DEPTH_COMPONENT, GL_FLOAT, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT)");
break;
case CELL_GCM_TEXTURE_DEPTH16: // 16-bit unsigned fixed-point number
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, tex.GetWidth(), tex.GetHeight(), 0, GL_DEPTH_COMPONENT, GL_SHORT, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_DEPTH16)");
break;
case CELL_GCM_TEXTURE_DEPTH16_FLOAT: // 16-bit unsigned float
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, tex.GetWidth(), tex.GetHeight(), 0, GL_DEPTH_COMPONENT, GL_FLOAT, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_DEPTH16_FLOAT)");
break;
case CELL_GCM_TEXTURE_X16: // A 16-bit fixed-point number
{
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_X16)");
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_RED, GL_UNSIGNED_SHORT, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_X16)");
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_X16)");
static const GLint swizzleMaskX16[] = { GL_RED, GL_ONE, GL_RED, GL_ONE };
glRemap = swizzleMaskX16;
}
break;
case CELL_GCM_TEXTURE_Y16_X16: // Two 16-bit fixed-point numbers
{
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_Y16_X16)");
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_RG, GL_UNSIGNED_SHORT, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_Y16_X16)");
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_Y16_X16)");
static const GLint swizzleMaskX32_Y16_X16[] = { GL_GREEN, GL_RED, GL_GREEN, GL_RED };
glRemap = swizzleMaskX32_Y16_X16;
}
break;
case CELL_GCM_TEXTURE_R5G5B5A1:
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_R5G5B5A1)");
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_R5G5B5A1)");
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_R5G5B5A1)");
break;
case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT: // Four fp16 values
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT)");
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_RGBA, GL_HALF_FLOAT, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT)");
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT)");
break;
case CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT: // Four fp32 values
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_BGRA, GL_FLOAT, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT)");
break;
case CELL_GCM_TEXTURE_X32_FLOAT: // One 32-bit floating-point number
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_RED, GL_FLOAT, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_X32_FLOAT)");
static const GLint swizzleMaskX32_FLOAT[] = { GL_RED, GL_ONE, GL_ONE, GL_ONE };
glRemap = swizzleMaskX32_FLOAT;
}
break;
case CELL_GCM_TEXTURE_D1R5G5B5:
{
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_D1R5G5B5)");
// TODO: Texture swizzling
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_D1R5G5B5)");
static const GLint swizzleMaskX32_D1R5G5B5[] = { GL_ONE, GL_RED, GL_GREEN, GL_BLUE };
glRemap = swizzleMaskX32_D1R5G5B5;
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_D1R5G5B5)");
}
break;
case CELL_GCM_TEXTURE_D8R8G8B8: // 8 bits of garbage and three unsigned 8-bit fixed-point numbers
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_D8R8G8B8)");
static const GLint swizzleMaskX32_D8R8G8B8[] = { GL_ONE, GL_RED, GL_GREEN, GL_BLUE };
glRemap = swizzleMaskX32_D8R8G8B8;
}
break;
case CELL_GCM_TEXTURE_Y16_X16_FLOAT: // Two fp16 values
{
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE);
checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_Y16_X16_FLOAT)");
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_RG, GL_HALF_FLOAT, pixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_Y16_X16_FLOAT)");
glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_Y16_X16_FLOAT)");
static const GLint swizzleMaskX32_Y16_X16_FLOAT[] = { GL_RED, GL_GREEN, GL_RED, GL_GREEN };
glRemap = swizzleMaskX32_Y16_X16_FLOAT;
}
break;
case CELL_GCM_TEXTURE_COMPRESSED_B8R8_G8R8 & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN):
{
const u32 numPixels = tex.GetWidth() * tex.GetHeight();
unswizzledPixels = (u8 *)malloc(numPixels * 4);
// TODO: Speed.
for (u32 i = 0; i < numPixels; i += 2) {
unswizzledPixels[i * 4 + 0 + 0] = pixels[i * 2 + 3];
unswizzledPixels[i * 4 + 0 + 1] = pixels[i * 2 + 2];
unswizzledPixels[i * 4 + 0 + 2] = pixels[i * 2 + 0];
unswizzledPixels[i * 4 + 0 + 3] = 255;
// The second pixel is the same, except for red.
unswizzledPixels[i * 4 + 4 + 0] = pixels[i * 2 + 1];
unswizzledPixels[i * 4 + 4 + 1] = pixels[i * 2 + 2];
unswizzledPixels[i * 4 + 4 + 2] = pixels[i * 2 + 0];
unswizzledPixels[i * 4 + 4 + 3] = 255;
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, unswizzledPixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_COMPRESSED_B8R8_G8R8 & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN)");
free(unswizzledPixels);
}
break;
case CELL_GCM_TEXTURE_COMPRESSED_R8B8_R8G8 & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN):
{
const u32 numPixels = tex.GetWidth() * tex.GetHeight();
unswizzledPixels = (u8 *)malloc(numPixels * 4);
// TODO: Speed.
for (u32 i = 0; i < numPixels; i += 2) {
unswizzledPixels[i * 4 + 0 + 0] = pixels[i * 2 + 2];
unswizzledPixels[i * 4 + 0 + 1] = pixels[i * 2 + 3];
unswizzledPixels[i * 4 + 0 + 2] = pixels[i * 2 + 1];
unswizzledPixels[i * 4 + 0 + 3] = 255;
// The second pixel is the same, except for red.
unswizzledPixels[i * 4 + 4 + 0] = pixels[i * 2 + 0];
unswizzledPixels[i * 4 + 4 + 1] = pixels[i * 2 + 3];
unswizzledPixels[i * 4 + 4 + 2] = pixels[i * 2 + 1];
unswizzledPixels[i * 4 + 4 + 3] = 255;
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, unswizzledPixels);
checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_COMPRESSED_R8B8_R8G8 & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN)");
free(unswizzledPixels);
}
break;
default: LOG_ERROR(RSX, "Init tex error: Bad tex format (0x%x | %s | 0x%x)", format,
(is_swizzled ? "swizzled" : "linear"), tex.GetFormat() & 0x40); break;
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, tex.GetMipmap() - 1);
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, tex.GetMipmap() > 1);
if (format != CELL_GCM_TEXTURE_B8 && format != CELL_GCM_TEXTURE_X16 && format != CELL_GCM_TEXTURE_X32_FLOAT)
{
u8 remap_a = tex.GetRemap() & 0x3;
u8 remap_r = (tex.GetRemap() >> 2) & 0x3;
u8 remap_g = (tex.GetRemap() >> 4) & 0x3;
u8 remap_b = (tex.GetRemap() >> 6) & 0x3;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, glRemap[remap_a]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, glRemap[remap_r]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, glRemap[remap_g]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, glRemap[remap_b]);
}
else
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, glRemap[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, glRemap[1]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, glRemap[2]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, glRemap[3]);
}
checkForGlError("GLTexture::Init() -> remap");
static const int gl_tex_zfunc[] =
{
GL_NEVER,
GL_LESS,
GL_EQUAL,
GL_LEQUAL,
GL_GREATER,
GL_NOTEQUAL,
GL_GEQUAL,
GL_ALWAYS,
};
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GetGlWrap(tex.GetWrapS()));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GetGlWrap(tex.GetWrapT()));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GetGlWrap(tex.GetWrapR()));
checkForGlError("GLTexture::Init() -> wrap");
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, gl_tex_zfunc[tex.GetZfunc()]);
checkForGlError("GLTexture::Init() -> compare");
glTexEnvi(GL_TEXTURE_FILTER_CONTROL, GL_TEXTURE_LOD_BIAS, tex.GetBias());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, (tex.GetMinLOD() >> 8));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, (tex.GetMaxLOD() >> 8));
checkForGlError("GLTexture::Init() -> lod");
static const int gl_tex_min_filter[] =
{
GL_NEAREST, // unused
GL_NEAREST,
GL_LINEAR,
GL_NEAREST_MIPMAP_NEAREST,
GL_LINEAR_MIPMAP_NEAREST,
GL_NEAREST_MIPMAP_LINEAR,
GL_LINEAR_MIPMAP_LINEAR,
GL_NEAREST, // CELL_GCM_TEXTURE_CONVOLUTION_MIN
};
static const int gl_tex_mag_filter[] = {
GL_NEAREST, // unused
GL_NEAREST,
GL_LINEAR,
GL_NEAREST, // unused
GL_LINEAR // CELL_GCM_TEXTURE_CONVOLUTION_MAG
};
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_tex_min_filter[tex.GetMinFilter()]);
checkForGlError("GLTexture::Init() -> min filters");
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_tex_mag_filter[tex.GetMagFilter()]);
checkForGlError("GLTexture::Init() -> mag filters");
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, GetMaxAniso(tex.GetMaxAniso()));
checkForGlError("GLTexture::Init() -> max anisotropy");
//Unbind();
if(is_swizzled && format == CELL_GCM_TEXTURE_A8R8G8B8)
{
free(unswizzledPixels);
}
}
void Save(RSXTexture& tex, const std::string& name)
{
if(!m_id || !tex.GetOffset() || !tex.GetWidth() || !tex.GetHeight()) return;
const u32 texPixelCount = tex.GetWidth() * tex.GetHeight();
u32* alldata = new u32[texPixelCount];
Bind();
switch(tex.GetFormat() & ~(0x20 | 0x40))
{
case CELL_GCM_TEXTURE_B8:
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, alldata);
break;
case CELL_GCM_TEXTURE_A8R8G8B8:
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, alldata);
break;
default:
delete[] alldata;
return;
}
{
rFile f(name + ".raw", rFile::write);
f.Write(alldata, texPixelCount * 4);
}
u8* data = new u8[texPixelCount * 3];
u8* alpha = new u8[texPixelCount];
u8* src = (u8*)alldata;
u8* dst_d = data;
u8* dst_a = alpha;
for (u32 i = 0; i < texPixelCount; i++)
{
*dst_d++ = *src++;
*dst_d++ = *src++;
*dst_d++ = *src++;
*dst_a++ = *src++;
}
rImage out;
out.Create(tex.GetWidth(), tex.GetHeight(), data, alpha);
out.SaveFile(name, rBITMAP_TYPE_PNG);
delete[] alldata;
//free(data);
//free(alpha);
}
void Save(RSXTexture& tex)
{
static const std::string& dir_path = "textures";
static const std::string& file_fmt = dir_path + "/" + "tex[%d].png";
if(!rExists(dir_path)) rMkdir(dir_path);
u32 count = 0;
while(rExists(fmt::Format(file_fmt, count))) count++;
Save(tex, fmt::Format(file_fmt, count));
}
void Bind()
{
glBindTexture(GL_TEXTURE_2D, m_id);
}
void Unbind()
{
glBindTexture(GL_TEXTURE_2D, 0);
}
void Delete()
{
if(m_id)
{
glDeleteTextures(1, &m_id);
m_id = 0;
}
}
}; };
class PostDrawObj class PostDrawObj
@ -630,33 +75,12 @@ protected:
GLrbo m_rbo; GLrbo m_rbo;
public: public:
virtual void Draw() virtual void Draw();
{
static bool s_is_initialized = false;
if(!s_is_initialized)
{
s_is_initialized = true;
Initialize();
}
else
{
m_program.Use();
}
}
virtual void InitializeShaders() = 0; virtual void InitializeShaders() = 0;
virtual void InitializeLocations() = 0; virtual void InitializeLocations() = 0;
void Initialize() void Initialize();
{
InitializeShaders();
m_fp.Compile();
m_vp.Compile();
m_program.Create(m_vp.id, m_fp.GetId());
m_program.Use();
InitializeLocations();
}
}; };
class DrawCursorObj : public PostDrawObj class DrawCursorObj : public PostDrawObj
@ -675,133 +99,15 @@ public:
{ {
} }
virtual void Draw() virtual void Draw();
{
checkForGlError("PostDrawObj : Unknown error.");
PostDrawObj::Draw(); virtual void InitializeShaders();
checkForGlError("PostDrawObj::Draw");
if(!m_fbo.IsCreated()) void SetTexture(void* pixels, int width, int height);
{
m_fbo.Create();
checkForGlError("DrawCursorObj : m_fbo.Create");
m_fbo.Bind();
checkForGlError("DrawCursorObj : m_fbo.Bind");
m_rbo.Create(); void SetPosition(float x, float y, float z = 0.0f);
checkForGlError("DrawCursorObj : m_rbo.Create");
m_rbo.Bind();
checkForGlError("DrawCursorObj : m_rbo.Bind");
m_rbo.Storage(GL_RGBA, m_width, m_height);
checkForGlError("DrawCursorObj : m_rbo.Storage");
m_fbo.Renderbuffer(GL_COLOR_ATTACHMENT0, m_rbo.GetId()); void InitializeLocations();
checkForGlError("DrawCursorObj : m_fbo.Renderbuffer");
}
m_fbo.Bind();
checkForGlError("DrawCursorObj : m_fbo.Bind");
glDrawBuffer(GL_COLOR_ATTACHMENT0);
checkForGlError("DrawCursorObj : glDrawBuffer");
m_program.Use();
checkForGlError("DrawCursorObj : m_program.Use");
if(m_update_texture)
{
//m_update_texture = false;
glUniform2f(m_program.GetLocation("in_tc"), m_width, m_height);
checkForGlError("DrawCursorObj : glUniform2f");
if(!m_tex_id)
{
glGenTextures(1, &m_tex_id);
checkForGlError("DrawCursorObj : glGenTextures");
}
glActiveTexture(GL_TEXTURE0);
checkForGlError("DrawCursorObj : glActiveTexture");
glBindTexture(GL_TEXTURE_2D, m_tex_id);
checkForGlError("DrawCursorObj : glBindTexture");
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_width, m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_pixels);
checkForGlError("DrawCursorObj : glTexImage2D");
m_program.SetTex(0);
}
if(m_update_pos)
{
//m_update_pos = false;
glUniform4f(m_program.GetLocation("in_pos"), m_pos_x, m_pos_y, m_pos_z, 1.0f);
checkForGlError("DrawCursorObj : glUniform4f");
}
glDrawArrays(GL_QUADS, 0, 4);
checkForGlError("DrawCursorObj : glDrawArrays");
m_fbo.Bind(GL_READ_FRAMEBUFFER);
checkForGlError("DrawCursorObj : m_fbo.Bind(GL_READ_FRAMEBUFFER)");
GLfbo::Bind(GL_DRAW_FRAMEBUFFER, 0);
checkForGlError("DrawCursorObj : GLfbo::Bind(GL_DRAW_FRAMEBUFFER, 0)");
GLfbo::Blit(
0, 0, m_width, m_height,
0, 0, m_width, m_height,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
checkForGlError("DrawCursorObj : GLfbo::Blit");
m_fbo.Bind();
checkForGlError("DrawCursorObj : m_fbo.Bind");
}
virtual void InitializeShaders()
{
m_vp.shader =
"#version 330\n"
"\n"
"uniform vec4 in_pos;\n"
"uniform vec2 in_tc;\n"
"out vec2 tc;\n"
"\n"
"void main()\n"
"{\n"
" tc = in_tc;\n"
" gl_Position = in_pos;\n"
"}\n";
m_fp.SetShaderText(
"#version 330\n"
"\n"
"in vec2 tc;\n"
"uniform sampler2D tex0;\n"
"layout (location = 0) out vec4 res;\n"
"\n"
"void main()\n"
"{\n"
" res = texture(tex0, tc);\n"
"}\n");
}
void SetTexture(void* pixels, int width, int height)
{
m_pixels = pixels;
m_width = width;
m_height = height;
m_update_texture = true;
}
void SetPosition(float x, float y, float z = 0.0f)
{
m_pos_x = x;
m_pos_y = y;
m_pos_z = z;
m_update_pos = true;
}
void InitializeLocations()
{
//ConLog.Warning("tex0 location = 0x%x", m_program.GetLocation("tex0"));
}
}; };
class GLGSRender //TODO: find out why this used to inherit from wxWindow class GLGSRender //TODO: find out why this used to inherit from wxWindow

View file

@ -1,6 +1,5 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h" #include "Utilities/Log.h"
#include "Emu/Memory/Memory.h"
#include "GLProgram.h" #include "GLProgram.h"
#include "GLGSRender.h" #include "GLGSRender.h"

View file

@ -1,6 +1,5 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h" #include "Utilities/Log.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "GLVertexProgram.h" #include "GLVertexProgram.h"

View file

@ -1,12 +1,23 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h"
#include "Emu/Memory/Memory.h"
#include "rpcs3/Ini.h" #include "rpcs3/Ini.h"
#include "sysutil_video.h"
#include "GSManager.h" #include "GSManager.h"
#include "Null/NullGSRender.h" #include "Null/NullGSRender.h"
#include "GL/GLGSRender.h" #include "GL/GLGSRender.h"
void GSInfo::Init()
{
mode.resolutionId = Ini.GSResolution.GetValue();
mode.scanMode = CELL_VIDEO_OUT_SCAN_MODE_INTERLACE;
mode.conversion = CELL_VIDEO_OUT_DISPLAY_CONVERSION_NONE;
mode.aspect = Ini.GSAspectRatio.GetValue();
mode.refreshRates = CELL_VIDEO_OUT_REFRESH_RATE_50HZ;
mode.format = CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8;
mode.pitch = 4;
}
GSManager::GSManager() : m_render(nullptr) GSManager::GSManager() : m_render(nullptr)
{ {
} }

View file

@ -1,7 +1,5 @@
#pragma once #pragma once
#include "sysutil_video.h"
#include "GSRender.h" #include "GSRender.h"
#include "rpcs3/Ini.h"
struct GSInfo struct GSInfo
{ {
@ -21,16 +19,7 @@ struct GSInfo
{ {
} }
void Init() void Init();
{
mode.resolutionId = Ini.GSResolution.GetValue();
mode.scanMode = CELL_VIDEO_OUT_SCAN_MODE_INTERLACE;
mode.conversion = CELL_VIDEO_OUT_DISPLAY_CONVERSION_NONE;
mode.aspect = Ini.GSAspectRatio.GetValue();
mode.refreshRates = CELL_VIDEO_OUT_REFRESH_RATE_50HZ;
mode.format = CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8;
mode.pitch = 4;
}
}; };
class GSManager class GSManager

View file

@ -1,10 +1,30 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "GSRender.h" #include "GSRender.h"
GSLock::GSLock(GSRender& renderer, GSLockType type)
: m_renderer(renderer)
, m_type(type)
{
switch (m_type)
{
case GS_LOCK_NOT_WAIT: m_renderer.m_cs_main.lock(); break;
case GS_LOCK_WAIT_FLUSH: m_renderer.m_sem_flush.wait(); break;
case GS_LOCK_WAIT_FLIP: m_renderer.m_sem_flip.wait(); break;
}
}
GSLock::~GSLock()
{
switch (m_type)
{
case GS_LOCK_NOT_WAIT: m_renderer.m_cs_main.unlock(); break;
case GS_LOCK_WAIT_FLUSH: m_renderer.m_sem_flush.post(); break;
case GS_LOCK_WAIT_FLIP: m_renderer.m_sem_flip.post(); break;
}
}
GSLockCurrent::GSLockCurrent(GSLockType type) : GSLock(Emu.GetGSManager().GetRender(), type) GSLockCurrent::GSLockCurrent(GSLockType type) : GSLock(Emu.GetGSManager().GetRender(), type)
{ {
} }

View file

@ -1,5 +1,4 @@
#pragma once #pragma once
#include "Emu/RSX/GCM.h"
#include "Emu/RSX/RSXThread.h" #include "Emu/RSX/RSXThread.h"
struct GSRender : public RSXThread struct GSRender : public RSXThread
@ -25,27 +24,9 @@ private:
GSLockType m_type; GSLockType m_type;
public: public:
GSLock(GSRender& renderer, GSLockType type) GSLock(GSRender& renderer, GSLockType type);
: m_renderer(renderer)
, m_type(type)
{
switch(m_type)
{
case GS_LOCK_NOT_WAIT: m_renderer.m_cs_main.lock(); break;
case GS_LOCK_WAIT_FLUSH: m_renderer.m_sem_flush.wait(); break;
case GS_LOCK_WAIT_FLIP: m_renderer.m_sem_flip.wait(); break;
}
}
~GSLock() ~GSLock();
{
switch(m_type)
{
case GS_LOCK_NOT_WAIT: m_renderer.m_cs_main.unlock(); break;
case GS_LOCK_WAIT_FLUSH: m_renderer.m_sem_flush.post(); break;
case GS_LOCK_WAIT_FLIP: m_renderer.m_sem_flip.post(); break;
}
}
}; };
struct GSLockCurrent : GSLock struct GSLockCurrent : GSLock

View file

@ -1,7 +1,4 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h"
#include "Emu/Memory/Memory.h"
#include "RSXThread.h"
#include "RSXThread.h" #include "RSXThread.h"
#include "RSXTexture.h" #include "RSXTexture.h"

View file

@ -1,11 +1,12 @@
#include "stdafx.h" #include "stdafx.h"
#include "rpcs3/Ini.h"
#include "Utilities/Log.h" #include "Utilities/Log.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "RSXThread.h" #include "RSXThread.h"
#include "Emu/SysCalls/lv2/sys_time.h" #include "Emu/SysCalls/lv2/sys_time.h"
#define ARGS(x) (x >= count ? OutOfArgsCount(x, cmd, count, args) : args[x].ToLE()) #define ARGS(x) (x >= count ? OutOfArgsCount(x, cmd, count, args.GetAddr()) : args[x].ToLE())
u32 methodRegisters[0xffff]; u32 methodRegisters[0xffff];
@ -139,8 +140,9 @@ u32 RSXVertexData::GetTypeSize()
#define CMD_LOG(...) #define CMD_LOG(...)
#endif #endif
u32 RSXThread::OutOfArgsCount(const uint x, const u32 cmd, const u32 count, mem32_ptr_t args) u32 RSXThread::OutOfArgsCount(const uint x, const u32 cmd, const u32 count, const u32 args_addr)
{ {
mem32_ptr_t args(args_addr);
std::string debug = GetMethodName(cmd); std::string debug = GetMethodName(cmd);
debug += "("; debug += "(";
for(u32 i=0; i<count; ++i) debug += (i ? ", " : "") + fmt::Format("0x%x", ARGS(i)); for(u32 i=0; i<count; ++i) debug += (i ? ", " : "") + fmt::Format("0x%x", ARGS(i));
@ -205,8 +207,10 @@ u32 RSXThread::OutOfArgsCount(const uint x, const u32 cmd, const u32 count, mem3
index = (cmd - a) / m; \ index = (cmd - a) / m; \
case a \ case a \
void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, mem32_ptr_t args, const u32 count) void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const u32 count)
{ {
mem32_ptr_t args(args_addr);
#if CMD_DEBUG #if CMD_DEBUG
std::string debug = GetMethodName(cmd); std::string debug = GetMethodName(cmd);
debug += "("; debug += "(";
@ -2237,7 +2241,7 @@ void RSXThread::Task()
methodRegisters[(cmd & 0xffff) + (i*4*inc)] = ARGS(i); methodRegisters[(cmd & 0xffff) + (i*4*inc)] = ARGS(i);
} }
DoCmd(cmd, cmd & 0x3ffff, args, count); DoCmd(cmd, cmd & 0x3ffff, args.GetAddr(), count);
m_ctrl->get = get + (count + 1) * 4; m_ctrl->get = get + (count + 1) * 4;
//memset(Memory.GetMemFromAddr(p.m_ioAddress + get), 0, (count + 1) * 4); //memset(Memory.GetMemFromAddr(p.m_ioAddress + get), 0, (count + 1) * 4);
@ -2252,3 +2256,33 @@ void RSXThread::Task()
OnExitThread(); OnExitThread();
} }
void RSXThread::Init(const u32 ioAddress, const u32 ioSize, const u32 ctrlAddress, const u32 localAddress)
{
m_ctrl = (CellGcmControl*)&Memory[ctrlAddress];
m_ioAddress = ioAddress;
m_ioSize = ioSize;
m_ctrlAddress = ctrlAddress;
m_local_mem_addr = localAddress;
m_cur_vertex_prog = nullptr;
m_cur_shader_prog = nullptr;
m_cur_shader_prog_num = 0;
m_used_gcm_commands.clear();
OnInit();
ThreadBase::Start();
}
u32 RSXThread::ReadIO32(u32 addr)
{
u32 value;
Memory.RSXIOMem.Read32(Memory.RSXIOMem.GetStartAddr() + addr, &value);
return value;
}
void RSXThread::WriteIO32(u32 addr, u32 value)
{
Memory.RSXIOMem.Write32(Memory.RSXIOMem.GetStartAddr() + addr, value);
}

View file

@ -4,7 +4,6 @@
#include "RSXVertexProgram.h" #include "RSXVertexProgram.h"
#include "RSXFragmentProgram.h" #include "RSXFragmentProgram.h"
#include "Emu/SysCalls/Callback.h" #include "Emu/SysCalls/Callback.h"
#include "Emu/Memory/Memory.h"
#include <stack> #include <stack>
#include <set> // For tracking a list of used gcm commands #include <set> // For tracking a list of used gcm commands
@ -611,8 +610,8 @@ protected:
void Begin(u32 draw_mode); void Begin(u32 draw_mode);
void End(); void End();
u32 OutOfArgsCount(const uint x, const u32 cmd, const u32 count, mem32_ptr_t args); u32 OutOfArgsCount(const uint x, const u32 cmd, const u32 count, const u32 args_addr);
void DoCmd(const u32 fcmd, const u32 cmd, mem32_ptr_t args, const u32 count); void DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const u32 count);
void nativeRescale(float width, float height); void nativeRescale(float width, float height);
virtual void OnInit() = 0; virtual void OnInit() = 0;
@ -636,33 +635,9 @@ protected:
virtual void Task(); virtual void Task();
public: public:
void Init(const u32 ioAddress, const u32 ioSize, const u32 ctrlAddress, const u32 localAddress) void Init(const u32 ioAddress, const u32 ioSize, const u32 ctrlAddress, const u32 localAddress);
{
m_ctrl = (CellGcmControl*)&Memory[ctrlAddress];
m_ioAddress = ioAddress;
m_ioSize = ioSize;
m_ctrlAddress = ctrlAddress;
m_local_mem_addr = localAddress;
m_cur_vertex_prog = nullptr; u32 ReadIO32(u32 addr);
m_cur_shader_prog = nullptr;
m_cur_shader_prog_num = 0;
m_used_gcm_commands.clear(); void WriteIO32(u32 addr, u32 value);
OnInit();
ThreadBase::Start();
}
u32 ReadIO32(u32 addr)
{
u32 value;
Memory.RSXIOMem.Read32(Memory.RSXIOMem.GetStartAddr() + addr, &value);
return value;
}
void WriteIO32(u32 addr, u32 value)
{
Memory.RSXIOMem.Write32(Memory.RSXIOMem.GetStartAddr() + addr, value);
}
}; };

View file

@ -2,10 +2,9 @@
#include "Utilities/Log.h" #include "Utilities/Log.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Callback.h"
#include "Emu/Cell/PPUThread.h" #include "Emu/Cell/PPUThread.h"
#include "Emu/Cell/PPCThread.h"
#include "Callback.h"
Callback::Callback(u32 slot, u64 addr) Callback::Callback(u32 slot, u64 addr)
: m_addr(addr) : m_addr(addr)

View file

@ -1,10 +1,6 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "SysCalls.h" #include "SysCalls.h"
#define FUNC_LOG_ERROR(x) LOG_ERROR(HLE, x); return 0
std::string SysCalls::GetHLEFuncName(const u32 fid) std::string SysCalls::GetHLEFuncName(const u32 fid)
{ {
switch(fid) switch(fid)

View file

@ -0,0 +1,32 @@
#include "stdafx.h"
#include "rpcs3/Ini.h"
#include "Utilities/Log.h"
#include "Emu/System.h"
#include "LogBase.h"
bool LogBase::CheckLogging() const
{
return Ini.HLELogging.GetValue();
}
void LogBase::LogOutput(LogType type, const char* info, const std::string& text)
{
switch (type)
{
case LogNotice: LOG_NOTICE(HLE, "%s%s%s", GetName().c_str(), info, text.c_str()); break;
case LogSuccess: LOG_SUCCESS(HLE, "%s%s%s", GetName().c_str(), info, text.c_str()); break;
case LogWarning: LOG_WARNING(HLE, "%s%s%s", GetName().c_str(), info, text.c_str()); break;
case LogError: LOG_ERROR(HLE, "%s%s%s", GetName().c_str(), info, text.c_str()); break;
}
}
void LogBase::LogOutput(LogType type, const u32 id, const char* info, const std::string& text)
{
switch (type)
{
case LogNotice: LOG_NOTICE(HLE, "%s[%d]%s%s", GetName().c_str(), id, info, text.c_str()); break;
case LogSuccess: LOG_SUCCESS(HLE, "%s[%d]%s%s", GetName().c_str(), id, info, text.c_str()); break;
case LogWarning: LOG_WARNING(HLE, "%s[%d]%s%s", GetName().c_str(), id, info, text.c_str()); break;
case LogError: LOG_ERROR(HLE, "%s[%d]%s%s", GetName().c_str(), id, info, text.c_str()); break;
}
}

View file

@ -3,6 +3,18 @@
class LogBase class LogBase
{ {
bool m_logging; bool m_logging;
bool CheckLogging() const;
enum LogType
{
LogNotice,
LogSuccess,
LogWarning,
LogError,
};
void LogOutput(LogType type, const char* info, const std::string& text);
void LogOutput(LogType type, const u32 id, const char* info, const std::string& text);
public: public:
void SetLogging(bool value) void SetLogging(bool value)
@ -10,12 +22,6 @@ public:
m_logging = value; m_logging = value;
} }
bool GetLogging()
{
//return m_logging; // TODO
return Ini.HLELogging.GetValue();
}
LogBase() LogBase()
{ {
SetLogging(false); SetLogging(false);
@ -25,17 +31,17 @@ public:
template<typename... Targs> void Notice(const u32 id, const char* fmt, Targs... args) template<typename... Targs> void Notice(const u32 id, const char* fmt, Targs... args)
{ {
LOG_NOTICE(HLE, GetName() + fmt::Format("[%d]: ", id) + fmt::Format(fmt, args...)); LogOutput(LogNotice, id, ": ", fmt::Format(fmt, args...));
} }
template<typename... Targs> void Notice(const char* fmt, Targs... args) template<typename... Targs> void Notice(const char* fmt, Targs... args)
{ {
LOG_NOTICE(HLE, GetName() + ": " + fmt::Format(fmt, args...)); LogOutput(LogNotice, ": ", fmt::Format(fmt, args...));
} }
template<typename... Targs> __forceinline void Log(const char* fmt, Targs... args) template<typename... Targs> __forceinline void Log(const char* fmt, Targs... args)
{ {
if (GetLogging()) if (CheckLogging())
{ {
Notice(fmt, args...); Notice(fmt, args...);
} }
@ -43,39 +49,49 @@ public:
template<typename... Targs> __forceinline void Log(const u32 id, const char* fmt, Targs... args) template<typename... Targs> __forceinline void Log(const u32 id, const char* fmt, Targs... args)
{ {
if (GetLogging()) if (CheckLogging())
{ {
Notice(id, fmt, args...); Notice(id, fmt, args...);
} }
} }
template<typename... Targs> void Success(const u32 id, const char* fmt, Targs... args)
{
LogOutput(LogSuccess, id, ": ", fmt::Format(fmt, args...));
}
template<typename... Targs> void Success(const char* fmt, Targs... args)
{
LogOutput(LogSuccess, ": ", fmt::Format(fmt, args...));
}
template<typename... Targs> void Warning(const u32 id, const char* fmt, Targs... args) template<typename... Targs> void Warning(const u32 id, const char* fmt, Targs... args)
{ {
LOG_WARNING(HLE, GetName() + fmt::Format("[%d] warning: ", id) + fmt::Format(fmt, args...)); LogOutput(LogWarning, id, " warning: ", fmt::Format(fmt, args...));
} }
template<typename... Targs> void Warning(const char* fmt, Targs... args) template<typename... Targs> void Warning(const char* fmt, Targs... args)
{ {
LOG_WARNING(HLE, GetName() + " warning: " + fmt::Format(fmt, args...)); LogOutput(LogWarning, " warning: ", fmt::Format(fmt, args...));
} }
template<typename... Targs> void Error(const u32 id, const char* fmt, Targs... args) template<typename... Targs> void Error(const u32 id, const char* fmt, Targs... args)
{ {
LOG_ERROR(HLE, GetName() + fmt::Format("[%d] error: ", id) + fmt::Format(fmt, args...)); LogOutput(LogError, id, " error: ", fmt::Format(fmt, args...));
} }
template<typename... Targs> void Error(const char* fmt, Targs... args) template<typename... Targs> void Error(const char* fmt, Targs... args)
{ {
LOG_ERROR(HLE, GetName() + " error: " + fmt::Format(fmt, args...)); LogOutput(LogError, " error: ", fmt::Format(fmt, args...));
} }
template<typename... Targs> void Todo(const u32 id, const char* fmt, Targs... args) template<typename... Targs> void Todo(const u32 id, const char* fmt, Targs... args)
{ {
LOG_ERROR(HLE, GetName() + fmt::Format("[%d] TODO: ", id) + fmt::Format(fmt, args...)); LogOutput(LogError, id, " TODO: ", fmt::Format(fmt, args...));
} }
template<typename... Targs> void Todo(const char* fmt, Targs... args) template<typename... Targs> void Todo(const char* fmt, Targs... args)
{ {
LOG_ERROR(HLE, GetName() + " TODO: " + fmt::Format(fmt, args...)); LogOutput(LogError, " TODO: ", fmt::Format(fmt, args...));
} }
}; };

View file

@ -1,18 +1,24 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/Static.h"
#include "Crypto/sha1.h" #include "Crypto/sha1.h"
#include <mutex> #include <mutex>
#include "ModuleManager.h" #include "ModuleManager.h"
u32 getFunctionId(const std::string& name) u32 getFunctionId(const char* name)
{ {
const char* suffix = "\x67\x59\x65\x99\x04\x25\x04\x90\x56\x64\x27\x49\x94\x89\x74\x1A"; // Symbol name suffix const char* suffix = "\x67\x59\x65\x99\x04\x25\x04\x90\x56\x64\x27\x49\x94\x89\x74\x1A"; // Symbol name suffix
std::string input = name + suffix; u8 output[20];
unsigned char output[20];
// Compute SHA-1 hash
sha1_context ctx;
sha1_starts(&ctx);
sha1_update(&ctx, (const u8*)name, strlen(name));
sha1_update(&ctx, (const u8*)suffix, strlen(suffix));
sha1_finish(&ctx, output);
sha1((unsigned char*)input.c_str(), input.length(), output); // Compute SHA-1 hash
return (u32&)output[0]; return (u32&)output[0];
} }
@ -167,3 +173,18 @@ bool Module::CheckID(u32 id, ID*& _id) const
{ {
return Emu.GetIdManager().CheckID(id) && (_id = &Emu.GetIdManager().GetID(id))->m_name == GetName(); return Emu.GetIdManager().CheckID(id) && (_id = &Emu.GetIdManager().GetID(id))->m_name == GetName();
} }
bool Module::RemoveId(u32 id)
{
return Emu.GetIdManager().RemoveID(id);
}
IdManager& Module::GetIdManager() const
{
return Emu.GetIdManager();
}
void Module::PushNewFuncSub(SFunc* func)
{
Emu.GetSFuncManager().push_back(func);
}

View file

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "Emu/SysCalls/SC_FUNC.h" #include "Emu/SysCalls/SC_FUNC.h"
#include "ErrorCodes.h"
#include "LogBase.h" #include "LogBase.h"
//TODO //TODO
@ -17,7 +17,7 @@ struct ModuleFunc
~ModuleFunc() ~ModuleFunc()
{ {
safe_delete(func); delete func;
} }
}; };
@ -38,10 +38,12 @@ struct SFunc
~SFunc() ~SFunc()
{ {
safe_delete(func); delete func;
} }
}; };
class StaticFuncManager;
class Module : public LogBase class Module : public LogBase
{ {
std::string m_name; std::string m_name;
@ -50,6 +52,9 @@ class Module : public LogBase
void (*m_load_func)(); void (*m_load_func)();
void (*m_unload_func)(); void (*m_unload_func)();
IdManager& GetIdManager() const;
void PushNewFuncSub(SFunc* func);
public: public:
std::vector<ModuleFunc*> m_funcs_list; std::vector<ModuleFunc*> m_funcs_list;
@ -106,15 +111,17 @@ public:
template<typename T> template<typename T>
u32 GetNewId(T* data, IDType type = TYPE_OTHER) u32 GetNewId(T* data, IDType type = TYPE_OTHER)
{ {
return Emu.GetIdManager().GetNewID<T>(GetName(), data, type); return GetIdManager().GetNewID<T>(GetName(), data, type);
} }
bool RemoveId(u32 id);
template<typename T> __forceinline void AddFunc(u32 id, T func); template<typename T> __forceinline void AddFunc(u32 id, T func);
template<typename T> __forceinline void AddFunc(const std::string& name, T func); template<typename T> __forceinline void AddFunc(const char* name, T func);
template<typename T> __forceinline void AddFuncSub(const char group[8], const u64 ops[], const char* name, T func); template<typename T> __forceinline void AddFuncSub(const char group[8], const u64 ops[], const char* name, T func);
}; };
u32 getFunctionId(const std::string& name); u32 getFunctionId(const char* name);
template<typename T> template<typename T>
__forceinline void Module::AddFunc(u32 id, T func) __forceinline void Module::AddFunc(u32 id, T func)
@ -123,7 +130,7 @@ __forceinline void Module::AddFunc(u32 id, T func)
} }
template<typename T> template<typename T>
__forceinline void Module::AddFunc(const std::string& name, T func) __forceinline void Module::AddFunc(const char* name, T func)
{ {
AddFunc(getFunctionId(name), func); AddFunc(getFunctionId(name), func);
} }
@ -152,5 +159,13 @@ __forceinline void Module::AddFuncSub(const char group[8], const u64 ops[], cons
op.crc = re(op.crc); op.crc = re(op.crc);
sf->ops.push_back(op); sf->ops.push_back(op);
} }
Emu.GetSFuncManager().push_back(sf); PushNewFuncSub(sf);
} }
#define REG_SUB(module, group, name, ...) \
static const u64 name ## _table[] = {__VA_ARGS__ , 0}; \
module->AddFuncSub(group, name ## _table, #name, name)
#define REG_FUNC(module, name) module->AddFunc(getFunctionId(#name), name)
#define UNIMPLEMENTED_FUNC(module) module->Todo("%s", __FUNCTION__)

View file

@ -1,8 +1,8 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/Io/Keyboard.h" #include "Emu/Io/Keyboard.h"
extern Module *sys_io; extern Module *sys_io;

View file

@ -1,8 +1,8 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/Io/Mouse.h" #include "Emu/Io/Mouse.h"
extern Module *sys_io; extern Module *sys_io;

View file

@ -1,8 +1,8 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/Io/Pad.h" #include "Emu/Io/Pad.h"
extern Module *sys_io; extern Module *sys_io;
@ -383,8 +383,6 @@ int cellPadSetPortSetting(u32 port_no, u32 port_setting)
{ {
sys_io->Log("cellPadSetPortSetting(port_no=%d, port_setting=0x%x)", port_no, port_setting); sys_io->Log("cellPadSetPortSetting(port_no=%d, port_setting=0x%x)", port_no, port_setting);
if(!Emu.GetPadManager().IsInited()) return CELL_PAD_ERROR_UNINITIALIZED; if(!Emu.GetPadManager().IsInited()) return CELL_PAD_ERROR_UNINITIALIZED;
if ((port_setting < CELL_PAD_SETTING_PRESS_ON) || port_setting >(CELL_PAD_SETTING_PRESS_ON | CELL_PAD_SETTING_SENSOR_ON) && port_setting != 0)
return CELL_PAD_ERROR_INVALID_PARAMETER;
const PadInfo& rinfo = Emu.GetPadManager().GetInfo(); const PadInfo& rinfo = Emu.GetPadManager().GetInfo();
if (port_no >= rinfo.max_connect) return CELL_PAD_ERROR_INVALID_PARAMETER; if (port_no >= rinfo.max_connect) return CELL_PAD_ERROR_INVALID_PARAMETER;
if (port_no >= rinfo.now_connect) return CELL_PAD_ERROR_NO_DEVICE; if (port_no >= rinfo.now_connect) return CELL_PAD_ERROR_NO_DEVICE;

View file

@ -1,10 +1,7 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/SysCalls.h"
#include "cellPamf.h"
extern std::mutex g_mutex_avcodec_open2; extern std::mutex g_mutex_avcodec_open2;
@ -15,12 +12,77 @@ extern "C"
#include "libswresample/swresample.h" #include "libswresample/swresample.h"
} }
#include "cellPamf.h"
#include "cellAdec.h" #include "cellAdec.h"
//void cellAdec_init(); //void cellAdec_init();
//Module cellAdec(0x0006, cellAdec_init); //Module cellAdec(0x0006, cellAdec_init);
Module *cellAdec = nullptr; Module *cellAdec = nullptr;
AudioDecoder::AudioDecoder(AudioCodecType type, u32 addr, u32 size, u32 func, u32 arg)
: type(type)
, memAddr(addr)
, memSize(size)
, memBias(0)
, cbFunc(func)
, cbArg(arg)
, adecCb(nullptr)
, is_running(false)
, is_finished(false)
, just_started(false)
, just_finished(false)
, ctx(nullptr)
, fmt(nullptr)
{
AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_ATRAC3P);
if (!codec)
{
cellAdec->Error("AudioDecoder(): avcodec_find_decoder(ATRAC3P) failed");
Emu.Pause();
return;
}
fmt = avformat_alloc_context();
if (!fmt)
{
cellAdec->Error("AudioDecoder(): avformat_alloc_context failed");
Emu.Pause();
return;
}
io_buf = (u8*)av_malloc(4096);
fmt->pb = avio_alloc_context(io_buf, 4096, 0, this, adecRead, NULL, NULL);
if (!fmt->pb)
{
cellAdec->Error("AudioDecoder(): avio_alloc_context failed");
Emu.Pause();
return;
}
}
AudioDecoder::~AudioDecoder()
{
// TODO: check finalization
if (ctx)
{
for (u32 i = frames.GetCount() - 1; ~i; i--)
{
AdecFrame& af = frames.Peek(i);
av_frame_unref(af.data);
av_frame_free(&af.data);
}
avcodec_close(ctx);
avformat_close_input(&fmt);
}
if (fmt)
{
if (io_buf)
{
av_free(io_buf);
}
if (fmt->pb) av_free(fmt->pb);
avformat_free_context(fmt);
}
}
int adecRawRead(void* opaque, u8* buf, int buf_size) int adecRawRead(void* opaque, u8* buf, int buf_size)
{ {
AudioDecoder& adec = *(AudioDecoder*)opaque; AudioDecoder& adec = *(AudioDecoder*)opaque;
@ -34,7 +96,7 @@ next:
{ {
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
LOG_WARNING(HLE, "adecRawRead(): aborted"); cellAdec->Warning("adecRawRead(): aborted");
return 0; return 0;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1));
@ -66,7 +128,7 @@ next:
} }
break; break;
default: default:
LOG_ERROR(HLE, "adecRawRead(): sequence error (task %d)", adec.job.Peek().type); cellAdec->Error("adecRawRead(): sequence error (task %d)", adec.job.Peek().type);
return -1; return -1;
} }
@ -101,7 +163,7 @@ int adecRead(void* opaque, u8* buf, int buf_size)
{ {
if (buf_size < (int)adec.reader.rem_size) if (buf_size < (int)adec.reader.rem_size)
{ {
LOG_ERROR(HLE, "adecRead(): too small buf_size (rem_size = %d, buf_size = %d)", adec.reader.rem_size, buf_size); cellAdec->Error("adecRead(): too small buf_size (rem_size = %d, buf_size = %d)", adec.reader.rem_size, buf_size);
Emu.Pause(); Emu.Pause();
return 0; return 0;
} }
@ -121,7 +183,7 @@ int adecRead(void* opaque, u8* buf, int buf_size)
if (adecRawRead(opaque, header, 8) < 8) break; if (adecRawRead(opaque, header, 8) < 8) break;
if (header[0] != 0x0f || header[1] != 0xd0) if (header[0] != 0x0f || header[1] != 0xd0)
{ {
LOG_ERROR(HLE, "adecRead(): 0x0FD0 header not found"); cellAdec->Error("adecRead(): 0x0FD0 header not found");
Emu.Pause(); Emu.Pause();
return -1; return -1;
} }
@ -131,7 +193,7 @@ int adecRead(void* opaque, u8* buf, int buf_size)
OMAHeader oma(1 /* atrac3p id */, header[2], header[3]); OMAHeader oma(1 /* atrac3p id */, header[2], header[3]);
if (buf_size < sizeof(oma) + 8) if (buf_size < sizeof(oma) + 8)
{ {
LOG_ERROR(HLE, "adecRead(): OMAHeader writing failed"); cellAdec->Error("adecRead(): OMAHeader writing failed");
Emu.Pause(); Emu.Pause();
return 0; return 0;
} }
@ -188,7 +250,7 @@ u32 adecOpen(AudioDecoder* data)
thread t("Audio Decoder[" + std::to_string(adec_id) + "] Thread", [&]() thread t("Audio Decoder[" + std::to_string(adec_id) + "] Thread", [&]()
{ {
LOG_NOTICE(HLE, "Audio Decoder thread started"); cellAdec->Notice("Audio Decoder thread started");
AdecTask& task = adec.task; AdecTask& task = adec.task;
@ -219,288 +281,288 @@ u32 adecOpen(AudioDecoder* data)
switch (task.type) switch (task.type)
{ {
case adecStartSeq: case adecStartSeq:
{ {
// TODO: reset data // TODO: reset data
LOG_WARNING(HLE, "adecStartSeq:"); cellAdec->Warning("adecStartSeq:");
adec.reader.addr = 0; adec.reader.addr = 0;
adec.reader.size = 0; adec.reader.size = 0;
adec.reader.init = false; adec.reader.init = false;
if (adec.reader.rem) free(adec.reader.rem); if (adec.reader.rem) free(adec.reader.rem);
adec.reader.rem = nullptr; adec.reader.rem = nullptr;
adec.reader.rem_size = 0; adec.reader.rem_size = 0;
adec.is_running = true; adec.is_running = true;
adec.just_started = true; adec.just_started = true;
} }
break; break;
case adecEndSeq: case adecEndSeq:
{ {
// TODO: finalize // TODO: finalize
LOG_WARNING(HLE, "adecEndSeq:"); cellAdec->Warning("adecEndSeq:");
/*Callback cb; /*Callback cb;
cb.SetAddr(adec.cbFunc); cb.SetAddr(adec.cbFunc);
cb.Handle(adec.id, CELL_ADEC_MSG_TYPE_SEQDONE, CELL_OK, adec.cbArg); cb.Handle(adec.id, CELL_ADEC_MSG_TYPE_SEQDONE, CELL_OK, adec.cbArg);
cb.Branch(true); // ???*/ cb.Branch(true); // ???*/
adec.adecCb->ExecAsCallback(adec.cbFunc, true, adec.id, CELL_ADEC_MSG_TYPE_SEQDONE, CELL_OK, adec.cbArg); adec.adecCb->ExecAsCallback(adec.cbFunc, true, adec.id, CELL_ADEC_MSG_TYPE_SEQDONE, CELL_OK, adec.cbArg);
adec.is_running = false; adec.is_running = false;
adec.just_finished = true; adec.just_finished = true;
} }
break; break;
case adecDecodeAu: case adecDecodeAu:
{
int err = 0;
adec.reader.addr = task.au.addr;
adec.reader.size = task.au.size;
//LOG_NOTICE(HLE, "Audio AU: size = 0x%x, pts = 0x%llx", task.au.size, task.au.pts);
if (adec.just_started)
{ {
int err = 0; adec.first_pts = task.au.pts;
adec.last_pts = task.au.pts - 0x10000; // hack
}
adec.reader.addr = task.au.addr; struct AVPacketHolder : AVPacket
adec.reader.size = task.au.size; {
//LOG_NOTICE(HLE, "Audio AU: size = 0x%x, pts = 0x%llx", task.au.size, task.au.pts); AVPacketHolder(u32 size)
if (adec.just_started)
{ {
adec.first_pts = task.au.pts; av_init_packet(this);
adec.last_pts = task.au.pts - 0x10000; // hack
if (size)
{
data = (u8*)av_calloc(1, size + FF_INPUT_BUFFER_PADDING_SIZE);
this->size = size + FF_INPUT_BUFFER_PADDING_SIZE;
}
else
{
data = NULL;
size = 0;
}
} }
struct AVPacketHolder : AVPacket ~AVPacketHolder()
{ {
AVPacketHolder(u32 size) av_free(data);
{ //av_free_packet(this);
av_init_packet(this); }
if (size) } au(0);
{
data = (u8*)av_calloc(1, size + FF_INPUT_BUFFER_PADDING_SIZE);
this->size = size + FF_INPUT_BUFFER_PADDING_SIZE;
}
else
{
data = NULL;
size = 0;
}
}
~AVPacketHolder() /*{
{ wxFile dump;
av_free(data); dump.Open(wxString::Format("audio pts-0x%llx.dump", task.au.pts), wxFile::write);
//av_free_packet(this); u8* buf = (u8*)malloc(task.au.size);
} if (Memory.CopyToReal(buf, task.au.addr, task.au.size)) dump.Write(buf, task.au.size);
free(buf);
dump.Close();
}*/
} au(0); if (adec.just_started && adec.just_finished)
{
avcodec_flush_buffers(adec.ctx);
adec.reader.init = true;
adec.just_finished = false;
adec.just_started = false;
}
else if (adec.just_started) // deferred initialization
{
err = avformat_open_input(&adec.fmt, NULL, av_find_input_format("oma"), NULL);
if (err)
{
cellAdec->Error("adecDecodeAu: avformat_open_input() failed");
Emu.Pause();
break;
}
AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_ATRAC3P); // ???
if (!codec)
{
cellAdec->Error("adecDecodeAu: avcodec_find_decoder() failed");
Emu.Pause();
break;
}
//err = avformat_find_stream_info(adec.fmt, NULL);
//if (err)
//{
// cellAdec->Error("adecDecodeAu: avformat_find_stream_info() failed");
// Emu.Pause();
// break;
//}
//if (!adec.fmt->nb_streams)
//{
// cellAdec->Error("adecDecodeAu: no stream found");
// Emu.Pause();
// break;
//}
if (!avformat_new_stream(adec.fmt, codec))
{
cellAdec->Error("adecDecodeAu: avformat_new_stream() failed");
Emu.Pause();
break;
}
adec.ctx = adec.fmt->streams[0]->codec; // TODO: check data
/*{ AVDictionary* opts = nullptr;
wxFile dump; av_dict_set(&opts, "refcounted_frames", "1", 0);
dump.Open(wxString::Format("audio pts-0x%llx.dump", task.au.pts), wxFile::write); {
u8* buf = (u8*)malloc(task.au.size); std::lock_guard<std::mutex> lock(g_mutex_avcodec_open2);
if (Memory.CopyToReal(buf, task.au.addr, task.au.size)) dump.Write(buf, task.au.size); // not multithread-safe (???)
free(buf); err = avcodec_open2(adec.ctx, codec, &opts);
dump.Close(); }
if (err)
{
cellAdec->Error("adecDecodeAu: avcodec_open2() failed");
Emu.Pause();
break;
}
adec.just_started = false;
}
bool last_frame = false;
while (true)
{
if (Emu.IsStopped())
{
cellAdec->Warning("adecDecodeAu: aborted");
return;
}
/*if (!adec.ctx) // fake
{
AdecFrame frame;
frame.pts = task.au.pts;
frame.auAddr = task.au.addr;
frame.auSize = task.au.size;
frame.userdata = task.au.userdata;
frame.size = 4096;
frame.data = nullptr;
adec.frames.Push(frame);
adec.adecCb->ExecAsCallback(adec.cbFunc, false, adec.id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, adec.cbArg);
break;
}*/ }*/
if (adec.just_started && adec.just_finished) last_frame = av_read_frame(adec.fmt, &au) < 0;
if (last_frame)
{ {
avcodec_flush_buffers(adec.ctx); //break;
adec.reader.init = true; av_free(au.data);
adec.just_finished = false; au.data = NULL;
adec.just_started = false; au.size = 0;
}
else if (adec.just_started) // deferred initialization
{
err = avformat_open_input(&adec.fmt, NULL, av_find_input_format("oma"), NULL);
if (err)
{
LOG_ERROR(HLE, "adecDecodeAu: avformat_open_input() failed");
Emu.Pause();
break;
}
AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_ATRAC3P); // ???
if (!codec)
{
LOG_ERROR(HLE, "adecDecodeAu: avcodec_find_decoder() failed");
Emu.Pause();
break;
}
/*err = avformat_find_stream_info(adec.fmt, NULL);
if (err)
{
LOG_ERROR(HLE, "adecDecodeAu: avformat_find_stream_info() failed");
Emu.Pause();
break;
}
if (!adec.fmt->nb_streams)
{
LOG_ERROR(HLE, "adecDecodeAu: no stream found");
Emu.Pause();
break;
}*/
if (!avformat_new_stream(adec.fmt, codec))
{
LOG_ERROR(HLE, "adecDecodeAu: avformat_new_stream() failed");
Emu.Pause();
break;
}
adec.ctx = adec.fmt->streams[0]->codec; // TODO: check data
AVDictionary* opts = nullptr;
av_dict_set(&opts, "refcounted_frames", "1", 0);
{
std::lock_guard<std::mutex> lock(g_mutex_avcodec_open2);
// not multithread-safe (???)
err = avcodec_open2(adec.ctx, codec, &opts);
}
if (err)
{
LOG_ERROR(HLE, "adecDecodeAu: avcodec_open2() failed");
Emu.Pause();
break;
}
adec.just_started = false;
} }
bool last_frame = false; struct AdecFrameHolder : AdecFrame
while (true)
{ {
if (Emu.IsStopped()) AdecFrameHolder()
{ {
LOG_WARNING(HLE, "adecDecodeAu: aborted"); data = av_frame_alloc();
return;
} }
/*if (!adec.ctx) // fake ~AdecFrameHolder()
{ {
AdecFrame frame; if (data)
frame.pts = task.au.pts; {
frame.auAddr = task.au.addr; av_frame_unref(data);
frame.auSize = task.au.size; av_frame_free(&data);
frame.userdata = task.au.userdata; }
frame.size = 4096; }
frame.data = nullptr;
adec.frames.Push(frame);
adec.adecCb->ExecAsCallback(adec.cbFunc, false, adec.id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, adec.cbArg); } frame;
if (!frame.data)
{
cellAdec->Error("adecDecodeAu: av_frame_alloc() failed");
Emu.Pause();
break;
}
int got_frame = 0;
int decode = avcodec_decode_audio4(adec.ctx, frame.data, &got_frame, &au);
if (decode <= 0)
{
if (!last_frame && decode < 0)
{
cellAdec->Error("adecDecodeAu: AU decoding error(0x%x)", decode);
}
if (!got_frame && adec.reader.size == 0) break;
}
if (got_frame)
{
u64 ts = av_frame_get_best_effort_timestamp(frame.data);
if (ts != AV_NOPTS_VALUE)
{
frame.pts = ts/* - adec.first_pts*/;
adec.last_pts = frame.pts;
}
else
{
adec.last_pts += ((u64)frame.data->nb_samples) * 90000 / 48000;
frame.pts = adec.last_pts;
}
//frame.pts = adec.last_pts;
//adec.last_pts += ((u64)frame.data->nb_samples) * 90000 / 48000; // ???
frame.auAddr = task.au.addr;
frame.auSize = task.au.size;
frame.userdata = task.au.userdata;
frame.size = frame.data->nb_samples * frame.data->channels * sizeof(float);
if (frame.data->format != AV_SAMPLE_FMT_FLTP)
{
cellAdec->Error("adecDecodeaAu: unsupported frame format(%d)", frame.data->format);
Emu.Pause();
break; break;
}*/
last_frame = av_read_frame(adec.fmt, &au) < 0;
if (last_frame)
{
//break;
av_free(au.data);
au.data = NULL;
au.size = 0;
} }
if (frame.data->channels != 2)
struct AdecFrameHolder : AdecFrame
{ {
AdecFrameHolder() cellAdec->Error("adecDecodeAu: unsupported channel count (%d)", frame.data->channels);
{
data = av_frame_alloc();
}
~AdecFrameHolder()
{
if (data)
{
av_frame_unref(data);
av_frame_free(&data);
}
}
} frame;
if (!frame.data)
{
LOG_ERROR(HLE, "adecDecodeAu: av_frame_alloc() failed");
Emu.Pause(); Emu.Pause();
break; break;
} }
int got_frame = 0; //LOG_NOTICE(HLE, "got audio frame (pts=0x%llx, nb_samples=%d, ch=%d, sample_rate=%d, nbps=%d)",
//frame.pts, frame.data->nb_samples, frame.data->channels, frame.data->sample_rate,
//av_get_bytes_per_sample((AVSampleFormat)frame.data->format));
int decode = avcodec_decode_audio4(adec.ctx, frame.data, &got_frame, &au); adec.frames.Push(frame);
frame.data = nullptr; // to prevent destruction
if (decode <= 0) /*Callback cb;
{ cb.SetAddr(adec.cbFunc);
if (!last_frame && decode < 0) cb.Handle(adec.id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, adec.cbArg);
{ cb.Branch(false);*/
LOG_ERROR(HLE, "adecDecodeAu: AU decoding error(0x%x)", decode); adec.adecCb->ExecAsCallback(adec.cbFunc, false, adec.id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, adec.cbArg);
}
if (!got_frame && adec.reader.size == 0) break;
}
if (got_frame)
{
u64 ts = av_frame_get_best_effort_timestamp(frame.data);
if (ts != AV_NOPTS_VALUE)
{
frame.pts = ts/* - adec.first_pts*/;
adec.last_pts = frame.pts;
}
else
{
adec.last_pts += ((u64)frame.data->nb_samples) * 90000 / 48000;
frame.pts = adec.last_pts;
}
//frame.pts = adec.last_pts;
//adec.last_pts += ((u64)frame.data->nb_samples) * 90000 / 48000; // ???
frame.auAddr = task.au.addr;
frame.auSize = task.au.size;
frame.userdata = task.au.userdata;
frame.size = frame.data->nb_samples * frame.data->channels * sizeof(float);
if (frame.data->format != AV_SAMPLE_FMT_FLTP)
{
LOG_ERROR(HLE, "adecDecodeaAu: unsupported frame format(%d)", frame.data->format);
Emu.Pause();
break;
}
if (frame.data->channels != 2)
{
LOG_ERROR(HLE, "adecDecodeAu: unsupported channel count (%d)", frame.data->channels);
Emu.Pause();
break;
}
//LOG_NOTICE(HLE, "got audio frame (pts=0x%llx, nb_samples=%d, ch=%d, sample_rate=%d, nbps=%d)",
//frame.pts, frame.data->nb_samples, frame.data->channels, frame.data->sample_rate,
//av_get_bytes_per_sample((AVSampleFormat)frame.data->format));
adec.frames.Push(frame);
frame.data = nullptr; // to prevent destruction
/*Callback cb;
cb.SetAddr(adec.cbFunc);
cb.Handle(adec.id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, adec.cbArg);
cb.Branch(false);*/
adec.adecCb->ExecAsCallback(adec.cbFunc, false, adec.id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, adec.cbArg);
}
} }
/*Callback cb;
cb.SetAddr(adec.cbFunc);
cb.Handle(adec.id, CELL_ADEC_MSG_TYPE_AUDONE, task.au.auInfo_addr, adec.cbArg);
cb.Branch(false);*/
adec.adecCb->ExecAsCallback(adec.cbFunc, false, adec.id, CELL_ADEC_MSG_TYPE_AUDONE, task.au.auInfo_addr, adec.cbArg);
} }
break;
/*Callback cb;
cb.SetAddr(adec.cbFunc);
cb.Handle(adec.id, CELL_ADEC_MSG_TYPE_AUDONE, task.au.auInfo_addr, adec.cbArg);
cb.Branch(false);*/
adec.adecCb->ExecAsCallback(adec.cbFunc, false, adec.id, CELL_ADEC_MSG_TYPE_AUDONE, task.au.auInfo_addr, adec.cbArg);
}
break;
case adecClose: case adecClose:
{ {
adec.is_finished = true; adec.is_finished = true;
LOG_NOTICE(HLE, "Audio Decoder thread ended"); cellAdec->Notice("Audio Decoder thread ended");
return; return;
} }
default: default:
LOG_ERROR(HLE, "Audio Decoder thread error: unknown task(%d)", task.type); cellAdec->Error("Audio Decoder thread error: unknown task(%d)", task.type);
} }
} }
adec.is_finished = true; adec.is_finished = true;
LOG_WARNING(HLE, "Audio Decoder thread aborted"); cellAdec->Warning("Audio Decoder thread aborted");
}); });
t.detach(); t.detach();
@ -512,8 +574,8 @@ bool adecCheckType(AudioCodecType type)
{ {
switch (type) switch (type)
{ {
case CELL_ADEC_TYPE_ATRACX: LOG_NOTICE(HLE, "adecCheckType: ATRAC3plus"); break; case CELL_ADEC_TYPE_ATRACX: cellAdec->Notice("adecCheckType: ATRAC3plus"); break;
case CELL_ADEC_TYPE_ATRACX_2CH: LOG_NOTICE(HLE, "adecCheckType: ATRAC3plus 2ch"); break; case CELL_ADEC_TYPE_ATRACX_2CH: cellAdec->Notice("adecCheckType: ATRAC3plus 2ch"); break;
case CELL_ADEC_TYPE_ATRACX_6CH: case CELL_ADEC_TYPE_ATRACX_6CH:
case CELL_ADEC_TYPE_ATRACX_8CH: case CELL_ADEC_TYPE_ATRACX_8CH:
@ -588,7 +650,7 @@ int cellAdecClose(u32 handle)
{ {
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
LOG_WARNING(HLE, "cellAdecClose(%d) aborted", handle); cellAdec->Warning("cellAdecClose(%d) aborted", handle);
break; break;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1));
@ -752,15 +814,15 @@ int cellAdecGetPcmItem(u32 handle, mem32_t pcmItem_ptr)
void cellAdec_init() void cellAdec_init()
{ {
cellAdec->AddFunc(0x7e4a4a49, cellAdecQueryAttr); REG_FUNC(cellAdec, cellAdecQueryAttr);
cellAdec->AddFunc(0xd00a6988, cellAdecOpen); REG_FUNC(cellAdec, cellAdecOpen);
cellAdec->AddFunc(0x8b5551a4, cellAdecOpenEx); REG_FUNC(cellAdec, cellAdecOpenEx);
cellAdec->AddFunc(0x847d2380, cellAdecClose); REG_FUNC(cellAdec, cellAdecClose);
cellAdec->AddFunc(0x487b613e, cellAdecStartSeq); REG_FUNC(cellAdec, cellAdecStartSeq);
cellAdec->AddFunc(0xe2ea549b, cellAdecEndSeq); REG_FUNC(cellAdec, cellAdecEndSeq);
cellAdec->AddFunc(0x1529e506, cellAdecDecodeAu); REG_FUNC(cellAdec, cellAdecDecodeAu);
cellAdec->AddFunc(0x97ff2af1, cellAdecGetPcm); REG_FUNC(cellAdec, cellAdecGetPcm);
cellAdec->AddFunc(0xbd75f78b, cellAdecGetPcmItem); REG_FUNC(cellAdec, cellAdecGetPcmItem);
av_register_all(); av_register_all();
avcodec_register_all(); avcodec_register_all();

View file

@ -1117,67 +1117,7 @@ public:
CPUThread* adecCb; CPUThread* adecCb;
AudioDecoder(AudioCodecType type, u32 addr, u32 size, u32 func, u32 arg) AudioDecoder(AudioCodecType type, u32 addr, u32 size, u32 func, u32 arg);
: type(type)
, memAddr(addr)
, memSize(size)
, memBias(0)
, cbFunc(func)
, cbArg(arg)
, adecCb(nullptr)
, is_running(false)
, is_finished(false)
, just_started(false)
, just_finished(false)
, ctx(nullptr)
, fmt(nullptr)
{
AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_ATRAC3P);
if (!codec)
{
LOG_ERROR(HLE, "AudioDecoder(): avcodec_find_decoder(ATRAC3P) failed");
Emu.Pause();
return;
}
fmt = avformat_alloc_context();
if (!fmt)
{
LOG_ERROR(HLE, "AudioDecoder(): avformat_alloc_context failed");
Emu.Pause();
return;
}
io_buf = (u8*)av_malloc(4096);
fmt->pb = avio_alloc_context(io_buf, 4096, 0, this, adecRead, NULL, NULL);
if (!fmt->pb)
{
LOG_ERROR(HLE, "AudioDecoder(): avio_alloc_context failed");
Emu.Pause();
return;
}
}
~AudioDecoder() ~AudioDecoder();
{
// TODO: check finalization
if (ctx)
{
for (u32 i = frames.GetCount() - 1; ~i; i--)
{
AdecFrame& af = frames.Peek(i);
av_frame_unref(af.data);
av_frame_free(&af.data);
}
avcodec_close(ctx);
avformat_close_input(&fmt);
}
if (fmt)
{
if (io_buf)
{
av_free(io_buf);
}
if (fmt->pb) av_free(fmt->pb);
avformat_free_context(fmt);
}
}
}; };

View file

@ -1,8 +1,6 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/SysCalls.h"
Module *cellAtrac = nullptr; Module *cellAtrac = nullptr;

View file

@ -1,14 +1,15 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/SysCalls.h"
#include "rpcs3/Ini.h"
#include "Utilities/SQueue.h" #include "Utilities/SQueue.h"
#include "Emu/Event.h" #include "Emu/Event.h"
#include "Emu/Audio/cellAudio.h" #include "Emu/SysCalls/lv2/sys_time.h"
#include "Emu/Audio/AudioManager.h" //#include "Emu/Audio/AudioManager.h"
#include "Emu/Audio/AudioDumper.h" #include "Emu/Audio/AudioDumper.h"
#include "Emu/Audio/cellAudio.h"
//void cellAudio_init(); //void cellAudio_init();
//Module cellAudio(0x0011, cellAudio_init); //Module cellAudio(0x0011, cellAudio_init);
@ -51,11 +52,11 @@ int cellAudioInit()
if (do_dump && !m_dump.Init()) if (do_dump && !m_dump.Init())
{ {
LOG_ERROR(HLE, "cellAudioInit(): AudioDumper::Init() failed"); cellAudio->Error("cellAudioInit(): AudioDumper::Init() failed");
return; return;
} }
LOG_NOTICE(HLE, "Audio thread started"); cellAudio->Notice("Audio thread started");
if (Ini.AudioDumpToFile.GetValue()) if (Ini.AudioDumpToFile.GetValue())
m_dump.WriteHeader(); m_dump.WriteHeader();
@ -136,7 +137,7 @@ int cellAudioInit()
{ {
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
LOG_WARNING(HLE, "Audio thread aborted"); cellAudio->Warning("Audio thread aborted");
goto abort; goto abort;
} }
@ -358,7 +359,7 @@ int cellAudioInit()
} }
} }
const u64 stamp1 = get_system_time(); //const u64 stamp1 = get_system_time();
if (first_mix) if (first_mix)
{ {
@ -380,7 +381,7 @@ int cellAudioInit()
oal_buffer_offset = 0; oal_buffer_offset = 0;
} }
const u64 stamp2 = get_system_time(); //const u64 stamp2 = get_system_time();
// send aftermix event (normal audio event) // send aftermix event (normal audio event)
{ {
@ -408,7 +409,7 @@ int cellAudioInit()
Emu.GetEventManager().SendEvent(keys[i], 0x10103000e010e07, 0, 0, 0); Emu.GetEventManager().SendEvent(keys[i], 0x10103000e010e07, 0, 0, 0);
} }
const u64 stamp3 = get_system_time(); //const u64 stamp3 = get_system_time();
if (do_dump && !first_mix) if (do_dump && !first_mix)
{ {
@ -416,7 +417,7 @@ int cellAudioInit()
{ {
if (m_dump.WriteData(&buf8ch, sizeof(buf8ch)) != sizeof(buf8ch)) // write file data if (m_dump.WriteData(&buf8ch, sizeof(buf8ch)) != sizeof(buf8ch)) // write file data
{ {
LOG_ERROR(HLE, "cellAudioInit(): AudioDumper::WriteData() failed"); cellAudio->Error("cellAudioInit(): AudioDumper::WriteData() failed");
goto abort; goto abort;
} }
} }
@ -424,13 +425,13 @@ int cellAudioInit()
{ {
if (m_dump.WriteData(&buf2ch, sizeof(buf2ch)) != sizeof(buf2ch)) // write file data if (m_dump.WriteData(&buf2ch, sizeof(buf2ch)) != sizeof(buf2ch)) // write file data
{ {
LOG_ERROR(HLE, "cellAudioInit(): AudioDumper::WriteData() failed"); cellAudio->Error("cellAudioInit(): AudioDumper::WriteData() failed");
goto abort; goto abort;
} }
} }
else else
{ {
LOG_ERROR(HLE, "cellAudioInit(): unknown AudioDumper::GetCh() value (%d)", m_dump.GetCh()); cellAudio->Error("cellAudioInit(): unknown AudioDumper::GetCh() value (%d)", m_dump.GetCh());
goto abort; goto abort;
} }
} }
@ -438,7 +439,7 @@ int cellAudioInit()
//LOG_NOTICE(HLE, "Audio perf: start=%d (access=%d, AddData=%d, events=%d, dump=%d)", //LOG_NOTICE(HLE, "Audio perf: start=%d (access=%d, AddData=%d, events=%d, dump=%d)",
//stamp0 - m_config.start_time, stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2, get_system_time() - stamp3); //stamp0 - m_config.start_time, stamp1 - stamp0, stamp2 - stamp1, stamp3 - stamp2, get_system_time() - stamp3);
} }
LOG_NOTICE(HLE, "Audio thread ended"); cellAudio->Notice("Audio thread ended");
abort: abort:
queue.Push(nullptr); queue.Push(nullptr);
queue_float.Push(nullptr); queue_float.Push(nullptr);
@ -470,7 +471,7 @@ abort:
{ {
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
LOG_WARNING(HLE, "cellAudioInit() aborted"); cellAudio->Warning("cellAudioInit() aborted");
return CELL_OK; return CELL_OK;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1));
@ -495,7 +496,7 @@ int cellAudioQuit()
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1));
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
LOG_WARNING(HLE, "cellAudioQuit(): aborted"); cellAudio->Warning("cellAudioQuit(): aborted");
return CELL_OK; return CELL_OK;
} }
} }

View file

@ -1,7 +1,5 @@
#include "stdafx.h" #include "stdafx.h"
#if 0 #if 0
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/SysCalls/SC_FUNC.h"
void cellBgdl_init(); void cellBgdl_init();
Module cellBgdl(0x003f, cellBgdl_init); Module cellBgdl(0x003f, cellBgdl_init);

View file

@ -1,7 +1,5 @@
#include "stdafx.h" #include "stdafx.h"
#if 0 #if 0
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/SysCalls/SC_FUNC.h"
void cellCamera_init(); void cellCamera_init();
Module cellCamera(0x0023, cellCamera_init); Module cellCamera(0x0023, cellCamera_init);

View file

@ -1,7 +1,5 @@
#include "stdafx.h" #include "stdafx.h"
#if 0 #if 0
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/SysCalls/SC_FUNC.h"
void cellCelp8Enc_init(); void cellCelp8Enc_init();
Module cellCelp8Enc(0x0048, cellCelp8Enc_init); Module cellCelp8Enc(0x0048, cellCelp8Enc_init);

View file

@ -1,8 +1,5 @@
#include "stdafx.h" #include "stdafx.h"
#if 0 #if 0
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/SysCalls/SC_FUNC.h"
void cellCelpEnc_init(); void cellCelpEnc_init();
Module cellCelpEnc(0xf00a, cellCelpEnc_init); Module cellCelpEnc(0xf00a, cellCelpEnc_init);

View file

@ -1,10 +1,8 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h" #include "Emu/System.h"
#include "Emu/Cell/PPUThread.h"
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/SysCalls.h"
#include "cellPamf.h" #include "cellPamf.h"
#include "cellDmux.h" #include "cellDmux.h"
@ -12,6 +10,300 @@
//Module cellDmux(0x0007, cellDmux_init); //Module cellDmux(0x0007, cellDmux_init);
Module *cellDmux = nullptr; Module *cellDmux = nullptr;
PesHeader::PesHeader(DemuxerStream& stream)
: pts(0xffffffffffffffffull)
, dts(0xffffffffffffffffull)
, size(0)
, new_au(false)
{
u16 header;
stream.get(header);
stream.get(size);
if (size)
{
u8 empty = 0;
u8 v;
while (true)
{
stream.get(v);
if (v != 0xFF) break; // skip padding bytes
empty++;
if (empty == size) return;
};
if ((v & 0xF0) == 0x20 && (size - empty) >= 5) // pts only
{
new_au = true;
pts = stream.get_ts(v);
stream.skip(size - empty - 5);
}
else
{
new_au = true;
if ((v & 0xF0) != 0x30 || (size - empty) < 10)
{
cellDmux->Error("PesHeader(): pts not found");
Emu.Pause();
}
pts = stream.get_ts(v);
stream.get(v);
if ((v & 0xF0) != 0x10)
{
cellDmux->Error("PesHeader(): dts not found");
Emu.Pause();
}
dts = stream.get_ts(v);
stream.skip(size - empty - 10);
}
}
}
bool ElementaryStream::is_full()
{
if (released < put_count)
{
u32 first = entries.Peek();
if (first >= put)
{
return (first - put) < GetMaxAU();
}
else
{
// probably, always false
return (put + GetMaxAU()) > (memAddr + memSize);
}
}
else
{
return false;
}
}
const u32 ElementaryStream::GetMaxAU() const
{
return (fidMajor == 0xbd) ? 4096 : 640 * 1024 + 128; // TODO
}
u32 ElementaryStream::freespace()
{
if (size > GetMaxAU())
{
cellDmux->Error("es::freespace(): last_size too big (size=0x%x, max_au=0x%x)", size, GetMaxAU());
Emu.Pause();
return 0;
}
return GetMaxAU() - size;
}
bool ElementaryStream::hasunseen()
{
std::lock_guard<std::mutex> lock(m_mutex);
return peek_count < put_count;
}
bool ElementaryStream::hasdata()
{
std::lock_guard<std::mutex> lock(m_mutex);
return size != 0;
}
bool ElementaryStream::isfull()
{
std::lock_guard<std::mutex> lock(m_mutex);
return is_full();
}
void ElementaryStream::finish(DemuxerStream& stream) // not multithread-safe
{
u32 addr;
{
std::lock_guard<std::mutex> lock(m_mutex);
//if (fidMajor != 0xbd) LOG_NOTICE(HLE, ">>> es::finish(): peek=0x%x, first=0x%x, put=0x%x, size=0x%x", peek, first, put, size);
addr = put;
/*if (!first)
{
first = put;
}
if (!peek)
{
peek = put;
}*/
mem_ptr_t<CellDmuxAuInfo> info(put);
//if (fidMajor != 0xbd) LOG_WARNING(HLE, "es::finish(): (%s) size = 0x%x, info_addr=0x%x, pts = 0x%x",
//wxString(fidMajor == 0xbd ? "ATRAC3P Audio" : "Video AVC").wx_str(),
//(u32)info->auSize, put, (u32)info->ptsLower);
u32 new_addr = a128(put + 128 + size);
put = ((new_addr + GetMaxAU()) > (memAddr + memSize))
? memAddr : new_addr;
size = 0;
put_count++;
//if (fidMajor != 0xbd) LOG_NOTICE(HLE, "<<< es::finish(): peek=0x%x, first=0x%x, put=0x%x, size=0x%x", peek, first, put, size);
}
if (!entries.Push(addr))
{
cellDmux->Error("es::finish() aborted (no space)");
}
}
void ElementaryStream::push(DemuxerStream& stream, u32 sz, PesHeader& pes)
{
std::lock_guard<std::mutex> lock(m_mutex);
if (is_full())
{
cellDmux->Error("es::push(): buffer is full");
Emu.Pause();
return;
}
u32 data_addr = put + 128 + size;
size += sz;
memcpy(Memory + data_addr, Memory + stream.addr, sz);
stream.skip(sz);
mem_ptr_t<CellDmuxAuInfoEx> info(put);
info->auAddr = put + 128;
info->auSize = size;
if (pes.new_au)
{
info->dts.lower = (u32)pes.dts;
info->dts.upper = (u32)(pes.dts >> 32);
info->pts.lower = (u32)pes.pts;
info->pts.upper = (u32)(pes.pts >> 32);
info->isRap = false; // TODO: set valid value
info->reserved = 0;
info->userData = stream.userdata;
}
mem_ptr_t<CellDmuxPamfAuSpecificInfoAvc> tail(put + sizeof(CellDmuxAuInfoEx));
tail->reserved1 = 0;
mem_ptr_t<CellDmuxAuInfo> inf(put + 64);
inf->auAddr = put + 128;
inf->auSize = size;
if (pes.new_au)
{
inf->dtsLower = (u32)pes.dts;
inf->dtsUpper = (u32)(pes.dts >> 32);
inf->ptsLower = (u32)pes.pts;
inf->ptsUpper = (u32)(pes.pts >> 32);
inf->auMaxSize = 0; // ?????
inf->userData = stream.userdata;
}
}
bool ElementaryStream::release()
{
std::lock_guard<std::mutex> lock(m_mutex);
//if (fidMajor != 0xbd) LOG_NOTICE(HLE, ">>> es::release(): peek=0x%x, first=0x%x, put=0x%x, size=0x%x", peek, first, put, size);
if (released >= put_count)
{
cellDmux->Error("es::release(): buffer is empty");
return false;
}
u32 addr = entries.Peek();
mem_ptr_t<CellDmuxAuInfo> info(addr);
//if (fidMajor != 0xbd) LOG_WARNING(HLE, "es::release(): (%s) size = 0x%x, info = 0x%x, pts = 0x%x",
//wxString(fidMajor == 0xbd ? "ATRAC3P Audio" : "Video AVC").wx_str(), (u32)info->auSize, first, (u32)info->ptsLower);
if (released >= peek_count)
{
cellDmux->Error("es::release(): buffer has not been seen yet");
return false;
}
/*u32 new_addr = a128(info.GetAddr() + 128 + info->auSize);
if (new_addr == put)
{
first = 0;
}
else if ((new_addr + GetMaxAU()) > (memAddr + memSize))
{
first = memAddr;
}
else
{
first = new_addr;
}*/
released++;
if (!entries.Pop(addr))
{
cellDmux->Error("es::release(): entries.Pop() aborted (no entries found)");
return false;
}
//if (fidMajor != 0xbd) LOG_NOTICE(HLE, "<<< es::release(): peek=0x%x, first=0x%x, put=0x%x, size=0x%x", peek, first, put, size);
return true;
}
bool ElementaryStream::peek(u32& out_data, bool no_ex, u32& out_spec, bool update_index)
{
std::lock_guard<std::mutex> lock(m_mutex);
//if (fidMajor != 0xbd) LOG_NOTICE(HLE, ">>> es::peek(%sAu%s): peek=0x%x, first=0x%x, put=0x%x, size=0x%x", wxString(update_index ? "Get" : "Peek").wx_str(),
//wxString(no_ex ? "" : "Ex").wx_str(), peek, first, put, size);
if (peek_count >= put_count) return false;
if (peek_count < released)
{
cellDmux->Error("es::peek(): sequence error: peek_count < released (peek_count=%d, released=%d)", peek_count, released);
Emu.Pause();
return false;
}
u32 addr = entries.Peek(peek_count - released);
mem_ptr_t<CellDmuxAuInfo> info(addr);
//if (fidMajor != 0xbd) LOG_WARNING(HLE, "es::peek(%sAu(Ex)): (%s) size = 0x%x, info = 0x%x, pts = 0x%x",
//wxString(update_index ? "Get" : "Peek").wx_str(),
//wxString(fidMajor == 0xbd ? "ATRAC3P Audio" : "Video AVC").wx_str(), (u32)info->auSize, peek, (u32)info->ptsLower);
out_data = addr;
out_spec = out_data + sizeof(CellDmuxAuInfoEx);
if (no_ex) out_data += 64;
if (update_index)
{
/*u32 new_addr = a128(peek + 128 + info->auSize);
if (new_addr == put)
{
peek = 0;
}
else if ((new_addr + GetMaxAU()) > (memAddr + memSize))
{
peek = memAddr;
}
else
{
peek = new_addr;
}*/
peek_count++;
}
//if (fidMajor != 0xbd) LOG_NOTICE(HLE, "<<< es::peek(%sAu%s): peek=0x%x, first=0x%x, put=0x%x, size=0x%x", wxString(update_index ? "Get" : "Peek").wx_str(),
//wxString(no_ex ? "" : "Ex").wx_str(), peek, first, put, size);
return true;
}
void ElementaryStream::reset()
{
std::lock_guard<std::mutex> lock(m_mutex);
//first = 0;
//peek = 0;
put = memAddr;
size = 0;
entries.Clear();
put_count = 0;
released = 0;
peek_count = 0;
}
void dmuxQueryAttr(u32 info_addr /* may be 0 */, mem_ptr_t<CellDmuxAttr> attr) void dmuxQueryAttr(u32 info_addr /* may be 0 */, mem_ptr_t<CellDmuxAttr> attr)
{ {
attr->demuxerVerLower = 0x280000; // TODO: check values attr->demuxerVerLower = 0x280000; // TODO: check values
@ -45,7 +337,7 @@ u32 dmuxOpen(Demuxer* data)
thread t("Demuxer[" + std::to_string(dmux_id) + "] Thread", [&]() thread t("Demuxer[" + std::to_string(dmux_id) + "] Thread", [&]()
{ {
LOG_NOTICE(HLE, "Demuxer thread started (mem=0x%x, size=0x%x, cb=0x%x, arg=0x%x)", dmux.memAddr, dmux.memSize, dmux.cbFunc, dmux.cbArg); cellDmux->Notice("Demuxer thread started (mem=0x%x, size=0x%x, cb=0x%x, arg=0x%x)", dmux.memAddr, dmux.memSize, dmux.cbFunc, dmux.cbArg);
DemuxerTask task; DemuxerTask task;
DemuxerStream stream; DemuxerStream stream;
@ -132,7 +424,7 @@ u32 dmuxOpen(Demuxer* data)
if (!pes.new_au) // temporarily if (!pes.new_au) // temporarily
{ {
LOG_ERROR(HLE, "No pts info found"); cellDmux->Error("No pts info found");
} }
// read additional header: // read additional header:
@ -262,7 +554,7 @@ u32 dmuxOpen(Demuxer* data)
case 0x1dc: case 0x1dd: case 0x1de: case 0x1df: case 0x1dc: case 0x1dd: case 0x1de: case 0x1df:
{ {
// unknown // unknown
LOG_WARNING(HLE, "Unknown MPEG stream found"); cellDmux->Warning("Unknown MPEG stream found");
stream.skip(4); stream.skip(4);
stream.get(len); stream.get(len);
stream.skip(len); stream.skip(len);
@ -271,7 +563,7 @@ u32 dmuxOpen(Demuxer* data)
case USER_DATA_START_CODE: case USER_DATA_START_CODE:
{ {
LOG_ERROR(HLE, "USER_DATA_START_CODE found"); cellDmux->Error("USER_DATA_START_CODE found");
return; return;
} }
@ -298,7 +590,7 @@ u32 dmuxOpen(Demuxer* data)
{ {
if (task.stream.discontinuity) if (task.stream.discontinuity)
{ {
LOG_WARNING(HLE, "dmuxSetStream (beginning)"); cellDmux->Warning("dmuxSetStream (beginning)");
for (u32 i = 0; i < 192; i++) for (u32 i = 0; i < 192; i++)
{ {
if (esALL[i]) if (esALL[i])
@ -312,7 +604,7 @@ u32 dmuxOpen(Demuxer* data)
if (updates_count != updates_signaled) if (updates_count != updates_signaled)
{ {
LOG_ERROR(HLE, "dmuxSetStream: stream update inconsistency (input=%d, signaled=%d)", updates_count, updates_signaled); cellDmux->Error("dmuxSetStream: stream update inconsistency (input=%d, signaled=%d)", updates_count, updates_signaled);
return; return;
} }
@ -351,7 +643,7 @@ u32 dmuxOpen(Demuxer* data)
case dmuxClose: case dmuxClose:
{ {
dmux.is_finished = true; dmux.is_finished = true;
LOG_NOTICE(HLE, "Demuxer thread ended"); cellDmux->Notice("Demuxer thread ended");
return; return;
} }
@ -375,7 +667,7 @@ u32 dmuxOpen(Demuxer* data)
} }
else else
{ {
LOG_WARNING(HLE, "dmuxEnableEs: (TODO) unsupported filter (0x%x, 0x%x, 0x%x, 0x%x)", es.fidMajor, es.fidMinor, es.sup1, es.sup2); cellDmux->Warning("dmuxEnableEs: (TODO) unsupported filter (0x%x, 0x%x, 0x%x, 0x%x)", es.fidMajor, es.fidMinor, es.sup1, es.sup2);
} }
es.dmux = &dmux; es.dmux = &dmux;
} }
@ -386,7 +678,7 @@ u32 dmuxOpen(Demuxer* data)
ElementaryStream& es = *task.es.es_ptr; ElementaryStream& es = *task.es.es_ptr;
if (es.dmux != &dmux) if (es.dmux != &dmux)
{ {
LOG_WARNING(HLE, "dmuxDisableEs: invalid elementary stream"); cellDmux->Warning("dmuxDisableEs: invalid elementary stream");
break; break;
} }
for (u32 i = 0; i < 192; i++) for (u32 i = 0; i < 192; i++)
@ -444,11 +736,11 @@ u32 dmuxOpen(Demuxer* data)
break; break;
default: default:
LOG_ERROR(HLE, "Demuxer thread error: unknown task(%d)", task.type); cellDmux->Error("Demuxer thread error: unknown task(%d)", task.type);
return; return;
} }
} }
LOG_WARNING(HLE, "Demuxer thread aborted"); cellDmux->Warning("Demuxer thread aborted");
}); });
t.detach(); t.detach();
@ -552,7 +844,7 @@ int cellDmuxClose(u32 demuxerHandle)
{ {
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
LOG_WARNING(HLE, "cellDmuxClose(%d) aborted", demuxerHandle); cellDmux->Warning("cellDmuxClose(%d) aborted", demuxerHandle);
return CELL_OK; return CELL_OK;
} }
@ -579,7 +871,7 @@ int cellDmuxSetStream(u32 demuxerHandle, const u32 streamAddress, u32 streamSize
{ {
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
LOG_WARNING(HLE, "cellDmuxSetStream(%d) aborted (waiting)", demuxerHandle); cellDmux->Warning("cellDmuxSetStream(%d) aborted (waiting)", demuxerHandle);
return CELL_OK; return CELL_OK;
} }
std::this_thread::sleep_for(std::chrono::milliseconds(1)); std::this_thread::sleep_for(std::chrono::milliseconds(1));
@ -598,12 +890,12 @@ int cellDmuxSetStream(u32 demuxerHandle, const u32 streamAddress, u32 streamSize
u32 addr; u32 addr;
if (!dmux->fbSetStream.Pop(addr)) if (!dmux->fbSetStream.Pop(addr))
{ {
LOG_WARNING(HLE, "cellDmuxSetStream(%d) aborted (fbSetStream.Pop())", demuxerHandle); cellDmux->Warning("cellDmuxSetStream(%d) aborted (fbSetStream.Pop())", demuxerHandle);
return CELL_OK; return CELL_OK;
} }
if (addr != info.addr) if (addr != info.addr)
{ {
LOG_ERROR(HLE, "cellDmuxSetStream(%d): wrong stream queued (right=0x%x, queued=0x%x)", demuxerHandle, info.addr, addr); cellDmux->Error("cellDmuxSetStream(%d): wrong stream queued (right=0x%x, queued=0x%x)", demuxerHandle, info.addr, addr);
Emu.Pause(); Emu.Pause();
} }
return CELL_OK; return CELL_OK;
@ -639,12 +931,12 @@ int cellDmuxResetStreamAndWaitDone(u32 demuxerHandle)
u32 addr; u32 addr;
if (!dmux->fbSetStream.Pop(addr)) if (!dmux->fbSetStream.Pop(addr))
{ {
LOG_WARNING(HLE, "cellDmuxResetStreamAndWaitDone(%d) aborted (fbSetStream.Pop())", demuxerHandle); cellDmux->Warning("cellDmuxResetStreamAndWaitDone(%d) aborted (fbSetStream.Pop())", demuxerHandle);
return CELL_OK; return CELL_OK;
} }
if (addr != 0) if (addr != 0)
{ {
LOG_ERROR(HLE, "cellDmuxResetStreamAndWaitDone(%d): wrong stream queued (0x%x)", demuxerHandle, addr); cellDmux->Error("cellDmuxResetStreamAndWaitDone(%d): wrong stream queued (0x%x)", demuxerHandle, addr);
Emu.Pause(); Emu.Pause();
} }
return CELL_OK; return CELL_OK;

View file

@ -362,53 +362,7 @@ struct PesHeader
u8 size; u8 size;
bool new_au; bool new_au;
PesHeader(DemuxerStream& stream) PesHeader(DemuxerStream& stream);
: pts(0xffffffffffffffff)
, dts(0xffffffffffffffff)
, size(0)
, new_au(false)
{
u16 header;
stream.get(header);
stream.get(size);
if (size)
{
u8 empty = 0;
u8 v;
while (true)
{
stream.get(v);
if (v != 0xFF) break; // skip padding bytes
empty++;
if (empty == size) return;
};
if ((v & 0xF0) == 0x20 && (size - empty) >= 5) // pts only
{
new_au = true;
pts = stream.get_ts(v);
stream.skip(size - empty - 5);
}
else
{
new_au = true;
if ((v & 0xF0) != 0x30 || (size - empty) < 10)
{
LOG_ERROR(HLE, "PesHeader(): pts not found");
Emu.Pause();
}
pts = stream.get_ts(v);
stream.get(v);
if ((v & 0xF0) != 0x10)
{
LOG_ERROR(HLE, "PesHeader(): dts not found");
Emu.Pause();
}
dts = stream.get_ts(v);
stream.skip(size - empty - 10);
}
}
}
}; };
class ElementaryStream; class ElementaryStream;
@ -493,26 +447,7 @@ class ElementaryStream
//u32 first; // AU that will be released //u32 first; // AU that will be released
//u32 peek; // AU that will be obtained by GetAu(Ex)/PeekAu(Ex) //u32 peek; // AU that will be obtained by GetAu(Ex)/PeekAu(Ex)
bool is_full() bool is_full();
{
if (released < put_count)
{
u32 first = entries.Peek();
if (first >= put)
{
return (first - put) < GetMaxAU();
}
else
{
// probably, always false
return (put + GetMaxAU()) > (memAddr + memSize);
}
}
else
{
return false;
}
}
public: public:
Demuxer* dmux; Demuxer* dmux;
@ -548,228 +483,23 @@ public:
{ {
} }
const u32 GetMaxAU() const const u32 GetMaxAU() const;
{
return (fidMajor == 0xbd) ? 4096 : 640 * 1024 + 128; // TODO
}
u32 freespace() u32 freespace();
{
if (size > GetMaxAU())
{
LOG_ERROR(HLE, "es::freespace(): last_size too big (size=0x%x, max_au=0x%x)", size, GetMaxAU());
Emu.Pause();
return 0;
}
return GetMaxAU() - size;
}
bool hasunseen() bool hasunseen();
{
std::lock_guard<std::mutex> lock(m_mutex);
return peek_count < put_count;
}
bool hasdata() bool hasdata();
{
std::lock_guard<std::mutex> lock(m_mutex);
return size;
}
bool isfull() bool isfull();
{
std::lock_guard<std::mutex> lock(m_mutex);
return is_full();
}
void finish(DemuxerStream& stream) // not multithread-safe void finish(DemuxerStream& stream);
{
u32 addr;
{
std::lock_guard<std::mutex> lock(m_mutex);
//if (fidMajor != 0xbd) LOG_NOTICE(HLE, ">>> es::finish(): peek=0x%x, first=0x%x, put=0x%x, size=0x%x", peek, first, put, size);
addr = put; void push(DemuxerStream& stream, u32 sz, PesHeader& pes);
/*if (!first)
{
first = put;
}
if (!peek)
{
peek = put;
}*/
mem_ptr_t<CellDmuxAuInfo> info(put); bool release();
//if (fidMajor != 0xbd) LOG_WARNING(HLE, "es::finish(): (%s) size = 0x%x, info_addr=0x%x, pts = 0x%x",
//wxString(fidMajor == 0xbd ? "ATRAC3P Audio" : "Video AVC").wx_str(),
//(u32)info->auSize, put, (u32)info->ptsLower);
u32 new_addr = a128(put + 128 + size); bool peek(u32& out_data, bool no_ex, u32& out_spec, bool update_index);
put = ((new_addr + GetMaxAU()) > (memAddr + memSize))
? memAddr : new_addr;
size = 0; void reset();
put_count++;
//if (fidMajor != 0xbd) LOG_NOTICE(HLE, "<<< es::finish(): peek=0x%x, first=0x%x, put=0x%x, size=0x%x", peek, first, put, size);
}
if (!entries.Push(addr))
{
LOG_ERROR(HLE, "es::finish() aborted (no space)");
}
}
void push(DemuxerStream& stream, u32 sz, PesHeader& pes)
{
std::lock_guard<std::mutex> lock(m_mutex);
if (is_full())
{
LOG_ERROR(HLE, "es::push(): buffer is full");
Emu.Pause();
return;
}
u32 data_addr = put + 128 + size;
size += sz;
memcpy(Memory + data_addr, Memory + stream.addr, sz);
stream.skip(sz);
mem_ptr_t<CellDmuxAuInfoEx> info(put);
info->auAddr = put + 128;
info->auSize = size;
if (pes.new_au)
{
info->dts.lower = (u32)pes.dts;
info->dts.upper = (u32)(pes.dts >> 32);
info->pts.lower = (u32)pes.pts;
info->pts.upper = (u32)(pes.pts >> 32);
info->isRap = false; // TODO: set valid value
info->reserved = 0;
info->userData = stream.userdata;
}
mem_ptr_t<CellDmuxPamfAuSpecificInfoAvc> tail(put + sizeof(CellDmuxAuInfoEx));
tail->reserved1 = 0;
mem_ptr_t<CellDmuxAuInfo> inf(put + 64);
inf->auAddr = put + 128;
inf->auSize = size;
if (pes.new_au)
{
inf->dtsLower = (u32)pes.dts;
inf->dtsUpper = (u32)(pes.dts >> 32);
inf->ptsLower = (u32)pes.pts;
inf->ptsUpper = (u32)(pes.pts >> 32);
inf->auMaxSize = 0; // ?????
inf->userData = stream.userdata;
}
}
bool release()
{
std::lock_guard<std::mutex> lock(m_mutex);
//if (fidMajor != 0xbd) LOG_NOTICE(HLE, ">>> es::release(): peek=0x%x, first=0x%x, put=0x%x, size=0x%x", peek, first, put, size);
if (released >= put_count)
{
LOG_ERROR(HLE, "es::release(): buffer is empty");
return false;
}
u32 addr = entries.Peek();
mem_ptr_t<CellDmuxAuInfo> info(addr);
//if (fidMajor != 0xbd) LOG_WARNING(HLE, "es::release(): (%s) size = 0x%x, info = 0x%x, pts = 0x%x",
//wxString(fidMajor == 0xbd ? "ATRAC3P Audio" : "Video AVC").wx_str(), (u32)info->auSize, first, (u32)info->ptsLower);
if (released >= peek_count)
{
LOG_ERROR(HLE, "es::release(): buffer has not been seen yet");
return false;
}
/*u32 new_addr = a128(info.GetAddr() + 128 + info->auSize);
if (new_addr == put)
{
first = 0;
}
else if ((new_addr + GetMaxAU()) > (memAddr + memSize))
{
first = memAddr;
}
else
{
first = new_addr;
}*/
released++;
if (!entries.Pop(addr))
{
LOG_ERROR(HLE, "es::release(): entries.Pop() aborted (no entries found)");
return false;
}
//if (fidMajor != 0xbd) LOG_NOTICE(HLE, "<<< es::release(): peek=0x%x, first=0x%x, put=0x%x, size=0x%x", peek, first, put, size);
return true;
}
bool peek(u32& out_data, bool no_ex, u32& out_spec, bool update_index)
{
std::lock_guard<std::mutex> lock(m_mutex);
//if (fidMajor != 0xbd) LOG_NOTICE(HLE, ">>> es::peek(%sAu%s): peek=0x%x, first=0x%x, put=0x%x, size=0x%x", wxString(update_index ? "Get" : "Peek").wx_str(),
//wxString(no_ex ? "" : "Ex").wx_str(), peek, first, put, size);
if (peek_count >= put_count) return false;
if (peek_count < released)
{
LOG_ERROR(HLE, "es::peek(): sequence error: peek_count < released (peek_count=%d, released=%d)", peek_count, released);
Emu.Pause();
return false;
}
u32 addr = entries.Peek(peek_count - released);
mem_ptr_t<CellDmuxAuInfo> info(addr);
//if (fidMajor != 0xbd) LOG_WARNING(HLE, "es::peek(%sAu(Ex)): (%s) size = 0x%x, info = 0x%x, pts = 0x%x",
//wxString(update_index ? "Get" : "Peek").wx_str(),
//wxString(fidMajor == 0xbd ? "ATRAC3P Audio" : "Video AVC").wx_str(), (u32)info->auSize, peek, (u32)info->ptsLower);
out_data = addr;
out_spec = out_data + sizeof(CellDmuxAuInfoEx);
if (no_ex) out_data += 64;
if (update_index)
{
/*u32 new_addr = a128(peek + 128 + info->auSize);
if (new_addr == put)
{
peek = 0;
}
else if ((new_addr + GetMaxAU()) > (memAddr + memSize))
{
peek = memAddr;
}
else
{
peek = new_addr;
}*/
peek_count++;
}
//if (fidMajor != 0xbd) LOG_NOTICE(HLE, "<<< es::peek(%sAu%s): peek=0x%x, first=0x%x, put=0x%x, size=0x%x", wxString(update_index ? "Get" : "Peek").wx_str(),
//wxString(no_ex ? "" : "Ex").wx_str(), peek, first, put, size);
return true;
}
void reset()
{
std::lock_guard<std::mutex> lock(m_mutex);
//first = 0;
//peek = 0;
put = memAddr;
size = 0;
entries.Clear();
put_count = 0;
released = 0;
peek_count = 0;
}
}; };

View file

@ -1,7 +1,5 @@
#include "stdafx.h" #include "stdafx.h"
#if 0 #if 0
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/SysCalls/SC_FUNC.h"
void cellFiber_init(); void cellFiber_init();
Module cellFiber(0x0043, cellFiber_init); Module cellFiber(0x0043, cellFiber_init);

View file

@ -1,13 +1,10 @@
#include "stdafx.h" #include "stdafx.h"
#include "Utilities/Log.h"
#include "Emu/Memory/Memory.h" #include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/Cell/PPUThread.h"
#include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/SysCalls.h"
#include "stblib/stb_truetype.h"
#include "Emu/FS/vfsFile.h" #include "Emu/FS/vfsFile.h"
#include "cellFont.h" #include "cellFont.h"
#include "stblib/stb_truetype.h"
//void cellFont_init(); //void cellFont_init();
//void cellFont_load(); //void cellFont_load();
@ -15,224 +12,6 @@
//Module cellFont(0x0019, cellFont_init, cellFont_load, cellFont_unload); //Module cellFont(0x0019, cellFont_init, cellFont_load, cellFont_unload);
Module *cellFont = nullptr; Module *cellFont = nullptr;
// Font Set Types
enum
{
CELL_FONT_TYPE_RODIN_SANS_SERIF_LATIN = 0x00000000,
CELL_FONT_TYPE_RODIN_SANS_SERIF_LIGHT_LATIN = 0x00000001,
CELL_FONT_TYPE_RODIN_SANS_SERIF_BOLD_LATIN = 0x00000002,
CELL_FONT_TYPE_RODIN_SANS_SERIF_LATIN2 = 0x00000018,
CELL_FONT_TYPE_RODIN_SANS_SERIF_LIGHT_LATIN2 = 0x00000019,
CELL_FONT_TYPE_RODIN_SANS_SERIF_BOLD_LATIN2 = 0x0000001a,
CELL_FONT_TYPE_MATISSE_SERIF_LATIN = 0x00000020,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_JAPANESE = 0x00000008,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_LIGHT_JAPANESE = 0x00000009,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_BOLD_JAPANESE = 0x0000000a,
CELL_FONT_TYPE_YD_GOTHIC_KOREAN = 0x0000000c,
CELL_FONT_TYPE_SEURAT_MARU_GOTHIC_LATIN = 0x00000040,
CELL_FONT_TYPE_SEURAT_MARU_GOTHIC_LATIN2 = 0x00000041,
CELL_FONT_TYPE_VAGR_SANS_SERIF_ROUND = 0x00000043,
CELL_FONT_TYPE_VAGR_SANS_SERIF_ROUND_LATIN2 = 0x00000044,
CELL_FONT_TYPE_SEURAT_MARU_GOTHIC_JAPANESE = 0x00000048,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_JP_SET = 0x00000100,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_LATIN_SET = 0x00000101,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_RODIN_SET = 0x00000104,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_RODIN2_SET = 0x00000204,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_YG_RODIN2_SET = 0x00000201,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_YG_DFHEI5_SET = 0x00000108,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_YG_DFHEI5_RODIN_SET = 0x00000109,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_YG_DFHEI5_RODIN2_SET = 0x00000209,
CELL_FONT_TYPE_DFHEI5_GOTHIC_YG_NEWRODIN_TCH_SET = 0x0000010a,
CELL_FONT_TYPE_DFHEI5_GOTHIC_YG_NEWRODIN_RODIN_TCH_SET = 0x0000010b,
CELL_FONT_TYPE_DFHEI5_GOTHIC_YG_NEWRODIN_RODIN2_TCH_SET = 0x0000020b,
CELL_FONT_TYPE_DFHEI5_GOTHIC_YG_NEWRODIN_SCH_SET = 0x0000010c,
CELL_FONT_TYPE_DFHEI5_GOTHIC_YG_NEWRODIN_RODIN_SCH_SET = 0x0000010d,
CELL_FONT_TYPE_DFHEI5_GOTHIC_YG_NEWRODIN_RODIN2_SCH_SET = 0x0000020d,
CELL_FONT_TYPE_SEURAT_MARU_GOTHIC_RSANS_SET = 0x00300104,
CELL_FONT_TYPE_SEURAT_CAPIE_MARU_GOTHIC_RSANS_SET = 0x00300105,
CELL_FONT_TYPE_SEURAT_CAPIE_MARU_GOTHIC_JP_SET = 0x00300107,
CELL_FONT_TYPE_SEURAT_MARU_GOTHIC_YG_DFHEI5_RSANS_SET = 0x00300109,
CELL_FONT_TYPE_SEURAT_CAPIE_MARU_GOTHIC_YG_DFHEI5_RSANS_SET = 0x0030010F,
CELL_FONT_TYPE_VAGR_SEURAT_CAPIE_MARU_GOTHIC_RSANS_SET = 0x00300124,
CELL_FONT_TYPE_VAGR_SEURAT_CAPIE_MARU_GOTHIC_YG_DFHEI5_RSANS_SET = 0x00300129,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_YG_LIGHT_SET = 0x00040100,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_YG_RODIN_LIGHT_SET = 0x00040101,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_YG_RODIN2_LIGHT_SET = 0x00040201,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_RODIN_LIGHT_SET = 0x00040104,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_RODIN2_LIGHT_SET = 0x00040204,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_YG_BOLD_SET = 0x00070100,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_YG_RODIN_BOLD_SET = 0x00070101,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_YG_RODIN2_BOLD_SET = 0x00070201,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_RODIN_BOLD_SET = 0x00070104,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_RODIN2_BOLD_SET = 0x00070204,
CELL_FONT_TYPE_SEURAT_MARU_GOTHIC_RSANS2_SET = 0x00300204,
CELL_FONT_TYPE_SEURAT_CAPIE_MARU_GOTHIC_RSANS2_SET = 0x00300205,
CELL_FONT_TYPE_SEURAT_MARU_GOTHIC_YG_DFHEI5_RSANS2_SET = 0x00300209,
CELL_FONT_TYPE_SEURAT_CAPIE_MARU_GOTHIC_YG_DFHEI5_RSANS2_SET = 0x0030020F,
CELL_FONT_TYPE_SEURAT_CAPIE_MARU_GOTHIC_YG_DFHEI5_VAGR2_SET = 0x00300229,
CELL_FONT_TYPE_SEURAT_CAPIE_MARU_GOTHIC_VAGR2_SET = 0x00300224,
};
enum
{
CELL_FONT_MAP_FONT = 0,
CELL_FONT_MAP_UNICODE = 1,
};
struct CellFontConfig
{
struct {
be_t<u32> buffer_addr;
be_t<u32> size;
} FileCache;
be_t<u32> userFontEntryMax;
be_t<u32> userFontEntrys_addr;
be_t<u32> flags;
};
struct CellFontRenderer
{
void *systemReserved[64];
};
//Custom enum to determine the origin of a CellFont object
enum
{
CELL_FONT_OPEN_FONTSET,
CELL_FONT_OPEN_FONT_FILE,
CELL_FONT_OPEN_FONT_INSTANCE,
CELL_FONT_OPEN_MEMORY,
};
struct CellFont
{
//void* SystemReserved[64];
be_t<float> scale_x;
be_t<float> scale_y;
be_t<float> slant;
be_t<u32> renderer_addr;
stbtt_fontinfo stbfont;
be_t<u32> fontdata_addr;
be_t<u32> origin;
};
struct CellFontType
{
be_t<u32> type;
be_t<u32> map;
};
struct CellFontInitGraphicsConfigGcm
{
be_t<u32> configType;
struct {
be_t<u32> address;
be_t<u32> size;
} GraphicsMemory;
struct {
be_t<u32> address;
be_t<u32> size;
} MappedMainMemory;
struct {
be_t<s16> slotNumber;
be_t<s16> slotCount;
} VertexShader;
};
struct CellFontGraphics
{
u32 graphicsType;
u32 SystemClosed_addr;
};
struct CellFontHorizontalLayout
{
be_t<float> baseLineY;
be_t<float> lineHeight;
be_t<float> effectHeight;
};
struct CellFontVerticalLayout
{
be_t<float> baseLineX;
be_t<float> lineWidth;
be_t<float> effectWidth;
};
struct CellFontGlyphMetrics
{
be_t<float> width;
be_t<float> height;
struct {
be_t<float> bearingX;
be_t<float> bearingY;
be_t<float> advance;
} Horizontal;
struct {
be_t<float> bearingX;
be_t<float> bearingY;
be_t<float> advance;
} Vertical;
};
struct CellFontImageTransInfo
{
be_t<u32> Image_addr;
be_t<u32> imageWidthByte;
be_t<u32> imageWidth;
be_t<u32> imageHeight;
be_t<u32> Surface_addr;
be_t<u32> surfWidthByte;
};
struct CellFontRendererConfig
{
struct BufferingPolicy
{
be_t<u32> buffer;
be_t<u32> initSize;
be_t<u32> maxSize;
be_t<u32> expandSize;
be_t<u32> resetSize;
};
};
struct CellFontRenderSurface
{
be_t<u32> buffer_addr;
be_t<u32> widthByte;
be_t<u32> pixelSizeByte;
be_t<u32> width, height;
struct {
be_t<u32> x0, y0;
be_t<u32> x1, y1;
} Scissor;
};
// Internal Datatypes
struct CCellFontInternal //Module cellFont
{
u32 m_buffer_addr, m_buffer_size;
u32 m_userFontEntrys_addr, m_userFontEntryMax;
bool m_bInitialized;
bool m_bFontGcmInitialized;
CCellFontInternal()
: m_buffer_addr(0)
, m_buffer_size(0)
, m_bInitialized(false)
, m_bFontGcmInitialized(false)
{
}
};
CCellFontInternal* s_fontInternalInstance = nullptr; CCellFontInternal* s_fontInternalInstance = nullptr;
// Functions // Functions
@ -296,7 +75,9 @@ int cellFontOpenFontMemory(mem_ptr_t<CellFontLibrary> library, u32 fontAddr, u32
if (!s_fontInternalInstance->m_bInitialized) if (!s_fontInternalInstance->m_bInitialized)
return CELL_FONT_ERROR_UNINITIALIZED; return CELL_FONT_ERROR_UNINITIALIZED;
if (!stbtt_InitFont(&(font->stbfont), (unsigned char*)Memory.VirtualToRealAddr(fontAddr), 0)) font->stbfont = (stbtt_fontinfo*)((u8*)&(font->stbfont) + sizeof(void*)); // hack: use next bytes of the struct
if (!stbtt_InitFont(font->stbfont, (unsigned char*)Memory.VirtualToRealAddr(fontAddr), 0))
return CELL_FONT_ERROR_FONT_OPEN_FAILED; return CELL_FONT_ERROR_FONT_OPEN_FAILED;
font->renderer_addr = 0; font->renderer_addr = 0;
@ -484,8 +265,8 @@ int cellFontGetHorizontalLayout(mem_ptr_t<CellFont> font, mem_ptr_t<CellFontHori
font.GetAddr(), layout.GetAddr()); font.GetAddr(), layout.GetAddr());
int ascent, descent, lineGap; int ascent, descent, lineGap;
float scale = stbtt_ScaleForPixelHeight(&(font->stbfont), font->scale_y); float scale = stbtt_ScaleForPixelHeight(font->stbfont, font->scale_y);
stbtt_GetFontVMetrics(&(font->stbfont), &ascent, &descent, &lineGap); stbtt_GetFontVMetrics(font->stbfont, &ascent, &descent, &lineGap);
layout->baseLineY = ascent * scale; layout->baseLineY = ascent * scale;
layout->lineHeight = (ascent-descent+lineGap) * scale; layout->lineHeight = (ascent-descent+lineGap) * scale;
@ -559,14 +340,14 @@ int cellFontRenderCharGlyphImage(mem_ptr_t<CellFont> font, u32 code, mem_ptr_t<C
// Render the character // Render the character
int width, height, xoff, yoff; int width, height, xoff, yoff;
float scale = stbtt_ScaleForPixelHeight(&(font->stbfont), font->scale_y); float scale = stbtt_ScaleForPixelHeight(font->stbfont, font->scale_y);
unsigned char* box = stbtt_GetCodepointBitmap(&(font->stbfont), scale, scale, code, &width, &height, &xoff, &yoff); unsigned char* box = stbtt_GetCodepointBitmap(font->stbfont, scale, scale, code, &width, &height, &xoff, &yoff);
if (!box) return CELL_OK; if (!box) return CELL_OK;
// Get the baseLineY value // Get the baseLineY value
int baseLineY; int baseLineY;
int ascent, descent, lineGap; int ascent, descent, lineGap;
stbtt_GetFontVMetrics(&(font->stbfont), &ascent, &descent, &lineGap); stbtt_GetFontVMetrics(font->stbfont, &ascent, &descent, &lineGap);
baseLineY = ascent * scale; baseLineY = ascent * scale;
// Move the rendered character to the surface // Move the rendered character to the surface
@ -641,9 +422,9 @@ int cellFontGetCharGlyphMetrics(mem_ptr_t<CellFont> font, u32 code, mem_ptr_t<Ce
int x0, y0, x1, y1; int x0, y0, x1, y1;
int advanceWidth, leftSideBearing; int advanceWidth, leftSideBearing;
float scale = stbtt_ScaleForPixelHeight(&(font->stbfont), font->scale_y); float scale = stbtt_ScaleForPixelHeight(font->stbfont, font->scale_y);
stbtt_GetCodepointBox(&(font->stbfont), code, &x0, &y0, &x1, &y1); stbtt_GetCodepointBox(font->stbfont, code, &x0, &y0, &x1, &y1);
stbtt_GetCodepointHMetrics(&(font->stbfont), code, &advanceWidth, &leftSideBearing); stbtt_GetCodepointHMetrics(font->stbfont, code, &advanceWidth, &leftSideBearing);
// TODO: Add the rest of the information // TODO: Add the rest of the information
metrics->width = (x1-x0) * scale; metrics->width = (x1-x0) * scale;

View file

@ -44,4 +44,225 @@ struct CellFontMemoryInterface
//CellFontFreeCallback Free; //CellFontFreeCallback Free;
//CellFontReallocCallback Realloc; //CellFontReallocCallback Realloc;
//CellFontCallocCallback Calloc; //CellFontCallocCallback Calloc;
};
// Font Set Types
enum
{
CELL_FONT_TYPE_RODIN_SANS_SERIF_LATIN = 0x00000000,
CELL_FONT_TYPE_RODIN_SANS_SERIF_LIGHT_LATIN = 0x00000001,
CELL_FONT_TYPE_RODIN_SANS_SERIF_BOLD_LATIN = 0x00000002,
CELL_FONT_TYPE_RODIN_SANS_SERIF_LATIN2 = 0x00000018,
CELL_FONT_TYPE_RODIN_SANS_SERIF_LIGHT_LATIN2 = 0x00000019,
CELL_FONT_TYPE_RODIN_SANS_SERIF_BOLD_LATIN2 = 0x0000001a,
CELL_FONT_TYPE_MATISSE_SERIF_LATIN = 0x00000020,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_JAPANESE = 0x00000008,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_LIGHT_JAPANESE = 0x00000009,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_BOLD_JAPANESE = 0x0000000a,
CELL_FONT_TYPE_YD_GOTHIC_KOREAN = 0x0000000c,
CELL_FONT_TYPE_SEURAT_MARU_GOTHIC_LATIN = 0x00000040,
CELL_FONT_TYPE_SEURAT_MARU_GOTHIC_LATIN2 = 0x00000041,
CELL_FONT_TYPE_VAGR_SANS_SERIF_ROUND = 0x00000043,
CELL_FONT_TYPE_VAGR_SANS_SERIF_ROUND_LATIN2 = 0x00000044,
CELL_FONT_TYPE_SEURAT_MARU_GOTHIC_JAPANESE = 0x00000048,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_JP_SET = 0x00000100,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_LATIN_SET = 0x00000101,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_RODIN_SET = 0x00000104,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_RODIN2_SET = 0x00000204,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_YG_RODIN2_SET = 0x00000201,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_YG_DFHEI5_SET = 0x00000108,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_YG_DFHEI5_RODIN_SET = 0x00000109,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_YG_DFHEI5_RODIN2_SET = 0x00000209,
CELL_FONT_TYPE_DFHEI5_GOTHIC_YG_NEWRODIN_TCH_SET = 0x0000010a,
CELL_FONT_TYPE_DFHEI5_GOTHIC_YG_NEWRODIN_RODIN_TCH_SET = 0x0000010b,
CELL_FONT_TYPE_DFHEI5_GOTHIC_YG_NEWRODIN_RODIN2_TCH_SET = 0x0000020b,
CELL_FONT_TYPE_DFHEI5_GOTHIC_YG_NEWRODIN_SCH_SET = 0x0000010c,
CELL_FONT_TYPE_DFHEI5_GOTHIC_YG_NEWRODIN_RODIN_SCH_SET = 0x0000010d,
CELL_FONT_TYPE_DFHEI5_GOTHIC_YG_NEWRODIN_RODIN2_SCH_SET = 0x0000020d,
CELL_FONT_TYPE_SEURAT_MARU_GOTHIC_RSANS_SET = 0x00300104,
CELL_FONT_TYPE_SEURAT_CAPIE_MARU_GOTHIC_RSANS_SET = 0x00300105,
CELL_FONT_TYPE_SEURAT_CAPIE_MARU_GOTHIC_JP_SET = 0x00300107,
CELL_FONT_TYPE_SEURAT_MARU_GOTHIC_YG_DFHEI5_RSANS_SET = 0x00300109,
CELL_FONT_TYPE_SEURAT_CAPIE_MARU_GOTHIC_YG_DFHEI5_RSANS_SET = 0x0030010F,
CELL_FONT_TYPE_VAGR_SEURAT_CAPIE_MARU_GOTHIC_RSANS_SET = 0x00300124,
CELL_FONT_TYPE_VAGR_SEURAT_CAPIE_MARU_GOTHIC_YG_DFHEI5_RSANS_SET = 0x00300129,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_YG_LIGHT_SET = 0x00040100,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_YG_RODIN_LIGHT_SET = 0x00040101,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_YG_RODIN2_LIGHT_SET = 0x00040201,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_RODIN_LIGHT_SET = 0x00040104,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_RODIN2_LIGHT_SET = 0x00040204,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_YG_BOLD_SET = 0x00070100,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_YG_RODIN_BOLD_SET = 0x00070101,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_YG_RODIN2_BOLD_SET = 0x00070201,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_RODIN_BOLD_SET = 0x00070104,
CELL_FONT_TYPE_NEWRODIN_GOTHIC_RODIN2_BOLD_SET = 0x00070204,
CELL_FONT_TYPE_SEURAT_MARU_GOTHIC_RSANS2_SET = 0x00300204,
CELL_FONT_TYPE_SEURAT_CAPIE_MARU_GOTHIC_RSANS2_SET = 0x00300205,
CELL_FONT_TYPE_SEURAT_MARU_GOTHIC_YG_DFHEI5_RSANS2_SET = 0x00300209,
CELL_FONT_TYPE_SEURAT_CAPIE_MARU_GOTHIC_YG_DFHEI5_RSANS2_SET = 0x0030020F,
CELL_FONT_TYPE_SEURAT_CAPIE_MARU_GOTHIC_YG_DFHEI5_VAGR2_SET = 0x00300229,
CELL_FONT_TYPE_SEURAT_CAPIE_MARU_GOTHIC_VAGR2_SET = 0x00300224,
};
enum
{
CELL_FONT_MAP_FONT = 0,
CELL_FONT_MAP_UNICODE = 1,
};
struct CellFontConfig
{
struct {
be_t<u32> buffer_addr;
be_t<u32> size;
} FileCache;
be_t<u32> userFontEntryMax;
be_t<u32> userFontEntrys_addr;
be_t<u32> flags;
};
struct CellFontRenderer
{
void *systemReserved[64];
};
//Custom enum to determine the origin of a CellFont object
enum
{
CELL_FONT_OPEN_FONTSET,
CELL_FONT_OPEN_FONT_FILE,
CELL_FONT_OPEN_FONT_INSTANCE,
CELL_FONT_OPEN_MEMORY,
};
struct stbtt_fontinfo;
struct CellFont
{
//void* SystemReserved[64];
be_t<float> scale_x;
be_t<float> scale_y;
be_t<float> slant;
be_t<u32> renderer_addr;
be_t<u32> fontdata_addr;
be_t<u32> origin;
stbtt_fontinfo* stbfont;
// hack: don't place anything after pointer
};
struct CellFontType
{
be_t<u32> type;
be_t<u32> map;
};
struct CellFontInitGraphicsConfigGcm
{
be_t<u32> configType;
struct {
be_t<u32> address;
be_t<u32> size;
} GraphicsMemory;
struct {
be_t<u32> address;
be_t<u32> size;
} MappedMainMemory;
struct {
be_t<s16> slotNumber;
be_t<s16> slotCount;
} VertexShader;
};
struct CellFontGraphics
{
u32 graphicsType;
u32 SystemClosed_addr;
};
struct CellFontHorizontalLayout
{
be_t<float> baseLineY;
be_t<float> lineHeight;
be_t<float> effectHeight;
};
struct CellFontVerticalLayout
{
be_t<float> baseLineX;
be_t<float> lineWidth;
be_t<float> effectWidth;
};
struct CellFontGlyphMetrics
{
be_t<float> width;
be_t<float> height;
struct {
be_t<float> bearingX;
be_t<float> bearingY;
be_t<float> advance;
} Horizontal;
struct {
be_t<float> bearingX;
be_t<float> bearingY;
be_t<float> advance;
} Vertical;
};
struct CellFontImageTransInfo
{
be_t<u32> Image_addr;
be_t<u32> imageWidthByte;
be_t<u32> imageWidth;
be_t<u32> imageHeight;
be_t<u32> Surface_addr;
be_t<u32> surfWidthByte;
};
struct CellFontRendererConfig
{
struct BufferingPolicy
{
be_t<u32> buffer;
be_t<u32> initSize;
be_t<u32> maxSize;
be_t<u32> expandSize;
be_t<u32> resetSize;
};
};
struct CellFontRenderSurface
{
be_t<u32> buffer_addr;
be_t<u32> widthByte;
be_t<u32> pixelSizeByte;
be_t<u32> width, height;
struct {
be_t<u32> x0, y0;
be_t<u32> x1, y1;
} Scissor;
};
// Internal Datatypes
struct CCellFontInternal //Module cellFont
{
u32 m_buffer_addr, m_buffer_size;
u32 m_userFontEntrys_addr, m_userFontEntryMax;
bool m_bInitialized;
bool m_bFontGcmInitialized;
CCellFontInternal()
: m_buffer_addr(0)
, m_buffer_size(0)
, m_bInitialized(false)
, m_bFontGcmInitialized(false)
{
}
}; };

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