This commit is contained in:
aenu
2025-08-19 22:57:46 +08:00
parent 54c4eff2a0
commit 619f5fca9d
115 changed files with 2756 additions and 1092 deletions

View File

@@ -72,7 +72,7 @@ extern std::shared_ptr<CPUDisAsm> make_disasm(const cpu_thread* cpu, shared_ptr<
result->set_cpu_handle(std::move(handle));
return result;
}
#if 0
template <>
void fmt_class_string<cheat_type>::format(std::string& out, u64 arg)
{
@@ -94,7 +94,7 @@ void fmt_class_string<cheat_type>::format(std::string& out, u64 arg)
return unknown;
});
}
#endif
template <>
void fmt_class_string<std::chrono::sys_time<typename std::chrono::system_clock::duration>>::format(std::string& out, u64 arg)
{
@@ -182,7 +182,7 @@ __attribute__((constructor)) static void init_localized_strings()
class android_save_dialog:public SaveDialogBase{
public:
s32 ShowSaveDataList(std::vector<SaveDataEntry>& save_entries, s32 focused, u32 op, vm::ptr<CellSaveDataListSet> listSet, bool enable_overlay) override
s32 ShowSaveDataList(const std::string& base_dir, std::vector<SaveDataEntry>& save_entries, s32 focused, u32 op, vm::ptr<CellSaveDataListSet> listSet, bool enable_overlay) override
{
LOGI("ShowSaveDataList(save_entries=%d, focused=%d, op=0x%x, listSet=*0x%x, enable_overlay=%d)", save_entries.size(), focused, op, listSet, enable_overlay);

View File

@@ -2,7 +2,6 @@
#include "util/types.hpp"
#include <string>
#include <vector>
#include <algorithm>
#include "util/asm.hpp"

View File

@@ -1,10 +1,32 @@
#include "stdafx.h"
#include "cheat_info.h"
#include "Config.h"
#include "StrUtil.h"
LOG_CHANNEL(log_cheat, "Cheat");
template <>
void fmt_class_string<cheat_type>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](cheat_type value)
{
switch (value)
{
case cheat_type::unsigned_8_cheat: return "Unsigned 8 bits";
case cheat_type::unsigned_16_cheat: return "Unsigned 16 bits";
case cheat_type::unsigned_32_cheat: return "Unsigned 32 bits";
case cheat_type::unsigned_64_cheat: return "Unsigned 64 bits";
case cheat_type::signed_8_cheat: return "Signed 8 bits";
case cheat_type::signed_16_cheat: return "Signed 16 bits";
case cheat_type::signed_32_cheat: return "Signed 32 bits";
case cheat_type::signed_64_cheat: return "Signed 64 bits";
case cheat_type::float_32_cheat: return "Float 32 bits";
case cheat_type::max: break;
}
return unknown;
});
}
bool cheat_info::from_str(const std::string& cheat_line)
{
auto cheat_vec = fmt::split(cheat_line, {"@@@"}, false);

View File

@@ -14,6 +14,7 @@ enum class cheat_type : u8
signed_16_cheat,
signed_32_cheat,
signed_64_cheat,
float_32_cheat,
max
};

View File

@@ -49,7 +49,7 @@ public:
if (!next)
{
// Do not allow access beyond many element more at a time
// Do not allow access beyond many element more at a time
ensure(!installed && index - i < N * 2);
installed = true;
@@ -384,17 +384,25 @@ public:
template <typename T>
class lf_queue final
{
atomic_t<u64> m_head{0};
lf_queue_item<T>* load(u64 value) const noexcept
private:
struct fat_ptr
{
return reinterpret_cast<lf_queue_item<T>*>(value >> 16);
u64 ptr{};
u32 is_non_null{};
u32 reserved{};
};
atomic_t<fat_ptr> m_head{fat_ptr{}};
lf_queue_item<T>* load(fat_ptr value) const noexcept
{
return reinterpret_cast<lf_queue_item<T>*>(value.ptr);
}
// Extract all elements and reverse element order (FILO to FIFO)
lf_queue_item<T>* reverse() noexcept
{
if (auto* head = load(m_head) ? load(m_head.exchange(0)) : nullptr)
if (auto* head = load(m_head) ? load(m_head.exchange(fat_ptr{})) : nullptr)
{
if (auto* prev = head->m_link)
{
@@ -420,7 +428,7 @@ public:
lf_queue(lf_queue&& other) noexcept
{
m_head.release(other.m_head.exchange(0));
m_head.release(other.m_head.exchange(fat_ptr{}));
}
lf_queue& operator=(lf_queue&& other) noexcept
@@ -430,8 +438,7 @@ public:
return *this;
}
delete load(m_head);
m_head.release(other.m_head.exchange(0));
delete load(m_head.exchange(other.m_head.exchange(fat_ptr{})));
return *this;
}
@@ -442,12 +449,17 @@ public:
void wait(std::nullptr_t /*null*/ = nullptr) noexcept
{
if (m_head == 0)
if (!operator bool())
{
utils::bless<atomic_t<u32>>(&m_head)[1].wait(0);
get_wait_atomic().wait(0);
}
}
atomic_t<u32> &get_wait_atomic()
{
return *utils::bless<atomic_t<u32>>(&m_head.raw().is_non_null);
}
const volatile void* observe() const noexcept
{
return load(m_head);
@@ -455,7 +467,7 @@ public:
explicit operator bool() const noexcept
{
return m_head != 0;
return observe() != nullptr;
}
template <bool Notify = true, typename... Args>
@@ -464,25 +476,25 @@ public:
auto oldv = m_head.load();
auto item = new lf_queue_item<T>(load(oldv), std::forward<Args>(args)...);
while (!m_head.compare_exchange(oldv, reinterpret_cast<u64>(item) << 16))
while (!m_head.compare_exchange(oldv, fat_ptr{reinterpret_cast<u64>(item), item != nullptr, 0}))
{
item->m_link = load(oldv);
}
if (!oldv && Notify)
if (!oldv.ptr && Notify)
{
// Notify only if queue was empty
notify(true);
}
return !oldv;
return !oldv.ptr;
}
void notify(bool force = false)
{
if (force || operator bool())
{
utils::bless<atomic_t<u32>>(&m_head)[1].notify_one();
get_wait_atomic().notify_one();
}
}
@@ -498,7 +510,7 @@ public:
lf_queue_slice<T> pop_all_reversed()
{
lf_queue_slice<T> result;
result.m_head = load(m_head.exchange(0));
result.m_head = load(m_head.exchange(fat_ptr{}));
return result;
}

View File

@@ -1,6 +1,7 @@
#include "util/types.hpp"
#include <vector>
#include <mutex>
#include "Emu/Cell/timers.hpp"
// Thread-safe object pool with garbage collection
class universal_pool

View File

@@ -4,7 +4,6 @@
#include "Utilities/Thread.h"
#include "Emu/Cell/lv2/sys_spu.h"
#include "Emu/Cell/lv2/sys_sync.h"
#include <thread>

View File

@@ -195,7 +195,7 @@ struct audio_port
// Handle copy ctor of atomic var
audio_port(const audio_port& r)
{
std::memcpy(this, &r, sizeof(r));
std::memcpy(static_cast<void*>(this), &r, sizeof(r));
}
ENABLE_BITWISE_SERIALIZATION;

View File

@@ -1,7 +1,6 @@
#pragma once
#include "util/types.hpp"
#include "util/endian.hpp"
// Error codes
enum CellAudioInError : u32
@@ -76,7 +75,7 @@ struct CellAudioInDeviceInfo
u8 reserved[12];
be_t<u64> deviceId;
be_t<u64> type;
char name[64];
char name[64]; // Not necessarily null terminated!
CellAudioInSoundMode availableModes[16];
};

View File

@@ -26,11 +26,6 @@ void fmt_class_string<CellDaisyError>::format(std::string& out, u64 arg)
});
}
// Temporarily
#ifndef _MSC_VER
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
using LFQueue2 = struct CellDaisyLFQueue2;
using Lock = struct CellDaisyLock;
using ScatterGatherInterlock = struct CellDaisyScatterGatherInterlock;
@@ -38,134 +33,134 @@ using AtomicInterlock = volatile struct CellDaisyAtomicInterlock;
error_code cellDaisyLFQueue2GetPopPointer(vm::ptr<LFQueue2> queue, vm::ptr<s32> pPointer, u32 isBlocking)
{
cellDaisy.todo("cellDaisyLFQueue2GetPopPointer()");
cellDaisy.todo("cellDaisyLFQueue2GetPopPointer(queue=*0x%x, pPointer=*0x%x, isBlocking=%d)", queue, pPointer, isBlocking);
return CELL_OK;
}
error_code cellDaisyLFQueue2CompletePopPointer(vm::ptr<LFQueue2> queue, s32 pointer, vm::ptr<s32(vm::ptr<void>, u32)> fpSendSignal, u32 isQueueFull)
{
cellDaisy.todo("cellDaisyLFQueue2CompletePopPointer()");
cellDaisy.todo("cellDaisyLFQueue2CompletePopPointer(queue=*0x%x, pointer=0x%x, fpSendSignal=*0x%x, isQueueFull=%d)", queue, pointer, fpSendSignal, isQueueFull);
return CELL_OK;
}
void cellDaisyLFQueue2PushOpen(vm::ptr<LFQueue2> queue)
{
cellDaisy.todo("cellDaisyLFQueue2PushOpen()");
cellDaisy.todo("cellDaisyLFQueue2PushOpen(queue=*0x%x)", queue);
}
error_code cellDaisyLFQueue2PushClose(vm::ptr<LFQueue2> queue, vm::ptr<s32(vm::ptr<void>, u32)> fpSendSignal)
{
cellDaisy.todo("cellDaisyLFQueue2PushClose()");
cellDaisy.todo("cellDaisyLFQueue2PushClose(queue=*0x%x, fpSendSignal=*0x%x)", queue, fpSendSignal);
return CELL_OK;
}
void cellDaisyLFQueue2PopOpen(vm::ptr<LFQueue2> queue)
{
cellDaisy.todo("cellDaisyLFQueue2PopOpen()");
cellDaisy.todo("cellDaisyLFQueue2PopOpen(queue=*0x%x)", queue);
}
error_code cellDaisyLFQueue2PopClose(vm::ptr<LFQueue2> queue, vm::ptr<s32(vm::ptr<void>, u32)> fpSendSignal)
{
cellDaisy.todo("cellDaisyLFQueue2PopClose()");
cellDaisy.todo("cellDaisyLFQueue2PopClose(queue=*0x%x, fpSendSignal=*0x%x)", queue, fpSendSignal);
return CELL_OK;
}
error_code cellDaisyLFQueue2HasUnfinishedConsumer(vm::ptr<LFQueue2> queue, u32 isCancelled)
{
cellDaisy.todo("cellDaisyLFQueue2HasUnfinishedConsumer()");
cellDaisy.todo("cellDaisyLFQueue2HasUnfinishedConsumer(queue=*0x%x, isCancelled=%d)", queue, isCancelled);
return CELL_OK;
}
error_code cellDaisy_snprintf(vm::ptr<char> buffer, u32 count, vm::cptr<char> fmt, ppu_va_args_t fmt_args)
{
cellDaisy.todo("cellDaisy_snprintf()");
cellDaisy.todo("cellDaisy_snprintf(buffer=*0x%x, count=%d, fmt=*0x%x, fmt_args=%d)", buffer, count, fmt, fmt_args.count);
return CELL_OK;
}
error_code cellDaisyLock_initialize(vm::ptr<Lock> _this, u32 depth)
{
cellDaisy.todo("cellDaisyLock_initialize()");
cellDaisy.todo("cellDaisyLock_initialize(_this=*0x%x, depth=%d)", _this, depth);
return CELL_OK;
}
error_code cellDaisyLock_getNextHeadPointer(vm::ptr<Lock> _this)
{
cellDaisy.todo("cellDaisyLock_getNextHeadPointer()");
cellDaisy.todo("cellDaisyLock_getNextHeadPointer(_this=*0x%x)", _this);
return CELL_OK;
}
error_code cellDaisyLock_getNextTailPointer(vm::ptr<Lock> _this)
{
cellDaisy.todo("cellDaisyLock_getNextTailPointer()");
cellDaisy.todo("cellDaisyLock_getNextTailPointer(_this=*0x%x)", _this);
return CELL_OK;
}
error_code cellDaisyLock_completeConsume(vm::ptr<Lock> _this, u32 pointer)
{
cellDaisy.todo("cellDaisyLock_completeConsume()");
cellDaisy.todo("cellDaisyLock_completeConsume(_this=*0x%x, pointer=0x%x)", _this, pointer);
return CELL_OK;
}
error_code cellDaisyLock_completeProduce(vm::ptr<Lock> _this, u32 pointer)
{
cellDaisy.todo("cellDaisyLock_completeProduce()");
cellDaisy.todo("cellDaisyLock_completeProduce(_this=*0x%x, pointer=0x%x)", _this, pointer);
return CELL_OK;
}
error_code cellDaisyLock_pushOpen(vm::ptr<Lock> _this)
{
cellDaisy.todo("cellDaisyLock_pushOpen()");
cellDaisy.todo("cellDaisyLock_pushOpen(_this=*0x%x)", _this);
return CELL_OK;
}
error_code cellDaisyLock_pushClose(vm::ptr<Lock> _this)
{
cellDaisy.todo("cellDaisyLock_pushClose()");
cellDaisy.todo("cellDaisyLock_pushClose(_this=*0x%x)", _this);
return CELL_OK;
}
error_code cellDaisyLock_popOpen(vm::ptr<Lock> _this)
{
cellDaisy.todo("cellDaisyLock_popOpen()");
cellDaisy.todo("cellDaisyLock_popOpen(_this=*0x%x)", _this);
return CELL_OK;
}
error_code cellDaisyLock_popClose(vm::ptr<Lock> _this)
{
cellDaisy.todo("cellDaisyLock_popClose()");
cellDaisy.todo("cellDaisyLock_popClose(_this=*0x%x)", _this);
return CELL_OK;
}
void cellDaisyScatterGatherInterlock_1(vm::ptr<ScatterGatherInterlock> _this, vm::ptr<AtomicInterlock> ea, u32 size, vm::ptr<void> eaSignal, vm::ptr<s32(vm::ptr<void>, u32)> fpSendSignal)
{
cellDaisy.todo("cellDaisyScatterGatherInterlock_1()");
cellDaisy.todo("cellDaisyScatterGatherInterlock_1(_this=*0x%x, ea=*0x%x, size=%d, eaSignal=*0x%x, fpSendSignal=*0x%x)", _this, ea, size, eaSignal, fpSendSignal);
}
void cellDaisyScatterGatherInterlock_2(vm::ptr<ScatterGatherInterlock> _this, u32 size, vm::ptr<u32> ids, u32 numSpus, u8 spup)
{
cellDaisy.todo("cellDaisyScatterGatherInterlock_2()");
cellDaisy.todo("cellDaisyScatterGatherInterlock_2(_this=*0x%x, size=%d, ids=*0x%x, numSpus=%d, spup=%d)", _this, size, ids, numSpus, spup);
}
void cellDaisyScatterGatherInterlock_9tor(vm::ptr<ScatterGatherInterlock> _this)
{
cellDaisy.todo("cellDaisyScatterGatherInterlock_9tor()");
cellDaisy.todo("cellDaisyScatterGatherInterlock_9tor(_this=*0x%x)", _this);
}
error_code cellDaisyScatterGatherInterlock_probe(vm::ptr<ScatterGatherInterlock> _this, u32 isBlocking)
{
cellDaisy.todo("cellDaisyScatterGatherInterlock_probe()");
cellDaisy.todo("cellDaisyScatterGatherInterlock_probe(_this=*0x%x, isBlocking=%d)", _this, isBlocking);
return CELL_OK;
}
error_code cellDaisyScatterGatherInterlock_release(vm::ptr<ScatterGatherInterlock> _this)
{
cellDaisy.todo("cellDaisyScatterGatherInterlock_release()");
cellDaisy.todo("cellDaisyScatterGatherInterlock_release(_this=*0x%x)", _this);
return CELL_OK;
}
void cellDaisyScatterGatherInterlock_proceedSequenceNumber(vm::ptr<ScatterGatherInterlock> _this)
{
cellDaisy.todo("cellDaisyScatterGatherInterlock_proceedSequenceNumber()");
cellDaisy.todo("cellDaisyScatterGatherInterlock_proceedSequenceNumber(_this=*0x%x)", _this);
}

View File

@@ -9,6 +9,8 @@
#include "util/asm.hpp"
#include <thread>
LOG_CHANNEL(cellDmux);
template <>

View File

@@ -1,6 +1,7 @@
#pragma once
#include "Emu/Memory/vm_ptr.h"
#include "cellPamf.h"
// Error Codes
enum CellDmuxError :u32

View File

@@ -2,7 +2,6 @@
#include "Emu/Cell/PPUModule.h"
#include "Emu/IdManager.h"
#include "cellPamf.h"
#include "cellDmux.h"
#include "cellDmuxPamf.h"

View File

@@ -161,7 +161,8 @@ enum CellGemVideoConvertFormatEnum : s32
// External device IDs (types)
enum
{
SHARP_SHOOTER_DEVICE_ID = 0x8081
SHARP_SHOOTER_DEVICE_ID = 0x8081,
RACING_WHEEL_DEVICE_ID = 0x8101
};
struct CellGemAttribute

View File

@@ -9,15 +9,8 @@
#include "Emu/Cell/lv2/sys_fs.h"
#include "cellGifDec.h"
#include "util/asm.hpp"
LOG_CHANNEL(cellGifDec);
// Temporarily
#ifndef _MSC_VER
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
template <>
void fmt_class_string<CellGifDecError>::format(std::string& out, u64 arg)
{
@@ -273,7 +266,7 @@ error_code cellGifDecReadHeader(vm::ptr<GifDecoder> mainHandle, vm::ptr<GifStrea
return CELL_GIFDEC_ERROR_ARG;
}
const u32& fd = subHandle->fd;
const u32 fd = subHandle->fd;
CellGifDecInfo& current_info = subHandle->info;
// Write the header to buffer
@@ -302,7 +295,7 @@ error_code cellGifDecReadHeader(vm::ptr<GifDecoder> mainHandle, vm::ptr<GifStrea
return CELL_GIFDEC_ERROR_STREAM_FORMAT; // Surprisingly there is no error code related with headerss
}
u8 packedField = buffer[10];
const u8 packedField = buffer[10];
current_info.SWidth = buffer[6] + buffer[7] * 0x100;
current_info.SHeight = buffer[8] + buffer[9] * 0x100;
current_info.SGlobalColorTableFlag = packedField >> 7;
@@ -520,8 +513,8 @@ error_code cellGifDecDecodeData(vm::ptr<GifDecoder> mainHandle, vm::cptr<GifStre
return CELL_GIFDEC_ERROR_STREAM_FORMAT;
const int bytesPerLine = static_cast<int>(dataCtrlParam->outputBytesPerLine);
const char nComponents = 4;
uint image_size = width * height * nComponents;
constexpr char nComponents = 4;
const u32 image_size = width * height * nComponents;
switch(current_outParam.outputColorSpace)
{
@@ -541,9 +534,8 @@ error_code cellGifDecDecodeData(vm::ptr<GifDecoder> mainHandle, vm::cptr<GifStre
{
memcpy(data.get_ptr(), image.get(), image_size);
}
break;
}
break;
case CELL_GIFDEC_ARGB:
{
if (bytesPerLine > width * nComponents) // Check if we need padding
@@ -579,9 +571,8 @@ error_code cellGifDecDecodeData(vm::ptr<GifDecoder> mainHandle, vm::cptr<GifStre
}
std::memcpy(data.get_ptr(), img.get(), image_size);
}
break;
}
break;
default:
return CELL_GIFDEC_ERROR_ARG;
}

View File

@@ -516,7 +516,7 @@ error_code cellHttpUtilEscapeUri(vm::ptr<char> out, u32 outSize, vm::cptr<u8> in
for (u32 pos = 0; rindex >= 0; rindex--, pos++)
{
char c1 = in[pos];
const char c1 = in[pos];
if (false) // DAT[c1] == '\x03') // TODO
{
@@ -529,7 +529,7 @@ error_code cellHttpUtilEscapeUri(vm::ptr<char> out, u32 outSize, vm::cptr<u8> in
return CELL_HTTP_UTIL_ERROR_NO_MEMORY;
}
const char* chars = "0123456789ABCDEF";
constexpr const char* chars = "0123456789ABCDEF";
out[out_pos++] = '%'; // 0x25
out[out_pos++] = chars[c1 >> 4];
out[out_pos++] = chars[c1 & 0xf];
@@ -618,7 +618,7 @@ error_code cellHttpUtilFormUrlEncode(vm::ptr<char> out, u32 outSize, vm::cptr<u8
for (u32 pos = 0; rindex >= 0; rindex--, pos++)
{
char c1 = in[pos];
const char c1 = in[pos];
if (c1 == ' ')
{
@@ -645,7 +645,7 @@ error_code cellHttpUtilFormUrlEncode(vm::ptr<char> out, u32 outSize, vm::cptr<u8
return CELL_HTTP_UTIL_ERROR_NO_MEMORY;
}
const char* chars = "0123456789ABCDEF";
constexpr const char* chars = "0123456789ABCDEF";
out[out_pos++] = '%'; // 0x25
out[out_pos++] = chars[c1 >> 4];
out[out_pos++] = chars[c1 & 0xf];
@@ -707,7 +707,7 @@ error_code cellHttpUtilFormUrlDecode(vm::ptr<u8> out, u32 size, vm::cptr<char> i
for (s32 index = 0, pos = 0;; index++)
{
size_needed = index + 1;
char c1 = in[pos++];
const char c1 = in[pos++];
if (!c1)
{
@@ -731,7 +731,7 @@ error_code cellHttpUtilFormUrlDecode(vm::ptr<u8> out, u32 size, vm::cptr<char> i
const auto check_char = [](b8 c)
{
u32 utmp = static_cast<u32>(c);
const u32 utmp = static_cast<u32>(c);
s32 stmp = utmp - 48;
if (static_cast<u8>(c - 48) > 9)
{

View File

@@ -9,15 +9,8 @@
#include "Emu/Cell/lv2/sys_fs.h"
#include "cellJpgDec.h"
#include "util/asm.hpp"
LOG_CHANNEL(cellJpgDec);
// Temporarily
#ifndef _MSC_VER
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
template <>
void fmt_class_string<CellJpgDecError>::format(std::string& out, u64 arg)
{
@@ -42,19 +35,19 @@ void fmt_class_string<CellJpgDecError>::format(std::string& out, u64 arg)
error_code cellJpgDecCreate(u32 mainHandle, u32 threadInParam, u32 threadOutParam)
{
UNIMPLEMENTED_FUNC(cellJpgDec);
cellJpgDec.todo("cellJpgDecCreate(mainHandle=0x%x, threadInParam=0x%x, threadOutParam=0x%x)", mainHandle, threadInParam, threadOutParam);
return CELL_OK;
}
error_code cellJpgDecExtCreate(u32 mainHandle, u32 threadInParam, u32 threadOutParam, u32 extThreadInParam, u32 extThreadOutParam)
{
UNIMPLEMENTED_FUNC(cellJpgDec);
cellJpgDec.todo("cellJpgDecExtCreate(mainHandle=0x%x, threadInParam=0x%x, threadOutParam=0x%x, extThreadInParam=0x%x, extThreadOutParam=0x%x)", mainHandle, threadInParam, threadOutParam, extThreadInParam, extThreadOutParam);
return CELL_OK;
}
error_code cellJpgDecDestroy(u32 mainHandle)
{
UNIMPLEMENTED_FUNC(cellJpgDec);
cellJpgDec.todo("cellJpgDecDestroy(mainHandle=0x%x)", mainHandle);
return CELL_OK;
}
@@ -76,7 +69,7 @@ error_code cellJpgDecOpen(u32 mainHandle, vm::ptr<u32> subHandle, vm::ptr<CellJp
case CELL_JPGDEC_FILE:
{
// Get file descriptor and size
const auto real_path = vfs::get(src->fileName.get_ptr());
const std::string real_path = vfs::get(src->fileName.get_ptr());
fs::file file_s(real_path);
if (!file_s) return CELL_JPGDEC_ERROR_OPEN_FILE;
@@ -127,8 +120,8 @@ error_code cellJpgDecReadHeader(u32 mainHandle, u32 subHandle, vm::ptr<CellJpgDe
return CELL_JPGDEC_ERROR_FATAL;
}
const u32& fd = subHandle_data->fd;
const u64& fileSize = subHandle_data->fileSize;
const u32 fd = subHandle_data->fd;
const u64 fileSize = subHandle_data->fileSize;
CellJpgDecInfo& current_info = subHandle_data->info;
// Write the header to buffer
@@ -158,12 +151,12 @@ error_code cellJpgDecReadHeader(u32 mainHandle, u32 subHandle, vm::ptr<CellJpgDe
u32 i = 4;
if(i >= fileSize)
if (i >= fileSize)
return CELL_JPGDEC_ERROR_HEADER;
u16 block_length = buffer[i] * 0xFF + buffer[i+1];
u16 block_length = buffer[i] * 0xFF + buffer[i + 1];
while(true)
while (true)
{
i += block_length; // Increase the file index to get to the next block
if (i >= fileSize || // Check to protect against segmentation faults
@@ -172,15 +165,15 @@ error_code cellJpgDecReadHeader(u32 mainHandle, u32 subHandle, vm::ptr<CellJpgDe
return CELL_JPGDEC_ERROR_HEADER;
}
if(buffer[i+1] == 0xC0)
if (buffer[i + 1] == 0xC0)
break; // 0xFFC0 is the "Start of frame" marker which contains the file size
i += 2; // Skip the block marker
block_length = buffer[i] * 0xFF + buffer[i+1]; // Go to the next block
block_length = buffer[i] * 0xFF + buffer[i + 1]; // Go to the next block
}
current_info.imageWidth = buffer[i+7]*0x100 + buffer[i+8];
current_info.imageHeight = buffer[i+5]*0x100 + buffer[i+6];
current_info.imageWidth = buffer[i + 7] * 0x100 + buffer[i + 8];
current_info.imageHeight = buffer[i + 5] * 0x100 + buffer[i + 6];
current_info.numComponents = 3; // Unimplemented
current_info.colorSpace = CELL_JPG_RGB;
@@ -232,7 +225,7 @@ error_code cellJpgDecDecodeData(u32 mainHandle, u32 subHandle, vm::ptr<u8> data,
}
//Decode JPG file. (TODO: Is there any faster alternative? Can we do it without external libraries?)
int width, height, actual_components;
int width = 0, height = 0, actual_components = 0;
auto image = std::unique_ptr<unsigned char,decltype(&::free)>
(
stbi_load_from_memory(jpg.get(), ::narrow<int>(fileSize), &width, &height, &actual_components, 4),
@@ -267,18 +260,17 @@ error_code cellJpgDecDecodeData(u32 mainHandle, u32 subHandle, vm::ptr<u8> data,
{
memcpy(data.get_ptr(), image.get(), image_size);
}
break;
}
break;
case CELL_JPG_ARGB:
{
const int nComponents = 4;
constexpr int nComponents = 4;
image_size *= nComponents;
if (bytesPerLine > width * nComponents || flip) //check if we need padding
{
//TODO: Find out if we can't do padding without an extra copy
const int linesize = std::min(bytesPerLine, width * nComponents);
const auto output = std::make_unique<char[]>(linesize);
std::vector<char> output(image_size);
for (int i = 0; i < height; i++)
{
const int dstOffset = i * bytesPerLine;
@@ -290,33 +282,32 @@ error_code cellJpgDecDecodeData(u32 mainHandle, u32 subHandle, vm::ptr<u8> data,
output[j + 2] = image.get()[srcOffset + j + 1];
output[j + 3] = image.get()[srcOffset + j + 2];
}
std::memcpy(&data[dstOffset], output.get(), linesize);
std::memcpy(&data[dstOffset], output.data(), linesize);
}
}
else
{
const auto img = std::make_unique<uint[]>(image_size);
uint* source_current = reinterpret_cast<uint*>(image.get());
uint* dest_current = img.get();
for (uint i = 0; i < image_size / nComponents; i++)
std::vector<u32> img(image_size);
const u32* source_current = reinterpret_cast<const u32*>(image.get());
u32* dest_current = img.data();
for (u32 i = 0; i < image_size / nComponents; i++)
{
uint val = *source_current;
const u32 val = *source_current;
*dest_current = (val >> 24) | (val << 8); // set alpha (A8) as leftmost byte
source_current++;
dest_current++;
}
std::memcpy(data.get_ptr(), img.get(), image_size);
std::memcpy(data.get_ptr(), img.data(), image_size);
}
break;
}
break;
case CELL_JPG_GRAYSCALE:
case CELL_JPG_YCbCr:
case CELL_JPG_UPSAMPLE_ONLY:
case CELL_JPG_GRAYSCALE_TO_ALPHA_RGBA:
case CELL_JPG_GRAYSCALE_TO_ALPHA_ARGB:
cellJpgDec.error("cellJpgDecDecodeData: Unsupported color space (%d)", current_outParam.outputColorSpace);
break;
break;
default:
return CELL_JPGDEC_ERROR_ARG;
@@ -324,7 +315,7 @@ error_code cellJpgDecDecodeData(u32 mainHandle, u32 subHandle, vm::ptr<u8> data,
dataOutInfo->status = CELL_JPGDEC_DEC_STATUS_FINISH;
if(dataCtrlParam->outputBytesPerLine)
if (dataCtrlParam->outputBytesPerLine)
dataOutInfo->outputLines = static_cast<u32>(image_size / dataCtrlParam->outputBytesPerLine);
return CELL_OK;

View File

@@ -1,6 +1,6 @@
#include "stdafx.h"
#include "Emu/Cell/PPUModule.h"
#include "cellKb.h"
#include "Emu/Io/Keyboard.h"
LOG_CHANNEL(cellKey2char);

File diff suppressed because it is too large Load Diff

View File

@@ -52,25 +52,25 @@ enum
L10N_CODEPAGE_863,
L10N_CODEPAGE_866,
L10N_CODEPAGE_932,
L10N_SHIFT_JIS,
L10N_SHIFT_JIS = L10N_CODEPAGE_932,
L10N_CODEPAGE_936,
L10N_GBK,
L10N_GBK = L10N_CODEPAGE_936,
L10N_CODEPAGE_949,
L10N_UHC,
L10N_UHC = L10N_CODEPAGE_949,
L10N_CODEPAGE_950,
L10N_BIG5,
L10N_BIG5 = L10N_CODEPAGE_950,
L10N_CODEPAGE_1251,
L10N_CODEPAGE_1252,
L10N_EUC_CN,
L10N_EUC_JP,
L10N_EUC_KR,
L10N_ISO_2022_JP,
L10N_JIS,
L10N_JIS = L10N_ISO_2022_JP,
L10N_ARIB,
L10N_HZ,
L10N_GB18030,
L10N_RIS_506,
L10N_MUSIC_SHIFT_JIS,
L10N_MUSIC_SHIFT_JIS = L10N_RIS_506,
//FW 3.10 and below
L10N_CODEPAGE_852,
L10N_CODEPAGE_1250,
@@ -88,3 +88,12 @@ enum
L10N_CODEPAGE_869,
_L10N_CODE_
};
enum
{
UTF16_SURROGATES_MASK1 = 0xf800,
UTF16_SURROGATES_MASK2 = 0xfc00,
UTF16_SURROGATES = 0xd800,
UTF16_HIGH_SURROGATES = 0xd800,
UTF16_LOW_SURROGATES = 0xdc00,
};

View File

@@ -1,6 +1,5 @@
#include "stdafx.h"
#include "Emu/IdManager.h"
#include "Emu/System.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/Io/MouseHandler.h"

View File

@@ -177,6 +177,11 @@ struct music_state
return CELL_MUSIC_ERROR_NO_MORE_CONTENT;
}
if (!fs::is_file(path))
{
cellMusic.error("set_playback_command: File does not exist: '%s'", path);
}
switch (command)
{
case CELL_MUSIC_PB_CMD_FASTFORWARD:
@@ -213,19 +218,29 @@ error_code cell_music_select_contents()
error_code error = rsx::overlays::show_media_list_dialog(rsx::overlays::media_list_dialog::media_type::audio, vfs_dir_path, title,
[&music](s32 status, utils::media_info info)
{
sysutil_register_cb([&music, info, status](ppu_thread& ppu) -> s32
sysutil_register_cb([&music, info = std::move(info), status](ppu_thread& ppu) -> s32
{
std::lock_guard lock(music.mtx);
const u32 result = status >= 0 ? u32{CELL_OK} : u32{CELL_MUSIC_CANCELED};
if (result == CELL_OK)
{
// Let's always choose the whole directory for now
std::string track;
std::string dir = info.path;
if (fs::is_file(info.path))
{
track = std::move(dir);
dir = fs::get_parent_dir(track);
}
music_selection_context context{};
context.set_playlist(info.path);
context.set_playlist(dir);
context.set_track(track);
// TODO: context.repeat_mode = CELL_SEARCH_REPEATMODE_NONE;
// TODO: context.context_option = CELL_SEARCH_CONTEXTOPTION_NONE;
music.current_selection_context = context;
music.current_selection_context = std::move(context);
music.current_selection_context.create_playlist(music_selection_context::get_next_hash());
cellMusic.success("Media list dialog: selected entry '%s'", context.playlist.front());
cellMusic.success("Media list dialog: selected entry '%s'", music.current_selection_context.playlist.front());
}
else
{
@@ -556,7 +571,7 @@ error_code cellMusicSetPlaybackCommand2(s32 command, vm::ptr<void> param)
auto& music = g_fxo->get<music_state>();
if (!music.func)
return CELL_MUSIC2_ERROR_GENERIC;
return { CELL_MUSIC2_ERROR_GENERIC, "Not initialized" };
error_code result = CELL_OK;
@@ -585,7 +600,7 @@ error_code cellMusicSetPlaybackCommand(s32 command, vm::ptr<void> param)
auto& music = g_fxo->get<music_state>();
if (!music.func)
return CELL_MUSIC_ERROR_GENERIC;
return { CELL_MUSIC_ERROR_GENERIC, "Not initialized" };
error_code result = CELL_OK;

View File

@@ -166,6 +166,7 @@ struct music_selection_context
void set_playlist(const std::string& path);
void create_playlist(const std::string& new_hash);
bool load_playlist();
void set_track(std::string_view track);
u32 step_track(bool next);
operator bool() const

View File

@@ -12,9 +12,6 @@
#include "cellSysutil.h"
#include "util/media_utils.h"
#include <deque>
LOG_CHANNEL(cellMusicDecode);
template<>
@@ -140,19 +137,29 @@ error_code cell_music_decode_select_contents()
error_code error = rsx::overlays::show_media_list_dialog(rsx::overlays::media_list_dialog::media_type::audio, vfs_dir_path, title,
[&dec](s32 status, utils::media_info info)
{
sysutil_register_cb([&dec, info, status](ppu_thread& ppu) -> s32
sysutil_register_cb([&dec, info = std::move(info), status](ppu_thread& ppu) -> s32
{
std::lock_guard lock(dec.mutex);
const u32 result = status >= 0 ? u32{CELL_OK} : u32{CELL_MUSIC_DECODE_CANCELED};
if (result == CELL_OK)
{
// Let's always choose the whole directory for now
std::string track;
std::string dir = info.path;
if (fs::is_file(info.path))
{
track = std::move(dir);
dir = fs::get_parent_dir(track);
}
music_selection_context context{};
context.set_playlist(info.path);
context.set_playlist(dir);
context.set_track(track);
// TODO: context.repeat_mode = CELL_SEARCH_REPEATMODE_NONE;
// TODO: context.context_option = CELL_SEARCH_CONTEXTOPTION_NONE;
dec.current_selection_context = context;
dec.current_selection_context = std::move(context);
dec.current_selection_context.create_playlist(music_selection_context::get_next_hash());
cellMusicDecode.success("Media list dialog: selected entry '%s'", context.playlist.front());
cellMusicDecode.success("Media list dialog: selected entry '%s'", dec.current_selection_context.playlist.front());
}
else
{

View File

@@ -2,7 +2,6 @@
#include "Emu/Cell/PPUModule.h"
#include "Emu/IdManager.h"
#include "Emu/VFS.h"
#include "Utilities/StrUtil.h"
#include "cellSysutil.h"
LOG_CHANNEL(cellMusicExport);

View File

@@ -16,7 +16,7 @@ bool music_selection_context::set(const CellMusicSelectionContext& in)
return false;
}
u32 pos = sizeof(magic);
constexpr u32 pos = sizeof(magic);
hash = &in.data[pos];
return load_playlist();
@@ -77,7 +77,7 @@ std::string music_selection_context::get_yaml_path() const
if (!fs::create_path(path))
{
cellMusicSelectionContext.fatal("Failed to create path: %s (%s)", path, fs::g_tls_error);
cellMusicSelectionContext.fatal("get_yaml_path: Failed to create path: %s (%s)", path, fs::g_tls_error);
}
return path + hash + ".yml";
@@ -101,14 +101,21 @@ void music_selection_context::set_playlist(const std::string& path)
continue;
}
playlist.push_back(dir_path + std::string(path + "/" + dir_entry.name).substr(vfs_dir_path.length()));
std::string track = dir_path + std::string(path + "/" + dir_entry.name).substr(vfs_dir_path.length());
cellMusicSelectionContext.notice("set_playlist: Adding track to playlist: '%s'. (path: '%s', name: '%s')", track, path, dir_entry.name);
playlist.push_back(std::move(track));
}
}
else
{
content_type = CELL_SEARCH_CONTENTTYPE_MUSIC;
playlist.push_back(dir_path + path.substr(vfs_dir_path.length()));
std::string track = dir_path + path.substr(vfs_dir_path.length());
cellMusicSelectionContext.notice("set_playlist: Adding track to playlist: '%s'. (path: '%s')", track, path);
playlist.push_back(std::move(track));
}
valid = true;
}
void music_selection_context::create_playlist(const std::string& new_hash)
@@ -116,7 +123,7 @@ void music_selection_context::create_playlist(const std::string& new_hash)
hash = new_hash;
const std::string yaml_path = get_yaml_path();
cellMusicSelectionContext.notice("Saving music playlist file %s", yaml_path);
cellMusicSelectionContext.notice("create_playlist: Saving music playlist file %s", yaml_path);
YAML::Emitter out;
out << YAML::BeginMap;
@@ -138,9 +145,9 @@ void music_selection_context::create_playlist(const std::string& new_hash)
fs::pending_file file(yaml_path);
if (!file.file || (file.file.write(out.c_str(), out.size()), !file.commit()))
if (!file.file || file.file.write(out.c_str(), out.size()) < out.size() || !file.commit())
{
cellMusicSelectionContext.error("Failed to create music playlist file %s (error=%s)", yaml_path, fs::g_tls_error);
cellMusicSelectionContext.error("create_playlist: Failed to create music playlist file '%s' (error=%s)", yaml_path, fs::g_tls_error);
}
}
@@ -149,7 +156,7 @@ bool music_selection_context::load_playlist()
playlist.clear();
const std::string path = get_yaml_path();
cellMusicSelectionContext.notice("Loading music playlist file %s", path);
cellMusicSelectionContext.notice("load_playlist: Loading music playlist file '%s'", path);
std::string content;
{
@@ -158,7 +165,7 @@ bool music_selection_context::load_playlist()
if (!file)
{
cellMusicSelectionContext.error("Failed to load music playlist file %s: %s", path, fs::g_tls_error);
cellMusicSelectionContext.error("load_playlist: Failed to load music playlist file '%s': %s", path, fs::g_tls_error);
return false;
}
@@ -169,7 +176,7 @@ bool music_selection_context::load_playlist()
if (!error.empty() || !root)
{
cellMusicSelectionContext.error("Failed to load music playlist file %s:\n%s", path, error);
cellMusicSelectionContext.error("load_playlist: Failed to load music playlist file '%s':\n%s", path, error);
return false;
}
@@ -178,54 +185,54 @@ bool music_selection_context::load_playlist()
const std::string version = get_yaml_node_value<std::string>(root["Version"], err);
if (!err.empty())
{
cellMusicSelectionContext.error("No Version entry found. Error: '%s' (file: %s)", err, path);
cellMusicSelectionContext.error("load_playlist: No Version entry found. Error: '%s' (file: '%s')", err, path);
return false;
}
if (version != target_version)
{
cellMusicSelectionContext.error("Version '%s' does not match music playlist target '%s' (file: %s)", version, target_version, path);
cellMusicSelectionContext.error("load_playlist: Version '%s' does not match music playlist target '%s' (file: '%s')", version, target_version, path);
return false;
}
const std::string file_type = get_yaml_node_value<std::string>(root["FileType"], err);
if (!err.empty())
{
cellMusicSelectionContext.error("No FileType entry found. Error: '%s' (file: %s)", err, path);
cellMusicSelectionContext.error("load_playlist: No FileType entry found. Error: '%s' (file: '%s')", err, path);
return false;
}
if (file_type != target_file_type)
{
cellMusicSelectionContext.error("FileType '%s' does not match music playlist target '%s' (file: %s)", file_type, target_file_type, path);
cellMusicSelectionContext.error("load_playlist: FileType '%s' does not match music playlist target '%s' (file: '%s')", file_type, target_file_type, path);
return false;
}
content_type = static_cast<CellSearchContentType>(get_yaml_node_value<u32>(root["ContentType"], err));
if (!err.empty())
{
cellMusicSelectionContext.error("No ContentType entry found. Error: '%s' (file: %s)", err, path);
cellMusicSelectionContext.error("load_playlist: No ContentType entry found. Error: '%s' (file: '%s')", err, path);
return false;
}
context_option = static_cast<CellSearchContextOption>(get_yaml_node_value<u32>(root["ContextOption"], err));
if (!err.empty())
{
cellMusicSelectionContext.error("No ContextOption entry found. Error: '%s' (file: %s)", err, path);
cellMusicSelectionContext.error("load_playlist: No ContextOption entry found. Error: '%s' (file: '%s')", err, path);
return false;
}
repeat_mode = static_cast<CellSearchRepeatMode>(get_yaml_node_value<u32>(root["RepeatMode"], err));
if (!err.empty())
{
cellMusicSelectionContext.error("No RepeatMode entry found. Error: '%s' (file: %s)", err, path);
cellMusicSelectionContext.error("load_playlist: No RepeatMode entry found. Error: '%s' (file: '%s')", err, path);
return false;
}
first_track = get_yaml_node_value<u32>(root["FirstTrack"], err);
if (!err.empty())
{
cellMusicSelectionContext.error("No FirstTrack entry found. Error: '%s' (file: %s)", err, path);
cellMusicSelectionContext.error("load_playlist: No FirstTrack entry found. Error: '%s' (file: '%s')", err, path);
return false;
}
@@ -233,24 +240,49 @@ bool music_selection_context::load_playlist()
if (!track_node || track_node.Type() != YAML::NodeType::Sequence)
{
cellMusicSelectionContext.error("No Tracks entry found or Tracks is not a Sequence. (file: %s)", path);
cellMusicSelectionContext.error("load_playlist: No Tracks entry found or Tracks is not a Sequence. (file: '%s')", path);
return false;
}
for (usz i = 0; i < track_node.size(); i++)
{
cellMusicSelectionContext.notice("load_playlist: Adding track to playlist: '%s'. (file: '%s')", track_node[i].Scalar(), path);
playlist.push_back(track_node[i].Scalar());
}
cellMusicSelectionContext.notice("load_playlist: Loaded music playlist file '%s' (context: %s)", path, to_string());
valid = true;
return true;
}
void music_selection_context::set_track(std::string_view track)
{
if (track.empty()) return;
if (playlist.empty())
{
cellMusicSelectionContext.error("set_track: No tracks to play... (requested path='%s')", track);
return;
}
for (usz i = 0; i < playlist.size(); i++)
{
cellMusicSelectionContext.error("set_track: Comparing track '%s' vs '%s'", track, playlist[i]);
if (track.ends_with(playlist[i]))
{
first_track = current_track = static_cast<u32>(i);
return;
}
}
cellMusicSelectionContext.error("set_track: Track '%s' not found...", track);
}
u32 music_selection_context::step_track(bool next)
{
if (playlist.empty())
{
cellMusicSelectionContext.error("No tracks to play...");
cellMusicSelectionContext.error("step_track: No tracks to play...");
current_track = umax;
return umax;
}
@@ -265,7 +297,7 @@ u32 music_selection_context::step_track(bool next)
if (++current_track >= playlist.size())
{
// We are at the end of the playlist.
cellMusicSelectionContext.notice("No more tracks to play in playlist...");
cellMusicSelectionContext.notice("step_track: No more tracks to play in playlist...");
current_track = umax;
return umax;
}
@@ -276,7 +308,7 @@ u32 music_selection_context::step_track(bool next)
if (current_track == 0)
{
// We are at the start of the playlist.
cellMusicSelectionContext.notice("No more tracks to play in playlist...");
cellMusicSelectionContext.notice("step_track: No more tracks to play in playlist...");
current_track = umax;
return umax;
}
@@ -314,13 +346,13 @@ u32 music_selection_context::step_track(bool next)
case CELL_SEARCH_REPEATMODE_NOREPEAT1:
{
// We are done. We only wanted to decode a single track.
cellMusicSelectionContext.notice("No more tracks to play...");
cellMusicSelectionContext.notice("step_track: No more tracks to play...");
current_track = umax;
return umax;
}
default:
{
fmt::throw_exception("Unknown repeat mode %d", static_cast<u32>(repeat_mode));
fmt::throw_exception("step_track: Unknown repeat mode %d", static_cast<u32>(repeat_mode));
}
}
@@ -329,7 +361,7 @@ u32 music_selection_context::step_track(bool next)
if (next ? current_track == 0 : current_track == (playlist.size() - 1))
{
// We reached the first or last track again. Let's shuffle!
cellMusicSelectionContext.notice("Shuffling playlist...");
cellMusicSelectionContext.notice("step_track: Shuffling playlist...");
auto engine = std::default_random_engine{};
std::shuffle(std::begin(playlist), std::end(playlist), engine);
}

View File

@@ -2,7 +2,6 @@
#include "Emu/system_config.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/IdManager.h"
#include "Emu/Cell/lv2/sys_sync.h"
#include "cellGame.h"
#include "cellSysutil.h"

View File

@@ -1,6 +1,5 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/system_config.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/Io/interception.h"
#include "Emu/Io/Keyboard.h"

View File

@@ -1,6 +1,5 @@
#include "stdafx.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/IdManager.h"
#include "Emu/VFS.h"
#include "Emu/System.h"
#include "cellSysutil.h"

View File

@@ -2,7 +2,6 @@
#include "Emu/Cell/PPUModule.h"
#include "Emu/IdManager.h"
#include "Emu/VFS.h"
#include "Utilities/StrUtil.h"
#include "cellSysutil.h"
LOG_CHANNEL(cellPhotoExport);

View File

@@ -19,11 +19,6 @@ typedef png_bytep iCCP_profile_type;
typedef png_charp iCCP_profile_type;
#endif
// Temporarily
#ifndef _MSC_VER
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
LOG_CHANNEL(cellPngDec);
template <>
@@ -149,7 +144,7 @@ void pngDecRowCallback(png_structp png_ptr, png_bytep new_row, png_uint_32 row_n
png_progressive_combine_row(png_ptr, data, new_row);
}
void pngDecInfoCallback(png_structp png_ptr, png_infop info)
void pngDecInfoCallback(png_structp png_ptr, png_infop /*info*/)
{
PngStream* stream = static_cast<PngStream*>(png_get_progressive_ptr(png_ptr));
if (!stream)
@@ -162,7 +157,7 @@ void pngDecInfoCallback(png_structp png_ptr, png_infop info)
stream->buffer->cursor += (stream->buffer->length - remaining);
}
void pngDecEndCallback(png_structp png_ptr, png_infop info)
void pngDecEndCallback(png_structp png_ptr, png_infop /*info*/)
{
PngStream* stream = static_cast<PngStream*>(png_get_progressive_ptr(png_ptr));
if (!stream)
@@ -175,17 +170,17 @@ void pngDecEndCallback(png_structp png_ptr, png_infop info)
}
// Custom error handler for libpng
[[noreturn]] void pngDecError(png_structp png_ptr, png_const_charp error_message)
[[noreturn]] void pngDecError(png_structp /*png_ptr*/, png_const_charp error_message)
{
cellPngDec.error("%s", error_message);
cellPngDec.error("pngDecError: %s", error_message);
// we can't return here or libpng blows up
fmt::throw_exception("Fatal Error in libpng: %s", error_message);
}
// Custom warning handler for libpng
void pngDecWarning(png_structp png_ptr, png_const_charp error_message)
void pngDecWarning(png_structp /*png_ptr*/, png_const_charp error_message)
{
cellPngDec.warning("%s", error_message);
cellPngDec.warning("pngDecWarning: %s", error_message);
}
// Get the chunk information of the PNG file. IDAT is marked as existing, only after decoding or reading the header.
@@ -337,7 +332,7 @@ be_t<u32> pngDecGetChunkInformation(PngStream* stream, bool IDAT = false)
return chunk_information;
}
error_code pngDecCreate(ppu_thread& ppu, PPHandle png_handle, PThreadInParam thread_in_param, PThreadOutParam thread_out_param, PExtThreadInParam extra_thread_in_param = vm::null, PExtThreadOutParam extra_thread_out_param = vm::null)
error_code pngDecCreate(ppu_thread& ppu, PPHandle png_handle, PThreadInParam thread_in_param, PThreadOutParam thread_out_param, PExtThreadInParam /*extra_thread_in_param*/ = vm::null, PExtThreadOutParam extra_thread_out_param = vm::null)
{
// Check if partial image decoding is used
if (extra_thread_out_param)
@@ -908,103 +903,103 @@ error_code cellPngDecExtDecodeData(ppu_thread& ppu, PHandle handle, PStream stre
error_code cellPngDecGetUnknownChunks(PHandle handle, PStream stream, vm::pptr<CellPngUnknownChunk> unknownChunk, vm::ptr<u32> unknownChunkNumber)
{
cellPngDec.todo("cellPngDecGetUnknownChunks()");
cellPngDec.todo("cellPngDecGetUnknownChunks(handle=*0x%x, stream=*0x%x, unknownChunk=*0x%x, unknownChunkNumber=*0x%x)", handle, stream, unknownChunk, unknownChunkNumber);
return CELL_OK;
}
error_code cellPngDecGetpCAL(PHandle handle, PStream stream, vm::ptr<CellPngPCAL> pcal)
{
cellPngDec.todo("cellPngDecGetpCAL()");
cellPngDec.todo("cellPngDecGetpCAL(handle=*0x%x, stream=*0x%x, pcal=*0x%x)", handle, stream, pcal);
return CELL_OK;
}
error_code cellPngDecGetcHRM(PHandle handle, PStream stream, vm::ptr<CellPngCHRM> chrm)
{
cellPngDec.todo("cellPngDecGetcHRM()");
cellPngDec.todo("cellPngDecGetcHRM(handle=*0x%x, stream=*0x%x, chrm=*0x%x)", handle, stream, chrm);
return CELL_OK;
}
error_code cellPngDecGetsCAL(PHandle handle, PStream stream, vm::ptr<CellPngSCAL> scal)
{
cellPngDec.todo("cellPngDecGetsCAL()");
cellPngDec.todo("cellPngDecGetsCAL(handle=*0x%x, stream=*0x%x, scal=*0x%x)", handle, stream, scal);
return CELL_OK;
}
error_code cellPngDecGetpHYs(PHandle handle, PStream stream, vm::ptr<CellPngPHYS> phys)
{
cellPngDec.todo("cellPngDecGetpHYs()");
cellPngDec.todo("cellPngDecGetpHYs(handle=*0x%x, stream=*0x%x, phys=*0x%x)", handle, stream, phys);
return CELL_OK;
}
error_code cellPngDecGetoFFs(PHandle handle, PStream stream, vm::ptr<CellPngOFFS> offs)
{
cellPngDec.todo("cellPngDecGetoFFs()");
cellPngDec.todo("cellPngDecGetoFFs(handle=*0x%x, stream=*0x%x, offs=*0x%x)", handle, stream, offs);
return CELL_OK;
}
error_code cellPngDecGetsPLT(PHandle handle, PStream stream, vm::ptr<CellPngSPLT> splt)
{
cellPngDec.todo("cellPngDecGetsPLT()");
cellPngDec.todo("cellPngDecGetsPLT(handle=*0x%x, stream=*0x%x, splt=*0x%x)", handle, stream, splt);
return CELL_OK;
}
error_code cellPngDecGetbKGD(PHandle handle, PStream stream, vm::ptr<CellPngBKGD> bkgd)
{
cellPngDec.todo("cellPngDecGetbKGD()");
cellPngDec.todo("cellPngDecGetbKGD(handle=*0x%x, stream=*0x%x, bkgd=*0x%x)", handle, stream, bkgd);
return CELL_OK;
}
error_code cellPngDecGettIME(PHandle handle, PStream stream, vm::ptr<CellPngTIME> time)
{
cellPngDec.todo("cellPngDecGettIME()");
cellPngDec.todo("cellPngDecGettIME(handle=*0x%x, stream=*0x%x, time=*0x%x)", handle, stream, time);
return CELL_OK;
}
error_code cellPngDecGethIST(PHandle handle, PStream stream, vm::ptr<CellPngHIST> hist)
{
cellPngDec.todo("cellPngDecGethIST()");
cellPngDec.todo("cellPngDecGethIST(handle=*0x%x, stream=*0x%x, hist=*0x%x)", handle, stream, hist);
return CELL_OK;
}
error_code cellPngDecGettRNS(PHandle handle, PStream stream, vm::ptr<CellPngTRNS> trns)
{
cellPngDec.todo("cellPngDecGettRNS()");
cellPngDec.todo("cellPngDecGettRNS(handle=*0x%x, stream=*0x%x, trns=*0x%x)", handle, stream, trns);
return CELL_OK;
}
error_code cellPngDecGetsBIT(PHandle handle, PStream stream, vm::ptr<CellPngSBIT> sbit)
{
cellPngDec.todo("cellPngDecGetsBIT()");
cellPngDec.todo("cellPngDecGetsBIT(handle=*0x%x, stream=*0x%x, sbit=*0x%x)", handle, stream, sbit);
return CELL_OK;
}
error_code cellPngDecGetiCCP(PHandle handle, PStream stream, vm::ptr<CellPngICCP> iccp)
{
cellPngDec.todo("cellPngDecGetiCCP()");
cellPngDec.todo("cellPngDecGetiCCP(handle=*0x%x, stream=*0x%x, iccp=*0x%x)", handle, stream, iccp);
return CELL_OK;
}
error_code cellPngDecGetsRGB(PHandle handle, PStream stream, vm::ptr<CellPngSRGB> srgb)
{
cellPngDec.todo("cellPngDecGetsRGB()");
cellPngDec.todo("cellPngDecGetsRGB(handle=*0x%x, stream=*0x%x, srgb=*0x%x)", handle, stream, srgb);
return CELL_OK;
}
error_code cellPngDecGetgAMA(PHandle handle, PStream stream, vm::ptr<CellPngGAMA> gama)
{
cellPngDec.todo("cellPngDecGetgAMA()");
cellPngDec.todo("cellPngDecGetgAMA(handle=*0x%x, stream=*0x%x, gama=*0x%x)", handle, stream, gama);
return CELL_OK;
}
error_code cellPngDecGetPLTE(PHandle handle, PStream stream, vm::ptr<CellPngPLTE> plte)
{
cellPngDec.todo("cellPngDecGetPLTE()");
cellPngDec.todo("cellPngDecGetPLTE(handle=*0x%x, stream=*0x%x, plte=*0x%x)", handle, stream, plte);
return CELL_OK;
}
error_code cellPngDecGetTextChunk(PHandle handle, PStream stream, vm::ptr<u32> textInfoNum, vm::pptr<CellPngTextInfo> textInfo)
{
cellPngDec.todo("cellPngDecGetTextChunk()");
cellPngDec.todo("cellPngDecGetTextChunk(handle=*0x%x, stream=*0x%x, textInfoNum=*0x%x, textInfo=*0x%x)", handle, stream, textInfoNum, textInfo);
return CELL_OK;
}

View File

@@ -2,7 +2,6 @@
#include "Emu/Cell/PPUModule.h"
#include "Emu/IdManager.h"
#include "cellPngEnc.h"
#include "png.h"
LOG_CHANNEL(cellPngEnc);

View File

@@ -894,7 +894,7 @@ void rec_info::stop_video_provider(bool flush)
}
}
bool create_path(std::string& out, std::string dir_name, std::string file_name)
bool create_path(std::string& out, std::string dir_name, const std::string& file_name)
{
out.clear();
@@ -903,7 +903,7 @@ bool create_path(std::string& out, std::string dir_name, std::string file_name)
return false;
}
out = dir_name;
out = std::move(dir_name);
if (!out.empty() && out.back() != '/')
{

View File

@@ -78,7 +78,7 @@ error_code cellRtcGetCurrentTick(ppu_thread& ppu, vm::ptr<CellRtcTick> pTick)
error_code cellRtcGetCurrentClock(ppu_thread& ppu, vm::ptr<CellRtcDateTime> pClock, s32 iTimeZone)
{
cellRtc.notice("cellRtcGetCurrentClock(pClock=*0x%x, iTimeZone=%d)", pClock, iTimeZone);
cellRtc.trace("cellRtcGetCurrentClock(pClock=*0x%x, iTimeZone=%d)", pClock, iTimeZone);
const vm::var<sys_page_attr_t> page_attr;
@@ -1505,7 +1505,7 @@ error_code cellRtcGetSystemTime(ppu_thread& ppu, vm::cptr<CellRtcDateTime> pDate
error_code cellRtcGetTime_t(ppu_thread& ppu, vm::cptr<CellRtcDateTime> pDateTime, vm::ptr<s64> piTime)
{
cellRtc.notice("cellRtcGetTime_t(pDateTime=*0x%x, piTime=*0x%x)", pDateTime, piTime);
cellRtc.trace("cellRtcGetTime_t(pDateTime=*0x%x, piTime=*0x%x)", pDateTime, piTime);
const vm::var<sys_page_attr_t> page_attr;

View File

@@ -1,6 +1,5 @@
#include "stdafx.h"
#include "Emu/Cell/PPUModule.h"
#include "cellSail.h"
LOG_CHANNEL(cellSailRec);

View File

@@ -8,6 +8,7 @@
#include "Emu/Cell/lv2/sys_sync.h"
#include "Emu/Cell/lv2/sys_process.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/Cell/timers.hpp"
#include "Emu/Cell/Modules/cellSysutil.h"
#include "Emu/Cell/Modules/cellUserInfo.h"
#include "Emu/RSX/Overlays/overlay_message.h"
@@ -19,6 +20,7 @@
#include "Loader/PSF.h"
#include "Utilities/StrUtil.h"
#include "Utilities/date_time.h"
#include "Utilities/sema.h"
#include <mutex>
#include <algorithm>
@@ -242,7 +244,7 @@ static std::vector<SaveDataEntry> get_save_entries(const std::string& base_dir,
continue;
}
SaveDataEntry save_entry;
SaveDataEntry save_entry {};
save_entry.dirName = psf::get_string(psf, "SAVEDATA_DIRECTORY");
save_entry.listParam = psf::get_string(psf, "SAVEDATA_LIST_PARAM");
save_entry.title = psf::get_string(psf, "TITLE");
@@ -305,7 +307,7 @@ static error_code select_and_delete(ppu_thread& ppu)
// Display a blocking Save Data List asynchronously in the GUI thread.
if (auto save_dialog = Emu.GetCallbacks().get_save_dialog())
{
selected = save_dialog->ShowSaveDataList(save_entries, focused, SAVEDATA_OP_LIST_DELETE, vm::null, g_fxo->get<savedata_manager>().enable_overlay);
selected = save_dialog->ShowSaveDataList(base_dir, save_entries, focused, SAVEDATA_OP_LIST_DELETE, vm::null, g_fxo->get<savedata_manager>().enable_overlay);
}
// Reschedule after a blocking dialog returns
@@ -324,7 +326,7 @@ static error_code select_and_delete(ppu_thread& ppu)
focused = save_entries.empty() ? -1 : selected;
// Get information from the selected entry
SaveDataEntry entry = save_entries[selected];
const SaveDataEntry& entry = ::at32(save_entries, selected);
const std::string info = entry.title + "\n" + entry.subtitle + "\n" + entry.details;
// Reusable display message string
@@ -758,7 +760,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
result->userdata = userdata; // probably should be assigned only once (allows the callback to change it)
SaveDataEntry save_entry;
SaveDataEntry save_entry {};
if (setList)
{
@@ -818,7 +820,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
break;
}
SaveDataEntry save_entry2;
SaveDataEntry save_entry2 {};
save_entry2.dirName = psf::get_string(psf, "SAVEDATA_DIRECTORY");
save_entry2.listParam = psf::get_string(psf, "SAVEDATA_LIST_PARAM");
save_entry2.title = psf::get_string(psf, "TITLE");
@@ -1181,7 +1183,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
// Display a blocking Save Data List asynchronously in the GUI thread.
if (auto save_dialog = Emu.GetCallbacks().get_save_dialog())
{
selected = save_dialog->ShowSaveDataList(save_entries, focused, operation, listSet, g_fxo->get<savedata_manager>().enable_overlay);
selected = save_dialog->ShowSaveDataList(base_dir, save_entries, focused, operation, listSet, g_fxo->get<savedata_manager>().enable_overlay);
}
else
{
@@ -1212,8 +1214,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
else
{
// Get information from the selected entry
SaveDataEntry entry = save_entries[selected];
message = get_confirmation_message(operation, entry);
message = get_confirmation_message(operation, ::at32(save_entries, selected));
}
// Yield before a blocking dialog is being spawned
@@ -1343,14 +1344,14 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
else
{
// Get information from the selected entry
SaveDataEntry entry = save_entries[selected];
message = get_confirmation_message(operation, entry);
message = get_confirmation_message(operation, ::at32(save_entries, selected));
}
// Yield before a blocking dialog is being spawned
lv2_obj::sleep(ppu);
// Get user confirmation by opening a blocking dialog
// TODO: show fixedSet->newIcon
s32 return_code = CELL_MSGDIALOG_BUTTON_NONE;
error_code res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO, vm::make_str(message), msg_dialog_source::_cellSaveData, vm::null, vm::null, vm::null, &return_code);
@@ -2499,12 +2500,7 @@ error_code cellSaveDataListDelete(ppu_thread& ppu, PSetList setList, PSetBuf set
return savedata_op(ppu, SAVEDATA_OP_LIST_DELETE, 0, vm::null, 0, setList, setBuf, funcList, vm::null, vm::null, vm::null, container, 0x40, userdata, 0, funcDone);
}
// Temporarily
#ifndef _MSC_VER
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
error_code cellSaveDataListImport(ppu_thread& ppu, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
error_code cellSaveDataListImport(ppu_thread& /*ppu*/, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
{
cellSaveData.todo("cellSaveDataListImport(setList=*0x%x, maxSizeKB=%d, funcDone=*0x%x, container=0x%x, userdata=*0x%x)", setList, maxSizeKB, funcDone, container, userdata);
@@ -2519,7 +2515,7 @@ error_code cellSaveDataListImport(ppu_thread& ppu, PSetList setList, u32 maxSize
return CELL_OK;
}
error_code cellSaveDataListExport(ppu_thread& ppu, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
error_code cellSaveDataListExport(ppu_thread& /*ppu*/, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
{
cellSaveData.todo("cellSaveDataListExport(setList=*0x%x, maxSizeKB=%d, funcDone=*0x%x, container=0x%x, userdata=*0x%x)", setList, maxSizeKB, funcDone, container, userdata);
@@ -2534,7 +2530,7 @@ error_code cellSaveDataListExport(ppu_thread& ppu, PSetList setList, u32 maxSize
return CELL_OK;
}
error_code cellSaveDataFixedImport(ppu_thread& ppu, vm::cptr<char> dirName, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
error_code cellSaveDataFixedImport(ppu_thread& /*ppu*/, vm::cptr<char> dirName, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
{
cellSaveData.todo("cellSaveDataFixedImport(dirName=%s, maxSizeKB=%d, funcDone=*0x%x, container=0x%x, userdata=*0x%x)", dirName, maxSizeKB, funcDone, container, userdata);
@@ -2549,7 +2545,7 @@ error_code cellSaveDataFixedImport(ppu_thread& ppu, vm::cptr<char> dirName, u32
return CELL_OK;
}
error_code cellSaveDataFixedExport(ppu_thread& ppu, vm::cptr<char> dirName, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
error_code cellSaveDataFixedExport(ppu_thread& /*ppu*/, vm::cptr<char> dirName, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
{
cellSaveData.todo("cellSaveDataFixedExport(dirName=%s, maxSizeKB=%d, funcDone=*0x%x, container=0x%x, userdata=*0x%x)", dirName, maxSizeKB, funcDone, container, userdata);
@@ -2580,7 +2576,7 @@ error_code cellSaveDataUserListDelete(ppu_thread& ppu, u32 userId, PSetList setL
return savedata_op(ppu, SAVEDATA_OP_LIST_DELETE, 0, vm::null, 0, setList, setBuf, funcList, vm::null, vm::null, vm::null, container, 0x40, userdata, userId, funcDone);
}
error_code cellSaveDataUserListImport(ppu_thread& ppu, u32 userId, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
error_code cellSaveDataUserListImport(ppu_thread& /*ppu*/, u32 userId, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
{
cellSaveData.todo("cellSaveDataUserListImport(userId=%d, setList=*0x%x, maxSizeKB=%d, funcDone=*0x%x, container=0x%x, userdata=*0x%x)", userId, setList, maxSizeKB, funcDone, container, userdata);
@@ -2595,7 +2591,7 @@ error_code cellSaveDataUserListImport(ppu_thread& ppu, u32 userId, PSetList setL
return CELL_OK;
}
error_code cellSaveDataUserListExport(ppu_thread& ppu, u32 userId, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
error_code cellSaveDataUserListExport(ppu_thread& /*ppu*/, u32 userId, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
{
cellSaveData.todo("cellSaveDataUserListExport(userId=%d, setList=*0x%x, maxSizeKB=%d, funcDone=*0x%x, container=0x%x, userdata=*0x%x)", userId, setList, maxSizeKB, funcDone, container, userdata);
@@ -2610,7 +2606,7 @@ error_code cellSaveDataUserListExport(ppu_thread& ppu, u32 userId, PSetList setL
return CELL_OK;
}
error_code cellSaveDataUserFixedImport(ppu_thread& ppu, u32 userId, vm::cptr<char> dirName, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
error_code cellSaveDataUserFixedImport(ppu_thread& /*ppu*/, u32 userId, vm::cptr<char> dirName, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
{
cellSaveData.todo("cellSaveDataUserFixedImport(userId=%d, dirName=%s, maxSizeKB=%d, funcDone=*0x%x, container=0x%x, userdata=*0x%x)", userId, dirName, maxSizeKB, funcDone, container, userdata);
@@ -2625,7 +2621,7 @@ error_code cellSaveDataUserFixedImport(ppu_thread& ppu, u32 userId, vm::cptr<cha
return CELL_OK;
}
error_code cellSaveDataUserFixedExport(ppu_thread& ppu, u32 userId, vm::cptr<char> dirName, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
error_code cellSaveDataUserFixedExport(ppu_thread& /*ppu*/, u32 userId, vm::cptr<char> dirName, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
{
cellSaveData.todo("cellSaveDataUserFixedExport(userId=%d, dirName=%s, maxSizeKB=%d, funcDone=*0x%x, container=0x%x, userdata=*0x%x)", userId, dirName, maxSizeKB, funcDone, container, userdata);

View File

@@ -1,7 +1,6 @@
#pragma once
#include "util/types.hpp"
#include "util/endian.hpp"
#include "Emu/Memory/vm_ptr.h"
#include <string>
#include <vector>
@@ -362,5 +361,5 @@ class SaveDialogBase
public:
virtual ~SaveDialogBase();
virtual s32 ShowSaveDataList(std::vector<SaveDataEntry>& save_entries, s32 focused, u32 op, vm::ptr<CellSaveDataListSet> listSet, bool enable_overlay) = 0;
virtual s32 ShowSaveDataList(const std::string& base_dir, std::vector<SaveDataEntry>& save_entries, s32 focused, u32 op, vm::ptr<CellSaveDataListSet> listSet, bool enable_overlay) = 0;
};

View File

@@ -160,11 +160,6 @@ void fmt_class_string<SpursWorkloadState>::format(std::string& out, u64 arg)
error_code sys_spu_image_close(ppu_thread&, vm::ptr<sys_spu_image> img);
// Temporarily
#ifndef _MSC_VER
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
//----------------------------------------------------------------------------
// Function prototypes
//----------------------------------------------------------------------------
@@ -738,7 +733,7 @@ void _spurs::handler_entry(ppu_thread& ppu, vm::ptr<CellSpurs> spurs)
}
}
s32 _spurs::create_handler(vm::ptr<CellSpurs> spurs, u32 ppuPriority)
s32 _spurs::create_handler(vm::ptr<CellSpurs> /*spurs*/, u32 /*ppuPriority*/)
{
struct handler_thread : ppu_thread
{
@@ -909,7 +904,7 @@ void _spurs::event_helper_entry(ppu_thread& ppu, vm::ptr<CellSpurs> spurs)
}
}
s32 _spurs::create_event_helper(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 ppuPriority)
s32 _spurs::create_event_helper(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 /*ppuPriority*/)
{
if (s32 rc = _spurs::create_lv2_eq(ppu, spurs, spurs.ptr(&CellSpurs::eventQueue), spurs.ptr(&CellSpurs::spuPort), 0x2A, sys_event_queue_attribute_t{SYS_SYNC_PRIORITY, SYS_PPU_QUEUE, {"_spuPrv\0"_u64}}))
{
@@ -981,7 +976,7 @@ void _spurs::init_event_port_mux(vm::ptr<CellSpurs::EventPortMux> eventPortMux,
eventPortMux->x08 = unknown;
}
s32 _spurs::add_default_syswkl(vm::ptr<CellSpurs> spurs, vm::cptr<u8> swlPriority, u32 swlMaxSpu, u32 swlIsPreem)
s32 _spurs::add_default_syswkl(vm::ptr<CellSpurs> /*spurs*/, vm::cptr<u8> /*swlPriority*/, u32 /*swlMaxSpu*/, u32 /*swlIsPreem*/)
{
// TODO: Implement this
return CELL_OK;
@@ -1859,7 +1854,7 @@ s32 cellSpursSetPriority(vm::ptr<CellSpurs> spurs, u32 wid, u32 spuId, u32 prior
/// Set preemption victim SPU
s32 cellSpursSetPreemptionVictimHints(vm::ptr<CellSpurs> spurs, vm::cptr<b8> isPreemptible)
{
UNIMPLEMENTED_FUNC(cellSpurs);
cellSpurs.todo("cellSpursSetPreemptionVictimHints(spurs=*0x%x, isPreemptible=*0x%x)", spurs, isPreemptible);
return CELL_OK;
}
@@ -2230,7 +2225,7 @@ s32 cellSpursTraceStop(ppu_thread& ppu, vm::ptr<CellSpurs> spurs)
//----------------------------------------------------------------------------
/// Initialize attributes of a workload
s32 _cellSpursWorkloadAttributeInitialize(ppu_thread& ppu, vm::ptr<CellSpursWorkloadAttribute> attr, u32 revision, u32 sdkVersion, vm::cptr<void> pm, u32 size, u64 data, vm::cptr<u8[8]> priority, u32 minCnt, u32 maxCnt)
s32 _cellSpursWorkloadAttributeInitialize(ppu_thread& /*ppu*/, vm::ptr<CellSpursWorkloadAttribute> attr, u32 revision, u32 sdkVersion, vm::cptr<void> pm, u32 size, u64 data, vm::cptr<u8[8]> priority, u32 minCnt, u32 maxCnt)
{
cellSpurs.warning("_cellSpursWorkloadAttributeInitialize(attr=*0x%x, revision=%d, sdkVersion=0x%x, pm=*0x%x, size=0x%x, data=0x%llx, priority=*0x%x, minCnt=0x%x, maxCnt=0x%x)",
attr, revision, sdkVersion, pm, size, data, priority, minCnt, maxCnt);
@@ -2277,7 +2272,7 @@ s32 _cellSpursWorkloadAttributeInitialize(ppu_thread& ppu, vm::ptr<CellSpursWork
}
/// Set the name of a workload
s32 cellSpursWorkloadAttributeSetName(ppu_thread& ppu, vm::ptr<CellSpursWorkloadAttribute> attr, vm::cptr<char> nameClass, vm::cptr<char> nameInstance)
s32 cellSpursWorkloadAttributeSetName(ppu_thread& /*ppu*/, vm::ptr<CellSpursWorkloadAttribute> attr, vm::cptr<char> nameClass, vm::cptr<char> nameInstance)
{
cellSpurs.warning("cellSpursWorkloadAttributeSetName(attr=*0x%x, nameClass=%s, nameInstance=%s)", attr, nameClass, nameInstance);
@@ -2771,7 +2766,7 @@ s32 cellSpursWakeUp(ppu_thread& ppu, vm::ptr<CellSpurs> spurs)
}
/// Send a workload signal
s32 cellSpursSendWorkloadSignal(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 wid)
s32 cellSpursSendWorkloadSignal(ppu_thread& /*ppu*/, vm::ptr<CellSpurs> spurs, u32 wid)
{
cellSpurs.warning("cellSpursSendWorkloadSignal(spurs=*0x%x, wid=%d)", spurs, wid);
@@ -2833,7 +2828,7 @@ s32 cellSpursGetWorkloadFlag(vm::ptr<CellSpurs> spurs, vm::pptr<CellSpursWorkloa
}
/// Set ready count
s32 cellSpursReadyCountStore(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 wid, u32 value)
s32 cellSpursReadyCountStore(ppu_thread& /*ppu*/, vm::ptr<CellSpurs> spurs, u32 wid, u32 value)
{
cellSpurs.trace("cellSpursReadyCountStore(spurs=*0x%x, wid=%d, value=0x%x)", spurs, wid, value);
@@ -2871,7 +2866,7 @@ s32 cellSpursReadyCountStore(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 wid,
}
/// Swap ready count
s32 cellSpursReadyCountSwap(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 wid, vm::ptr<u32> old, u32 swap)
s32 cellSpursReadyCountSwap(ppu_thread& /*ppu*/, vm::ptr<CellSpurs> spurs, u32 wid, vm::ptr<u32> old, u32 swap)
{
cellSpurs.trace("cellSpursReadyCountSwap(spurs=*0x%x, wid=%d, old=*0x%x, swap=0x%x)", spurs, wid, old, swap);
@@ -2909,7 +2904,7 @@ s32 cellSpursReadyCountSwap(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 wid,
}
/// Compare and swap ready count
s32 cellSpursReadyCountCompareAndSwap(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 wid, vm::ptr<u32> old, u32 compare, u32 swap)
s32 cellSpursReadyCountCompareAndSwap(ppu_thread& /*ppu*/, vm::ptr<CellSpurs> spurs, u32 wid, vm::ptr<u32> old, u32 compare, u32 swap)
{
cellSpurs.trace("cellSpursReadyCountCompareAndSwap(spurs=*0x%x, wid=%d, old=*0x%x, compare=0x%x, swap=0x%x)", spurs, wid, old, compare, swap);
@@ -2950,7 +2945,7 @@ s32 cellSpursReadyCountCompareAndSwap(ppu_thread& ppu, vm::ptr<CellSpurs> spurs,
}
/// Increase or decrease ready count
s32 cellSpursReadyCountAdd(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 wid, vm::ptr<u32> old, s32 value)
s32 cellSpursReadyCountAdd(ppu_thread& /*ppu*/, vm::ptr<CellSpurs> spurs, u32 wid, vm::ptr<u32> old, s32 value)
{
cellSpurs.trace("cellSpursReadyCountAdd(spurs=*0x%x, wid=%d, old=*0x%x, value=0x%x)", spurs, wid, old, value);
@@ -3030,7 +3025,7 @@ s32 cellSpursGetWorkloadData(vm::ptr<CellSpurs> spurs, vm::ptr<u64> data, u32 wi
}
/// Get workload information
s32 cellSpursGetWorkloadInfo(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 wid, vm::ptr<CellSpursWorkloadInfo> info)
s32 cellSpursGetWorkloadInfo(ppu_thread& /*ppu*/, vm::ptr<CellSpurs> spurs, u32 wid, vm::ptr<CellSpursWorkloadInfo> info)
{
cellSpurs.todo("cellSpursGetWorkloadInfo(spurs=*0x%x, wid=0x%x, info=*0x%x)", spurs, wid, info);
return CELL_OK;
@@ -3135,7 +3130,7 @@ s32 _cellSpursWorkloadFlagReceiver(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u3
}
/// Set/unset the recipient of the workload flag
s32 _cellSpursWorkloadFlagReceiver2(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 wid, u32 is_set, u32 print_debug_output)
s32 _cellSpursWorkloadFlagReceiver2(ppu_thread& /*ppu*/, vm::ptr<CellSpurs> spurs, u32 wid, u32 is_set, u32 print_debug_output)
{
cellSpurs.warning("_cellSpursWorkloadFlagReceiver2(spurs=*0x%x, wid=%d, is_set=%d, print_debug_output=%d)", spurs, wid, is_set, print_debug_output);
@@ -3833,19 +3828,19 @@ s32 _cellSpursLFQueueInitialize(vm::ptr<void> pTasksetOrSpurs, vm::ptr<CellSpurs
s32 _cellSpursLFQueuePushBody()
{
UNIMPLEMENTED_FUNC(cellSpurs);
cellSpurs.todo("_cellSpursLFQueuePushBody()");
return CELL_OK;
}
s32 cellSpursLFQueueAttachLv2EventQueue(vm::ptr<CellSyncLFQueue> queue)
{
UNIMPLEMENTED_FUNC(cellSpurs);
cellSpurs.todo("cellSpursLFQueueAttachLv2EventQueue(queue=*0x%x)", queue);
return CELL_OK;
}
s32 cellSpursLFQueueDetachLv2EventQueue(vm::ptr<CellSyncLFQueue> queue)
{
UNIMPLEMENTED_FUNC(cellSpurs);
cellSpurs.todo("cellSpursLFQueueDetachLv2EventQueue(queue=*0x%x)", queue);
return CELL_OK;
}
@@ -4571,7 +4566,7 @@ s32 cellSpursTasksetUnsetExceptionEventHandler(vm::ptr<CellSpursTaskset> taskset
return CELL_OK;
}
s32 cellSpursLookUpTasksetAddress(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, vm::pptr<CellSpursTaskset> taskset, u32 id)
s32 cellSpursLookUpTasksetAddress(ppu_thread& /*ppu*/, vm::ptr<CellSpurs> spurs, vm::pptr<CellSpursTaskset> taskset, u32 id)
{
cellSpurs.warning("cellSpursLookUpTasksetAddress(spurs=*0x%x, taskset=**0x%x, id=0x%x)", spurs, taskset, id);
@@ -4653,9 +4648,9 @@ s32 _cellSpursTasksetAttributeInitialize(vm::ptr<CellSpursTasksetAttribute> attr
return CELL_OK;
}
s32 _spurs::check_job_chain_attribute(u32 sdkVer, vm::cptr<u64> jcEntry, u16 sizeJobDescr, u16 maxGrabbedJob
, u64 priorities, u32 maxContention, u8 autoSpuCount, u32 tag1, u32 tag2
, u8 isFixedMemAlloc, u32 maxSizeJob, u32 initSpuCount)
s32 _spurs::check_job_chain_attribute(u32 sdkVer, vm::cptr<u64> jcEntry, u16 sizeJobDescr, u16 maxGrabbedJob,
u64 priorities, u32 /*maxContention*/, u8 autoSpuCount, u32 tag1, u32 tag2,
u8 /*isFixedMemAlloc*/, u32 maxSizeJob, u32 initSpuCount)
{
if (!jcEntry)
return CELL_SPURS_JOB_ERROR_NULL_POINTER;
@@ -4686,9 +4681,9 @@ s32 _spurs::check_job_chain_attribute(u32 sdkVer, vm::cptr<u64> jcEntry, u16 siz
return CELL_OK;
}
s32 _spurs::create_job_chain(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursJobChain> jobChain, vm::cptr<u64> jobChainEntry, u16 sizeJob
, u16 maxGrabbedJob, vm::cptr<u8[8]> prio, u32 maxContention, b8 autoReadyCount
, u32 tag1, u32 tag2, u32 HaltOnError, vm::cptr<char> name, u32 param_13, u32 param_14)
s32 _spurs::create_job_chain(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursJobChain> jobChain, vm::cptr<u64> jobChainEntry, u16 /*sizeJob*/,
u16 maxGrabbedJob, vm::cptr<u8[8]> prio, u32 maxContention, b8 /*autoReadyCount*/,
u32 tag1, u32 tag2, u32 /*HaltOnError*/, vm::cptr<char> name, u32 /*param_13*/, u32 /*param_14*/)
{
const s32 sdkVer = _spurs::get_sdk_version();
jobChain->spurs = spurs;

View File

@@ -1,9 +1,6 @@
#include "stdafx.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/Cell/lv2/sys_spu.h"
#include "cellSpursJq.h"
LOG_CHANNEL(cellSpursJq);
error_code cellSpursJobQueueAttributeInitialize()

View File

@@ -15,7 +15,6 @@ LOG_CHANNEL(cellSpurs);
// Temporarily
#ifndef _MSC_VER
#pragma GCC diagnostic ignored "-Wunused-function"
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
//----------------------------------------------------------------------------
@@ -89,7 +88,7 @@ void spursJobchainPopUrgentCommand(spu_thread& spu);
//----------------------------------------------------------------------------
// Output trace information
void cellSpursModulePutTrace(CellSpursTracePacket* packet, u32 dmaTagId)
void cellSpursModulePutTrace(CellSpursTracePacket* /*packet*/, u32 /*dmaTagId*/)
{
// TODO: Implement this
}
@@ -871,7 +870,7 @@ void spursSysServiceIdleHandler(spu_thread& spu, SpursKernelContext* ctxt)
}
// Main function for the system service
void spursSysServiceMain(spu_thread& spu, u32 pollStatus)
void spursSysServiceMain(spu_thread& spu, u32 /*pollStatus*/)
{
const auto ctxt = spu._ptr<SpursKernelContext>(0x100);
@@ -1166,7 +1165,7 @@ void spursSysServiceUpdateShutdownCompletionEvents(spu_thread& spu, SpursKernelC
}
// Update the trace count for this SPU
void spursSysServiceTraceSaveCount(spu_thread& spu, SpursKernelContext* ctxt)
void spursSysServiceTraceSaveCount(spu_thread& /*spu*/, SpursKernelContext* ctxt)
{
if (ctxt->traceBuffer)
{
@@ -2056,7 +2055,7 @@ s32 spursTasksetLoadElf(spu_thread& spu, u32* entryPoint, u32* lowestLoadAddr, u
//----------------------------------------------------------------------------
// SPURS taskset policy module functions
//----------------------------------------------------------------------------
bool spursJobChainEntry(spu_thread& spu)
bool spursJobChainEntry(spu_thread& /*spu*/)
{
//const auto ctxt = spu._ptr<SpursJobChainContext>(0x4a00);
//auto kernelCtxt = spu._ptr<SpursKernelContext>(spu.gpr[3]._u32[3]);

View File

@@ -580,8 +580,6 @@ error_code cellSysutilCheckCallback(ppu_thread& ppu)
auto& cbm = g_fxo->get<sysutil_cb_manager>();
bool read = false;
for (auto&& func : cbm.registered.pop_all())
{
if (func.call_active && !*func.call_active)
@@ -589,7 +587,11 @@ error_code cellSysutilCheckCallback(ppu_thread& ppu)
continue;
}
read = true;
// Increase read counter before we call the callback.
// We use this counter to check if the game reacts to a command during game termination and calls sys_process_exit.
// We would not realize that the game reacted in time and terminate it prematurely if we increased
// the counter after we called the callback and the callback did some time-consuming work.
cbm.read_counter++;
if (s32 res = func.func(ppu))
{
@@ -603,11 +605,6 @@ error_code cellSysutilCheckCallback(ppu_thread& ppu)
}
}
if (read)
{
cbm.read_counter++;
}
return CELL_OK;
}

View File

@@ -1619,10 +1619,25 @@ error_code cellVdecSetFrameRate(u32 handle, CellVdecFrameRate frameRateCode)
return CELL_OK;
}
error_code cellVdecOpenExt()
error_code cellVdecOpenExt(ppu_thread& ppu, vm::cptr<CellVdecType> type, vm::cptr<CellVdecResourceExt> res, vm::cptr<CellVdecCb> cb, vm::ptr<u32> handle)
{
UNIMPLEMENTED_FUNC(cellVdec);
return CELL_OK;
cellVdec.warning("cellVdecOpenExt(type=*0x%x, res=*0x%x, cb=*0x%x, handle=*0x%x)", type, res, cb, handle);
if (!res)
{
return CELL_VDEC_ERROR_ARG;
}
vm::var<CellVdecResource> tmp = vm::make_var<CellVdecResource>({});
tmp->memAddr = res->memAddr;
tmp->memSize = res->memSize;
tmp->ppuThreadPriority = res->ppuThreadPriority;
tmp->ppuThreadStackSize = res->ppuThreadStackSize;
tmp->spuThreadPriority = 0;
tmp->numOfSpus = res->numOfSpus;
const vm::ptr<CellVdecResource> ptr = vm::cast(tmp.addr());
return vdecOpen(ppu, type, ptr, cb, handle);
}
error_code cellVdecStartSeqExt()

View File

@@ -133,6 +133,16 @@ struct CellVdecResourceEx
be_t<u32> spursResource_addr;
};
struct CellVdecResourceExt // speculative
{
be_t<u32> memAddr;
be_t<u32> memSize;
be_t<s32> ppuThreadPriority;
be_t<u32> ppuThreadStackSize;
u8 unk[12];
be_t<u32> numOfSpus;
};
// Access Unit Information
struct CellVdecAuInfo
{

View File

@@ -2,7 +2,6 @@
#include "Emu/Cell/PPUModule.h"
#include "Emu/IdManager.h"
#include "Emu/VFS.h"
#include "Utilities/StrUtil.h"
#include "cellSysutil.h"
LOG_CHANNEL(cellVideoExport);

View File

@@ -423,7 +423,7 @@ error_code cellVideoOutGetDeviceInfo(u32 videoOut, u32 deviceIndex, vm::ptr<Cell
error_code cellVideoOutGetNumberOfDevice(u32 videoOut)
{
cellSysutil.warning("cellVideoOutGetNumberOfDevice(videoOut=%d)", videoOut);
cellSysutil.trace("cellVideoOutGetNumberOfDevice(videoOut=%d)", videoOut);
switch (videoOut)
{
@@ -478,11 +478,6 @@ error_code cellVideoOutGetResolutionAvailability(u32 videoOut, u32 resolutionId,
return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT;
}
// Temporarily
#ifndef _MSC_VER
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
error_code cellVideoOutGetConvertCursorColorInfo(vm::ptr<u8> rgbOutputRange)
{
cellSysutil.todo("cellVideoOutGetConvertCursorColorInfo(rgbOutputRange=*0x%x)", rgbOutputRange);

View File

@@ -1,8 +1,5 @@
#pragma once
#include <unordered_map>
#include <deque>
// libvoice = 0x80310801 - 0x803108ff
// libvoice version 100

View File

@@ -4,6 +4,8 @@
#include "cellWebBrowser.h"
#include "Emu/IdManager.h"
#include "cellSysutil.h"
LOG_CHANNEL(cellSysutil);
struct browser_info

View File

@@ -1,7 +1,5 @@
#pragma once
#include "cellSysutil.h"
#include "Emu/Memory/vm_ptr.h"
//events

View File

@@ -34,308 +34,303 @@ void fmt_class_string<CellSnd3Error>::format(std::string& out, u64 arg)
});
}
// Temporarily
#ifndef _MSC_VER
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
error_code cellSnd3Init(u32 maxVoice, u32 samples, vm::ptr<CellSnd3RequestQueueCtx> queue)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3Init(maxVoice=%d, samples=%d, queue=*0x%x)", maxVoice, samples, queue);
return CELL_OK;
}
error_code cellSnd3Exit()
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3Exit()");
return CELL_OK;
}
u16 cellSnd3Note2Pitch(u16 center_note, u16 center_fine, u16 note, s16 fine)
{
libsnd3.todo("cellSnd3Note2Pitch()");
libsnd3.todo("cellSnd3Note2Pitch(center_note=%d, center_fine=%d, note=%d, fine=%d)", center_note, center_fine, note, fine);
return 0;
}
u16 cellSnd3Pitch2Note(u16 center_note, u16 center_fine, u16 pitch)
{
libsnd3.todo("cellSnd3Pitch2Note()");
libsnd3.todo("cellSnd3Pitch2Note(center_note=%d, center_fine=%d, pitch=%d)", center_note, center_fine, pitch);
return 0;
}
error_code cellSnd3SetOutputMode(u32 mode)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3SetOutputMode(mode=%d)", mode);
return CELL_OK;
}
error_code cellSnd3Synthesis(vm::ptr<f32> pOutL, vm::ptr<f32> pOutR)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3Synthesis(pOutL=*0x%x, pOutR=*0x%x)", pOutL, pOutR);
return CELL_OK;
}
error_code cellSnd3SynthesisEx(vm::ptr<f32> pOutL, vm::ptr<f32> pOutR, vm::ptr<f32> pOutRL, vm::ptr<f32> pOutRR)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3SynthesisEx(pOutL=*0x%x, pOutR=*0x%x, pOutRL=*0x%x, pOutRR=*0x%x)", pOutL, pOutR, pOutRL, pOutRR);
return CELL_OK;
}
error_code cellSnd3BindSoundData(vm::ptr<CellSnd3DataCtx> snd3Ctx, vm::ptr<void> hd3, u32 synthMemOffset)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3BindSoundData(snd3Ctx=*0x%x, hd3=*0x%x, synthMemOffset=0x%x)", snd3Ctx, hd3, synthMemOffset);
return CELL_OK;
}
error_code cellSnd3UnbindSoundData(u32 hd3ID)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3UnbindSoundData(hd3ID=0x%x)", hd3ID);
return CELL_OK;
}
error_code cellSnd3NoteOnByTone(u32 hd3ID, u32 toneIndex, u32 note, u32 keyOnID, vm::ptr<CellSnd3KeyOnParam> keyOnParam)
{
libsnd3.todo("cellSnd3NoteOnByTone()");
libsnd3.todo("cellSnd3NoteOnByTone(hd3ID=0x%x, toneIndex=%d, note=%d, keyOnID=0x%x, keyOnParam=*0x%x)", hd3ID, toneIndex, note, keyOnID, keyOnParam);
return CELL_OK;
}
error_code cellSnd3KeyOnByTone(u32 hd3ID, u32 toneIndex, u32 pitch, u32 keyOnID, vm::ptr<CellSnd3KeyOnParam> keyOnParam)
{
libsnd3.todo("cellSnd3KeyOnByTone()");
libsnd3.todo("cellSnd3KeyOnByTone(hd3ID=0x%x, toneIndex=%d, pitch=%d, keyOnID=0x%x, keyOnParam=*0x%x)", hd3ID, toneIndex, pitch, keyOnID, keyOnParam);
return CELL_OK;
}
error_code cellSnd3VoiceNoteOnByTone(u32 hd3ID, u32 voiceNum, u32 toneIndex, u32 note, u32 keyOnID, vm::ptr<CellSnd3KeyOnParam> keyOnParam)
{
libsnd3.todo("cellSnd3VoiceNoteOnByTone()");
libsnd3.todo("cellSnd3VoiceNoteOnByTone(hd3ID=0x%x, voiceNum=%d, toneIndex=%d, note=%d, keyOnID=0x%x, keyOnParam=*0x%x)", hd3ID, voiceNum, toneIndex, note, keyOnID, keyOnParam);
return CELL_OK;
}
error_code cellSnd3VoiceKeyOnByTone(u32 hd3ID, u32 voiceNum, u32 toneIndex, u32 pitch, u32 keyOnID, vm::ptr<CellSnd3KeyOnParam> keyOnParam)
{
libsnd3.todo("cellSnd3VoiceKeyOnByTone()");
libsnd3.todo("cellSnd3VoiceKeyOnByTone(hd3ID=0x%x, voiceNum=%d, toneIndex=%d, pitch=%d, keyOnID=0x%x, keyOnParam=*0x%x)", hd3ID, voiceNum, toneIndex, pitch, keyOnID, keyOnParam);
return CELL_OK;
}
error_code cellSnd3VoiceSetReserveMode(u32 voiceNum, u32 reserveMode)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3VoiceSetReserveMode(voiceNum=%d, reserveMode=%d)", voiceNum, reserveMode);
return CELL_OK;
}
error_code cellSnd3VoiceSetSustainHold(u32 voiceNum, u32 sustainHold)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3VoiceSetSustainHold(voiceNum=%d, sustainHold=%d)", voiceNum, sustainHold);
return CELL_OK;
}
error_code cellSnd3VoiceKeyOff(u32 voiceNum)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3VoiceKeyOff(voiceNum=%d)", voiceNum);
return CELL_OK;
}
error_code cellSnd3VoiceSetPitch(u32 voiceNum, s32 addPitch)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3VoiceSetPitch(voiceNum=%d, addPitch=%d)", voiceNum, addPitch);
return CELL_OK;
}
error_code cellSnd3VoiceSetVelocity(u32 voiceNum, u32 velocity)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3VoiceSetVelocity(voiceNum=%d, velocity=%d)", voiceNum, velocity);
return CELL_OK;
}
error_code cellSnd3VoiceSetPanpot(u32 voiceNum, u32 panpot)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3VoiceSetPanpot(voiceNum=%d, panpot=%d)", voiceNum, panpot);
return CELL_OK;
}
error_code cellSnd3VoiceSetPanpotEx(u32 voiceNum, u32 panpotEx)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3VoiceSetPanpotEx(voiceNum=%d, panpotEx=%d)", voiceNum, panpotEx);
return CELL_OK;
}
error_code cellSnd3VoiceSetPitchBend(u32 voiceNum, u32 bendValue)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3VoiceSetPitchBend(voiceNum=%d, bendValue=%d)", voiceNum, bendValue);
return CELL_OK;
}
error_code cellSnd3VoiceAllKeyOff()
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3VoiceAllKeyOff()");
return CELL_OK;
}
error_code cellSnd3VoiceGetEnvelope(u32 voiceNum)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3VoiceGetEnvelope(voiceNum=%d)", voiceNum);
return CELL_OK;
}
error_code cellSnd3VoiceGetStatus(u32 voiceNum)
{
libsnd3.todo("cellSnd3VoiceGetStatus()");
libsnd3.todo("cellSnd3VoiceGetStatus(voiceNum=%d)", voiceNum);
return CELL_OK;
}
u32 cellSnd3KeyOffByID(u32 keyOnID)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3KeyOffByID(keyOnID=%d)", keyOnID);
return CELL_OK;
}
error_code cellSnd3GetVoice(u32 midiChannel, u32 keyOnID, vm::ptr<CellSnd3VoiceBitCtx> voiceBit)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3GetVoice(midiChannel=%d, keyOnID=%d, voiceBit=*0x%x)", midiChannel, keyOnID, voiceBit);
return CELL_OK;
}
error_code cellSnd3GetVoiceByID(u32 ID, vm::ptr<CellSnd3VoiceBitCtx> voiceBit)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3GetVoiceByID(ID=%d, voiceBit=*0x%x)", ID, voiceBit);
return CELL_OK;
}
error_code cellSnd3NoteOn(u32 hd3ID, u32 midiChannel, u32 midiProgram, u32 midiNote, u32 sustain, vm::ptr<CellSnd3KeyOnParam> keyOnParam, u32 keyOnID)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3NoteOn(hd3ID=%d, midiChannel=%d, midiProgram=%d, midiNote=%d, sustain=%d, keyOnParam=*0x%x, keyOnID=%d)", hd3ID, midiChannel, midiProgram, midiNote, sustain, keyOnParam, keyOnID);
return CELL_OK;
}
error_code cellSnd3NoteOff(u32 midiChannel, u32 midiNote, u32 keyOnID)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3NoteOff(midiChannel=%d, midiNote=%d, keyOnID=%d)", midiChannel, midiNote, keyOnID);
return CELL_OK;
}
error_code cellSnd3SetSustainHold(u32 midiChannel, u32 sustainHold, u32 keyOnID)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3SetSustainHold(midiChannel=%d, sustainHold=%d, keyOnID=%d)", midiChannel, sustainHold, keyOnID);
return CELL_OK;
}
error_code cellSnd3SetEffectType(u16 effectType, s16 returnVol, u16 delay, u16 feedback)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3SetEffectType(effectType=%d, returnVol=%d, delay=%d, feedback=%d)", effectType, returnVol, delay, feedback);
return CELL_OK;
}
error_code cellSnd3SMFBind(vm::ptr<CellSnd3SmfCtx> smfCtx, vm::ptr<void> smf, u32 hd3ID)
{
libsnd3.todo("cellSnd3SMFBind()");
libsnd3.todo("cellSnd3SMFBind(smfCtx=*0x%x, delay=*0x%x, hd3ID=%d)", smfCtx, smf, hd3ID);
return CELL_OK;
}
error_code cellSnd3SMFUnbind(u32 smfID)
{
libsnd3.todo("cellSnd3SMFUnbind()");
libsnd3.todo("cellSnd3SMFUnbind(smfID=%d)", smfID);
return CELL_OK;
}
error_code cellSnd3SMFPlay(u32 smfID, u32 playVelocity, u32 playPan, u32 playCount)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3SMFPlay(smfID=%d, playVelocity=%d, playPan=%d, playCount=%d)", smfID, playVelocity, playPan, playCount);
return CELL_OK;
}
error_code cellSnd3SMFPlayEx(u32 smfID, u32 playVelocity, u32 playPan, u32 playPanEx, u32 playCount)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3SMFPlayEx(smfID=%d, playVelocity=%d, playPan=%d, playPanEx=%d, playCount=%d)", smfID, playVelocity, playPan, playPanEx, playCount);
return CELL_OK;
}
error_code cellSnd3SMFPause(u32 smfID)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3SMFPause(smfID=%d)", smfID);
return CELL_OK;
}
error_code cellSnd3SMFResume(u32 smfID)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3SMFResume(smfID=%d)", smfID);
return CELL_OK;
}
error_code cellSnd3SMFStop(u32 smfID)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3SMFStop(smfID=%d)", smfID);
return CELL_OK;
}
error_code cellSnd3SMFAddTempo(u32 smfID, s32 addTempo)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3SMFAddTempo(smfID=%d, addTempo=%d)", smfID, addTempo);
return CELL_OK;
}
error_code cellSnd3SMFGetTempo(u32 smfID)
{
libsnd3.todo("cellSnd3SMFGetTempo()");
libsnd3.todo("cellSnd3SMFGetTempo(smfID=%d)", smfID);
return CELL_OK;
}
error_code cellSnd3SMFSetPlayVelocity(u32 smfID, u32 playVelocity)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3SMFSetPlayVelocity(smfID=%d, playVelocity=%d)", smfID, playVelocity);
return CELL_OK;
}
error_code cellSnd3SMFGetPlayVelocity(u32 smfID)
{
libsnd3.todo("cellSnd3SMFGetPlayVelocity()");
libsnd3.todo("cellSnd3SMFGetPlayVelocity(smfID=%d)", smfID);
return CELL_OK;
}
error_code cellSnd3SMFSetPlayPanpot(u32 smfID, u32 playPanpot)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3SMFSetPlayPanpot(smfID=%d, playPanpot=%d)", smfID, playPanpot);
return CELL_OK;
}
error_code cellSnd3SMFSetPlayPanpotEx(u32 smfID, u32 playPanpotEx)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3SMFSetPlayPanpotEx(smfID=%d, playPanpotEx=%d)", smfID, playPanpotEx);
return CELL_OK;
}
error_code cellSnd3SMFGetPlayPanpot(u32 smfID)
{
libsnd3.todo("cellSnd3SMFGetPlayPanpot()");
libsnd3.todo("cellSnd3SMFGetPlayPanpot(smfID=%d)", smfID);
return CELL_OK;
}
error_code cellSnd3SMFGetPlayPanpotEx(u32 smfID)
{
libsnd3.todo("cellSnd3SMFGetPlayPanpotEx()");
libsnd3.todo("cellSnd3SMFGetPlayPanpotEx(smfID=%d)", smfID);
return CELL_OK;
}
error_code cellSnd3SMFGetPlayStatus(u32 smfID)
{
libsnd3.todo("cellSnd3SMFGetPlayStatus()");
libsnd3.todo("cellSnd3SMFGetPlayStatus(smfID=%d)", smfID);
return CELL_OK;
}
error_code cellSnd3SMFSetPlayChannel(u32 smfID, u32 playChannelBit)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3SMFSetPlayChannel(smfID=%d, playChannelBit=%d)", smfID, playChannelBit);
return CELL_OK;
}
error_code cellSnd3SMFGetPlayChannel(u32 smfID, vm::ptr<u32> playChannelBit)
{
libsnd3.todo("cellSnd3SMFGetPlayChannel()");
libsnd3.todo("cellSnd3SMFGetPlayChannel(smfID=%d, playChannelBit=*0x%x)", smfID, playChannelBit);
return CELL_OK;
}
error_code cellSnd3SMFGetKeyOnID(u32 smfID, u32 midiChannel, vm::ptr<u32> keyOnID)
{
UNIMPLEMENTED_FUNC(libsnd3);
libsnd3.todo("cellSnd3SMFAddTempo(smfID=%d, midiChannel=%d, keyOnID=*0x%x)", smfID, midiChannel, keyOnID);
return CELL_OK;
}

View File

@@ -1,11 +1,9 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/system_utils.hpp"
#include "Emu/VFS.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/Cell/Modules/cellUserInfo.h"
#include "Emu/Io/interception.h"
#include "Emu/NP/signaling_handler.h"
#include "Utilities/StrUtil.h"
#include "sysPrxForUser.h"
@@ -16,6 +14,7 @@
#include "sceNp.h"
#include "cellSysutil.h"
#include "Emu/Cell/timers.hpp"
#include "Emu/Cell/lv2/sys_time.h"
#include "Emu/Cell/lv2/sys_fs.h"
#include "Emu/Cell/lv2/sys_sync.h"
@@ -23,6 +22,7 @@
#include "Emu/NP/np_contexts.h"
#include "Emu/NP/np_helpers.h"
#include "Emu/NP/np_structs_extra.h"
#include "Emu/NP/signaling_handler.h"
#include "Emu/system_config.h"
#include "Emu/RSX/Overlays/overlay_manager.h"

View File

@@ -592,7 +592,6 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle,
// open trophy pack file
std::string trp_path = vfs::get(Emu.GetDir() + "TROPDIR/" + ctxt->trp_name + "/TROPHY.TRP");
fs::file stream;
if(Emu.GetIsoFs()&&trp_path[0]==':')
stream=fs::file(*Emu.GetIsoFs(), trp_path);
@@ -721,9 +720,9 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle,
lock2.unlock();
struct register_context_thread : register_context_thread_name
lv2_obj::sleep(ppu);
{
void operator()(s32 progress_cb_count, u32 context, vm::ptr<SceNpTrophyStatusCallback> statusCb, vm::ptr<void> arg) const
const s32 progress_cb_count = ::narrow<s32>(tropusr->GetTrophiesCount()) - 1;
{
// This emulates vsh sending the events and ensures that not 2 events are processed at once
const std::pair<SceNpTrophyStatus, s32> statuses[] =
@@ -737,6 +736,13 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle,
// Create a counter which is destroyed after the function ends
const auto queued = std::make_shared<atomic_t<u32>>(0);
u32 total_events = 0;
for (auto status : statuses)
{
total_events += status.second + 1;
}
for (auto status : statuses)
{
for (s32 completed = 0; completed <= status.second; completed++)
@@ -759,8 +765,9 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle,
u64 current = get_system_time();
const u64 until_max = current + 300'000;
const u64 until_min = current + 100'000;
// Minimum register trophy time 2 seconds globally.
const u64 until_min = current + (2'000'000 / total_events);
const u64 until_max = until_min + 50'000;
// If too much time passes just send the rest of the events anyway
for (u32 old_value = *queued; current < (old_value ? until_max : until_min);
@@ -777,19 +784,13 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle,
if (thread_ctrl::state() == thread_state::aborting)
{
return;
return {};
}
}
}
}
}
};
lv2_obj::sleep(ppu);
g_fxo->get<named_thread<register_context_thread>>()(::narrow<s32>(tropusr->GetTrophiesCount()) - 1, context, statusCb, arg);
thread_ctrl::wait_for(200'000);
}
return CELL_OK;
}

View File

@@ -2,8 +2,6 @@
#include "Emu/IdManager.h"
#include "Emu/Cell/PPUModule.h"
#include "sysPrxForUser.h"
LOG_CHANNEL(sysPrxForUser);
struct HeapInfo

View File

@@ -65,38 +65,33 @@ void fmt_class_string<CellLv2DbgError>::format(std::string& out, u64 arg)
});
}
// Temporarily
#ifndef _MSC_VER
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
error_code sys_dbg_read_ppu_thread_context(u64 id, vm::ptr<sys_dbg_ppu_thread_context_t> ppu_context)
{
sys_lv2dbg.todo("sys_dbg_read_ppu_thread_context()");
sys_lv2dbg.todo("sys_dbg_read_ppu_thread_context(id=0x%x, ppu_context=*0x%x)", id, ppu_context);
return CELL_OK;
}
error_code sys_dbg_read_spu_thread_context(u32 id, vm::ptr<sys_dbg_spu_thread_context_t> spu_context)
{
sys_lv2dbg.todo("sys_dbg_read_spu_thread_context()");
sys_lv2dbg.todo("sys_dbg_read_spu_thread_context(id=0x%x, spu_context=*0x%x)", id, spu_context);
return CELL_OK;
}
error_code sys_dbg_read_spu_thread_context2(u32 id, vm::ptr<sys_dbg_spu_thread_context2_t> spu_context)
{
sys_lv2dbg.todo("sys_dbg_read_spu_thread_context2()");
sys_lv2dbg.todo("sys_dbg_read_spu_thread_context2(id=0x%x, spu_context=*0x%x)", id, spu_context);
return CELL_OK;
}
error_code sys_dbg_set_stacksize_ppu_exception_handler(u32 stacksize)
{
sys_lv2dbg.todo("sys_dbg_set_stacksize_ppu_exception_handler()");
sys_lv2dbg.todo("sys_dbg_set_stacksize_ppu_exception_handler(stacksize=0x%x)", stacksize);
return CELL_OK;
}
error_code sys_dbg_initialize_ppu_exception_handler(s32 prio)
{
sys_lv2dbg.todo("sys_dbg_initialize_ppu_exception_handler()");
sys_lv2dbg.todo("sys_dbg_initialize_ppu_exception_handler(prio=0x%x)", prio);
return CELL_OK;
}
@@ -108,7 +103,7 @@ error_code sys_dbg_finalize_ppu_exception_handler()
error_code sys_dbg_register_ppu_exception_handler(vm::ptr<dbg_exception_handler_t> callback, u64 ctrl_flags)
{
sys_lv2dbg.todo("sys_dbg_register_ppu_exception_handler()");
sys_lv2dbg.todo("sys_dbg_register_ppu_exception_handler(callback=*0x%x, ctrl_flags=0x%x)", callback, ctrl_flags);
return CELL_OK;
}
@@ -120,170 +115,163 @@ error_code sys_dbg_unregister_ppu_exception_handler()
error_code sys_dbg_signal_to_ppu_exception_handler(u64 flags)
{
sys_lv2dbg.todo("sys_dbg_signal_to_ppu_exception_handler()");
sys_lv2dbg.todo("sys_dbg_signal_to_ppu_exception_handler(flags=0x%x)", flags);
return CELL_OK;
}
error_code sys_dbg_get_mutex_information(u32 id, vm::ptr<sys_dbg_mutex_information_t> info)
{
sys_lv2dbg.todo("sys_dbg_get_mutex_information()");
sys_lv2dbg.todo("sys_dbg_get_mutex_information(id=0x%x, info=*0x%x)", id, info);
return CELL_OK;
}
error_code sys_dbg_get_cond_information(u32 id, vm::ptr<sys_dbg_cond_information_t> info)
{
sys_lv2dbg.todo("sys_dbg_get_cond_information()");
sys_lv2dbg.todo("sys_dbg_get_cond_information(id=0x%x, info=*0x%x)", id, info);
return CELL_OK;
}
error_code sys_dbg_get_rwlock_information(u32 id, vm::ptr<sys_dbg_rwlock_information_t> info)
{
sys_lv2dbg.todo("sys_dbg_get_rwlock_information()");
sys_lv2dbg.todo("sys_dbg_get_rwlock_information(id=0x%x, info=*0x%x)", id, info);
return CELL_OK;
}
error_code sys_dbg_get_event_queue_information(u32 id, vm::ptr<sys_dbg_event_queue_information_t> info)
{
sys_lv2dbg.todo("sys_dbg_get_event_queue_information()");
sys_lv2dbg.todo("sys_dbg_get_event_queue_information(id=0x%x, info=*0x%x)", id, info);
return CELL_OK;
}
error_code sys_dbg_get_semaphore_information(u32 id, vm::ptr<sys_dbg_semaphore_information_t> info)
{
sys_lv2dbg.todo("sys_dbg_get_semaphore_information()");
sys_lv2dbg.todo("sys_dbg_get_semaphore_information(id=0x%x, info=*0x%x)", id, info);
return CELL_OK;
}
error_code sys_dbg_get_lwmutex_information(u32 id, vm::ptr<sys_dbg_lwmutex_information_t> info)
{
sys_lv2dbg.todo("sys_dbg_get_lwmutex_information()");
sys_lv2dbg.todo("sys_dbg_get_lwmutex_information(id=0x%x, info=*0x%x)", id, info);
return CELL_OK;
}
error_code sys_dbg_get_lwcond_information(u32 id, vm::ptr<sys_dbg_lwcond_information_t> info)
{
sys_lv2dbg.todo("sys_dbg_get_lwcond_information()");
sys_lv2dbg.todo("sys_dbg_get_lwcond_information(id=0x%x, info=*0x%x)", id, info);
return CELL_OK;
}
error_code sys_dbg_get_event_flag_information(u32 id, vm::ptr<sys_dbg_event_flag_information_t> info)
{
sys_lv2dbg.todo("sys_dbg_get_event_flag_information()");
sys_lv2dbg.todo("sys_dbg_get_event_flag_information(id=0x%x, info=*0x%x)", id, info);
return CELL_OK;
}
error_code sys_dbg_get_ppu_thread_ids(vm::ptr<u64> ids, vm::ptr<u64> ids_num, vm::ptr<u64> all_ids_num)
{
sys_lv2dbg.todo("sys_dbg_get_ppu_thread_ids()");
sys_lv2dbg.todo("sys_dbg_get_ppu_thread_ids(ids=*0x%x, ids_num=*0x%x, all_ids_num=*0x%x)", ids, ids_num, all_ids_num);
return CELL_OK;
}
error_code sys_dbg_get_spu_thread_group_ids(vm::ptr<u32> ids, vm::ptr<u64> ids_num, vm::ptr<u64> all_ids_num)
{
sys_lv2dbg.todo("sys_dbg_get_spu_thread_group_ids()");
sys_lv2dbg.todo("sys_dbg_get_spu_thread_group_ids(ids=*0x%x, ids_num=*0x%x, all_ids_num=*0x%x)", ids, ids_num, all_ids_num);
return CELL_OK;
}
error_code sys_dbg_get_spu_thread_ids(u32 group_id, vm::ptr<u32> ids, vm::ptr<u64> ids_num, vm::ptr<u64> all_ids_num)
{
sys_lv2dbg.todo("sys_dbg_get_spu_thread_ids()");
sys_lv2dbg.todo("sys_dbg_get_spu_thread_ids(group_id=0x%x, ids=*0x%x, ids_num=*0x%x, all_ids_num=*0x%x)", group_id, ids, ids_num, all_ids_num);
return CELL_OK;
}
error_code sys_dbg_get_ppu_thread_name(u64 id, vm::ptr<char> name)
{
sys_lv2dbg.todo("sys_dbg_get_ppu_thread_name()");
sys_lv2dbg.todo("sys_dbg_get_ppu_thread_name(id=0x%x, name=*0x%x)", id, name);
return CELL_OK;
}
error_code sys_dbg_get_spu_thread_name(u32 id, vm::ptr<char> name)
{
sys_lv2dbg.todo("sys_dbg_get_spu_thread_name()");
sys_lv2dbg.todo("sys_dbg_get_spu_thread_name(id=0x%x, name=*0x%x)", id, name);
return CELL_OK;
}
error_code sys_dbg_get_spu_thread_group_name(u32 id, vm::ptr<char> name)
{
sys_lv2dbg.todo("sys_dbg_get_spu_thread_group_name()");
sys_lv2dbg.todo("sys_dbg_get_spu_thread_group_name(id=0x%x, name=*0x%x)", id, name);
return CELL_OK;
}
error_code sys_dbg_get_ppu_thread_status(u64 id, vm::ptr<u32> status)
{
sys_lv2dbg.todo("sys_dbg_get_ppu_thread_status()");
sys_lv2dbg.todo("sys_dbg_get_ppu_thread_status(id=0x%x, status=*0x%x)", id, status);
return CELL_OK;
}
error_code sys_dbg_get_spu_thread_group_status(u32 id, vm::ptr<u32> status)
{
sys_lv2dbg.todo("sys_dbg_get_spu_thread_group_status()");
sys_lv2dbg.todo("sys_dbg_get_spu_thread_group_status(id=0x%x, status=*0x%x)", id, status);
return CELL_OK;
}
error_code sys_dbg_enable_floating_point_enabled_exception(u64 id, u64 flags, u64 opt1, u64 opt2)
{
sys_lv2dbg.todo("sys_dbg_enable_floating_point_enabled_exception()");
sys_lv2dbg.todo("sys_dbg_enable_floating_point_enabled_exception(id=0x%x, flags=0x%x, opt1=0x%x, opt2=0x%x)", id, flags, opt1, opt2);
return CELL_OK;
}
error_code sys_dbg_disable_floating_point_enabled_exception(u64 id, u64 flags, u64 opt1, u64 opt2)
{
sys_lv2dbg.todo("sys_dbg_disable_floating_point_enabled_exception()");
sys_lv2dbg.todo("sys_dbg_disable_floating_point_enabled_exception(id=0x%x, flags=0x%x, opt1=0x%x, opt2=0x%x)", id, flags, opt1, opt2);
return CELL_OK;
}
error_code sys_dbg_vm_get_page_information(u32 addr, u32 num, vm::ptr<sys_vm_page_information_t> pageinfo)
{
sys_lv2dbg.todo("sys_dbg_vm_get_page_information()");
sys_lv2dbg.todo("sys_dbg_vm_get_page_information(addr=0x%x, num=0x%x, pageinfo=*0x%x)", addr, num, pageinfo);
return CELL_OK;
}
error_code sys_dbg_set_address_to_dabr(u64 addr, u64 ctrl_flag)
{
sys_lv2dbg.todo("sys_dbg_set_address_to_dabr()");
sys_lv2dbg.todo("sys_dbg_set_address_to_dabr(addr=0x%x, spu_context=0x%x)", addr, ctrl_flag);
return CELL_OK;
}
error_code sys_dbg_get_address_from_dabr(vm::ptr<u64> addr, vm::ptr<u64> ctrl_flag)
{
sys_lv2dbg.todo("sys_dbg_get_address_from_dabr()");
sys_lv2dbg.todo("sys_dbg_get_address_from_dabr(addr=*0x%x, spu_context=*0x%x)", addr, ctrl_flag);
return CELL_OK;
}
error_code sys_dbg_signal_to_coredump_handler(u64 data1, u64 data2, u64 data3)
{
sys_lv2dbg.todo("sys_dbg_signal_to_coredump_handler()");
sys_lv2dbg.todo("sys_dbg_signal_to_coredump_handler(data1=0x%x, data2=0x%x, data3=0x%x)", data1, data2, data3);
return CELL_OK;
}
error_code sys_dbg_mat_set_condition(u32 addr, u64 cond)
{
sys_lv2dbg.todo("sys_dbg_mat_set_condition()");
sys_lv2dbg.todo("sys_dbg_mat_set_condition(addr=0x%x, cond=0x%x)", addr, cond);
return CELL_OK;
}
error_code sys_dbg_mat_get_condition(u32 addr, vm::ptr<u64> condp)
{
sys_lv2dbg.todo("sys_dbg_mat_get_condition()");
sys_lv2dbg.todo("sys_dbg_mat_get_condition(addr=0x%x, condp=*0x%x)", addr, condp);
return CELL_OK;
}
error_code sys_dbg_get_coredump_params(vm::ptr<s32> param)
{
sys_lv2dbg.todo("sys_dbg_get_coredump_params()");
sys_lv2dbg.todo("sys_dbg_get_coredump_params(param=*0x%x)", param);
return CELL_OK;
}
error_code sys_dbg_set_mask_to_ppu_exception_handler(u64 mask, u64 flags)
{
sys_lv2dbg.todo("sys_dbg_set_mask_to_ppu_exception_handler()");
sys_lv2dbg.todo("sys_dbg_set_mask_to_ppu_exception_handler(mask=0x%x, flags=0x%x)", mask, flags);
return CELL_OK;
}

View File

@@ -2,7 +2,7 @@
#include "Emu/System.h"
#include "Emu/system_config.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/Cell/timers.hpp"
#include "Emu/Cell/lv2/sys_lwmutex.h"
#include "Emu/Cell/lv2/sys_mutex.h"
#include "sysPrxForUser.h"

View File

@@ -7,8 +7,6 @@
#include "Emu/Cell/lv2/sys_mutex.h"
#include "Emu/Cell/lv2/sys_cond.h"
#include "sysPrxForUser.h"
LOG_CHANNEL(sysPrxForUser);
using sys_mempool_t = u32;

View File

@@ -1,16 +1,9 @@
#include "stdafx.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/IdManager.h"
#include "sys_net_.h"
LOG_CHANNEL(libnet);
// Temporarily
#ifndef _MSC_VER
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
s32 sys_net_accept(s32 s, vm::ptr<sys_net_sockaddr> addr, vm::ptr<u32> paddrlen)
{
libnet.todo("accept(s=%d, addr=*0x%x, paddrlen=*0x%x)", s, addr, paddrlen);
@@ -46,19 +39,22 @@ s32 sys_net_gethostbyname()
s32 sys_net_getpeername(s32 s, vm::ptr<sys_net_sockaddr> addr, vm::ptr<u32> paddrlen)
{
UNIMPLEMENTED_FUNC(libnet);
libnet.todo("getpeername(s=%d, addr=*0x%x, paddrlen=*0x%x)", s, addr, paddrlen);
return CELL_OK;
}
s32 sys_net_getsockname(s32 s, vm::ptr<sys_net_sockaddr> addr, vm::ptr<u32> paddrlen)
{
UNIMPLEMENTED_FUNC(libnet);
libnet.todo("getsockname(s=%d, addr=*0x%x, paddrlen=*0x%x)", s, addr, paddrlen);
return CELL_OK;
}
s32 sys_net_getsockopt(s32 s, s32 level, s32 optname, vm::ptr<void> optval, vm::ptr<u32> optlen)
{
UNIMPLEMENTED_FUNC(libnet);
libnet.todo("getsockopt(s=%d, level=%d, optname=%d, optval=*0x%x, optlen=*0x%x)", s, level, optname, optval, optlen);
return CELL_OK;
}
@@ -143,7 +139,8 @@ s32 sys_net_recvfrom(s32 s, vm::ptr<void> buf, u32 len, s32 flags, vm::ptr<sys_n
s32 sys_net_recvmsg(s32 s, vm::ptr<sys_net_msghdr> msg, s32 flags)
{
UNIMPLEMENTED_FUNC(libnet);
libnet.todo("recvmsg(s=%d, msg=*0x%x, flags=0x%x)", s, msg, flags);
return CELL_OK;
}
@@ -156,7 +153,8 @@ s32 sys_net_send(s32 s, vm::cptr<void> buf, u32 len, s32 flags)
s32 sys_net_sendmsg(s32 s, vm::cptr<sys_net_msghdr> msg, s32 flags)
{
UNIMPLEMENTED_FUNC(libnet);
libnet.todo("sendmsg(s=%d, msg=*0x%x, flags=0x%x)", s, msg, flags);
return CELL_OK;
}
@@ -197,7 +195,8 @@ s32 sys_net_socketclose(s32 s)
s32 sys_net_socketpoll(vm::ptr<sys_net_pollfd> fds, s32 nfds, s32 ms)
{
UNIMPLEMENTED_FUNC(libnet);
libnet.todo("socketpoll(fds=*0x%x, nfds=%d, ms=%d)", fds, nfds, ms);
return CELL_OK;
}
@@ -272,7 +271,8 @@ s32 sys_net_get_sockinfo(s32 s, vm::ptr<sys_net_sockinfo_t> p, s32 n)
s32 sys_net_close_dump(s32 id, vm::ptr<s32> pflags)
{
UNIMPLEMENTED_FUNC(libnet);
libnet.todo("sys_net_close_dump(id=%d, pflags=*0x%x)", id, pflags);
return CELL_OK;
}
@@ -310,7 +310,8 @@ s32 sys_net_show_route()
s32 sys_net_read_dump(s32 id, vm::ptr<void> buf, s32 len, vm::ptr<s32> pflags)
{
UNIMPLEMENTED_FUNC(libnet);
libnet.todo("sys_net_read_dump(id=%d, buf=*0x%x, len=%d, pflags=*0x%x)", id, buf, len, pflags);
return CELL_OK;
}
@@ -346,7 +347,8 @@ s32 sys_net_get_sockinfo_ex()
s32 sys_net_open_dump(s32 len, s32 flags)
{
UNIMPLEMENTED_FUNC(libnet);
libnet.todo("sys_net_open_dump(len=%d, flags=0x%x)", len, flags);
return CELL_OK;
}

View File

@@ -1,7 +1,6 @@
#pragma once
#include "Emu/Cell/lv2/sys_net.h"
#include "Emu/Memory/vm.h"
struct sys_net_sockinfo_t
{

View File

@@ -1,7 +1,5 @@
#include "stdafx.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/IdManager.h"
#include "Emu/Cell/lv2/sys_ppu_thread.h"
#include "Emu/Cell/lv2/sys_interrupt.h"
#include "Emu/Cell/lv2/sys_lwmutex.h"

View File

@@ -1,8 +1,6 @@
#include "stdafx.h"
#include "Emu/Cell/PPUModule.h"
#include "sysPrxForUser.h"
LOG_CHANNEL(sysPrxForUser);
error_code sys_rsxaudio_close_connection()

View File

@@ -1,8 +1,6 @@
#include "stdafx.h"
#include "Emu/Cell/PPUModule.h"
#include "sysPrxForUser.h"
LOG_CHANNEL(sysPrxForUser);
void sys_spinlock_initialize(vm::ptr<atomic_be_t<u32>> lock)

View File

@@ -3,7 +3,6 @@
#include "Emu/Cell/PPUModule.h"
#include "Emu/Cell/lv2/sys_spu.h"
#include "Crypto/unself.h"
#include "Loader/ELF.h"
#include "sysPrxForUser.h"

View File

@@ -532,7 +532,7 @@ namespace ppu_patterns
}
static constexpr struct const_tag{} is_const;
static constexpr struct range_tag{} is_range;
/*static constexpr*/ struct range_tag{} /*is_range*/;
static constexpr struct min_value_tag{} minv;
static constexpr struct max_value_tag{} maxv;
static constexpr struct sign_bit_tag{} sign_bitv;
@@ -2361,7 +2361,9 @@ bool ppu_module<lv2_obj>::analyse(u32 lib_toc, u32 entry, const u32 sec_end, con
}
case ppu_itype::MTSPR:
{
switch (const u32 n = (op.spr >> 5) | ((op.spr & 0x1f) << 5))
const u32 spr_idx = (op.spr >> 5) | ((op.spr & 0x1f) << 5);
switch (spr_idx)
{
case 0x001: // MTXER
{
@@ -2459,7 +2461,6 @@ bool ppu_module<lv2_obj>::analyse(u32 lib_toc, u32 entry, const u32 sec_end, con
const reg_state_t rb = get_reg(op.rb);
const bool is_ra = ra(is_const) && (ra(minv) >= start && ra(minv) < segs_end);
const bool is_rb = rb(is_const) && (rb(minv) >= start && rb(minv) < segs_end);
if (ra(is_const) == rb(is_const))
{

View File

@@ -1902,8 +1902,9 @@ auto gen_ghc_cpp_trampoline(ppu_intrp_func_t fn_target)
// Take second ghc arg
c.mov(args[0], x86::rbp);
c.mov(args[2].r32(), x86::dword_ptr(args[0], ::offset32(&ppu_thread::cia)));
c.add(args[2], x86::qword_ptr(reinterpret_cast<u64>(&vm::g_base_addr)));
c.jmp(fn_target);
c.movabs(args[1], reinterpret_cast<u64>(&vm::g_base_addr));
c.add(args[2], x86::qword_ptr(args[1]));
c.jmp(Imm(fn_target));
};
}

View File

@@ -192,13 +192,13 @@ namespace ppu_func_detail
const u32 v_count = (info.last_value >> 24);
// TODO: check calculations
const bool is_float = std::is_floating_point_v<T>;
const bool is_vector = std::is_same_v<std::decay_t<T>, v128>;
const bool is_context = std::is_base_of_v<std::decay_t<T>, ppu_thread>;
const bool is_variadic = std::is_same_v<std::decay_t<T>, ppu_va_args_t>;
const bool is_general = !is_float && !is_vector && !is_context && !is_variadic;
constexpr bool is_float = std::is_floating_point_v<T>;
constexpr bool is_vector = std::is_same_v<std::decay_t<T>, v128>;
constexpr bool is_context = std::is_base_of_v<std::decay_t<T>, ppu_thread>;
constexpr bool is_variadic = std::is_same_v<std::decay_t<T>, ppu_va_args_t>;
constexpr bool is_general = !is_float && !is_vector && !is_context && !is_variadic;
const arg_class t =
constexpr arg_class t =
is_general ? (g_count >= 8 ? ARG_STACK : ARG_GENERAL) :
is_float ? (f_count >= 13 ? ARG_STACK : ARG_FLOAT) :
is_vector ? (v_count >= 12 ? ARG_STACK : ARG_VECTOR) :
@@ -206,9 +206,9 @@ namespace ppu_func_detail
is_variadic ? ARG_VARIADIC :
ARG_UNKNOWN;
const u32 g = g_count + (is_general || is_float ? 1 : is_vector ? (g_count & 1) + 2 : 0);
const u32 f = f_count + is_float;
const u32 v = v_count + is_vector;
constexpr u32 g = g_count + (is_general || is_float ? 1 : is_vector ? (g_count & 1) + 2 : 0);
constexpr u32 f = f_count + is_float;
constexpr u32 v = v_count + is_vector;
return call<Types...>(ppu, func, arg_info_pack_t<Info..., t | (g << 8) | (f << 16) | (v << 24)>{});
}
@@ -218,9 +218,9 @@ namespace ppu_func_detail
{
static_assert(!std::is_pointer_v<RT>, "Invalid function result type (pointer)");
static_assert(!std::is_reference_v<RT>, "Invalid function result type (reference)");
static const bool is_float = std::is_floating_point_v<RT>;
static const bool is_vector = std::is_same_v<std::decay_t<RT>, v128>;
static const arg_class value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL);
static constexpr bool is_float = std::is_floating_point_v<RT>;
static constexpr bool is_vector = std::is_same_v<std::decay_t<RT>, v128>;
static constexpr arg_class value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL);
};
template<typename RT, typename... T> struct func_binder;

View File

@@ -1171,7 +1171,9 @@ static void ppu_check_patch_spu_images(const ppu_module<lv2_obj>& mod, const ppu
auto find_first_of_multiple = [](std::string_view data, std::initializer_list<std::string_view> values, usz index)
{
u32 pos = static_cast<u32>(data.size());
u32 pos = umax;
ensure(data.size() <= pos && index <= data.size());
for (std::string_view value : values)
{
@@ -1191,65 +1193,74 @@ static void ppu_check_patch_spu_images(const ppu_module<lv2_obj>& mod, const ppu
u32 prev_bound = 0;
for (u32 i = find_first_of_multiple(seg_view, prefixes, 0); i < seg.size; i = find_first_of_multiple(seg_view, prefixes, utils::align<u32>(i + 1, 4)))
for (u32 prefix_addr = find_first_of_multiple(seg_view, prefixes, 0); prefix_addr < seg.size; prefix_addr = find_first_of_multiple(seg_view, prefixes, prefix_addr + 4))
{
const auto elf_header = ensure(mod.get_ptr<u8>(seg.addr + i));
const auto elf_header = ensure(mod.get_ptr<u8>(seg.addr + prefix_addr));
if (i % 4 == 0 && std::memcmp(elf_header, "\x24\0\x40\x80", 4) == 0)
if (std::memcmp(elf_header, "\x24\0\x40\x80", 4) == 0)
{
bool next = true;
const u32 old_i = i;
u32 guid_start = umax, guid_end = umax;
const u32 old_prefix_addr = prefix_addr;
for (u32 search = i & -128, tries = 10; tries && search >= prev_bound; tries--, search = utils::sub_saturate<u32>(search, 128))
auto search_guid_pattern = [&](u32 index, std::string_view data_span, s32 advance_index, u32 lower_bound, u32 uppper_bound) -> u32
{
if (seg_view[search] != 0x42 && seg_view[search] != 0x43)
for (u32 search = index & -16, tries = 16 * 64; tries && search >= lower_bound && search < uppper_bound; tries = tries - 1, search = advance_index < 0 ? utils::sub_saturate<u32>(search, 0 - advance_index) : search + advance_index)
{
continue;
}
const u32 inst1 = read_from_ptr<be_t<u32>>(seg_view, search);
const u32 inst2 = read_from_ptr<be_t<u32>>(seg_view, search + 4);
const u32 inst3 = read_from_ptr<be_t<u32>>(seg_view, search + 8);
const u32 inst4 = read_from_ptr<be_t<u32>>(seg_view, search + 12);
if ((inst1 & 0xfe'00'00'7f) != 0x42000002 || (inst2 & 0xfe'00'00'7f) != 0x42000002 || (inst3 & 0xfe'00'00'7f) != 0x42000002 || (inst4 & 0xfe'00'00'7f) != 0x42000002)
{
continue;
}
guid_start = search + seg.addr;
i = search;
next = false;
break;
}
if (next)
{
continue;
}
std::string_view ls_segment = seg_view.substr(i);
// Bound to a bit less than LS size
ls_segment = ls_segment.substr(0, 0x38000);
for (u32 addr_last = 0, valid_count = 0, invalid_count = 0;;)
{
const u32 instruction = static_cast<u32>(ls_segment.find("\x24\0\x40\x80"sv, addr_last));
if (instruction != umax)
{
if (instruction % 4 != i % 4)
if (seg_view[search] != 0x42 && seg_view[search] != 0x43)
{
// Unaligned, continue
addr_last = instruction + (i % 4 - instruction % 4) % 4;
continue;
}
// FIXME: This seems to terminate SPU code prematurely in some cases
// Likely due to absolute branches
if (spu_thread::is_exec_code(instruction, {reinterpret_cast<const u8*>(ls_segment.data()), ls_segment.size()}, 0))
const u32 inst1 = read_from_ptr<be_t<u32>>(data_span, search);
const u32 inst2 = read_from_ptr<be_t<u32>>(data_span, search + 4);
const u32 inst3 = read_from_ptr<be_t<u32>>(data_span, search + 8);
const u32 inst4 = read_from_ptr<be_t<u32>>(data_span, search + 12);
if ((inst1 & 0xfe'00'00'7f) != 0x42000002 || (inst2 & 0xfe'00'00'7f) != 0x42000002 || (inst3 & 0xfe'00'00'7f) != 0x42000002 || (inst4 & 0xfe'00'00'7f) != 0x42000002)
{
continue;
}
if (!spu_thread::is_exec_code(search, {reinterpret_cast<const u8*>(data_span.data()), data_span.size()}, 0, true, true))
{
continue;
}
return search;
}
return umax;
};
prefix_addr = search_guid_pattern(prefix_addr, seg_view, -16, prev_bound, seg.size);
if (prefix_addr == umax)
{
prefix_addr = old_prefix_addr;
continue;
}
u32 guid_start = seg.addr + prefix_addr, guid_end = umax;
std::string_view ls_segment = seg_view.substr(prefix_addr);
// Bound to a bit less than LS size
ls_segment = ls_segment.substr(0, SPU_LS_SIZE - 0x8000);
for (u32 addr_last = 0, valid_count = 0, invalid_count = 0;;)
{
const u32 instruction = std::min<u32>(search_guid_pattern(addr_last, ls_segment, +16, 0, ::size32(ls_segment)), find_first_of_multiple(ls_segment, prefixes, addr_last));
if (instruction != umax && std::memcmp(ls_segment.data() + instruction, "\x24\0\x40\x80", 4) == 0)
{
if (instruction % 4 != prefix_addr % 4)
{
// Unaligned, continue
addr_last = instruction + (prefix_addr % 4 - instruction % 4) % 4;
continue;
}
// Check execution compatibility
if (spu_thread::is_exec_code(instruction, {reinterpret_cast<const u8*>(ls_segment.data()), ls_segment.size()}, 0, true, true))
{
addr_last = instruction + 4;
valid_count++;
@@ -1270,8 +1281,7 @@ static void ppu_check_patch_spu_images(const ppu_module<lv2_obj>& mod, const ppu
if (addr_last >= 0x80 && valid_count >= 2)
{
const u32 begin = i & -128;
u32 end = std::min<u32>(seg.size, utils::align<u32>(i + addr_last + 256, 128));
u32 end = std::min<u32>({instruction, seg.size - prefix_addr, utils::align<u32>(addr_last + 256, 128)});
u32 guessed_ls_addr = 0;
@@ -1279,12 +1289,12 @@ static void ppu_check_patch_spu_images(const ppu_module<lv2_obj>& mod, const ppu
// ILA R2, PC + 8
// BIE/BID R2
for (u32 found = 0, last_vaddr = 0, it = begin + 16; it < end - 16; it += 4)
for (u32 found = 0, last_vaddr = 0, it = 16; it < end - 16; it += 4)
{
const u32 inst1 = read_from_ptr<be_t<u32>>(seg_view, it);
const u32 inst2 = read_from_ptr<be_t<u32>>(seg_view, it + 4);
const u32 inst3 = read_from_ptr<be_t<u32>>(seg_view, it + 8);
const u32 inst4 = read_from_ptr<be_t<u32>>(seg_view, it + 12);
const u32 inst1 = read_from_ptr<be_t<u32>>(ls_segment, it);
const u32 inst2 = read_from_ptr<be_t<u32>>(ls_segment, it + 4);
const u32 inst3 = read_from_ptr<be_t<u32>>(ls_segment, it + 8);
const u32 inst4 = read_from_ptr<be_t<u32>>(ls_segment, it + 12);
if ((inst1 & 0xfe'00'00'7f) == 0x42000002 && (inst2 & 0xfe'00'00'7f) == 0x42000002 && (inst3 & 0xfe'00'00'7f) == 0x42000002 && (inst4 & 0xfe'00'00'7f) == 0x42000002)
{
@@ -1298,7 +1308,7 @@ static void ppu_check_patch_spu_images(const ppu_module<lv2_obj>& mod, const ppu
{
const u32 addr_inst = (inst1 >> 7) % 0x40000;
if (u32 addr_seg = addr_inst - std::min<u32>(it + 8 - begin, addr_inst))
if (u32 addr_seg = addr_inst - std::min<u32>(it + 8, addr_inst))
{
if (last_vaddr != addr_seg)
{
@@ -1321,23 +1331,27 @@ static void ppu_check_patch_spu_images(const ppu_module<lv2_obj>& mod, const ppu
if (guessed_ls_addr)
{
end = begin + std::min<u32>(end - begin, SPU_LS_SIZE - guessed_ls_addr);
end = prefix_addr + std::min<u32>(end, SPU_LS_SIZE - guessed_ls_addr);
}
else
{
end = prefix_addr + std::min<u32>(end, SPU_LS_SIZE);
}
ppu_log.success("Found valid roaming SPU code at 0x%x..0x%x (guessed_ls_addr=0x%x, GUID=0x%05x..0x%05x)", seg.addr + begin, seg.addr + end, guessed_ls_addr, guid_start, guid_end);
ppu_log.success("Found valid roaming SPU code at 0x%x..0x%x (guessed_ls_addr=0x%x, GUID=0x%05x..0x%05x)", seg.addr + prefix_addr, seg.addr + end, guessed_ls_addr, guid_start, guid_end);
if (!is_firmware && _main == &mod)
{
// Siginify that the base address is unknown by passing 0
utilize_spu_data_segment(guessed_ls_addr ? guessed_ls_addr : 0x4000, seg_view.data() + begin, end - begin);
utilize_spu_data_segment(guessed_ls_addr ? guessed_ls_addr : 0x4000, seg_view.data() + prefix_addr, end - prefix_addr);
}
i = std::max<u32>(end, i + 4) - 4;
prev_bound = i + 4;
prefix_addr = std::max<u32>(end, prefix_addr + 4) - 4;
prev_bound = prefix_addr + 4;
}
else
{
i = old_i;
prefix_addr = old_prefix_addr;
}
break;
@@ -1347,7 +1361,7 @@ static void ppu_check_patch_spu_images(const ppu_module<lv2_obj>& mod, const ppu
}
// Try to load SPU image
const spu_exec_object obj(fs::file(elf_header, seg.size - i));
const spu_exec_object obj(fs::file(elf_header, seg.size - prefix_addr));
if (obj != elf_error::ok)
{
@@ -1392,7 +1406,7 @@ static void ppu_check_patch_spu_images(const ppu_module<lv2_obj>& mod, const ppu
sha1_update(&sha2, (elf_header + prog.p_offset), prog.p_filesz);
// We assume that the string SPUNAME exists 0x14 bytes into the NOTE segment
name = ensure(mod.get_ptr<const char>(seg.addr + i + prog.p_offset + 0x14));
name = ensure(mod.get_ptr<const char>(seg.addr + prefix_addr + prog.p_offset + 0x14));
if (!name.empty())
{
@@ -1401,7 +1415,7 @@ static void ppu_check_patch_spu_images(const ppu_module<lv2_obj>& mod, const ppu
}
}
fmt::append(dump, " (image addr: 0x%x, size: 0x%x)", seg.addr + i, obj.highest_offset);
fmt::append(dump, " (image addr: 0x%x, size: 0x%x)", seg.addr + prefix_addr, obj.highest_offset);
sha1_finish(&sha2, sha1_hash);
@@ -1451,8 +1465,8 @@ static void ppu_check_patch_spu_images(const ppu_module<lv2_obj>& mod, const ppu
ppu_loader.success("SPU executable hash: %s (<- %u)%s", hash, applied.size(), dump);
}
i += ::narrow<u32>(obj.highest_offset) - 4;
prev_bound = i + 4;
prefix_addr += ::narrow<u32>(obj.highest_offset - 4);
prev_bound = prefix_addr + 4;
}
}
@@ -2141,6 +2155,8 @@ bool ppu_load_exec(const ppu_exec_object& elf, bool virtual_load, const std::str
const auto old_process_info = g_ps3_process_info;
u32 segs_size = 0;
// Allocate memory at fixed positions
for (const auto& prog : elf.progs)
{
@@ -2235,6 +2251,8 @@ bool ppu_load_exec(const ppu_exec_object& elf, bool virtual_load, const std::str
{
ppu_register_range(addr, size);
}
segs_size += utils::align<u32>(size + (addr % 0x10000), 0x10000);
}
}
@@ -2759,7 +2777,7 @@ bool ppu_load_exec(const ppu_exec_object& elf, bool virtual_load, const std::str
ppu->gpr[1] -= stack_alloc_size;
ensure(g_fxo->get<lv2_memory_container>().take(primary_stacksize));
ensure(g_fxo->get<lv2_memory_container>().take(primary_stacksize + segs_size));
ppu->cmd_push({ppu_cmd::initialize, 0});

View File

@@ -220,19 +220,21 @@ const auto ppu_gateway = build_function_asm<void(*)(ppu_thread*)>("ppu_gateway",
c.mov(x86::qword_ptr(args[0], ::offset32(&ppu_thread::hv_ctx, &rpcs3::hypervisor_context_t::regs)), x86::rsp);
// Initialize args
c.mov(x86::r13, x86::qword_ptr(reinterpret_cast<u64>(&vm::g_exec_addr)));
c.movabs(x86::r13, reinterpret_cast<u64>(&vm::g_exec_addr));
c.mov(x86::r13, x86::qword_ptr(x86::r13));
c.mov(x86::rbp, args[0]);
c.mov(x86::edx, x86::dword_ptr(x86::rbp, ::offset32(&ppu_thread::cia))); // Load PC
c.mov(x86::rax, x86::qword_ptr(x86::r13, x86::edx, 1, 0)); // Load call target
c.mov(x86::rdx, x86::rax);
c.shl(x86::rax, 16);
c.shr(x86::rax, 16);
c.shr(x86::rdx, 48);
c.mov(x86::rax, x86::qword_ptr(x86::r13, x86::rdx, 1, 0)); // Load call target
c.movabs(x86::r12, vm::g_exec_addr_seg_offset);
c.add(x86::r12, x86::r13);
c.shr(x86::edx, 1);
c.mov(x86::edx, x86::word_ptr(x86::r12, x86::edx)); // Load relocation base
c.shl(x86::edx, 13);
c.mov(x86::r12d, x86::edx); // Load relocation base
c.mov(x86::r12d, x86::edx); // Set relocation base
c.mov(x86::rbx, x86::qword_ptr(reinterpret_cast<u64>(&vm::g_base_addr)));
c.movabs(x86::rbx, reinterpret_cast<u64>(&vm::g_base_addr));
c.mov(x86::rbx, x86::qword_ptr(x86::rbx));
c.mov(x86::r14, x86::qword_ptr(x86::rbp, ::offset32(&ppu_thread::gpr, 0))); // Load some registers
c.mov(x86::rsi, x86::qword_ptr(x86::rbp, ::offset32(&ppu_thread::gpr, 1)));
c.mov(x86::rdi, x86::qword_ptr(x86::rbp, ::offset32(&ppu_thread::gpr, 2)));
@@ -346,14 +348,11 @@ const auto ppu_gateway = build_function_asm<void(*)(ppu_thread*)>("ppu_gateway",
c.ldr(call_target, arm::Mem(a64::x19, pc));
// Compute REG_Hp
const arm::GpX reg_hp = a64::x21;
c.mov(reg_hp, call_target);
c.lsr(reg_hp, reg_hp, 48);
c.mov(reg_hp, Imm(vm::g_exec_addr_seg_offset));
c.add(reg_hp, reg_hp, pc, arm::Shift(arm::ShiftOp::kLSR, 2));
c.ldrh(reg_hp.w(), arm::Mem(a64::x19, reg_hp));
c.lsl(reg_hp.w(), reg_hp.w(), 13);
// Zero top 16 bits of call target
c.lsl(call_target, call_target, Imm(16));
c.lsr(call_target, call_target, Imm(16));
// Load registers
c.mov(a64::x22, Imm(reinterpret_cast<u64>(&vm::g_base_addr)));
c.ldr(a64::x22, arm::Mem(a64::x22));
@@ -473,6 +472,11 @@ static inline u8* ppu_ptr(u32 addr)
return vm::g_exec_addr + u64{addr} * 2;
}
static inline u8* ppu_seg_ptr(u32 addr)
{
return vm::g_exec_addr + vm::g_exec_addr_seg_offset + (addr >> 1);
}
static inline ppu_intrp_func_t ppu_read(u32 addr)
{
return read_from_ptr<ppu_intrp_func_t>(ppu_ptr(addr));
@@ -518,7 +522,7 @@ void ppu_recompiler_fallback(ppu_thread& ppu)
while (true)
{
if (uptr func = uptr(ppu_read(ppu.cia)); (func << 16 >> 16) != reinterpret_cast<uptr>(ppu_recompiler_fallback_ghc))
if (uptr func = uptr(ppu_read(ppu.cia)); func != reinterpret_cast<uptr>(ppu_recompiler_fallback_ghc))
{
// We found a recompiler function at cia, return
break;
@@ -773,6 +777,9 @@ extern void ppu_register_range(u32 addr, u32 size)
utils::memory_commit(ppu_ptr(addr), u64{size} * 2, utils::protection::rw);
ensure(vm::page_protect(addr, size, 0, vm::page_executable));
// Segment data
utils::memory_commit(ppu_seg_ptr(addr), size >> 1, utils::protection::rw);
if (g_cfg.core.ppu_debug)
{
utils::memory_commit(vm::g_stat_addr + addr, size);
@@ -785,12 +792,13 @@ extern void ppu_register_range(u32 addr, u32 size)
if (g_cfg.core.ppu_decoder == ppu_decoder_type::llvm)
{
// Assume addr is the start of first segment of PRX
const uptr entry_value = reinterpret_cast<uptr>(ppu_recompiler_fallback_ghc) | (seg_base << (32 + 3));
write_to_ptr<uptr>(ppu_ptr(addr), entry_value);
write_to_ptr<uptr>(ppu_ptr(addr), std::bit_cast<uptr>(ppu_recompiler_fallback_ghc));
write_to_ptr<u16>(ppu_seg_ptr(addr), static_cast<u16>(seg_base >> 13));
}
else
{
write_to_ptr<ppu_intrp_func_t>(ppu_ptr(addr), ppu_fallback);
write_to_ptr<u16>(ppu_seg_ptr(addr), 0);
}
addr += 4;
@@ -805,7 +813,7 @@ extern void ppu_register_function_at(u32 addr, u32 size, ppu_intrp_func_t ptr =
// Initialize specific function
if (ptr)
{
write_to_ptr<uptr>(ppu_ptr(addr), (reinterpret_cast<uptr>(ptr) & 0xffff'ffff'ffffu) | (uptr(ppu_read(addr)) & ~0xffff'ffff'ffffu));
write_to_ptr<uptr>(ppu_ptr(addr), std::bit_cast<uptr>(ptr));
return;
}
@@ -3164,8 +3172,9 @@ const auto ppu_stcx_accurate_tx = build_function_asm<u64(*)(u32 raddr, u64 rtime
// Create stack frame if necessary (Windows ABI has only 6 volatile vector registers)
c.push(x86::rbp);
c.push(x86::r13);
c.push(x86::r14);
c.sub(x86::rsp, 40);
c.sub(x86::rsp, 48);
#ifdef _WIN32
if (!s_tsx_avx)
{
@@ -3176,14 +3185,16 @@ const auto ppu_stcx_accurate_tx = build_function_asm<u64(*)(u32 raddr, u64 rtime
// Prepare registers
build_swap_rdx_with(c, args, x86::r10);
c.mov(x86::rbp, x86::qword_ptr(reinterpret_cast<u64>(&vm::g_sudo_addr)));
c.movabs(x86::rbp, reinterpret_cast<u64>(&vm::g_sudo_addr));
c.mov(x86::rbp, x86::qword_ptr(x86::rbp));
c.lea(x86::rbp, x86::qword_ptr(x86::rbp, args[0]));
c.and_(x86::rbp, -128);
c.prefetchw(x86::byte_ptr(x86::rbp, 0));
c.prefetchw(x86::byte_ptr(x86::rbp, 64));
c.movzx(args[0].r32(), args[0].r16());
c.shr(args[0].r32(), 1);
c.lea(x86::r11, x86::qword_ptr(reinterpret_cast<u64>(+vm::g_reservations), args[0]));
c.movabs(x86::r11, reinterpret_cast<u64>(+vm::g_reservations));
c.lea(x86::r11, x86::qword_ptr(x86::r11, args[0]));
c.and_(x86::r11, -128 / 2);
c.and_(args[0].r32(), 63);
@@ -3217,7 +3228,8 @@ const auto ppu_stcx_accurate_tx = build_function_asm<u64(*)(u32 raddr, u64 rtime
{
build_get_tsc(c);
c.sub(x86::rax, stamp0);
c.cmp(x86::rax, x86::qword_ptr(reinterpret_cast<u64>(&g_rtm_tx_limit2)));
c.movabs(x86::r13, reinterpret_cast<u64>(&g_rtm_tx_limit2));
c.cmp(x86::rax, x86::qword_ptr(x86::r13));
c.jae(fall);
});
@@ -3342,8 +3354,9 @@ const auto ppu_stcx_accurate_tx = build_function_asm<u64(*)(u32 raddr, u64 rtime
c.vzeroupper();
}
c.add(x86::rsp, 40);
c.add(x86::rsp, 48);
c.pop(x86::r14);
c.pop(x86::r13);
c.pop(x86::rbp);
maybe_flush_lbr(c);
@@ -5079,17 +5092,18 @@ bool ppu_initialize(const ppu_module<lv2_obj>& info, bool check_only, u64 file_s
code_size_until_jump = buf_end - buf_start;
c.add(x86::edx, seg0);
c.mov(x86::rax, x86::qword_ptr(reinterpret_cast<u64>(&vm::g_exec_addr)));
c.movabs(x86::rax, reinterpret_cast<u64>(&vm::g_exec_addr));
c.mov(x86::rax, x86::qword_ptr(x86::rax));
c.mov(x86::dword_ptr(x86::rbp, ::offset32(&ppu_thread::cia)), x86::edx);
c.mov(x86::rax, x86::qword_ptr(x86::rax, x86::rdx, 1, 0)); // Load call target
c.mov(x86::rdx, x86::rax);
c.shl(x86::rax, 16);
c.shr(x86::rax, 16);
c.shr(x86::rdx, 48);
c.mov(x86::rcx, x86::qword_ptr(x86::rax, x86::rdx, 1, 0)); // Load call target
c.movabs(x86::r12, vm::g_exec_addr_seg_offset);
c.add(x86::rax, x86::r12);
c.shr(x86::edx, 1);
c.mov(x86::edx, x86::word_ptr(x86::rax, x86::edx)); // Load relocation base
c.shl(x86::edx, 13);
c.mov(x86::r12d, x86::edx); // Load relocation base
c.jmp(x86::rax);
c.mov(x86::r12d, x86::edx); // Set relocation base
c.jmp(x86::rcx);
#else
// Load REG_Base - use absolute jump target to bypass rel jmp range limits
// X19 contains vm::g_exec_addr
@@ -5125,14 +5139,11 @@ bool ppu_initialize(const ppu_module<lv2_obj>& info, bool check_only, u64 file_s
// Compute REG_Hp
const arm::GpX reg_hp = a64::x21;
c.mov(reg_hp, call_target);
c.lsr(reg_hp, reg_hp, 48);
c.mov(reg_hp, Imm(vm::g_exec_addr_seg_offset));
c.add(reg_hp, reg_hp, pc, arm::Shift(arm::ShiftOp::kLSR, 2));
c.ldrh(reg_hp.w(), arm::Mem(exec_addr, reg_hp));
c.lsl(reg_hp.w(), reg_hp.w(), 13);
// Zero top 16 bits of call target
c.lsl(call_target, call_target, 16);
c.lsr(call_target, call_target, 16);
// Execute LLE call
c.br(call_target);
#endif
@@ -5400,7 +5411,7 @@ bool ppu_initialize(const ppu_module<lv2_obj>& info, bool check_only, u64 file_s
settings += ppu_settings::contains_symbol_resolver; // Avoid invalidating all modules for this purpose
// Write version, hash, CPU, settings
fmt::append(obj_name, "v6-kusa-%s-%s-%s.obj", fmt::base57(output, 16), fmt::base57(settings), jit_compiler::cpu(g_cfg.core.llvm_cpu));
fmt::append(obj_name, "v7-kusa-%s-%s-%s.obj", fmt::base57(output, 16), fmt::base57(settings), jit_compiler::cpu(g_cfg.core.llvm_cpu));
}
if (cpu ? cpu->state.all_of(cpu_flag::exit) : Emu.IsStopped())
@@ -5712,7 +5723,7 @@ bool ppu_initialize(const ppu_module<lv2_obj>& info, bool check_only, u64 file_s
for (u32 addr = info.segs[0].addr; addr < info.segs[0].addr + info.segs[0].size; addr += 4, inst_ptr++)
{
if (*inst_ptr == ppu_instructions::BLR() && (reinterpret_cast<uptr>(ppu_read(addr)) << 16 >> 16) == reinterpret_cast<uptr>(ppu_recompiler_fallback_ghc))
if (*inst_ptr == ppu_instructions::BLR() && reinterpret_cast<uptr>(ppu_read(addr)) == reinterpret_cast<uptr>(ppu_recompiler_fallback_ghc))
{
write_to_ptr<ppu_intrp_func_t>(ppu_ptr(addr), BLR_func);
}

View File

@@ -411,12 +411,19 @@ Function* PPUTranslator::GetSymbolResolver(const ppu_module<lv2_obj>& info)
const auto faddr = m_ir->CreateLoad(ptr_inst->getResultElementType(), ptr_inst);
const auto faddr_int = m_ir->CreatePtrToInt(faddr, get_type<uptr>());
const auto fval = m_ir->CreateOr(m_ir->CreateShl(m_seg0, 32 + 3), faddr_int);
const auto pos = m_ir->CreateShl(m_reloc ? m_ir->CreateAdd(func_pc, m_seg0) : func_pc, 1);
const auto pos_32 = m_reloc ? m_ir->CreateAdd(func_pc, m_seg0) : func_pc;
const auto pos = m_ir->CreateShl(pos_32, 1);
const auto ptr = dyn_cast<GetElementPtrInst>(m_ir->CreateGEP(get_type<u8>(), m_exec, pos));
const auto seg_base_ptr = m_ir->CreateIntToPtr(m_ir->CreateAdd(
m_ir->CreatePtrToInt(m_exec, get_type<u64>()), m_ir->getInt64(vm::g_exec_addr_seg_offset)), m_exec->getType());
const auto seg_pos = m_ir->CreateLShr(pos_32, 1);
const auto seg_ptr = dyn_cast<GetElementPtrInst>(m_ir->CreateGEP(get_type<u8>(), seg_base_ptr, seg_pos));
const auto seg_val = m_ir->CreateTrunc(m_ir->CreateLShr(m_seg0, 13), get_type<u16>());
// Store to jumptable
m_ir->CreateStore(fval, ptr);
m_ir->CreateStore(faddr_int, ptr);
m_ir->CreateStore(seg_val, seg_ptr);
// Increment index and branch back to loop
const auto post_add = m_ir->CreateAdd(index_value, m_ir->getInt64(1));
@@ -605,10 +612,15 @@ void PPUTranslator::CallFunction(u64 target, Value* indirect)
const auto pos = m_ir->CreateShl(indirect, 1);
const auto ptr = dyn_cast<GetElementPtrInst>(m_ir->CreateGEP(get_type<u8>(), m_exec, pos));
const auto val = m_ir->CreateLoad(get_type<u64>(), ptr);
callee = FunctionCallee(type, m_ir->CreateIntToPtr(m_ir->CreateAnd(val, 0xffff'ffff'ffff), type->getPointerTo()));
callee = FunctionCallee(type, m_ir->CreateIntToPtr(val, type->getPointerTo()));
// Load new segment address
seg0 = m_ir->CreateShl(m_ir->CreateLShr(val, 48), 13);
const auto seg_base_ptr = m_ir->CreateIntToPtr(m_ir->CreateAdd(
m_ir->CreatePtrToInt(m_exec, get_type<u64>()), m_ir->getInt64(vm::g_exec_addr_seg_offset)), m_exec->getType());
const auto seg_pos = m_ir->CreateLShr(indirect, 1);
const auto seg_ptr = dyn_cast<GetElementPtrInst>(m_ir->CreateGEP(get_type<u8>(), seg_base_ptr, seg_pos));
const auto seg_val = m_ir->CreateZExt(m_ir->CreateLoad(get_type<u16>(), seg_ptr), get_type<u64>());
seg0 = m_ir->CreateShl(seg_val, 13);
}
m_ir->SetInsertPoint(block);

View File

@@ -3,7 +3,7 @@
#include "Loader/ELF.h"
#include "util/asm.hpp"
#include "Emu/Cell/RawSPUThread.h"
#include "SPUThread.h"
inline void try_start(spu_thread& spu)
{

View File

@@ -1,3 +1 @@
#pragma once
#include "SPUThread.h"

View File

@@ -5,15 +5,12 @@
#include "Emu/IdManager.h"
#include "Emu/Cell/timers.hpp"
#include "SPUDisAsm.h"
#include "SPUThread.h"
#include "SPUInterpreter.h"
#include "PPUAnalyser.h"
#include "Crypto/sha1.h"
#include "util/asm.hpp"
#include "util/v128.hpp"
#include "util/simd.hpp"
#include "util/sysinfo.hpp"
#include <cmath>
@@ -2773,14 +2770,17 @@ void spu_recompiler::FREST(spu_opcode_t op)
const u64 fraction_lut_addr = reinterpret_cast<u64>(spu_frest_fraction_lut);
const u64 exponent_lut_addr = reinterpret_cast<u64>(spu_frest_exponent_lut);
c->movabs(*arg0, fraction_lut_addr);
c->movabs(*arg1, exponent_lut_addr);
for (u32 index = 0; index < 4; index++)
{
c->pextrd(*qw0, v_fraction, index);
c->mov(*qw1, asmjit::x86::dword_ptr(fraction_lut_addr, *qw0, 2));
c->mov(*qw1, asmjit::x86::dword_ptr(*arg0, *qw0, 2));
c->pinsrd(v_fraction, *qw1, index);
c->pextrd(*qw0, v_exponent, index);
c->mov(*qw1, asmjit::x86::dword_ptr(exponent_lut_addr, *qw0, 2));
c->mov(*qw1, asmjit::x86::dword_ptr(*arg1, *qw0, 2));
c->pinsrd(v_exponent, *qw1, index);
}
@@ -2813,14 +2813,17 @@ void spu_recompiler::FRSQEST(spu_opcode_t op)
const u64 fraction_lut_addr = reinterpret_cast<u64>(spu_frsqest_fraction_lut);
const u64 exponent_lut_addr = reinterpret_cast<u64>(spu_frsqest_exponent_lut);
c->movabs(*arg0, fraction_lut_addr);
c->movabs(*arg1, exponent_lut_addr);
for (u32 index = 0; index < 4; index++)
{
c->pextrd(*qw0, v_fraction, index);
c->mov(*qw1, asmjit::x86::dword_ptr(fraction_lut_addr, *qw0, 2));
c->mov(*qw1, asmjit::x86::dword_ptr(*arg0, *qw0, 2));
c->pinsrd(v_fraction, *qw1, index);
c->pextrd(*qw0, v_exponent, index);
c->mov(*qw1, asmjit::x86::dword_ptr(exponent_lut_addr, *qw0, 2));
c->mov(*qw1, asmjit::x86::dword_ptr(*arg1, *qw0, 2));
c->pinsrd(v_exponent, *qw1, index);
}

View File

@@ -1,7 +1,5 @@
#pragma once
#include "util/types.hpp"
// SPU Instruction Type
struct spu_itype
{

View File

@@ -842,6 +842,7 @@ void spu_cache::initialize(bool build_existing_cache)
// Initialize compiler instances for parallel compilation
std::unique_ptr<spu_recompiler_base> compiler;
#if defined(ARCH_X64)
if (g_cfg.core.spu_decoder == spu_decoder_type::asmjit)
{
compiler = spu_recompiler_base::make_asmjit_recompiler();
@@ -850,6 +851,22 @@ void spu_cache::initialize(bool build_existing_cache)
{
compiler = spu_recompiler_base::make_llvm_recompiler();
}
else
{
fmt::throw_exception("Unsupported spu decoder '%s'", g_cfg.core.spu_decoder);
}
#elif defined(ARCH_ARM64)
if (g_cfg.core.spu_decoder == spu_decoder_type::llvm)
{
compiler = spu_recompiler_base::make_llvm_recompiler();
}
else
{
fmt::throw_exception("Unsupported spu decoder '%s'", g_cfg.core.spu_decoder);
}
#else
#error "Unimplemented"
#endif
compiler->init();
@@ -2545,7 +2562,7 @@ bool reg_state_t::is_const() const
bool reg_state_t::compare_tags(const reg_state_t& rhs) const
{
// Compare by tag, address of instruction origin
// Compare by tag, address of instruction origin
return tag == rhs.tag && origin == rhs.origin && is_instruction == rhs.is_instruction;
}
@@ -6066,7 +6083,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
else if (atomic16->ls_offs.compare_with_mask_indifference(atomic16->lsa, SPU_LS_MASK_128) && atomic16->ls.is_less_than(128 - (atomic16->ls_offs.value & 127)))
{
// Relative memory access with offset less than 128 bytes
// Common around SPU utilities which have less strict restrictions about memory alignment
// Common around SPU utilities which have less strict restrictions about memory alignment
ok = true;
}
}
@@ -6340,7 +6357,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
{
atomic16->mem_count++;
// Do not clear lower 16 bytes addressing because the program can move on 4-byte basis
// Do not clear lower 16 bytes addressing because the program can move on 4-byte basis
const u32 offs = spu_branch_target(pos - result.lower_bound, op.si16);
if (atomic16->lsa.is_const() && [&]()
@@ -7359,7 +7376,7 @@ struct spu_llvm_worker
set_relax_flag = false;
}
thread_ctrl::wait_on(utils::bless<atomic_t<u32>>(&registered)[1], 0);
thread_ctrl::wait_on(registered.get_wait_atomic(), 0);
slice = registered.pop_all();
}())
{
@@ -7474,7 +7491,7 @@ struct spu_llvm
while (!registered && thread_ctrl::state() != thread_state::aborting)
{
// Wait for the first SPU block before launching any thread
thread_ctrl::wait_on(utils::bless<atomic_t<u32>>(&registered)[1], 0);
thread_ctrl::wait_on(registered.get_wait_atomic(), 0);
}
if (thread_ctrl::state() == thread_state::aborting)
@@ -7577,7 +7594,7 @@ struct spu_llvm
// Interrupt profiler thread and put it to sleep
static_cast<void>(prof_mutex.reset());
thread_ctrl::wait_on(utils::bless<atomic_t<u32>>(&registered)[1], 0);
thread_ctrl::wait_on(registered.get_wait_atomic(), 0);
std::fill(notify_compile.begin(), notify_compile.end(), 0); // Reset notification flags
notify_compile_count = 0;
compile_pending = 0;
@@ -8142,7 +8159,7 @@ std::array<reg_state_t, s_reg_max>& block_reg_info::evaluate_start_state(const s
// Check if the node is resolved
if (!node->has_true_state)
{
// Assume this block cannot be resolved at the moment
// Assume this block cannot be resolved at the moment
is_all_resolved = false;
break;
}

View File

@@ -3,7 +3,6 @@
#include "Utilities/JIT.h"
#include "SPUThread.h"
#include "Emu/Cell/Common.h"
#include "Emu/Cell/SPUAnalyser.h"
#include "Emu/system_config.h"
@@ -13,7 +12,6 @@
#include "util/sysinfo.hpp"
#include <cmath>
#include <cfenv>
#if !defined(_MSC_VER)
#pragma GCC diagnostic push

View File

@@ -628,6 +628,8 @@ const auto spu_putllc_tx = build_function_asm<u64(*)(u32 raddr, u64 rtime, void*
//}
// Create stack frame if necessary (Windows ABI has only 6 volatile vector registers)
c.push(x86::rbp);
c.push(x86::rbx);
#ifdef _WIN32
c.sub(x86::rsp, 168);
if (s_tsx_avx)
@@ -648,17 +650,21 @@ const auto spu_putllc_tx = build_function_asm<u64(*)(u32 raddr, u64 rtime, void*
c.movups(x86::oword_ptr(x86::rsp, 128), x86::xmm14);
c.movups(x86::oword_ptr(x86::rsp, 144), x86::xmm15);
}
#else
c.sub(x86::rsp, 40);
#endif
// Prepare registers
build_swap_rdx_with(c, args, x86::r10);
c.mov(args[1], x86::qword_ptr(reinterpret_cast<u64>(&vm::g_sudo_addr)));
c.movabs(args[1], reinterpret_cast<u64>(&vm::g_sudo_addr));
c.mov(args[1], x86::qword_ptr(args[1]));
c.lea(args[1], x86::qword_ptr(args[1], args[0]));
c.prefetchw(x86::byte_ptr(args[1], 0));
c.prefetchw(x86::byte_ptr(args[1], 64));
c.and_(args[0].r32(), 0xff80);
c.shr(args[0].r32(), 1);
c.lea(x86::r11, x86::qword_ptr(reinterpret_cast<u64>(+vm::g_reservations), args[0]));
c.movabs(x86::r11, reinterpret_cast<u64>(+vm::g_reservations));
c.lea(x86::r11, x86::qword_ptr(x86::r11, args[0]));
// Prepare data
if (s_tsx_avx)
@@ -703,7 +709,8 @@ const auto spu_putllc_tx = build_function_asm<u64(*)(u32 raddr, u64 rtime, void*
c.add(x86::qword_ptr(args[2], ::offset32(&spu_thread::ftx) - ::offset32(&spu_thread::rdata)), 1);
build_get_tsc(c);
c.sub(x86::rax, stamp0);
c.cmp(x86::rax, x86::qword_ptr(reinterpret_cast<u64>(&g_rtm_tx_limit2)));
c.movabs(x86::rbx, reinterpret_cast<u64>(&g_rtm_tx_limit2));
c.cmp(x86::rax, x86::qword_ptr(x86::rbx));
c.jae(fall);
});
@@ -853,8 +860,13 @@ const auto spu_putllc_tx = build_function_asm<u64(*)(u32 raddr, u64 rtime, void*
c.movups(x86::xmm15, x86::oword_ptr(x86::rsp, 144));
}
c.add(x86::rsp, 168);
#else
c.add(x86::rsp, 40);
#endif
c.pop(x86::rbx);
c.pop(x86::rbp);
if (s_tsx_avx)
{
c.vzeroupper();
@@ -884,8 +896,10 @@ const auto spu_putlluc_tx = build_function_asm<u64(*)(u32 raddr, const void* rda
//}
// Create stack frame if necessary (Windows ABI has only 6 volatile vector registers)
#ifdef _WIN32
c.push(x86::rbp);
c.push(x86::rbx);
c.sub(x86::rsp, 40);
#ifdef _WIN32
if (!s_tsx_avx)
{
c.movups(x86::oword_ptr(x86::rsp, 0), x86::xmm6);
@@ -894,7 +908,8 @@ const auto spu_putlluc_tx = build_function_asm<u64(*)(u32 raddr, const void* rda
#endif
// Prepare registers
build_swap_rdx_with(c, args, x86::r10);
c.mov(x86::r11, x86::qword_ptr(reinterpret_cast<u64>(&vm::g_sudo_addr)));
c.movabs(x86::r11, reinterpret_cast<u64>(&vm::g_sudo_addr));
c.mov(x86::r11, x86::qword_ptr(x86::r11));
c.lea(x86::r11, x86::qword_ptr(x86::r11, args[0]));
c.prefetchw(x86::byte_ptr(x86::r11, 0));
c.prefetchw(x86::byte_ptr(x86::r11, 64));
@@ -921,7 +936,8 @@ const auto spu_putlluc_tx = build_function_asm<u64(*)(u32 raddr, const void* rda
c.and_(args[0].r32(), 0xff80);
c.shr(args[0].r32(), 1);
c.lea(args[1], x86::qword_ptr(reinterpret_cast<u64>(+vm::g_reservations), args[0]));
c.movabs(args[1], reinterpret_cast<u64>(+vm::g_reservations));
c.lea(args[1], x86::qword_ptr(args[1], args[0]));
// Alloc args[0] to stamp0
const auto stamp0 = args[0];
@@ -933,7 +949,8 @@ const auto spu_putlluc_tx = build_function_asm<u64(*)(u32 raddr, const void* rda
c.add(x86::qword_ptr(args[3]), 1);
build_get_tsc(c);
c.sub(x86::rax, stamp0);
c.cmp(x86::rax, x86::qword_ptr(reinterpret_cast<u64>(&g_rtm_tx_limit2)));
c.movabs(x86::rbx, reinterpret_cast<u64>(&g_rtm_tx_limit2));
c.cmp(x86::rax, x86::qword_ptr(x86::rbx));
c.jae(fall);
});
@@ -986,6 +1003,10 @@ const auto spu_putlluc_tx = build_function_asm<u64(*)(u32 raddr, const void* rda
c.vzeroupper();
}
c.add(x86::rsp, 40);
c.pop(x86::rbx);
c.pop(x86::rbp);
maybe_flush_lbr(c);
c.ret();
#else
@@ -1023,11 +1044,13 @@ const auto spu_getllar_tx = build_function_asm<u64(*)(u32 raddr, void* rdata, cp
// Prepare registers
build_swap_rdx_with(c, args, x86::r10);
c.mov(x86::rbp, x86::qword_ptr(reinterpret_cast<u64>(&vm::g_sudo_addr)));
c.movabs(x86::rbp, reinterpret_cast<u64>(&vm::g_sudo_addr));
c.mov(x86::rbp, x86::qword_ptr(x86::rbp));
c.lea(x86::rbp, x86::qword_ptr(x86::rbp, args[0]));
c.and_(args[0].r32(), 0xff80);
c.shr(args[0].r32(), 1);
c.lea(x86::r11, x86::qword_ptr(reinterpret_cast<u64>(+vm::g_reservations), args[0]));
c.movabs(x86::r11, reinterpret_cast<u64>(+vm::g_reservations));
c.lea(x86::r11, x86::qword_ptr(x86::r11, args[0]));
// Alloc args[0] to stamp0
const auto stamp0 = args[0];
@@ -1039,7 +1062,8 @@ const auto spu_getllar_tx = build_function_asm<u64(*)(u32 raddr, void* rdata, cp
c.add(x86::qword_ptr(args[2], ::offset32(&spu_thread::ftx)), 1);
build_get_tsc(c);
c.sub(x86::rax, stamp0);
c.cmp(x86::rax, x86::qword_ptr(reinterpret_cast<u64>(&g_rtm_tx_limit1)));
c.movabs(x86::rbx, reinterpret_cast<u64>(&g_rtm_tx_limit1));
c.cmp(x86::rax, x86::qword_ptr(x86::rbx));
c.jae(fall);
});
@@ -1209,8 +1233,6 @@ void spu_thread::dump_regs(std::string& ret, std::any& /*custom_data*/) const
u32 saved_pc = umax;
const u8* lsa_state_ptr = nullptr;
const u8* lsa_ptr = _ptr<u8>(ch_mfc_cmd.lsa);
// Load PC, GPRs and reservation data atomically
// We may not load the entire context atomically, but there is importance their state being intact for debugging
do
@@ -2107,6 +2129,41 @@ u8* spu_thread::map_ls(utils::shm& shm, void* ptr)
return ls;
}
void spu_thread::init_spu_decoder()
{
ensure(!jit);
#if !defined(ARCH_X64) && !defined(ARCH_ARM64)
#error "Unimplemented"
#else
const spu_decoder_type spu_decoder = g_cfg.core.spu_decoder;
#if defined(ARCH_X64)
if (spu_decoder == spu_decoder_type::asmjit)
{
jit = spu_recompiler_base::make_asmjit_recompiler();
}
else
#endif
if (spu_decoder == spu_decoder_type::llvm)
{
#if defined(ARCH_X64)
jit = spu_recompiler_base::make_fast_llvm_recompiler();
#elif defined(ARCH_ARM64)
jit = spu_recompiler_base::make_llvm_recompiler();
#endif
}
else if (spu_decoder == spu_decoder_type::_static || spu_decoder == spu_decoder_type::dynamic)
{
//
}
else
{
fmt::throw_exception("Unsupported spu decoder '%s'", g_cfg.core.spu_decoder);
}
#endif
}
spu_thread::spu_thread(lv2_spu_group* group, u32 index, std::string_view name, u32 lv2_id, bool is_isolated, u32 option)
: cpu_thread(idm::last_id())
, group(group)
@@ -2118,20 +2175,7 @@ spu_thread::spu_thread(lv2_spu_group* group, u32 index, std::string_view name, u
, lv2_id(lv2_id)
, spu_tname(make_single<std::string>(name))
{
if (g_cfg.core.spu_decoder == spu_decoder_type::asmjit)
{
jit = spu_recompiler_base::make_asmjit_recompiler();
}
else if (g_cfg.core.spu_decoder == spu_decoder_type::llvm)
{
#if defined(ARCH_X64)
jit = spu_recompiler_base::make_fast_llvm_recompiler();
#elif defined(ARCH_ARM64)
jit = spu_recompiler_base::make_llvm_recompiler();
#else
#error "Unimplemented"
#endif
}
init_spu_decoder();
if (g_cfg.core.mfc_debug)
{
@@ -2193,20 +2237,7 @@ spu_thread::spu_thread(utils::serial& ar, lv2_spu_group* group)
, lv2_id(ar)
, spu_tname(make_single<std::string>(ar.operator std::string()))
{
if (g_cfg.core.spu_decoder == spu_decoder_type::asmjit)
{
jit = spu_recompiler_base::make_asmjit_recompiler();
}
else if (g_cfg.core.spu_decoder == spu_decoder_type::llvm)
{
#if defined(ARCH_X64)
jit = spu_recompiler_base::make_fast_llvm_recompiler();
#elif defined(ARCH_ARM64)
jit = spu_recompiler_base::make_llvm_recompiler();
#else
#error "Unimplemented"
#endif
}
init_spu_decoder();
if (g_cfg.core.mfc_debug)
{
@@ -4329,7 +4360,7 @@ bool spu_thread::check_mfc_interrupts(u32 next_pc)
return false;
}
bool spu_thread::is_exec_code(u32 addr, std::span<const u8> ls_ptr, u32 base_addr, bool avoid_dead_code)
bool spu_thread::is_exec_code(u32 addr, std::span<const u8> ls_ptr, u32 base_addr, bool avoid_dead_code, bool is_range_limited)
{
bool had_conditional = false;
@@ -4337,12 +4368,12 @@ bool spu_thread::is_exec_code(u32 addr, std::span<const u8> ls_ptr, u32 base_add
{
if (addr & ~0x3FFFC)
{
return false;
return is_range_limited;
}
if (addr < base_addr || addr >= base_addr + ls_ptr.size())
{
return false;
return is_range_limited;
}
const u32 addr0 = spu_branch_target(addr);
@@ -4445,19 +4476,19 @@ bool spu_thread::is_exec_code(u32 addr, std::span<const u8> ls_ptr, u32 base_add
// Detect "invalid" relative branches
// Branch offsets that, although are the only way to get X code address using relative address
// Rely on overflow/underflow of SPU memory bounds
// Thus they would behave differently if SPU LS memory size was to increase (evolving the CELL architecture was the original plan)
// Thus they would behave differently if SPU LS memory size was to increase (evolving the CELL architecture was the original plan)
// Making them highly unlikely to be valid code
if (rel < 0)
{
if (addr < 0u - rel)
{
return false;
return is_range_limited;
}
}
else if (SPU_LS_SIZE - addr <= rel + 0u)
{
return false;
return is_range_limited;
}
if (type == spu_itype::BRSL)
@@ -4487,7 +4518,7 @@ bool spu_thread::is_exec_code(u32 addr, std::span<const u8> ls_ptr, u32 base_add
if (route_pc < base_addr || route_pc >= base_addr + ls_ptr.size())
{
return false;
return is_range_limited;
}
// Test the validity of a single instruction of the optional target
@@ -4518,6 +4549,126 @@ u32 spu_thread::get_mfc_completed() const
return ch_tag_mask & ~mfc_fence;
}
u32 evaluate_spin_optimization(std::span<u8> stats, u64 evaluate_time, const cfg::uint<0, 100>& wait_percent, bool inclined_for_responsiveness = false)
{
ensure(stats.size() >= 2 && stats.size() <= 16);
const u32 percent = wait_percent;
// Predict whether or not to use operating system sleep based on history
std::array<u8, 16> old_stats{};
std::copy_n(stats.data(), stats.size(), old_stats.data());
// Rotate history (prepare newest entry)
stats[0] = 0;
std::copy_n(old_stats.data(), stats.size() - 1, stats.data() + 1);
u32 total_wait = 0;
u32 zero_count = 0; // Try to ignore major inconsistencies
u32 consecutive_zero = 0;
u32 consecutive_zero_or_one = 0;
u32 consecutive_zero_or_one_tally = 0;
usz index = umax;
for (u8 val : old_stats)
{
index++;
if (index == stats.size())
{
break;
}
total_wait += val;
if (val == 0)
{
if (consecutive_zero == index)
{
consecutive_zero++;
consecutive_zero_or_one++;
//consecutive_zero_or_one_tally += 0;
}
++zero_count;
}
if (val == 1)
{
if (consecutive_zero_or_one == index)
{
consecutive_zero_or_one++;
consecutive_zero_or_one_tally++;
}
}
}
if (inclined_for_responsiveness)
{
total_wait /= 2;
}
// Add to chance if previous wait was long enough
u32 add_count = 0;
if (stats.size() == 4)
{
add_count = zero_count == 3 && total_wait >= 9 ? (total_wait - 8) * 40
: zero_count == 2 && total_wait >= 8 ? (total_wait - 7) * 40
: zero_count == 1 && total_wait >= 7 ? (total_wait - 6) * 40
: zero_count == 0 && total_wait >= 4 ? (total_wait - 3) * 40
: 0;
}
else
{
add_count = zero_count >= 12 && total_wait >= 80 ? (total_wait - 80) * 30
: zero_count >= 7 && total_wait >= 30 ? (total_wait - 30) * 10
: zero_count >= 4 && total_wait >= 20 ? (total_wait - 20) * 10
: zero_count >= 0 && total_wait >= 10 ? (total_wait - 10) * 10
: 0;
}
if (stats.size() == 16 && (consecutive_zero >= 2 || (consecutive_zero_or_one >= 3 && consecutive_zero_or_one_tally < consecutive_zero_or_one * 2 / 3)))
{
// Thread is back to action after some sleep
add_count = 0;
}
if (inclined_for_responsiveness && std::count(old_stats.data(), old_stats.data() + 3, 0) >= 2)
{
add_count = 0;
}
// Evalute its value (shift-right to ensure its randomness with different CPUs)
const u32 busy_waiting_switch = ((evaluate_time >> 8) % 100 + add_count < percent) ? 1 : 0;
thread_local usz g_system_wait = 0, g_busy_wait = 0;
if (busy_waiting_switch)
{
g_busy_wait++;
}
else
{
g_system_wait++;
}
if ((g_system_wait + g_busy_wait) && (g_system_wait + g_busy_wait) % 200 == 0)
{
spu_log.trace("SPU wait: count=%d. switch=%d, spin=%d, busy=%d, system=%d, {%d, %d, %d, %d}", total_wait, busy_waiting_switch, !"TODO: Spin", +g_busy_wait, +g_system_wait, old_stats[0], old_stats[1], old_stats[2], old_stats[3]);
}
if ((g_system_wait + g_busy_wait) % 5000 == 0)
{
g_system_wait = 0;
g_busy_wait = 0;
}
return busy_waiting_switch;
}
bool spu_thread::process_mfc_cmd()
{
// Stall infinitely if MFC queue is full
@@ -4632,61 +4783,16 @@ bool spu_thread::process_mfc_cmd()
getllar_spin_count = std::min<u32>(getllar_spin_count + 1, u16{umax});
static atomic_t<usz> g_ok = 0, g_fail = 0;
if (getllar_busy_waiting_switch == umax && getllar_spin_count == 4)
{
// Hidden value to force busy waiting (100 to 1 are dynamically adjusted, 0 is not)
if (!g_cfg.core.spu_getllar_spin_optimization_disabled)
{
const u32 percent = g_cfg.core.spu_getllar_busy_waiting_percentage;
// Predict whether or not to use operating system sleep based on history
auto& stats = getllar_wait_time[(addr % SPU_LS_SIZE) / 128];
const std::array<u8, 4> old_stats = stats;
std::array<u8, 4> new_stats{};
// Rotate history (prepare newest entry)
new_stats[0] = 0;
new_stats[1] = old_stats[0];
new_stats[2] = old_stats[1];
new_stats[3] = old_stats[2];
stats = new_stats;
u32 total_wait = 0;
u32 zero_count = 0; // Try to ignore major inconsistencies
for (u8 val : old_stats)
{
total_wait += val;
if (val == 0) ++zero_count;
}
// Add to chance if previous wait was long enough
const u32 add_count = zero_count == 3 && total_wait >= 40 ? (total_wait - 39) * 40
: zero_count == 2 && total_wait >= 11 ? (total_wait - 10) * 40
: zero_count == 1 && total_wait >= 8 ? (total_wait - 7) * 40
: zero_count == 0 && total_wait >= 6 ? (total_wait - 5) * 40
: 0;
// Evalute its value (shift-right to ensure its randomness with different CPUs)
getllar_busy_waiting_switch = ((perf0.get() >> 8) % 100 + add_count < percent) ? 1 : 0;
getllar_evaluate_time = perf0.get();
auto& history = getllar_wait_time[(addr % SPU_LS_SIZE) / 128];
if (getllar_busy_waiting_switch)
{
g_fail++;
}
else
{
g_ok++;
}
if ((g_ok + g_fail) % 200 == 0 && !getllar_busy_waiting_switch)
spu_log.trace("SPU wait: count=%d. switch=%d, spin=%d, fail=%d, ok=%d, {%d, %d, %d, %d}", total_wait, getllar_busy_waiting_switch, getllar_spin_count, +g_fail, +g_ok, old_stats[0], old_stats[1], old_stats[2], old_stats[3] );
getllar_busy_waiting_switch =
evaluate_spin_optimization({ history.data(), history.size() }, getllar_evaluate_time, g_cfg.core.spu_getllar_busy_waiting_percentage);
}
else
{
@@ -5004,7 +5110,7 @@ bool spu_thread::process_mfc_cmd()
if (group->spurs_running == max_run - 1)
{
// Try to let another thread slip in and take over execution
// Try to let another thread slip in and take over execution
thread_ctrl::wait_for(300);
// Update value
@@ -5029,7 +5135,7 @@ bool spu_thread::process_mfc_cmd()
if (spurs_last_task_timestamp)
{
const u64 avg_entry = spurs_average_task_duration / spurs_task_count_to_calculate;
spurs_average_task_duration -= avg_entry;
spurs_average_task_duration -= avg_entry;
spurs_average_task_duration += std::min<u64>(45'000, current - spurs_last_task_timestamp);
spu_log.trace("duration: %d, avg=%d", current - spurs_last_task_timestamp, spurs_average_task_duration / spurs_task_count_to_calculate);
spurs_last_task_timestamp = 0;
@@ -5050,7 +5156,7 @@ bool spu_thread::process_mfc_cmd()
}
max_run = group->max_run;
prev_running = group->spurs_running.fetch_op([max_run](u32& x)
{
if (x < max_run)
@@ -5115,7 +5221,7 @@ bool spu_thread::process_mfc_cmd()
if (spurs_last_task_timestamp)
{
const u64 avg_entry = spurs_average_task_duration / spurs_task_count_to_calculate;
spurs_average_task_duration -= avg_entry;
spurs_average_task_duration -= avg_entry;
spurs_average_task_duration += std::min<u64>(45'000, current - spurs_last_task_timestamp);
spu_log.trace("duration: %d, avg=%d", current - spurs_last_task_timestamp, spurs_average_task_duration / spurs_task_count_to_calculate);
spurs_last_task_timestamp = 0;
@@ -5937,7 +6043,52 @@ s64 spu_thread::get_ch_value(u32 ch)
return true;
};
for (; !events.count; events = get_events(mask1 & ~SPU_EVENT_LR, true, true))
const bool is_LR_wait = raddr && mask1 & SPU_EVENT_LR;
auto& history = eventstat_wait_time[(raddr % SPU_LS_SIZE) / 128];
if (is_LR_wait)
{
const u32 spu_group_restart = group ? +group->stop_count : 0;
// Check if waiting session changed
if (eventstat_raddr != raddr || eventstat_block_counter != block_counter || last_getllar != eventstat_getllar || eventstat_spu_group_restart != spu_group_restart)
{
eventstat_raddr = raddr;
eventstat_block_counter = block_counter;
eventstat_getllar = last_getllar;
eventstat_spu_group_restart = spu_group_restart;
eventstat_spin_count = 0;
eventstat_evaluate_time = get_system_time();
eventstat_busy_waiting_switch = umax;
}
else
{
u8& val = history.front();
val = static_cast<u8>(std::min<u32>(val + 1, u8{umax}));
}
}
else
{
eventstat_busy_waiting_switch = 0;
eventstat_raddr = 0;
eventstat_block_counter = 0;
}
if (eventstat_busy_waiting_switch == umax)
{
bool value = false;
if (is_LR_wait && g_cfg.core.spu_reservation_busy_waiting_enabled)
{
// Make single-threaded groups inclined for busy-waiting
value = evaluate_spin_optimization({ history.data(), history.size() }, eventstat_evaluate_time, g_cfg.core.spu_reservation_busy_waiting_percentage, group && group->max_num == 1) != 0;
}
eventstat_busy_waiting_switch = value ? 1 : 0;
}
for (bool is_first = true; !events.count; events = get_events(mask1 & ~SPU_EVENT_LR, true, true), is_first = false)
{
const auto old = +state;
@@ -5952,7 +6103,7 @@ s64 spu_thread::get_ch_value(u32 ch)
}
// Optimized check
if (raddr && mask1 & SPU_EVENT_LR)
if (is_LR_wait)
{
if (cache_line_waiter_index == umax)
{
@@ -5983,6 +6134,59 @@ s64 spu_thread::get_ch_value(u32 ch)
set_events(SPU_EVENT_LR);
continue;
}
if (!is_first && eventstat_busy_waiting_switch != 1)
{
u8& val = history.front();
val = static_cast<u8>(std::min<u32>(val + 1, u8{umax}));
}
}
if (eventstat_busy_waiting_switch == 1)
{
// Don't be stubborn, force operating sleep if too much time has passed
const u64 time_since = get_system_time() - eventstat_evaluate_time;
if (time_since >= (utils::get_thread_count() >= 9 ? 50'000 : 3000))
{
spu_log.trace("SPU RdEventStat wait for 0x%x failed", raddr);
history.front() = 2;
eventstat_busy_waiting_switch = 0;
continue;
}
#if defined(ARCH_X64)
if (utils::has_um_wait())
{
if (utils::has_waitpkg())
{
__tpause(std::min<u32>(eventstat_spin_count, 10) * 500, 0x1);
}
else
{
struct check_wait_t
{
static FORCE_INLINE bool needs_wait(u64 rtime, const atomic_t<u64>& mem_rtime) noexcept
{
return rtime == mem_rtime;
}
};
// Provide the first X64 cache line of the reservation to be tracked
__mwaitx<check_wait_t>(std::min<u32>(eventstat_spin_count, 17) * 500, 0xf0, std::addressof(*resrv_mem), +rtime, vm::reservation_acquire(raddr));
}
}
else
#endif
{
busy_wait(300);
}
// Check other reservations in other threads
lv2_obj::notify_all();
eventstat_spin_count++;
continue;
}
if (raddr && (mask1 & ~SPU_EVENT_TM) == SPU_EVENT_LR)

View File

@@ -638,6 +638,7 @@ public:
virtual ~spu_thread() override;
void cleanup();
void cpu_init();
void init_spu_decoder();
static const u32 id_base = 0x02000000; // TODO (used to determine thread type)
static const u32 id_step = 1;
@@ -805,6 +806,14 @@ public:
u32 getllar_busy_waiting_switch = umax; // umax means the test needs evaluation, otherwise it's a boolean
u64 getllar_evaluate_time = 0;
u32 eventstat_raddr = 0;
u32 eventstat_getllar = 0;
u64 eventstat_block_counter = 0;
u64 eventstat_spu_group_restart = 0;
u64 eventstat_spin_count = 0;
u64 eventstat_evaluate_time = 0;
u32 eventstat_busy_waiting_switch = 0;
std::vector<mfc_cmd_dump> mfc_history;
u64 mfc_dump_idx = 0;
static constexpr u32 max_mfc_dump_idx = 4096;
@@ -828,6 +837,7 @@ public:
bool stop_flag_removal_protection = false;
std::array<std::array<u8, 4>, SPU_LS_SIZE / 128> getllar_wait_time{};
std::array<std::array<u8, 16>, SPU_LS_SIZE / 128> eventstat_wait_time{};
void push_snr(u32 number, u32 value);
static void do_dma_transfer(spu_thread* _this, const spu_mfc_cmd& args, u8* ls);
@@ -843,7 +853,7 @@ public:
void set_events(u32 bits);
void set_interrupt_status(bool enable);
bool check_mfc_interrupts(u32 next_pc);
static bool is_exec_code(u32 addr, std::span<const u8> ls_ptr, u32 base_addr = 0, bool avoid_dead_code = false); // Only a hint, do not rely on it other than debugging purposes
static bool is_exec_code(u32 addr, std::span<const u8> ls_ptr, u32 base_addr = 0, bool avoid_dead_code = false, bool is_range_limited = false); // A hint, do not rely on it for true execution compatibility
static std::vector<u32> discover_functions(u32 base_addr, std::span<const u8> ls, bool is_known_addr, u32 /*entry*/);
u32 get_ch_count(u32 ch);
s64 get_ch_value(u32 ch);

View File

@@ -2160,7 +2160,7 @@ bool lv2_obj::wait_timeout(u64 usec, ppu_thread* cpu, bool scale, bool is_usleep
}
u64 remaining = usec - passed;
#if defined(__linux__)
#ifdef __linux__
// NOTE: Assumption that timer initialization has succeeded
constexpr u64 host_min_quantum = 10;
#else
@@ -2178,7 +2178,7 @@ bool lv2_obj::wait_timeout(u64 usec, ppu_thread* cpu, bool scale, bool is_usleep
{
if (remaining > host_min_quantum)
{
#if defined(__linux__)
#ifdef __linux__
// With timerslack set low, Linux is precise for all values above
wait_for(remaining);
#else
@@ -2268,7 +2268,7 @@ void lv2_obj::notify_all() noexcept
u32 notifies[total_waiters]{};
// There may be 6 waiters, but checking them all may be performance expensive
// There may be 6 waiters, but checking them all may be performance expensive
// Instead, check 2 at max, but use the CPU ID index to tell which index to start checking so the work would be distributed across all threads
atomic_t<u64, 64>* range_lock = nullptr;

View File

@@ -1,5 +1,4 @@
#include "stdafx.h"
#include "Emu/Memory/vm.h"
#include "Emu/Cell/ErrorCodes.h"

View File

@@ -2,7 +2,6 @@
#include "util/serialization.hpp"
#include "Emu/IdManager.h"
#include "Emu/IPC.h"
#include "Emu/System.h"
#include "Emu/Cell/ErrorCodes.h"
@@ -60,7 +59,6 @@ CellError lv2_cond::on_id_create()
if (!mutex)
{
_mutex = static_cast<shared_ptr<lv2_obj>>(ensure(idm::get_unlocked<lv2_obj, lv2_mutex>(mtx_id)));
}
// Defer function
@@ -72,7 +70,7 @@ CellError lv2_cond::on_id_create()
std::function<void(void*)> lv2_cond::load(utils::serial& ar)
{
return load_func(make_shared<lv2_cond>(ar));
return load_func(make_shared<lv2_cond>(stx::exact_t<utils::serial&>(ar)));
}
void lv2_cond::save(utils::serial& ar)

View File

@@ -1,6 +1,4 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/Memory/vm.h"
#include "Emu/IdManager.h"
#include "Emu/Cell/lv2/sys_event.h"
@@ -122,7 +120,7 @@ void lv2_config::remove_service_event(u32 id)
lv2_config_service_event& lv2_config_service_event::operator=(thread_state s) noexcept
{
if (s == thread_state::finished)
if (s == thread_state::destroying_context && !m_destroyed.exchange(true))
{
if (auto global = g_fxo->try_get<lv2_config>())
{
@@ -133,6 +131,23 @@ lv2_config_service_event& lv2_config_service_event::operator=(thread_state s) no
return *this;
}
lv2_config_service_event::~lv2_config_service_event() noexcept
{
operator=(thread_state::destroying_context);
}
lv2_config::~lv2_config() noexcept
{
for (auto& [key, event] : events)
{
if (event)
{
// Avoid collision with lv2_config_service_event destructor
event->m_destroyed = true;
}
}
}
// LV2 Config Service Listener
bool lv2_config_service_listener::check_service(const lv2_config_service& service) const
{

View File

@@ -1,11 +1,8 @@
#pragma once
#include <map>
#include <list>
#include "util/atomic.hpp"
#include "util/shared_ptr.hpp"
#include "Emu/Cell/timers.hpp"
/*
* sys_config is a "subscription-based data storage API"
@@ -161,6 +158,8 @@ public:
return null_ptr;
}
~lv2_config() noexcept;
};
/*
@@ -276,7 +275,7 @@ public:
// Utilities
usz get_size() const { return sizeof(sys_config_service_event_t)-1 + data.size(); }
shared_ptr<lv2_config_service> get_shared_ptr () const { return idm::get_unlocked<lv2_config_service>(idm_id); }
shared_ptr<lv2_config_service> get_shared_ptr () const { return stx::make_shared_from_this<lv2_config_service>(this); }
u32 get_id() const { return idm_id; }
};
@@ -342,7 +341,7 @@ public:
// Utilities
u32 get_id() const { return idm_id; }
shared_ptr<lv2_config_service_listener> get_shared_ptr() const { return idm::get_unlocked<lv2_config_service_listener>(idm_id); }
shared_ptr<lv2_config_service_listener> get_shared_ptr() const { return stx::make_shared_from_this<lv2_config_service_listener>(this); }
};
/*
@@ -360,6 +359,10 @@ class lv2_config_service_event
return g_fxo->get<service_event_id>().next_id++;
}
atomic_t<bool> m_destroyed = false;
friend class lv2_config;
public:
const u32 id;
@@ -391,8 +394,7 @@ public:
// Destructor
lv2_config_service_event& operator=(thread_state s) noexcept;
~lv2_config_service_event() noexcept = default;
~lv2_config_service_event() noexcept;
// Notify queue that this event exists
bool notify() const;

View File

@@ -37,8 +37,8 @@ lv2_event_queue::lv2_event_queue(utils::serial& ar) noexcept
std::function<void(void*)> lv2_event_queue::load(utils::serial& ar)
{
auto queue = make_shared<lv2_event_queue>(ar);
return [ptr = lv2_obj::load(queue->key, queue)](void* storage) { *static_cast<shared_ptr<lv2_obj>*>(storage) = ptr; };
auto queue = make_shared<lv2_event_queue>(stx::exact_t<utils::serial&>(ar));
return [ptr = lv2_obj::load(queue->key, queue)](void* storage) { *static_cast<atomic_ptr<lv2_obj>*>(storage) = ptr; };
}
void lv2_event_queue::save(utils::serial& ar)
@@ -420,10 +420,8 @@ error_code sys_event_queue_tryreceive(ppu_thread& ppu, u32 equeue_id, vm::ptr<sy
while (count < size && !queue->events.empty())
{
auto& dest = events[count++];
const auto event = queue->events.front();
std::tie(dest.source, dest.data1, dest.data2, dest.data3) = queue->events.front();
queue->events.pop_front();
std::tie(dest.source, dest.data1, dest.data2, dest.data3) = event;
}
lock.unlock();

View File

@@ -2,13 +2,10 @@
#include "sys_event_flag.h"
#include "Emu/IdManager.h"
#include "Emu/IPC.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/Cell/PPUThread.h"
#include <algorithm>
#include "util/asm.hpp"
LOG_CHANNEL(sys_event_flag);
@@ -24,7 +21,7 @@ lv2_event_flag::lv2_event_flag(utils::serial& ar)
std::function<void(void*)> lv2_event_flag::load(utils::serial& ar)
{
return load_func(make_shared<lv2_event_flag>(ar));
return load_func(make_shared<lv2_event_flag>(stx::exact_t<utils::serial&>(ar)));
}
void lv2_event_flag::save(utils::serial& ar)

View File

@@ -79,7 +79,7 @@ void fmt_class_string<lv2_file>::format(std::string& out, u64 arg)
const usz pos = file.file ? file.file.pos() : umax;
const usz size = file.file ? file.file.size() : umax;
fmt::append(out, u8"%s, “%s”, Mode: 0x%x, Flags: 0x%x, Pos/Size: %s/%s (0x%x/0x%x)", file.type, file.name.data(), file.mode, file.flags, get_size(pos), get_size(size), pos, size);
fmt::append(out, u8"%s, '%s', Mode: 0x%x, Flags: 0x%x, Pos/Size: %s/%s (0x%x/0x%x)", file.type, file.name.data(), file.mode, file.flags, get_size(pos), get_size(size), pos, size);
}
template<>
@@ -87,7 +87,7 @@ void fmt_class_string<lv2_dir>::format(std::string& out, u64 arg)
{
const auto& dir = get_object(arg);
fmt::append(out, u8"Directory, “%s”, Entries: %u/%u", dir.name.data(), std::min<u64>(dir.pos, dir.entries.size()), dir.entries.size());
fmt::append(out, u8"Directory, '%s', Entries: %u/%u", dir.name.data(), std::min<u64>(dir.pos, dir.entries.size()), dir.entries.size());
}
bool has_fs_write_rights(std::string_view vpath)

View File

@@ -7,7 +7,6 @@
#include "Emu/Cell/SPUThread.h"
#include "Emu/IdManager.h"
#include "util/vm.hpp"
#include "util/asm.hpp"
LOG_CHANNEL(sys_memory);
@@ -33,7 +32,7 @@ std::function<void(void*)> lv2_memory_container::load(utils::serial& ar)
// Use idm::last_id() only for the instances at IDM
return [ptr = make_shared<lv2_memory_container>(stx::exact_t<utils::serial&>(ar), true)](void* storage)
{
*static_cast<shared_ptr<lv2_memory_container>*>(storage) = ptr;
*static_cast<atomic_ptr<lv2_memory_container>*>(storage) = ptr;
};
}

View File

@@ -36,12 +36,8 @@ lv2_memory::lv2_memory(u32 size, u32 align, u64 flags, u64 key, bool pshared, lv
, key(key)
, pshared(pshared)
, ct(ct)
, shm(std::make_shared<utils::shm>(size, 1 /* shareable flag */))
, shm(null_ptr)
{
#ifndef _WIN32
// Optimization that's useless on Windows :puke:
utils::memory_lock(shm->map_self(), size);
#endif
}
lv2_memory::lv2_memory(utils::serial& ar)
@@ -51,23 +47,17 @@ lv2_memory::lv2_memory(utils::serial& ar)
, key(ar)
, pshared(ar)
, ct(lv2_memory_container::search(ar.pop<u32>()))
, shm([&](u32 addr)
, shm([&](u32 addr) -> shared_ptr<std::shared_ptr<utils::shm>>
{
if (addr)
{
return ensure(vm::get(vm::any, addr)->peek(addr).second);
return make_single_value(ensure(vm::get(vm::any, addr)->peek(addr).second));
}
const auto _shm = std::make_shared<utils::shm>(size, 1);
ar(std::span(_shm->map_self(), size));
return _shm;
return null_ptr;
}(ar.pop<u32>()))
, counter(ar)
{
#ifndef _WIN32
// Optimization that's useless on Windows :puke:
utils::memory_lock(shm->map_self(), size);
#endif
}
CellError lv2_memory::on_id_create()
@@ -84,7 +74,7 @@ CellError lv2_memory::on_id_create()
std::function<void(void*)> lv2_memory::load(utils::serial& ar)
{
auto mem = make_shared<lv2_memory>(ar);
auto mem = make_shared<lv2_memory>(stx::exact_t<utils::serial&>(ar));
mem->exists++; // Disable on_id_create()
auto func = load_func(mem, +mem->pshared);
mem->exists--;
@@ -96,13 +86,7 @@ void lv2_memory::save(utils::serial& ar)
USING_SERIALIZATION_VERSION(lv2_memory);
ar(size, align, flags, key, pshared, ct->id);
ar(counter ? vm::get_shm_addr(shm) : 0);
if (!counter)
{
ar(std::span(shm->map_self(), size));
}
ar(counter ? vm::get_shm_addr(*shm.load()) : 0);
ar(counter);
}
@@ -645,6 +629,22 @@ error_code sys_mmapper_map_shared_memory(ppu_thread& ppu, u32 addr, u32 mem_id,
return CELL_EALIGN;
}
for (stx::shared_ptr<std::shared_ptr<utils::shm>> to_insert, null; !mem.shm;)
{
// Insert atomically the memory handle (laziliy allocated)
if (!to_insert)
{
to_insert = make_single_value(std::make_shared<utils::shm>(mem.size, 1 /* shareable flag */));
}
null.reset();
if (mem.shm.compare_exchange(null, to_insert))
{
break;
}
}
mem.counter++;
return {};
});
@@ -659,7 +659,9 @@ error_code sys_mmapper_map_shared_memory(ppu_thread& ppu, u32 addr, u32 mem_id,
return mem.ret;
}
if (!area->falloc(addr, mem->size, &mem->shm, mem->align == 0x10000 ? SYS_MEMORY_PAGE_SIZE_64K : SYS_MEMORY_PAGE_SIZE_1M))
auto shm_ptr = *mem->shm.load();
if (!area->falloc(addr, mem->size, &shm_ptr, mem->align == 0x10000 ? SYS_MEMORY_PAGE_SIZE_64K : SYS_MEMORY_PAGE_SIZE_1M))
{
mem->counter--;
@@ -697,6 +699,22 @@ error_code sys_mmapper_search_and_map(ppu_thread& ppu, u32 start_addr, u32 mem_i
return CELL_EALIGN;
}
for (stx::shared_ptr<std::shared_ptr<utils::shm>> to_insert, null; !mem.shm;)
{
// Insert atomically the memory handle (laziliy allocated)
if (!to_insert)
{
to_insert = make_single_value(std::make_shared<utils::shm>(mem.size, 1 /* shareable flag */));
}
null.reset();
if (mem.shm.compare_exchange(null, to_insert))
{
break;
}
}
mem.counter++;
return {};
});
@@ -711,7 +729,9 @@ error_code sys_mmapper_search_and_map(ppu_thread& ppu, u32 start_addr, u32 mem_i
return mem.ret;
}
const u32 addr = area->alloc(mem->size, &mem->shm, mem->align, mem->align == 0x10000 ? SYS_MEMORY_PAGE_SIZE_64K : SYS_MEMORY_PAGE_SIZE_1M);
auto shm_ptr = *mem->shm.load();
const u32 addr = area->alloc(mem->size, &shm_ptr, mem->align, mem->align == 0x10000 ? SYS_MEMORY_PAGE_SIZE_64K : SYS_MEMORY_PAGE_SIZE_1M);
if (!addr)
{
@@ -755,7 +775,7 @@ error_code sys_mmapper_unmap_shared_memory(ppu_thread& ppu, u32 addr, vm::ptr<u3
const auto mem = idm::select<lv2_obj, lv2_memory>([&](u32 id, lv2_memory& mem) -> u32
{
if (mem.shm.get() == shm.second.get())
if (auto shm0 = mem.shm.load(); shm0 && shm0->get() == shm.second.get())
{
return id;
}

View File

@@ -5,6 +5,8 @@
#include "Emu/Memory/vm_ptr.h"
#include "Emu/Cell/ErrorCodes.h"
#include "util/shared_ptr.hpp"
#include <vector>
struct lv2_memory_container;
@@ -24,7 +26,7 @@ struct lv2_memory : lv2_obj
const u64 key; // IPC key
const bool pshared; // Process shared flag
lv2_memory_container* const ct; // Associated memory container
const std::shared_ptr<utils::shm> shm;
atomic_ptr<std::shared_ptr<utils::shm>> shm;
atomic_t<u32> counter{0};

View File

@@ -1,7 +1,6 @@
#include "stdafx.h"
#include "Emu/IdManager.h"
#include "Emu/IPC.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/Cell/PPUThread.h"
@@ -27,7 +26,7 @@ lv2_mutex::lv2_mutex(utils::serial& ar)
std::function<void(void*)> lv2_mutex::load(utils::serial& ar)
{
return load_func(make_shared<lv2_mutex>(ar));
return load_func(make_shared<lv2_mutex>(stx::exact_t<utils::serial&>(ar)));
}
void lv2_mutex::save(utils::serial& ar)

View File

@@ -15,7 +15,6 @@
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"
#endif
#include <errno.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
@@ -24,7 +23,6 @@
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <poll.h>
#ifdef __clang__
#pragma GCC diagnostic pop
@@ -33,9 +31,7 @@
#include "Emu/NP/np_handler.h"
#include "Emu/NP/np_helpers.h"
#include "Emu/NP/np_dnshook.h"
#include <chrono>
#include "Emu/Cell/timers.hpp"
#include <shared_mutex>
#include "sys_net/network_context.h"
@@ -293,7 +289,7 @@ std::function<void(void*)> lv2_socket::load(utils::serial& ar)
sock_lv2->bind(sock_lv2->last_bound_addr);
}
return [ptr = sock_lv2](void* storage) { *static_cast<shared_ptr<lv2_socket>*>(storage) = ptr; };;
return [ptr = sock_lv2](void* storage) { *static_cast<atomic_ptr<lv2_socket>*>(storage) = ptr; };;
}
void lv2_socket::save(utils::serial& ar, bool save_only_this_class)

View File

@@ -3,7 +3,6 @@
#include "Emu/Cell/PPUAnalyser.h"
#include "Emu/Memory/vm_ptr.h"
#include "sys_sync.h"
#include <vector>
struct lv2_overlay final : ppu_module<lv2_obj>
{

View File

@@ -16,6 +16,7 @@
#include "sys_memory.h"
#include "util/asm.hpp"
#include <thread>
LOG_CHANNEL(sys_ppu_thread);

View File

@@ -271,7 +271,7 @@ error_code _sys_process_get_paramsfo(vm::ptr<char> buffer)
{
sys_process.warning("_sys_process_get_paramsfo(buffer=0x%x)", buffer);
if (!Emu.GetTitleID().length())
if (Emu.GetTitleID().empty())
{
return CELL_ENOENT;
}
@@ -498,6 +498,9 @@ void lv2_exitspawn(ppu_thread& ppu, std::vector<std::string>& argv, std::vector<
};
signal_system_cache_can_stay();
// Make sure we keep the game window opened
//Emu.SetContinuousMode(true);
Emu.Kill(false);
});

View File

@@ -2,7 +2,6 @@
#include "sys_semaphore.h"
#include "Emu/IdManager.h"
#include "Emu/IPC.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/Cell/PPUThread.h"

View File

@@ -1,5 +1,4 @@
#include "stdafx.h"
#include "Emu/Memory/vm.h"
#include "Emu/System.h"
#include "Emu/Cell/ErrorCodes.h"

View File

@@ -553,7 +553,7 @@ error_code sys_ss_individual_info_manager(u64 pkg_id, u64 a2, vm::ptr<u64> out_s
case 0x17002:
{
// TODO
vm::write<u64>(a5, a4); // Write back size of buffer
vm::write<u64>(static_cast<u32>(a5), a4); // Write back size of buffer
break;
}
// Get EID size

View File

@@ -1,5 +1,4 @@
#include "stdafx.h"
#include "Emu/Memory/vm.h"
#include "Emu/IdManager.h"
#include "Emu/Cell/ErrorCodes.h"

View File

@@ -1,19 +1,14 @@
#pragma once
#include "Utilities/mutex.h"
#include "Utilities/sema.h"
#include "Emu/CPU/CPUThread.h"
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/Cell/timers.hpp"
#include "Emu/Memory/vm_reservation.h"
#include "Emu/IdManager.h"
#include "Emu/IPC.h"
#include "util/shared_ptr.hpp"
#include <thread>
// attr_protocol (waiting scheduling policy)
enum lv2_protocol : u8
{
@@ -449,7 +444,7 @@ public:
static std::function<void(void*)> load_func(shared_ptr<T> make, u64 pshared = umax)
{
const u64 key = make->key;
return [ptr = load<T>(key, make, pshared)](void* storage) { *static_cast<shared_ptr<Storage>*>(storage) = ptr; };
return [ptr = load<T>(key, make, pshared)](void* storage) { *static_cast<atomic_ptr<Storage>*>(storage) = ptr; };
}
static bool wait_timeout(u64 usec, ppu_thread* cpu = {}, bool scale = true, bool is_usleep = false);

View File

@@ -378,7 +378,7 @@ error_code sys_time_get_current_time(vm::ptr<s64> sec, vm::ptr<s64> nsec)
if (g_cfg.core.clocks_scale == 100)
{
// get the seconds from the system clock, and add the console time offset (which might be negative)
*sec = ts.tv_sec;// + g_cfg.sys.console_time_offset;
*sec = ts.tv_sec + g_cfg.sys.console_time_offset;
if (!nsec)
{
@@ -410,7 +410,7 @@ error_code sys_time_get_current_time(vm::ptr<s64> sec, vm::ptr<s64> nsec)
tv_nsec = stv_nsec + (tv_nsec * g_cfg.core.clocks_scale / 100);
// Scale seconds and add from nanoseconds / 1'000'000'000, and add the console time offset (which might be negative)
*sec = stv_sec + (tv_sec * g_cfg.core.clocks_scale / 100u) + (tv_nsec / 1000000000ull);// + g_cfg.sys.console_time_offset;
*sec = stv_sec + (tv_sec * g_cfg.core.clocks_scale / 100u) + (tv_nsec / 1000000000ull) + g_cfg.sys.console_time_offset;
if (!nsec)
{

View File

@@ -1,8 +1,6 @@
#pragma once
#include "sys_event.h"
#include "Utilities/Thread.h"
#include "Emu/Memory/vm_ptr.h"

View File

@@ -6,7 +6,6 @@
#include "Emu/Cell/ErrorCodes.h"
#include "Emu/Cell/PPUThread.h"
#include "Emu/Cell/timers.hpp"
#include "Emu/Memory/vm_locking.h"
sys_vm_t::sys_vm_t(u32 _addr, u32 vsize, lv2_memory_container* ct, u32 psize)
: ct(ct)

View File

@@ -34,6 +34,8 @@ namespace vm
extern u8* const g_free_addr;
extern u8 g_reservations[65536 / 128 * 64];
static constexpr u64 g_exec_addr_seg_offset = 0x2'0000'0000ULL;
struct writer_lock;
enum memory_location_t : uint

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