This commit is contained in:
aenu
2025-08-20 23:48:44 +08:00
parent 5eee912e2f
commit b79daca261
137 changed files with 1547 additions and 3522 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
#if 1
template <>
void fmt_class_string<cheat_type>::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(const std::string& base_dir, std::vector<SaveDataEntry>& save_entries, s32 focused, u32 op, vm::ptr<CellSaveDataListSet> listSet, bool enable_overlay) override
s32 ShowSaveDataList(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

@@ -216,7 +216,7 @@ public:
// Apply patch (returns the number of entries applied)
void apply(std::vector<u32>& applied_total, const std::string& name, std::function<u8*(u32, u32)> mem_translate, u32 filesz = -1, u32 min_addr = 0);
// Deallocate memory used by patches
void unload(const std::string& name);

View File

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

View File

@@ -1,32 +1,10 @@
#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,7 +14,6 @@ enum class cheat_type : u8
signed_16_cheat,
signed_32_cheat,
signed_64_cheat,
float_32_cheat,
max
};

View File

@@ -1,4 +1,5 @@
#include "cond.h"
#include "sync.h"
// use constants, increase signal space

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,25 +384,17 @@ public:
template <typename T>
class lf_queue final
{
private:
struct fat_ptr
{
u64 ptr{};
u32 is_non_null{};
u32 reserved{};
};
atomic_t<u64> m_head{0};
atomic_t<fat_ptr> m_head{fat_ptr{}};
lf_queue_item<T>* load(fat_ptr value) const noexcept
lf_queue_item<T>* load(u64 value) const noexcept
{
return reinterpret_cast<lf_queue_item<T>*>(value.ptr);
return reinterpret_cast<lf_queue_item<T>*>(value >> 16);
}
// 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(fat_ptr{})) : nullptr)
if (auto* head = load(m_head) ? load(m_head.exchange(0)) : nullptr)
{
if (auto* prev = head->m_link)
{
@@ -428,7 +420,7 @@ public:
lf_queue(lf_queue&& other) noexcept
{
m_head.release(other.m_head.exchange(fat_ptr{}));
m_head.release(other.m_head.exchange(0));
}
lf_queue& operator=(lf_queue&& other) noexcept
@@ -438,7 +430,8 @@ public:
return *this;
}
delete load(m_head.exchange(other.m_head.exchange(fat_ptr{})));
delete load(m_head);
m_head.release(other.m_head.exchange(0));
return *this;
}
@@ -449,17 +442,12 @@ public:
void wait(std::nullptr_t /*null*/ = nullptr) noexcept
{
if (!operator bool())
if (m_head == 0)
{
get_wait_atomic().wait(0);
utils::bless<atomic_t<u32>>(&m_head)[1].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);
@@ -467,7 +455,7 @@ public:
explicit operator bool() const noexcept
{
return observe() != nullptr;
return m_head != 0;
}
template <bool Notify = true, typename... Args>
@@ -476,25 +464,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, fat_ptr{reinterpret_cast<u64>(item), item != nullptr, 0}))
while (!m_head.compare_exchange(oldv, reinterpret_cast<u64>(item) << 16))
{
item->m_link = load(oldv);
}
if (!oldv.ptr && Notify)
if (!oldv && Notify)
{
// Notify only if queue was empty
notify(true);
}
return !oldv.ptr;
return !oldv;
}
void notify(bool force = false)
{
if (force || operator bool())
{
get_wait_atomic().notify_one();
utils::bless<atomic_t<u32>>(&m_head)[1].notify_one();
}
}
@@ -510,7 +498,7 @@ public:
lf_queue_slice<T> pop_all_reversed()
{
lf_queue_slice<T> result;
result.m_head = load(m_head.exchange(fat_ptr{}));
result.m_head = load(m_head.exchange(0));
return result;
}

View File

@@ -2,6 +2,7 @@
#include <util/types.hpp>
#include <unordered_set>
#include <vector>
#include <string>
// Patch utilities specific to PPU code

View File

@@ -1,7 +1,6 @@
#include "util/types.hpp"
#include <vector>
#include <mutex>
#include "Emu/Cell/timers.hpp"
// Thread-safe object pool with garbage collection
class universal_pool
@@ -84,8 +83,9 @@ public:
transactional_storage& operator=(const transactional_storage&) = delete;
transactional_storage(transactional_storage&& other)
: pool(std::move(other.pool))
{
pool = std::move(other.pool);
std::unique_lock lock_other{other.current_mutex};
const std::shared_ptr<T> other_current = other.current;
other.current = nullptr;

View File

@@ -4,6 +4,7 @@
#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(static_cast<void*>(this), &r, sizeof(r));
std::memcpy(this, &r, sizeof(r));
}
ENABLE_BITWISE_SERIALIZATION;

View File

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

View File

@@ -38,17 +38,11 @@ void fmt_class_string<CellAudioInError>::format(std::string& out, u64 arg)
struct avconf_manager
{
shared_mutex mutex;
struct device_info
{
CellAudioInDeviceInfo info {};
std::string full_device_name; // The device name may be too long for CellAudioInDeviceInfo, so we additionally save the full name.
};
std::vector<device_info> devices;
std::vector<CellAudioInDeviceInfo> devices;
CellAudioInDeviceMode inDeviceMode = CELL_AUDIO_IN_SINGLE_DEVICE_MODE; // TODO: use somewhere
void copy_device_info(u32 num, vm::ptr<CellAudioInDeviceInfo> info) const;
std::optional<device_info> get_device_info(vm::cptr<char> name) const;
std::optional<CellAudioInDeviceInfo> get_device_info(vm::cptr<char> name) const;
avconf_manager();
@@ -68,89 +62,78 @@ avconf_manager::avconf_manager()
switch (g_cfg.audio.microphone_type)
{
case microphone_handler::standard:
{
for (u32 index = 0; index < mic_list.size(); index++)
{
device_info device {};
device.info.portType = CELL_AUDIO_IN_PORT_USB;
device.info.availableModeCount = 1;
device.info.state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE;
device.info.deviceId = 0xE11CC0DE + curindex;
device.info.type = 0xC0DEE11C;
device.info.availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM;
device.info.availableModes[0].channel = CELL_AUDIO_IN_CHNUM_2;
device.info.availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ;
device.info.deviceNumber = curindex;
device.full_device_name = mic_list[index];
strcpy_trunc(device.info.name, device.full_device_name);
devices.emplace_back();
devices[curindex].portType = CELL_AUDIO_IN_PORT_USB;
devices[curindex].availableModeCount = 1;
devices[curindex].state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE;
devices[curindex].deviceId = 0xE11CC0DE + curindex;
devices[curindex].type = 0xC0DEE11C;
devices[curindex].availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM;
devices[curindex].availableModes[0].channel = CELL_AUDIO_IN_CHNUM_2;
devices[curindex].availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ;
devices[curindex].deviceNumber = curindex;
strcpy_trunc(devices[curindex].name, mic_list[index]);
devices.push_back(std::move(device));
curindex++;
}
break;
}
case microphone_handler::real_singstar:
case microphone_handler::singstar:
{
// Only one device for singstar device
device_info device {};
device.info.portType = CELL_AUDIO_IN_PORT_USB;
device.info.availableModeCount = 1;
device.info.state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE;
device.info.deviceId = 0x00000001;
device.info.type = 0x14150000;
device.info.availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM;
device.info.availableModes[0].channel = CELL_AUDIO_IN_CHNUM_2;
device.info.availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ;
device.info.deviceNumber = curindex;
device.full_device_name = mic_list[0];
strcpy_trunc(device.info.name, device.full_device_name);
devices.emplace_back();
devices[curindex].portType = CELL_AUDIO_IN_PORT_USB;
devices[curindex].availableModeCount = 1;
devices[curindex].state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE;
devices[curindex].deviceId = 0x00000001;
devices[curindex].type = 0x14150000;
devices[curindex].availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM;
devices[curindex].availableModes[0].channel = CELL_AUDIO_IN_CHNUM_2;
devices[curindex].availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ;
devices[curindex].deviceNumber = curindex;
strcpy_trunc(devices[curindex].name, mic_list[0]);
devices.push_back(std::move(device));
curindex++;
break;
}
case microphone_handler::rocksmith:
{
device_info device {};
device.info.portType = CELL_AUDIO_IN_PORT_USB;
device.info.availableModeCount = 1;
device.info.state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE;
device.info.deviceId = 0x12BA00FF; // Specific to rocksmith usb input
device.info.type = 0xC0DE73C4;
device.info.availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM;
device.info.availableModes[0].channel = CELL_AUDIO_IN_CHNUM_1;
device.info.availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ;
device.info.deviceNumber = curindex;
device.full_device_name = mic_list[0];
strcpy_trunc(device.info.name, device.full_device_name);
devices.emplace_back();
devices[curindex].portType = CELL_AUDIO_IN_PORT_USB;
devices[curindex].availableModeCount = 1;
devices[curindex].state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE;
devices[curindex].deviceId = 0x12BA00FF; // Specific to rocksmith usb input
devices[curindex].type = 0xC0DE73C4;
devices[curindex].availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM;
devices[curindex].availableModes[0].channel = CELL_AUDIO_IN_CHNUM_1;
devices[curindex].availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ;
devices[curindex].deviceNumber = curindex;
strcpy_trunc(devices[curindex].name, mic_list[0]);
devices.push_back(std::move(device));
curindex++;
break;
}
case microphone_handler::null:
default:
break;
default: break;
}
}
if (g_cfg.io.camera != camera_handler::null)
{
device_info device {};
device.info.portType = CELL_AUDIO_IN_PORT_USB;
device.info.availableModeCount = 1;
device.info.state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE;
device.info.deviceId = 0xDEADBEEF;
device.info.type = 0xBEEFDEAD;
device.info.availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM;
device.info.availableModes[0].channel = CELL_AUDIO_IN_CHNUM_NONE;
device.info.availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ;
device.info.deviceNumber = curindex;
device.full_device_name = "USB Camera";
strcpy_trunc(device.info.name, device.full_device_name);
devices.emplace_back();
devices[curindex].portType = CELL_AUDIO_IN_PORT_USB;
devices[curindex].availableModeCount = 1;
devices[curindex].state = CELL_AUDIO_IN_DEVICE_STATE_AVAILABLE;
devices[curindex].deviceId = 0xDEADBEEF;
devices[curindex].type = 0xBEEFDEAD;
devices[curindex].availableModes[0].type = CELL_AUDIO_IN_CODING_TYPE_LPCM;
devices[curindex].availableModes[0].channel = CELL_AUDIO_IN_CHNUM_NONE;
devices[curindex].availableModes[0].fs = CELL_AUDIO_IN_FS_8KHZ | CELL_AUDIO_IN_FS_12KHZ | CELL_AUDIO_IN_FS_16KHZ | CELL_AUDIO_IN_FS_24KHZ | CELL_AUDIO_IN_FS_32KHZ | CELL_AUDIO_IN_FS_48KHZ;
devices[curindex].deviceNumber = curindex;
strcpy_trunc(devices[curindex].name, "USB Camera");
devices.push_back(std::move(device));
curindex++;
}
}
@@ -159,14 +142,14 @@ void avconf_manager::copy_device_info(u32 num, vm::ptr<CellAudioInDeviceInfo> in
{
memset(info.get_ptr(), 0, sizeof(CellAudioInDeviceInfo));
ensure(num < devices.size());
*info = devices[num].info;
*info = devices[num];
}
std::optional<avconf_manager::device_info> avconf_manager::get_device_info(vm::cptr<char> name) const
std::optional<CellAudioInDeviceInfo> avconf_manager::get_device_info(vm::cptr<char> name) const
{
for (const device_info& device : devices)
for (const CellAudioInDeviceInfo& device : devices)
{
if (strncmp(device.info.name, name.get_ptr(), sizeof(device.info.name)) == 0)
if (strncmp(device.name, name.get_ptr(), sizeof(device.name)) == 0)
{
return device;
}
@@ -237,57 +220,17 @@ error_code cellAudioInGetDeviceInfo(u32 deviceNumber, u32 deviceIndex, vm::ptr<C
return CELL_OK;
}
template <bool Is_Float, bool Range_Limited>
void convert_cursor_color(const u8* src, u8* dst, s32 num, f32 gamma)
{
for (s32 i = 0; i < num; i++, src += 4, dst += 4)
{
for (s32 c = 1; c < 4; c++)
{
if constexpr (Is_Float)
{
if constexpr (Range_Limited)
{
const f32 val = (src[c] / 255.0f) * 219.0f + 16.0f;
dst[c] = static_cast<u8>(val + 0.5f);
}
else
{
dst[c] = src[c];
}
}
else
{
f32 val = std::clamp(std::pow(src[c] / 255.0f, gamma), 0.0f, 1.0f);
if constexpr (Range_Limited)
{
val = val * 219.0f + 16.0f;
}
else
{
val *= 255.0f;
}
dst[c] = static_cast<u8>(val + 0.5f);
}
}
}
}
error_code cellVideoOutConvertCursorColor(u32 videoOut, s32 displaybuffer_format, f32 gamma, s32 source_buffer_format, vm::ptr<void> src_addr, vm::ptr<u32> dest_addr, s32 num)
{
cellAvconfExt.warning("cellVideoOutConvertCursorColor(videoOut=%d, displaybuffer_format=0x%x, gamma=%f, source_buffer_format=0x%x, src_addr=*0x%x, dest_addr=*0x%x, num=0x%x)", videoOut,
cellAvconfExt.todo("cellVideoOutConvertCursorColor(videoOut=%d, displaybuffer_format=0x%x, gamma=0x%x, source_buffer_format=0x%x, src_addr=*0x%x, dest_addr=*0x%x, num=0x%x)", videoOut,
displaybuffer_format, gamma, source_buffer_format, src_addr, dest_addr, num);
if (!src_addr || !dest_addr)
if (!dest_addr || num == 0)
{
return CELL_VIDEO_OUT_ERROR_ILLEGAL_PARAMETER;
}
if (displaybuffer_format < 0 ||
displaybuffer_format > CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_R16G16B16X16_FLOAT ||
source_buffer_format != CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8)
if (displaybuffer_format > CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_R16G16B16X16_FLOAT || src_addr)
{
return CELL_VIDEO_OUT_ERROR_PARAMETER_OUT_OF_RANGE;
}
@@ -308,32 +251,6 @@ error_code cellVideoOutConvertCursorColor(u32 videoOut, s32 displaybuffer_format
return error;
}
const u8* src = reinterpret_cast<const u8*>(src_addr.get_ptr());
u8* dst = reinterpret_cast<u8*>(dest_addr.get_ptr());
if (displaybuffer_format == CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_R16G16B16X16_FLOAT)
{
if (*rgbOutputRange == CELL_VIDEO_OUT_RGB_OUTPUT_RANGE_LIMITED)
{
convert_cursor_color<true, true>(src, dst, num, gamma);
}
else
{
convert_cursor_color<true, false>(src, dst, num, gamma);
}
}
else
{
if (*rgbOutputRange == CELL_VIDEO_OUT_RGB_OUTPUT_RANGE_LIMITED)
{
convert_cursor_color<false, true>(src, dst, num, gamma);
}
else
{
convert_cursor_color<false, false>(src, dst, num, gamma);
}
}
return CELL_OK;
}
@@ -481,8 +398,8 @@ error_code cellAudioInRegisterDevice(u64 deviceType, vm::cptr<char> name, vm::pt
auto& av_manager = g_fxo->get<avconf_manager>();
const std::lock_guard lock(av_manager.mutex);
std::optional<avconf_manager::device_info> device = av_manager.get_device_info(name);
if (!device)
std::optional<CellAudioInDeviceInfo> info = av_manager.get_device_info(name);
if (!info || !memchr(info->name, '\0', sizeof(info->name)))
{
// TODO
return CELL_AUDIO_IN_ERROR_DEVICE_NOT_FOUND;
@@ -490,7 +407,7 @@ error_code cellAudioInRegisterDevice(u64 deviceType, vm::cptr<char> name, vm::pt
auto& mic_thr = g_fxo->get<mic_thread>();
const std::lock_guard mic_lock(mic_thr.mutex);
const u32 device_number = mic_thr.register_device(device->full_device_name);
const u32 device_number = mic_thr.register_device(info->name);
return not_an_error(device_number);
}

View File

@@ -6,7 +6,6 @@
#include "Emu/Cell/PPUModule.h"
#include "Emu/Cell/lv2/sys_event.h"
#include "Emu/IdManager.h"
#include "Emu/Cell/timers.hpp"
#include <cmath>
@@ -61,6 +60,11 @@ void fmt_class_string<CellCameraFormat>::format(std::string& out, u64 arg)
});
}
// Temporarily
#ifndef _MSC_VER
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
// **************
// * Prototypes *
// **************
@@ -144,44 +148,9 @@ void camera_context::save(utils::serial& ar)
return;
}
const s32 version = GET_OR_USE_SERIALIZATION_VERSION(ar.is_writing(), cellCamera);
GET_OR_USE_SERIALIZATION_VERSION(ar.is_writing(), cellCamera);
ar(notify_data_map, start_timestamp_us, read_mode, is_streaming, is_attached, is_open, info, attr, frame_num);
if (ar.is_writing() || version >= 2)
{
ar(is_attached_dirty);
}
if (!ar.is_writing())
{
if (is_open)
{
if (!open_camera())
{
cellCamera.error("Failed to open camera while loading savestate");
}
else if (is_streaming && !start_camera())
{
cellCamera.error("Failed to start camera while loading savestate");
}
}
}
}
gem_camera_shared::gem_camera_shared(utils::serial& ar)
{
save(ar);
}
void gem_camera_shared::save(utils::serial& ar)
{
const s32 version = GET_OR_USE_SERIALIZATION_VERSION(ar.is_writing(), cellCamera);
if (ar.is_writing() || version >= 2)
{
ar(frame_timestamp_us, width, height, size, format);
}
}
static bool check_dev_num(s32 dev_num)
@@ -397,7 +366,7 @@ error_code check_init_and_open(s32 dev_num)
}
// This represents a recurring subfunction throughout libCamera
error_code check_resolution(s32 /*dev_num*/)
error_code check_resolution(s32 dev_num)
{
// TODO: Some sort of connection check maybe?
//if (error == CELL_CAMERA_ERROR_RESOLUTION_UNKNOWN)
@@ -408,7 +377,7 @@ error_code check_resolution(s32 /*dev_num*/)
return CELL_OK;
}
// This represents an often used sequence in libCamera (usually the beginning of a subfunction).
// This represents a oftenly used sequence in libCamera (usually the beginning of a subfunction).
// There also exist common sequences for mutex lock/unlock by the way.
error_code check_resolution_ex(s32 dev_num)
{
@@ -466,6 +435,7 @@ error_code cellCameraInit()
g_camera.attr[CELL_CAMERA_USBLOAD] = { 4 };
break;
}
case fake_camera_type::eyetoy2:
{
g_camera.attr[CELL_CAMERA_SATURATION] = { 64 };
@@ -485,6 +455,7 @@ error_code cellCameraInit()
g_camera.attr[CELL_CAMERA_AGCHIGH] = { 64 };
break;
}
case fake_camera_type::uvc1_1:
{
g_camera.attr[CELL_CAMERA_DEVICEID] = { 0x5ca, 0x18d0 }; // KBCR-S01MU
@@ -492,14 +463,14 @@ error_code cellCameraInit()
g_camera.attr[CELL_CAMERA_NUMFRAME] = { 1 }; // Amount of supported resolutions
break;
}
default:
cellCamera.todo("Trying to init cellCamera with un-researched camera type.");
break;
}
// TODO: Some other default attributes? Need to check the actual behaviour on a real PS3.
g_camera.is_attached = g_cfg.io.camera != camera_handler::null;
g_camera.is_attached = true;
g_camera.init = 1;
return CELL_OK;
}
@@ -813,26 +784,26 @@ s32 cellCameraIsAttached(s32 dev_num)
if (g_cfg.io.camera == camera_handler::null)
{
return 0;
return false;
}
auto& g_camera = g_fxo->get<camera_thread>();
if (!g_camera.init)
{
return 0;
return false;
}
if (!check_dev_num(dev_num))
{
return 0;
return false;
}
vm::var<s32> type;
if (cellCameraGetType(dev_num, type) != CELL_OK)
{
return 0;
return false;
}
std::lock_guard lock(g_camera.mutex);
@@ -845,17 +816,17 @@ s32 cellCameraIsAttached(s32 dev_num)
// normally should be attached immediately after event queue is registered, but just to be sure
if (!is_attached)
{
g_camera.is_attached = is_attached = true;
g_camera.is_attached_dirty = true;
g_camera.send_attach_state(true);
is_attached = g_camera.is_attached;
}
}
return is_attached ? 1 : 0;
return is_attached;
}
s32 cellCameraIsOpen(s32 dev_num)
{
cellCamera.trace("cellCameraIsOpen(dev_num=%d)", dev_num);
cellCamera.notice("cellCameraIsOpen(dev_num=%d)", dev_num);
if (g_cfg.io.camera == camera_handler::null)
{
@@ -881,7 +852,7 @@ s32 cellCameraIsOpen(s32 dev_num)
s32 cellCameraIsStarted(s32 dev_num)
{
cellCamera.trace("cellCameraIsStarted(dev_num=%d)", dev_num);
cellCamera.notice("cellCameraIsStarted(dev_num=%d)", dev_num);
if (g_cfg.io.camera == camera_handler::null)
{
@@ -1635,15 +1606,9 @@ void camera_context::operator()()
{
while (thread_ctrl::state() != thread_state::aborting && !Emu.IsStopped())
{
// send ATTACH event
if (init && is_attached_dirty && !Emu.IsPausedOrReady())
{
send_attach_state(is_attached);
}
const s32 fps = info.framerate;
if (!init || !fps || Emu.IsPausedOrReady() || g_cfg.io.camera == camera_handler::null)
if (!fps || Emu.IsPausedOrReady() || g_cfg.io.camera == camera_handler::null)
{
thread_ctrl::wait_for(1000); // hack
continue;
@@ -1818,7 +1783,6 @@ void camera_context::reset_state()
read_mode = CELL_CAMERA_READ_FUNCCALL;
is_streaming = false;
is_attached = false;
is_attached_dirty = false;
is_open = false;
info.framerate = 0;
std::memset(&attr, 0, sizeof(attr));
@@ -1864,7 +1828,6 @@ void camera_context::send_attach_state(bool attached)
// We're not expected to send any events for attaching/detaching
is_attached = attached;
is_attached_dirty = false;
}
void camera_context::set_attr(s32 attrib, u32 arg1, u32 arg2)
@@ -1899,13 +1862,15 @@ void camera_context::set_attr(s32 attrib, u32 arg1, u32 arg2)
void camera_context::add_queue(u64 key, u64 source, u64 flag)
{
std::lock_guard lock(mutex);
{
std::lock_guard lock_data_map(mutex_notify_data_map);
notify_data_map[key] = { source, flag };
}
is_attached_dirty = true;
// send ATTACH event - HACKY
send_attach_state(is_attached);
}
void camera_context::remove_queue(u64 key)
@@ -1932,8 +1897,7 @@ bool camera_context::on_handler_state(camera_handler_base::camera_handler_state
{
if (is_attached)
{
is_attached = false;
is_attached_dirty = true;
send_attach_state(false);
}
if (handler)
{
@@ -1974,8 +1938,7 @@ bool camera_context::on_handler_state(camera_handler_base::camera_handler_state
if (!is_attached)
{
cellCamera.warning("Camera handler not attached. Sending attach event...", static_cast<int>(state));
is_attached = true;
is_attached_dirty = true;
send_attach_state(true);
}
break;
}

View File

@@ -1,9 +1,9 @@
#pragma once
#include "Utilities/Timer.h"
#include "Emu/Cell/lv2/sys_memory.h"
#include "Utilities/Thread.h"
#include "Emu/Io/camera_handler_base.h"
#include "Emu/Memory/vm_ptr.h"
#include "Utilities/mutex.h"
#include <map>
@@ -427,7 +427,6 @@ public:
atomic_t<u8> read_mode{CELL_CAMERA_READ_FUNCCALL};
atomic_t<bool> is_streaming{false};
atomic_t<bool> is_attached{false};
atomic_t<bool> is_attached_dirty{false};
atomic_t<bool> is_open{false};
CellCameraInfoEx info{};
@@ -472,13 +471,6 @@ using camera_thread = named_thread<camera_context>;
/// Shared data between cellGem and cellCamera
struct gem_camera_shared
{
gem_camera_shared() {}
gem_camera_shared(utils::serial& ar);
void save(utils::serial& ar);
SAVESTATE_INIT_POS(7);
atomic_t<u64> frame_timestamp_us{}; // latest read timestamp from cellCamera (cellCameraRead(Ex))
atomic_t<s32> width{640};
atomic_t<s32> height{480};

View File

@@ -107,8 +107,13 @@ struct cross_controller
void stop_thread()
{
// Join thread
connection_thread.reset();
if (connection_thread)
{
auto& thread = *connection_thread;
thread = thread_state::aborting;
thread();
connection_thread.reset();
}
};
};

View File

@@ -26,6 +26,11 @@ 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;
@@ -33,134 +38,134 @@ using AtomicInterlock = volatile struct CellDaisyAtomicInterlock;
error_code cellDaisyLFQueue2GetPopPointer(vm::ptr<LFQueue2> queue, vm::ptr<s32> pPointer, u32 isBlocking)
{
cellDaisy.todo("cellDaisyLFQueue2GetPopPointer(queue=*0x%x, pPointer=*0x%x, isBlocking=%d)", queue, pPointer, isBlocking);
cellDaisy.todo("cellDaisyLFQueue2GetPopPointer()");
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(queue=*0x%x, pointer=0x%x, fpSendSignal=*0x%x, isQueueFull=%d)", queue, pointer, fpSendSignal, isQueueFull);
cellDaisy.todo("cellDaisyLFQueue2CompletePopPointer()");
return CELL_OK;
}
void cellDaisyLFQueue2PushOpen(vm::ptr<LFQueue2> queue)
{
cellDaisy.todo("cellDaisyLFQueue2PushOpen(queue=*0x%x)", queue);
cellDaisy.todo("cellDaisyLFQueue2PushOpen()");
}
error_code cellDaisyLFQueue2PushClose(vm::ptr<LFQueue2> queue, vm::ptr<s32(vm::ptr<void>, u32)> fpSendSignal)
{
cellDaisy.todo("cellDaisyLFQueue2PushClose(queue=*0x%x, fpSendSignal=*0x%x)", queue, fpSendSignal);
cellDaisy.todo("cellDaisyLFQueue2PushClose()");
return CELL_OK;
}
void cellDaisyLFQueue2PopOpen(vm::ptr<LFQueue2> queue)
{
cellDaisy.todo("cellDaisyLFQueue2PopOpen(queue=*0x%x)", queue);
cellDaisy.todo("cellDaisyLFQueue2PopOpen()");
}
error_code cellDaisyLFQueue2PopClose(vm::ptr<LFQueue2> queue, vm::ptr<s32(vm::ptr<void>, u32)> fpSendSignal)
{
cellDaisy.todo("cellDaisyLFQueue2PopClose(queue=*0x%x, fpSendSignal=*0x%x)", queue, fpSendSignal);
cellDaisy.todo("cellDaisyLFQueue2PopClose()");
return CELL_OK;
}
error_code cellDaisyLFQueue2HasUnfinishedConsumer(vm::ptr<LFQueue2> queue, u32 isCancelled)
{
cellDaisy.todo("cellDaisyLFQueue2HasUnfinishedConsumer(queue=*0x%x, isCancelled=%d)", queue, isCancelled);
cellDaisy.todo("cellDaisyLFQueue2HasUnfinishedConsumer()");
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(buffer=*0x%x, count=%d, fmt=*0x%x, fmt_args=%d)", buffer, count, fmt, fmt_args.count);
cellDaisy.todo("cellDaisy_snprintf()");
return CELL_OK;
}
error_code cellDaisyLock_initialize(vm::ptr<Lock> _this, u32 depth)
{
cellDaisy.todo("cellDaisyLock_initialize(_this=*0x%x, depth=%d)", _this, depth);
cellDaisy.todo("cellDaisyLock_initialize()");
return CELL_OK;
}
error_code cellDaisyLock_getNextHeadPointer(vm::ptr<Lock> _this)
{
cellDaisy.todo("cellDaisyLock_getNextHeadPointer(_this=*0x%x)", _this);
cellDaisy.todo("cellDaisyLock_getNextHeadPointer()");
return CELL_OK;
}
error_code cellDaisyLock_getNextTailPointer(vm::ptr<Lock> _this)
{
cellDaisy.todo("cellDaisyLock_getNextTailPointer(_this=*0x%x)", _this);
cellDaisy.todo("cellDaisyLock_getNextTailPointer()");
return CELL_OK;
}
error_code cellDaisyLock_completeConsume(vm::ptr<Lock> _this, u32 pointer)
{
cellDaisy.todo("cellDaisyLock_completeConsume(_this=*0x%x, pointer=0x%x)", _this, pointer);
cellDaisy.todo("cellDaisyLock_completeConsume()");
return CELL_OK;
}
error_code cellDaisyLock_completeProduce(vm::ptr<Lock> _this, u32 pointer)
{
cellDaisy.todo("cellDaisyLock_completeProduce(_this=*0x%x, pointer=0x%x)", _this, pointer);
cellDaisy.todo("cellDaisyLock_completeProduce()");
return CELL_OK;
}
error_code cellDaisyLock_pushOpen(vm::ptr<Lock> _this)
{
cellDaisy.todo("cellDaisyLock_pushOpen(_this=*0x%x)", _this);
cellDaisy.todo("cellDaisyLock_pushOpen()");
return CELL_OK;
}
error_code cellDaisyLock_pushClose(vm::ptr<Lock> _this)
{
cellDaisy.todo("cellDaisyLock_pushClose(_this=*0x%x)", _this);
cellDaisy.todo("cellDaisyLock_pushClose()");
return CELL_OK;
}
error_code cellDaisyLock_popOpen(vm::ptr<Lock> _this)
{
cellDaisy.todo("cellDaisyLock_popOpen(_this=*0x%x)", _this);
cellDaisy.todo("cellDaisyLock_popOpen()");
return CELL_OK;
}
error_code cellDaisyLock_popClose(vm::ptr<Lock> _this)
{
cellDaisy.todo("cellDaisyLock_popClose(_this=*0x%x)", _this);
cellDaisy.todo("cellDaisyLock_popClose()");
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(_this=*0x%x, ea=*0x%x, size=%d, eaSignal=*0x%x, fpSendSignal=*0x%x)", _this, ea, size, eaSignal, fpSendSignal);
cellDaisy.todo("cellDaisyScatterGatherInterlock_1()");
}
void cellDaisyScatterGatherInterlock_2(vm::ptr<ScatterGatherInterlock> _this, u32 size, vm::ptr<u32> ids, u32 numSpus, u8 spup)
{
cellDaisy.todo("cellDaisyScatterGatherInterlock_2(_this=*0x%x, size=%d, ids=*0x%x, numSpus=%d, spup=%d)", _this, size, ids, numSpus, spup);
cellDaisy.todo("cellDaisyScatterGatherInterlock_2()");
}
void cellDaisyScatterGatherInterlock_9tor(vm::ptr<ScatterGatherInterlock> _this)
{
cellDaisy.todo("cellDaisyScatterGatherInterlock_9tor(_this=*0x%x)", _this);
cellDaisy.todo("cellDaisyScatterGatherInterlock_9tor()");
}
error_code cellDaisyScatterGatherInterlock_probe(vm::ptr<ScatterGatherInterlock> _this, u32 isBlocking)
{
cellDaisy.todo("cellDaisyScatterGatherInterlock_probe(_this=*0x%x, isBlocking=%d)", _this, isBlocking);
cellDaisy.todo("cellDaisyScatterGatherInterlock_probe()");
return CELL_OK;
}
error_code cellDaisyScatterGatherInterlock_release(vm::ptr<ScatterGatherInterlock> _this)
{
cellDaisy.todo("cellDaisyScatterGatherInterlock_release(_this=*0x%x)", _this);
cellDaisy.todo("cellDaisyScatterGatherInterlock_release()");
return CELL_OK;
}
void cellDaisyScatterGatherInterlock_proceedSequenceNumber(vm::ptr<ScatterGatherInterlock> _this)
{
cellDaisy.todo("cellDaisyScatterGatherInterlock_proceedSequenceNumber(_this=*0x%x)", _this);
cellDaisy.todo("cellDaisyScatterGatherInterlock_proceedSequenceNumber()");
}

View File

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

View File

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

View File

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

View File

@@ -12,7 +12,6 @@
#include "Emu/IdManager.h"
#include "Emu/RSX/Overlays/overlay_cursor.h"
#include "Input/pad_thread.h"
#include "Emu/Cell/lv2/sys_memory.h"
#ifdef HAVE_LIBEVDEV
#include "Input/evdev_gun_handler.h"

View File

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

View File

@@ -9,8 +9,15 @@
#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)
{
@@ -266,7 +273,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
@@ -295,7 +302,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
}
const u8 packedField = buffer[10];
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;
@@ -513,8 +520,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);
constexpr char nComponents = 4;
const u32 image_size = width * height * nComponents;
const char nComponents = 4;
uint image_size = width * height * nComponents;
switch(current_outParam.outputColorSpace)
{
@@ -534,8 +541,9 @@ 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
@@ -571,8 +579,9 @@ 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++)
{
const char c1 = in[pos];
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;
}
constexpr const char* chars = "0123456789ABCDEF";
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++)
{
const char c1 = in[pos];
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;
}
constexpr const char* chars = "0123456789ABCDEF";
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;
const char c1 = in[pos++];
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)
{
const u32 utmp = static_cast<u32>(c);
u32 utmp = static_cast<u32>(c);
s32 stmp = utmp - 48;
if (static_cast<u8>(c - 48) > 9)
{

View File

@@ -9,8 +9,15 @@
#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)
{
@@ -35,19 +42,19 @@ void fmt_class_string<CellJpgDecError>::format(std::string& out, u64 arg)
error_code cellJpgDecCreate(u32 mainHandle, u32 threadInParam, u32 threadOutParam)
{
cellJpgDec.todo("cellJpgDecCreate(mainHandle=0x%x, threadInParam=0x%x, threadOutParam=0x%x)", mainHandle, threadInParam, threadOutParam);
UNIMPLEMENTED_FUNC(cellJpgDec);
return CELL_OK;
}
error_code cellJpgDecExtCreate(u32 mainHandle, u32 threadInParam, u32 threadOutParam, u32 extThreadInParam, u32 extThreadOutParam)
{
cellJpgDec.todo("cellJpgDecExtCreate(mainHandle=0x%x, threadInParam=0x%x, threadOutParam=0x%x, extThreadInParam=0x%x, extThreadOutParam=0x%x)", mainHandle, threadInParam, threadOutParam, extThreadInParam, extThreadOutParam);
UNIMPLEMENTED_FUNC(cellJpgDec);
return CELL_OK;
}
error_code cellJpgDecDestroy(u32 mainHandle)
{
cellJpgDec.todo("cellJpgDecDestroy(mainHandle=0x%x)", mainHandle);
UNIMPLEMENTED_FUNC(cellJpgDec);
return CELL_OK;
}
@@ -69,7 +76,7 @@ error_code cellJpgDecOpen(u32 mainHandle, vm::ptr<u32> subHandle, vm::ptr<CellJp
case CELL_JPGDEC_FILE:
{
// Get file descriptor and size
const std::string real_path = vfs::get(src->fileName.get_ptr());
const auto real_path = vfs::get(src->fileName.get_ptr());
fs::file file_s(real_path);
if (!file_s) return CELL_JPGDEC_ERROR_OPEN_FILE;
@@ -120,8 +127,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
@@ -151,12 +158,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
@@ -165,15 +172,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;
@@ -225,7 +232,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 = 0, height = 0, actual_components = 0;
int width, height, actual_components;
auto image = std::unique_ptr<unsigned char,decltype(&::free)>
(
stbi_load_from_memory(jpg.get(), ::narrow<int>(fileSize), &width, &height, &actual_components, 4),
@@ -260,17 +267,18 @@ 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:
{
constexpr int nComponents = 4;
const 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);
std::vector<char> output(image_size);
const auto output = std::make_unique<char[]>(linesize);
for (int i = 0; i < height; i++)
{
const int dstOffset = i * bytesPerLine;
@@ -282,32 +290,33 @@ 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.data(), linesize);
std::memcpy(&data[dstOffset], output.get(), linesize);
}
}
else
{
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++)
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++)
{
const u32 val = *source_current;
uint 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.data(), image_size);
std::memcpy(data.get_ptr(), img.get(), 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;
@@ -315,7 +324,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 "Emu/Io/Keyboard.h"
#include "cellKb.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_CODEPAGE_932,
L10N_SHIFT_JIS,
L10N_CODEPAGE_936,
L10N_GBK = L10N_CODEPAGE_936,
L10N_GBK,
L10N_CODEPAGE_949,
L10N_UHC = L10N_CODEPAGE_949,
L10N_UHC,
L10N_CODEPAGE_950,
L10N_BIG5 = L10N_CODEPAGE_950,
L10N_BIG5,
L10N_CODEPAGE_1251,
L10N_CODEPAGE_1252,
L10N_EUC_CN,
L10N_EUC_JP,
L10N_EUC_KR,
L10N_ISO_2022_JP,
L10N_JIS = L10N_ISO_2022_JP,
L10N_JIS,
L10N_ARIB,
L10N_HZ,
L10N_GB18030,
L10N_RIS_506,
L10N_MUSIC_SHIFT_JIS = L10N_RIS_506,
L10N_MUSIC_SHIFT_JIS,
//FW 3.10 and below
L10N_CODEPAGE_852,
L10N_CODEPAGE_1250,
@@ -88,12 +88,3 @@ 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,5 +1,6 @@
#include "stdafx.h"
#include "Emu/IdManager.h"
#include "Emu/System.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/Io/MouseHandler.h"

View File

@@ -177,11 +177,6 @@ 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:
@@ -218,29 +213,19 @@ 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 = std::move(info), status](ppu_thread& ppu) -> s32
sysutil_register_cb([&music, 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(dir);
context.set_track(track);
context.set_playlist(info.path);
// TODO: context.repeat_mode = CELL_SEARCH_REPEATMODE_NONE;
// TODO: context.context_option = CELL_SEARCH_CONTEXTOPTION_NONE;
music.current_selection_context = std::move(context);
music.current_selection_context = context;
music.current_selection_context.create_playlist(music_selection_context::get_next_hash());
cellMusic.success("Media list dialog: selected entry '%s'", music.current_selection_context.playlist.front());
cellMusic.success("Media list dialog: selected entry '%s'", context.playlist.front());
}
else
{
@@ -571,7 +556,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, "Not initialized" };
return CELL_MUSIC2_ERROR_GENERIC;
error_code result = CELL_OK;
@@ -600,7 +585,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, "Not initialized" };
return CELL_MUSIC_ERROR_GENERIC;
error_code result = CELL_OK;

View File

@@ -166,7 +166,6 @@ 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,6 +12,9 @@
#include "cellSysutil.h"
#include "util/media_utils.h"
#include <deque>
LOG_CHANNEL(cellMusicDecode);
template<>
@@ -137,29 +140,19 @@ 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 = std::move(info), status](ppu_thread& ppu) -> s32
sysutil_register_cb([&dec, 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(dir);
context.set_track(track);
context.set_playlist(info.path);
// TODO: context.repeat_mode = CELL_SEARCH_REPEATMODE_NONE;
// TODO: context.context_option = CELL_SEARCH_CONTEXTOPTION_NONE;
dec.current_selection_context = std::move(context);
dec.current_selection_context = context;
dec.current_selection_context.create_playlist(music_selection_context::get_next_hash());
cellMusicDecode.success("Media list dialog: selected entry '%s'", dec.current_selection_context.playlist.front());
cellMusicDecode.success("Media list dialog: selected entry '%s'", context.playlist.front());
}
else
{

View File

@@ -2,6 +2,7 @@
#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;
}
constexpr u32 pos = sizeof(magic);
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("get_yaml_path: Failed to create path: %s (%s)", path, fs::g_tls_error);
cellMusicSelectionContext.fatal("Failed to create path: %s (%s)", path, fs::g_tls_error);
}
return path + hash + ".yml";
@@ -101,21 +101,14 @@ void music_selection_context::set_playlist(const std::string& path)
continue;
}
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));
playlist.push_back(dir_path + std::string(path + "/" + dir_entry.name).substr(vfs_dir_path.length()));
}
}
else
{
content_type = CELL_SEARCH_CONTENTTYPE_MUSIC;
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));
playlist.push_back(dir_path + path.substr(vfs_dir_path.length()));
}
valid = true;
}
void music_selection_context::create_playlist(const std::string& new_hash)
@@ -123,7 +116,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("create_playlist: Saving music playlist file %s", yaml_path);
cellMusicSelectionContext.notice("Saving music playlist file %s", yaml_path);
YAML::Emitter out;
out << YAML::BeginMap;
@@ -145,9 +138,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()) < out.size() || !file.commit())
if (!file.file || (file.file.write(out.c_str(), out.size()), !file.commit()))
{
cellMusicSelectionContext.error("create_playlist: Failed to create music playlist file '%s' (error=%s)", yaml_path, fs::g_tls_error);
cellMusicSelectionContext.error("Failed to create music playlist file %s (error=%s)", yaml_path, fs::g_tls_error);
}
}
@@ -156,7 +149,7 @@ bool music_selection_context::load_playlist()
playlist.clear();
const std::string path = get_yaml_path();
cellMusicSelectionContext.notice("load_playlist: Loading music playlist file '%s'", path);
cellMusicSelectionContext.notice("Loading music playlist file %s", path);
std::string content;
{
@@ -165,7 +158,7 @@ bool music_selection_context::load_playlist()
if (!file)
{
cellMusicSelectionContext.error("load_playlist: Failed to load music playlist file '%s': %s", path, fs::g_tls_error);
cellMusicSelectionContext.error("Failed to load music playlist file %s: %s", path, fs::g_tls_error);
return false;
}
@@ -176,7 +169,7 @@ bool music_selection_context::load_playlist()
if (!error.empty() || !root)
{
cellMusicSelectionContext.error("load_playlist: Failed to load music playlist file '%s':\n%s", path, error);
cellMusicSelectionContext.error("Failed to load music playlist file %s:\n%s", path, error);
return false;
}
@@ -185,54 +178,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("load_playlist: No Version entry found. Error: '%s' (file: '%s')", err, path);
cellMusicSelectionContext.error("No Version entry found. Error: '%s' (file: %s)", err, path);
return false;
}
if (version != target_version)
{
cellMusicSelectionContext.error("load_playlist: Version '%s' does not match music playlist target '%s' (file: '%s')", version, target_version, path);
cellMusicSelectionContext.error("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("load_playlist: No FileType entry found. Error: '%s' (file: '%s')", err, path);
cellMusicSelectionContext.error("No FileType entry found. Error: '%s' (file: %s)", err, path);
return false;
}
if (file_type != target_file_type)
{
cellMusicSelectionContext.error("load_playlist: FileType '%s' does not match music playlist target '%s' (file: '%s')", file_type, target_file_type, path);
cellMusicSelectionContext.error("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("load_playlist: No ContentType entry found. Error: '%s' (file: '%s')", err, path);
cellMusicSelectionContext.error("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("load_playlist: No ContextOption entry found. Error: '%s' (file: '%s')", err, path);
cellMusicSelectionContext.error("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("load_playlist: No RepeatMode entry found. Error: '%s' (file: '%s')", err, path);
cellMusicSelectionContext.error("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("load_playlist: No FirstTrack entry found. Error: '%s' (file: '%s')", err, path);
cellMusicSelectionContext.error("No FirstTrack entry found. Error: '%s' (file: %s)", err, path);
return false;
}
@@ -240,49 +233,24 @@ bool music_selection_context::load_playlist()
if (!track_node || track_node.Type() != YAML::NodeType::Sequence)
{
cellMusicSelectionContext.error("load_playlist: No Tracks entry found or Tracks is not a Sequence. (file: '%s')", path);
cellMusicSelectionContext.error("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("step_track: No tracks to play...");
cellMusicSelectionContext.error("No tracks to play...");
current_track = umax;
return umax;
}
@@ -297,7 +265,7 @@ u32 music_selection_context::step_track(bool next)
if (++current_track >= playlist.size())
{
// We are at the end of the playlist.
cellMusicSelectionContext.notice("step_track: No more tracks to play in playlist...");
cellMusicSelectionContext.notice("No more tracks to play in playlist...");
current_track = umax;
return umax;
}
@@ -308,7 +276,7 @@ u32 music_selection_context::step_track(bool next)
if (current_track == 0)
{
// We are at the start of the playlist.
cellMusicSelectionContext.notice("step_track: No more tracks to play in playlist...");
cellMusicSelectionContext.notice("No more tracks to play in playlist...");
current_track = umax;
return umax;
}
@@ -346,13 +314,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("step_track: No more tracks to play...");
cellMusicSelectionContext.notice("No more tracks to play...");
current_track = umax;
return umax;
}
default:
{
fmt::throw_exception("step_track: Unknown repeat mode %d", static_cast<u32>(repeat_mode));
fmt::throw_exception("Unknown repeat mode %d", static_cast<u32>(repeat_mode));
}
}
@@ -361,7 +329,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("step_track: Shuffling playlist...");
cellMusicSelectionContext.notice("Shuffling playlist...");
auto engine = std::default_random_engine{};
std::shuffle(std::begin(playlist), std::end(playlist), engine);
}

View File

@@ -2,6 +2,7 @@
#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,5 +1,6 @@
#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

@@ -3,6 +3,7 @@
#include "Emu/Io/pad_types.h"
#include <array>
#include "util/types.hpp"
enum CellPadError : u32
{
@@ -41,13 +42,13 @@ enum
struct pad_data_internal
{
u16 vendor_id = 0;
u16 product_id = 0;
u32 port_status = 0;
u32 device_capability = 0;
u32 device_type = 0;
u32 pclass_type = 0;
u32 pclass_profile = 0;
u16 vendor_id;
u16 product_id;
u32 port_status;
u32 device_capability;
u32 device_type;
u32 pclass_type;
u32 pclass_profile;
ENABLE_BITWISE_SERIALIZATION;
};

View File

@@ -1,5 +1,6 @@
#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,6 +2,7 @@
#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,6 +19,11 @@ 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 <>
@@ -144,7 +149,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)
@@ -157,7 +162,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)
@@ -170,17 +175,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("pngDecError: %s", error_message);
cellPngDec.error("%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("pngDecWarning: %s", error_message);
cellPngDec.warning("%s", error_message);
}
// Get the chunk information of the PNG file. IDAT is marked as existing, only after decoding or reading the header.
@@ -332,7 +337,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)
@@ -903,103 +908,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(handle=*0x%x, stream=*0x%x, unknownChunk=*0x%x, unknownChunkNumber=*0x%x)", handle, stream, unknownChunk, unknownChunkNumber);
cellPngDec.todo("cellPngDecGetUnknownChunks()");
return CELL_OK;
}
error_code cellPngDecGetpCAL(PHandle handle, PStream stream, vm::ptr<CellPngPCAL> pcal)
{
cellPngDec.todo("cellPngDecGetpCAL(handle=*0x%x, stream=*0x%x, pcal=*0x%x)", handle, stream, pcal);
cellPngDec.todo("cellPngDecGetpCAL()");
return CELL_OK;
}
error_code cellPngDecGetcHRM(PHandle handle, PStream stream, vm::ptr<CellPngCHRM> chrm)
{
cellPngDec.todo("cellPngDecGetcHRM(handle=*0x%x, stream=*0x%x, chrm=*0x%x)", handle, stream, chrm);
cellPngDec.todo("cellPngDecGetcHRM()");
return CELL_OK;
}
error_code cellPngDecGetsCAL(PHandle handle, PStream stream, vm::ptr<CellPngSCAL> scal)
{
cellPngDec.todo("cellPngDecGetsCAL(handle=*0x%x, stream=*0x%x, scal=*0x%x)", handle, stream, scal);
cellPngDec.todo("cellPngDecGetsCAL()");
return CELL_OK;
}
error_code cellPngDecGetpHYs(PHandle handle, PStream stream, vm::ptr<CellPngPHYS> phys)
{
cellPngDec.todo("cellPngDecGetpHYs(handle=*0x%x, stream=*0x%x, phys=*0x%x)", handle, stream, phys);
cellPngDec.todo("cellPngDecGetpHYs()");
return CELL_OK;
}
error_code cellPngDecGetoFFs(PHandle handle, PStream stream, vm::ptr<CellPngOFFS> offs)
{
cellPngDec.todo("cellPngDecGetoFFs(handle=*0x%x, stream=*0x%x, offs=*0x%x)", handle, stream, offs);
cellPngDec.todo("cellPngDecGetoFFs()");
return CELL_OK;
}
error_code cellPngDecGetsPLT(PHandle handle, PStream stream, vm::ptr<CellPngSPLT> splt)
{
cellPngDec.todo("cellPngDecGetsPLT(handle=*0x%x, stream=*0x%x, splt=*0x%x)", handle, stream, splt);
cellPngDec.todo("cellPngDecGetsPLT()");
return CELL_OK;
}
error_code cellPngDecGetbKGD(PHandle handle, PStream stream, vm::ptr<CellPngBKGD> bkgd)
{
cellPngDec.todo("cellPngDecGetbKGD(handle=*0x%x, stream=*0x%x, bkgd=*0x%x)", handle, stream, bkgd);
cellPngDec.todo("cellPngDecGetbKGD()");
return CELL_OK;
}
error_code cellPngDecGettIME(PHandle handle, PStream stream, vm::ptr<CellPngTIME> time)
{
cellPngDec.todo("cellPngDecGettIME(handle=*0x%x, stream=*0x%x, time=*0x%x)", handle, stream, time);
cellPngDec.todo("cellPngDecGettIME()");
return CELL_OK;
}
error_code cellPngDecGethIST(PHandle handle, PStream stream, vm::ptr<CellPngHIST> hist)
{
cellPngDec.todo("cellPngDecGethIST(handle=*0x%x, stream=*0x%x, hist=*0x%x)", handle, stream, hist);
cellPngDec.todo("cellPngDecGethIST()");
return CELL_OK;
}
error_code cellPngDecGettRNS(PHandle handle, PStream stream, vm::ptr<CellPngTRNS> trns)
{
cellPngDec.todo("cellPngDecGettRNS(handle=*0x%x, stream=*0x%x, trns=*0x%x)", handle, stream, trns);
cellPngDec.todo("cellPngDecGettRNS()");
return CELL_OK;
}
error_code cellPngDecGetsBIT(PHandle handle, PStream stream, vm::ptr<CellPngSBIT> sbit)
{
cellPngDec.todo("cellPngDecGetsBIT(handle=*0x%x, stream=*0x%x, sbit=*0x%x)", handle, stream, sbit);
cellPngDec.todo("cellPngDecGetsBIT()");
return CELL_OK;
}
error_code cellPngDecGetiCCP(PHandle handle, PStream stream, vm::ptr<CellPngICCP> iccp)
{
cellPngDec.todo("cellPngDecGetiCCP(handle=*0x%x, stream=*0x%x, iccp=*0x%x)", handle, stream, iccp);
cellPngDec.todo("cellPngDecGetiCCP()");
return CELL_OK;
}
error_code cellPngDecGetsRGB(PHandle handle, PStream stream, vm::ptr<CellPngSRGB> srgb)
{
cellPngDec.todo("cellPngDecGetsRGB(handle=*0x%x, stream=*0x%x, srgb=*0x%x)", handle, stream, srgb);
cellPngDec.todo("cellPngDecGetsRGB()");
return CELL_OK;
}
error_code cellPngDecGetgAMA(PHandle handle, PStream stream, vm::ptr<CellPngGAMA> gama)
{
cellPngDec.todo("cellPngDecGetgAMA(handle=*0x%x, stream=*0x%x, gama=*0x%x)", handle, stream, gama);
cellPngDec.todo("cellPngDecGetgAMA()");
return CELL_OK;
}
error_code cellPngDecGetPLTE(PHandle handle, PStream stream, vm::ptr<CellPngPLTE> plte)
{
cellPngDec.todo("cellPngDecGetPLTE(handle=*0x%x, stream=*0x%x, plte=*0x%x)", handle, stream, plte);
cellPngDec.todo("cellPngDecGetPLTE()");
return CELL_OK;
}
error_code cellPngDecGetTextChunk(PHandle handle, PStream stream, vm::ptr<u32> textInfoNum, vm::pptr<CellPngTextInfo> textInfo)
{
cellPngDec.todo("cellPngDecGetTextChunk(handle=*0x%x, stream=*0x%x, textInfoNum=*0x%x, textInfo=*0x%x)", handle, stream, textInfoNum, textInfo);
cellPngDec.todo("cellPngDecGetTextChunk()");
return CELL_OK;
}

View File

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

View File

@@ -828,8 +828,13 @@ void rec_info::stop_video_provider(bool flush)
{
cellRec.notice("Stopping video provider.");
// Join thread
video_provider_thread.reset();
if (video_provider_thread)
{
auto& thread = *video_provider_thread;
thread = thread_state::aborting;
thread();
video_provider_thread.reset();
}
// Flush the ringbuffer if necessary.
// This should only happen if the video sink is not the encoder itself.
@@ -889,7 +894,7 @@ void rec_info::stop_video_provider(bool flush)
}
}
bool create_path(std::string& out, std::string dir_name, const std::string& file_name)
bool create_path(std::string& out, std::string dir_name, std::string file_name)
{
out.clear();
@@ -898,7 +903,7 @@ bool create_path(std::string& out, std::string dir_name, const std::string& file
return false;
}
out = std::move(dir_name);
out = 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.trace("cellRtcGetCurrentClock(pClock=*0x%x, iTimeZone=%d)", pClock, iTimeZone);
cellRtc.notice("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.trace("cellRtcGetTime_t(pDateTime=*0x%x, piTime=*0x%x)", pDateTime, piTime);
cellRtc.notice("cellRtcGetTime_t(pDateTime=*0x%x, piTime=*0x%x)", pDateTime, piTime);
const vm::var<sys_page_attr_t> page_attr;

View File

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

View File

@@ -8,7 +8,6 @@
#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"
@@ -20,7 +19,6 @@
#include "Loader/PSF.h"
#include "Utilities/StrUtil.h"
#include "Utilities/date_time.h"
#include "Utilities/sema.h"
#include <mutex>
#include <algorithm>
@@ -244,7 +242,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");
@@ -307,7 +305,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(base_dir, save_entries, focused, SAVEDATA_OP_LIST_DELETE, vm::null, g_fxo->get<savedata_manager>().enable_overlay);
selected = save_dialog->ShowSaveDataList(save_entries, focused, SAVEDATA_OP_LIST_DELETE, vm::null, g_fxo->get<savedata_manager>().enable_overlay);
}
// Reschedule after a blocking dialog returns
@@ -326,7 +324,7 @@ static error_code select_and_delete(ppu_thread& ppu)
focused = save_entries.empty() ? -1 : selected;
// Get information from the selected entry
const SaveDataEntry& entry = ::at32(save_entries, selected);
SaveDataEntry entry = save_entries[selected];
const std::string info = entry.title + "\n" + entry.subtitle + "\n" + entry.details;
// Reusable display message string
@@ -700,32 +698,11 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
u32 errDialog, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncFixed funcFixed, PFuncStat funcStat,
PFuncFile funcFile, u32 container, u32 unk_op_flags /*TODO*/, vm::ptr<void> userdata, u32 userId, PFuncDone funcDone)
{
if (setList)
{
if (const auto& [ok, list] = setList.try_read(); ok)
{
cellSaveData.notice("savedata_op(): setList = { .sortType=%d, .sortOrder=%d, .dirNamePrefix='%s' }", list.sortType, list.sortOrder, list.dirNamePrefix);
}
else
{
cellSaveData.error("savedata_op(): Failed to read setList!");
}
}
if (const auto& [ok, list] = setList.try_read(); ok)
cellSaveData.notice("savedata_op(): setList = { .sortType=%d, .sortOrder=%d, .dirNamePrefix='%s' }", list.sortType, list.sortOrder, list.dirNamePrefix);
if (setBuf)
{
if (const auto& [ok, buf] = setBuf.try_read(); ok)
{
cellSaveData.notice("savedata_op(): setBuf = { .dirListMax=%d, .fileListMax=%d, .bufSize=%d }", buf.dirListMax, buf.fileListMax, buf.bufSize);
}
else
{
cellSaveData.error("savedata_op(): Failed to read setBuf!");
}
}
// There is a lot going on in this function, ensure function log and past log commands have completed for ease of debugging
logs::listener::sync_all();
if (const auto& [ok, buf] = setBuf.try_read(); ok)
cellSaveData.notice("savedata_op(): setBuf = { .dirListMax=%d, .fileListMax=%d, .bufSize=%d }", buf.dirListMax, buf.fileListMax, buf.bufSize);
if (const auto ecode = savedata_check_args(operation, version, dirName, errDialog, setList, setBuf, funcList, funcFixed, funcStat,
funcFile, container, unk_op_flags, userdata, userId, funcDone))
@@ -781,7 +758,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)
{
@@ -841,7 +818,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");
@@ -879,34 +856,25 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
const u32 order = setList->sortOrder;
const u32 type = setList->sortType;
std::sort(save_entries.begin(), save_entries.end(), [order, type](const SaveDataEntry& entry1, const SaveDataEntry& entry2) -> bool
std::sort(save_entries.begin(), save_entries.end(), [=](const SaveDataEntry& entry1, const SaveDataEntry& entry2)
{
const bool mtime_lower = entry1.mtime < entry2.mtime;
const bool mtime_equal = entry1.mtime == entry2.mtime;
const bool subtitle_lower = entry1.subtitle < entry2.subtitle;
const bool subtitle_equal = entry1.subtitle == entry2.subtitle;
const bool revert_order = order == CELL_SAVEDATA_SORTORDER_DESCENT;
if (type == CELL_SAVEDATA_SORTTYPE_MODIFIEDTIME)
if (order == CELL_SAVEDATA_SORTORDER_DESCENT && type == CELL_SAVEDATA_SORTTYPE_MODIFIEDTIME)
{
if (mtime_equal)
{
return subtitle_lower != revert_order;
}
return mtime_lower != revert_order;
return entry1.mtime >= entry2.mtime;
}
else if (type == CELL_SAVEDATA_SORTTYPE_SUBTITLE)
if (order == CELL_SAVEDATA_SORTORDER_DESCENT && type == CELL_SAVEDATA_SORTTYPE_SUBTITLE)
{
if (subtitle_equal)
{
return mtime_lower != revert_order;
}
return subtitle_lower != revert_order;
return entry1.subtitle >= entry2.subtitle;
}
if (order == CELL_SAVEDATA_SORTORDER_ASCENT && type == CELL_SAVEDATA_SORTTYPE_MODIFIEDTIME)
{
return entry1.mtime < entry2.mtime;
}
if (order == CELL_SAVEDATA_SORTORDER_ASCENT && type == CELL_SAVEDATA_SORTTYPE_SUBTITLE)
{
return entry1.subtitle < entry2.subtitle;
}
ensure(false);
return true;
});
}
@@ -1213,7 +1181,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(base_dir, save_entries, focused, operation, listSet, g_fxo->get<savedata_manager>().enable_overlay);
selected = save_dialog->ShowSaveDataList(save_entries, focused, operation, listSet, g_fxo->get<savedata_manager>().enable_overlay);
}
else
{
@@ -1244,7 +1212,8 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
else
{
// Get information from the selected entry
message = get_confirmation_message(operation, ::at32(save_entries, selected));
SaveDataEntry entry = save_entries[selected];
message = get_confirmation_message(operation, entry);
}
// Yield before a blocking dialog is being spawned
@@ -1374,14 +1343,14 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
else
{
// Get information from the selected entry
message = get_confirmation_message(operation, ::at32(save_entries, selected));
SaveDataEntry entry = save_entries[selected];
message = get_confirmation_message(operation, entry);
}
// 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);
@@ -2530,7 +2499,12 @@ 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);
}
error_code cellSaveDataListImport(ppu_thread& /*ppu*/, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
// 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)
{
cellSaveData.todo("cellSaveDataListImport(setList=*0x%x, maxSizeKB=%d, funcDone=*0x%x, container=0x%x, userdata=*0x%x)", setList, maxSizeKB, funcDone, container, userdata);
@@ -2545,7 +2519,7 @@ error_code cellSaveDataListImport(ppu_thread& /*ppu*/, PSetList setList, u32 max
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);
@@ -2560,7 +2534,7 @@ error_code cellSaveDataListExport(ppu_thread& /*ppu*/, PSetList setList, u32 max
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);
@@ -2575,7 +2549,7 @@ error_code cellSaveDataFixedImport(ppu_thread& /*ppu*/, vm::cptr<char> dirName,
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);
@@ -2606,7 +2580,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);
@@ -2621,7 +2595,7 @@ error_code cellSaveDataUserListImport(ppu_thread& /*ppu*/, u32 userId, PSetList
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);
@@ -2636,7 +2610,7 @@ error_code cellSaveDataUserListExport(ppu_thread& /*ppu*/, u32 userId, PSetList
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);
@@ -2651,7 +2625,7 @@ error_code cellSaveDataUserFixedImport(ppu_thread& /*ppu*/, u32 userId, vm::cptr
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,6 +1,7 @@
#pragma once
#include "util/types.hpp"
#include "util/endian.hpp"
#include "Emu/Memory/vm_ptr.h"
#include <string>
#include <vector>
@@ -361,5 +362,5 @@ class SaveDialogBase
public:
virtual ~SaveDialogBase();
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;
virtual s32 ShowSaveDataList(std::vector<SaveDataEntry>& save_entries, s32 focused, u32 op, vm::ptr<CellSaveDataListSet> listSet, bool enable_overlay) = 0;
};

View File

@@ -160,6 +160,11 @@ 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
//----------------------------------------------------------------------------
@@ -733,7 +738,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
{
@@ -904,7 +909,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}}))
{
@@ -976,7 +981,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;
@@ -1854,7 +1859,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)
{
cellSpurs.todo("cellSpursSetPreemptionVictimHints(spurs=*0x%x, isPreemptible=*0x%x)", spurs, isPreemptible);
UNIMPLEMENTED_FUNC(cellSpurs);
return CELL_OK;
}
@@ -2225,7 +2230,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);
@@ -2272,7 +2277,7 @@ s32 _cellSpursWorkloadAttributeInitialize(ppu_thread& /*ppu*/, vm::ptr<CellSpurs
}
/// 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);
@@ -2766,7 +2771,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);
@@ -2828,7 +2833,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);
@@ -2866,7 +2871,7 @@ s32 cellSpursReadyCountStore(ppu_thread& /*ppu*/, vm::ptr<CellSpurs> spurs, u32
}
/// 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);
@@ -2904,7 +2909,7 @@ s32 cellSpursReadyCountSwap(ppu_thread& /*ppu*/, vm::ptr<CellSpurs> spurs, u32 w
}
/// 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);
@@ -2945,7 +2950,7 @@ s32 cellSpursReadyCountCompareAndSwap(ppu_thread& /*ppu*/, vm::ptr<CellSpurs> sp
}
/// 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);
@@ -3025,7 +3030,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;
@@ -3130,7 +3135,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);
@@ -3828,19 +3833,19 @@ s32 _cellSpursLFQueueInitialize(vm::ptr<void> pTasksetOrSpurs, vm::ptr<CellSpurs
s32 _cellSpursLFQueuePushBody()
{
cellSpurs.todo("_cellSpursLFQueuePushBody()");
UNIMPLEMENTED_FUNC(cellSpurs);
return CELL_OK;
}
s32 cellSpursLFQueueAttachLv2EventQueue(vm::ptr<CellSyncLFQueue> queue)
{
cellSpurs.todo("cellSpursLFQueueAttachLv2EventQueue(queue=*0x%x)", queue);
UNIMPLEMENTED_FUNC(cellSpurs);
return CELL_OK;
}
s32 cellSpursLFQueueDetachLv2EventQueue(vm::ptr<CellSyncLFQueue> queue)
{
cellSpurs.todo("cellSpursLFQueueDetachLv2EventQueue(queue=*0x%x)", queue);
UNIMPLEMENTED_FUNC(cellSpurs);
return CELL_OK;
}
@@ -4566,7 +4571,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);
@@ -4648,9 +4653,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;
@@ -4681,9 +4686,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,6 +1,9 @@
#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,6 +15,7 @@ LOG_CHANNEL(cellSpurs);
// Temporarily
#ifndef _MSC_VER
#pragma GCC diagnostic ignored "-Wunused-function"
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
//----------------------------------------------------------------------------
@@ -88,7 +89,7 @@ void spursJobchainPopUrgentCommand(spu_thread& spu);
//----------------------------------------------------------------------------
// Output trace information
void cellSpursModulePutTrace(CellSpursTracePacket* /*packet*/, u32 /*dmaTagId*/)
void cellSpursModulePutTrace(CellSpursTracePacket* packet, u32 dmaTagId)
{
// TODO: Implement this
}
@@ -870,7 +871,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);
@@ -1165,7 +1166,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)
{
@@ -2055,7 +2056,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,6 +580,8 @@ 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)
@@ -587,11 +589,7 @@ error_code cellSysutilCheckCallback(ppu_thread& ppu)
continue;
}
// 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++;
read = true;
if (s32 res = func.func(ppu))
{
@@ -605,6 +603,11 @@ error_code cellSysutilCheckCallback(ppu_thread& ppu)
}
}
if (read)
{
cbm.read_counter++;
}
return CELL_OK;
}

View File

@@ -1220,7 +1220,7 @@ error_code cellVdecGetPictureExt(ppu_thread& ppu, u32 handle, vm::cptr<CellVdecP
if (arg4 || format->unk0 || format->unk1)
{
cellVdec.todo("cellVdecGetPictureExt: Unknown arguments (arg4=*0x%x, unk0=0x%x, unk1=0x%x)", arg4, format->unk0, format->unk1);
fmt::throw_exception("cellVdecGetPictureExt: Unknown arguments (arg4=*0x%x, unk0=0x%x, unk1=0x%x)", arg4, format->unk0, format->unk1);
}
vdec_frame frame;
@@ -1619,25 +1619,10 @@ error_code cellVdecSetFrameRate(u32 handle, CellVdecFrameRate frameRateCode)
return CELL_OK;
}
error_code cellVdecOpenExt(ppu_thread& ppu, vm::cptr<CellVdecType> type, vm::cptr<CellVdecResourceExt> res, vm::cptr<CellVdecCb> cb, vm::ptr<u32> handle)
error_code cellVdecOpenExt()
{
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);
UNIMPLEMENTED_FUNC(cellVdec);
return CELL_OK;
}
error_code cellVdecStartSeqExt()

View File

@@ -133,16 +133,6 @@ 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,6 +2,7 @@
#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.trace("cellVideoOutGetNumberOfDevice(videoOut=%d)", videoOut);
cellSysutil.warning("cellVideoOutGetNumberOfDevice(videoOut=%d)", videoOut);
switch (videoOut)
{
@@ -478,6 +478,11 @@ 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,5 +1,8 @@
#pragma once
#include <unordered_map>
#include <deque>
// libvoice = 0x80310801 - 0x803108ff
// libvoice version 100

View File

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

View File

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

View File

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

View File

@@ -1,9 +1,11 @@
#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"
@@ -14,7 +16,6 @@
#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"
@@ -22,7 +23,6 @@
#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"
@@ -4265,7 +4265,7 @@ error_code sceNpManagerGetEntitlementById(vm::cptr<char> entId, vm::ptr<SceNpEnt
return SCE_NP_ERROR_INVALID_ARGUMENT;
}
return SCE_NP_ERROR_ID_NOT_FOUND;
return CELL_OK;
}
error_code sceNpManagerGetSigninId(vm::ptr<void> signInId)

View File

@@ -592,6 +592,7 @@ 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);
@@ -720,9 +721,9 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle,
lock2.unlock();
lv2_obj::sleep(ppu);
struct register_context_thread : register_context_thread_name
{
const s32 progress_cb_count = ::narrow<s32>(tropusr->GetTrophiesCount()) - 1;
void operator()(s32 progress_cb_count, u32 context, vm::ptr<SceNpTrophyStatusCallback> statusCb, vm::ptr<void> arg) const
{
// This emulates vsh sending the events and ensures that not 2 events are processed at once
const std::pair<SceNpTrophyStatus, s32> statuses[] =
@@ -736,13 +737,6 @@ 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++)
@@ -765,9 +759,8 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle,
u64 current = get_system_time();
// 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;
const u64 until_max = current + 300'000;
const u64 until_min = current + 100'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);
@@ -784,13 +777,19 @@ 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

@@ -59,7 +59,13 @@ struct sce_np_util_manager
void join_thread()
{
bandwidth_test_thread.reset();
if (bandwidth_test_thread)
{
auto& thread = *bandwidth_test_thread;
thread = thread_state::aborting;
thread();
bandwidth_test_thread.reset();
}
}
};

View File

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

View File

@@ -65,33 +65,38 @@ 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(id=0x%x, ppu_context=*0x%x)", id, ppu_context);
sys_lv2dbg.todo("sys_dbg_read_ppu_thread_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(id=0x%x, spu_context=*0x%x)", id, spu_context);
sys_lv2dbg.todo("sys_dbg_read_spu_thread_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(id=0x%x, spu_context=*0x%x)", id, spu_context);
sys_lv2dbg.todo("sys_dbg_read_spu_thread_context2()");
return CELL_OK;
}
error_code sys_dbg_set_stacksize_ppu_exception_handler(u32 stacksize)
{
sys_lv2dbg.todo("sys_dbg_set_stacksize_ppu_exception_handler(stacksize=0x%x)", stacksize);
sys_lv2dbg.todo("sys_dbg_set_stacksize_ppu_exception_handler()");
return CELL_OK;
}
error_code sys_dbg_initialize_ppu_exception_handler(s32 prio)
{
sys_lv2dbg.todo("sys_dbg_initialize_ppu_exception_handler(prio=0x%x)", prio);
sys_lv2dbg.todo("sys_dbg_initialize_ppu_exception_handler()");
return CELL_OK;
}
@@ -103,7 +108,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(callback=*0x%x, ctrl_flags=0x%x)", callback, ctrl_flags);
sys_lv2dbg.todo("sys_dbg_register_ppu_exception_handler()");
return CELL_OK;
}
@@ -115,163 +120,170 @@ 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(flags=0x%x)", flags);
sys_lv2dbg.todo("sys_dbg_signal_to_ppu_exception_handler()");
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(id=0x%x, info=*0x%x)", id, info);
sys_lv2dbg.todo("sys_dbg_get_mutex_information()");
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(id=0x%x, info=*0x%x)", id, info);
sys_lv2dbg.todo("sys_dbg_get_cond_information()");
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(id=0x%x, info=*0x%x)", id, info);
sys_lv2dbg.todo("sys_dbg_get_rwlock_information()");
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(id=0x%x, info=*0x%x)", id, info);
sys_lv2dbg.todo("sys_dbg_get_event_queue_information()");
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(id=0x%x, info=*0x%x)", id, info);
sys_lv2dbg.todo("sys_dbg_get_semaphore_information()");
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(id=0x%x, info=*0x%x)", id, info);
sys_lv2dbg.todo("sys_dbg_get_lwmutex_information()");
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(id=0x%x, info=*0x%x)", id, info);
sys_lv2dbg.todo("sys_dbg_get_lwcond_information()");
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(id=0x%x, info=*0x%x)", id, info);
sys_lv2dbg.todo("sys_dbg_get_event_flag_information()");
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(ids=*0x%x, ids_num=*0x%x, all_ids_num=*0x%x)", ids, ids_num, all_ids_num);
sys_lv2dbg.todo("sys_dbg_get_ppu_thread_ids()");
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(ids=*0x%x, ids_num=*0x%x, all_ids_num=*0x%x)", ids, ids_num, all_ids_num);
sys_lv2dbg.todo("sys_dbg_get_spu_thread_group_ids()");
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(group_id=0x%x, ids=*0x%x, ids_num=*0x%x, all_ids_num=*0x%x)", group_id, ids, ids_num, all_ids_num);
sys_lv2dbg.todo("sys_dbg_get_spu_thread_ids()");
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(id=0x%x, name=*0x%x)", id, name);
sys_lv2dbg.todo("sys_dbg_get_ppu_thread_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(id=0x%x, name=*0x%x)", id, name);
sys_lv2dbg.todo("sys_dbg_get_spu_thread_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(id=0x%x, name=*0x%x)", id, name);
sys_lv2dbg.todo("sys_dbg_get_spu_thread_group_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(id=0x%x, status=*0x%x)", id, status);
sys_lv2dbg.todo("sys_dbg_get_ppu_thread_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(id=0x%x, status=*0x%x)", id, status);
sys_lv2dbg.todo("sys_dbg_get_spu_thread_group_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(id=0x%x, flags=0x%x, opt1=0x%x, opt2=0x%x)", id, flags, opt1, opt2);
sys_lv2dbg.todo("sys_dbg_enable_floating_point_enabled_exception()");
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(id=0x%x, flags=0x%x, opt1=0x%x, opt2=0x%x)", id, flags, opt1, opt2);
sys_lv2dbg.todo("sys_dbg_disable_floating_point_enabled_exception()");
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(addr=0x%x, num=0x%x, pageinfo=*0x%x)", addr, num, pageinfo);
sys_lv2dbg.todo("sys_dbg_vm_get_page_information()");
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(addr=0x%x, spu_context=0x%x)", addr, ctrl_flag);
sys_lv2dbg.todo("sys_dbg_set_address_to_dabr()");
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(addr=*0x%x, spu_context=*0x%x)", addr, ctrl_flag);
sys_lv2dbg.todo("sys_dbg_get_address_from_dabr()");
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(data1=0x%x, data2=0x%x, data3=0x%x)", data1, data2, data3);
sys_lv2dbg.todo("sys_dbg_signal_to_coredump_handler()");
return CELL_OK;
}
error_code sys_dbg_mat_set_condition(u32 addr, u64 cond)
{
sys_lv2dbg.todo("sys_dbg_mat_set_condition(addr=0x%x, cond=0x%x)", addr, cond);
sys_lv2dbg.todo("sys_dbg_mat_set_condition()");
return CELL_OK;
}
error_code sys_dbg_mat_get_condition(u32 addr, vm::ptr<u64> condp)
{
sys_lv2dbg.todo("sys_dbg_mat_get_condition(addr=0x%x, condp=*0x%x)", addr, condp);
sys_lv2dbg.todo("sys_dbg_mat_get_condition()");
return CELL_OK;
}
error_code sys_dbg_get_coredump_params(vm::ptr<s32> param)
{
sys_lv2dbg.todo("sys_dbg_get_coredump_params(param=*0x%x)", param);
sys_lv2dbg.todo("sys_dbg_get_coredump_params()");
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(mask=0x%x, flags=0x%x)", mask, flags);
sys_lv2dbg.todo("sys_dbg_set_mask_to_ppu_exception_handler()");
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,6 +7,8 @@
#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,9 +1,16 @@
#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);
@@ -39,22 +46,19 @@ s32 sys_net_gethostbyname()
s32 sys_net_getpeername(s32 s, vm::ptr<sys_net_sockaddr> addr, vm::ptr<u32> paddrlen)
{
libnet.todo("getpeername(s=%d, addr=*0x%x, paddrlen=*0x%x)", s, addr, paddrlen);
UNIMPLEMENTED_FUNC(libnet);
return CELL_OK;
}
s32 sys_net_getsockname(s32 s, vm::ptr<sys_net_sockaddr> addr, vm::ptr<u32> paddrlen)
{
libnet.todo("getsockname(s=%d, addr=*0x%x, paddrlen=*0x%x)", s, addr, paddrlen);
UNIMPLEMENTED_FUNC(libnet);
return CELL_OK;
}
s32 sys_net_getsockopt(s32 s, s32 level, s32 optname, vm::ptr<void> optval, vm::ptr<u32> optlen)
{
libnet.todo("getsockopt(s=%d, level=%d, optname=%d, optval=*0x%x, optlen=*0x%x)", s, level, optname, optval, optlen);
UNIMPLEMENTED_FUNC(libnet);
return CELL_OK;
}
@@ -139,8 +143,7 @@ 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)
{
libnet.todo("recvmsg(s=%d, msg=*0x%x, flags=0x%x)", s, msg, flags);
UNIMPLEMENTED_FUNC(libnet);
return CELL_OK;
}
@@ -153,8 +156,7 @@ 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)
{
libnet.todo("sendmsg(s=%d, msg=*0x%x, flags=0x%x)", s, msg, flags);
UNIMPLEMENTED_FUNC(libnet);
return CELL_OK;
}
@@ -195,8 +197,7 @@ s32 sys_net_socketclose(s32 s)
s32 sys_net_socketpoll(vm::ptr<sys_net_pollfd> fds, s32 nfds, s32 ms)
{
libnet.todo("socketpoll(fds=*0x%x, nfds=%d, ms=%d)", fds, nfds, ms);
UNIMPLEMENTED_FUNC(libnet);
return CELL_OK;
}
@@ -271,8 +272,7 @@ 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)
{
libnet.todo("sys_net_close_dump(id=%d, pflags=*0x%x)", id, pflags);
UNIMPLEMENTED_FUNC(libnet);
return CELL_OK;
}
@@ -310,8 +310,7 @@ s32 sys_net_show_route()
s32 sys_net_read_dump(s32 id, vm::ptr<void> buf, s32 len, vm::ptr<s32> pflags)
{
libnet.todo("sys_net_read_dump(id=%d, buf=*0x%x, len=%d, pflags=*0x%x)", id, buf, len, pflags);
UNIMPLEMENTED_FUNC(libnet);
return CELL_OK;
}
@@ -347,8 +346,7 @@ s32 sys_net_get_sockinfo_ex()
s32 sys_net_open_dump(s32 len, s32 flags)
{
libnet.todo("sys_net_open_dump(len=%d, flags=0x%x)", len, flags);
UNIMPLEMENTED_FUNC(libnet);
return CELL_OK;
}

View File

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

View File

@@ -1,5 +1,7 @@
#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,6 +1,8 @@
#include "stdafx.h"
#include "Emu/Cell/PPUModule.h"
#include "sysPrxForUser.h"
LOG_CHANNEL(sysPrxForUser);
error_code sys_rsxaudio_close_connection()

View File

@@ -1,6 +1,8 @@
#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,6 +3,7 @@
#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,9 +2361,7 @@ bool ppu_module<lv2_obj>::analyse(u32 lib_toc, u32 entry, const u32 sec_end, con
}
case ppu_itype::MTSPR:
{
const u32 spr_idx = (op.spr >> 5) | ((op.spr & 0x1f) << 5);
switch (spr_idx)
switch (const u32 n = (op.spr >> 5) | ((op.spr & 0x1f) << 5))
{
case 0x001: // MTXER
{
@@ -2461,6 +2459,7 @@ 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,9 +1902,8 @@ 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.movabs(args[1], reinterpret_cast<u64>(&vm::g_base_addr));
c.add(args[2], x86::qword_ptr(args[1]));
c.jmp(Imm(fn_target));
c.add(args[2], x86::qword_ptr(reinterpret_cast<u64>(&vm::g_base_addr)));
c.jmp(fn_target);
};
}

View File

@@ -192,13 +192,13 @@ namespace ppu_func_detail
const u32 v_count = (info.last_value >> 24);
// TODO: check calculations
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 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 arg_class t =
const 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;
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;
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;
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 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);
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);
};
template<typename RT, typename... T> struct func_binder;

View File

@@ -139,7 +139,7 @@ struct ppu_exec_select
#define RETURN_(...) \
if constexpr (Build == 0) { \
static_cast<void>(exec); \
if (is_debugger_present() || g_cfg.core.ppu_debug) return +[](ppu_thread& ppu, ppu_opcode_t op, be_t<u32>* this_op, ppu_intrp_func* next_fn) { \
if (is_debugger_present()) return +[](ppu_thread& ppu, ppu_opcode_t op, be_t<u32>* this_op, ppu_intrp_func* next_fn) { \
exec(__VA_ARGS__); \
const auto next_op = this_op + 1; \
const auto fn = atomic_storage<ppu_intrp_func_t>::load(next_fn->fn); \

View File

@@ -1171,9 +1171,7 @@ 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 = umax;
ensure(data.size() <= pos && index <= data.size());
u32 pos = static_cast<u32>(data.size());
for (std::string_view value : values)
{
@@ -1193,74 +1191,65 @@ static void ppu_check_patch_spu_images(const ppu_module<lv2_obj>& mod, const ppu
u32 prev_bound = 0;
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))
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)))
{
const auto elf_header = ensure(mod.get_ptr<u8>(seg.addr + prefix_addr));
const auto elf_header = ensure(mod.get_ptr<u8>(seg.addr + i));
if (std::memcmp(elf_header, "\x24\0\x40\x80", 4) == 0)
if (i % 4 == 0 && std::memcmp(elf_header, "\x24\0\x40\x80", 4) == 0)
{
const u32 old_prefix_addr = prefix_addr;
bool next = true;
const u32 old_i = i;
u32 guid_start = umax, guid_end = umax;
auto search_guid_pattern = [&](u32 index, std::string_view data_span, s32 advance_index, u32 lower_bound, u32 uppper_bound) -> u32
for (u32 search = i & -128, tries = 10; tries && search >= prev_bound; tries--, search = utils::sub_saturate<u32>(search, 128))
{
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)
if (seg_view[search] != 0x42 && seg_view[search] != 0x43)
{
if (seg_view[search] != 0x42 && seg_view[search] != 0x43)
{
continue;
}
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;
continue;
}
return umax;
};
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);
prefix_addr = search_guid_pattern(prefix_addr, seg_view, -16, prev_bound, seg.size);
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 (prefix_addr == umax)
guid_start = search + seg.addr;
i = search;
next = false;
break;
}
if (next)
{
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);
std::string_view ls_segment = seg_view.substr(i);
// Bound to a bit less than LS size
ls_segment = ls_segment.substr(0, SPU_LS_SIZE - 0x8000);
ls_segment = ls_segment.substr(0, 0x38000);
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));
const u32 instruction = static_cast<u32>(ls_segment.find("\x24\0\x40\x80"sv, addr_last));
if (instruction != umax && std::memcmp(ls_segment.data() + instruction, "\x24\0\x40\x80", 4) == 0)
if (instruction != umax)
{
if (instruction % 4 != prefix_addr % 4)
if (instruction % 4 != i % 4)
{
// Unaligned, continue
addr_last = instruction + (prefix_addr % 4 - instruction % 4) % 4;
addr_last = instruction + (i % 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))
// 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))
{
addr_last = instruction + 4;
valid_count++;
@@ -1281,7 +1270,8 @@ static void ppu_check_patch_spu_images(const ppu_module<lv2_obj>& mod, const ppu
if (addr_last >= 0x80 && valid_count >= 2)
{
u32 end = std::min<u32>({instruction, seg.size - prefix_addr, utils::align<u32>(addr_last + 256, 128)});
const u32 begin = i & -128;
u32 end = std::min<u32>(seg.size, utils::align<u32>(i + addr_last + 256, 128));
u32 guessed_ls_addr = 0;
@@ -1289,12 +1279,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 = 16; it < end - 16; it += 4)
for (u32 found = 0, last_vaddr = 0, it = begin + 16; it < end - 16; it += 4)
{
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);
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);
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)
{
@@ -1308,7 +1298,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, addr_inst))
if (u32 addr_seg = addr_inst - std::min<u32>(it + 8 - begin, addr_inst))
{
if (last_vaddr != addr_seg)
{
@@ -1331,27 +1321,23 @@ static void ppu_check_patch_spu_images(const ppu_module<lv2_obj>& mod, const ppu
if (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);
end = begin + std::min<u32>(end - begin, SPU_LS_SIZE - guessed_ls_addr);
}
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);
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);
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() + prefix_addr, end - prefix_addr);
utilize_spu_data_segment(guessed_ls_addr ? guessed_ls_addr : 0x4000, seg_view.data() + begin, end - begin);
}
prefix_addr = std::max<u32>(end, prefix_addr + 4) - 4;
prev_bound = prefix_addr + 4;
i = std::max<u32>(end, i + 4) - 4;
prev_bound = i + 4;
}
else
{
prefix_addr = old_prefix_addr;
i = old_i;
}
break;
@@ -1361,7 +1347,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 - prefix_addr));
const spu_exec_object obj(fs::file(elf_header, seg.size - i));
if (obj != elf_error::ok)
{
@@ -1406,7 +1392,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 + prefix_addr + prog.p_offset + 0x14));
name = ensure(mod.get_ptr<const char>(seg.addr + i + prog.p_offset + 0x14));
if (!name.empty())
{
@@ -1415,7 +1401,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 + prefix_addr, obj.highest_offset);
fmt::append(dump, " (image addr: 0x%x, size: 0x%x)", seg.addr + i, obj.highest_offset);
sha1_finish(&sha2, sha1_hash);
@@ -1465,8 +1451,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);
}
prefix_addr += ::narrow<u32>(obj.highest_offset - 4);
prev_bound = prefix_addr + 4;
i += ::narrow<u32>(obj.highest_offset) - 4;
prev_bound = i + 4;
}
}
@@ -2155,8 +2141,6 @@ 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)
{
@@ -2251,8 +2235,6 @@ 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);
}
}
@@ -2777,7 +2759,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 + segs_size));
ensure(g_fxo->get<lv2_memory_container>().take(primary_stacksize));
ppu->cmd_push({ppu_cmd::initialize, 0});

View File

@@ -220,21 +220,19 @@ 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.movabs(x86::r13, reinterpret_cast<u64>(&vm::g_exec_addr));
c.mov(x86::r13, x86::qword_ptr(x86::r13));
c.mov(x86::r13, x86::qword_ptr(reinterpret_cast<u64>(&vm::g_exec_addr)));
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::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.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.shl(x86::edx, 13);
c.mov(x86::r12d, x86::edx); // Set relocation base
c.mov(x86::r12d, x86::edx); // Load relocation base
c.movabs(x86::rbx, reinterpret_cast<u64>(&vm::g_base_addr));
c.mov(x86::rbx, x86::qword_ptr(x86::rbx));
c.mov(x86::rbx, x86::qword_ptr(reinterpret_cast<u64>(&vm::g_base_addr)));
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)));
@@ -348,11 +346,14 @@ 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, 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.mov(reg_hp, call_target);
c.lsr(reg_hp, reg_hp, 48);
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));
@@ -472,11 +473,6 @@ 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));
@@ -522,7 +518,7 @@ void ppu_recompiler_fallback(ppu_thread& ppu)
while (true)
{
if (uptr func = uptr(ppu_read(ppu.cia)); func != reinterpret_cast<uptr>(ppu_recompiler_fallback_ghc))
if (uptr func = uptr(ppu_read(ppu.cia)); (func << 16 >> 16) != reinterpret_cast<uptr>(ppu_recompiler_fallback_ghc))
{
// We found a recompiler function at cia, return
break;
@@ -777,9 +773,6 @@ 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);
@@ -792,13 +785,12 @@ 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
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));
const uptr entry_value = reinterpret_cast<uptr>(ppu_recompiler_fallback_ghc) | (seg_base << (32 + 3));
write_to_ptr<uptr>(ppu_ptr(addr), entry_value);
}
else
{
write_to_ptr<ppu_intrp_func_t>(ppu_ptr(addr), ppu_fallback);
write_to_ptr<u16>(ppu_seg_ptr(addr), 0);
}
addr += 4;
@@ -813,7 +805,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), std::bit_cast<uptr>(ptr));
write_to_ptr<uptr>(ppu_ptr(addr), (reinterpret_cast<uptr>(ptr) & 0xffff'ffff'ffffu) | (uptr(ppu_read(addr)) & ~0xffff'ffff'ffffu));
return;
}
@@ -3172,9 +3164,8 @@ 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, 48);
c.sub(x86::rsp, 40);
#ifdef _WIN32
if (!s_tsx_avx)
{
@@ -3185,16 +3176,14 @@ 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.movabs(x86::rbp, reinterpret_cast<u64>(&vm::g_sudo_addr));
c.mov(x86::rbp, x86::qword_ptr(x86::rbp));
c.mov(x86::rbp, x86::qword_ptr(reinterpret_cast<u64>(&vm::g_sudo_addr)));
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.movabs(x86::r11, reinterpret_cast<u64>(+vm::g_reservations));
c.lea(x86::r11, x86::qword_ptr(x86::r11, args[0]));
c.lea(x86::r11, x86::qword_ptr(reinterpret_cast<u64>(+vm::g_reservations), args[0]));
c.and_(x86::r11, -128 / 2);
c.and_(args[0].r32(), 63);
@@ -3228,8 +3217,7 @@ const auto ppu_stcx_accurate_tx = build_function_asm<u64(*)(u32 raddr, u64 rtime
{
build_get_tsc(c);
c.sub(x86::rax, stamp0);
c.movabs(x86::r13, reinterpret_cast<u64>(&g_rtm_tx_limit2));
c.cmp(x86::rax, x86::qword_ptr(x86::r13));
c.cmp(x86::rax, x86::qword_ptr(reinterpret_cast<u64>(&g_rtm_tx_limit2)));
c.jae(fall);
});
@@ -3354,9 +3342,8 @@ const auto ppu_stcx_accurate_tx = build_function_asm<u64(*)(u32 raddr, u64 rtime
c.vzeroupper();
}
c.add(x86::rsp, 48);
c.add(x86::rsp, 40);
c.pop(x86::r14);
c.pop(x86::r13);
c.pop(x86::rbp);
maybe_flush_lbr(c);
@@ -5092,18 +5079,17 @@ 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.movabs(x86::rax, reinterpret_cast<u64>(&vm::g_exec_addr));
c.mov(x86::rax, x86::qword_ptr(x86::rax));
c.mov(x86::rax, x86::qword_ptr(reinterpret_cast<u64>(&vm::g_exec_addr)));
c.mov(x86::dword_ptr(x86::rbp, ::offset32(&ppu_thread::cia)), x86::edx);
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.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.shl(x86::edx, 13);
c.mov(x86::r12d, x86::edx); // Set relocation base
c.jmp(x86::rcx);
c.mov(x86::r12d, x86::edx); // Load relocation base
c.jmp(x86::rax);
#else
// Load REG_Base - use absolute jump target to bypass rel jmp range limits
// X19 contains vm::g_exec_addr
@@ -5139,11 +5125,14 @@ 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, 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.mov(reg_hp, call_target);
c.lsr(reg_hp, reg_hp, 48);
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
@@ -5411,7 +5400,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, "v7-kusa-%s-%s-%s.obj", fmt::base57(output, 16), fmt::base57(settings), jit_compiler::cpu(g_cfg.core.llvm_cpu));
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));
}
if (cpu ? cpu->state.all_of(cpu_flag::exit) : Emu.IsStopped())
@@ -5723,7 +5712,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)) == reinterpret_cast<uptr>(ppu_recompiler_fallback_ghc))
if (*inst_ptr == ppu_instructions::BLR() && (reinterpret_cast<uptr>(ppu_read(addr)) << 16 >> 16) == reinterpret_cast<uptr>(ppu_recompiler_fallback_ghc))
{
write_to_ptr<ppu_intrp_func_t>(ppu_ptr(addr), BLR_func);
}
@@ -5760,7 +5749,7 @@ static void ppu_initialize2(jit_compiler& jit, const ppu_module<lv2_obj>& module
// Define some types
const auto _func = FunctionType::get(translator.get_type<void>(), {
translator.get_type<u8*>(), // Exec base
translator.get_type<u8*>(), // PPU context
translator.GetContextType()->getPointerTo(), // PPU context
translator.get_type<u64>(), // Segment address (for PRX)
translator.get_type<u8*>(), // Memory base
translator.get_type<u64>(), // r0

View File

@@ -340,7 +340,7 @@ Function* PPUTranslator::GetSymbolResolver(const ppu_module<lv2_obj>& info)
const auto ftype = FunctionType::get(get_type<void>(), {
get_type<u8*>(), // Exec base
m_ir->getPtrTy(), // PPU context
GetContextType()->getPointerTo(), // PPU context
get_type<u64>(), // Segment address (for PRX)
get_type<u8*>(), // Memory base
get_type<u64>(), // r0
@@ -380,7 +380,7 @@ Function* PPUTranslator::GetSymbolResolver(const ppu_module<lv2_obj>& info)
const auto addr_array = new GlobalVariable(*m_module, addr_array_type, false, GlobalValue::PrivateLinkage, ConstantDataArray::get(m_context, vec_addrs));
// Create an array of function pointers
const auto func_table_type = ArrayType::get(m_ir->getPtrTy(), functions.size());
const auto func_table_type = ArrayType::get(ftype->getPointerTo(), functions.size());
const auto init_func_table = ConstantArray::get(func_table_type, functions);
const auto func_table = new GlobalVariable(*m_module, func_table_type, false, GlobalVariable::PrivateLinkage, init_func_table);
@@ -407,22 +407,16 @@ Function* PPUTranslator::GetSymbolResolver(const ppu_module<lv2_obj>& info)
const auto func_pc = ZExt(m_ir->CreateLoad(ptr_inst->getResultElementType(), ptr_inst), get_type<u64>());
ptr_inst = dyn_cast<GetElementPtrInst>(m_ir->CreateGEP(func_table->getValueType(), func_table, {m_ir->getInt64(0), index_value}));
assert(ptr_inst->getResultElementType() == m_ir->getPtrTy());
assert(ptr_inst->getResultElementType() == ftype->getPointerTo());
const auto faddr = m_ir->CreateLoad(ptr_inst->getResultElementType(), ptr_inst);
const auto faddr_int = m_ir->CreatePtrToInt(faddr, get_type<uptr>());
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 = m_ir->CreatePtrAdd(m_exec, pos);
const auto seg_base_ptr = m_ir->CreatePtrAdd(m_exec, m_ir->getInt64(vm::g_exec_addr_seg_offset));
const auto seg_pos = m_ir->CreateLShr(pos_32, 1);
const auto seg_ptr = m_ir->CreatePtrAdd(seg_base_ptr, seg_pos);
const auto seg_val = m_ir->CreateTrunc(m_ir->CreateLShr(m_seg0, 13), get_type<u16>());
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 ptr = dyn_cast<GetElementPtrInst>(m_ir->CreateGEP(get_type<u8>(), m_exec, pos));
// Store to jumptable
m_ir->CreateStore(faddr_int, ptr);
m_ir->CreateStore(seg_val, seg_ptr);
m_ir->CreateStore(fval, ptr);
// Increment index and branch back to loop
const auto post_add = m_ir->CreateAdd(index_value, m_ir->getInt64(1));
@@ -609,16 +603,12 @@ void PPUTranslator::CallFunction(u64 target, Value* indirect)
}
const auto pos = m_ir->CreateShl(indirect, 1);
const auto ptr = m_ir->CreatePtrAdd(m_exec, pos);
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(val, m_ir->getPtrTy()));
callee = FunctionCallee(type, m_ir->CreateIntToPtr(m_ir->CreateAnd(val, 0xffff'ffff'ffff), type->getPointerTo()));
// Load new segment address
const auto seg_base_ptr = m_ir->CreatePtrAdd(m_exec, m_ir->getInt64(vm::g_exec_addr_seg_offset));
const auto seg_pos = m_ir->CreateLShr(indirect, 1);
const auto seg_ptr = m_ir->CreatePtrAdd(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);
seg0 = m_ir->CreateShl(m_ir->CreateLShr(val, 48), 13);
}
m_ir->SetInsertPoint(block);
@@ -822,7 +812,7 @@ void PPUTranslator::UseCondition(MDNode* hint, Value* cond)
llvm::Value* PPUTranslator::GetMemory(llvm::Value* addr)
{
return m_ir->CreatePtrAdd(m_base, addr);
return m_ir->CreateGEP(get_type<u8>(), m_base, addr);
}
void PPUTranslator::TestAborted()
@@ -2792,8 +2782,8 @@ void PPUTranslator::MFOCRF(ppu_opcode_t op)
else if (std::none_of(m_cr + 0, m_cr + 32, [](auto* p) { return p; }))
{
// MFCR (optimized)
Value* ln0 = m_ir->CreateStructGEP(m_thread_type, m_thread, 99);
Value* ln1 = m_ir->CreateStructGEP(m_thread_type, m_thread, 115);
Value* ln0 = m_ir->CreateIntToPtr(m_ir->CreatePtrToInt(m_ir->CreateStructGEP(m_thread_type, m_thread, 99), GetType<uptr>()), GetType<u8[16]>()->getPointerTo());
Value* ln1 = m_ir->CreateIntToPtr(m_ir->CreatePtrToInt(m_ir->CreateStructGEP(m_thread_type, m_thread, 115), GetType<uptr>()), GetType<u8[16]>()->getPointerTo());
ln0 = m_ir->CreateLoad(GetType<u8[16]>(), ln0);
ln1 = m_ir->CreateLoad(GetType<u8[16]>(), ln1);
@@ -5382,7 +5372,7 @@ MDNode* PPUTranslator::CheckBranchProbability(u32 bo)
void PPUTranslator::build_interpreter()
{
#define BUILD_VEC_INST(i) { \
m_function = llvm::cast<llvm::Function>(m_module->getOrInsertFunction("op_" #i, get_type<void>(), m_ir->getPtrTy()).getCallee()); \
m_function = llvm::cast<llvm::Function>(m_module->getOrInsertFunction("op_" #i, get_type<void>(), m_thread_type->getPointerTo()).getCallee()); \
std::fill(std::begin(m_globals), std::end(m_globals), nullptr); \
std::fill(std::begin(m_locals), std::end(m_locals), nullptr); \
IRBuilder<> irb(BasicBlock::Create(m_context, "__entry", m_function)); \

View File

@@ -3,7 +3,7 @@
#include "Loader/ELF.h"
#include "util/asm.hpp"
#include "SPUThread.h"
#include "Emu/Cell/RawSPUThread.h"
inline void try_start(spu_thread& spu)
{
@@ -130,18 +130,6 @@ bool spu_thread::read_reg(const u32 addr, u32& value)
return true;
}
case Prxy_QueryMask_offs:
{
value = mfc_prxy_mask;
return true;
}
case Prxy_QueryType_offs:
{
value = 0;
return true;
}
case SPU_Out_MBox_offs:
{
value = ch_out_mbox.pop();
@@ -150,29 +138,7 @@ bool spu_thread::read_reg(const u32 addr, u32& value)
case SPU_MBox_Status_offs:
{
// Load channel counts atomically
auto counts = std::make_tuple(ch_out_mbox.get_count(), ch_in_mbox.get_count(), ch_out_intr_mbox.get_count());
while (true)
{
atomic_fence_acquire();
const auto counts_check = std::make_tuple(ch_out_mbox.get_count(), ch_in_mbox.get_count(), ch_out_intr_mbox.get_count());
if (counts_check == counts)
{
break;
}
// Update and reload
counts = counts_check;
}
const u32 out_mbox = std::get<0>(counts);
const u32 in_mbox = 4 - std::get<1>(counts);
const u32 intr_mbox = std::get<2>(counts);
value = (out_mbox & 0xff) | ((in_mbox << 8) & 0xff00) | ((intr_mbox << 16) & 0xff0000);
value = (ch_out_mbox.get_count() & 0xff) | ((4 - ch_in_mbox.get_count()) << 8 & 0xff00) | (ch_out_intr_mbox.get_count() << 16 & 0xff0000);
return true;
}
@@ -379,8 +345,6 @@ bool spu_thread::test_is_problem_state_register_offset(u32 offset, bool for_read
case MFC_QStatus_offs:
case SPU_Out_MBox_offs:
case SPU_MBox_Status_offs:
case Prxy_QueryType_offs:
case Prxy_QueryMask_offs:
case SPU_Status_offs:
case Prxy_TagStatus_offs:
case SPU_NPC_offs:

View File

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

View File

@@ -5,12 +5,15 @@
#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>
@@ -2770,17 +2773,14 @@ 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(*arg0, *qw0, 2));
c->mov(*qw1, asmjit::x86::dword_ptr(fraction_lut_addr, *qw0, 2));
c->pinsrd(v_fraction, *qw1, index);
c->pextrd(*qw0, v_exponent, index);
c->mov(*qw1, asmjit::x86::dword_ptr(*arg1, *qw0, 2));
c->mov(*qw1, asmjit::x86::dword_ptr(exponent_lut_addr, *qw0, 2));
c->pinsrd(v_exponent, *qw1, index);
}
@@ -2813,17 +2813,14 @@ 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(*arg0, *qw0, 2));
c->mov(*qw1, asmjit::x86::dword_ptr(fraction_lut_addr, *qw0, 2));
c->pinsrd(v_fraction, *qw1, index);
c->pextrd(*qw0, v_exponent, index);
c->mov(*qw1, asmjit::x86::dword_ptr(*arg1, *qw0, 2));
c->mov(*qw1, asmjit::x86::dword_ptr(exponent_lut_addr, *qw0, 2));
c->pinsrd(v_exponent, *qw1, index);
}

View File

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

View File

@@ -842,7 +842,6 @@ 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();
@@ -851,22 +850,6 @@ 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();
@@ -2562,7 +2545,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;
}
@@ -6083,7 +6066,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;
}
}
@@ -6357,7 +6340,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() && [&]()
@@ -7376,7 +7359,7 @@ struct spu_llvm_worker
set_relax_flag = false;
}
thread_ctrl::wait_on(registered.get_wait_atomic(), 0);
thread_ctrl::wait_on(utils::bless<atomic_t<u32>>(&registered)[1], 0);
slice = registered.pop_all();
}())
{
@@ -7491,7 +7474,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(registered.get_wait_atomic(), 0);
thread_ctrl::wait_on(utils::bless<atomic_t<u32>>(&registered)[1], 0);
}
if (thread_ctrl::state() == thread_state::aborting)
@@ -7594,7 +7577,7 @@ struct spu_llvm
// Interrupt profiler thread and put it to sleep
static_cast<void>(prof_mutex.reset());
thread_ctrl::wait_on(registered.get_wait_atomic(), 0);
thread_ctrl::wait_on(utils::bless<atomic_t<u32>>(&registered)[1], 0);
std::fill(notify_compile.begin(), notify_compile.end(), 0); // Reset notification flags
notify_compile_count = 0;
compile_pending = 0;
@@ -8159,7 +8142,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,6 +3,7 @@
#include "Utilities/JIT.h"
#include "SPUThread.h"
#include "Emu/Cell/Common.h"
#include "Emu/Cell/SPUAnalyser.h"
#include "Emu/system_config.h"
@@ -12,6 +13,7 @@
#include "util/sysinfo.hpp"
#include <cmath>
#include <cfenv>
#if !defined(_MSC_VER)
#pragma GCC diagnostic push

File diff suppressed because it is too large Load Diff

View File

@@ -628,8 +628,6 @@ 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)
@@ -650,21 +648,17 @@ 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.movabs(args[1], reinterpret_cast<u64>(&vm::g_sudo_addr));
c.mov(args[1], x86::qword_ptr(args[1]));
c.mov(args[1], x86::qword_ptr(reinterpret_cast<u64>(&vm::g_sudo_addr)));
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.movabs(x86::r11, reinterpret_cast<u64>(+vm::g_reservations));
c.lea(x86::r11, x86::qword_ptr(x86::r11, args[0]));
c.lea(x86::r11, x86::qword_ptr(reinterpret_cast<u64>(+vm::g_reservations), args[0]));
// Prepare data
if (s_tsx_avx)
@@ -709,8 +703,7 @@ 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.movabs(x86::rbx, reinterpret_cast<u64>(&g_rtm_tx_limit2));
c.cmp(x86::rax, x86::qword_ptr(x86::rbx));
c.cmp(x86::rax, x86::qword_ptr(reinterpret_cast<u64>(&g_rtm_tx_limit2)));
c.jae(fall);
});
@@ -860,13 +853,8 @@ 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();
@@ -896,10 +884,8 @@ 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)
c.push(x86::rbp);
c.push(x86::rbx);
c.sub(x86::rsp, 40);
#ifdef _WIN32
c.sub(x86::rsp, 40);
if (!s_tsx_avx)
{
c.movups(x86::oword_ptr(x86::rsp, 0), x86::xmm6);
@@ -908,8 +894,7 @@ 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.movabs(x86::r11, reinterpret_cast<u64>(&vm::g_sudo_addr));
c.mov(x86::r11, x86::qword_ptr(x86::r11));
c.mov(x86::r11, x86::qword_ptr(reinterpret_cast<u64>(&vm::g_sudo_addr)));
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));
@@ -936,8 +921,7 @@ 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.movabs(args[1], reinterpret_cast<u64>(+vm::g_reservations));
c.lea(args[1], x86::qword_ptr(args[1], args[0]));
c.lea(args[1], x86::qword_ptr(reinterpret_cast<u64>(+vm::g_reservations), args[0]));
// Alloc args[0] to stamp0
const auto stamp0 = args[0];
@@ -949,8 +933,7 @@ 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.movabs(x86::rbx, reinterpret_cast<u64>(&g_rtm_tx_limit2));
c.cmp(x86::rax, x86::qword_ptr(x86::rbx));
c.cmp(x86::rax, x86::qword_ptr(reinterpret_cast<u64>(&g_rtm_tx_limit2)));
c.jae(fall);
});
@@ -1003,10 +986,6 @@ 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
@@ -1044,13 +1023,11 @@ 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.movabs(x86::rbp, reinterpret_cast<u64>(&vm::g_sudo_addr));
c.mov(x86::rbp, x86::qword_ptr(x86::rbp));
c.mov(x86::rbp, x86::qword_ptr(reinterpret_cast<u64>(&vm::g_sudo_addr)));
c.lea(x86::rbp, x86::qword_ptr(x86::rbp, args[0]));
c.and_(args[0].r32(), 0xff80);
c.shr(args[0].r32(), 1);
c.movabs(x86::r11, reinterpret_cast<u64>(+vm::g_reservations));
c.lea(x86::r11, x86::qword_ptr(x86::r11, args[0]));
c.lea(x86::r11, x86::qword_ptr(reinterpret_cast<u64>(+vm::g_reservations), args[0]));
// Alloc args[0] to stamp0
const auto stamp0 = args[0];
@@ -1062,8 +1039,7 @@ 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.movabs(x86::rbx, reinterpret_cast<u64>(&g_rtm_tx_limit1));
c.cmp(x86::rax, x86::qword_ptr(x86::rbx));
c.cmp(x86::rax, x86::qword_ptr(reinterpret_cast<u64>(&g_rtm_tx_limit1)));
c.jae(fall);
});
@@ -1233,6 +1209,8 @@ 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
@@ -2129,41 +2107,6 @@ 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)
@@ -2175,7 +2118,20 @@ 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))
{
init_spu_decoder();
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
}
if (g_cfg.core.mfc_debug)
{
@@ -2237,7 +2193,20 @@ spu_thread::spu_thread(utils::serial& ar, lv2_spu_group* group)
, lv2_id(ar)
, spu_tname(make_single<std::string>(ar.operator std::string()))
{
init_spu_decoder();
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
}
if (g_cfg.core.mfc_debug)
{
@@ -4047,22 +4016,6 @@ void do_cell_atomic_128_store(u32 addr, const void* to_write)
auto& sdata = *vm::get_super_ptr<spu_rdata_t>(addr);
auto& res = *utils::bless<atomic_t<u128>>(vm::g_reservations + (addr & 0xff80) / 2);
if (std::memcmp(static_cast<const u8*>(to_write), &sdata, 16) == 0 && std::memcmp(static_cast<const u8*>(to_write) + 64, &sdata[64], 16) == 0)
{
const auto& write_data = *static_cast<const spu_rdata_t*>(to_write);
const u64 at_read_time = vm::reservation_acquire(addr);
if (!(at_read_time & 127))
{
if (cmp_rdata(sdata, write_data) && at_read_time == vm::reservation_acquire(addr) && cmp_rdata(sdata, write_data))
{
// Write of the same data (verified atomically)
vm::try_reservation_update(addr);
return;
}
}
}
for (u64 j = 0;; j++)
{
auto [_oldd, _ok] = res.fetch_op([&](u128& r)
@@ -4376,7 +4329,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 is_range_limited)
bool spu_thread::is_exec_code(u32 addr, std::span<const u8> ls_ptr, u32 base_addr, bool avoid_dead_code)
{
bool had_conditional = false;
@@ -4384,12 +4337,12 @@ bool spu_thread::is_exec_code(u32 addr, std::span<const u8> ls_ptr, u32 base_add
{
if (addr & ~0x3FFFC)
{
return is_range_limited;
return false;
}
if (addr < base_addr || addr >= base_addr + ls_ptr.size())
{
return is_range_limited;
return false;
}
const u32 addr0 = spu_branch_target(addr);
@@ -4492,19 +4445,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 is_range_limited;
return false;
}
}
else if (SPU_LS_SIZE - addr <= rel + 0u)
{
return is_range_limited;
return false;
}
if (type == spu_itype::BRSL)
@@ -4534,7 +4487,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 is_range_limited;
return false;
}
// Test the validity of a single instruction of the optional target
@@ -4565,126 +4518,6 @@ 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 (stats.size() == 16 && 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
@@ -4797,38 +4630,63 @@ bool spu_thread::process_mfc_cmd()
return true;
}
if (last_getllar != pc || last_getllar_lsa != ch_mfc_cmd.lsa)
{
getllar_busy_waiting_switch = umax;
getllar_spin_count = 0;
return true;
}
// Check if LSA points to an OUT buffer on the stack from a caller - unlikely to be a loop
if (last_getllar_lsa >= SPU_LS_SIZE - 0x10000 && last_getllar_lsa > last_getllar_gpr1)
{
auto cs = dump_callstack_list();
if (!cs.empty() && last_getllar_lsa > cs[0].second)
{
getllar_busy_waiting_switch = umax;
getllar_spin_count = 0;
return true;
}
}
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)
{
getllar_evaluate_time = perf0.get();
auto& history = getllar_wait_time[(addr % SPU_LS_SIZE) / 128];
const u32 percent = g_cfg.core.spu_getllar_busy_waiting_percentage;
getllar_busy_waiting_switch =
evaluate_spin_optimization({ history.data(), history.size() }, getllar_evaluate_time, 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();
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] );
}
else
{
@@ -4862,7 +4720,6 @@ bool spu_thread::process_mfc_cmd()
last_getllar = pc;
last_getllar_gpr1 = gpr[1]._u32[3];
last_getllar_lsa = ch_mfc_cmd.lsa;
if (getllar_busy_waiting_switch == 1)
{
@@ -5147,7 +5004,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
@@ -5172,7 +5029,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;
@@ -5193,7 +5050,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)
@@ -5258,7 +5115,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;
@@ -6056,6 +5913,11 @@ s64 spu_thread::get_ch_value(u32 ch)
const usz seed = (utils::get_tsc() >> 8) % 100;
#ifdef __linux__
const bool reservation_busy_waiting = false;
#else
const bool reservation_busy_waiting = (seed + ((raddr == spurs_addr) ? 50u : 0u)) < g_cfg.core.spu_reservation_busy_waiting_percentage;
#endif
usz cache_line_waiter_index = umax;
auto check_cache_line_waiter = [&]()
@@ -6075,52 +5937,7 @@ s64 spu_thread::get_ch_value(u32 ch)
return 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)
for (; !events.count; events = get_events(mask1 & ~SPU_EVENT_LR, true, true))
{
const auto old = +state;
@@ -6135,7 +5952,7 @@ s64 spu_thread::get_ch_value(u32 ch)
}
// Optimized check
if (is_LR_wait)
if (raddr && mask1 & SPU_EVENT_LR)
{
if (cache_line_waiter_index == umax)
{
@@ -6166,59 +5983,6 @@ 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(static_cast<u32>(std::min<u64>(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>(static_cast<u32>(std::min<u64>(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)
@@ -6241,7 +6005,8 @@ s64 spu_thread::get_ch_value(u32 ch)
}
}
if (true)
// Don't busy-wait with TSX - memory is sensitive
if (g_use_rtm || !reservation_busy_waiting)
{
if (u32 work_count = g_spu_work_count)
{
@@ -6368,6 +6133,10 @@ s64 spu_thread::get_ch_value(u32 ch)
}
#endif
}
else
{
busy_wait();
}
continue;
}
@@ -6841,7 +6610,7 @@ bool spu_thread::set_ch_value(u32 ch, u32 value)
fmt::throw_exception("Unknown/illegal channel in WRCH (ch=%d [%s], value=0x%x)", ch, ch < 128 ? spu_ch_name[ch] : "???", value);
}
extern void resume_spu_thread_group_from_waiting(spu_thread& spu, std::array<shared_ptr<named_thread<spu_thread>>, 8>& notify_spus)
extern void resume_spu_thread_group_from_waiting(spu_thread& spu)
{
const auto group = spu.group;
@@ -6855,7 +6624,7 @@ extern void resume_spu_thread_group_from_waiting(spu_thread& spu, std::array<sha
{
group->run_state = SPU_THREAD_GROUP_STATUS_SUSPENDED;
spu.state += cpu_flag::signal;
ensure(spu.state & cpu_flag::suspend);
spu.state.notify_one();
return;
}
@@ -6873,7 +6642,7 @@ extern void resume_spu_thread_group_from_waiting(spu_thread& spu, std::array<sha
thread->state -= cpu_flag::suspend;
}
notify_spus[thread->index] = thread;
thread->state.notify_one();
}
}
}

View File

@@ -638,7 +638,6 @@ 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;
@@ -802,19 +801,10 @@ public:
u32 last_getllar = umax; // LS address of last GETLLAR (if matches current GETLLAR we can let the thread rest)
u32 last_getllar_gpr1 = umax;
u32 last_getllar_addr = umax;
u32 last_getllar_lsa = umax;
u32 getllar_spin_count = 0;
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;
@@ -838,7 +828,6 @@ 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);
@@ -854,7 +843,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, bool is_range_limited = false); // A hint, do not rely on it for true execution compatibility
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 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;
#ifdef __linux__
#if defined(__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)
{
#ifdef __linux__
#if defined(__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,4 +1,5 @@
#include "stdafx.h"
#include "Emu/Memory/vm.h"
#include "Emu/Cell/ErrorCodes.h"

View File

@@ -2,6 +2,7 @@
#include "util/serialization.hpp"
#include "Emu/IdManager.h"
#include "Emu/IPC.h"
#include "Emu/System.h"
#include "Emu/Cell/ErrorCodes.h"
@@ -59,6 +60,7 @@ 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
@@ -70,7 +72,7 @@ CellError lv2_cond::on_id_create()
std::function<void(void*)> lv2_cond::load(utils::serial& ar)
{
return load_func(make_shared<lv2_cond>(stx::exact_t<utils::serial&>(ar)));
return load_func(make_shared<lv2_cond>(ar));
}
void lv2_cond::save(utils::serial& ar)

View File

@@ -1,4 +1,6 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/Memory/vm.h"
#include "Emu/IdManager.h"
#include "Emu/Cell/lv2/sys_event.h"
@@ -120,7 +122,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::destroying_context && !m_destroyed.exchange(true))
if (s == thread_state::finished)
{
if (auto global = g_fxo->try_get<lv2_config>())
{
@@ -131,23 +133,6 @@ 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,8 +1,11 @@
#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"
@@ -158,8 +161,6 @@ public:
return null_ptr;
}
~lv2_config() noexcept;
};
/*
@@ -275,7 +276,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 stx::make_shared_from_this<lv2_config_service>(this); }
shared_ptr<lv2_config_service> get_shared_ptr () const { return idm::get_unlocked<lv2_config_service>(idm_id); }
u32 get_id() const { return idm_id; }
};
@@ -341,7 +342,7 @@ public:
// Utilities
u32 get_id() const { return idm_id; }
shared_ptr<lv2_config_service_listener> get_shared_ptr() const { return stx::make_shared_from_this<lv2_config_service_listener>(this); }
shared_ptr<lv2_config_service_listener> get_shared_ptr() const { return idm::get_unlocked<lv2_config_service_listener>(idm_id); }
};
/*
@@ -359,10 +360,6 @@ 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;
@@ -394,7 +391,8 @@ public:
// Destructor
lv2_config_service_event& operator=(thread_state s) noexcept;
~lv2_config_service_event() noexcept;
~lv2_config_service_event() noexcept = default;
// 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>(stx::exact_t<utils::serial&>(ar));
return [ptr = lv2_obj::load(queue->key, queue)](void* storage) { *static_cast<atomic_ptr<lv2_obj>*>(storage) = ptr; };
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; };
}
void lv2_event_queue::save(utils::serial& ar)
@@ -117,7 +117,7 @@ shared_ptr<lv2_event_queue> lv2_event_queue::find(u64 ipc_key)
return g_fxo->get<ipc_manager<lv2_event_queue, u64>>().get(ipc_key);
}
extern void resume_spu_thread_group_from_waiting(spu_thread& spu, std::array<shared_ptr<named_thread<spu_thread>>, 8>& notify_spus);
extern void resume_spu_thread_group_from_waiting(spu_thread& spu);
CellError lv2_event_queue::send(lv2_event event, bool* notified_thread, lv2_event_port* port)
{
@@ -126,22 +126,6 @@ CellError lv2_event_queue::send(lv2_event event, bool* notified_thread, lv2_even
*notified_thread = false;
}
struct notify_spus_t
{
std::array<shared_ptr<named_thread<spu_thread>>, 8> spus;
~notify_spus_t() noexcept
{
for (auto& spu : spus)
{
if (spu && spu->state & cpu_flag::wait)
{
spu->state.notify_one();
}
}
}
} notify_spus{};
std::lock_guard lock(mutex);
if (!exists)
@@ -215,7 +199,7 @@ CellError lv2_event_queue::send(lv2_event event, bool* notified_thread, lv2_even
const u32 data2 = static_cast<u32>(std::get<2>(event));
const u32 data3 = static_cast<u32>(std::get<3>(event));
spu.ch_in_mbox.set_values(4, CELL_OK, data1, data2, data3);
resume_spu_thread_group_from_waiting(spu, notify_spus.spus);
resume_spu_thread_group_from_waiting(spu);
}
return {};
@@ -276,22 +260,6 @@ error_code sys_event_queue_destroy(ppu_thread& ppu, u32 equeue_id, s32 mode)
return CELL_EINVAL;
}
struct notify_spus_t
{
std::array<shared_ptr<named_thread<spu_thread>>, 8> spus;
~notify_spus_t() noexcept
{
for (auto& spu : spus)
{
if (spu && spu->state & cpu_flag::wait)
{
spu->state.notify_one();
}
}
}
} notify_spus{};
std::vector<lv2_event> events;
std::unique_lock<shared_mutex> qlock;
@@ -389,7 +357,7 @@ error_code sys_event_queue_destroy(ppu_thread& ppu, u32 equeue_id, s32 mode)
for (auto cpu = +queue->sq; cpu; cpu = cpu->next_cpu)
{
cpu->ch_in_mbox.set_values(1, CELL_ECANCELED);
resume_spu_thread_group_from_waiting(*cpu, notify_spus.spus);
resume_spu_thread_group_from_waiting(*cpu);
}
atomic_storage<spu_thread*>::release(queue->sq, nullptr);
@@ -452,8 +420,10 @@ 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++];
std::tie(dest.source, dest.data1, dest.data2, dest.data3) = queue->events.front();
const auto event = queue->events.front();
queue->events.pop_front();
std::tie(dest.source, dest.data1, dest.data2, dest.data3) = event;
}
lock.unlock();

View File

@@ -2,10 +2,13 @@
#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);
@@ -21,7 +24,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>(stx::exact_t<utils::serial&>(ar)));
return load_func(make_shared<lv2_event_flag>(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

@@ -6,6 +6,7 @@
#include "Utilities/StrUtil.h"
#include <string>
#include <mutex>
// Open Flags
enum : s32

View File

@@ -10,7 +10,6 @@
#include "Utilities/StrUtil.h"
#include "Utilities/Thread.h"
#include "Emu/Cell/timers.hpp"
#include "sys_game.h"
LOG_CHANNEL(sys_game);

View File

@@ -1,6 +1,7 @@
#include "stdafx.h"
#include "sys_hid.h"
#include "Emu/Memory/vm.h"
#include "Emu/Memory/vm_var.h"
#include "Emu/Cell/PPUThread.h"

View File

@@ -7,6 +7,7 @@
#include "Emu/Cell/SPUThread.h"
#include "Emu/IdManager.h"
#include "util/vm.hpp"
#include "util/asm.hpp"
LOG_CHANNEL(sys_memory);
@@ -32,7 +33,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<atomic_ptr<lv2_memory_container>*>(storage) = ptr;
*static_cast<shared_ptr<lv2_memory_container>*>(storage) = ptr;
};
}

View File

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

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