diff --git a/app/src/main/cpp/aps3e_rp3_impl.cpp b/app/src/main/cpp/aps3e_rp3_impl.cpp index 0dbf1fc..08f8383 100644 --- a/app/src/main/cpp/aps3e_rp3_impl.cpp +++ b/app/src/main/cpp/aps3e_rp3_impl.cpp @@ -72,7 +72,7 @@ extern std::shared_ptr make_disasm(const cpu_thread* cpu, shared_ptr< result->set_cpu_handle(std::move(handle)); return result; } - +#if 0 template <> void fmt_class_string::format(std::string& out, u64 arg) { @@ -94,7 +94,7 @@ void fmt_class_string::format(std::string& out, u64 arg) return unknown; }); } - +#endif template <> void fmt_class_string>::format(std::string& out, u64 arg) { @@ -182,7 +182,7 @@ __attribute__((constructor)) static void init_localized_strings() class android_save_dialog:public SaveDialogBase{ public: - s32 ShowSaveDataList(std::vector& save_entries, s32 focused, u32 op, vm::ptr listSet, bool enable_overlay) override + s32 ShowSaveDataList(const std::string& base_dir, std::vector& save_entries, s32 focused, u32 op, vm::ptr 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); diff --git a/app/src/main/cpp/rpcs3/Utilities/cfmt.h b/app/src/main/cpp/rpcs3/Utilities/cfmt.h index 3b2c94d..9d23c6f 100644 --- a/app/src/main/cpp/rpcs3/Utilities/cfmt.h +++ b/app/src/main/cpp/rpcs3/Utilities/cfmt.h @@ -2,7 +2,6 @@ #include "util/types.hpp" #include -#include #include #include "util/asm.hpp" diff --git a/app/src/main/cpp/rpcs3/Utilities/cheat_info.cpp b/app/src/main/cpp/rpcs3/Utilities/cheat_info.cpp index 42ffb89..a16be27 100644 --- a/app/src/main/cpp/rpcs3/Utilities/cheat_info.cpp +++ b/app/src/main/cpp/rpcs3/Utilities/cheat_info.cpp @@ -1,10 +1,32 @@ #include "stdafx.h" #include "cheat_info.h" -#include "Config.h" #include "StrUtil.h" LOG_CHANNEL(log_cheat, "Cheat"); +template <> +void fmt_class_string::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); diff --git a/app/src/main/cpp/rpcs3/Utilities/cheat_info.h b/app/src/main/cpp/rpcs3/Utilities/cheat_info.h index 9c77d8d..3ceb327 100644 --- a/app/src/main/cpp/rpcs3/Utilities/cheat_info.h +++ b/app/src/main/cpp/rpcs3/Utilities/cheat_info.h @@ -14,6 +14,7 @@ enum class cheat_type : u8 signed_16_cheat, signed_32_cheat, signed_64_cheat, + float_32_cheat, max }; diff --git a/app/src/main/cpp/rpcs3/Utilities/lockless.h b/app/src/main/cpp/rpcs3/Utilities/lockless.h index 48142de..5028b39 100644 --- a/app/src/main/cpp/rpcs3/Utilities/lockless.h +++ b/app/src/main/cpp/rpcs3/Utilities/lockless.h @@ -49,7 +49,7 @@ public: if (!next) { - // Do not allow access beyond many element more at a time + // Do not allow access beyond many element more at a time ensure(!installed && index - i < N * 2); installed = true; @@ -384,17 +384,25 @@ public: template class lf_queue final { - atomic_t m_head{0}; - - lf_queue_item* load(u64 value) const noexcept +private: + struct fat_ptr { - return reinterpret_cast*>(value >> 16); + u64 ptr{}; + u32 is_non_null{}; + u32 reserved{}; + }; + + atomic_t m_head{fat_ptr{}}; + + lf_queue_item* load(fat_ptr value) const noexcept + { + return reinterpret_cast*>(value.ptr); } // Extract all elements and reverse element order (FILO to FIFO) lf_queue_item* reverse() noexcept { - if (auto* head = load(m_head) ? load(m_head.exchange(0)) : nullptr) + if (auto* head = load(m_head) ? load(m_head.exchange(fat_ptr{})) : nullptr) { if (auto* prev = head->m_link) { @@ -420,7 +428,7 @@ public: lf_queue(lf_queue&& other) noexcept { - m_head.release(other.m_head.exchange(0)); + m_head.release(other.m_head.exchange(fat_ptr{})); } lf_queue& operator=(lf_queue&& other) noexcept @@ -430,8 +438,7 @@ public: return *this; } - delete load(m_head); - m_head.release(other.m_head.exchange(0)); + delete load(m_head.exchange(other.m_head.exchange(fat_ptr{}))); return *this; } @@ -442,12 +449,17 @@ public: void wait(std::nullptr_t /*null*/ = nullptr) noexcept { - if (m_head == 0) + if (!operator bool()) { - utils::bless>(&m_head)[1].wait(0); + get_wait_atomic().wait(0); } } + atomic_t &get_wait_atomic() + { + return *utils::bless>(&m_head.raw().is_non_null); + } + const volatile void* observe() const noexcept { return load(m_head); @@ -455,7 +467,7 @@ public: explicit operator bool() const noexcept { - return m_head != 0; + return observe() != nullptr; } template @@ -464,25 +476,25 @@ public: auto oldv = m_head.load(); auto item = new lf_queue_item(load(oldv), std::forward(args)...); - while (!m_head.compare_exchange(oldv, reinterpret_cast(item) << 16)) + while (!m_head.compare_exchange(oldv, fat_ptr{reinterpret_cast(item), item != nullptr, 0})) { item->m_link = load(oldv); } - if (!oldv && Notify) + if (!oldv.ptr && Notify) { // Notify only if queue was empty notify(true); } - return !oldv; + return !oldv.ptr; } void notify(bool force = false) { if (force || operator bool()) { - utils::bless>(&m_head)[1].notify_one(); + get_wait_atomic().notify_one(); } } @@ -498,7 +510,7 @@ public: lf_queue_slice pop_all_reversed() { lf_queue_slice result; - result.m_head = load(m_head.exchange(0)); + result.m_head = load(m_head.exchange(fat_ptr{})); return result; } diff --git a/app/src/main/cpp/rpcs3/Utilities/transactional_storage.h b/app/src/main/cpp/rpcs3/Utilities/transactional_storage.h index dda86ef..55e8aa9 100644 --- a/app/src/main/cpp/rpcs3/Utilities/transactional_storage.h +++ b/app/src/main/cpp/rpcs3/Utilities/transactional_storage.h @@ -1,6 +1,7 @@ #include "util/types.hpp" #include #include +#include "Emu/Cell/timers.hpp" // Thread-safe object pool with garbage collection class universal_pool diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/HLE_PATCHES.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/HLE_PATCHES.cpp index 0d5fa62..8b3ad0b 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/HLE_PATCHES.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/HLE_PATCHES.cpp @@ -4,7 +4,6 @@ #include "Utilities/Thread.h" #include "Emu/Cell/lv2/sys_spu.h" -#include "Emu/Cell/lv2/sys_sync.h" #include diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellAudio.h b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellAudio.h index 939b7f9..a88ac6e 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellAudio.h +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellAudio.h @@ -195,7 +195,7 @@ struct audio_port // Handle copy ctor of atomic var audio_port(const audio_port& r) { - std::memcpy(this, &r, sizeof(r)); + std::memcpy(static_cast(this), &r, sizeof(r)); } ENABLE_BITWISE_SERIALIZATION; diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellAudioIn.h b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellAudioIn.h index a630ce4..7ceaa2d 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellAudioIn.h +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellAudioIn.h @@ -1,7 +1,6 @@ #pragma once #include "util/types.hpp" -#include "util/endian.hpp" // Error codes enum CellAudioInError : u32 @@ -76,7 +75,7 @@ struct CellAudioInDeviceInfo u8 reserved[12]; be_t deviceId; be_t type; - char name[64]; + char name[64]; // Not necessarily null terminated! CellAudioInSoundMode availableModes[16]; }; diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellDaisy.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellDaisy.cpp index e0d2926..a6e3520 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellDaisy.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellDaisy.cpp @@ -26,11 +26,6 @@ void fmt_class_string::format(std::string& out, u64 arg) }); } -// Temporarily -#ifndef _MSC_VER -#pragma GCC diagnostic ignored "-Wunused-parameter" -#endif - using LFQueue2 = struct CellDaisyLFQueue2; using Lock = struct CellDaisyLock; using ScatterGatherInterlock = struct CellDaisyScatterGatherInterlock; @@ -38,134 +33,134 @@ using AtomicInterlock = volatile struct CellDaisyAtomicInterlock; error_code cellDaisyLFQueue2GetPopPointer(vm::ptr queue, vm::ptr pPointer, u32 isBlocking) { - cellDaisy.todo("cellDaisyLFQueue2GetPopPointer()"); + cellDaisy.todo("cellDaisyLFQueue2GetPopPointer(queue=*0x%x, pPointer=*0x%x, isBlocking=%d)", queue, pPointer, isBlocking); return CELL_OK; } error_code cellDaisyLFQueue2CompletePopPointer(vm::ptr queue, s32 pointer, vm::ptr, u32)> fpSendSignal, u32 isQueueFull) { - cellDaisy.todo("cellDaisyLFQueue2CompletePopPointer()"); + cellDaisy.todo("cellDaisyLFQueue2CompletePopPointer(queue=*0x%x, pointer=0x%x, fpSendSignal=*0x%x, isQueueFull=%d)", queue, pointer, fpSendSignal, isQueueFull); return CELL_OK; } void cellDaisyLFQueue2PushOpen(vm::ptr queue) { - cellDaisy.todo("cellDaisyLFQueue2PushOpen()"); + cellDaisy.todo("cellDaisyLFQueue2PushOpen(queue=*0x%x)", queue); } error_code cellDaisyLFQueue2PushClose(vm::ptr queue, vm::ptr, u32)> fpSendSignal) { - cellDaisy.todo("cellDaisyLFQueue2PushClose()"); + cellDaisy.todo("cellDaisyLFQueue2PushClose(queue=*0x%x, fpSendSignal=*0x%x)", queue, fpSendSignal); return CELL_OK; } void cellDaisyLFQueue2PopOpen(vm::ptr queue) { - cellDaisy.todo("cellDaisyLFQueue2PopOpen()"); + cellDaisy.todo("cellDaisyLFQueue2PopOpen(queue=*0x%x)", queue); } error_code cellDaisyLFQueue2PopClose(vm::ptr queue, vm::ptr, u32)> fpSendSignal) { - cellDaisy.todo("cellDaisyLFQueue2PopClose()"); + cellDaisy.todo("cellDaisyLFQueue2PopClose(queue=*0x%x, fpSendSignal=*0x%x)", queue, fpSendSignal); return CELL_OK; } error_code cellDaisyLFQueue2HasUnfinishedConsumer(vm::ptr queue, u32 isCancelled) { - cellDaisy.todo("cellDaisyLFQueue2HasUnfinishedConsumer()"); + cellDaisy.todo("cellDaisyLFQueue2HasUnfinishedConsumer(queue=*0x%x, isCancelled=%d)", queue, isCancelled); return CELL_OK; } error_code cellDaisy_snprintf(vm::ptr buffer, u32 count, vm::cptr fmt, ppu_va_args_t fmt_args) { - cellDaisy.todo("cellDaisy_snprintf()"); + cellDaisy.todo("cellDaisy_snprintf(buffer=*0x%x, count=%d, fmt=*0x%x, fmt_args=%d)", buffer, count, fmt, fmt_args.count); return CELL_OK; } error_code cellDaisyLock_initialize(vm::ptr _this, u32 depth) { - cellDaisy.todo("cellDaisyLock_initialize()"); + cellDaisy.todo("cellDaisyLock_initialize(_this=*0x%x, depth=%d)", _this, depth); return CELL_OK; } error_code cellDaisyLock_getNextHeadPointer(vm::ptr _this) { - cellDaisy.todo("cellDaisyLock_getNextHeadPointer()"); + cellDaisy.todo("cellDaisyLock_getNextHeadPointer(_this=*0x%x)", _this); return CELL_OK; } error_code cellDaisyLock_getNextTailPointer(vm::ptr _this) { - cellDaisy.todo("cellDaisyLock_getNextTailPointer()"); + cellDaisy.todo("cellDaisyLock_getNextTailPointer(_this=*0x%x)", _this); return CELL_OK; } error_code cellDaisyLock_completeConsume(vm::ptr _this, u32 pointer) { - cellDaisy.todo("cellDaisyLock_completeConsume()"); + cellDaisy.todo("cellDaisyLock_completeConsume(_this=*0x%x, pointer=0x%x)", _this, pointer); return CELL_OK; } error_code cellDaisyLock_completeProduce(vm::ptr _this, u32 pointer) { - cellDaisy.todo("cellDaisyLock_completeProduce()"); + cellDaisy.todo("cellDaisyLock_completeProduce(_this=*0x%x, pointer=0x%x)", _this, pointer); return CELL_OK; } error_code cellDaisyLock_pushOpen(vm::ptr _this) { - cellDaisy.todo("cellDaisyLock_pushOpen()"); + cellDaisy.todo("cellDaisyLock_pushOpen(_this=*0x%x)", _this); return CELL_OK; } error_code cellDaisyLock_pushClose(vm::ptr _this) { - cellDaisy.todo("cellDaisyLock_pushClose()"); + cellDaisy.todo("cellDaisyLock_pushClose(_this=*0x%x)", _this); return CELL_OK; } error_code cellDaisyLock_popOpen(vm::ptr _this) { - cellDaisy.todo("cellDaisyLock_popOpen()"); + cellDaisy.todo("cellDaisyLock_popOpen(_this=*0x%x)", _this); return CELL_OK; } error_code cellDaisyLock_popClose(vm::ptr _this) { - cellDaisy.todo("cellDaisyLock_popClose()"); + cellDaisy.todo("cellDaisyLock_popClose(_this=*0x%x)", _this); return CELL_OK; } void cellDaisyScatterGatherInterlock_1(vm::ptr _this, vm::ptr ea, u32 size, vm::ptr eaSignal, vm::ptr, u32)> fpSendSignal) { - cellDaisy.todo("cellDaisyScatterGatherInterlock_1()"); + cellDaisy.todo("cellDaisyScatterGatherInterlock_1(_this=*0x%x, ea=*0x%x, size=%d, eaSignal=*0x%x, fpSendSignal=*0x%x)", _this, ea, size, eaSignal, fpSendSignal); } void cellDaisyScatterGatherInterlock_2(vm::ptr _this, u32 size, vm::ptr ids, u32 numSpus, u8 spup) { - cellDaisy.todo("cellDaisyScatterGatherInterlock_2()"); + cellDaisy.todo("cellDaisyScatterGatherInterlock_2(_this=*0x%x, size=%d, ids=*0x%x, numSpus=%d, spup=%d)", _this, size, ids, numSpus, spup); } void cellDaisyScatterGatherInterlock_9tor(vm::ptr _this) { - cellDaisy.todo("cellDaisyScatterGatherInterlock_9tor()"); + cellDaisy.todo("cellDaisyScatterGatherInterlock_9tor(_this=*0x%x)", _this); } error_code cellDaisyScatterGatherInterlock_probe(vm::ptr _this, u32 isBlocking) { - cellDaisy.todo("cellDaisyScatterGatherInterlock_probe()"); + cellDaisy.todo("cellDaisyScatterGatherInterlock_probe(_this=*0x%x, isBlocking=%d)", _this, isBlocking); return CELL_OK; } error_code cellDaisyScatterGatherInterlock_release(vm::ptr _this) { - cellDaisy.todo("cellDaisyScatterGatherInterlock_release()"); + cellDaisy.todo("cellDaisyScatterGatherInterlock_release(_this=*0x%x)", _this); return CELL_OK; } void cellDaisyScatterGatherInterlock_proceedSequenceNumber(vm::ptr _this) { - cellDaisy.todo("cellDaisyScatterGatherInterlock_proceedSequenceNumber()"); + cellDaisy.todo("cellDaisyScatterGatherInterlock_proceedSequenceNumber(_this=*0x%x)", _this); } diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellDmux.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellDmux.cpp index 5c94463..d7f6f84 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellDmux.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellDmux.cpp @@ -9,6 +9,8 @@ #include "util/asm.hpp" +#include + LOG_CHANNEL(cellDmux); template <> diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellDmux.h b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellDmux.h index 884a3eb..1767165 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellDmux.h +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellDmux.h @@ -1,6 +1,7 @@ #pragma once #include "Emu/Memory/vm_ptr.h" +#include "cellPamf.h" // Error Codes enum CellDmuxError :u32 diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellDmuxPamf.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellDmuxPamf.cpp index a7b24c3..70162d4 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellDmuxPamf.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellDmuxPamf.cpp @@ -2,7 +2,6 @@ #include "Emu/Cell/PPUModule.h" #include "Emu/IdManager.h" -#include "cellPamf.h" #include "cellDmux.h" #include "cellDmuxPamf.h" diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellGem.h b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellGem.h index b5e03db..c70e238 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellGem.h +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellGem.h @@ -161,7 +161,8 @@ enum CellGemVideoConvertFormatEnum : s32 // External device IDs (types) enum { - SHARP_SHOOTER_DEVICE_ID = 0x8081 + SHARP_SHOOTER_DEVICE_ID = 0x8081, + RACING_WHEEL_DEVICE_ID = 0x8101 }; struct CellGemAttribute diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellGifDec.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellGifDec.cpp index 448f860..faf8def 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellGifDec.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellGifDec.cpp @@ -9,15 +9,8 @@ #include "Emu/Cell/lv2/sys_fs.h" #include "cellGifDec.h" -#include "util/asm.hpp" - LOG_CHANNEL(cellGifDec); -// Temporarily -#ifndef _MSC_VER -#pragma GCC diagnostic ignored "-Wunused-parameter" -#endif - template <> void fmt_class_string::format(std::string& out, u64 arg) { @@ -273,7 +266,7 @@ error_code cellGifDecReadHeader(vm::ptr mainHandle, vm::ptrfd; + const u32 fd = subHandle->fd; CellGifDecInfo& current_info = subHandle->info; // Write the header to buffer @@ -302,7 +295,7 @@ error_code cellGifDecReadHeader(vm::ptr mainHandle, vm::ptr> 7; @@ -520,8 +513,8 @@ error_code cellGifDecDecodeData(vm::ptr mainHandle, vm::cptr(dataCtrlParam->outputBytesPerLine); - const char nComponents = 4; - uint image_size = width * height * nComponents; + constexpr char nComponents = 4; + const u32 image_size = width * height * nComponents; switch(current_outParam.outputColorSpace) { @@ -541,9 +534,8 @@ error_code cellGifDecDecodeData(vm::ptr mainHandle, vm::cptr width * nComponents) // Check if we need padding @@ -579,9 +571,8 @@ error_code cellGifDecDecodeData(vm::ptr mainHandle, vm::cptr out, u32 outSize, vm::cptr in for (u32 pos = 0; rindex >= 0; rindex--, pos++) { - char c1 = in[pos]; + const char c1 = in[pos]; if (false) // DAT[c1] == '\x03') // TODO { @@ -529,7 +529,7 @@ error_code cellHttpUtilEscapeUri(vm::ptr out, u32 outSize, vm::cptr in return CELL_HTTP_UTIL_ERROR_NO_MEMORY; } - const char* chars = "0123456789ABCDEF"; + constexpr const char* chars = "0123456789ABCDEF"; out[out_pos++] = '%'; // 0x25 out[out_pos++] = chars[c1 >> 4]; out[out_pos++] = chars[c1 & 0xf]; @@ -618,7 +618,7 @@ error_code cellHttpUtilFormUrlEncode(vm::ptr out, u32 outSize, vm::cptr= 0; rindex--, pos++) { - char c1 = in[pos]; + const char c1 = in[pos]; if (c1 == ' ') { @@ -645,7 +645,7 @@ error_code cellHttpUtilFormUrlEncode(vm::ptr out, u32 outSize, vm::cptr> 4]; out[out_pos++] = chars[c1 & 0xf]; @@ -707,7 +707,7 @@ error_code cellHttpUtilFormUrlDecode(vm::ptr out, u32 size, vm::cptr i for (s32 index = 0, pos = 0;; index++) { size_needed = index + 1; - char c1 = in[pos++]; + const char c1 = in[pos++]; if (!c1) { @@ -731,7 +731,7 @@ error_code cellHttpUtilFormUrlDecode(vm::ptr out, u32 size, vm::cptr i const auto check_char = [](b8 c) { - u32 utmp = static_cast(c); + const u32 utmp = static_cast(c); s32 stmp = utmp - 48; if (static_cast(c - 48) > 9) { diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellJpgDec.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellJpgDec.cpp index 82ec567..5123ec6 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellJpgDec.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellJpgDec.cpp @@ -9,15 +9,8 @@ #include "Emu/Cell/lv2/sys_fs.h" #include "cellJpgDec.h" -#include "util/asm.hpp" - LOG_CHANNEL(cellJpgDec); -// Temporarily -#ifndef _MSC_VER -#pragma GCC diagnostic ignored "-Wunused-parameter" -#endif - template <> void fmt_class_string::format(std::string& out, u64 arg) { @@ -42,19 +35,19 @@ void fmt_class_string::format(std::string& out, u64 arg) error_code cellJpgDecCreate(u32 mainHandle, u32 threadInParam, u32 threadOutParam) { - UNIMPLEMENTED_FUNC(cellJpgDec); + cellJpgDec.todo("cellJpgDecCreate(mainHandle=0x%x, threadInParam=0x%x, threadOutParam=0x%x)", mainHandle, threadInParam, threadOutParam); return CELL_OK; } error_code cellJpgDecExtCreate(u32 mainHandle, u32 threadInParam, u32 threadOutParam, u32 extThreadInParam, u32 extThreadOutParam) { - UNIMPLEMENTED_FUNC(cellJpgDec); + cellJpgDec.todo("cellJpgDecExtCreate(mainHandle=0x%x, threadInParam=0x%x, threadOutParam=0x%x, extThreadInParam=0x%x, extThreadOutParam=0x%x)", mainHandle, threadInParam, threadOutParam, extThreadInParam, extThreadOutParam); return CELL_OK; } error_code cellJpgDecDestroy(u32 mainHandle) { - UNIMPLEMENTED_FUNC(cellJpgDec); + cellJpgDec.todo("cellJpgDecDestroy(mainHandle=0x%x)", mainHandle); return CELL_OK; } @@ -76,7 +69,7 @@ error_code cellJpgDecOpen(u32 mainHandle, vm::ptr subHandle, vm::ptrfileName.get_ptr()); + const std::string real_path = vfs::get(src->fileName.get_ptr()); fs::file file_s(real_path); if (!file_s) return CELL_JPGDEC_ERROR_OPEN_FILE; @@ -127,8 +120,8 @@ error_code cellJpgDecReadHeader(u32 mainHandle, u32 subHandle, vm::ptrfd; - const u64& fileSize = subHandle_data->fileSize; + const u32 fd = subHandle_data->fd; + const u64 fileSize = subHandle_data->fileSize; CellJpgDecInfo& current_info = subHandle_data->info; // Write the header to buffer @@ -158,12 +151,12 @@ error_code cellJpgDecReadHeader(u32 mainHandle, u32 subHandle, vm::ptr= fileSize) + if (i >= fileSize) return CELL_JPGDEC_ERROR_HEADER; - u16 block_length = buffer[i] * 0xFF + buffer[i+1]; + u16 block_length = buffer[i] * 0xFF + buffer[i + 1]; - while(true) + while (true) { i += block_length; // Increase the file index to get to the next block if (i >= fileSize || // Check to protect against segmentation faults @@ -172,15 +165,15 @@ error_code cellJpgDecReadHeader(u32 mainHandle, u32 subHandle, vm::ptr data, } //Decode JPG file. (TODO: Is there any faster alternative? Can we do it without external libraries?) - int width, height, actual_components; + int width = 0, height = 0, actual_components = 0; auto image = std::unique_ptr ( stbi_load_from_memory(jpg.get(), ::narrow(fileSize), &width, &height, &actual_components, 4), @@ -267,18 +260,17 @@ error_code cellJpgDecDecodeData(u32 mainHandle, u32 subHandle, vm::ptr data, { memcpy(data.get_ptr(), image.get(), image_size); } + break; } - break; - case CELL_JPG_ARGB: { - const int nComponents = 4; + constexpr int nComponents = 4; image_size *= nComponents; if (bytesPerLine > width * nComponents || flip) //check if we need padding { //TODO: Find out if we can't do padding without an extra copy const int linesize = std::min(bytesPerLine, width * nComponents); - const auto output = std::make_unique(linesize); + std::vector output(image_size); for (int i = 0; i < height; i++) { const int dstOffset = i * bytesPerLine; @@ -290,33 +282,32 @@ error_code cellJpgDecDecodeData(u32 mainHandle, u32 subHandle, vm::ptr data, output[j + 2] = image.get()[srcOffset + j + 1]; output[j + 3] = image.get()[srcOffset + j + 2]; } - std::memcpy(&data[dstOffset], output.get(), linesize); + std::memcpy(&data[dstOffset], output.data(), linesize); } } else { - const auto img = std::make_unique(image_size); - uint* source_current = reinterpret_cast(image.get()); - uint* dest_current = img.get(); - for (uint i = 0; i < image_size / nComponents; i++) + std::vector img(image_size); + const u32* source_current = reinterpret_cast(image.get()); + u32* dest_current = img.data(); + for (u32 i = 0; i < image_size / nComponents; i++) { - uint val = *source_current; + const u32 val = *source_current; *dest_current = (val >> 24) | (val << 8); // set alpha (A8) as leftmost byte source_current++; dest_current++; } - std::memcpy(data.get_ptr(), img.get(), image_size); + std::memcpy(data.get_ptr(), img.data(), image_size); } + break; } - break; - case CELL_JPG_GRAYSCALE: case CELL_JPG_YCbCr: case CELL_JPG_UPSAMPLE_ONLY: case CELL_JPG_GRAYSCALE_TO_ALPHA_RGBA: case CELL_JPG_GRAYSCALE_TO_ALPHA_ARGB: cellJpgDec.error("cellJpgDecDecodeData: Unsupported color space (%d)", current_outParam.outputColorSpace); - break; + break; default: return CELL_JPGDEC_ERROR_ARG; @@ -324,7 +315,7 @@ error_code cellJpgDecDecodeData(u32 mainHandle, u32 subHandle, vm::ptr data, dataOutInfo->status = CELL_JPGDEC_DEC_STATUS_FINISH; - if(dataCtrlParam->outputBytesPerLine) + if (dataCtrlParam->outputBytesPerLine) dataOutInfo->outputLines = static_cast(image_size / dataCtrlParam->outputBytesPerLine); return CELL_OK; diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellKey2char.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellKey2char.cpp index bbe7e18..ba09a70 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellKey2char.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellKey2char.cpp @@ -1,6 +1,6 @@ #include "stdafx.h" #include "Emu/Cell/PPUModule.h" -#include "cellKb.h" +#include "Emu/Io/Keyboard.h" LOG_CHANNEL(cellKey2char); diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellL10n.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellL10n.cpp index 01df498..6b3ffc4 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellL10n.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellL10n.cpp @@ -16,8 +16,6 @@ typedef const char *HostCode; #include "cellL10n.h" -#include "util/asm.hpp" - LOG_CHANNEL(cellL10n); // Translate code id to code name. some codepage may has another name. @@ -56,9 +54,7 @@ bool _L10nCodeParse(s32 code, HostCode& retCode) case L10N_CODEPAGE_866: retCode = 866; return true; case L10N_CODEPAGE_932: retCode = 932; return true; case L10N_CODEPAGE_936: retCode = 936; return true; // GBK - case L10N_GBK: retCode = 936; return true; case L10N_CODEPAGE_949: retCode = 949; return true; // UHC - case L10N_UHC: retCode = 949; return true; // UHC case L10N_CODEPAGE_950: retCode = 950; return true; case L10N_CODEPAGE_1251: retCode = 1251; return true; // CYRL case L10N_CODEPAGE_1252: retCode = 1252; return true; // ANSI @@ -66,14 +62,11 @@ bool _L10nCodeParse(s32 code, HostCode& retCode) case L10N_EUC_JP: retCode = 51932; return true; case L10N_EUC_KR: retCode = 51949; return true; case L10N_ISO_2022_JP: retCode = 50222; return true; - case L10N_JIS: retCode = 50222; return true; // Maybe 708/720/864/1256/10004/20420/28596/ case L10N_ARIB: retCode = 20420; return true; // TODO: think that should be ARABIC. case L10N_HZ: retCode = 52936; return true; case L10N_GB18030: retCode = 54936; return true; case L10N_RIS_506: retCode = 932; return true; // MS_KANJI, TODO: Code page - case L10N_SHIFT_JIS: retCode = 932; return true; // SJIS - case L10N_MUSIC_SHIFT_JIS: retCode = 932; return true; // MSJIS // These are only supported with FW 3.10 and above case L10N_CODEPAGE_852: retCode = 852; return true; case L10N_CODEPAGE_1250: retCode = 1250; return true; // EE @@ -89,7 +82,6 @@ bool _L10nCodeParse(s32 code, HostCode& retCode) case L10N_CODEPAGE_861: retCode = 861; return true; case L10N_CODEPAGE_865: retCode = 865; return true; case L10N_CODEPAGE_869: retCode = 869; return true; - case L10N_BIG5: retCode = 950; return true; // Codepage 950 default: return false; } #else @@ -123,24 +115,18 @@ bool _L10nCodeParse(s32 code, HostCode& retCode) case L10N_CODEPAGE_866: retCode = "CP866"; return true; case L10N_CODEPAGE_932: retCode = "CP932"; return true; case L10N_CODEPAGE_936: retCode = "CP936"; return true; - case L10N_GBK: retCode = "CP936"; return true; case L10N_CODEPAGE_949: retCode = "CP949"; return true; - case L10N_UHC: retCode = "CP949"; return true; case L10N_CODEPAGE_950: retCode = "CP950"; return true; - case L10N_BIG5: retCode = "CP950"; return true; // BIG5 = CodePage 950 case L10N_CODEPAGE_1251: retCode = "CP1251"; return true; // CYRL case L10N_CODEPAGE_1252: retCode = "CP1252"; return true; // ANSI case L10N_EUC_CN: retCode = "EUC-CN"; return true; // GB2312 case L10N_EUC_JP: retCode = "EUC-JP"; return true; case L10N_EUC_KR: retCode = "EUC-KR"; return true; case L10N_ISO_2022_JP: retCode = "ISO-2022-JP"; return true; - case L10N_JIS: retCode = "ISO-2022-JP"; return true; case L10N_ARIB: retCode = "ARABIC"; return true; // TODO: think that should be ARABIC. case L10N_HZ: retCode = "HZ"; return true; case L10N_GB18030: retCode = "GB18030"; return true; case L10N_RIS_506: retCode = "Shift_JIS"; return true; // MS_KANJI - case L10N_SHIFT_JIS: retCode = "Shift_JIS"; return true; // CP932 for Microsoft - case L10N_MUSIC_SHIFT_JIS: retCode = "Shift_JIS"; return true; // MusicShiftJIS // These are only supported with FW 3.10 and below case L10N_CODEPAGE_852: retCode = "CP852"; return true; case L10N_CODEPAGE_1250: retCode = "CP1250"; return true; // EE @@ -164,41 +150,36 @@ bool _L10nCodeParse(s32 code, HostCode& retCode) #ifdef _WIN32 // Use code page to transform std::string to std::wstring. -s32 _OEM2Wide(HostCode oem_code, const std::string& src, std::wstring& dst) +s32 _OEM2Wide(HostCode oem_code, std::string_view src, std::wstring& dst) { - //Such length returned should include the '\0' character. - const s32 length = MultiByteToWideChar(oem_code, 0, src.c_str(), -1, nullptr, 0); - wchar_t *store = new wchar_t[length](); + // Such length returned should include the '\0' character. + const s32 length = MultiByteToWideChar(oem_code, 0, src.data(), -1, nullptr, 0); + std::vector store(length); - MultiByteToWideChar(oem_code, 0, src.c_str(), -1, static_cast(store), length); - dst = std::wstring(store); - - delete[] store; - store = nullptr; + MultiByteToWideChar(oem_code, 0, src.data(), -1, static_cast(store.data()), length); + dst = std::wstring(store.data()); return length - 1; } // Use Code page to transform std::wstring to std::string. -s32 _Wide2OEM(HostCode oem_code, const std::wstring& src, std::string& dst) +s32 _Wide2OEM(HostCode oem_code, std::wstring_view src, std::string& dst) { //Such length returned should include the '\0' character. - const s32 length = WideCharToMultiByte(oem_code, 0, src.c_str(), -1, nullptr, 0, nullptr, nullptr); - char *store = new char[length](); + const s32 length = WideCharToMultiByte(oem_code, 0, src.data(), -1, nullptr, 0, nullptr, nullptr); + std::vector store(length); - WideCharToMultiByte(oem_code, 0, src.c_str(), -1, store, length, nullptr, nullptr); - dst = std::string(store); - - delete[] store; - store = nullptr; + WideCharToMultiByte(oem_code, 0, src.data(), -1, store.data(), length, nullptr, nullptr); + dst = std::string(store.data()); return length - 1; } // Convert Codepage to Codepage (all char*) -std::string _OemToOem(HostCode src_code, HostCode dst_code, const std::string& str) +std::string _OemToOem(HostCode src_code, HostCode dst_code, std::string_view str) { - std::wstring wide; std::string result; + std::wstring wide; + std::string result; _OEM2Wide(src_code, str, wide); _Wide2OEM(dst_code, wide, result); return result; @@ -209,21 +190,23 @@ std::string _OemToOem(HostCode src_code, HostCode dst_code, const std::string& s s32 _ConvertStr(s32 src_code, const void *src, s32 src_len, s32 dst_code, void *dst, s32 *dst_len, [[maybe_unused]] bool allowIncomplete) { HostCode srcCode = 0, dstCode = 0; //OEM code pages - bool src_page_converted = _L10nCodeParse(src_code, srcCode); //Check if code is in list. - bool dst_page_converted = _L10nCodeParse(dst_code, dstCode); + const bool src_page_converted = _L10nCodeParse(src_code, srcCode); //Check if code is in list. + const bool dst_page_converted = _L10nCodeParse(dst_code, dstCode); - if (((!src_page_converted) && (srcCode == 0)) - || ((!dst_page_converted) && (dstCode == 0))) + if (((!src_page_converted) && (srcCode == 0)) || + ((!dst_page_converted) && (dstCode == 0))) + { return ConverterUnknown; + } #ifdef _WIN32 - const std::string wrapped_source = std::string(static_cast(src), src_len); + const std::string_view wrapped_source = std::string_view(static_cast(src), src_len); const std::string target = _OemToOem(srcCode, dstCode, wrapped_source); - if (dst != nullptr) + if (dst) { if (target.length() > static_cast(*dst_len)) return DSTExhausted; - memcpy(dst, target.c_str(), target.length()); + std::memcpy(dst, target.c_str(), target.length()); } *dst_len = ::narrow(target.size()); @@ -232,7 +215,7 @@ s32 _ConvertStr(s32 src_code, const void *src, s32 src_len, s32 dst_code, void * s32 retValue = ConversionOK; iconv_t ict = iconv_open(dstCode, srcCode); usz srcLen = src_len; - if (dst != NULL) + if (dst) { usz dstLen = *dst_len; usz ictd = iconv(ict, utils::bless(&src), &srcLen, utils::bless(&dst), &dstLen); @@ -282,7 +265,7 @@ s32 _ConvertStr(s32 src_code, const void *src, s32 src_len, s32 dst_code, void * #endif } -s32 _L10nConvertStr(s32 src_code, vm::cptr src, vm::cptr src_len, s32 dst_code, vm::ptr dst, vm::ptr dst_len) +s32 _L10nConvertStr(s32 src_code, vm::cptr src, vm::cptr src_len, s32 dst_code, vm::ptr dst, vm::ptr dst_len) { s32 dstLen = *dst_len; s32 result = _ConvertStr(src_code, src.get_ptr(), *src_len, dst_code, dst ? dst.get_ptr() : nullptr, &dstLen, false); @@ -290,7 +273,7 @@ s32 _L10nConvertStr(s32 src_code, vm::cptr src, vm::cptr src_len, s32 return result; } -s32 _L10nConvertChar(s32 src_code, const void *src, s32 src_len, s32 dst_code, vm::ptr dst, vm::ptr dst_len) +s32 _L10nConvertChar(s32 src_code, const void *src, u32 src_len, s32 dst_code, vm::ptr dst, vm::ptr dst_len) { s32 dstLen = 0x7FFFFFFF; s32 result = _ConvertStr(src_code, src, src_len, dst_code, dst.get_ptr(), &dstLen, true); @@ -298,28 +281,32 @@ s32 _L10nConvertChar(s32 src_code, const void *src, s32 src_len, s32 dst_code, v return result; } -s32 _L10nConvertCharNoResult(s32 src_code, const void *src, s32 src_len, s32 dst_code, vm::ptr dst) -{ - s32 dstLen = 0x7FFFFFFF; - [[maybe_unused]] s32 result = _ConvertStr(src_code, src, src_len, dst_code, dst.get_ptr(), &dstLen, true); - return dstLen; -} - s32 UCS2toEUCJP() { cellL10n.todo("UCS2toEUCJP()"); return 0; } -s32 l10n_convert() +s32 l10n_convert(s32 cd, vm::cptr src, vm::ptr dst, vm::ptr dst_len) { - cellL10n.todo("l10n_convert()"); + cellL10n.todo("l10n_convert(cd=0x%x, src=*0x%x, dst=*0x%x, dst_len=*0x%x)", cd, src, dst, dst_len); return 0; } -s32 UCS2toUTF32() +s32 UCS2toUTF32(u16 ucs2, vm::ptr utf32) { - cellL10n.todo("UCS2toUTF32()"); + cellL10n.notice("UCS2toUTF32(ucs2=0x%x, utf32=*0x%x)", ucs2, utf32); + + const s32 sucs2 = static_cast(ucs2); + + if ((sucs2 & UTF16_SURROGATES_MASK1) != UTF16_HIGH_SURROGATES) + { + ensure(!!utf32); // Not actually checked + + *utf32 = sucs2; + return 1; + } + return 0; } @@ -383,9 +370,43 @@ s32 kuten2eucjp() return 0; } -s32 sjis2jis() +u16 sjis2jis(u16 c) { - cellL10n.todo("sjis2jis()"); + cellL10n.notice("sjis2jis(c=0x%x)", c); + + u64 v0 = static_cast(static_cast(static_cast(c))) >> 8 & 0xff; + u64 v1 = v0 - 0x81; + + if (((v1 & 0xffff) >= 0x7c) || (0x3f >= ((v0 - 0xa0) & 0xffff))) + { + return 0; + } + + const u64 v2 = static_cast(static_cast(c)) & 0xff; + + if (0x3f < v2 && (v2 < 0xfd && (static_cast(v2) != 0x7f))) + { + if (0x9f < v0) + { + v1 = v0 - 0xc1; + } + + u16 v3 = static_cast(v2) - 0x7e; + v0 = (v1 & 0x7fffffff) * 2 + 0x22; + + if (v2 < 0x9f) + { + const s16 v4 = v2 < 0x7f ? 0x1f : 0x20; + v3 = static_cast(v2) - v4; + v0 = (v1 & 0x7fffffff) * 2 + 0x21; + } + + if ((v0 & 0xffff) < 0x7f) + { + return static_cast((v0 & 0xffff) << 8) | v3; + } + } + return 0; } @@ -490,9 +511,58 @@ s32 eucjp2jis() return CELL_OK; } -s32 UTF32stoUTF8s(vm::cptr src, vm::cptr src_len, vm::ptr dst, vm::ptr dst_len) +s32 UTF32toUTF8(u32 src, vm::ptr dst); + +s32 UTF32stoUTF8s(vm::cptr src, vm::ptr src_len, vm::ptr dst, vm::ptr dst_len) { - cellL10n.todo("UTF32stoUTF8s(src=*0x%x, src_len=*0x%x, dst=*0x%x, dst_len=*0x%x)", src, src_len, dst, dst_len); + cellL10n.notice("UTF32stoUTF8s(src=*0x%x, src_len=*0x%x, dst=*0x%x, dst_len=*0x%x)", src, src_len, dst, dst_len); + + ensure(src_len && dst_len); // Not really checked + + if (*src_len == 0u) + { + *dst_len = 0; + return ConversionOK; + } + + ensure(src); // Not really checked + + u32 len = 0; + u32 dst_pos = 0; + + auto tmp = vm::make_var[4]>({0, 0, 0, 0}); + const vm::ptr utf8_tmp = vm::cast(tmp.addr()); + + for (u32 src_pos = 0; src_pos < *src_len; src_pos++) + { + const s32 utf8_len = UTF32toUTF8(src[src_pos], utf8_tmp); + + if (utf8_len == 0) + { + *src_len -= src_pos; + *dst_len = len; + return SRCIllegal; + } + + len += utf8_len; + + if (dst) + { + if (*dst_len < len) + { + *src_len -= src_pos; + *dst_len = len - utf8_len; + return DSTExhausted; + } + + for (s32 i = 0; i < utf8_len; i++) + { + dst[dst_pos++] = utf8_tmp[i]; + } + } + } + + *dst_len = len; return ConversionOK; } @@ -502,27 +572,140 @@ s32 sjishan2zen() return 0; } -s32 UCS2toSBCS() +s32 UCS2toSBCS(u16 src, vm::ptr dst, u32 code_page) { - cellL10n.todo("UCS2toSBCS()"); + cellL10n.notice("UCS2toSBCS(src=0x%x, dst=*0x%x, code_page=0x%x)", src, dst, code_page); + + HostCode code = 0; + if ((code_page >= _L10N_CODE_) || !_L10nCodeParse(code_page, code)) + { + return -1; + } + + if (src < 0xfffe) + { + ensure(!!dst); // Not really checked + + if (src < 0x80) + { + *dst = static_cast(src); + return 1; + } + + vm::var dst_len = vm::make_var(0); + const s32 res = _L10nConvertChar(L10N_UCS2, &src, sizeof(src), code_page, dst, dst_len); + + if (res == ConversionOK) + { + return 1; + } + + if (res == ConverterUnknown) + { + return -1; + } + } + return 0; } s32 UTF8stoGBKs() { - cellL10n.todo("UCS2toSBCS()"); + cellL10n.todo("UTF8stoGBKs()"); return ConversionOK; } -s32 UTF8toUCS2() +s32 UTF8toUCS2(vm::cptr src, vm::ptr dst) { - cellL10n.todo("UTF8toUCS2()"); - return 0; + cellL10n.notice("UTF8toUCS2(src=*0x%x, dst=*0x%x)", src, dst); + + ensure(src && dst); // Not really checked + + if ((((src[0] & 0xf0) == 0xe0) && ((src[1] & 0xc0) == 0x80)) && ((src[2] & 0xc0) == 0x80)) + { + const u64 ucs2 = (static_cast(src[1]) & 0x3f) << 6 | (static_cast(src[0]) & 0xf) << 0xc | (static_cast(src[2]) & 0x3f); + + if (ucs2 < 0x800) + { + return 0; + } + + if ((static_cast(ucs2) & UTF16_SURROGATES_MASK1) == UTF16_HIGH_SURROGATES) + { + return 0; + } + + *dst = static_cast(ucs2); + return 3; + } + + if ((((src[0] & 0xe0) == 0xc0) && (0xc1 < static_cast(src[0]))) && ((src[1] & 0xc0) == 0x80)) + { + *dst = (src[0] & 0x1f) << 6 | (src[1] & 0x3f); + return 2; + } + + if (static_cast(src[0]) < '\0') + { + return 0; + } + + *dst = static_cast(src[0]); + return 1; } -s32 UCS2stoUTF8s(vm::cptr src, vm::cptr src_len, vm::ptr dst, vm::ptr dst_len) +s32 UCS2toUTF8(u16 ucs2, vm::ptr utf8); + +s32 UCS2stoUTF8s(vm::cptr src, vm::ptr src_len, vm::ptr dst, vm::ptr dst_len) { - cellL10n.todo("UCS2stoUTF8s(src=*0x%x, src_len=*0x%x, dst=*0x%x, dst_len=*0x%x)", src, src_len, dst, dst_len); + cellL10n.notice("UCS2stoUTF8s(src=*0x%x, src_len=*0x%x, dst=*0x%x, dst_len=*0x%x)", src, src_len, dst, dst_len); + + ensure(src_len && dst_len); // Not really checked + + if (*src_len == 0u) + { + *dst_len = 0; + return ConversionOK; + } + + ensure(src); // Not really checked + + u32 len = 0; + u32 dst_pos = 0; + + auto tmp = vm::make_var[4]>({0, 0, 0, 0}); + const vm::ptr utf8_tmp = vm::cast(tmp.addr()); + + for (u32 src_pos = 0; src_pos < *src_len; src_pos++) + { + const s32 utf8_size = UCS2toUTF8(src[src_pos], utf8_tmp); + + if (utf8_size == 0) + { + *src_len -= src_pos; + *dst_len = len; + return SRCIllegal; + } + + len += utf8_size; + + if (dst) + { + if (*dst_len < len) + { + *src_len -= src_pos; + *dst_len = len - utf8_size; + return DSTExhausted; + } + + for (s32 i = 0; i < utf8_size; i++) + { + dst[dst_pos++] = utf8_tmp[i]; + } + } + } + + *dst_len = len; return ConversionOK; } @@ -532,10 +715,57 @@ s32 EUCKRstoUTF8s() return ConversionOK; } -s32 UTF16stoUTF32s(vm::cptr src, vm::cptr src_len, vm::ptr dst, vm::ptr dst_len) +s32 UTF16toUTF32(vm::cptr src, vm::ptr dst); + +s32 UTF16stoUTF32s(vm::cptr src, vm::ptr src_len, vm::ptr dst, vm::ptr dst_len) { - cellL10n.warning("UTF16stoUTF32s(src=*0x%x, src_len=*0x%x, dst=*0x%x, dst_len=*0x%x)", src, src_len, dst, dst_len); - return _L10nConvertStr(L10N_UTF16, src, src_len, L10N_UTF32, dst, dst_len); + cellL10n.notice("UTF16stoUTF32s(src=*0x%x, src_len=*0x%x, dst=*0x%x, dst_len=*0x%x)", src, src_len, dst, dst_len); + + ensure(src_len && dst_len); // Not really checked + + if (*src_len == 0u) + { + *dst_len = 0; + return ConversionOK; + } + + ensure(src); // Not really checked + + u32 len = 0; + u32 dst_pos = 0; + + vm::var utf32_tmp = vm::make_var(0); + + for (u32 src_pos = 0; src_pos < *src_len;) + { + const s32 utf16_len = UTF16toUTF32(src + src_pos, utf32_tmp); + + if (utf16_len == 0) + { + *src_len -= src_pos; + *dst_len = len; + return SRCIllegal; + } + + len++; + + if (dst) + { + if (*dst_len < len) + { + *src_len -= src_pos; + *dst_len = dst_pos; + return DSTExhausted; + } + + dst[dst_pos++] = *utf32_tmp; + } + + src_pos += utf16_len; + } + + *dst_len = len; + return ConversionOK; } s32 UTF8toEUCKR() @@ -544,10 +774,51 @@ s32 UTF8toEUCKR() return 0; } -s32 UTF16toUTF8() +s32 UTF16toUTF8(vm::cptr src, vm::ptr dst, vm::ptr dst_len) { - cellL10n.todo("UTF16toUTF8()"); - return 0; + cellL10n.notice("UTF16toUTF8(src=*0x%x, dst=*0x%x, dst_len=*0x%x)", src, dst, dst_len); + + ensure(src && dst && dst_len); // Not really checked + + const u64 utf16_long = src[0]; + vm::cptr src_raw = vm::cast(src.addr()); + + if ((src[0] & UTF16_SURROGATES_MASK1) == UTF16_HIGH_SURROGATES) + { + if (((src[0] & UTF16_SURROGATES_MASK2) == UTF16_HIGH_SURROGATES) && ((src[1] & UTF16_SURROGATES_MASK2) == UTF16_LOW_SURROGATES)) + { + const s64 lVar2 = (static_cast(src[0] >> 6) & 0xf) + 1; + dst[0] = static_cast(static_cast(lVar2 << 0x20) >> 0x22) | 0xf0; + dst[1] = (static_cast(lVar2) * '\x10' & 0x30U) | (static_cast(src[0] >> 2) & 0xf) | 0x80; + dst[2] = (static_cast(src[1] >> 6) & 0xf) | (static_cast(src[0]) & 3) << 4 | 0x80; + dst[3] = (static_cast(src_raw[3]) & 0x3f) | 0x80; + *dst_len = 4; + return 2; + } + + return 0; + } + + if (0x7ff < utf16_long) + { + dst[0] = static_cast((utf16_long << 0x20) >> 0x2c) | 0xe0; + dst[1] = (static_cast(src[0] >> 6) & 0x3f) | 0x80; + dst[2] = (static_cast(src_raw[1]) & 0x3f) | 0x80; + *dst_len = 3; + return 1; + } + + if (utf16_long < 0x80) + { + dst[0] = static_cast(src[0]); + *dst_len = 1; + return 1; + } + + dst[0] = static_cast((utf16_long << 0x20) >> 0x26) | 0xc0; + dst[1] = (static_cast(src_raw[1]) & 0x3f) | 0x80; + *dst_len = 2; + return 1; } s32 ARIBstoUTF8s() @@ -556,7 +827,7 @@ s32 ARIBstoUTF8s() return ConversionOK; } -s32 SJISstoUTF8s(vm::cptr src, vm::cptr src_len, vm::ptr dst, vm::ptr dst_len) +s32 SJISstoUTF8s(vm::cptr src, vm::cptr src_len, vm::ptr dst, vm::ptr dst_len) { cellL10n.warning("SJISstoUTF8s(src=*0x%x, src_len=*0x%x, dst=*0x%x, dst_len=*0x%x)", src, src_len, dst, dst_len); return _L10nConvertStr(L10N_CODEPAGE_932, src, src_len, L10N_UTF8, dst, dst_len); @@ -646,10 +917,51 @@ s32 UTF8stoBIG5s() return ConversionOK; } -s32 UTF16stoUCS2s(vm::cptr src, vm::cptr src_len, vm::ptr dst, vm::ptr dst_len) +s32 UTF16stoUCS2s(vm::cptr src, vm::ptr src_len, vm::ptr dst, vm::ptr dst_len) { - cellL10n.warning("UTF16stoUCS2s(src=*0x%x, src_len=*0x%x, dst=*0x%x, dst_len=*0x%x)", src, src_len, dst, dst_len); - return _L10nConvertStr(L10N_UTF16, src, src_len, L10N_UCS2, dst, dst_len); + cellL10n.notice("UTF16stoUCS2s(src=*0x%x, src_len=*0x%x, dst=*0x%x, dst_len=*0x%x)", src, src_len, dst, dst_len); + + ensure(src_len && dst_len); // Not really checked + + if (*src_len == 0u) + { + *dst_len = 0; + return ConversionOK; + } + + ensure(src); // Not really checked + + u32 len = 0; + u32 dst_pos = 0; + + for (u32 src_pos = 0; src_pos < *src_len; src_pos++) + { + const u16 utf16 = src[src_pos]; + + if ((utf16 & UTF16_SURROGATES_MASK1) == UTF16_HIGH_SURROGATES) + { + *src_len -= src_pos; + *dst_len = src_pos; + return SRCIllegal; + } + + len++; + + if (dst) + { + if (*dst_len < len) + { + *src_len -= src_pos; + *dst_len = src_pos; + return DSTExhausted; + } + + dst[dst_pos++] = utf16; + } + } + + *dst_len = len; + return ConversionOK; } s32 UCS2stoGB18030s() @@ -738,9 +1050,71 @@ s32 JISstoSJISs(vm::cptr src, vm::cptr src_len, vm::ptr dst, vm::pt return 0; } -s32 UTF8toUTF16() +s32 UTF8toUTF16(vm::cptr src, vm::ptr dst, vm::ptr dst_len) { - cellL10n.todo("UTF8toUTF16()"); + cellL10n.notice("UTF8toUTF16(src=*0x%x, dst=*0x%x, dst_len=*0x%x)", src, dst, dst_len); + + ensure(src && dst && dst_len); // Not really checked + + u64 longval = src[0]; + + if ((src[0] & 0xf8) == 0xf0) + { + if ((src[1] & 0xc0) == 0x80) + { + if ((src[2] & 0xc0) == 0x80 && (src[3] & 0xc0) == 0x80) + { + longval = (longval & 7) << 2 | (static_cast(src[1] >> 4) & 3); + + if (((longval - 1) & 0xffff) < 0x10) + { + dst[0] = (src[1] & 0xf) << 2 | (src[2] >> 4 & 3) | static_cast(((longval - 1) & 0xffffffff) << 6) | UTF16_HIGH_SURROGATES; + dst[1] = (src[2] & 0xf) << 6 | (src[3] & 0x3f) | UTF16_LOW_SURROGATES; + *dst_len = 2; + return 4; + } + } + } + } + else + { + if ((src[0] & 0xf0) != 0xe0) + { + if (((src[0] & 0xe0) == 0xc0) && (0xc1 < longval)) + { + if ((src[1] & 0xc0) != 0x80) + { + return 0; + } + + dst[0] = (src[0] & 0x1f) << 6 | (src[1] & 0x3f); + *dst_len = 1; + return 2; + } + + if (static_cast(src[0]) < '\0') + { + return 0; + } + + dst[0] = static_cast(src[0]); + *dst_len = 1; + return 1; + } + + if ((src[1] & 0xc0) == 0x80 && (src[2] & 0xc0) == 0x80) + { + longval = (static_cast(src[1]) & 0x3f) << 6 | (longval & 0xf) << 0xc | (static_cast(src[2]) & 0x3f); + + if ((0x7ff < longval && ((static_cast(longval) & UTF16_SURROGATES_MASK1) != UTF16_HIGH_SURROGATES))) + { + dst[0] = static_cast(longval); + *dst_len = 1; + return 3; + } + } + } + return 0; } @@ -762,9 +1136,20 @@ s32 SjisHan2Zen() return ConversionOK; } -s32 UCS2toUTF16() +s32 UCS2toUTF16(u16 ucs2, vm::ptr utf16) { - cellL10n.todo("UCS2toUTF16()"); + cellL10n.notice("UCS2toUTF16(ucs2=0x%x, utf16=*0x%x)", ucs2, utf16); + + const s32 sucs2 = static_cast(ucs2); + + if ((sucs2 & UTF16_SURROGATES_MASK1) != UTF16_HIGH_SURROGATES) + { + ensure(!!utf16); // Not actually checked + + *utf16 = ucs2; + return 1; + } + return 0; } @@ -774,9 +1159,40 @@ s32 UCS2toMSJIS() return 0; } -s32 sjis2kuten() +u16 sjis2kuten(u16 c) { - cellL10n.todo("sjis2kuten()"); + cellL10n.notice("sjis2kuten(c=0x%x)", c); + + u64 v0 = static_cast(static_cast(static_cast(c))) >> 8 & 0xff; + u64 v1 = v0 - 0x81; + + if (((v1 & 0xffff) >= 0x7c) || (0x3f >= ((v0 - 0xa0) & 0xffff))) + { + return 0; + } + + const u64 v2 = static_cast(static_cast(c)) & 0xff; + + if (0x3f < v2 && (v2 < 0xfd && (static_cast(v2) != 0x7f))) + { + if (0x9f < v0) + { + v1 = v0 - 0xc1; + } + + u16 v3 = static_cast(v2) - 0x9e; + v0 = (v1 & 0x7fffffff) * 2 + 2; + + if (v2 < 0x9f) + { + const s16 v4 = v2 < 0x7f ? 0x1f : 0x20; + v3 = (static_cast(v2) - v4) - 0x20; + v0 = (v1 & 0x7fffffff) * 2 + 1; + } + + return static_cast((v0 & 0xffffffff) << 8) | v3; + } + return 0; } @@ -786,9 +1202,18 @@ s32 UCS2toUHC() return 0; } -s32 UTF32toUCS2() +s32 UTF32toUCS2(u32 src, vm::ptr dst) { - cellL10n.todo("UTF32toUCS2()"); + cellL10n.notice("UTF32toUCS2(src=0x%x, dst=*0x%x)", src, dst); + + if ((src < 0x10000) && (0x7ff < src - UTF16_HIGH_SURROGATES)) + { + ensure(!!dst); // Not really checked + + *dst = static_cast(src); + return 1; + } + return 0; } @@ -810,15 +1235,66 @@ s32 UCS2stoEUCJPs() return ConversionOK; } -s32 UTF16toUCS2() +s32 UTF16toUCS2(vm::cptr src, vm::ptr dst) { - cellL10n.todo("UTF16toUCS2()"); + cellL10n.notice("UTF16toUCS2(src=*0x%x, dst=*0x%x)", src, dst); + + ensure(!!src); // Not really checked + + if ((*src & UTF16_SURROGATES_MASK1) != UTF16_HIGH_SURROGATES) + { + ensure(!!dst); // Not really checked + *dst = *src; + return 1; + } + return 0; } -s32 UCS2stoUTF16s(vm::cptr src, vm::cptr src_len, vm::ptr dst, vm::ptr dst_len) +s32 UCS2stoUTF16s(vm::cptr src, vm::ptr src_len, vm::ptr dst, vm::ptr dst_len) { - cellL10n.todo("UCS2stoUTF16s(src=*0x%x, src_len=*0x%x, dst=*0x%x, dst_len=*0x%x)", src, src_len, dst, dst_len); + cellL10n.notice("UCS2stoUTF16s(src=*0x%x, src_len=*0x%x, dst=*0x%x, dst_len=*0x%x)", src, src_len, dst, dst_len); + + ensure(src_len && dst_len); // Not really checked + + if (*src_len == 0u) + { + *dst_len = 0; + return ConversionOK; + } + + ensure(src); // Not really checked + + u32 len = 0; + u32 dst_pos = 0; + + for (u32 src_pos = 0; src_pos < *src_len; src_pos++) + { + const u16 ucs2 = src[src_pos]; + + if ((ucs2 & UTF16_SURROGATES_MASK1) == UTF16_HIGH_SURROGATES) + { + *src_len -= src_pos; + *dst_len = src_pos; + return SRCIllegal; + } + + len++; + + if (dst) + { + if (*dst_len < len) + { + *src_len -= src_pos; + *dst_len = src_pos; + return DSTExhausted; + } + + dst[dst_pos++] = ucs2; + } + } + + *dst_len = len; return ConversionOK; } @@ -828,10 +1304,86 @@ s32 UCS2stoEUCCNs() return ConversionOK; } -s32 SBCSstoUTF8s(vm::cptr src, vm::cptr src_len, vm::ptr dst, vm::ptr dst_len, s32 enc) +s32 SBCSstoUTF8s(vm::cptr src, vm::ptr src_len, vm::ptr dst, vm::ptr dst_len, u32 code_page) { - cellL10n.warning("SBCSstoUTF8s(src=*0x%x, src_len=*0x%x, dst=*0x%x, dst_len=*0x%x, enc=*0x%x)", src, src_len, dst, dst_len, enc); - return _L10nConvertStr(enc, src, src_len, L10N_UTF8, dst, dst_len); // Might not work in some scenarios + cellL10n.notice("SBCSstoUTF8s(src=*0x%x, src_len=*0x%x, dst=*0x%x, dst_len=*0x%x, code_page=0x%x)", src, src_len, dst, dst_len, code_page); + + HostCode code = 0; + if ((code_page >= _L10N_CODE_) || !_L10nCodeParse(code_page, code)) + { + return ConverterUnknown; + } + + ensure(src_len && dst_len); // Not really checked + + if (*src_len == 0u) + { + *dst_len = 0; + return ConversionOK; + } + + ensure(src); // Not really checked + + u32 len = 0; + u32 dst_pos = 0; + + for (u32 src_pos = 0; src_pos < *src_len; src_pos++) + { + u8 src_val = src[src_pos]; + u64 longval = static_cast(src_val); + s32 utf8_len = 1; + + if (static_cast(src_val) < '\0') + { + u8 dst_tmp[4] = {}; + s32 dst_len_tmp = 4; + + const s32 res = _ConvertStr(code_page, &src_val, 1, L10N_UTF8, &dst_tmp, &dst_len_tmp, false); + + if (res != ConversionOK) + { + *src_len -= src_pos; + *dst_len = len; + return SRCIllegal; + } + + longval = *reinterpret_cast(dst_tmp); + utf8_len = dst_len_tmp; + } + + len += utf8_len; + + if (dst) + { + if (*dst_len < len) + { + *src_len -= src_pos; + *dst_len = len - utf8_len; + return DSTExhausted; + } + + src_val = static_cast(longval); + + if (utf8_len == 3) + { + dst[dst_pos++] = static_cast((longval << 0x20) >> 0x2c) | 0xe0; + dst[dst_pos++] = (static_cast(longval >> 6) & 0x3f) | 0x80; + dst[dst_pos++] = (src_val & 0x3f) | 0x80; + } + else if (utf8_len == 1) + { + dst[dst_pos++] = src_val; + } + else + { + dst[dst_pos++] = static_cast(longval >> 6) | 0xc0; + dst[dst_pos++] = (src_val & 0x3f) | 0x80; + } + } + } + + *dst_len = len; + return ConversionOK; } s32 SJISstoJISs(vm::cptr src, vm::cptr src_len, vm::ptr dst, vm::ptr dst_len) @@ -840,16 +1392,112 @@ s32 SJISstoJISs(vm::cptr src, vm::cptr src_len, vm::ptr dst, vm::pt return 0; } -s32 SBCStoUTF8() +s32 SBCStoUTF8(u8 src, vm::ptr dst, u32 code_page) { - cellL10n.todo("SBCStoUTF8()"); - return 0; + cellL10n.notice("SBCStoUTF8(src=0x%x, dst=*0x%x, code_page=0x%x)", src, *dst, code_page); + + HostCode code = 0; + if ((code_page >= _L10N_CODE_) || !_L10nCodeParse(code_page, code)) + { + return -1; + } + + ensure(!!dst); // Not really checked + + if (static_cast(src) >= 0) + { + *dst = src; + return 1; + } + + u8 dst_tmp = 0; + s32 dst_len_tmp = 1; + + const s32 res = _ConvertStr(L10N_UTF8, &src, 1, code_page, &dst_tmp, &dst_len_tmp, false); + if (res != ConversionOK) + { + return 0; + } + + const u64 longval = static_cast(dst_tmp); + const u8 val = static_cast(dst_tmp) & 0x3f; + + if (longval < 0x800) + { + dst[0] = static_cast((longval << 0x20) >> 0x26) | 0xc0; + dst[1] = val | 0x80; + return 2; + } + + dst[0] = static_cast((longval << 0x20) >> 0x2c) | 0xe0; + dst[1] = (static_cast(static_cast(dst_tmp) >> 6) & 0x3f) | 0x80; + dst[2] = val | 0x80; + return 3; } -s32 UTF8toUTF32() +s32 UTF8toUTF32(vm::cptr src, vm::ptr dst) { - cellL10n.todo("UTF8toUTF32()"); - return 0; + cellL10n.notice("UTF8toUTF32(src=*0x%x, dst=*0x%x)", src, dst); + + ensure(src && dst); // Not really checked + + u64 longval = src[0]; + + if ((src[0] & 0xf8) == 0xf0) + { + if ((src[1] & 0xc0) != 0x80 || + (src[2] & 0xc0) != 0x80 || + (src[3] & 0xc0) != 0x80) + { + return 0; + } + + longval = (static_cast(src[2]) & 0x3f) << 6 | (longval & 7) << 0x12 | (static_cast(src[1]) & 0x3f) << 0xc | (static_cast(src[3]) & 0x3f); + if (0xfffff < ((longval - 0x10000) & 0xffffffff)) + { + return 0; + } + + *dst = static_cast(longval); + return 4; + } + + if ((src[0] & 0xf0) == 0xe0) + { + if ((src[1] & 0xc0) != 0x80 || + (src[2] & 0xc0) != 0x80) + { + return 0; + } + + longval = (static_cast(src[1]) & 0x3f) << 6 | (longval & 0xf) << 0xc | (static_cast(src[2]) & 0x3f); + if (longval < 0x800 || ((longval - UTF16_HIGH_SURROGATES) & 0xffffffff) < 0x800) + { + return 0; + } + + *dst = static_cast(longval); + return 3; + } + + if (((src[0] & 0xe0) == 0xc0) && (0xc1 < longval)) + { + if ((src[1] & 0xc0) != 0x80) + { + return 0; + } + + *dst = (src[0] & 0x1f) << 6 | (src[1] & 0x3f); + return 2; + } + + if (static_cast(src[0]) < '\0') + { + return 0; + } + + *dst = static_cast(src[0]); + return 1; } s32 jstrchk(vm::cptr jstr) @@ -890,9 +1538,57 @@ s32 EucJpZen2Han() return ConversionOK; } -s32 UTF32stoUTF16s(vm::cptr src, vm::cptr src_len, vm::ptr dst, vm::ptr dst_len) +s32 UTF32toUTF16(u32 src, vm::ptr dst); + +s32 UTF32stoUTF16s(vm::cptr src, vm::ptr src_len, vm::ptr dst, vm::ptr dst_len) { - cellL10n.todo("UTF32stoUTF16s(src=*0x%x, src_len=*0x%x, dst=*0x%x, dst_len=*0x%x)", src, src_len, dst, dst_len); + cellL10n.notice("UTF32stoUTF16s(src=*0x%x, src_len=*0x%x, dst=*0x%x, dst_len=*0x%x)", src, src_len, dst, dst_len); + + ensure(src_len && dst_len); // Not really checked + + if (*src_len == 0u) + { + *dst_len = 0; + return ConversionOK; + } + + ensure(src); // Not really checked + + u32 len = 0; + u32 dst_pos = 0; + + auto tmp = vm::make_var[2]>({0, 0}); + const vm::ptr utf16_tmp = vm::cast(tmp.addr()); + + for (u32 src_pos = 0; src_pos < *src_len; src_pos++) + { + const s32 utf16_len = UTF32toUTF16(src[src_pos], utf16_tmp); + if (utf16_len == 0) + { + *src_len -= src_pos; + *dst_len = len; + return SRCIllegal; + } + + len += utf16_len; + + if (dst) + { + if (*dst_len < len) + { + *src_len -= src_pos; + *dst_len = len - utf16_len; + return DSTExhausted; + } + + for (s32 i = 0; i < utf16_len; i++) + { + dst[dst_pos++] = utf16_tmp[i]; + } + } + } + + *dst_len = len; return ConversionOK; } @@ -926,9 +1622,54 @@ s32 EUCKRstoUHCs(vm::cptr src, vm::cptr src_len, vm::ptr dst, vm::p return 0; } -s32 UTF8stoUTF32s(vm::cptr src, vm::cptr src_len, vm::ptr dst, vm::ptr dst_len) +s32 UTF8stoUTF32s(vm::cptr src, vm::ptr src_len, vm::ptr dst, vm::ptr dst_len) { - cellL10n.todo("UTF8stoUTF32s(src=*0x%x, src_len=*0x%x, dst=*0x%x, dst_len=*0x%x)", src, src_len, dst, dst_len); + cellL10n.notice("UTF8stoUTF32s(src=*0x%x, src_len=*0x%x, dst=*0x%x, dst_len=*0x%x)", src, src_len, dst, dst_len); + + ensure(src_len && dst_len); // Not really checked + + if (*src_len == 0u) + { + *dst_len = 0; + return ConversionOK; + } + + ensure(src); // Not really checked + + u32 len = 0; + u32 dst_pos = 0; + + vm::var utf32_tmp = vm::make_var(0); + + for (u32 src_pos = 0; src_pos < *src_len;) + { + const s32 utf8_len = UTF8toUTF32(src + src_pos, utf32_tmp); + + if (utf8_len == 0) + { + *src_len -= src_pos; + *dst_len = len; + return SRCIllegal; + } + + len++; + + if (dst) + { + if (*dst_len < len) + { + *src_len -= src_pos; + *dst_len = dst_pos; + return DSTExhausted; + } + + dst[dst_pos++] = *utf32_tmp; + } + + src_pos += utf8_len; + } + + *dst_len = len; return ConversionOK; } @@ -950,7 +1691,7 @@ s32 UHCtoUCS2() return 0; } -s32 L10nConvertStr(s32 src_code, vm::cptr src, vm::ptr src_len, s32 dst_code, vm::ptr dst, vm::ptr dst_len) +s32 L10nConvertStr(s32 src_code, vm::cptr src, vm::ptr src_len, s32 dst_code, vm::ptr dst, vm::ptr dst_len) { cellL10n.error("L10nConvertStr(src_code=%d, src=*0x%x, src_len=*0x%x, dst_code=%d, dst=*0x%x, dst_len=*0x%x)", src_code, src, src_len, dst_code, dst, dst_len); return _L10nConvertStr(src_code, src, src_len, dst_code, dst, dst_len); @@ -968,15 +1709,83 @@ s32 UTF8toUHC() return 0; } -s32 UTF32toUTF8() +s32 UTF32toUTF8(u32 src, vm::ptr dst) { - cellL10n.todo("UTF32toUTF8()"); - return 0; + cellL10n.notice("UTF32toUTF8(src=0x%x, dst=*0x%x)", src, dst); + + const u64 utf32 = static_cast(static_cast(src)); + if (((utf32 & 0xffffffff) >= 0x110000) || (0x7ff >= ((utf32 - UTF16_HIGH_SURROGATES) & 0xffffffff))) + { + return 0; + } + + ensure(!!dst); // Not really checked + + if (0xffff < (utf32 & 0xffffffff)) + { + dst[0] = static_cast((utf32 << 0x20) >> 0x32) | 0xf0; + dst[1] = (static_cast(utf32 >> 0xc) & 0x3f) | 0x80; + dst[2] = (static_cast(utf32 >> 6) & 0x3f) | 0x80; + dst[3] = (static_cast(src) & 0x3f) | 0x80; + return 4; + } + + if ((utf32 & 0xffffffff) < 0x80) + { + dst[0] = static_cast(src); + return 1; + } + + if ((utf32 & 0xffffffff) < 0x800) + { + dst[0] = static_cast((utf32 << 0x20) >> 0x26) | 0xc0; + dst[1] = (static_cast(src) & 0x3f) | 0x80; + return 2; + } + + dst[0] = static_cast((utf32 << 0x20) >> 0x2c) | 0xe0; + dst[1] = (static_cast(utf32 >> 6) & 0x3f) | 0x80; + dst[2] = (static_cast(src) & 0x3f) | 0x80; + return 3; } -s32 sjis2eucjp() +u16 sjis2eucjp(u16 c) { - cellL10n.todo("sjis2eucjp()"); + cellL10n.notice("sjis2eucjp(c=0x%x)", c); + + u64 v0 = static_cast(static_cast(static_cast(c))) >> 8 & 0xff; + u64 v1 = v0 - 0x81; + + if (((v1 & 0xffff) >= 0x7c) || (0x3f >= ((v0 - 0xa0) & 0xffff))) + { + return 0; + } + + const u64 v2 = static_cast(static_cast(c)) & 0xff; + + if (0x3f < v2 && (v2 < 0xfd && (static_cast(v2) != 0x7f))) + { + if (0x9f < v0) + { + v1 = v0 - 0xc1; + } + + u16 v3 = static_cast(v2) - 0x7e; + v0 = (v1 & 0x7fffffff) * 2 + 0x22; + + if (v2 < 0x9f) + { + const s16 v4 = v2 < 0x7f ? 0x1f : 0x20; + v3 = static_cast(v2) - v4; + v0 = (v1 & 0x7fffffff) * 2 + 0x21; + } + + if ((v0 & 0xffff) < 0x7f) + { + return static_cast((v0 & 0xffff) << 8) | v3 | 0x8080; + } + } + return 0; } @@ -998,10 +1807,27 @@ s32 EUCKRtoUCS2() return 0; } -s32 UTF32toUTF16() +s32 UTF32toUTF16(u32 src, vm::ptr dst) { - cellL10n.todo("UTF32toUTF16()"); - return 0; + cellL10n.notice("UTF32toUTF16(src=0x%x, dst=*0x%x)", src, dst); + + const u64 utf32 = static_cast(static_cast(src)); + if (((utf32 & 0xffffffff) >= 0x110000) || (0x7ff >= ((utf32 - UTF16_HIGH_SURROGATES) & 0xffffffff))) + { + return 0; + } + + ensure(!!dst); // Not really checked + + if (0xffff < (utf32 & 0xffffffff)) + { + dst[0] = static_cast(((utf32 - 0x10000) << 0x20) >> 0x2a) | UTF16_HIGH_SURROGATES; + dst[1] = (static_cast(src) & 0x3ff) | UTF16_LOW_SURROGATES; + return 2; + } + + dst[0] = static_cast(src); + return 1; } s32 EUCCNstoUCS2s() @@ -1010,9 +1836,67 @@ s32 EUCCNstoUCS2s() return ConversionOK; } -s32 SBCSstoUCS2s() +s32 SBCSstoUCS2s(vm::cptr src, vm::ptr src_len, vm::ptr dst, vm::ptr dst_len, u32 code_page) { - cellL10n.todo("SBCSstoUCS2s()"); + cellL10n.notice("SBCSstoUCS2s(src=*0x%x, src_len=*0x%x, dst=*0x%x, dst_len=*0x%x, code_page=0x%x)", src, src_len, dst, dst_len, code_page); + + HostCode code = 0; + if ((code_page >= _L10N_CODE_) || !_L10nCodeParse(code_page, code)) + { + return ConverterUnknown; + } + + ensure(src_len && dst_len); // Not really checked + + if (*src_len == 0u) + { + *dst_len = 0; + return ConversionOK; + } + + ensure(src); // Not really checked + + u32 len = 0; + u32 dst_pos = 0; + + for (u32 src_pos = 0; src_pos < *src_len; src_pos++) + { + const u8 src_val = src[src_pos]; + u16 val = static_cast(src_val); + + if (static_cast(src_val) < '\0') + { + u16 dst_tmp = 0; + s32 dst_len_tmp = 2; + + const s32 res = _ConvertStr(code_page, &src_val, 1, L10N_UCS2, &dst_tmp, &dst_len_tmp, false); + + if (res != ConversionOK) + { + *src_len -= src_pos; + *dst_len = dst_pos; + return SRCIllegal; + } + + val = dst_tmp; + } + + len++; + + if (dst) + { + if (*dst_len < len) + { + *src_len -= src_pos; + *dst_len = dst_pos; + return DSTExhausted; + } + + dst[dst_pos++] = val; + } + } + + *dst_len = len; return ConversionOK; } @@ -1046,23 +1930,38 @@ s32 UCS2toGBK() return 0; } -s32 UTF16toUTF32() +s32 UTF16toUTF32(vm::cptr src, vm::ptr dst) { - cellL10n.todo("UTF16toUTF32()"); + cellL10n.notice("UTF16toUTF32(src=*0x%x, dst=*0x%x)", src, dst); + + ensure(src && dst); // Not really checked + + if ((src[0] & UTF16_SURROGATES_MASK1) != UTF16_HIGH_SURROGATES) + { + *dst = static_cast(src[0]); + return 1; + } + + if (((src[0] & UTF16_SURROGATES_MASK2) == (src[0] & UTF16_SURROGATES_MASK1)) && ((src[1] & UTF16_SURROGATES_MASK2) == UTF16_LOW_SURROGATES)) + { + *dst = ((src[0] & 0x3ff) * 0x400 + 0x10000) | (src[1] & 0x3ff); + return 2; + } + return 0; } -s32 l10n_convert_str(s32 cd, vm::cptr src, vm::ptr src_len, vm::ptr dst, vm::ptr dst_len) +s32 l10n_convert_str(s32 cd, vm::cptr src, vm::cptr src_len, vm::ptr dst, vm::ptr dst_len) { cellL10n.warning("l10n_convert_str(cd=%d, src=*0x%x, src_len=*0x%x, dst=*0x%x, dst_len=*0x%x)", cd, src, src_len, dst, dst_len); - s32 src_code = cd >> 16; - s32 dst_code = cd & 0xffff; + const s32 src_code = cd >> 16; + const s32 dst_code = cd & 0xffff; return _L10nConvertStr(src_code, src, src_len, dst_code, dst, dst_len); } -s32 EUCJPstoJISs(vm::cptr src, vm::cptr src_len, vm::ptr dst, vm::ptr dst_len) +s32 EUCJPstoJISs(vm::cptr src, vm::cptr src_len, vm::ptr dst, vm::ptr dst_len) { cellL10n.warning("EUCJPstoJISs(src=*0x%x, src_len=*0x%x, dst=*0x%x, dst_len=*0x%x)", src, src_len, dst, dst_len); return _L10nConvertStr(L10N_EUC_JP, src, src_len, L10N_ISO_2022_JP, dst, dst_len); @@ -1092,9 +1991,35 @@ s32 isEucJpKigou() return 0; } -s32 UCS2toUTF8() +s32 UCS2toUTF8(u16 ucs2, vm::ptr utf8) { - cellL10n.todo("UCS2toUTF8()"); + cellL10n.notice("UCS2toUTF8(ucs2=0x%x, utf8=*0x%x)", ucs2, utf8); + + const u64 val = static_cast(ucs2) & 0xffff; + + if ((static_cast(val) & UTF16_SURROGATES_MASK1) != UTF16_HIGH_SURROGATES) + { + ensure(!!utf8); // Not really checked + + if (val < 0x80) + { + utf8[0] = static_cast(ucs2); + return 1; + } + + if (val < 0x800) + { + utf8[0] = static_cast((val << 0x20) >> 0x26) | 0xc0; + utf8[1] = (static_cast(ucs2) & 0x3f) | 0x80; + return 2; + } + + utf8[0] = static_cast((val << 0x20) >> 0x2c) | 0xe0; + utf8[1] = (static_cast(val >> 6) & 0x3f) | 0x80; + utf8[2] = (static_cast(ucs2) & 0x3f) | 0x80; + return 3; + } + return 0; } @@ -1128,9 +2053,24 @@ s32 kuten2sjis() return 0; } -s32 UTF8toSBCS() +s32 UTF8toSBCS(vm::cptr src, vm::ptr dst, u32 code_page) { - cellL10n.todo("UTF8toSBCS()"); + cellL10n.notice("UTF8toSBCS(src=*0x%x, dst=*0x%x, code_page=0x%x)", src, dst, code_page); + + vm::var ucs2_tmp = vm::make_var(0); + + const s32 utf8_len = UTF8toUCS2(src, ucs2_tmp); + if (utf8_len != 0) + { + const s32 len = UCS2toSBCS(*ucs2_tmp, dst, code_page); + if (1 < len + 1U) + { + return utf8_len; + } + + return len; + } + return 0; } @@ -1170,10 +2110,35 @@ s32 UCS2toEUCKR() return 0; } -s32 SBCStoUCS2() +s32 SBCStoUCS2(u8 src, vm::ptr dst, u32 code_page) { - cellL10n.todo("SBCStoUCS2()"); - return 0; + cellL10n.notice("SBCStoUCS2(src=0x%x, dst=*0x%x, code_page=0x%x)", src, dst, code_page); + + HostCode code = 0; + if ((code_page >= _L10N_CODE_) || !_L10nCodeParse(code_page, code)) + { + return -1; + } + + ensure(!!dst); // Not really checked + + if (static_cast(src) >= 0) + { + *dst = static_cast(static_cast(src)) & 0xff; + return 1; + } + + u16 dst_tmp = 0; + s32 dst_len_tmp = sizeof(u16); + + const s32 res = _ConvertStr(code_page, &src, 1, L10N_UCS2, &dst_tmp, &dst_len_tmp, false); + if (res != ConversionOK) + { + return 0; + } + + *dst = dst_tmp; + return 1; } s32 MSJISstoUCS2s() @@ -1186,6 +2151,13 @@ s32 l10n_get_converter(u32 src_code, u32 dst_code) { cellL10n.warning("l10n_get_converter(src_code=%d, dst_code=%d)", src_code, dst_code); return (src_code << 16) | dst_code; + + if (_L10N_CODE_ <= src_code || _L10N_CODE_ <= dst_code) + { + return 0xffffffff; + } + + return (src_code << 16) | dst_code; } s32 GB18030stoUTF8s() @@ -1200,9 +2172,50 @@ s32 SJISstoEUCJPs(vm::cptr src, vm::cptr src_len, vm::ptr dst, vm:: return 0; } -s32 UTF32stoUCS2s(vm::cptr src, vm::cptr src_len, vm::ptr dst, vm::ptr dst_len) +s32 UTF32stoUCS2s(vm::cptr src, vm::ptr src_len, vm::ptr dst, vm::ptr dst_len) { - cellL10n.todo("UTF32stoUCS2s(src=*0x%x, src_len=*0x%x, dst=*0x%x, dst_len=*0x%x)", src, src_len, dst, dst_len); + cellL10n.notice("UTF32stoUCS2s(src=*0x%x, src_len=*0x%x, dst=*0x%x, dst_len=*0x%x)", src, src_len, dst, dst_len); + + ensure(src_len && dst_len); // Not really checked + + if (*src_len == 0u) + { + *dst_len = 0; + return ConversionOK; + } + + ensure(src); // Not really checked + + u32 len = 0; + u32 dst_pos = 0; + + for (u32 src_pos = 0; src_pos < *src_len; src_pos++) + { + const u32 utf32 = src[src_pos]; + + if (utf32 >= 0x10000 || (0x7ff >= utf32 - UTF16_HIGH_SURROGATES)) + { + *src_len -= src_pos; + *dst_len = src_pos; + return SRCIllegal; + } + + len++; + + if (dst) + { + if (*dst_len < len) + { + *src_len -= src_pos; + *dst_len = src_pos; + return DSTExhausted; + } + + dst[dst_pos++] = static_cast(utf32); + } + } + + *dst_len = len; return ConversionOK; } @@ -1218,9 +2231,86 @@ s32 EUCCNtoUCS2() return CELL_OK; } -s32 UTF8stoSBCSs() +s32 UTF8stoSBCSs(vm::cptr src, vm::ptr src_len, vm::ptr dst, vm::ptr dst_len, u32 code_page) { - cellL10n.todo("UTF8stoSBCSs()"); + cellL10n.notice("UTF8stoSBCSs(src=*0x%x, src_len=*0x%x, dst=*0x%x, dst_len=*0x%x, code_page=0x%x)", src, src_len, dst, dst_len, code_page); + + HostCode code = 0; + if ((code_page >= _L10N_CODE_) || !_L10nCodeParse(code_page, code)) + { + return ConverterUnknown; + } + + ensure(src_len && dst_len); // Not really checked + + if (*src_len == 0u) + { + *dst_len = 0; + return ConversionOK; + } + + ensure(src); // Not really checked + + u32 len = 0; + u32 dst_pos = 0; + + vm::var ucs2_tmp = vm::make_var(0); + + for (u32 src_pos = 0; src_pos < *src_len;) + { + const s32 utf8_len = UTF8toUCS2(src + src_pos, ucs2_tmp); + if (utf8_len == 0) + { + *src_len -= src_pos; + *dst_len = len; + return SRCIllegal; + } + + u16 ucs2 = *ucs2_tmp; + + if ((*src_len < (utf8_len + src_pos)) || (0xfffd < ucs2)) + { + *src_len -= src_pos; + *dst_len = len; + return SRCIllegal; + } + + if (0x7f < ucs2) + { + const u8 src_tmp = src[src_pos]; + u8 dst_tmp = 0; + s32 dst_len_tmp = 1; + + const s32 res = _ConvertStr(L10N_UTF8, &src_tmp, 1, code_page, &dst_tmp, &dst_len_tmp, false); + + if (res != ConversionOK) + { + *src_len -= src_pos; + *dst_len = dst_pos; + return SRCIllegal; + } + + ucs2 = dst_tmp; + } + + len++; + + if (dst) + { + if (*dst_len < len) + { + *src_len -= src_pos; + *dst_len = dst_pos; + return DSTExhausted; + } + + dst[dst_pos++] = static_cast(ucs2); + } + + src_pos += utf8_len; + } + + *dst_len = len; return ConversionOK; } @@ -1254,45 +2344,61 @@ s32 UTF8toBIG5() return 0; } -s32 UTF16stoUTF8s(vm::cptr utf16, vm::ref utf16_len, vm::ptr utf8, vm::ref utf8_len) +s32 UTF16stoUTF8s(vm::cptr src, vm::ptr src_len, vm::ptr dst, vm::ptr dst_len) { - cellL10n.error("UTF16stoUTF8s(utf16=*0x%x, utf16_len=*0x%x, utf8=*0x%x, utf8_len=*0x%x)", utf16, utf16_len.addr(), utf8, utf8_len.addr()); + cellL10n.notice("UTF16stoUTF8s(src=*0x%x, src_len=*0x%x, dst=*0x%x, dst_len=*0x%x)", src, src_len, dst, dst_len); - const u32 max_len = utf8_len; utf8_len = 0; + ensure(src_len && dst_len); // Not really checked - for (u32 i = 0, len = 0; i < static_cast(utf16_len); i++, utf8_len = len) + if (*src_len == 0u) { - const u16 ch = utf16[i]; + *dst_len = 0; + return ConversionOK; + } - // increase required length (TODO) - len = len + 1; + ensure(src); // Not really checked - // validate character (TODO) - //if () - //{ - // utf16_len -= i; - // return SRCIllegal; - //} + u32 len = 0; + u32 dst_pos = 0; - if (utf8) + auto tmp = vm::make_var[4]>({0, 0, 0, 0}); + const vm::ptr utf8_tmp = vm::cast(tmp.addr()); + vm::var utf8_len_tmp = vm::make_var(0); + + for (u32 src_pos = 0; src_pos < *src_len;) + { + *utf8_len_tmp = 4; + const s32 utf16_len = UTF16toUTF8(src + src_pos, utf8_tmp, utf8_len_tmp); + + if (utf16_len == 0) { - if (len > max_len) + *src_len -= src_pos; + *dst_len = len; + return SRCIllegal; + } + + const u32 utf8_len = *utf8_len_tmp; + len += utf8_len; + + if (dst) + { + if (*dst_len < len) { - utf16_len -= i; + *src_len -= src_pos; + *dst_len = len - utf8_len; return DSTExhausted; } - if (ch <= 0x7f) + for (u32 i = 0; i < utf8_len; i++) { - *utf8++ = static_cast(ch); - } - else - { - *utf8++ = '?'; // TODO + dst[dst_pos++] = utf8_tmp[i]; } } + + src_pos += utf16_len; } + *dst_len = len; return ConversionOK; } @@ -1308,7 +2414,7 @@ s32 GB18030toUTF8() return 0; } -s32 UTF8toSJIS(u8 ch, vm::ptr dst, vm::ptr dst_len) // Doesn't work backwards +s32 UTF8toSJIS(u8 ch, vm::ptr dst, vm::ptr dst_len) // Doesn't work backwards { cellL10n.warning("UTF8toSJIS(ch=%d, dst=*0x%x, dst_len=*0x%x)", ch, dst, dst_len); return _L10nConvertChar(L10N_UTF8, &ch, sizeof(ch), L10N_CODEPAGE_932, dst, dst_len); @@ -1320,15 +2426,122 @@ s32 ARIBstoUCS2s() return ConversionOK; } -s32 UCS2stoUTF32s(vm::cptr src, vm::cptr src_len, vm::ptr dst, vm::ptr dst_len) +s32 UCS2stoUTF32s(vm::cptr src, vm::ptr src_len, vm::ptr dst, vm::ptr dst_len) { - cellL10n.todo("UCS2stoUTF32s(src=*0x%x, src_len=*0x%x, dst=*0x%x, dst_len=*0x%x)", src, src_len, dst, dst_len); + cellL10n.notice("UCS2stoUTF32s(src=*0x%x, src_len=*0x%x, dst=*0x%x, dst_len=*0x%x)", src, src_len, dst, dst_len); + + ensure(src_len && dst_len); // Not really checked + + if (*src_len == 0u) + { + *dst_len = 0; + return ConversionOK; + } + + ensure(src); // Not really checked + + u32 len = 0; + u32 dst_pos = 0; + + for (u32 src_pos = 0; src_pos < *src_len; src_pos++) + { + const u16 ucs2 = src[src_pos]; + + if ((ucs2 & UTF16_SURROGATES_MASK1) == UTF16_HIGH_SURROGATES) + { + *src_len -= src_pos; + *dst_len = src_pos; + return SRCIllegal; + } + + len++; + + if (dst) + { + if (*dst_len < len) + { + *src_len -= src_pos; + *dst_len = src_pos; + return DSTExhausted; + } + + dst[dst_pos++] = static_cast(ucs2); + } + } + + *dst_len = len; return ConversionOK; } -s32 UCS2stoSBCSs() +s32 UCS2stoSBCSs(vm::cptr src, vm::ptr src_len, vm::ptr dst, vm::ptr dst_len, u32 code_page) { - cellL10n.todo("UCS2stoSBCSs()"); + cellL10n.notice("UCS2stoSBCSs(src=*0x%x, src_len=*0x%x, dst=*0x%x, dst_len=*0x%x, code_page=*0x%x)", src, src_len, dst, dst_len, code_page); + + HostCode code = 0; + if ((code_page >= _L10N_CODE_) || !_L10nCodeParse(code_page, code)) + { + return ConverterUnknown; + } + + ensure(src_len && dst_len); // Not really checked + + if (*src_len == 0u) + { + *dst_len = 0; + return ConversionOK; + } + + ensure(src); // Not really checked + + u32 len = 0; + u32 dst_pos = 0; + + for (u32 src_pos = 0; src_pos < *src_len; src_pos++) + { + const s16 ucs2 = src[src_pos]; + + if (ucs2 >= 0xfffe) + { + *src_len -= src_pos; + *dst_len = src_pos; + return SRCIllegal; + } + + u8 val = static_cast(ucs2); + + if (0x7f < ucs2) + { + const u16 src_tmp = src[src_pos]; + u8 dst_tmp = 0; + s32 dst_len_tmp = 1; + + const s32 res = _ConvertStr(L10N_UCS2, &src_tmp, sizeof(u16), code_page, &dst_tmp, &dst_len_tmp, false); + + if (res != ConversionOK) + { + *src_len -= src_pos; + *dst_len = dst_pos; + return SRCIllegal; + } + + val = dst_tmp; + } + + len++; + + if (dst) + { + if (*dst_len < len) + { + *src_len -= src_pos; + *dst_len = src_pos; + return DSTExhausted; + } + + dst[dst_pos++] = val; + } + } + return ConversionOK; } @@ -1350,13 +2563,64 @@ s32 SJIStoEUCJP() return 0; } -s32 UTF8stoUTF16s(vm::cptr src, vm::cptr src_len, vm::ptr dst, vm::ptr dst_len) +s32 UTF8stoUTF16s(vm::cptr src, vm::ptr src_len, vm::ptr dst, vm::ptr dst_len) { - cellL10n.warning("UTF8stoUTF16s(src=*0x%x, src_len=*0x%x, dst=*0x%x, dst_len=*0x%x)", src, src_len, dst, dst_len); - return _L10nConvertStr(L10N_UTF8, src, src_len, L10N_UTF16, dst, dst_len); + cellL10n.notice("UTF8stoUTF16s(src=*0x%x, src_len=*0x%x, dst=*0x%x, dst_len=*0x%x)", src, src_len, dst, dst_len); + + ensure(src_len && dst_len); // Not really checked + + if (*src_len == 0u) + { + *dst_len = 0; + return ConversionOK; + } + + ensure(src); // Not really checked + + u32 len = 0; + u32 dst_pos = 0; + + auto tmp = vm::make_var[2]>({0, 0}); + const vm::ptr utf16_tmp = vm::cast(tmp.addr()); + vm::var utf16_len_tmp = vm::make_var(0); + + for (u32 src_pos = 0; src_pos < *src_len;) + { + const s32 utf8_len = UTF8toUTF16(src + src_pos, utf16_tmp, utf16_len_tmp); + + if (utf8_len == 0) + { + *src_len -= src_pos; + *dst_len = len; + return SRCIllegal; + } + + const u32 utf16_len = *utf16_len_tmp; + len += utf16_len; + + if (dst) + { + if (*dst_len < len) + { + *src_len -= src_pos; + *dst_len = dst_pos; + return DSTExhausted; + } + + for (u32 i = 0; i < utf16_len; i++) + { + dst[dst_pos++] = utf16_tmp[i]; + } + } + + src_pos += utf8_len; + } + + *dst_len = len; + return ConversionOK; } -s32 SJISstoUCS2s(vm::cptr src, vm::cptr src_len, vm::ptr dst, vm::ptr dst_len) +s32 SJISstoUCS2s(vm::cptr src, vm::cptr src_len, vm::ptr dst, vm::ptr dst_len) { cellL10n.warning("SJISstoUCS2s(src=*0x%x, src_len=*0x%x, dst=*0x%x, dst_len=*0x%x)", src, src_len, dst, dst_len); return _L10nConvertStr(L10N_CODEPAGE_932, src, src_len, L10N_UCS2, dst, dst_len); @@ -1368,9 +2632,54 @@ s32 BIG5stoUCS2s() return ConversionOK; } -s32 UTF8stoUCS2s(vm::cptr src, vm::cptr src_len, vm::ptr dst, vm::ptr dst_len) +s32 UTF8stoUCS2s(vm::cptr src, vm::ptr src_len, vm::ptr dst, vm::ptr dst_len) { - cellL10n.todo("UTF8stoUCS2s(src=*0x%x, src_len=*0x%x, dst=*0x%x, dst_len=*0x%x)", src, src_len, dst, dst_len); + cellL10n.notice("UTF8stoUCS2s(src=*0x%x, src_len=*0x%x, dst=*0x%x, dst_len=*0x%x)", src, src_len, dst, dst_len); + + ensure(src_len && dst_len); // Not really checked + + if (*src_len == 0u) + { + *dst_len = 0; + return ConversionOK; + } + + ensure(src); // Not really checked + + u32 len = 0; + u32 dst_pos = 0; + + vm::var ucs2_tmp = vm::make_var(5); + + for (u32 src_pos = 0; src_pos < *src_len;) + { + const s32 utf8_len = UTF8toUCS2(src + src_pos, ucs2_tmp); + + if (utf8_len == 0 || *src_len < len) + { + *src_len -= src_pos; + *dst_len = len; + return SRCIllegal; + } + + len++; + + if (dst) + { + if (*dst_len < len) + { + *src_len -= src_pos; + *dst_len = dst_pos; + return DSTExhausted; + } + + dst[dst_pos++] = ucs2_tmp[0]; + } + + src_pos += utf8_len; + } + + *dst_len = len; return ConversionOK; } diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellL10n.h b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellL10n.h index 2a70dfb..f255f00 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellL10n.h +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellL10n.h @@ -52,25 +52,25 @@ enum L10N_CODEPAGE_863, L10N_CODEPAGE_866, L10N_CODEPAGE_932, - L10N_SHIFT_JIS, + L10N_SHIFT_JIS = L10N_CODEPAGE_932, L10N_CODEPAGE_936, - L10N_GBK, + L10N_GBK = L10N_CODEPAGE_936, L10N_CODEPAGE_949, - L10N_UHC, + L10N_UHC = L10N_CODEPAGE_949, L10N_CODEPAGE_950, - L10N_BIG5, + L10N_BIG5 = L10N_CODEPAGE_950, L10N_CODEPAGE_1251, L10N_CODEPAGE_1252, L10N_EUC_CN, L10N_EUC_JP, L10N_EUC_KR, L10N_ISO_2022_JP, - L10N_JIS, + L10N_JIS = L10N_ISO_2022_JP, L10N_ARIB, L10N_HZ, L10N_GB18030, L10N_RIS_506, - L10N_MUSIC_SHIFT_JIS, + L10N_MUSIC_SHIFT_JIS = L10N_RIS_506, //FW 3.10 and below L10N_CODEPAGE_852, L10N_CODEPAGE_1250, @@ -88,3 +88,12 @@ enum L10N_CODEPAGE_869, _L10N_CODE_ }; + +enum +{ + UTF16_SURROGATES_MASK1 = 0xf800, + UTF16_SURROGATES_MASK2 = 0xfc00, + UTF16_SURROGATES = 0xd800, + UTF16_HIGH_SURROGATES = 0xd800, + UTF16_LOW_SURROGATES = 0xdc00, +}; diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellMouse.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellMouse.cpp index 8b8d547..8bf550a 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellMouse.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellMouse.cpp @@ -1,6 +1,5 @@ #include "stdafx.h" #include "Emu/IdManager.h" -#include "Emu/System.h" #include "Emu/Cell/PPUModule.h" #include "Emu/Io/MouseHandler.h" diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellMusic.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellMusic.cpp index c517fe3..83937f7 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellMusic.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellMusic.cpp @@ -177,6 +177,11 @@ struct music_state return CELL_MUSIC_ERROR_NO_MORE_CONTENT; } + if (!fs::is_file(path)) + { + cellMusic.error("set_playback_command: File does not exist: '%s'", path); + } + switch (command) { case CELL_MUSIC_PB_CMD_FASTFORWARD: @@ -213,19 +218,29 @@ error_code cell_music_select_contents() error_code error = rsx::overlays::show_media_list_dialog(rsx::overlays::media_list_dialog::media_type::audio, vfs_dir_path, title, [&music](s32 status, utils::media_info info) { - sysutil_register_cb([&music, info, status](ppu_thread& ppu) -> s32 + sysutil_register_cb([&music, info = std::move(info), status](ppu_thread& ppu) -> s32 { std::lock_guard lock(music.mtx); const u32 result = status >= 0 ? u32{CELL_OK} : u32{CELL_MUSIC_CANCELED}; if (result == CELL_OK) { + // Let's always choose the whole directory for now + std::string track; + std::string dir = info.path; + if (fs::is_file(info.path)) + { + track = std::move(dir); + dir = fs::get_parent_dir(track); + } + music_selection_context context{}; - context.set_playlist(info.path); + context.set_playlist(dir); + context.set_track(track); // TODO: context.repeat_mode = CELL_SEARCH_REPEATMODE_NONE; // TODO: context.context_option = CELL_SEARCH_CONTEXTOPTION_NONE; - music.current_selection_context = context; + music.current_selection_context = std::move(context); music.current_selection_context.create_playlist(music_selection_context::get_next_hash()); - cellMusic.success("Media list dialog: selected entry '%s'", context.playlist.front()); + cellMusic.success("Media list dialog: selected entry '%s'", music.current_selection_context.playlist.front()); } else { @@ -556,7 +571,7 @@ error_code cellMusicSetPlaybackCommand2(s32 command, vm::ptr param) auto& music = g_fxo->get(); if (!music.func) - return CELL_MUSIC2_ERROR_GENERIC; + return { CELL_MUSIC2_ERROR_GENERIC, "Not initialized" }; error_code result = CELL_OK; @@ -585,7 +600,7 @@ error_code cellMusicSetPlaybackCommand(s32 command, vm::ptr param) auto& music = g_fxo->get(); if (!music.func) - return CELL_MUSIC_ERROR_GENERIC; + return { CELL_MUSIC_ERROR_GENERIC, "Not initialized" }; error_code result = CELL_OK; diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellMusic.h b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellMusic.h index d1cc13a..a98b305 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellMusic.h +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellMusic.h @@ -166,6 +166,7 @@ struct music_selection_context void set_playlist(const std::string& path); void create_playlist(const std::string& new_hash); bool load_playlist(); + void set_track(std::string_view track); u32 step_track(bool next); operator bool() const diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellMusicDecode.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellMusicDecode.cpp index 0880a5d..c938f72 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellMusicDecode.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellMusicDecode.cpp @@ -12,9 +12,6 @@ #include "cellSysutil.h" #include "util/media_utils.h" -#include - - LOG_CHANNEL(cellMusicDecode); template<> @@ -140,19 +137,29 @@ error_code cell_music_decode_select_contents() error_code error = rsx::overlays::show_media_list_dialog(rsx::overlays::media_list_dialog::media_type::audio, vfs_dir_path, title, [&dec](s32 status, utils::media_info info) { - sysutil_register_cb([&dec, info, status](ppu_thread& ppu) -> s32 + sysutil_register_cb([&dec, info = std::move(info), status](ppu_thread& ppu) -> s32 { std::lock_guard lock(dec.mutex); const u32 result = status >= 0 ? u32{CELL_OK} : u32{CELL_MUSIC_DECODE_CANCELED}; if (result == CELL_OK) { + // Let's always choose the whole directory for now + std::string track; + std::string dir = info.path; + if (fs::is_file(info.path)) + { + track = std::move(dir); + dir = fs::get_parent_dir(track); + } + music_selection_context context{}; - context.set_playlist(info.path); + context.set_playlist(dir); + context.set_track(track); // TODO: context.repeat_mode = CELL_SEARCH_REPEATMODE_NONE; // TODO: context.context_option = CELL_SEARCH_CONTEXTOPTION_NONE; - dec.current_selection_context = context; + dec.current_selection_context = std::move(context); dec.current_selection_context.create_playlist(music_selection_context::get_next_hash()); - cellMusicDecode.success("Media list dialog: selected entry '%s'", context.playlist.front()); + cellMusicDecode.success("Media list dialog: selected entry '%s'", dec.current_selection_context.playlist.front()); } else { diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellMusicExport.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellMusicExport.cpp index 752d7db..c01d4b7 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellMusicExport.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellMusicExport.cpp @@ -2,7 +2,6 @@ #include "Emu/Cell/PPUModule.h" #include "Emu/IdManager.h" #include "Emu/VFS.h" -#include "Utilities/StrUtil.h" #include "cellSysutil.h" LOG_CHANNEL(cellMusicExport); diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellMusicSelectionContext.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellMusicSelectionContext.cpp index 270786e..ae578d2 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellMusicSelectionContext.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellMusicSelectionContext.cpp @@ -16,7 +16,7 @@ bool music_selection_context::set(const CellMusicSelectionContext& in) return false; } - u32 pos = sizeof(magic); + constexpr u32 pos = sizeof(magic); hash = &in.data[pos]; return load_playlist(); @@ -77,7 +77,7 @@ std::string music_selection_context::get_yaml_path() const if (!fs::create_path(path)) { - cellMusicSelectionContext.fatal("Failed to create path: %s (%s)", path, fs::g_tls_error); + cellMusicSelectionContext.fatal("get_yaml_path: Failed to create path: %s (%s)", path, fs::g_tls_error); } return path + hash + ".yml"; @@ -101,14 +101,21 @@ void music_selection_context::set_playlist(const std::string& path) continue; } - playlist.push_back(dir_path + std::string(path + "/" + dir_entry.name).substr(vfs_dir_path.length())); + std::string track = dir_path + std::string(path + "/" + dir_entry.name).substr(vfs_dir_path.length()); + cellMusicSelectionContext.notice("set_playlist: Adding track to playlist: '%s'. (path: '%s', name: '%s')", track, path, dir_entry.name); + playlist.push_back(std::move(track)); } } else { content_type = CELL_SEARCH_CONTENTTYPE_MUSIC; - playlist.push_back(dir_path + path.substr(vfs_dir_path.length())); + + std::string track = dir_path + path.substr(vfs_dir_path.length()); + cellMusicSelectionContext.notice("set_playlist: Adding track to playlist: '%s'. (path: '%s')", track, path); + playlist.push_back(std::move(track)); } + + valid = true; } void music_selection_context::create_playlist(const std::string& new_hash) @@ -116,7 +123,7 @@ void music_selection_context::create_playlist(const std::string& new_hash) hash = new_hash; const std::string yaml_path = get_yaml_path(); - cellMusicSelectionContext.notice("Saving music playlist file %s", yaml_path); + cellMusicSelectionContext.notice("create_playlist: Saving music playlist file %s", yaml_path); YAML::Emitter out; out << YAML::BeginMap; @@ -138,9 +145,9 @@ void music_selection_context::create_playlist(const std::string& new_hash) fs::pending_file file(yaml_path); - if (!file.file || (file.file.write(out.c_str(), out.size()), !file.commit())) + if (!file.file || file.file.write(out.c_str(), out.size()) < out.size() || !file.commit()) { - cellMusicSelectionContext.error("Failed to create music playlist file %s (error=%s)", yaml_path, fs::g_tls_error); + cellMusicSelectionContext.error("create_playlist: Failed to create music playlist file '%s' (error=%s)", yaml_path, fs::g_tls_error); } } @@ -149,7 +156,7 @@ bool music_selection_context::load_playlist() playlist.clear(); const std::string path = get_yaml_path(); - cellMusicSelectionContext.notice("Loading music playlist file %s", path); + cellMusicSelectionContext.notice("load_playlist: Loading music playlist file '%s'", path); std::string content; { @@ -158,7 +165,7 @@ bool music_selection_context::load_playlist() if (!file) { - cellMusicSelectionContext.error("Failed to load music playlist file %s: %s", path, fs::g_tls_error); + cellMusicSelectionContext.error("load_playlist: Failed to load music playlist file '%s': %s", path, fs::g_tls_error); return false; } @@ -169,7 +176,7 @@ bool music_selection_context::load_playlist() if (!error.empty() || !root) { - cellMusicSelectionContext.error("Failed to load music playlist file %s:\n%s", path, error); + cellMusicSelectionContext.error("load_playlist: Failed to load music playlist file '%s':\n%s", path, error); return false; } @@ -178,54 +185,54 @@ bool music_selection_context::load_playlist() const std::string version = get_yaml_node_value(root["Version"], err); if (!err.empty()) { - cellMusicSelectionContext.error("No Version entry found. Error: '%s' (file: %s)", err, path); + cellMusicSelectionContext.error("load_playlist: No Version entry found. Error: '%s' (file: '%s')", err, path); return false; } if (version != target_version) { - cellMusicSelectionContext.error("Version '%s' does not match music playlist target '%s' (file: %s)", version, target_version, path); + cellMusicSelectionContext.error("load_playlist: Version '%s' does not match music playlist target '%s' (file: '%s')", version, target_version, path); return false; } const std::string file_type = get_yaml_node_value(root["FileType"], err); if (!err.empty()) { - cellMusicSelectionContext.error("No FileType entry found. Error: '%s' (file: %s)", err, path); + cellMusicSelectionContext.error("load_playlist: No FileType entry found. Error: '%s' (file: '%s')", err, path); return false; } if (file_type != target_file_type) { - cellMusicSelectionContext.error("FileType '%s' does not match music playlist target '%s' (file: %s)", file_type, target_file_type, path); + cellMusicSelectionContext.error("load_playlist: FileType '%s' does not match music playlist target '%s' (file: '%s')", file_type, target_file_type, path); return false; } content_type = static_cast(get_yaml_node_value(root["ContentType"], err)); if (!err.empty()) { - cellMusicSelectionContext.error("No ContentType entry found. Error: '%s' (file: %s)", err, path); + cellMusicSelectionContext.error("load_playlist: No ContentType entry found. Error: '%s' (file: '%s')", err, path); return false; } context_option = static_cast(get_yaml_node_value(root["ContextOption"], err)); if (!err.empty()) { - cellMusicSelectionContext.error("No ContextOption entry found. Error: '%s' (file: %s)", err, path); + cellMusicSelectionContext.error("load_playlist: No ContextOption entry found. Error: '%s' (file: '%s')", err, path); return false; } repeat_mode = static_cast(get_yaml_node_value(root["RepeatMode"], err)); if (!err.empty()) { - cellMusicSelectionContext.error("No RepeatMode entry found. Error: '%s' (file: %s)", err, path); + cellMusicSelectionContext.error("load_playlist: No RepeatMode entry found. Error: '%s' (file: '%s')", err, path); return false; } first_track = get_yaml_node_value(root["FirstTrack"], err); if (!err.empty()) { - cellMusicSelectionContext.error("No FirstTrack entry found. Error: '%s' (file: %s)", err, path); + cellMusicSelectionContext.error("load_playlist: No FirstTrack entry found. Error: '%s' (file: '%s')", err, path); return false; } @@ -233,24 +240,49 @@ bool music_selection_context::load_playlist() if (!track_node || track_node.Type() != YAML::NodeType::Sequence) { - cellMusicSelectionContext.error("No Tracks entry found or Tracks is not a Sequence. (file: %s)", path); + cellMusicSelectionContext.error("load_playlist: No Tracks entry found or Tracks is not a Sequence. (file: '%s')", path); return false; } for (usz i = 0; i < track_node.size(); i++) { + cellMusicSelectionContext.notice("load_playlist: Adding track to playlist: '%s'. (file: '%s')", track_node[i].Scalar(), path); playlist.push_back(track_node[i].Scalar()); } + cellMusicSelectionContext.notice("load_playlist: Loaded music playlist file '%s' (context: %s)", path, to_string()); valid = true; return true; } +void music_selection_context::set_track(std::string_view track) +{ + if (track.empty()) return; + + if (playlist.empty()) + { + cellMusicSelectionContext.error("set_track: No tracks to play... (requested path='%s')", track); + return; + } + + for (usz i = 0; i < playlist.size(); i++) + { + cellMusicSelectionContext.error("set_track: Comparing track '%s' vs '%s'", track, playlist[i]); + if (track.ends_with(playlist[i])) + { + first_track = current_track = static_cast(i); + return; + } + } + + cellMusicSelectionContext.error("set_track: Track '%s' not found...", track); +} + u32 music_selection_context::step_track(bool next) { if (playlist.empty()) { - cellMusicSelectionContext.error("No tracks to play..."); + cellMusicSelectionContext.error("step_track: No tracks to play..."); current_track = umax; return umax; } @@ -265,7 +297,7 @@ u32 music_selection_context::step_track(bool next) if (++current_track >= playlist.size()) { // We are at the end of the playlist. - cellMusicSelectionContext.notice("No more tracks to play in playlist..."); + cellMusicSelectionContext.notice("step_track: No more tracks to play in playlist..."); current_track = umax; return umax; } @@ -276,7 +308,7 @@ u32 music_selection_context::step_track(bool next) if (current_track == 0) { // We are at the start of the playlist. - cellMusicSelectionContext.notice("No more tracks to play in playlist..."); + cellMusicSelectionContext.notice("step_track: No more tracks to play in playlist..."); current_track = umax; return umax; } @@ -314,13 +346,13 @@ u32 music_selection_context::step_track(bool next) case CELL_SEARCH_REPEATMODE_NOREPEAT1: { // We are done. We only wanted to decode a single track. - cellMusicSelectionContext.notice("No more tracks to play..."); + cellMusicSelectionContext.notice("step_track: No more tracks to play..."); current_track = umax; return umax; } default: { - fmt::throw_exception("Unknown repeat mode %d", static_cast(repeat_mode)); + fmt::throw_exception("step_track: Unknown repeat mode %d", static_cast(repeat_mode)); } } @@ -329,7 +361,7 @@ u32 music_selection_context::step_track(bool next) if (next ? current_track == 0 : current_track == (playlist.size() - 1)) { // We reached the first or last track again. Let's shuffle! - cellMusicSelectionContext.notice("Shuffling playlist..."); + cellMusicSelectionContext.notice("step_track: Shuffling playlist..."); auto engine = std::default_random_engine{}; std::shuffle(std::begin(playlist), std::end(playlist), engine); } diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellNetCtl.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellNetCtl.cpp index e4b4fc8..97375c4 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellNetCtl.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellNetCtl.cpp @@ -2,7 +2,6 @@ #include "Emu/system_config.h" #include "Emu/Cell/PPUModule.h" #include "Emu/IdManager.h" -#include "Emu/Cell/lv2/sys_sync.h" #include "cellGame.h" #include "cellSysutil.h" diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellOskDialog.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellOskDialog.cpp index ecf2064..5b2c45e 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellOskDialog.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellOskDialog.cpp @@ -1,6 +1,5 @@ #include "stdafx.h" #include "Emu/System.h" -#include "Emu/system_config.h" #include "Emu/Cell/PPUModule.h" #include "Emu/Io/interception.h" #include "Emu/Io/Keyboard.h" diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellPhotoDecode.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellPhotoDecode.cpp index 843a0ad..5cef4ba 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellPhotoDecode.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellPhotoDecode.cpp @@ -1,6 +1,5 @@ #include "stdafx.h" #include "Emu/Cell/PPUModule.h" -#include "Emu/IdManager.h" #include "Emu/VFS.h" #include "Emu/System.h" #include "cellSysutil.h" diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellPhotoExport.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellPhotoExport.cpp index 34a1562..8a264bc 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellPhotoExport.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellPhotoExport.cpp @@ -2,7 +2,6 @@ #include "Emu/Cell/PPUModule.h" #include "Emu/IdManager.h" #include "Emu/VFS.h" -#include "Utilities/StrUtil.h" #include "cellSysutil.h" LOG_CHANNEL(cellPhotoExport); diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellPngDec.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellPngDec.cpp index cfb75b6..74c4cc6 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellPngDec.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellPngDec.cpp @@ -19,11 +19,6 @@ typedef png_bytep iCCP_profile_type; typedef png_charp iCCP_profile_type; #endif -// Temporarily -#ifndef _MSC_VER -#pragma GCC diagnostic ignored "-Wunused-parameter" -#endif - LOG_CHANNEL(cellPngDec); template <> @@ -149,7 +144,7 @@ void pngDecRowCallback(png_structp png_ptr, png_bytep new_row, png_uint_32 row_n png_progressive_combine_row(png_ptr, data, new_row); } -void pngDecInfoCallback(png_structp png_ptr, png_infop info) +void pngDecInfoCallback(png_structp png_ptr, png_infop /*info*/) { PngStream* stream = static_cast(png_get_progressive_ptr(png_ptr)); if (!stream) @@ -162,7 +157,7 @@ void pngDecInfoCallback(png_structp png_ptr, png_infop info) stream->buffer->cursor += (stream->buffer->length - remaining); } -void pngDecEndCallback(png_structp png_ptr, png_infop info) +void pngDecEndCallback(png_structp png_ptr, png_infop /*info*/) { PngStream* stream = static_cast(png_get_progressive_ptr(png_ptr)); if (!stream) @@ -175,17 +170,17 @@ void pngDecEndCallback(png_structp png_ptr, png_infop info) } // Custom error handler for libpng -[[noreturn]] void pngDecError(png_structp png_ptr, png_const_charp error_message) +[[noreturn]] void pngDecError(png_structp /*png_ptr*/, png_const_charp error_message) { - cellPngDec.error("%s", error_message); + cellPngDec.error("pngDecError: %s", error_message); // we can't return here or libpng blows up fmt::throw_exception("Fatal Error in libpng: %s", error_message); } // Custom warning handler for libpng -void pngDecWarning(png_structp png_ptr, png_const_charp error_message) +void pngDecWarning(png_structp /*png_ptr*/, png_const_charp error_message) { - cellPngDec.warning("%s", error_message); + cellPngDec.warning("pngDecWarning: %s", error_message); } // Get the chunk information of the PNG file. IDAT is marked as existing, only after decoding or reading the header. @@ -337,7 +332,7 @@ be_t pngDecGetChunkInformation(PngStream* stream, bool IDAT = false) return chunk_information; } -error_code pngDecCreate(ppu_thread& ppu, PPHandle png_handle, PThreadInParam thread_in_param, PThreadOutParam thread_out_param, PExtThreadInParam extra_thread_in_param = vm::null, PExtThreadOutParam extra_thread_out_param = vm::null) +error_code pngDecCreate(ppu_thread& ppu, PPHandle png_handle, PThreadInParam thread_in_param, PThreadOutParam thread_out_param, PExtThreadInParam /*extra_thread_in_param*/ = vm::null, PExtThreadOutParam extra_thread_out_param = vm::null) { // Check if partial image decoding is used if (extra_thread_out_param) @@ -908,103 +903,103 @@ error_code cellPngDecExtDecodeData(ppu_thread& ppu, PHandle handle, PStream stre error_code cellPngDecGetUnknownChunks(PHandle handle, PStream stream, vm::pptr unknownChunk, vm::ptr unknownChunkNumber) { - cellPngDec.todo("cellPngDecGetUnknownChunks()"); + cellPngDec.todo("cellPngDecGetUnknownChunks(handle=*0x%x, stream=*0x%x, unknownChunk=*0x%x, unknownChunkNumber=*0x%x)", handle, stream, unknownChunk, unknownChunkNumber); return CELL_OK; } error_code cellPngDecGetpCAL(PHandle handle, PStream stream, vm::ptr pcal) { - cellPngDec.todo("cellPngDecGetpCAL()"); + cellPngDec.todo("cellPngDecGetpCAL(handle=*0x%x, stream=*0x%x, pcal=*0x%x)", handle, stream, pcal); return CELL_OK; } error_code cellPngDecGetcHRM(PHandle handle, PStream stream, vm::ptr chrm) { - cellPngDec.todo("cellPngDecGetcHRM()"); + cellPngDec.todo("cellPngDecGetcHRM(handle=*0x%x, stream=*0x%x, chrm=*0x%x)", handle, stream, chrm); return CELL_OK; } error_code cellPngDecGetsCAL(PHandle handle, PStream stream, vm::ptr scal) { - cellPngDec.todo("cellPngDecGetsCAL()"); + cellPngDec.todo("cellPngDecGetsCAL(handle=*0x%x, stream=*0x%x, scal=*0x%x)", handle, stream, scal); return CELL_OK; } error_code cellPngDecGetpHYs(PHandle handle, PStream stream, vm::ptr phys) { - cellPngDec.todo("cellPngDecGetpHYs()"); + cellPngDec.todo("cellPngDecGetpHYs(handle=*0x%x, stream=*0x%x, phys=*0x%x)", handle, stream, phys); return CELL_OK; } error_code cellPngDecGetoFFs(PHandle handle, PStream stream, vm::ptr offs) { - cellPngDec.todo("cellPngDecGetoFFs()"); + cellPngDec.todo("cellPngDecGetoFFs(handle=*0x%x, stream=*0x%x, offs=*0x%x)", handle, stream, offs); return CELL_OK; } error_code cellPngDecGetsPLT(PHandle handle, PStream stream, vm::ptr splt) { - cellPngDec.todo("cellPngDecGetsPLT()"); + cellPngDec.todo("cellPngDecGetsPLT(handle=*0x%x, stream=*0x%x, splt=*0x%x)", handle, stream, splt); return CELL_OK; } error_code cellPngDecGetbKGD(PHandle handle, PStream stream, vm::ptr bkgd) { - cellPngDec.todo("cellPngDecGetbKGD()"); + cellPngDec.todo("cellPngDecGetbKGD(handle=*0x%x, stream=*0x%x, bkgd=*0x%x)", handle, stream, bkgd); return CELL_OK; } error_code cellPngDecGettIME(PHandle handle, PStream stream, vm::ptr time) { - cellPngDec.todo("cellPngDecGettIME()"); + cellPngDec.todo("cellPngDecGettIME(handle=*0x%x, stream=*0x%x, time=*0x%x)", handle, stream, time); return CELL_OK; } error_code cellPngDecGethIST(PHandle handle, PStream stream, vm::ptr hist) { - cellPngDec.todo("cellPngDecGethIST()"); + cellPngDec.todo("cellPngDecGethIST(handle=*0x%x, stream=*0x%x, hist=*0x%x)", handle, stream, hist); return CELL_OK; } error_code cellPngDecGettRNS(PHandle handle, PStream stream, vm::ptr trns) { - cellPngDec.todo("cellPngDecGettRNS()"); + cellPngDec.todo("cellPngDecGettRNS(handle=*0x%x, stream=*0x%x, trns=*0x%x)", handle, stream, trns); return CELL_OK; } error_code cellPngDecGetsBIT(PHandle handle, PStream stream, vm::ptr sbit) { - cellPngDec.todo("cellPngDecGetsBIT()"); + cellPngDec.todo("cellPngDecGetsBIT(handle=*0x%x, stream=*0x%x, sbit=*0x%x)", handle, stream, sbit); return CELL_OK; } error_code cellPngDecGetiCCP(PHandle handle, PStream stream, vm::ptr iccp) { - cellPngDec.todo("cellPngDecGetiCCP()"); + cellPngDec.todo("cellPngDecGetiCCP(handle=*0x%x, stream=*0x%x, iccp=*0x%x)", handle, stream, iccp); return CELL_OK; } error_code cellPngDecGetsRGB(PHandle handle, PStream stream, vm::ptr srgb) { - cellPngDec.todo("cellPngDecGetsRGB()"); + cellPngDec.todo("cellPngDecGetsRGB(handle=*0x%x, stream=*0x%x, srgb=*0x%x)", handle, stream, srgb); return CELL_OK; } error_code cellPngDecGetgAMA(PHandle handle, PStream stream, vm::ptr gama) { - cellPngDec.todo("cellPngDecGetgAMA()"); + cellPngDec.todo("cellPngDecGetgAMA(handle=*0x%x, stream=*0x%x, gama=*0x%x)", handle, stream, gama); return CELL_OK; } error_code cellPngDecGetPLTE(PHandle handle, PStream stream, vm::ptr plte) { - cellPngDec.todo("cellPngDecGetPLTE()"); + cellPngDec.todo("cellPngDecGetPLTE(handle=*0x%x, stream=*0x%x, plte=*0x%x)", handle, stream, plte); return CELL_OK; } error_code cellPngDecGetTextChunk(PHandle handle, PStream stream, vm::ptr textInfoNum, vm::pptr textInfo) { - cellPngDec.todo("cellPngDecGetTextChunk()"); + cellPngDec.todo("cellPngDecGetTextChunk(handle=*0x%x, stream=*0x%x, textInfoNum=*0x%x, textInfo=*0x%x)", handle, stream, textInfoNum, textInfo); return CELL_OK; } diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellPngEnc.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellPngEnc.cpp index f723ddf..c6da0c4 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellPngEnc.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellPngEnc.cpp @@ -2,7 +2,6 @@ #include "Emu/Cell/PPUModule.h" #include "Emu/IdManager.h" #include "cellPngEnc.h" -#include "png.h" LOG_CHANNEL(cellPngEnc); diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellRec.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellRec.cpp index 011a8df..19e3279 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellRec.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellRec.cpp @@ -894,7 +894,7 @@ void rec_info::stop_video_provider(bool flush) } } -bool create_path(std::string& out, std::string dir_name, std::string file_name) +bool create_path(std::string& out, std::string dir_name, const std::string& file_name) { out.clear(); @@ -903,7 +903,7 @@ bool create_path(std::string& out, std::string dir_name, std::string file_name) return false; } - out = dir_name; + out = std::move(dir_name); if (!out.empty() && out.back() != '/') { diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellRtc.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellRtc.cpp index 487f9b1..fb92dd6 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellRtc.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellRtc.cpp @@ -78,7 +78,7 @@ error_code cellRtcGetCurrentTick(ppu_thread& ppu, vm::ptr pTick) error_code cellRtcGetCurrentClock(ppu_thread& ppu, vm::ptr pClock, s32 iTimeZone) { - cellRtc.notice("cellRtcGetCurrentClock(pClock=*0x%x, iTimeZone=%d)", pClock, iTimeZone); + cellRtc.trace("cellRtcGetCurrentClock(pClock=*0x%x, iTimeZone=%d)", pClock, iTimeZone); const vm::var page_attr; @@ -1505,7 +1505,7 @@ error_code cellRtcGetSystemTime(ppu_thread& ppu, vm::cptr pDate error_code cellRtcGetTime_t(ppu_thread& ppu, vm::cptr pDateTime, vm::ptr piTime) { - cellRtc.notice("cellRtcGetTime_t(pDateTime=*0x%x, piTime=*0x%x)", pDateTime, piTime); + cellRtc.trace("cellRtcGetTime_t(pDateTime=*0x%x, piTime=*0x%x)", pDateTime, piTime); const vm::var page_attr; diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellSailRec.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellSailRec.cpp index e6d7d58..c7a3cba 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellSailRec.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellSailRec.cpp @@ -1,6 +1,5 @@ #include "stdafx.h" #include "Emu/Cell/PPUModule.h" -#include "cellSail.h" LOG_CHANNEL(cellSailRec); diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellSaveData.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellSaveData.cpp index 4ce8be0..eec2652 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellSaveData.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellSaveData.cpp @@ -8,6 +8,7 @@ #include "Emu/Cell/lv2/sys_sync.h" #include "Emu/Cell/lv2/sys_process.h" #include "Emu/Cell/PPUModule.h" +#include "Emu/Cell/timers.hpp" #include "Emu/Cell/Modules/cellSysutil.h" #include "Emu/Cell/Modules/cellUserInfo.h" #include "Emu/RSX/Overlays/overlay_message.h" @@ -19,6 +20,7 @@ #include "Loader/PSF.h" #include "Utilities/StrUtil.h" #include "Utilities/date_time.h" +#include "Utilities/sema.h" #include #include @@ -242,7 +244,7 @@ static std::vector get_save_entries(const std::string& base_dir, continue; } - SaveDataEntry save_entry; + SaveDataEntry save_entry {}; save_entry.dirName = psf::get_string(psf, "SAVEDATA_DIRECTORY"); save_entry.listParam = psf::get_string(psf, "SAVEDATA_LIST_PARAM"); save_entry.title = psf::get_string(psf, "TITLE"); @@ -305,7 +307,7 @@ static error_code select_and_delete(ppu_thread& ppu) // Display a blocking Save Data List asynchronously in the GUI thread. if (auto save_dialog = Emu.GetCallbacks().get_save_dialog()) { - selected = save_dialog->ShowSaveDataList(save_entries, focused, SAVEDATA_OP_LIST_DELETE, vm::null, g_fxo->get().enable_overlay); + selected = save_dialog->ShowSaveDataList(base_dir, save_entries, focused, SAVEDATA_OP_LIST_DELETE, vm::null, g_fxo->get().enable_overlay); } // Reschedule after a blocking dialog returns @@ -324,7 +326,7 @@ static error_code select_and_delete(ppu_thread& ppu) focused = save_entries.empty() ? -1 : selected; // Get information from the selected entry - SaveDataEntry entry = save_entries[selected]; + const SaveDataEntry& entry = ::at32(save_entries, selected); const std::string info = entry.title + "\n" + entry.subtitle + "\n" + entry.details; // Reusable display message string @@ -758,7 +760,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v result->userdata = userdata; // probably should be assigned only once (allows the callback to change it) - SaveDataEntry save_entry; + SaveDataEntry save_entry {}; if (setList) { @@ -818,7 +820,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v break; } - SaveDataEntry save_entry2; + SaveDataEntry save_entry2 {}; save_entry2.dirName = psf::get_string(psf, "SAVEDATA_DIRECTORY"); save_entry2.listParam = psf::get_string(psf, "SAVEDATA_LIST_PARAM"); save_entry2.title = psf::get_string(psf, "TITLE"); @@ -1181,7 +1183,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v // Display a blocking Save Data List asynchronously in the GUI thread. if (auto save_dialog = Emu.GetCallbacks().get_save_dialog()) { - selected = save_dialog->ShowSaveDataList(save_entries, focused, operation, listSet, g_fxo->get().enable_overlay); + selected = save_dialog->ShowSaveDataList(base_dir, save_entries, focused, operation, listSet, g_fxo->get().enable_overlay); } else { @@ -1212,8 +1214,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v else { // Get information from the selected entry - SaveDataEntry entry = save_entries[selected]; - message = get_confirmation_message(operation, entry); + message = get_confirmation_message(operation, ::at32(save_entries, selected)); } // Yield before a blocking dialog is being spawned @@ -1343,14 +1344,14 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v else { // Get information from the selected entry - SaveDataEntry entry = save_entries[selected]; - message = get_confirmation_message(operation, entry); + message = get_confirmation_message(operation, ::at32(save_entries, selected)); } // Yield before a blocking dialog is being spawned lv2_obj::sleep(ppu); // Get user confirmation by opening a blocking dialog + // TODO: show fixedSet->newIcon s32 return_code = CELL_MSGDIALOG_BUTTON_NONE; error_code res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO, vm::make_str(message), msg_dialog_source::_cellSaveData, vm::null, vm::null, vm::null, &return_code); @@ -2499,12 +2500,7 @@ error_code cellSaveDataListDelete(ppu_thread& ppu, PSetList setList, PSetBuf set return savedata_op(ppu, SAVEDATA_OP_LIST_DELETE, 0, vm::null, 0, setList, setBuf, funcList, vm::null, vm::null, vm::null, container, 0x40, userdata, 0, funcDone); } -// Temporarily -#ifndef _MSC_VER -#pragma GCC diagnostic ignored "-Wunused-parameter" -#endif - -error_code cellSaveDataListImport(ppu_thread& ppu, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr userdata) +error_code cellSaveDataListImport(ppu_thread& /*ppu*/, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr userdata) { cellSaveData.todo("cellSaveDataListImport(setList=*0x%x, maxSizeKB=%d, funcDone=*0x%x, container=0x%x, userdata=*0x%x)", setList, maxSizeKB, funcDone, container, userdata); @@ -2519,7 +2515,7 @@ error_code cellSaveDataListImport(ppu_thread& ppu, PSetList setList, u32 maxSize return CELL_OK; } -error_code cellSaveDataListExport(ppu_thread& ppu, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr userdata) +error_code cellSaveDataListExport(ppu_thread& /*ppu*/, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr userdata) { cellSaveData.todo("cellSaveDataListExport(setList=*0x%x, maxSizeKB=%d, funcDone=*0x%x, container=0x%x, userdata=*0x%x)", setList, maxSizeKB, funcDone, container, userdata); @@ -2534,7 +2530,7 @@ error_code cellSaveDataListExport(ppu_thread& ppu, PSetList setList, u32 maxSize return CELL_OK; } -error_code cellSaveDataFixedImport(ppu_thread& ppu, vm::cptr dirName, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr userdata) +error_code cellSaveDataFixedImport(ppu_thread& /*ppu*/, vm::cptr dirName, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr userdata) { cellSaveData.todo("cellSaveDataFixedImport(dirName=%s, maxSizeKB=%d, funcDone=*0x%x, container=0x%x, userdata=*0x%x)", dirName, maxSizeKB, funcDone, container, userdata); @@ -2549,7 +2545,7 @@ error_code cellSaveDataFixedImport(ppu_thread& ppu, vm::cptr dirName, u32 return CELL_OK; } -error_code cellSaveDataFixedExport(ppu_thread& ppu, vm::cptr dirName, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr userdata) +error_code cellSaveDataFixedExport(ppu_thread& /*ppu*/, vm::cptr dirName, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr userdata) { cellSaveData.todo("cellSaveDataFixedExport(dirName=%s, maxSizeKB=%d, funcDone=*0x%x, container=0x%x, userdata=*0x%x)", dirName, maxSizeKB, funcDone, container, userdata); @@ -2580,7 +2576,7 @@ error_code cellSaveDataUserListDelete(ppu_thread& ppu, u32 userId, PSetList setL return savedata_op(ppu, SAVEDATA_OP_LIST_DELETE, 0, vm::null, 0, setList, setBuf, funcList, vm::null, vm::null, vm::null, container, 0x40, userdata, userId, funcDone); } -error_code cellSaveDataUserListImport(ppu_thread& ppu, u32 userId, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr userdata) +error_code cellSaveDataUserListImport(ppu_thread& /*ppu*/, u32 userId, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr userdata) { cellSaveData.todo("cellSaveDataUserListImport(userId=%d, setList=*0x%x, maxSizeKB=%d, funcDone=*0x%x, container=0x%x, userdata=*0x%x)", userId, setList, maxSizeKB, funcDone, container, userdata); @@ -2595,7 +2591,7 @@ error_code cellSaveDataUserListImport(ppu_thread& ppu, u32 userId, PSetList setL return CELL_OK; } -error_code cellSaveDataUserListExport(ppu_thread& ppu, u32 userId, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr userdata) +error_code cellSaveDataUserListExport(ppu_thread& /*ppu*/, u32 userId, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr userdata) { cellSaveData.todo("cellSaveDataUserListExport(userId=%d, setList=*0x%x, maxSizeKB=%d, funcDone=*0x%x, container=0x%x, userdata=*0x%x)", userId, setList, maxSizeKB, funcDone, container, userdata); @@ -2610,7 +2606,7 @@ error_code cellSaveDataUserListExport(ppu_thread& ppu, u32 userId, PSetList setL return CELL_OK; } -error_code cellSaveDataUserFixedImport(ppu_thread& ppu, u32 userId, vm::cptr dirName, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr userdata) +error_code cellSaveDataUserFixedImport(ppu_thread& /*ppu*/, u32 userId, vm::cptr dirName, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr userdata) { cellSaveData.todo("cellSaveDataUserFixedImport(userId=%d, dirName=%s, maxSizeKB=%d, funcDone=*0x%x, container=0x%x, userdata=*0x%x)", userId, dirName, maxSizeKB, funcDone, container, userdata); @@ -2625,7 +2621,7 @@ error_code cellSaveDataUserFixedImport(ppu_thread& ppu, u32 userId, vm::cptr dirName, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr userdata) +error_code cellSaveDataUserFixedExport(ppu_thread& /*ppu*/, u32 userId, vm::cptr dirName, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr 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); diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellSaveData.h b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellSaveData.h index c88a4a3..0632c25 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellSaveData.h +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellSaveData.h @@ -1,7 +1,6 @@ #pragma once #include "util/types.hpp" -#include "util/endian.hpp" #include "Emu/Memory/vm_ptr.h" #include #include @@ -362,5 +361,5 @@ class SaveDialogBase public: virtual ~SaveDialogBase(); - virtual s32 ShowSaveDataList(std::vector& save_entries, s32 focused, u32 op, vm::ptr listSet, bool enable_overlay) = 0; + virtual s32 ShowSaveDataList(const std::string& base_dir, std::vector& save_entries, s32 focused, u32 op, vm::ptr listSet, bool enable_overlay) = 0; }; diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellSpurs.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellSpurs.cpp index 7cdb317..c09c808 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellSpurs.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellSpurs.cpp @@ -160,11 +160,6 @@ void fmt_class_string::format(std::string& out, u64 arg) error_code sys_spu_image_close(ppu_thread&, vm::ptr img); -// Temporarily -#ifndef _MSC_VER -#pragma GCC diagnostic ignored "-Wunused-parameter" -#endif - //---------------------------------------------------------------------------- // Function prototypes //---------------------------------------------------------------------------- @@ -738,7 +733,7 @@ void _spurs::handler_entry(ppu_thread& ppu, vm::ptr spurs) } } -s32 _spurs::create_handler(vm::ptr spurs, u32 ppuPriority) +s32 _spurs::create_handler(vm::ptr /*spurs*/, u32 /*ppuPriority*/) { struct handler_thread : ppu_thread { @@ -909,7 +904,7 @@ void _spurs::event_helper_entry(ppu_thread& ppu, vm::ptr spurs) } } -s32 _spurs::create_event_helper(ppu_thread& ppu, vm::ptr spurs, u32 ppuPriority) +s32 _spurs::create_event_helper(ppu_thread& ppu, vm::ptr spurs, u32 /*ppuPriority*/) { if (s32 rc = _spurs::create_lv2_eq(ppu, spurs, spurs.ptr(&CellSpurs::eventQueue), spurs.ptr(&CellSpurs::spuPort), 0x2A, sys_event_queue_attribute_t{SYS_SYNC_PRIORITY, SYS_PPU_QUEUE, {"_spuPrv\0"_u64}})) { @@ -981,7 +976,7 @@ void _spurs::init_event_port_mux(vm::ptr eventPortMux, eventPortMux->x08 = unknown; } -s32 _spurs::add_default_syswkl(vm::ptr spurs, vm::cptr swlPriority, u32 swlMaxSpu, u32 swlIsPreem) +s32 _spurs::add_default_syswkl(vm::ptr /*spurs*/, vm::cptr /*swlPriority*/, u32 /*swlMaxSpu*/, u32 /*swlIsPreem*/) { // TODO: Implement this return CELL_OK; @@ -1859,7 +1854,7 @@ s32 cellSpursSetPriority(vm::ptr spurs, u32 wid, u32 spuId, u32 prior /// Set preemption victim SPU s32 cellSpursSetPreemptionVictimHints(vm::ptr spurs, vm::cptr isPreemptible) { - UNIMPLEMENTED_FUNC(cellSpurs); + cellSpurs.todo("cellSpursSetPreemptionVictimHints(spurs=*0x%x, isPreemptible=*0x%x)", spurs, isPreemptible); return CELL_OK; } @@ -2230,7 +2225,7 @@ s32 cellSpursTraceStop(ppu_thread& ppu, vm::ptr spurs) //---------------------------------------------------------------------------- /// Initialize attributes of a workload -s32 _cellSpursWorkloadAttributeInitialize(ppu_thread& ppu, vm::ptr attr, u32 revision, u32 sdkVersion, vm::cptr pm, u32 size, u64 data, vm::cptr priority, u32 minCnt, u32 maxCnt) +s32 _cellSpursWorkloadAttributeInitialize(ppu_thread& /*ppu*/, vm::ptr attr, u32 revision, u32 sdkVersion, vm::cptr pm, u32 size, u64 data, vm::cptr priority, u32 minCnt, u32 maxCnt) { cellSpurs.warning("_cellSpursWorkloadAttributeInitialize(attr=*0x%x, revision=%d, sdkVersion=0x%x, pm=*0x%x, size=0x%x, data=0x%llx, priority=*0x%x, minCnt=0x%x, maxCnt=0x%x)", attr, revision, sdkVersion, pm, size, data, priority, minCnt, maxCnt); @@ -2277,7 +2272,7 @@ s32 _cellSpursWorkloadAttributeInitialize(ppu_thread& ppu, vm::ptr attr, vm::cptr nameClass, vm::cptr nameInstance) +s32 cellSpursWorkloadAttributeSetName(ppu_thread& /*ppu*/, vm::ptr attr, vm::cptr nameClass, vm::cptr nameInstance) { cellSpurs.warning("cellSpursWorkloadAttributeSetName(attr=*0x%x, nameClass=%s, nameInstance=%s)", attr, nameClass, nameInstance); @@ -2771,7 +2766,7 @@ s32 cellSpursWakeUp(ppu_thread& ppu, vm::ptr spurs) } /// Send a workload signal -s32 cellSpursSendWorkloadSignal(ppu_thread& ppu, vm::ptr spurs, u32 wid) +s32 cellSpursSendWorkloadSignal(ppu_thread& /*ppu*/, vm::ptr spurs, u32 wid) { cellSpurs.warning("cellSpursSendWorkloadSignal(spurs=*0x%x, wid=%d)", spurs, wid); @@ -2833,7 +2828,7 @@ s32 cellSpursGetWorkloadFlag(vm::ptr spurs, vm::pptr spurs, u32 wid, u32 value) +s32 cellSpursReadyCountStore(ppu_thread& /*ppu*/, vm::ptr spurs, u32 wid, u32 value) { cellSpurs.trace("cellSpursReadyCountStore(spurs=*0x%x, wid=%d, value=0x%x)", spurs, wid, value); @@ -2871,7 +2866,7 @@ s32 cellSpursReadyCountStore(ppu_thread& ppu, vm::ptr spurs, u32 wid, } /// Swap ready count -s32 cellSpursReadyCountSwap(ppu_thread& ppu, vm::ptr spurs, u32 wid, vm::ptr old, u32 swap) +s32 cellSpursReadyCountSwap(ppu_thread& /*ppu*/, vm::ptr spurs, u32 wid, vm::ptr old, u32 swap) { cellSpurs.trace("cellSpursReadyCountSwap(spurs=*0x%x, wid=%d, old=*0x%x, swap=0x%x)", spurs, wid, old, swap); @@ -2909,7 +2904,7 @@ s32 cellSpursReadyCountSwap(ppu_thread& ppu, vm::ptr spurs, u32 wid, } /// Compare and swap ready count -s32 cellSpursReadyCountCompareAndSwap(ppu_thread& ppu, vm::ptr spurs, u32 wid, vm::ptr old, u32 compare, u32 swap) +s32 cellSpursReadyCountCompareAndSwap(ppu_thread& /*ppu*/, vm::ptr spurs, u32 wid, vm::ptr old, u32 compare, u32 swap) { cellSpurs.trace("cellSpursReadyCountCompareAndSwap(spurs=*0x%x, wid=%d, old=*0x%x, compare=0x%x, swap=0x%x)", spurs, wid, old, compare, swap); @@ -2950,7 +2945,7 @@ s32 cellSpursReadyCountCompareAndSwap(ppu_thread& ppu, vm::ptr spurs, } /// Increase or decrease ready count -s32 cellSpursReadyCountAdd(ppu_thread& ppu, vm::ptr spurs, u32 wid, vm::ptr old, s32 value) +s32 cellSpursReadyCountAdd(ppu_thread& /*ppu*/, vm::ptr spurs, u32 wid, vm::ptr old, s32 value) { cellSpurs.trace("cellSpursReadyCountAdd(spurs=*0x%x, wid=%d, old=*0x%x, value=0x%x)", spurs, wid, old, value); @@ -3030,7 +3025,7 @@ s32 cellSpursGetWorkloadData(vm::ptr spurs, vm::ptr data, u32 wi } /// Get workload information -s32 cellSpursGetWorkloadInfo(ppu_thread& ppu, vm::ptr spurs, u32 wid, vm::ptr info) +s32 cellSpursGetWorkloadInfo(ppu_thread& /*ppu*/, vm::ptr spurs, u32 wid, vm::ptr info) { cellSpurs.todo("cellSpursGetWorkloadInfo(spurs=*0x%x, wid=0x%x, info=*0x%x)", spurs, wid, info); return CELL_OK; @@ -3135,7 +3130,7 @@ s32 _cellSpursWorkloadFlagReceiver(ppu_thread& ppu, vm::ptr spurs, u3 } /// Set/unset the recipient of the workload flag -s32 _cellSpursWorkloadFlagReceiver2(ppu_thread& ppu, vm::ptr spurs, u32 wid, u32 is_set, u32 print_debug_output) +s32 _cellSpursWorkloadFlagReceiver2(ppu_thread& /*ppu*/, vm::ptr spurs, u32 wid, u32 is_set, u32 print_debug_output) { cellSpurs.warning("_cellSpursWorkloadFlagReceiver2(spurs=*0x%x, wid=%d, is_set=%d, print_debug_output=%d)", spurs, wid, is_set, print_debug_output); @@ -3833,19 +3828,19 @@ s32 _cellSpursLFQueueInitialize(vm::ptr pTasksetOrSpurs, vm::ptr queue) { - UNIMPLEMENTED_FUNC(cellSpurs); + cellSpurs.todo("cellSpursLFQueueAttachLv2EventQueue(queue=*0x%x)", queue); return CELL_OK; } s32 cellSpursLFQueueDetachLv2EventQueue(vm::ptr queue) { - UNIMPLEMENTED_FUNC(cellSpurs); + cellSpurs.todo("cellSpursLFQueueDetachLv2EventQueue(queue=*0x%x)", queue); return CELL_OK; } @@ -4571,7 +4566,7 @@ s32 cellSpursTasksetUnsetExceptionEventHandler(vm::ptr taskset return CELL_OK; } -s32 cellSpursLookUpTasksetAddress(ppu_thread& ppu, vm::ptr spurs, vm::pptr taskset, u32 id) +s32 cellSpursLookUpTasksetAddress(ppu_thread& /*ppu*/, vm::ptr spurs, vm::pptr taskset, u32 id) { cellSpurs.warning("cellSpursLookUpTasksetAddress(spurs=*0x%x, taskset=**0x%x, id=0x%x)", spurs, taskset, id); @@ -4653,9 +4648,9 @@ s32 _cellSpursTasksetAttributeInitialize(vm::ptr attr return CELL_OK; } -s32 _spurs::check_job_chain_attribute(u32 sdkVer, vm::cptr 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 jcEntry, u16 sizeJobDescr, u16 maxGrabbedJob, + u64 priorities, u32 /*maxContention*/, u8 autoSpuCount, u32 tag1, u32 tag2, + u8 /*isFixedMemAlloc*/, u32 maxSizeJob, u32 initSpuCount) { if (!jcEntry) return CELL_SPURS_JOB_ERROR_NULL_POINTER; @@ -4686,9 +4681,9 @@ s32 _spurs::check_job_chain_attribute(u32 sdkVer, vm::cptr jcEntry, u16 siz return CELL_OK; } -s32 _spurs::create_job_chain(ppu_thread& ppu, vm::ptr spurs, vm::ptr jobChain, vm::cptr jobChainEntry, u16 sizeJob - , u16 maxGrabbedJob, vm::cptr prio, u32 maxContention, b8 autoReadyCount - , u32 tag1, u32 tag2, u32 HaltOnError, vm::cptr name, u32 param_13, u32 param_14) +s32 _spurs::create_job_chain(ppu_thread& ppu, vm::ptr spurs, vm::ptr jobChain, vm::cptr jobChainEntry, u16 /*sizeJob*/, + u16 maxGrabbedJob, vm::cptr prio, u32 maxContention, b8 /*autoReadyCount*/, + u32 tag1, u32 tag2, u32 /*HaltOnError*/, vm::cptr name, u32 /*param_13*/, u32 /*param_14*/) { const s32 sdkVer = _spurs::get_sdk_version(); jobChain->spurs = spurs; diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellSpursJq.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellSpursJq.cpp index dfbc3e0..b2cb3e4 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellSpursJq.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellSpursJq.cpp @@ -1,9 +1,6 @@ #include "stdafx.h" #include "Emu/Cell/PPUModule.h" -#include "Emu/Cell/lv2/sys_spu.h" -#include "cellSpursJq.h" - LOG_CHANNEL(cellSpursJq); error_code cellSpursJobQueueAttributeInitialize() diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp index a6cdeb6..4be2458 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellSpursSpu.cpp @@ -15,7 +15,6 @@ LOG_CHANNEL(cellSpurs); // Temporarily #ifndef _MSC_VER #pragma GCC diagnostic ignored "-Wunused-function" -#pragma GCC diagnostic ignored "-Wunused-parameter" #endif //---------------------------------------------------------------------------- @@ -89,7 +88,7 @@ void spursJobchainPopUrgentCommand(spu_thread& spu); //---------------------------------------------------------------------------- // Output trace information -void cellSpursModulePutTrace(CellSpursTracePacket* packet, u32 dmaTagId) +void cellSpursModulePutTrace(CellSpursTracePacket* /*packet*/, u32 /*dmaTagId*/) { // TODO: Implement this } @@ -871,7 +870,7 @@ void spursSysServiceIdleHandler(spu_thread& spu, SpursKernelContext* ctxt) } // Main function for the system service -void spursSysServiceMain(spu_thread& spu, u32 pollStatus) +void spursSysServiceMain(spu_thread& spu, u32 /*pollStatus*/) { const auto ctxt = spu._ptr(0x100); @@ -1166,7 +1165,7 @@ void spursSysServiceUpdateShutdownCompletionEvents(spu_thread& spu, SpursKernelC } // Update the trace count for this SPU -void spursSysServiceTraceSaveCount(spu_thread& spu, SpursKernelContext* ctxt) +void spursSysServiceTraceSaveCount(spu_thread& /*spu*/, SpursKernelContext* ctxt) { if (ctxt->traceBuffer) { @@ -2056,7 +2055,7 @@ s32 spursTasksetLoadElf(spu_thread& spu, u32* entryPoint, u32* lowestLoadAddr, u //---------------------------------------------------------------------------- // SPURS taskset policy module functions //---------------------------------------------------------------------------- -bool spursJobChainEntry(spu_thread& spu) +bool spursJobChainEntry(spu_thread& /*spu*/) { //const auto ctxt = spu._ptr(0x4a00); //auto kernelCtxt = spu._ptr(spu.gpr[3]._u32[3]); diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellSysutil.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellSysutil.cpp index a236398..a7d15af 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellSysutil.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellSysutil.cpp @@ -580,8 +580,6 @@ error_code cellSysutilCheckCallback(ppu_thread& ppu) auto& cbm = g_fxo->get(); - bool read = false; - for (auto&& func : cbm.registered.pop_all()) { if (func.call_active && !*func.call_active) @@ -589,7 +587,11 @@ error_code cellSysutilCheckCallback(ppu_thread& ppu) continue; } - read = true; + // Increase read counter before we call the callback. + // We use this counter to check if the game reacts to a command during game termination and calls sys_process_exit. + // We would not realize that the game reacted in time and terminate it prematurely if we increased + // the counter after we called the callback and the callback did some time-consuming work. + cbm.read_counter++; if (s32 res = func.func(ppu)) { @@ -603,11 +605,6 @@ error_code cellSysutilCheckCallback(ppu_thread& ppu) } } - if (read) - { - cbm.read_counter++; - } - return CELL_OK; } diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellVdec.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellVdec.cpp index 7ba9644..4574d99 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellVdec.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellVdec.cpp @@ -1619,10 +1619,25 @@ error_code cellVdecSetFrameRate(u32 handle, CellVdecFrameRate frameRateCode) return CELL_OK; } -error_code cellVdecOpenExt() +error_code cellVdecOpenExt(ppu_thread& ppu, vm::cptr type, vm::cptr res, vm::cptr cb, vm::ptr handle) { - UNIMPLEMENTED_FUNC(cellVdec); - return CELL_OK; + cellVdec.warning("cellVdecOpenExt(type=*0x%x, res=*0x%x, cb=*0x%x, handle=*0x%x)", type, res, cb, handle); + + if (!res) + { + return CELL_VDEC_ERROR_ARG; + } + + vm::var tmp = vm::make_var({}); + 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 ptr = vm::cast(tmp.addr()); + return vdecOpen(ppu, type, ptr, cb, handle); } error_code cellVdecStartSeqExt() diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellVdec.h b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellVdec.h index e09695b..9f30b7d 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellVdec.h +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellVdec.h @@ -133,6 +133,16 @@ struct CellVdecResourceEx be_t spursResource_addr; }; +struct CellVdecResourceExt // speculative +{ + be_t memAddr; + be_t memSize; + be_t ppuThreadPriority; + be_t ppuThreadStackSize; + u8 unk[12]; + be_t numOfSpus; +}; + // Access Unit Information struct CellVdecAuInfo { diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellVideoExport.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellVideoExport.cpp index 8ee6238..8c0ed93 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellVideoExport.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellVideoExport.cpp @@ -2,7 +2,6 @@ #include "Emu/Cell/PPUModule.h" #include "Emu/IdManager.h" #include "Emu/VFS.h" -#include "Utilities/StrUtil.h" #include "cellSysutil.h" LOG_CHANNEL(cellVideoExport); diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellVideoOut.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellVideoOut.cpp index 001d725..e0db365 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellVideoOut.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellVideoOut.cpp @@ -423,7 +423,7 @@ error_code cellVideoOutGetDeviceInfo(u32 videoOut, u32 deviceIndex, vm::ptr rgbOutputRange) { cellSysutil.todo("cellVideoOutGetConvertCursorColorInfo(rgbOutputRange=*0x%x)", rgbOutputRange); diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellVoice.h b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellVoice.h index 80fac88..2b269f5 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellVoice.h +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellVoice.h @@ -1,8 +1,5 @@ #pragma once -#include -#include - // libvoice = 0x80310801 - 0x803108ff // libvoice version 100 diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellWebBrowser.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellWebBrowser.cpp index 8a9991b..7f560c9 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellWebBrowser.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellWebBrowser.cpp @@ -4,6 +4,8 @@ #include "cellWebBrowser.h" #include "Emu/IdManager.h" +#include "cellSysutil.h" + LOG_CHANNEL(cellSysutil); struct browser_info diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellWebBrowser.h b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellWebBrowser.h index 7a66f5b..6c46c58 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellWebBrowser.h +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/cellWebBrowser.h @@ -1,7 +1,5 @@ #pragma once -#include "cellSysutil.h" - #include "Emu/Memory/vm_ptr.h" //events diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/libsnd3.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/libsnd3.cpp index 0263f92..146d9ad 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/libsnd3.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/libsnd3.cpp @@ -34,308 +34,303 @@ void fmt_class_string::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 queue) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3Init(maxVoice=%d, samples=%d, queue=*0x%x)", maxVoice, samples, queue); return CELL_OK; } error_code cellSnd3Exit() { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3Exit()"); return CELL_OK; } u16 cellSnd3Note2Pitch(u16 center_note, u16 center_fine, u16 note, s16 fine) { - libsnd3.todo("cellSnd3Note2Pitch()"); + libsnd3.todo("cellSnd3Note2Pitch(center_note=%d, center_fine=%d, note=%d, fine=%d)", center_note, center_fine, note, fine); return 0; } u16 cellSnd3Pitch2Note(u16 center_note, u16 center_fine, u16 pitch) { - libsnd3.todo("cellSnd3Pitch2Note()"); + libsnd3.todo("cellSnd3Pitch2Note(center_note=%d, center_fine=%d, pitch=%d)", center_note, center_fine, pitch); return 0; } error_code cellSnd3SetOutputMode(u32 mode) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3SetOutputMode(mode=%d)", mode); return CELL_OK; } error_code cellSnd3Synthesis(vm::ptr pOutL, vm::ptr pOutR) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3Synthesis(pOutL=*0x%x, pOutR=*0x%x)", pOutL, pOutR); return CELL_OK; } error_code cellSnd3SynthesisEx(vm::ptr pOutL, vm::ptr pOutR, vm::ptr pOutRL, vm::ptr pOutRR) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3SynthesisEx(pOutL=*0x%x, pOutR=*0x%x, pOutRL=*0x%x, pOutRR=*0x%x)", pOutL, pOutR, pOutRL, pOutRR); return CELL_OK; } error_code cellSnd3BindSoundData(vm::ptr snd3Ctx, vm::ptr hd3, u32 synthMemOffset) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3BindSoundData(snd3Ctx=*0x%x, hd3=*0x%x, synthMemOffset=0x%x)", snd3Ctx, hd3, synthMemOffset); return CELL_OK; } error_code cellSnd3UnbindSoundData(u32 hd3ID) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3UnbindSoundData(hd3ID=0x%x)", hd3ID); return CELL_OK; } error_code cellSnd3NoteOnByTone(u32 hd3ID, u32 toneIndex, u32 note, u32 keyOnID, vm::ptr keyOnParam) { - libsnd3.todo("cellSnd3NoteOnByTone()"); + libsnd3.todo("cellSnd3NoteOnByTone(hd3ID=0x%x, toneIndex=%d, note=%d, keyOnID=0x%x, keyOnParam=*0x%x)", hd3ID, toneIndex, note, keyOnID, keyOnParam); return CELL_OK; } error_code cellSnd3KeyOnByTone(u32 hd3ID, u32 toneIndex, u32 pitch, u32 keyOnID, vm::ptr keyOnParam) { - libsnd3.todo("cellSnd3KeyOnByTone()"); + libsnd3.todo("cellSnd3KeyOnByTone(hd3ID=0x%x, toneIndex=%d, pitch=%d, keyOnID=0x%x, keyOnParam=*0x%x)", hd3ID, toneIndex, pitch, keyOnID, keyOnParam); return CELL_OK; } error_code cellSnd3VoiceNoteOnByTone(u32 hd3ID, u32 voiceNum, u32 toneIndex, u32 note, u32 keyOnID, vm::ptr keyOnParam) { - libsnd3.todo("cellSnd3VoiceNoteOnByTone()"); + libsnd3.todo("cellSnd3VoiceNoteOnByTone(hd3ID=0x%x, voiceNum=%d, toneIndex=%d, note=%d, keyOnID=0x%x, keyOnParam=*0x%x)", hd3ID, voiceNum, toneIndex, note, keyOnID, keyOnParam); return CELL_OK; } error_code cellSnd3VoiceKeyOnByTone(u32 hd3ID, u32 voiceNum, u32 toneIndex, u32 pitch, u32 keyOnID, vm::ptr keyOnParam) { - libsnd3.todo("cellSnd3VoiceKeyOnByTone()"); + libsnd3.todo("cellSnd3VoiceKeyOnByTone(hd3ID=0x%x, voiceNum=%d, toneIndex=%d, pitch=%d, keyOnID=0x%x, keyOnParam=*0x%x)", hd3ID, voiceNum, toneIndex, pitch, keyOnID, keyOnParam); return CELL_OK; } error_code cellSnd3VoiceSetReserveMode(u32 voiceNum, u32 reserveMode) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3VoiceSetReserveMode(voiceNum=%d, reserveMode=%d)", voiceNum, reserveMode); return CELL_OK; } error_code cellSnd3VoiceSetSustainHold(u32 voiceNum, u32 sustainHold) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3VoiceSetSustainHold(voiceNum=%d, sustainHold=%d)", voiceNum, sustainHold); return CELL_OK; } error_code cellSnd3VoiceKeyOff(u32 voiceNum) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3VoiceKeyOff(voiceNum=%d)", voiceNum); return CELL_OK; } error_code cellSnd3VoiceSetPitch(u32 voiceNum, s32 addPitch) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3VoiceSetPitch(voiceNum=%d, addPitch=%d)", voiceNum, addPitch); return CELL_OK; } error_code cellSnd3VoiceSetVelocity(u32 voiceNum, u32 velocity) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3VoiceSetVelocity(voiceNum=%d, velocity=%d)", voiceNum, velocity); return CELL_OK; } error_code cellSnd3VoiceSetPanpot(u32 voiceNum, u32 panpot) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3VoiceSetPanpot(voiceNum=%d, panpot=%d)", voiceNum, panpot); return CELL_OK; } error_code cellSnd3VoiceSetPanpotEx(u32 voiceNum, u32 panpotEx) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3VoiceSetPanpotEx(voiceNum=%d, panpotEx=%d)", voiceNum, panpotEx); return CELL_OK; } error_code cellSnd3VoiceSetPitchBend(u32 voiceNum, u32 bendValue) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3VoiceSetPitchBend(voiceNum=%d, bendValue=%d)", voiceNum, bendValue); return CELL_OK; } error_code cellSnd3VoiceAllKeyOff() { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3VoiceAllKeyOff()"); return CELL_OK; } error_code cellSnd3VoiceGetEnvelope(u32 voiceNum) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3VoiceGetEnvelope(voiceNum=%d)", voiceNum); return CELL_OK; } error_code cellSnd3VoiceGetStatus(u32 voiceNum) { - libsnd3.todo("cellSnd3VoiceGetStatus()"); + libsnd3.todo("cellSnd3VoiceGetStatus(voiceNum=%d)", voiceNum); return CELL_OK; } u32 cellSnd3KeyOffByID(u32 keyOnID) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3KeyOffByID(keyOnID=%d)", keyOnID); return CELL_OK; } error_code cellSnd3GetVoice(u32 midiChannel, u32 keyOnID, vm::ptr voiceBit) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3GetVoice(midiChannel=%d, keyOnID=%d, voiceBit=*0x%x)", midiChannel, keyOnID, voiceBit); return CELL_OK; } error_code cellSnd3GetVoiceByID(u32 ID, vm::ptr voiceBit) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3GetVoiceByID(ID=%d, voiceBit=*0x%x)", ID, voiceBit); return CELL_OK; } error_code cellSnd3NoteOn(u32 hd3ID, u32 midiChannel, u32 midiProgram, u32 midiNote, u32 sustain, vm::ptr keyOnParam, u32 keyOnID) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3NoteOn(hd3ID=%d, midiChannel=%d, midiProgram=%d, midiNote=%d, sustain=%d, keyOnParam=*0x%x, keyOnID=%d)", hd3ID, midiChannel, midiProgram, midiNote, sustain, keyOnParam, keyOnID); return CELL_OK; } error_code cellSnd3NoteOff(u32 midiChannel, u32 midiNote, u32 keyOnID) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3NoteOff(midiChannel=%d, midiNote=%d, keyOnID=%d)", midiChannel, midiNote, keyOnID); return CELL_OK; } error_code cellSnd3SetSustainHold(u32 midiChannel, u32 sustainHold, u32 keyOnID) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3SetSustainHold(midiChannel=%d, sustainHold=%d, keyOnID=%d)", midiChannel, sustainHold, keyOnID); return CELL_OK; } error_code cellSnd3SetEffectType(u16 effectType, s16 returnVol, u16 delay, u16 feedback) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3SetEffectType(effectType=%d, returnVol=%d, delay=%d, feedback=%d)", effectType, returnVol, delay, feedback); return CELL_OK; } error_code cellSnd3SMFBind(vm::ptr smfCtx, vm::ptr smf, u32 hd3ID) { - libsnd3.todo("cellSnd3SMFBind()"); + libsnd3.todo("cellSnd3SMFBind(smfCtx=*0x%x, delay=*0x%x, hd3ID=%d)", smfCtx, smf, hd3ID); return CELL_OK; } error_code cellSnd3SMFUnbind(u32 smfID) { - libsnd3.todo("cellSnd3SMFUnbind()"); + libsnd3.todo("cellSnd3SMFUnbind(smfID=%d)", smfID); return CELL_OK; } error_code cellSnd3SMFPlay(u32 smfID, u32 playVelocity, u32 playPan, u32 playCount) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3SMFPlay(smfID=%d, playVelocity=%d, playPan=%d, playCount=%d)", smfID, playVelocity, playPan, playCount); return CELL_OK; } error_code cellSnd3SMFPlayEx(u32 smfID, u32 playVelocity, u32 playPan, u32 playPanEx, u32 playCount) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3SMFPlayEx(smfID=%d, playVelocity=%d, playPan=%d, playPanEx=%d, playCount=%d)", smfID, playVelocity, playPan, playPanEx, playCount); return CELL_OK; } error_code cellSnd3SMFPause(u32 smfID) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3SMFPause(smfID=%d)", smfID); return CELL_OK; } error_code cellSnd3SMFResume(u32 smfID) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3SMFResume(smfID=%d)", smfID); return CELL_OK; } error_code cellSnd3SMFStop(u32 smfID) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3SMFStop(smfID=%d)", smfID); return CELL_OK; } error_code cellSnd3SMFAddTempo(u32 smfID, s32 addTempo) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3SMFAddTempo(smfID=%d, addTempo=%d)", smfID, addTempo); return CELL_OK; } error_code cellSnd3SMFGetTempo(u32 smfID) { - libsnd3.todo("cellSnd3SMFGetTempo()"); + libsnd3.todo("cellSnd3SMFGetTempo(smfID=%d)", smfID); return CELL_OK; } error_code cellSnd3SMFSetPlayVelocity(u32 smfID, u32 playVelocity) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3SMFSetPlayVelocity(smfID=%d, playVelocity=%d)", smfID, playVelocity); return CELL_OK; } error_code cellSnd3SMFGetPlayVelocity(u32 smfID) { - libsnd3.todo("cellSnd3SMFGetPlayVelocity()"); + libsnd3.todo("cellSnd3SMFGetPlayVelocity(smfID=%d)", smfID); return CELL_OK; } error_code cellSnd3SMFSetPlayPanpot(u32 smfID, u32 playPanpot) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3SMFSetPlayPanpot(smfID=%d, playPanpot=%d)", smfID, playPanpot); return CELL_OK; } error_code cellSnd3SMFSetPlayPanpotEx(u32 smfID, u32 playPanpotEx) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3SMFSetPlayPanpotEx(smfID=%d, playPanpotEx=%d)", smfID, playPanpotEx); return CELL_OK; } error_code cellSnd3SMFGetPlayPanpot(u32 smfID) { - libsnd3.todo("cellSnd3SMFGetPlayPanpot()"); + libsnd3.todo("cellSnd3SMFGetPlayPanpot(smfID=%d)", smfID); return CELL_OK; } error_code cellSnd3SMFGetPlayPanpotEx(u32 smfID) { - libsnd3.todo("cellSnd3SMFGetPlayPanpotEx()"); + libsnd3.todo("cellSnd3SMFGetPlayPanpotEx(smfID=%d)", smfID); return CELL_OK; } error_code cellSnd3SMFGetPlayStatus(u32 smfID) { - libsnd3.todo("cellSnd3SMFGetPlayStatus()"); + libsnd3.todo("cellSnd3SMFGetPlayStatus(smfID=%d)", smfID); return CELL_OK; } error_code cellSnd3SMFSetPlayChannel(u32 smfID, u32 playChannelBit) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3SMFSetPlayChannel(smfID=%d, playChannelBit=%d)", smfID, playChannelBit); return CELL_OK; } error_code cellSnd3SMFGetPlayChannel(u32 smfID, vm::ptr playChannelBit) { - libsnd3.todo("cellSnd3SMFGetPlayChannel()"); + libsnd3.todo("cellSnd3SMFGetPlayChannel(smfID=%d, playChannelBit=*0x%x)", smfID, playChannelBit); return CELL_OK; } error_code cellSnd3SMFGetKeyOnID(u32 smfID, u32 midiChannel, vm::ptr keyOnID) { - UNIMPLEMENTED_FUNC(libsnd3); + libsnd3.todo("cellSnd3SMFAddTempo(smfID=%d, midiChannel=%d, keyOnID=*0x%x)", smfID, midiChannel, keyOnID); return CELL_OK; } diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sceNp.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sceNp.cpp index c0224ae..9a8e0db 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sceNp.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sceNp.cpp @@ -1,11 +1,9 @@ #include "stdafx.h" #include "Emu/System.h" #include "Emu/system_utils.hpp" -#include "Emu/VFS.h" #include "Emu/Cell/PPUModule.h" #include "Emu/Cell/Modules/cellUserInfo.h" #include "Emu/Io/interception.h" -#include "Emu/NP/signaling_handler.h" #include "Utilities/StrUtil.h" #include "sysPrxForUser.h" @@ -16,6 +14,7 @@ #include "sceNp.h" #include "cellSysutil.h" +#include "Emu/Cell/timers.hpp" #include "Emu/Cell/lv2/sys_time.h" #include "Emu/Cell/lv2/sys_fs.h" #include "Emu/Cell/lv2/sys_sync.h" @@ -23,6 +22,7 @@ #include "Emu/NP/np_contexts.h" #include "Emu/NP/np_helpers.h" #include "Emu/NP/np_structs_extra.h" +#include "Emu/NP/signaling_handler.h" #include "Emu/system_config.h" #include "Emu/RSX/Overlays/overlay_manager.h" diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp index 070ed17..3c7c1af 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp @@ -592,7 +592,6 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle, // open trophy pack file std::string trp_path = vfs::get(Emu.GetDir() + "TROPDIR/" + ctxt->trp_name + "/TROPHY.TRP"); - fs::file stream; if(Emu.GetIsoFs()&&trp_path[0]==':') stream=fs::file(*Emu.GetIsoFs(), trp_path); @@ -721,9 +720,9 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle, lock2.unlock(); - struct register_context_thread : register_context_thread_name + lv2_obj::sleep(ppu); { - void operator()(s32 progress_cb_count, u32 context, vm::ptr statusCb, vm::ptr arg) const + const s32 progress_cb_count = ::narrow(tropusr->GetTrophiesCount()) - 1; { // This emulates vsh sending the events and ensures that not 2 events are processed at once const std::pair statuses[] = @@ -737,6 +736,13 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle, // Create a counter which is destroyed after the function ends const auto queued = std::make_shared>(0); + u32 total_events = 0; + + for (auto status : statuses) + { + total_events += status.second + 1; + } + for (auto status : statuses) { for (s32 completed = 0; completed <= status.second; completed++) @@ -759,8 +765,9 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle, u64 current = get_system_time(); - const u64 until_max = current + 300'000; - const u64 until_min = current + 100'000; + // Minimum register trophy time 2 seconds globally. + const u64 until_min = current + (2'000'000 / total_events); + const u64 until_max = until_min + 50'000; // If too much time passes just send the rest of the events anyway for (u32 old_value = *queued; current < (old_value ? until_max : until_min); @@ -777,19 +784,13 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle, if (thread_ctrl::state() == thread_state::aborting) { - return; + return {}; } } } } } - }; - - lv2_obj::sleep(ppu); - - g_fxo->get>()(::narrow(tropusr->GetTrophiesCount()) - 1, context, statusCb, arg); - - thread_ctrl::wait_for(200'000); + } return CELL_OK; } diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_heap.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_heap.cpp index a502e26..c0ba4fb 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_heap.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_heap.cpp @@ -2,8 +2,6 @@ #include "Emu/IdManager.h" #include "Emu/Cell/PPUModule.h" -#include "sysPrxForUser.h" - LOG_CHANNEL(sysPrxForUser); struct HeapInfo diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_lv2dbg.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_lv2dbg.cpp index 2e13cf7..c9bb020 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_lv2dbg.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_lv2dbg.cpp @@ -65,38 +65,33 @@ void fmt_class_string::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 ppu_context) { - sys_lv2dbg.todo("sys_dbg_read_ppu_thread_context()"); + sys_lv2dbg.todo("sys_dbg_read_ppu_thread_context(id=0x%x, ppu_context=*0x%x)", id, ppu_context); return CELL_OK; } error_code sys_dbg_read_spu_thread_context(u32 id, vm::ptr spu_context) { - sys_lv2dbg.todo("sys_dbg_read_spu_thread_context()"); + sys_lv2dbg.todo("sys_dbg_read_spu_thread_context(id=0x%x, spu_context=*0x%x)", id, spu_context); return CELL_OK; } error_code sys_dbg_read_spu_thread_context2(u32 id, vm::ptr spu_context) { - sys_lv2dbg.todo("sys_dbg_read_spu_thread_context2()"); + sys_lv2dbg.todo("sys_dbg_read_spu_thread_context2(id=0x%x, spu_context=*0x%x)", id, spu_context); return CELL_OK; } error_code sys_dbg_set_stacksize_ppu_exception_handler(u32 stacksize) { - sys_lv2dbg.todo("sys_dbg_set_stacksize_ppu_exception_handler()"); + sys_lv2dbg.todo("sys_dbg_set_stacksize_ppu_exception_handler(stacksize=0x%x)", stacksize); return CELL_OK; } error_code sys_dbg_initialize_ppu_exception_handler(s32 prio) { - sys_lv2dbg.todo("sys_dbg_initialize_ppu_exception_handler()"); + sys_lv2dbg.todo("sys_dbg_initialize_ppu_exception_handler(prio=0x%x)", prio); return CELL_OK; } @@ -108,7 +103,7 @@ error_code sys_dbg_finalize_ppu_exception_handler() error_code sys_dbg_register_ppu_exception_handler(vm::ptr callback, u64 ctrl_flags) { - sys_lv2dbg.todo("sys_dbg_register_ppu_exception_handler()"); + sys_lv2dbg.todo("sys_dbg_register_ppu_exception_handler(callback=*0x%x, ctrl_flags=0x%x)", callback, ctrl_flags); return CELL_OK; } @@ -120,170 +115,163 @@ error_code sys_dbg_unregister_ppu_exception_handler() error_code sys_dbg_signal_to_ppu_exception_handler(u64 flags) { - sys_lv2dbg.todo("sys_dbg_signal_to_ppu_exception_handler()"); + sys_lv2dbg.todo("sys_dbg_signal_to_ppu_exception_handler(flags=0x%x)", flags); return CELL_OK; } error_code sys_dbg_get_mutex_information(u32 id, vm::ptr info) { - sys_lv2dbg.todo("sys_dbg_get_mutex_information()"); + sys_lv2dbg.todo("sys_dbg_get_mutex_information(id=0x%x, info=*0x%x)", id, info); return CELL_OK; } error_code sys_dbg_get_cond_information(u32 id, vm::ptr info) { - sys_lv2dbg.todo("sys_dbg_get_cond_information()"); + sys_lv2dbg.todo("sys_dbg_get_cond_information(id=0x%x, info=*0x%x)", id, info); return CELL_OK; } error_code sys_dbg_get_rwlock_information(u32 id, vm::ptr info) { - sys_lv2dbg.todo("sys_dbg_get_rwlock_information()"); + sys_lv2dbg.todo("sys_dbg_get_rwlock_information(id=0x%x, info=*0x%x)", id, info); return CELL_OK; } error_code sys_dbg_get_event_queue_information(u32 id, vm::ptr info) { - sys_lv2dbg.todo("sys_dbg_get_event_queue_information()"); + sys_lv2dbg.todo("sys_dbg_get_event_queue_information(id=0x%x, info=*0x%x)", id, info); return CELL_OK; } error_code sys_dbg_get_semaphore_information(u32 id, vm::ptr info) { - sys_lv2dbg.todo("sys_dbg_get_semaphore_information()"); + sys_lv2dbg.todo("sys_dbg_get_semaphore_information(id=0x%x, info=*0x%x)", id, info); return CELL_OK; } error_code sys_dbg_get_lwmutex_information(u32 id, vm::ptr info) { - sys_lv2dbg.todo("sys_dbg_get_lwmutex_information()"); + sys_lv2dbg.todo("sys_dbg_get_lwmutex_information(id=0x%x, info=*0x%x)", id, info); return CELL_OK; } error_code sys_dbg_get_lwcond_information(u32 id, vm::ptr info) { - sys_lv2dbg.todo("sys_dbg_get_lwcond_information()"); + sys_lv2dbg.todo("sys_dbg_get_lwcond_information(id=0x%x, info=*0x%x)", id, info); return CELL_OK; } error_code sys_dbg_get_event_flag_information(u32 id, vm::ptr info) { - sys_lv2dbg.todo("sys_dbg_get_event_flag_information()"); + sys_lv2dbg.todo("sys_dbg_get_event_flag_information(id=0x%x, info=*0x%x)", id, info); return CELL_OK; } error_code sys_dbg_get_ppu_thread_ids(vm::ptr ids, vm::ptr ids_num, vm::ptr all_ids_num) { - sys_lv2dbg.todo("sys_dbg_get_ppu_thread_ids()"); + sys_lv2dbg.todo("sys_dbg_get_ppu_thread_ids(ids=*0x%x, ids_num=*0x%x, all_ids_num=*0x%x)", ids, ids_num, all_ids_num); return CELL_OK; } error_code sys_dbg_get_spu_thread_group_ids(vm::ptr ids, vm::ptr ids_num, vm::ptr all_ids_num) { - sys_lv2dbg.todo("sys_dbg_get_spu_thread_group_ids()"); + sys_lv2dbg.todo("sys_dbg_get_spu_thread_group_ids(ids=*0x%x, ids_num=*0x%x, all_ids_num=*0x%x)", ids, ids_num, all_ids_num); return CELL_OK; } error_code sys_dbg_get_spu_thread_ids(u32 group_id, vm::ptr ids, vm::ptr ids_num, vm::ptr all_ids_num) { - sys_lv2dbg.todo("sys_dbg_get_spu_thread_ids()"); + sys_lv2dbg.todo("sys_dbg_get_spu_thread_ids(group_id=0x%x, ids=*0x%x, ids_num=*0x%x, all_ids_num=*0x%x)", group_id, ids, ids_num, all_ids_num); return CELL_OK; } error_code sys_dbg_get_ppu_thread_name(u64 id, vm::ptr name) { - sys_lv2dbg.todo("sys_dbg_get_ppu_thread_name()"); + sys_lv2dbg.todo("sys_dbg_get_ppu_thread_name(id=0x%x, name=*0x%x)", id, name); return CELL_OK; } error_code sys_dbg_get_spu_thread_name(u32 id, vm::ptr name) { - sys_lv2dbg.todo("sys_dbg_get_spu_thread_name()"); + sys_lv2dbg.todo("sys_dbg_get_spu_thread_name(id=0x%x, name=*0x%x)", id, name); return CELL_OK; } error_code sys_dbg_get_spu_thread_group_name(u32 id, vm::ptr name) { - sys_lv2dbg.todo("sys_dbg_get_spu_thread_group_name()"); + sys_lv2dbg.todo("sys_dbg_get_spu_thread_group_name(id=0x%x, name=*0x%x)", id, name); return CELL_OK; } - error_code sys_dbg_get_ppu_thread_status(u64 id, vm::ptr status) { - sys_lv2dbg.todo("sys_dbg_get_ppu_thread_status()"); + sys_lv2dbg.todo("sys_dbg_get_ppu_thread_status(id=0x%x, status=*0x%x)", id, status); return CELL_OK; } error_code sys_dbg_get_spu_thread_group_status(u32 id, vm::ptr status) { - sys_lv2dbg.todo("sys_dbg_get_spu_thread_group_status()"); + sys_lv2dbg.todo("sys_dbg_get_spu_thread_group_status(id=0x%x, status=*0x%x)", id, status); return CELL_OK; } - error_code sys_dbg_enable_floating_point_enabled_exception(u64 id, u64 flags, u64 opt1, u64 opt2) { - sys_lv2dbg.todo("sys_dbg_enable_floating_point_enabled_exception()"); + sys_lv2dbg.todo("sys_dbg_enable_floating_point_enabled_exception(id=0x%x, flags=0x%x, opt1=0x%x, opt2=0x%x)", id, flags, opt1, opt2); return CELL_OK; } error_code sys_dbg_disable_floating_point_enabled_exception(u64 id, u64 flags, u64 opt1, u64 opt2) { - sys_lv2dbg.todo("sys_dbg_disable_floating_point_enabled_exception()"); + sys_lv2dbg.todo("sys_dbg_disable_floating_point_enabled_exception(id=0x%x, flags=0x%x, opt1=0x%x, opt2=0x%x)", id, flags, opt1, opt2); return CELL_OK; } - error_code sys_dbg_vm_get_page_information(u32 addr, u32 num, vm::ptr pageinfo) { - sys_lv2dbg.todo("sys_dbg_vm_get_page_information()"); + sys_lv2dbg.todo("sys_dbg_vm_get_page_information(addr=0x%x, num=0x%x, pageinfo=*0x%x)", addr, num, pageinfo); return CELL_OK; } - error_code sys_dbg_set_address_to_dabr(u64 addr, u64 ctrl_flag) { - sys_lv2dbg.todo("sys_dbg_set_address_to_dabr()"); + sys_lv2dbg.todo("sys_dbg_set_address_to_dabr(addr=0x%x, spu_context=0x%x)", addr, ctrl_flag); return CELL_OK; } error_code sys_dbg_get_address_from_dabr(vm::ptr addr, vm::ptr ctrl_flag) { - sys_lv2dbg.todo("sys_dbg_get_address_from_dabr()"); + sys_lv2dbg.todo("sys_dbg_get_address_from_dabr(addr=*0x%x, spu_context=*0x%x)", addr, ctrl_flag); return CELL_OK; } - error_code sys_dbg_signal_to_coredump_handler(u64 data1, u64 data2, u64 data3) { - sys_lv2dbg.todo("sys_dbg_signal_to_coredump_handler()"); + sys_lv2dbg.todo("sys_dbg_signal_to_coredump_handler(data1=0x%x, data2=0x%x, data3=0x%x)", data1, data2, data3); return CELL_OK; } - error_code sys_dbg_mat_set_condition(u32 addr, u64 cond) { - sys_lv2dbg.todo("sys_dbg_mat_set_condition()"); + sys_lv2dbg.todo("sys_dbg_mat_set_condition(addr=0x%x, cond=0x%x)", addr, cond); return CELL_OK; } error_code sys_dbg_mat_get_condition(u32 addr, vm::ptr condp) { - sys_lv2dbg.todo("sys_dbg_mat_get_condition()"); + sys_lv2dbg.todo("sys_dbg_mat_get_condition(addr=0x%x, condp=*0x%x)", addr, condp); return CELL_OK; } - error_code sys_dbg_get_coredump_params(vm::ptr param) { - sys_lv2dbg.todo("sys_dbg_get_coredump_params()"); + sys_lv2dbg.todo("sys_dbg_get_coredump_params(param=*0x%x)", param); return CELL_OK; } error_code sys_dbg_set_mask_to_ppu_exception_handler(u64 mask, u64 flags) { - sys_lv2dbg.todo("sys_dbg_set_mask_to_ppu_exception_handler()"); + sys_lv2dbg.todo("sys_dbg_set_mask_to_ppu_exception_handler(mask=0x%x, flags=0x%x)", mask, flags); return CELL_OK; } diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_lwmutex_.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_lwmutex_.cpp index a9ec0b5..098761b 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_lwmutex_.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_lwmutex_.cpp @@ -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" diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_mempool.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_mempool.cpp index b7ffa72..2446619 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_mempool.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_mempool.cpp @@ -7,8 +7,6 @@ #include "Emu/Cell/lv2/sys_mutex.h" #include "Emu/Cell/lv2/sys_cond.h" -#include "sysPrxForUser.h" - LOG_CHANNEL(sysPrxForUser); using sys_mempool_t = u32; diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_net_.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_net_.cpp index f566bd2..affca67 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_net_.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_net_.cpp @@ -1,16 +1,9 @@ #include "stdafx.h" #include "Emu/Cell/PPUModule.h" -#include "Emu/IdManager.h" - #include "sys_net_.h" LOG_CHANNEL(libnet); -// Temporarily -#ifndef _MSC_VER -#pragma GCC diagnostic ignored "-Wunused-parameter" -#endif - s32 sys_net_accept(s32 s, vm::ptr addr, vm::ptr paddrlen) { libnet.todo("accept(s=%d, addr=*0x%x, paddrlen=*0x%x)", s, addr, paddrlen); @@ -46,19 +39,22 @@ s32 sys_net_gethostbyname() s32 sys_net_getpeername(s32 s, vm::ptr addr, vm::ptr paddrlen) { - UNIMPLEMENTED_FUNC(libnet); + libnet.todo("getpeername(s=%d, addr=*0x%x, paddrlen=*0x%x)", s, addr, paddrlen); + return CELL_OK; } s32 sys_net_getsockname(s32 s, vm::ptr addr, vm::ptr paddrlen) { - UNIMPLEMENTED_FUNC(libnet); + libnet.todo("getsockname(s=%d, addr=*0x%x, paddrlen=*0x%x)", s, addr, paddrlen); + return CELL_OK; } s32 sys_net_getsockopt(s32 s, s32 level, s32 optname, vm::ptr optval, vm::ptr optlen) { - UNIMPLEMENTED_FUNC(libnet); + libnet.todo("getsockopt(s=%d, level=%d, optname=%d, optval=*0x%x, optlen=*0x%x)", s, level, optname, optval, optlen); + return CELL_OK; } @@ -143,7 +139,8 @@ s32 sys_net_recvfrom(s32 s, vm::ptr buf, u32 len, s32 flags, vm::ptr msg, s32 flags) { - UNIMPLEMENTED_FUNC(libnet); + libnet.todo("recvmsg(s=%d, msg=*0x%x, flags=0x%x)", s, msg, flags); + return CELL_OK; } @@ -156,7 +153,8 @@ s32 sys_net_send(s32 s, vm::cptr buf, u32 len, s32 flags) s32 sys_net_sendmsg(s32 s, vm::cptr msg, s32 flags) { - UNIMPLEMENTED_FUNC(libnet); + libnet.todo("sendmsg(s=%d, msg=*0x%x, flags=0x%x)", s, msg, flags); + return CELL_OK; } @@ -197,7 +195,8 @@ s32 sys_net_socketclose(s32 s) s32 sys_net_socketpoll(vm::ptr fds, s32 nfds, s32 ms) { - UNIMPLEMENTED_FUNC(libnet); + libnet.todo("socketpoll(fds=*0x%x, nfds=%d, ms=%d)", fds, nfds, ms); + return CELL_OK; } @@ -272,7 +271,8 @@ s32 sys_net_get_sockinfo(s32 s, vm::ptr p, s32 n) s32 sys_net_close_dump(s32 id, vm::ptr pflags) { - UNIMPLEMENTED_FUNC(libnet); + libnet.todo("sys_net_close_dump(id=%d, pflags=*0x%x)", id, pflags); + return CELL_OK; } @@ -310,7 +310,8 @@ s32 sys_net_show_route() s32 sys_net_read_dump(s32 id, vm::ptr buf, s32 len, vm::ptr pflags) { - UNIMPLEMENTED_FUNC(libnet); + libnet.todo("sys_net_read_dump(id=%d, buf=*0x%x, len=%d, pflags=*0x%x)", id, buf, len, pflags); + return CELL_OK; } @@ -346,7 +347,8 @@ s32 sys_net_get_sockinfo_ex() s32 sys_net_open_dump(s32 len, s32 flags) { - UNIMPLEMENTED_FUNC(libnet); + libnet.todo("sys_net_open_dump(len=%d, flags=0x%x)", len, flags); + return CELL_OK; } diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_net_.h b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_net_.h index c49a65e..9ee344b 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_net_.h +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_net_.h @@ -1,7 +1,6 @@ #pragma once #include "Emu/Cell/lv2/sys_net.h" -#include "Emu/Memory/vm.h" struct sys_net_sockinfo_t { diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_ppu_thread_.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_ppu_thread_.cpp index cb3f5f6..033242e 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_ppu_thread_.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_ppu_thread_.cpp @@ -1,7 +1,5 @@ #include "stdafx.h" #include "Emu/Cell/PPUModule.h" -#include "Emu/IdManager.h" - #include "Emu/Cell/lv2/sys_ppu_thread.h" #include "Emu/Cell/lv2/sys_interrupt.h" #include "Emu/Cell/lv2/sys_lwmutex.h" diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_rsxaudio_.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_rsxaudio_.cpp index d686345..071a9de 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_rsxaudio_.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_rsxaudio_.cpp @@ -1,8 +1,6 @@ #include "stdafx.h" #include "Emu/Cell/PPUModule.h" -#include "sysPrxForUser.h" - LOG_CHANNEL(sysPrxForUser); error_code sys_rsxaudio_close_connection() diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_spinlock.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_spinlock.cpp index e499980..00a71de 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_spinlock.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_spinlock.cpp @@ -1,8 +1,6 @@ #include "stdafx.h" #include "Emu/Cell/PPUModule.h" -#include "sysPrxForUser.h" - LOG_CHANNEL(sysPrxForUser); void sys_spinlock_initialize(vm::ptr> lock) diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_spu_.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_spu_.cpp index 2c584a7..2bbbaee 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_spu_.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/Modules/sys_spu_.cpp @@ -3,7 +3,6 @@ #include "Emu/Cell/PPUModule.h" #include "Emu/Cell/lv2/sys_spu.h" -#include "Crypto/unself.h" #include "Loader/ELF.h" #include "sysPrxForUser.h" diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/PPUAnalyser.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/PPUAnalyser.cpp index 808c31f..56d4398 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/PPUAnalyser.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/PPUAnalyser.cpp @@ -532,7 +532,7 @@ namespace ppu_patterns } static constexpr struct const_tag{} is_const; -static constexpr struct range_tag{} is_range; +/*static constexpr*/ struct range_tag{} /*is_range*/; static constexpr struct min_value_tag{} minv; static constexpr struct max_value_tag{} maxv; static constexpr struct sign_bit_tag{} sign_bitv; @@ -2361,7 +2361,9 @@ bool ppu_module::analyse(u32 lib_toc, u32 entry, const u32 sec_end, con } case ppu_itype::MTSPR: { - switch (const u32 n = (op.spr >> 5) | ((op.spr & 0x1f) << 5)) + const u32 spr_idx = (op.spr >> 5) | ((op.spr & 0x1f) << 5); + + switch (spr_idx) { case 0x001: // MTXER { @@ -2459,7 +2461,6 @@ bool ppu_module::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)) { diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/PPUFunction.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/PPUFunction.cpp index 5ac681d..1cc1544 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/PPUFunction.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/PPUFunction.cpp @@ -1902,8 +1902,9 @@ auto gen_ghc_cpp_trampoline(ppu_intrp_func_t fn_target) // Take second ghc arg c.mov(args[0], x86::rbp); c.mov(args[2].r32(), x86::dword_ptr(args[0], ::offset32(&ppu_thread::cia))); - c.add(args[2], x86::qword_ptr(reinterpret_cast(&vm::g_base_addr))); - c.jmp(fn_target); + c.movabs(args[1], reinterpret_cast(&vm::g_base_addr)); + c.add(args[2], x86::qword_ptr(args[1])); + c.jmp(Imm(fn_target)); }; } diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/PPUFunction.h b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/PPUFunction.h index f8e02f2..a42ae12 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/PPUFunction.h +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/PPUFunction.h @@ -192,13 +192,13 @@ namespace ppu_func_detail const u32 v_count = (info.last_value >> 24); // TODO: check calculations - const bool is_float = std::is_floating_point_v; - const bool is_vector = std::is_same_v, v128>; - const bool is_context = std::is_base_of_v, ppu_thread>; - const bool is_variadic = std::is_same_v, ppu_va_args_t>; - const bool is_general = !is_float && !is_vector && !is_context && !is_variadic; + constexpr bool is_float = std::is_floating_point_v; + constexpr bool is_vector = std::is_same_v, v128>; + constexpr bool is_context = std::is_base_of_v, ppu_thread>; + constexpr bool is_variadic = std::is_same_v, ppu_va_args_t>; + constexpr bool is_general = !is_float && !is_vector && !is_context && !is_variadic; - const arg_class t = + constexpr arg_class t = is_general ? (g_count >= 8 ? ARG_STACK : ARG_GENERAL) : is_float ? (f_count >= 13 ? ARG_STACK : ARG_FLOAT) : is_vector ? (v_count >= 12 ? ARG_STACK : ARG_VECTOR) : @@ -206,9 +206,9 @@ namespace ppu_func_detail is_variadic ? ARG_VARIADIC : ARG_UNKNOWN; - const u32 g = g_count + (is_general || is_float ? 1 : is_vector ? (g_count & 1) + 2 : 0); - const u32 f = f_count + is_float; - const u32 v = v_count + is_vector; + constexpr u32 g = g_count + (is_general || is_float ? 1 : is_vector ? (g_count & 1) + 2 : 0); + constexpr u32 f = f_count + is_float; + constexpr u32 v = v_count + is_vector; return call(ppu, func, arg_info_pack_t{}); } @@ -218,9 +218,9 @@ namespace ppu_func_detail { static_assert(!std::is_pointer_v, "Invalid function result type (pointer)"); static_assert(!std::is_reference_v, "Invalid function result type (reference)"); - static const bool is_float = std::is_floating_point_v; - static const bool is_vector = std::is_same_v, v128>; - static const arg_class value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL); + static constexpr bool is_float = std::is_floating_point_v; + static constexpr bool is_vector = std::is_same_v, v128>; + static constexpr arg_class value = is_float ? ARG_FLOAT : (is_vector ? ARG_VECTOR : ARG_GENERAL); }; template struct func_binder; diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/PPUModule.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/PPUModule.cpp index 2c3b958..eca1177 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/PPUModule.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/PPUModule.cpp @@ -1171,7 +1171,9 @@ static void ppu_check_patch_spu_images(const ppu_module& mod, const ppu auto find_first_of_multiple = [](std::string_view data, std::initializer_list values, usz index) { - u32 pos = static_cast(data.size()); + u32 pos = umax; + + ensure(data.size() <= pos && index <= data.size()); for (std::string_view value : values) { @@ -1191,65 +1193,74 @@ static void ppu_check_patch_spu_images(const ppu_module& mod, const ppu u32 prev_bound = 0; - for (u32 i = find_first_of_multiple(seg_view, prefixes, 0); i < seg.size; i = find_first_of_multiple(seg_view, prefixes, utils::align(i + 1, 4))) + for (u32 prefix_addr = find_first_of_multiple(seg_view, prefixes, 0); prefix_addr < seg.size; prefix_addr = find_first_of_multiple(seg_view, prefixes, prefix_addr + 4)) { - const auto elf_header = ensure(mod.get_ptr(seg.addr + i)); + const auto elf_header = ensure(mod.get_ptr(seg.addr + prefix_addr)); - if (i % 4 == 0 && std::memcmp(elf_header, "\x24\0\x40\x80", 4) == 0) + if (std::memcmp(elf_header, "\x24\0\x40\x80", 4) == 0) { - bool next = true; - const u32 old_i = i; - u32 guid_start = umax, guid_end = umax; + const u32 old_prefix_addr = prefix_addr; - for (u32 search = i & -128, tries = 10; tries && search >= prev_bound; tries--, search = utils::sub_saturate(search, 128)) + auto search_guid_pattern = [&](u32 index, std::string_view data_span, s32 advance_index, u32 lower_bound, u32 uppper_bound) -> u32 { - if (seg_view[search] != 0x42 && seg_view[search] != 0x43) + for (u32 search = index & -16, tries = 16 * 64; tries && search >= lower_bound && search < uppper_bound; tries = tries - 1, search = advance_index < 0 ? utils::sub_saturate(search, 0 - advance_index) : search + advance_index) { - continue; - } - - const u32 inst1 = read_from_ptr>(seg_view, search); - const u32 inst2 = read_from_ptr>(seg_view, search + 4); - const u32 inst3 = read_from_ptr>(seg_view, search + 8); - const u32 inst4 = read_from_ptr>(seg_view, search + 12); - - if ((inst1 & 0xfe'00'00'7f) != 0x42000002 || (inst2 & 0xfe'00'00'7f) != 0x42000002 || (inst3 & 0xfe'00'00'7f) != 0x42000002 || (inst4 & 0xfe'00'00'7f) != 0x42000002) - { - continue; - } - - guid_start = search + seg.addr; - i = search; - next = false; - break; - } - - if (next) - { - continue; - } - - std::string_view ls_segment = seg_view.substr(i); - - // Bound to a bit less than LS size - ls_segment = ls_segment.substr(0, 0x38000); - - for (u32 addr_last = 0, valid_count = 0, invalid_count = 0;;) - { - const u32 instruction = static_cast(ls_segment.find("\x24\0\x40\x80"sv, addr_last)); - - if (instruction != umax) - { - if (instruction % 4 != i % 4) + if (seg_view[search] != 0x42 && seg_view[search] != 0x43) { - // Unaligned, continue - addr_last = instruction + (i % 4 - instruction % 4) % 4; continue; } - // FIXME: This seems to terminate SPU code prematurely in some cases - // Likely due to absolute branches - if (spu_thread::is_exec_code(instruction, {reinterpret_cast(ls_segment.data()), ls_segment.size()}, 0)) + const u32 inst1 = read_from_ptr>(data_span, search); + const u32 inst2 = read_from_ptr>(data_span, search + 4); + const u32 inst3 = read_from_ptr>(data_span, search + 8); + const u32 inst4 = read_from_ptr>(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(data_span.data()), data_span.size()}, 0, true, true)) + { + continue; + } + + return search; + } + + return umax; + }; + + prefix_addr = search_guid_pattern(prefix_addr, seg_view, -16, prev_bound, seg.size); + + if (prefix_addr == umax) + { + prefix_addr = old_prefix_addr; + continue; + } + + u32 guid_start = seg.addr + prefix_addr, guid_end = umax; + + std::string_view ls_segment = seg_view.substr(prefix_addr); + + // Bound to a bit less than LS size + ls_segment = ls_segment.substr(0, SPU_LS_SIZE - 0x8000); + + for (u32 addr_last = 0, valid_count = 0, invalid_count = 0;;) + { + const u32 instruction = std::min(search_guid_pattern(addr_last, ls_segment, +16, 0, ::size32(ls_segment)), find_first_of_multiple(ls_segment, prefixes, addr_last)); + + if (instruction != umax && std::memcmp(ls_segment.data() + instruction, "\x24\0\x40\x80", 4) == 0) + { + if (instruction % 4 != prefix_addr % 4) + { + // Unaligned, continue + addr_last = instruction + (prefix_addr % 4 - instruction % 4) % 4; + continue; + } + + // Check execution compatibility + if (spu_thread::is_exec_code(instruction, {reinterpret_cast(ls_segment.data()), ls_segment.size()}, 0, true, true)) { addr_last = instruction + 4; valid_count++; @@ -1270,8 +1281,7 @@ static void ppu_check_patch_spu_images(const ppu_module& mod, const ppu if (addr_last >= 0x80 && valid_count >= 2) { - const u32 begin = i & -128; - u32 end = std::min(seg.size, utils::align(i + addr_last + 256, 128)); + u32 end = std::min({instruction, seg.size - prefix_addr, utils::align(addr_last + 256, 128)}); u32 guessed_ls_addr = 0; @@ -1279,12 +1289,12 @@ static void ppu_check_patch_spu_images(const ppu_module& mod, const ppu // ILA R2, PC + 8 // BIE/BID R2 - for (u32 found = 0, last_vaddr = 0, it = begin + 16; it < end - 16; it += 4) + for (u32 found = 0, last_vaddr = 0, it = 16; it < end - 16; it += 4) { - const u32 inst1 = read_from_ptr>(seg_view, it); - const u32 inst2 = read_from_ptr>(seg_view, it + 4); - const u32 inst3 = read_from_ptr>(seg_view, it + 8); - const u32 inst4 = read_from_ptr>(seg_view, it + 12); + const u32 inst1 = read_from_ptr>(ls_segment, it); + const u32 inst2 = read_from_ptr>(ls_segment, it + 4); + const u32 inst3 = read_from_ptr>(ls_segment, it + 8); + const u32 inst4 = read_from_ptr>(ls_segment, it + 12); if ((inst1 & 0xfe'00'00'7f) == 0x42000002 && (inst2 & 0xfe'00'00'7f) == 0x42000002 && (inst3 & 0xfe'00'00'7f) == 0x42000002 && (inst4 & 0xfe'00'00'7f) == 0x42000002) { @@ -1298,7 +1308,7 @@ static void ppu_check_patch_spu_images(const ppu_module& mod, const ppu { const u32 addr_inst = (inst1 >> 7) % 0x40000; - if (u32 addr_seg = addr_inst - std::min(it + 8 - begin, addr_inst)) + if (u32 addr_seg = addr_inst - std::min(it + 8, addr_inst)) { if (last_vaddr != addr_seg) { @@ -1321,23 +1331,27 @@ static void ppu_check_patch_spu_images(const ppu_module& mod, const ppu if (guessed_ls_addr) { - end = begin + std::min(end - begin, SPU_LS_SIZE - guessed_ls_addr); + end = prefix_addr + std::min(end, SPU_LS_SIZE - guessed_ls_addr); + } + else + { + end = prefix_addr + std::min(end, SPU_LS_SIZE); } - ppu_log.success("Found valid roaming SPU code at 0x%x..0x%x (guessed_ls_addr=0x%x, GUID=0x%05x..0x%05x)", seg.addr + begin, seg.addr + end, guessed_ls_addr, guid_start, guid_end); + ppu_log.success("Found valid roaming SPU code at 0x%x..0x%x (guessed_ls_addr=0x%x, GUID=0x%05x..0x%05x)", seg.addr + prefix_addr, seg.addr + end, guessed_ls_addr, guid_start, guid_end); if (!is_firmware && _main == &mod) { // Siginify that the base address is unknown by passing 0 - utilize_spu_data_segment(guessed_ls_addr ? guessed_ls_addr : 0x4000, seg_view.data() + begin, end - begin); + utilize_spu_data_segment(guessed_ls_addr ? guessed_ls_addr : 0x4000, seg_view.data() + prefix_addr, end - prefix_addr); } - i = std::max(end, i + 4) - 4; - prev_bound = i + 4; + prefix_addr = std::max(end, prefix_addr + 4) - 4; + prev_bound = prefix_addr + 4; } else { - i = old_i; + prefix_addr = old_prefix_addr; } break; @@ -1347,7 +1361,7 @@ static void ppu_check_patch_spu_images(const ppu_module& mod, const ppu } // Try to load SPU image - const spu_exec_object obj(fs::file(elf_header, seg.size - i)); + const spu_exec_object obj(fs::file(elf_header, seg.size - prefix_addr)); if (obj != elf_error::ok) { @@ -1392,7 +1406,7 @@ static void ppu_check_patch_spu_images(const ppu_module& 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(seg.addr + i + prog.p_offset + 0x14)); + name = ensure(mod.get_ptr(seg.addr + prefix_addr + prog.p_offset + 0x14)); if (!name.empty()) { @@ -1401,7 +1415,7 @@ static void ppu_check_patch_spu_images(const ppu_module& mod, const ppu } } - fmt::append(dump, " (image addr: 0x%x, size: 0x%x)", seg.addr + i, obj.highest_offset); + fmt::append(dump, " (image addr: 0x%x, size: 0x%x)", seg.addr + prefix_addr, obj.highest_offset); sha1_finish(&sha2, sha1_hash); @@ -1451,8 +1465,8 @@ static void ppu_check_patch_spu_images(const ppu_module& mod, const ppu ppu_loader.success("SPU executable hash: %s (<- %u)%s", hash, applied.size(), dump); } - i += ::narrow(obj.highest_offset) - 4; - prev_bound = i + 4; + prefix_addr += ::narrow(obj.highest_offset - 4); + prev_bound = prefix_addr + 4; } } @@ -2141,6 +2155,8 @@ bool ppu_load_exec(const ppu_exec_object& elf, bool virtual_load, const std::str const auto old_process_info = g_ps3_process_info; + u32 segs_size = 0; + // Allocate memory at fixed positions for (const auto& prog : elf.progs) { @@ -2235,6 +2251,8 @@ bool ppu_load_exec(const ppu_exec_object& elf, bool virtual_load, const std::str { ppu_register_range(addr, size); } + + segs_size += utils::align(size + (addr % 0x10000), 0x10000); } } @@ -2759,7 +2777,7 @@ bool ppu_load_exec(const ppu_exec_object& elf, bool virtual_load, const std::str ppu->gpr[1] -= stack_alloc_size; - ensure(g_fxo->get().take(primary_stacksize)); + ensure(g_fxo->get().take(primary_stacksize + segs_size)); ppu->cmd_push({ppu_cmd::initialize, 0}); diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/PPUThread.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/PPUThread.cpp index c098007..0161a20 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/PPUThread.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/PPUThread.cpp @@ -220,19 +220,21 @@ const auto ppu_gateway = build_function_asm("ppu_gateway", c.mov(x86::qword_ptr(args[0], ::offset32(&ppu_thread::hv_ctx, &rpcs3::hypervisor_context_t::regs)), x86::rsp); // Initialize args - c.mov(x86::r13, x86::qword_ptr(reinterpret_cast(&vm::g_exec_addr))); + c.movabs(x86::r13, reinterpret_cast(&vm::g_exec_addr)); + c.mov(x86::r13, x86::qword_ptr(x86::r13)); c.mov(x86::rbp, args[0]); c.mov(x86::edx, x86::dword_ptr(x86::rbp, ::offset32(&ppu_thread::cia))); // Load PC - c.mov(x86::rax, x86::qword_ptr(x86::r13, x86::edx, 1, 0)); // Load call target - c.mov(x86::rdx, x86::rax); - c.shl(x86::rax, 16); - c.shr(x86::rax, 16); - c.shr(x86::rdx, 48); + c.mov(x86::rax, x86::qword_ptr(x86::r13, x86::rdx, 1, 0)); // Load call target + c.movabs(x86::r12, vm::g_exec_addr_seg_offset); + c.add(x86::r12, x86::r13); + c.shr(x86::edx, 1); + c.mov(x86::edx, x86::word_ptr(x86::r12, x86::edx)); // Load relocation base c.shl(x86::edx, 13); - c.mov(x86::r12d, x86::edx); // Load relocation base + c.mov(x86::r12d, x86::edx); // Set relocation base - c.mov(x86::rbx, x86::qword_ptr(reinterpret_cast(&vm::g_base_addr))); + c.movabs(x86::rbx, reinterpret_cast(&vm::g_base_addr)); + c.mov(x86::rbx, x86::qword_ptr(x86::rbx)); c.mov(x86::r14, x86::qword_ptr(x86::rbp, ::offset32(&ppu_thread::gpr, 0))); // Load some registers c.mov(x86::rsi, x86::qword_ptr(x86::rbp, ::offset32(&ppu_thread::gpr, 1))); c.mov(x86::rdi, x86::qword_ptr(x86::rbp, ::offset32(&ppu_thread::gpr, 2))); @@ -346,14 +348,11 @@ const auto ppu_gateway = build_function_asm("ppu_gateway", c.ldr(call_target, arm::Mem(a64::x19, pc)); // Compute REG_Hp const arm::GpX reg_hp = a64::x21; - c.mov(reg_hp, call_target); - c.lsr(reg_hp, reg_hp, 48); + c.mov(reg_hp, Imm(vm::g_exec_addr_seg_offset)); + c.add(reg_hp, reg_hp, pc, arm::Shift(arm::ShiftOp::kLSR, 2)); + c.ldrh(reg_hp.w(), arm::Mem(a64::x19, reg_hp)); c.lsl(reg_hp.w(), reg_hp.w(), 13); - // Zero top 16 bits of call target - c.lsl(call_target, call_target, Imm(16)); - c.lsr(call_target, call_target, Imm(16)); - // Load registers c.mov(a64::x22, Imm(reinterpret_cast(&vm::g_base_addr))); c.ldr(a64::x22, arm::Mem(a64::x22)); @@ -473,6 +472,11 @@ static inline u8* ppu_ptr(u32 addr) return vm::g_exec_addr + u64{addr} * 2; } +static inline u8* ppu_seg_ptr(u32 addr) +{ + return vm::g_exec_addr + vm::g_exec_addr_seg_offset + (addr >> 1); +} + static inline ppu_intrp_func_t ppu_read(u32 addr) { return read_from_ptr(ppu_ptr(addr)); @@ -518,7 +522,7 @@ void ppu_recompiler_fallback(ppu_thread& ppu) while (true) { - if (uptr func = uptr(ppu_read(ppu.cia)); (func << 16 >> 16) != reinterpret_cast(ppu_recompiler_fallback_ghc)) + if (uptr func = uptr(ppu_read(ppu.cia)); func != reinterpret_cast(ppu_recompiler_fallback_ghc)) { // We found a recompiler function at cia, return break; @@ -773,6 +777,9 @@ extern void ppu_register_range(u32 addr, u32 size) utils::memory_commit(ppu_ptr(addr), u64{size} * 2, utils::protection::rw); ensure(vm::page_protect(addr, size, 0, vm::page_executable)); + // Segment data + utils::memory_commit(ppu_seg_ptr(addr), size >> 1, utils::protection::rw); + if (g_cfg.core.ppu_debug) { utils::memory_commit(vm::g_stat_addr + addr, size); @@ -785,12 +792,13 @@ extern void ppu_register_range(u32 addr, u32 size) if (g_cfg.core.ppu_decoder == ppu_decoder_type::llvm) { // Assume addr is the start of first segment of PRX - const uptr entry_value = reinterpret_cast(ppu_recompiler_fallback_ghc) | (seg_base << (32 + 3)); - write_to_ptr(ppu_ptr(addr), entry_value); + write_to_ptr(ppu_ptr(addr), std::bit_cast(ppu_recompiler_fallback_ghc)); + write_to_ptr(ppu_seg_ptr(addr), static_cast(seg_base >> 13)); } else { write_to_ptr(ppu_ptr(addr), ppu_fallback); + write_to_ptr(ppu_seg_ptr(addr), 0); } addr += 4; @@ -805,7 +813,7 @@ extern void ppu_register_function_at(u32 addr, u32 size, ppu_intrp_func_t ptr = // Initialize specific function if (ptr) { - write_to_ptr(ppu_ptr(addr), (reinterpret_cast(ptr) & 0xffff'ffff'ffffu) | (uptr(ppu_read(addr)) & ~0xffff'ffff'ffffu)); + write_to_ptr(ppu_ptr(addr), std::bit_cast(ptr)); return; } @@ -3164,8 +3172,9 @@ const auto ppu_stcx_accurate_tx = build_function_asm(&vm::g_sudo_addr))); + c.movabs(x86::rbp, reinterpret_cast(&vm::g_sudo_addr)); + c.mov(x86::rbp, x86::qword_ptr(x86::rbp)); c.lea(x86::rbp, x86::qword_ptr(x86::rbp, args[0])); c.and_(x86::rbp, -128); c.prefetchw(x86::byte_ptr(x86::rbp, 0)); c.prefetchw(x86::byte_ptr(x86::rbp, 64)); c.movzx(args[0].r32(), args[0].r16()); c.shr(args[0].r32(), 1); - c.lea(x86::r11, x86::qword_ptr(reinterpret_cast(+vm::g_reservations), args[0])); + c.movabs(x86::r11, reinterpret_cast(+vm::g_reservations)); + c.lea(x86::r11, x86::qword_ptr(x86::r11, args[0])); c.and_(x86::r11, -128 / 2); c.and_(args[0].r32(), 63); @@ -3217,7 +3228,8 @@ const auto ppu_stcx_accurate_tx = build_function_asm(&g_rtm_tx_limit2))); + c.movabs(x86::r13, reinterpret_cast(&g_rtm_tx_limit2)); + c.cmp(x86::rax, x86::qword_ptr(x86::r13)); c.jae(fall); }); @@ -3342,8 +3354,9 @@ const auto ppu_stcx_accurate_tx = build_function_asm& info, bool check_only, u64 file_s code_size_until_jump = buf_end - buf_start; c.add(x86::edx, seg0); - c.mov(x86::rax, x86::qword_ptr(reinterpret_cast(&vm::g_exec_addr))); + c.movabs(x86::rax, reinterpret_cast(&vm::g_exec_addr)); + c.mov(x86::rax, x86::qword_ptr(x86::rax)); c.mov(x86::dword_ptr(x86::rbp, ::offset32(&ppu_thread::cia)), x86::edx); - c.mov(x86::rax, x86::qword_ptr(x86::rax, x86::rdx, 1, 0)); // Load call target - c.mov(x86::rdx, x86::rax); - c.shl(x86::rax, 16); - c.shr(x86::rax, 16); - c.shr(x86::rdx, 48); + c.mov(x86::rcx, x86::qword_ptr(x86::rax, x86::rdx, 1, 0)); // Load call target + c.movabs(x86::r12, vm::g_exec_addr_seg_offset); + c.add(x86::rax, x86::r12); + c.shr(x86::edx, 1); + c.mov(x86::edx, x86::word_ptr(x86::rax, x86::edx)); // Load relocation base c.shl(x86::edx, 13); - c.mov(x86::r12d, x86::edx); // Load relocation base - c.jmp(x86::rax); + c.mov(x86::r12d, x86::edx); // Set relocation base + c.jmp(x86::rcx); #else // Load REG_Base - use absolute jump target to bypass rel jmp range limits // X19 contains vm::g_exec_addr @@ -5125,14 +5139,11 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_s // Compute REG_Hp const arm::GpX reg_hp = a64::x21; - c.mov(reg_hp, call_target); - c.lsr(reg_hp, reg_hp, 48); + c.mov(reg_hp, Imm(vm::g_exec_addr_seg_offset)); + c.add(reg_hp, reg_hp, pc, arm::Shift(arm::ShiftOp::kLSR, 2)); + c.ldrh(reg_hp.w(), arm::Mem(exec_addr, reg_hp)); c.lsl(reg_hp.w(), reg_hp.w(), 13); - // Zero top 16 bits of call target - c.lsl(call_target, call_target, 16); - c.lsr(call_target, call_target, 16); - // Execute LLE call c.br(call_target); #endif @@ -5400,7 +5411,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_s settings += ppu_settings::contains_symbol_resolver; // Avoid invalidating all modules for this purpose // Write version, hash, CPU, settings - fmt::append(obj_name, "v6-kusa-%s-%s-%s.obj", fmt::base57(output, 16), fmt::base57(settings), jit_compiler::cpu(g_cfg.core.llvm_cpu)); + fmt::append(obj_name, "v7-kusa-%s-%s-%s.obj", fmt::base57(output, 16), fmt::base57(settings), jit_compiler::cpu(g_cfg.core.llvm_cpu)); } if (cpu ? cpu->state.all_of(cpu_flag::exit) : Emu.IsStopped()) @@ -5712,7 +5723,7 @@ bool ppu_initialize(const ppu_module& 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(ppu_read(addr)) << 16 >> 16) == reinterpret_cast(ppu_recompiler_fallback_ghc)) + if (*inst_ptr == ppu_instructions::BLR() && reinterpret_cast(ppu_read(addr)) == reinterpret_cast(ppu_recompiler_fallback_ghc)) { write_to_ptr(ppu_ptr(addr), BLR_func); } diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/PPUTranslator.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/PPUTranslator.cpp index e485eee..4d0cb52 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/PPUTranslator.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/PPUTranslator.cpp @@ -411,12 +411,19 @@ Function* PPUTranslator::GetSymbolResolver(const ppu_module& info) const auto faddr = m_ir->CreateLoad(ptr_inst->getResultElementType(), ptr_inst); const auto faddr_int = m_ir->CreatePtrToInt(faddr, get_type()); - const auto fval = m_ir->CreateOr(m_ir->CreateShl(m_seg0, 32 + 3), faddr_int); - const auto pos = m_ir->CreateShl(m_reloc ? m_ir->CreateAdd(func_pc, m_seg0) : func_pc, 1); + const auto pos_32 = m_reloc ? m_ir->CreateAdd(func_pc, m_seg0) : func_pc; + const auto pos = m_ir->CreateShl(pos_32, 1); const auto ptr = dyn_cast(m_ir->CreateGEP(get_type(), m_exec, pos)); + const auto seg_base_ptr = m_ir->CreateIntToPtr(m_ir->CreateAdd( + m_ir->CreatePtrToInt(m_exec, get_type()), m_ir->getInt64(vm::g_exec_addr_seg_offset)), m_exec->getType()); + const auto seg_pos = m_ir->CreateLShr(pos_32, 1); + const auto seg_ptr = dyn_cast(m_ir->CreateGEP(get_type(), seg_base_ptr, seg_pos)); + const auto seg_val = m_ir->CreateTrunc(m_ir->CreateLShr(m_seg0, 13), get_type()); + // Store to jumptable - m_ir->CreateStore(fval, ptr); + m_ir->CreateStore(faddr_int, ptr); + m_ir->CreateStore(seg_val, seg_ptr); // Increment index and branch back to loop const auto post_add = m_ir->CreateAdd(index_value, m_ir->getInt64(1)); @@ -605,10 +612,15 @@ void PPUTranslator::CallFunction(u64 target, Value* indirect) const auto pos = m_ir->CreateShl(indirect, 1); const auto ptr = dyn_cast(m_ir->CreateGEP(get_type(), m_exec, pos)); const auto val = m_ir->CreateLoad(get_type(), ptr); - callee = FunctionCallee(type, m_ir->CreateIntToPtr(m_ir->CreateAnd(val, 0xffff'ffff'ffff), type->getPointerTo())); + callee = FunctionCallee(type, m_ir->CreateIntToPtr(val, type->getPointerTo())); // Load new segment address - seg0 = m_ir->CreateShl(m_ir->CreateLShr(val, 48), 13); + const auto seg_base_ptr = m_ir->CreateIntToPtr(m_ir->CreateAdd( + m_ir->CreatePtrToInt(m_exec, get_type()), m_ir->getInt64(vm::g_exec_addr_seg_offset)), m_exec->getType()); + const auto seg_pos = m_ir->CreateLShr(indirect, 1); + const auto seg_ptr = dyn_cast(m_ir->CreateGEP(get_type(), seg_base_ptr, seg_pos)); + const auto seg_val = m_ir->CreateZExt(m_ir->CreateLoad(get_type(), seg_ptr), get_type()); + seg0 = m_ir->CreateShl(seg_val, 13); } m_ir->SetInsertPoint(block); diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/RawSPUThread.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/RawSPUThread.cpp index dd621ae..0104155 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/RawSPUThread.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/RawSPUThread.cpp @@ -3,7 +3,7 @@ #include "Loader/ELF.h" #include "util/asm.hpp" -#include "Emu/Cell/RawSPUThread.h" +#include "SPUThread.h" inline void try_start(spu_thread& spu) { diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/RawSPUThread.h b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/RawSPUThread.h index 921db8f..6f70f09 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/RawSPUThread.h +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/RawSPUThread.h @@ -1,3 +1 @@ #pragma once - -#include "SPUThread.h" diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp index 3a3ef1c..6b4b456 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/SPUASMJITRecompiler.cpp @@ -5,15 +5,12 @@ #include "Emu/IdManager.h" #include "Emu/Cell/timers.hpp" -#include "SPUDisAsm.h" #include "SPUThread.h" #include "SPUInterpreter.h" -#include "PPUAnalyser.h" #include "Crypto/sha1.h" #include "util/asm.hpp" #include "util/v128.hpp" -#include "util/simd.hpp" #include "util/sysinfo.hpp" #include @@ -2773,14 +2770,17 @@ void spu_recompiler::FREST(spu_opcode_t op) const u64 fraction_lut_addr = reinterpret_cast(spu_frest_fraction_lut); const u64 exponent_lut_addr = reinterpret_cast(spu_frest_exponent_lut); + c->movabs(*arg0, fraction_lut_addr); + c->movabs(*arg1, exponent_lut_addr); + for (u32 index = 0; index < 4; index++) { c->pextrd(*qw0, v_fraction, index); - c->mov(*qw1, asmjit::x86::dword_ptr(fraction_lut_addr, *qw0, 2)); + c->mov(*qw1, asmjit::x86::dword_ptr(*arg0, *qw0, 2)); c->pinsrd(v_fraction, *qw1, index); c->pextrd(*qw0, v_exponent, index); - c->mov(*qw1, asmjit::x86::dword_ptr(exponent_lut_addr, *qw0, 2)); + c->mov(*qw1, asmjit::x86::dword_ptr(*arg1, *qw0, 2)); c->pinsrd(v_exponent, *qw1, index); } @@ -2813,14 +2813,17 @@ void spu_recompiler::FRSQEST(spu_opcode_t op) const u64 fraction_lut_addr = reinterpret_cast(spu_frsqest_fraction_lut); const u64 exponent_lut_addr = reinterpret_cast(spu_frsqest_exponent_lut); + c->movabs(*arg0, fraction_lut_addr); + c->movabs(*arg1, exponent_lut_addr); + for (u32 index = 0; index < 4; index++) { c->pextrd(*qw0, v_fraction, index); - c->mov(*qw1, asmjit::x86::dword_ptr(fraction_lut_addr, *qw0, 2)); + c->mov(*qw1, asmjit::x86::dword_ptr(*arg0, *qw0, 2)); c->pinsrd(v_fraction, *qw1, index); c->pextrd(*qw0, v_exponent, index); - c->mov(*qw1, asmjit::x86::dword_ptr(exponent_lut_addr, *qw0, 2)); + c->mov(*qw1, asmjit::x86::dword_ptr(*arg1, *qw0, 2)); c->pinsrd(v_exponent, *qw1, index); } diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/SPUAnalyser.h b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/SPUAnalyser.h index faa85a5..103c655 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/SPUAnalyser.h +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/SPUAnalyser.h @@ -1,7 +1,5 @@ #pragma once -#include "util/types.hpp" - // SPU Instruction Type struct spu_itype { diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp index e11cc7a..d73efc8 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp @@ -842,6 +842,7 @@ void spu_cache::initialize(bool build_existing_cache) // Initialize compiler instances for parallel compilation std::unique_ptr compiler; +#if defined(ARCH_X64) if (g_cfg.core.spu_decoder == spu_decoder_type::asmjit) { compiler = spu_recompiler_base::make_asmjit_recompiler(); @@ -850,6 +851,22 @@ void spu_cache::initialize(bool build_existing_cache) { compiler = spu_recompiler_base::make_llvm_recompiler(); } + else + { + fmt::throw_exception("Unsupported spu decoder '%s'", g_cfg.core.spu_decoder); + } +#elif defined(ARCH_ARM64) + if (g_cfg.core.spu_decoder == spu_decoder_type::llvm) + { + compiler = spu_recompiler_base::make_llvm_recompiler(); + } + else + { + fmt::throw_exception("Unsupported spu decoder '%s'", g_cfg.core.spu_decoder); + } +#else +#error "Unimplemented" +#endif compiler->init(); @@ -2545,7 +2562,7 @@ bool reg_state_t::is_const() const bool reg_state_t::compare_tags(const reg_state_t& rhs) const { - // Compare by tag, address of instruction origin + // Compare by tag, address of instruction origin return tag == rhs.tag && origin == rhs.origin && is_instruction == rhs.is_instruction; } @@ -6066,7 +6083,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s else if (atomic16->ls_offs.compare_with_mask_indifference(atomic16->lsa, SPU_LS_MASK_128) && atomic16->ls.is_less_than(128 - (atomic16->ls_offs.value & 127))) { // Relative memory access with offset less than 128 bytes - // Common around SPU utilities which have less strict restrictions about memory alignment + // Common around SPU utilities which have less strict restrictions about memory alignment ok = true; } } @@ -6340,7 +6357,7 @@ spu_program spu_recompiler_base::analyse(const be_t* ls, u32 entry_point, s { atomic16->mem_count++; - // Do not clear lower 16 bytes addressing because the program can move on 4-byte basis + // Do not clear lower 16 bytes addressing because the program can move on 4-byte basis const u32 offs = spu_branch_target(pos - result.lower_bound, op.si16); if (atomic16->lsa.is_const() && [&]() @@ -7359,7 +7376,7 @@ struct spu_llvm_worker set_relax_flag = false; } - thread_ctrl::wait_on(utils::bless>(®istered)[1], 0); + thread_ctrl::wait_on(registered.get_wait_atomic(), 0); slice = registered.pop_all(); }()) { @@ -7474,7 +7491,7 @@ struct spu_llvm while (!registered && thread_ctrl::state() != thread_state::aborting) { // Wait for the first SPU block before launching any thread - thread_ctrl::wait_on(utils::bless>(®istered)[1], 0); + thread_ctrl::wait_on(registered.get_wait_atomic(), 0); } if (thread_ctrl::state() == thread_state::aborting) @@ -7577,7 +7594,7 @@ struct spu_llvm // Interrupt profiler thread and put it to sleep static_cast(prof_mutex.reset()); - thread_ctrl::wait_on(utils::bless>(®istered)[1], 0); + thread_ctrl::wait_on(registered.get_wait_atomic(), 0); std::fill(notify_compile.begin(), notify_compile.end(), 0); // Reset notification flags notify_compile_count = 0; compile_pending = 0; @@ -8142,7 +8159,7 @@ std::array& 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; } diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/SPUInterpreter.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/SPUInterpreter.cpp index 3d69d5f..a781da5 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/SPUInterpreter.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/SPUInterpreter.cpp @@ -3,7 +3,6 @@ #include "Utilities/JIT.h" #include "SPUThread.h" -#include "Emu/Cell/Common.h" #include "Emu/Cell/SPUAnalyser.h" #include "Emu/system_config.h" @@ -13,7 +12,6 @@ #include "util/sysinfo.hpp" #include -#include #if !defined(_MSC_VER) #pragma GCC diagnostic push diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/SPUThread.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/SPUThread.cpp index 3ab6a10..8f812b5 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/SPUThread.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/SPUThread.cpp @@ -628,6 +628,8 @@ const auto spu_putllc_tx = build_function_asm(&vm::g_sudo_addr))); + c.movabs(args[1], reinterpret_cast(&vm::g_sudo_addr)); + c.mov(args[1], x86::qword_ptr(args[1])); c.lea(args[1], x86::qword_ptr(args[1], args[0])); c.prefetchw(x86::byte_ptr(args[1], 0)); c.prefetchw(x86::byte_ptr(args[1], 64)); c.and_(args[0].r32(), 0xff80); c.shr(args[0].r32(), 1); - c.lea(x86::r11, x86::qword_ptr(reinterpret_cast(+vm::g_reservations), args[0])); + c.movabs(x86::r11, reinterpret_cast(+vm::g_reservations)); + c.lea(x86::r11, x86::qword_ptr(x86::r11, args[0])); // Prepare data if (s_tsx_avx) @@ -703,7 +709,8 @@ const auto spu_putllc_tx = build_function_asm(&g_rtm_tx_limit2))); + c.movabs(x86::rbx, reinterpret_cast(&g_rtm_tx_limit2)); + c.cmp(x86::rax, x86::qword_ptr(x86::rbx)); c.jae(fall); }); @@ -853,8 +860,13 @@ const auto spu_putllc_tx = build_function_asm(&vm::g_sudo_addr))); + c.movabs(x86::r11, reinterpret_cast(&vm::g_sudo_addr)); + c.mov(x86::r11, x86::qword_ptr(x86::r11)); c.lea(x86::r11, x86::qword_ptr(x86::r11, args[0])); c.prefetchw(x86::byte_ptr(x86::r11, 0)); c.prefetchw(x86::byte_ptr(x86::r11, 64)); @@ -921,7 +936,8 @@ const auto spu_putlluc_tx = build_function_asm(+vm::g_reservations), args[0])); + c.movabs(args[1], reinterpret_cast(+vm::g_reservations)); + c.lea(args[1], x86::qword_ptr(args[1], args[0])); // Alloc args[0] to stamp0 const auto stamp0 = args[0]; @@ -933,7 +949,8 @@ const auto spu_putlluc_tx = build_function_asm(&g_rtm_tx_limit2))); + c.movabs(x86::rbx, reinterpret_cast(&g_rtm_tx_limit2)); + c.cmp(x86::rax, x86::qword_ptr(x86::rbx)); c.jae(fall); }); @@ -986,6 +1003,10 @@ const auto spu_putlluc_tx = build_function_asm(&vm::g_sudo_addr))); + c.movabs(x86::rbp, reinterpret_cast(&vm::g_sudo_addr)); + c.mov(x86::rbp, x86::qword_ptr(x86::rbp)); c.lea(x86::rbp, x86::qword_ptr(x86::rbp, args[0])); c.and_(args[0].r32(), 0xff80); c.shr(args[0].r32(), 1); - c.lea(x86::r11, x86::qword_ptr(reinterpret_cast(+vm::g_reservations), args[0])); + c.movabs(x86::r11, reinterpret_cast(+vm::g_reservations)); + c.lea(x86::r11, x86::qword_ptr(x86::r11, args[0])); // Alloc args[0] to stamp0 const auto stamp0 = args[0]; @@ -1039,7 +1062,8 @@ const auto spu_getllar_tx = build_function_asm(&g_rtm_tx_limit1))); + c.movabs(x86::rbx, reinterpret_cast(&g_rtm_tx_limit1)); + c.cmp(x86::rax, x86::qword_ptr(x86::rbx)); c.jae(fall); }); @@ -1209,8 +1233,6 @@ void spu_thread::dump_regs(std::string& ret, std::any& /*custom_data*/) const u32 saved_pc = umax; const u8* lsa_state_ptr = nullptr; - const u8* lsa_ptr = _ptr(ch_mfc_cmd.lsa); - // Load PC, GPRs and reservation data atomically // We may not load the entire context atomically, but there is importance their state being intact for debugging do @@ -2107,6 +2129,41 @@ u8* spu_thread::map_ls(utils::shm& shm, void* ptr) return ls; } +void spu_thread::init_spu_decoder() +{ + ensure(!jit); + +#if !defined(ARCH_X64) && !defined(ARCH_ARM64) +#error "Unimplemented" +#else + const spu_decoder_type spu_decoder = g_cfg.core.spu_decoder; + +#if defined(ARCH_X64) + if (spu_decoder == spu_decoder_type::asmjit) + { + jit = spu_recompiler_base::make_asmjit_recompiler(); + } + else +#endif + if (spu_decoder == spu_decoder_type::llvm) + { +#if defined(ARCH_X64) + jit = spu_recompiler_base::make_fast_llvm_recompiler(); +#elif defined(ARCH_ARM64) + jit = spu_recompiler_base::make_llvm_recompiler(); +#endif + } + else if (spu_decoder == spu_decoder_type::_static || spu_decoder == spu_decoder_type::dynamic) + { + // + } + else + { + fmt::throw_exception("Unsupported spu decoder '%s'", g_cfg.core.spu_decoder); + } +#endif +} + spu_thread::spu_thread(lv2_spu_group* group, u32 index, std::string_view name, u32 lv2_id, bool is_isolated, u32 option) : cpu_thread(idm::last_id()) , group(group) @@ -2118,20 +2175,7 @@ spu_thread::spu_thread(lv2_spu_group* group, u32 index, std::string_view name, u , lv2_id(lv2_id) , spu_tname(make_single(name)) { - if (g_cfg.core.spu_decoder == spu_decoder_type::asmjit) - { - jit = spu_recompiler_base::make_asmjit_recompiler(); - } - else if (g_cfg.core.spu_decoder == spu_decoder_type::llvm) - { -#if defined(ARCH_X64) - jit = spu_recompiler_base::make_fast_llvm_recompiler(); -#elif defined(ARCH_ARM64) - jit = spu_recompiler_base::make_llvm_recompiler(); -#else -#error "Unimplemented" -#endif - } + init_spu_decoder(); if (g_cfg.core.mfc_debug) { @@ -2193,20 +2237,7 @@ spu_thread::spu_thread(utils::serial& ar, lv2_spu_group* group) , lv2_id(ar) , spu_tname(make_single(ar.operator std::string())) { - if (g_cfg.core.spu_decoder == spu_decoder_type::asmjit) - { - jit = spu_recompiler_base::make_asmjit_recompiler(); - } - else if (g_cfg.core.spu_decoder == spu_decoder_type::llvm) - { -#if defined(ARCH_X64) - jit = spu_recompiler_base::make_fast_llvm_recompiler(); -#elif defined(ARCH_ARM64) - jit = spu_recompiler_base::make_llvm_recompiler(); -#else -#error "Unimplemented" -#endif - } + init_spu_decoder(); if (g_cfg.core.mfc_debug) { @@ -4329,7 +4360,7 @@ bool spu_thread::check_mfc_interrupts(u32 next_pc) return false; } -bool spu_thread::is_exec_code(u32 addr, std::span ls_ptr, u32 base_addr, bool avoid_dead_code) +bool spu_thread::is_exec_code(u32 addr, std::span ls_ptr, u32 base_addr, bool avoid_dead_code, bool is_range_limited) { bool had_conditional = false; @@ -4337,12 +4368,12 @@ bool spu_thread::is_exec_code(u32 addr, std::span ls_ptr, u32 base_add { if (addr & ~0x3FFFC) { - return false; + return is_range_limited; } if (addr < base_addr || addr >= base_addr + ls_ptr.size()) { - return false; + return is_range_limited; } const u32 addr0 = spu_branch_target(addr); @@ -4445,19 +4476,19 @@ bool spu_thread::is_exec_code(u32 addr, std::span ls_ptr, u32 base_add // Detect "invalid" relative branches // Branch offsets that, although are the only way to get X code address using relative address // Rely on overflow/underflow of SPU memory bounds - // Thus they would behave differently if SPU LS memory size was to increase (evolving the CELL architecture was the original plan) + // Thus they would behave differently if SPU LS memory size was to increase (evolving the CELL architecture was the original plan) // Making them highly unlikely to be valid code if (rel < 0) { if (addr < 0u - rel) { - return false; + return is_range_limited; } } else if (SPU_LS_SIZE - addr <= rel + 0u) { - return false; + return is_range_limited; } if (type == spu_itype::BRSL) @@ -4487,7 +4518,7 @@ bool spu_thread::is_exec_code(u32 addr, std::span ls_ptr, u32 base_add if (route_pc < base_addr || route_pc >= base_addr + ls_ptr.size()) { - return false; + return is_range_limited; } // Test the validity of a single instruction of the optional target @@ -4518,6 +4549,126 @@ u32 spu_thread::get_mfc_completed() const return ch_tag_mask & ~mfc_fence; } +u32 evaluate_spin_optimization(std::span 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 old_stats{}; + std::copy_n(stats.data(), stats.size(), old_stats.data()); + + // Rotate history (prepare newest entry) + stats[0] = 0; + std::copy_n(old_stats.data(), stats.size() - 1, stats.data() + 1); + + u32 total_wait = 0; + u32 zero_count = 0; // Try to ignore major inconsistencies + u32 consecutive_zero = 0; + u32 consecutive_zero_or_one = 0; + u32 consecutive_zero_or_one_tally = 0; + + usz index = umax; + + for (u8 val : old_stats) + { + index++; + + if (index == stats.size()) + { + break; + } + + total_wait += val; + + if (val == 0) + { + if (consecutive_zero == index) + { + consecutive_zero++; + consecutive_zero_or_one++; + //consecutive_zero_or_one_tally += 0; + } + + ++zero_count; + } + + if (val == 1) + { + if (consecutive_zero_or_one == index) + { + consecutive_zero_or_one++; + consecutive_zero_or_one_tally++; + } + } + } + + if (inclined_for_responsiveness) + { + total_wait /= 2; + } + + // Add to chance if previous wait was long enough + u32 add_count = 0; + + if (stats.size() == 4) + { + add_count = zero_count == 3 && total_wait >= 9 ? (total_wait - 8) * 40 + : zero_count == 2 && total_wait >= 8 ? (total_wait - 7) * 40 + : zero_count == 1 && total_wait >= 7 ? (total_wait - 6) * 40 + : zero_count == 0 && total_wait >= 4 ? (total_wait - 3) * 40 + : 0; + } + else + { + add_count = zero_count >= 12 && total_wait >= 80 ? (total_wait - 80) * 30 + : zero_count >= 7 && total_wait >= 30 ? (total_wait - 30) * 10 + : zero_count >= 4 && total_wait >= 20 ? (total_wait - 20) * 10 + : zero_count >= 0 && total_wait >= 10 ? (total_wait - 10) * 10 + : 0; + } + + if (stats.size() == 16 && (consecutive_zero >= 2 || (consecutive_zero_or_one >= 3 && consecutive_zero_or_one_tally < consecutive_zero_or_one * 2 / 3))) + { + // Thread is back to action after some sleep + add_count = 0; + } + + if (inclined_for_responsiveness && std::count(old_stats.data(), old_stats.data() + 3, 0) >= 2) + { + add_count = 0; + } + + // Evalute its value (shift-right to ensure its randomness with different CPUs) + const u32 busy_waiting_switch = ((evaluate_time >> 8) % 100 + add_count < percent) ? 1 : 0; + + thread_local usz g_system_wait = 0, g_busy_wait = 0; + + if (busy_waiting_switch) + { + g_busy_wait++; + } + else + { + g_system_wait++; + } + + if ((g_system_wait + g_busy_wait) && (g_system_wait + g_busy_wait) % 200 == 0) + { + spu_log.trace("SPU wait: count=%d. switch=%d, spin=%d, busy=%d, system=%d, {%d, %d, %d, %d}", total_wait, busy_waiting_switch, !"TODO: Spin", +g_busy_wait, +g_system_wait, old_stats[0], old_stats[1], old_stats[2], old_stats[3]); + } + + if ((g_system_wait + g_busy_wait) % 5000 == 0) + { + g_system_wait = 0; + g_busy_wait = 0; + } + + return busy_waiting_switch; +} + bool spu_thread::process_mfc_cmd() { // Stall infinitely if MFC queue is full @@ -4632,61 +4783,16 @@ bool spu_thread::process_mfc_cmd() getllar_spin_count = std::min(getllar_spin_count + 1, u16{umax}); - static atomic_t g_ok = 0, g_fail = 0; - if (getllar_busy_waiting_switch == umax && getllar_spin_count == 4) { // Hidden value to force busy waiting (100 to 1 are dynamically adjusted, 0 is not) if (!g_cfg.core.spu_getllar_spin_optimization_disabled) { - const u32 percent = g_cfg.core.spu_getllar_busy_waiting_percentage; - - // Predict whether or not to use operating system sleep based on history - auto& stats = getllar_wait_time[(addr % SPU_LS_SIZE) / 128]; - - const std::array old_stats = stats; - std::array new_stats{}; - - // Rotate history (prepare newest entry) - new_stats[0] = 0; - new_stats[1] = old_stats[0]; - new_stats[2] = old_stats[1]; - new_stats[3] = old_stats[2]; - - stats = new_stats; - - u32 total_wait = 0; - u32 zero_count = 0; // Try to ignore major inconsistencies - - for (u8 val : old_stats) - { - total_wait += val; - if (val == 0) ++zero_count; - } - - // Add to chance if previous wait was long enough - const u32 add_count = zero_count == 3 && total_wait >= 40 ? (total_wait - 39) * 40 - : zero_count == 2 && total_wait >= 11 ? (total_wait - 10) * 40 - : zero_count == 1 && total_wait >= 8 ? (total_wait - 7) * 40 - : zero_count == 0 && total_wait >= 6 ? (total_wait - 5) * 40 - : 0; - - // Evalute its value (shift-right to ensure its randomness with different CPUs) - getllar_busy_waiting_switch = ((perf0.get() >> 8) % 100 + add_count < percent) ? 1 : 0; - getllar_evaluate_time = perf0.get(); + auto& history = getllar_wait_time[(addr % SPU_LS_SIZE) / 128]; - if (getllar_busy_waiting_switch) - { - g_fail++; - } - else - { - g_ok++; - } - - if ((g_ok + g_fail) % 200 == 0 && !getllar_busy_waiting_switch) - spu_log.trace("SPU wait: count=%d. switch=%d, spin=%d, fail=%d, ok=%d, {%d, %d, %d, %d}", total_wait, getllar_busy_waiting_switch, getllar_spin_count, +g_fail, +g_ok, old_stats[0], old_stats[1], old_stats[2], old_stats[3] ); + getllar_busy_waiting_switch = + evaluate_spin_optimization({ history.data(), history.size() }, getllar_evaluate_time, g_cfg.core.spu_getllar_busy_waiting_percentage); } else { @@ -5004,7 +5110,7 @@ bool spu_thread::process_mfc_cmd() if (group->spurs_running == max_run - 1) { - // Try to let another thread slip in and take over execution + // Try to let another thread slip in and take over execution thread_ctrl::wait_for(300); // Update value @@ -5029,7 +5135,7 @@ bool spu_thread::process_mfc_cmd() if (spurs_last_task_timestamp) { const u64 avg_entry = spurs_average_task_duration / spurs_task_count_to_calculate; - spurs_average_task_duration -= avg_entry; + spurs_average_task_duration -= avg_entry; spurs_average_task_duration += std::min(45'000, current - spurs_last_task_timestamp); spu_log.trace("duration: %d, avg=%d", current - spurs_last_task_timestamp, spurs_average_task_duration / spurs_task_count_to_calculate); spurs_last_task_timestamp = 0; @@ -5050,7 +5156,7 @@ bool spu_thread::process_mfc_cmd() } max_run = group->max_run; - + prev_running = group->spurs_running.fetch_op([max_run](u32& x) { if (x < max_run) @@ -5115,7 +5221,7 @@ bool spu_thread::process_mfc_cmd() if (spurs_last_task_timestamp) { const u64 avg_entry = spurs_average_task_duration / spurs_task_count_to_calculate; - spurs_average_task_duration -= avg_entry; + spurs_average_task_duration -= avg_entry; spurs_average_task_duration += std::min(45'000, current - spurs_last_task_timestamp); spu_log.trace("duration: %d, avg=%d", current - spurs_last_task_timestamp, spurs_average_task_duration / spurs_task_count_to_calculate); spurs_last_task_timestamp = 0; @@ -5937,7 +6043,52 @@ s64 spu_thread::get_ch_value(u32 ch) return true; }; - for (; !events.count; events = get_events(mask1 & ~SPU_EVENT_LR, true, true)) + const bool is_LR_wait = raddr && mask1 & SPU_EVENT_LR; + + auto& history = eventstat_wait_time[(raddr % SPU_LS_SIZE) / 128]; + + if (is_LR_wait) + { + const u32 spu_group_restart = group ? +group->stop_count : 0; + + // Check if waiting session changed + if (eventstat_raddr != raddr || eventstat_block_counter != block_counter || last_getllar != eventstat_getllar || eventstat_spu_group_restart != spu_group_restart) + { + eventstat_raddr = raddr; + eventstat_block_counter = block_counter; + eventstat_getllar = last_getllar; + eventstat_spu_group_restart = spu_group_restart; + eventstat_spin_count = 0; + eventstat_evaluate_time = get_system_time(); + eventstat_busy_waiting_switch = umax; + } + else + { + u8& val = history.front(); + val = static_cast(std::min(val + 1, u8{umax})); + } + } + else + { + eventstat_busy_waiting_switch = 0; + eventstat_raddr = 0; + eventstat_block_counter = 0; + } + + if (eventstat_busy_waiting_switch == umax) + { + bool value = false; + + if (is_LR_wait && g_cfg.core.spu_reservation_busy_waiting_enabled) + { + // Make single-threaded groups inclined for busy-waiting + value = evaluate_spin_optimization({ history.data(), history.size() }, eventstat_evaluate_time, g_cfg.core.spu_reservation_busy_waiting_percentage, group && group->max_num == 1) != 0; + } + + eventstat_busy_waiting_switch = value ? 1 : 0; + } + + for (bool is_first = true; !events.count; events = get_events(mask1 & ~SPU_EVENT_LR, true, true), is_first = false) { const auto old = +state; @@ -5952,7 +6103,7 @@ s64 spu_thread::get_ch_value(u32 ch) } // Optimized check - if (raddr && mask1 & SPU_EVENT_LR) + if (is_LR_wait) { if (cache_line_waiter_index == umax) { @@ -5983,6 +6134,59 @@ s64 spu_thread::get_ch_value(u32 ch) set_events(SPU_EVENT_LR); continue; } + + if (!is_first && eventstat_busy_waiting_switch != 1) + { + u8& val = history.front(); + val = static_cast(std::min(val + 1, u8{umax})); + } + } + + if (eventstat_busy_waiting_switch == 1) + { + // Don't be stubborn, force operating sleep if too much time has passed + const u64 time_since = get_system_time() - eventstat_evaluate_time; + + if (time_since >= (utils::get_thread_count() >= 9 ? 50'000 : 3000)) + { + spu_log.trace("SPU RdEventStat wait for 0x%x failed", raddr); + history.front() = 2; + eventstat_busy_waiting_switch = 0; + continue; + } + +#if defined(ARCH_X64) + if (utils::has_um_wait()) + { + if (utils::has_waitpkg()) + { + __tpause(std::min(eventstat_spin_count, 10) * 500, 0x1); + } + else + { + struct check_wait_t + { + static FORCE_INLINE bool needs_wait(u64 rtime, const atomic_t& mem_rtime) noexcept + { + return rtime == mem_rtime; + } + }; + + // Provide the first X64 cache line of the reservation to be tracked + __mwaitx(std::min(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) diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/SPUThread.h b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/SPUThread.h index 37cf1cf..ce84e9e 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/SPUThread.h +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/SPUThread.h @@ -638,6 +638,7 @@ public: virtual ~spu_thread() override; void cleanup(); void cpu_init(); + void init_spu_decoder(); static const u32 id_base = 0x02000000; // TODO (used to determine thread type) static const u32 id_step = 1; @@ -805,6 +806,14 @@ public: u32 getllar_busy_waiting_switch = umax; // umax means the test needs evaluation, otherwise it's a boolean u64 getllar_evaluate_time = 0; + u32 eventstat_raddr = 0; + u32 eventstat_getllar = 0; + u64 eventstat_block_counter = 0; + u64 eventstat_spu_group_restart = 0; + u64 eventstat_spin_count = 0; + u64 eventstat_evaluate_time = 0; + u32 eventstat_busy_waiting_switch = 0; + std::vector mfc_history; u64 mfc_dump_idx = 0; static constexpr u32 max_mfc_dump_idx = 4096; @@ -828,6 +837,7 @@ public: bool stop_flag_removal_protection = false; std::array, SPU_LS_SIZE / 128> getllar_wait_time{}; + std::array, SPU_LS_SIZE / 128> eventstat_wait_time{}; void push_snr(u32 number, u32 value); static void do_dma_transfer(spu_thread* _this, const spu_mfc_cmd& args, u8* ls); @@ -843,7 +853,7 @@ public: void set_events(u32 bits); void set_interrupt_status(bool enable); bool check_mfc_interrupts(u32 next_pc); - static bool is_exec_code(u32 addr, std::span ls_ptr, u32 base_addr = 0, bool avoid_dead_code = false); // Only a hint, do not rely on it other than debugging purposes + static bool is_exec_code(u32 addr, std::span ls_ptr, u32 base_addr = 0, bool avoid_dead_code = false, bool is_range_limited = false); // A hint, do not rely on it for true execution compatibility static std::vector discover_functions(u32 base_addr, std::span ls, bool is_known_addr, u32 /*entry*/); u32 get_ch_count(u32 ch); s64 get_ch_value(u32 ch); diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/lv2.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/lv2.cpp index 63ebd4c..8d4db2b 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/lv2.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/lv2.cpp @@ -2160,7 +2160,7 @@ bool lv2_obj::wait_timeout(u64 usec, ppu_thread* cpu, bool scale, bool is_usleep } u64 remaining = usec - passed; -#if defined(__linux__) +#ifdef __linux__ // NOTE: Assumption that timer initialization has succeeded constexpr u64 host_min_quantum = 10; #else @@ -2178,7 +2178,7 @@ bool lv2_obj::wait_timeout(u64 usec, ppu_thread* cpu, bool scale, bool is_usleep { if (remaining > host_min_quantum) { -#if defined(__linux__) +#ifdef __linux__ // With timerslack set low, Linux is precise for all values above wait_for(remaining); #else @@ -2268,7 +2268,7 @@ void lv2_obj::notify_all() noexcept u32 notifies[total_waiters]{}; - // There may be 6 waiters, but checking them all may be performance expensive + // There may be 6 waiters, but checking them all may be performance expensive // Instead, check 2 at max, but use the CPU ID index to tell which index to start checking so the work would be distributed across all threads atomic_t* range_lock = nullptr; diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_bdemu.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_bdemu.cpp index 4dfc6eb..51d8e48 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_bdemu.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_bdemu.cpp @@ -1,5 +1,4 @@ #include "stdafx.h" -#include "Emu/Memory/vm.h" #include "Emu/Cell/ErrorCodes.h" diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_cond.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_cond.cpp index 840b194..401ed3b 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_cond.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_cond.cpp @@ -2,7 +2,6 @@ #include "util/serialization.hpp" #include "Emu/IdManager.h" -#include "Emu/IPC.h" #include "Emu/System.h" #include "Emu/Cell/ErrorCodes.h" @@ -60,7 +59,6 @@ CellError lv2_cond::on_id_create() if (!mutex) { _mutex = static_cast>(ensure(idm::get_unlocked(mtx_id))); - } // Defer function @@ -72,7 +70,7 @@ CellError lv2_cond::on_id_create() std::function lv2_cond::load(utils::serial& ar) { - return load_func(make_shared(ar)); + return load_func(make_shared(stx::exact_t(ar))); } void lv2_cond::save(utils::serial& ar) diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_config.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_config.cpp index c39444c..0179a6b 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_config.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_config.cpp @@ -1,6 +1,4 @@ #include "stdafx.h" -#include "Emu/System.h" -#include "Emu/Memory/vm.h" #include "Emu/IdManager.h" #include "Emu/Cell/lv2/sys_event.h" @@ -122,7 +120,7 @@ void lv2_config::remove_service_event(u32 id) lv2_config_service_event& lv2_config_service_event::operator=(thread_state s) noexcept { - if (s == thread_state::finished) + if (s == thread_state::destroying_context && !m_destroyed.exchange(true)) { if (auto global = g_fxo->try_get()) { @@ -133,6 +131,23 @@ lv2_config_service_event& lv2_config_service_event::operator=(thread_state s) no return *this; } +lv2_config_service_event::~lv2_config_service_event() noexcept +{ + operator=(thread_state::destroying_context); +} + +lv2_config::~lv2_config() noexcept +{ + for (auto& [key, event] : events) + { + if (event) + { + // Avoid collision with lv2_config_service_event destructor + event->m_destroyed = true; + } + } +} + // LV2 Config Service Listener bool lv2_config_service_listener::check_service(const lv2_config_service& service) const { diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_config.h b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_config.h index 3915dfc..0804671 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_config.h +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_config.h @@ -1,11 +1,8 @@ #pragma once -#include -#include - #include "util/atomic.hpp" #include "util/shared_ptr.hpp" - +#include "Emu/Cell/timers.hpp" /* * sys_config is a "subscription-based data storage API" @@ -161,6 +158,8 @@ public: return null_ptr; } + + ~lv2_config() noexcept; }; /* @@ -276,7 +275,7 @@ public: // Utilities usz get_size() const { return sizeof(sys_config_service_event_t)-1 + data.size(); } - shared_ptr get_shared_ptr () const { return idm::get_unlocked(idm_id); } + shared_ptr get_shared_ptr () const { return stx::make_shared_from_this(this); } u32 get_id() const { return idm_id; } }; @@ -342,7 +341,7 @@ public: // Utilities u32 get_id() const { return idm_id; } - shared_ptr get_shared_ptr() const { return idm::get_unlocked(idm_id); } + shared_ptr get_shared_ptr() const { return stx::make_shared_from_this(this); } }; /* @@ -360,6 +359,10 @@ class lv2_config_service_event return g_fxo->get().next_id++; } + atomic_t m_destroyed = false; + + friend class lv2_config; + public: const u32 id; @@ -391,8 +394,7 @@ public: // Destructor lv2_config_service_event& operator=(thread_state s) noexcept; - - ~lv2_config_service_event() noexcept = default; + ~lv2_config_service_event() noexcept; // Notify queue that this event exists bool notify() const; diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_event.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_event.cpp index 0428fd0..db72972 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_event.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_event.cpp @@ -37,8 +37,8 @@ lv2_event_queue::lv2_event_queue(utils::serial& ar) noexcept std::function lv2_event_queue::load(utils::serial& ar) { - auto queue = make_shared(ar); - return [ptr = lv2_obj::load(queue->key, queue)](void* storage) { *static_cast*>(storage) = ptr; }; + auto queue = make_shared(stx::exact_t(ar)); + return [ptr = lv2_obj::load(queue->key, queue)](void* storage) { *static_cast*>(storage) = ptr; }; } void lv2_event_queue::save(utils::serial& ar) @@ -420,10 +420,8 @@ error_code sys_event_queue_tryreceive(ppu_thread& ppu, u32 equeue_id, vm::ptrevents.empty()) { auto& dest = events[count++]; - const auto event = queue->events.front(); + std::tie(dest.source, dest.data1, dest.data2, dest.data3) = queue->events.front(); queue->events.pop_front(); - - std::tie(dest.source, dest.data1, dest.data2, dest.data3) = event; } lock.unlock(); diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_event_flag.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_event_flag.cpp index 6c630e9..c28efaf 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_event_flag.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_event_flag.cpp @@ -2,13 +2,10 @@ #include "sys_event_flag.h" #include "Emu/IdManager.h" -#include "Emu/IPC.h" #include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/PPUThread.h" -#include - #include "util/asm.hpp" LOG_CHANNEL(sys_event_flag); @@ -24,7 +21,7 @@ lv2_event_flag::lv2_event_flag(utils::serial& ar) std::function lv2_event_flag::load(utils::serial& ar) { - return load_func(make_shared(ar)); + return load_func(make_shared(stx::exact_t(ar))); } void lv2_event_flag::save(utils::serial& ar) diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_fs.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_fs.cpp index 1be2d7a..5dafa75 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_fs.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_fs.cpp @@ -79,7 +79,7 @@ void fmt_class_string::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::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(dir.pos, dir.entries.size()), dir.entries.size()); + fmt::append(out, u8"Directory, '%s', Entries: %u/%u", dir.name.data(), std::min(dir.pos, dir.entries.size()), dir.entries.size()); } bool has_fs_write_rights(std::string_view vpath) diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_memory.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_memory.cpp index de55904..9f726e9 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_memory.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_memory.cpp @@ -7,7 +7,6 @@ #include "Emu/Cell/SPUThread.h" #include "Emu/IdManager.h" -#include "util/vm.hpp" #include "util/asm.hpp" LOG_CHANNEL(sys_memory); @@ -33,7 +32,7 @@ std::function lv2_memory_container::load(utils::serial& ar) // Use idm::last_id() only for the instances at IDM return [ptr = make_shared(stx::exact_t(ar), true)](void* storage) { - *static_cast*>(storage) = ptr; + *static_cast*>(storage) = ptr; }; } diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp index d134102..d7b66ad 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_mmapper.cpp @@ -36,12 +36,8 @@ lv2_memory::lv2_memory(u32 size, u32 align, u64 flags, u64 key, bool pshared, lv , key(key) , pshared(pshared) , ct(ct) - , shm(std::make_shared(size, 1 /* shareable flag */)) + , shm(null_ptr) { -#ifndef _WIN32 - // Optimization that's useless on Windows :puke: - utils::memory_lock(shm->map_self(), size); -#endif } lv2_memory::lv2_memory(utils::serial& ar) @@ -51,23 +47,17 @@ lv2_memory::lv2_memory(utils::serial& ar) , key(ar) , pshared(ar) , ct(lv2_memory_container::search(ar.pop())) - , shm([&](u32 addr) + , shm([&](u32 addr) -> shared_ptr> { if (addr) { - return ensure(vm::get(vm::any, addr)->peek(addr).second); + return make_single_value(ensure(vm::get(vm::any, addr)->peek(addr).second)); } - const auto _shm = std::make_shared(size, 1); - ar(std::span(_shm->map_self(), size)); - return _shm; + return null_ptr; }(ar.pop())) , counter(ar) { -#ifndef _WIN32 - // Optimization that's useless on Windows :puke: - utils::memory_lock(shm->map_self(), size); -#endif } CellError lv2_memory::on_id_create() @@ -84,7 +74,7 @@ CellError lv2_memory::on_id_create() std::function lv2_memory::load(utils::serial& ar) { - auto mem = make_shared(ar); + auto mem = make_shared(stx::exact_t(ar)); mem->exists++; // Disable on_id_create() auto func = load_func(mem, +mem->pshared); mem->exists--; @@ -96,13 +86,7 @@ void lv2_memory::save(utils::serial& ar) USING_SERIALIZATION_VERSION(lv2_memory); ar(size, align, flags, key, pshared, ct->id); - ar(counter ? vm::get_shm_addr(shm) : 0); - - if (!counter) - { - ar(std::span(shm->map_self(), size)); - } - + ar(counter ? vm::get_shm_addr(*shm.load()) : 0); ar(counter); } @@ -645,6 +629,22 @@ error_code sys_mmapper_map_shared_memory(ppu_thread& ppu, u32 addr, u32 mem_id, return CELL_EALIGN; } + for (stx::shared_ptr> to_insert, null; !mem.shm;) + { + // Insert atomically the memory handle (laziliy allocated) + if (!to_insert) + { + to_insert = make_single_value(std::make_shared(mem.size, 1 /* shareable flag */)); + } + + null.reset(); + + if (mem.shm.compare_exchange(null, to_insert)) + { + break; + } + } + mem.counter++; return {}; }); @@ -659,7 +659,9 @@ error_code sys_mmapper_map_shared_memory(ppu_thread& ppu, u32 addr, u32 mem_id, return mem.ret; } - if (!area->falloc(addr, mem->size, &mem->shm, mem->align == 0x10000 ? SYS_MEMORY_PAGE_SIZE_64K : SYS_MEMORY_PAGE_SIZE_1M)) + auto shm_ptr = *mem->shm.load(); + + if (!area->falloc(addr, mem->size, &shm_ptr, mem->align == 0x10000 ? SYS_MEMORY_PAGE_SIZE_64K : SYS_MEMORY_PAGE_SIZE_1M)) { mem->counter--; @@ -697,6 +699,22 @@ error_code sys_mmapper_search_and_map(ppu_thread& ppu, u32 start_addr, u32 mem_i return CELL_EALIGN; } + for (stx::shared_ptr> to_insert, null; !mem.shm;) + { + // Insert atomically the memory handle (laziliy allocated) + if (!to_insert) + { + to_insert = make_single_value(std::make_shared(mem.size, 1 /* shareable flag */)); + } + + null.reset(); + + if (mem.shm.compare_exchange(null, to_insert)) + { + break; + } + } + mem.counter++; return {}; }); @@ -711,7 +729,9 @@ error_code sys_mmapper_search_and_map(ppu_thread& ppu, u32 start_addr, u32 mem_i return mem.ret; } - const u32 addr = area->alloc(mem->size, &mem->shm, mem->align, mem->align == 0x10000 ? SYS_MEMORY_PAGE_SIZE_64K : SYS_MEMORY_PAGE_SIZE_1M); + auto shm_ptr = *mem->shm.load(); + + const u32 addr = area->alloc(mem->size, &shm_ptr, mem->align, mem->align == 0x10000 ? SYS_MEMORY_PAGE_SIZE_64K : SYS_MEMORY_PAGE_SIZE_1M); if (!addr) { @@ -755,7 +775,7 @@ error_code sys_mmapper_unmap_shared_memory(ppu_thread& ppu, u32 addr, vm::ptr([&](u32 id, lv2_memory& mem) -> u32 { - if (mem.shm.get() == shm.second.get()) + if (auto shm0 = mem.shm.load(); shm0 && shm0->get() == shm.second.get()) { return id; } diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_mmapper.h b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_mmapper.h index 544ff91..aec7278 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_mmapper.h +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_mmapper.h @@ -5,6 +5,8 @@ #include "Emu/Memory/vm_ptr.h" #include "Emu/Cell/ErrorCodes.h" +#include "util/shared_ptr.hpp" + #include struct lv2_memory_container; @@ -24,7 +26,7 @@ struct lv2_memory : lv2_obj const u64 key; // IPC key const bool pshared; // Process shared flag lv2_memory_container* const ct; // Associated memory container - const std::shared_ptr shm; + atomic_ptr> shm; atomic_t counter{0}; diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_mutex.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_mutex.cpp index c8ac190..92bf877 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_mutex.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_mutex.cpp @@ -1,7 +1,6 @@ #include "stdafx.h" #include "Emu/IdManager.h" -#include "Emu/IPC.h" #include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/PPUThread.h" @@ -27,7 +26,7 @@ lv2_mutex::lv2_mutex(utils::serial& ar) std::function lv2_mutex::load(utils::serial& ar) { - return load_func(make_shared(ar)); + return load_func(make_shared(stx::exact_t(ar))); } void lv2_mutex::save(utils::serial& ar) diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_net.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_net.cpp index 97d40d6..827a4c9 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_net.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_net.cpp @@ -15,7 +15,6 @@ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" #endif -#include #include #include #include @@ -24,7 +23,6 @@ #include #include #include -#include #include #ifdef __clang__ #pragma GCC diagnostic pop @@ -33,9 +31,7 @@ #include "Emu/NP/np_handler.h" #include "Emu/NP/np_helpers.h" -#include "Emu/NP/np_dnshook.h" - -#include +#include "Emu/Cell/timers.hpp" #include #include "sys_net/network_context.h" @@ -293,7 +289,7 @@ std::function lv2_socket::load(utils::serial& ar) sock_lv2->bind(sock_lv2->last_bound_addr); } - return [ptr = sock_lv2](void* storage) { *static_cast*>(storage) = ptr; };; + return [ptr = sock_lv2](void* storage) { *static_cast*>(storage) = ptr; };; } void lv2_socket::save(utils::serial& ar, bool save_only_this_class) diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_overlay.h b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_overlay.h index 1c950a4..1a204ba 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_overlay.h +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_overlay.h @@ -3,7 +3,6 @@ #include "Emu/Cell/PPUAnalyser.h" #include "Emu/Memory/vm_ptr.h" #include "sys_sync.h" -#include struct lv2_overlay final : ppu_module { diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp index 80e91bb..1b64849 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp @@ -16,6 +16,7 @@ #include "sys_memory.h" #include "util/asm.hpp" +#include LOG_CHANNEL(sys_ppu_thread); diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_process.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_process.cpp index 8038ffc..53e6437 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_process.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_process.cpp @@ -271,7 +271,7 @@ error_code _sys_process_get_paramsfo(vm::ptr buffer) { sys_process.warning("_sys_process_get_paramsfo(buffer=0x%x)", buffer); - if (!Emu.GetTitleID().length()) + if (Emu.GetTitleID().empty()) { return CELL_ENOENT; } @@ -498,6 +498,9 @@ void lv2_exitspawn(ppu_thread& ppu, std::vector& argv, std::vector< }; signal_system_cache_can_stay(); + + // Make sure we keep the game window opened + //Emu.SetContinuousMode(true); Emu.Kill(false); }); diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_semaphore.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_semaphore.cpp index 02e4052..7440cf2 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_semaphore.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_semaphore.cpp @@ -2,7 +2,6 @@ #include "sys_semaphore.h" #include "Emu/IdManager.h" -#include "Emu/IPC.h" #include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/PPUThread.h" diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_sm.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_sm.cpp index 5700be9..50a9b1c 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_sm.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_sm.cpp @@ -1,5 +1,4 @@ #include "stdafx.h" -#include "Emu/Memory/vm.h" #include "Emu/System.h" #include "Emu/Cell/ErrorCodes.h" diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_ss.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_ss.cpp index a602cd6..0315c3f 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_ss.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_ss.cpp @@ -553,7 +553,7 @@ error_code sys_ss_individual_info_manager(u64 pkg_id, u64 a2, vm::ptr out_s case 0x17002: { // TODO - vm::write(a5, a4); // Write back size of buffer + vm::write(static_cast(a5), a4); // Write back size of buffer break; } // Get EID size diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_storage.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_storage.cpp index d83a5b2..d5ee3bb 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_storage.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_storage.cpp @@ -1,5 +1,4 @@ #include "stdafx.h" -#include "Emu/Memory/vm.h" #include "Emu/IdManager.h" #include "Emu/Cell/ErrorCodes.h" diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_sync.h b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_sync.h index 644e0c9..bf99bcb 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_sync.h +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_sync.h @@ -1,19 +1,14 @@ #pragma once #include "Utilities/mutex.h" -#include "Utilities/sema.h" #include "Emu/CPU/CPUThread.h" #include "Emu/Cell/ErrorCodes.h" -#include "Emu/Cell/timers.hpp" -#include "Emu/Memory/vm_reservation.h" #include "Emu/IdManager.h" #include "Emu/IPC.h" #include "util/shared_ptr.hpp" -#include - // attr_protocol (waiting scheduling policy) enum lv2_protocol : u8 { @@ -449,7 +444,7 @@ public: static std::function load_func(shared_ptr make, u64 pshared = umax) { const u64 key = make->key; - return [ptr = load(key, make, pshared)](void* storage) { *static_cast*>(storage) = ptr; }; + return [ptr = load(key, make, pshared)](void* storage) { *static_cast*>(storage) = ptr; }; } static bool wait_timeout(u64 usec, ppu_thread* cpu = {}, bool scale = true, bool is_usleep = false); diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_time.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_time.cpp index c585b65..539bb9d 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_time.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_time.cpp @@ -378,7 +378,7 @@ error_code sys_time_get_current_time(vm::ptr sec, vm::ptr nsec) if (g_cfg.core.clocks_scale == 100) { // get the seconds from the system clock, and add the console time offset (which might be negative) - *sec = ts.tv_sec;// + g_cfg.sys.console_time_offset; + *sec = ts.tv_sec + g_cfg.sys.console_time_offset; if (!nsec) { @@ -410,7 +410,7 @@ error_code sys_time_get_current_time(vm::ptr sec, vm::ptr nsec) tv_nsec = stv_nsec + (tv_nsec * g_cfg.core.clocks_scale / 100); // Scale seconds and add from nanoseconds / 1'000'000'000, and add the console time offset (which might be negative) - *sec = stv_sec + (tv_sec * g_cfg.core.clocks_scale / 100u) + (tv_nsec / 1000000000ull);// + g_cfg.sys.console_time_offset; + *sec = stv_sec + (tv_sec * g_cfg.core.clocks_scale / 100u) + (tv_nsec / 1000000000ull) + g_cfg.sys.console_time_offset; if (!nsec) { diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_timer.h b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_timer.h index 14e1f31..8a0b2ed 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_timer.h +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_timer.h @@ -1,8 +1,6 @@ #pragma once #include "sys_event.h" - -#include "Utilities/Thread.h" #include "Emu/Memory/vm_ptr.h" diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_vm.cpp b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_vm.cpp index 2591824..2a224d2 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_vm.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Cell/lv2/sys_vm.cpp @@ -6,7 +6,6 @@ #include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/PPUThread.h" #include "Emu/Cell/timers.hpp" -#include "Emu/Memory/vm_locking.h" sys_vm_t::sys_vm_t(u32 _addr, u32 vsize, lv2_memory_container* ct, u32 psize) : ct(ct) diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/Memory/vm.h b/app/src/main/cpp/rpcs3/rpcs3/Emu/Memory/vm.h index 25ff1cd..2b2eccc 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/Memory/vm.h +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/Memory/vm.h @@ -34,6 +34,8 @@ namespace vm extern u8* const g_free_addr; extern u8 g_reservations[65536 / 128 * 64]; + static constexpr u64 g_exec_addr_seg_offset = 0x2'0000'0000ULL; + struct writer_lock; enum memory_location_t : uint diff --git a/app/src/main/cpp/rpcs3/rpcs3/Emu/system_config.h b/app/src/main/cpp/rpcs3/rpcs3/Emu/system_config.h index bf63117..422a90c 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/Emu/system_config.h +++ b/app/src/main/cpp/rpcs3/rpcs3/Emu/system_config.h @@ -42,7 +42,8 @@ struct cfg_root : cfg::node cfg::_bool set_daz_and_ftz{ this, "Set DAZ and FTZ", false }; cfg::_enum spu_decoder{ this, "SPU Decoder", spu_decoder_type::llvm }; cfg::uint<0, 100> spu_reservation_busy_waiting_percentage{ this, "SPU Reservation Busy Waiting Percentage", 0, true }; - cfg::uint<0, 101> spu_getllar_busy_waiting_percentage{ this, "SPU GETLLAR Busy Waiting Percentage", 100, true }; + cfg::_bool spu_reservation_busy_waiting_enabled{ this, "SPU Reservation Busy Waiting Enabled", false, true }; + cfg::uint<0, 100> spu_getllar_busy_waiting_percentage{ this, "SPU GETLLAR Busy Waiting Percentage", 100, true }; cfg::_bool spu_getllar_spin_optimization_disabled{ this, "Disable SPU GETLLAR Spin Optimization", false, true }; cfg::_bool spu_debug{ this, "SPU Debug" }; cfg::_bool mfc_debug{ this, "MFC Debug" }; @@ -351,7 +352,7 @@ struct cfg_root : cfg::node cfg::_enum language{ this, "Language", CellSysutilLang{1} }; // CELL_SYSUTIL_LANG_ENGLISH_US cfg::_enum keyboard_type{ this, "Keyboard Type", CellKbMappingType{0} }; // CELL_KB_MAPPING_101 = US cfg::_enum enter_button_assignment{ this, "Enter button assignment", enter_button_assign::cross }; - //cfg::_int<-60*60*24*365*100LL, 60*60*24*365*100LL> console_time_offset{ this, "Console time offset (s)", 0 }; // console time offset, limited to +/-100years + cfg::_int<-60*60*24*365*100LL, 60*60*24*365*100LL> console_time_offset{ this, "Console time offset (s)", 0 }; // console time offset, limited to +/-100years cfg::string system_name{this, "System Name", get_random_system_name()}; cfg::uint<0, umax> console_psid_high{this, "PSID high"}; cfg::uint<0, umax> console_psid_low{this, "PSID low"}; diff --git a/app/src/main/cpp/rpcs3/rpcs3/util/atomic.cpp b/app/src/main/cpp/rpcs3/rpcs3/util/atomic.cpp index 9a8638c..c8e76cb 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/util/atomic.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/util/atomic.cpp @@ -28,23 +28,21 @@ namespace utils #include "Utilities/sync.h" #include "Utilities/StrFmt.h" -#if defined(__linux__) && !defined(__ANDROID__) +#ifdef __linux__ static bool has_waitv() { static const bool s_has_waitv = [] { +#ifndef ANDROID + // FIXME: it produces SIGSYS signal syscall(SYS_futex_waitv, 0, 0, 0, 0, 0); - if (errno == ENOSYS) - return false; - return true; + return errno != ENOSYS; +#endif + return false; }(); return s_has_waitv; } -#elif defined(__ANDROID__) -constexpr bool has_waitv() { - return false; -} #endif #include @@ -59,8 +57,8 @@ constexpr bool has_waitv() { // Total number of entries. static constexpr usz s_hashtable_size = 1u << 17; -// Reference counter combined with shifted pointer (which is assumed to be 48 bit) -static constexpr uptr s_ref_mask = 0xffff; +// Reference counter mask +static constexpr uptr s_ref_mask = 0xffff'ffff; // Fix for silly on-first-use initializer static bool s_null_wait_cb(const void*, u64, u64){ return true; }; @@ -155,8 +153,16 @@ namespace // Essentially a fat semaphore struct alignas(64) cond_handle { - // Combined pointer (most significant 48 bits) and ref counter (16 least significant bits) - atomic_t ptr_ref; + struct fat_ptr + { + u64 ptr{}; + u32 reserved{}; + u32 ref_ctr{}; + + auto operator<=>(const fat_ptr& other) const = default; + }; + + atomic_t ptr_ref; u64 tid; u32 oldv; @@ -174,8 +180,10 @@ namespace { #ifdef _WIN32 tid = GetCurrentThreadId(); +#elif defined(ANDROID) + tid = pthread_self(); #else - tid = static_cast(pthread_self()); + tid = reinterpret_cast(pthread_self()); #endif #ifdef USE_STD @@ -183,7 +191,7 @@ namespace mtx.init(mtx); #endif - ensure(!ptr_ref.exchange((iptr << 16) | 1)); + ensure(ptr_ref.exchange(fat_ptr{iptr, 0, 1}) == fat_ptr{}); } void destroy() @@ -370,7 +378,7 @@ namespace if (cond_id) { // Set fake refctr - s_cond_list[cond_id].ptr_ref.release(1); + s_cond_list[cond_id].ptr_ref.release(cond_handle::fat_ptr{0, 0, 1}); cond_free(cond_id, -1); } } @@ -390,7 +398,7 @@ static u32 cond_alloc(uptr iptr, u32 tls_slot = -1) { // Fast reinitialize const u32 id = std::exchange(*ptls, 0); - s_cond_list[id].ptr_ref.release((iptr << 16) | 1); + s_cond_list[id].ptr_ref.release(cond_handle::fat_ptr{iptr, 0, 1}); return id; } @@ -461,15 +469,15 @@ static void cond_free(u32 cond_id, u32 tls_slot = -1) const auto cond = s_cond_list + cond_id; // Dereference, destroy on last ref - const bool last = cond->ptr_ref.atomic_op([](u64& val) + const bool last = cond->ptr_ref.atomic_op([](cond_handle::fat_ptr& val) { - ensure(val & s_ref_mask); + ensure(val.ref_ctr); - val--; + val.ref_ctr--; - if ((val & s_ref_mask) == 0) + if (val.ref_ctr == 0) { - val = 0; + val = cond_handle::fat_ptr{}; return true; } @@ -525,15 +533,15 @@ static cond_handle* cond_id_lock(u32 cond_id, uptr iptr = 0) while (true) { - const auto [old, ok] = cond->ptr_ref.fetch_op([&](u64& val) + const auto [old, ok] = cond->ptr_ref.fetch_op([&](cond_handle::fat_ptr& val) { - if (!val || (val & s_ref_mask) == s_ref_mask) + if (val == cond_handle::fat_ptr{} || val.ref_ctr == s_ref_mask) { // Don't reference already deallocated semaphore return false; } - if (iptr && (val >> 16) != iptr) + if (iptr && val.ptr != iptr) { // Pointer mismatch return false; @@ -548,7 +556,7 @@ static cond_handle* cond_id_lock(u32 cond_id, uptr iptr = 0) if (!did_ref) { - val++; + val.ref_ctr++; } return true; @@ -566,7 +574,7 @@ static cond_handle* cond_id_lock(u32 cond_id, uptr iptr = 0) return cond; } - if ((old & s_ref_mask) == s_ref_mask) + if (old.ref_ctr == s_ref_mask) { fmt::throw_exception("Reference count limit (%u) reached in an atomic notifier.", s_ref_mask); } @@ -589,12 +597,14 @@ namespace u64 maxc: 5; // Collision counter u64 maxd: 11; // Distance counter u64 bits: 24; // Allocated bits - u64 prio: 24; // Reserved + u64 prio: 8; // Reserved u64 ref : 16; // Ref counter - u64 iptr: 48; // First pointer to use slot (to count used slots) + u64 iptr: 64; // First pointer to use slot (to count used slots) }; + static_assert(sizeof(slot_allocator) == 16); + // Need to spare 16 bits for ref counter static constexpr u64 max_threads = 24; @@ -863,8 +873,7 @@ atomic_wait_engine::wait(const void* data, u32 old_value, u64 timeout, atomic_wa { uint ext_size = 0; - -#if defined(__linux__) +#ifdef __linux__ ::timespec ts{}; if (timeout + 1) { @@ -936,7 +945,7 @@ atomic_wait_engine::wait(const void* data, u32 old_value, u64 timeout, atomic_wa const auto stamp0 = utils::get_unique_tsc(); - const uptr iptr = reinterpret_cast(data) & (~s_ref_mask >> 16); + const uptr iptr = reinterpret_cast(data); uptr iptr_ext[atomic_wait::max_list - 1]{}; @@ -957,7 +966,7 @@ atomic_wait_engine::wait(const void* data, u32 old_value, u64 timeout, atomic_wa } } - iptr_ext[ext_size] = reinterpret_cast(e->data) & (~s_ref_mask >> 16); + iptr_ext[ext_size] = reinterpret_cast(e->data); ext_size++; } } @@ -1260,15 +1269,14 @@ void atomic_wait_engine::set_one_time_use_wait_callback(bool(*cb)(u64 progress)) void atomic_wait_engine::notify_one(const void* data) { - -#if defined(__linux__) +#ifdef __linux__ if (has_waitv()) { futex(const_cast(data), FUTEX_WAKE_PRIVATE, 1); return; } #endif - const uptr iptr = reinterpret_cast(data) & (~s_ref_mask >> 16); + const uptr iptr = reinterpret_cast(data); root_info::slot_search(iptr, [&](u32 cond_id) { @@ -1284,15 +1292,14 @@ void atomic_wait_engine::notify_one(const void* data) SAFE_BUFFERS(void) atomic_wait_engine::notify_all(const void* data) { - -#if defined(__linux__) +#ifdef __linux__ if (has_waitv()) { futex(const_cast(data), FUTEX_WAKE_PRIVATE, INT_MAX); return; } #endif - const uptr iptr = reinterpret_cast(data) & (~s_ref_mask >> 16); + const uptr iptr = reinterpret_cast(data); // Array count for batch notification u32 count = 0; diff --git a/app/src/main/cpp/rpcs3/rpcs3/util/atomic.hpp b/app/src/main/cpp/rpcs3/rpcs3/util/atomic.hpp index 593b7a5..80d9e34 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/util/atomic.hpp +++ b/app/src/main/cpp/rpcs3/rpcs3/util/atomic.hpp @@ -205,9 +205,9 @@ namespace atomic_wait constexpr void set(lf_queue& var, std::nullptr_t = nullptr) { static_assert(Index < Max); - static_assert(sizeof(var) == sizeof(uptr)); + static_assert(sizeof(var) == sizeof(uptr) * 2); - m_info[Index].data = reinterpret_cast(&var) + sizeof(u32); + m_info[Index].data = std::bit_cast(&var.get_wait_atomic().raw()); m_info[Index].old = 0; } @@ -215,9 +215,9 @@ namespace atomic_wait constexpr void set(stx::atomic_ptr& var, std::nullptr_t = nullptr) { static_assert(Index < Max); - static_assert(sizeof(var) == sizeof(uptr)); + static_assert(sizeof(var) == sizeof(uptr) * 2); - m_info[Index].data = reinterpret_cast(&var) + sizeof(u32); + m_info[Index].data = std::bit_cast(&var.get_wait_atomic().raw()); m_info[Index].old = 0; } diff --git a/app/src/main/cpp/rpcs3/rpcs3/util/dyn_lib.cpp b/app/src/main/cpp/rpcs3/rpcs3/util/dyn_lib.cpp index d739a28..1177aff 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/util/dyn_lib.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/util/dyn_lib.cpp @@ -29,6 +29,14 @@ namespace utils return loaded(); } +#ifdef _WIN32 + bool dynamic_library::load(const std::wstring& path) + { + m_handle = LoadLibraryW(path.c_str()); + return loaded(); + } +#endif + void dynamic_library::close() { #ifdef _WIN32 @@ -39,12 +47,12 @@ namespace utils m_handle = nullptr; } - void* dynamic_library::get_impl(const std::string& name) const + void* dynamic_library::get_impl(const char* name) const { #ifdef _WIN32 - return reinterpret_cast(GetProcAddress(reinterpret_cast(m_handle), name.c_str())); + return reinterpret_cast(GetProcAddress(reinterpret_cast(m_handle), name)); #else - return dlsym(m_handle, name.c_str()); + return dlsym(m_handle, name); #endif } diff --git a/app/src/main/cpp/rpcs3/rpcs3/util/dyn_lib.hpp b/app/src/main/cpp/rpcs3/rpcs3/util/dyn_lib.hpp index dcd958a..2968f8d 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/util/dyn_lib.hpp +++ b/app/src/main/cpp/rpcs3/rpcs3/util/dyn_lib.hpp @@ -31,26 +31,19 @@ namespace utils ~dynamic_library(); bool load(const std::string& path); +#ifdef _WIN32 + bool load(const std::wstring& path); +#endif void close(); private: - void* get_impl(const std::string& name) const; + void* get_impl(const char* name) const; public: template - Type* get(const std::string& name) const + Type get(const char* name) const { - Type* result; - *reinterpret_cast(&result) = get_impl(name); - return result; - } - - template - bool get(Type*& function, const std::string& name) const - { - *reinterpret_cast(&function) = get_impl(name); - - return function != nullptr; + return reinterpret_cast(get_impl(name)); } bool loaded() const; diff --git a/app/src/main/cpp/rpcs3/rpcs3/util/media_utils.cpp b/app/src/main/cpp/rpcs3/rpcs3/util/media_utils.cpp index 4ba78cb..73bc86e 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/util/media_utils.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/util/media_utils.cpp @@ -3,6 +3,7 @@ #include "Emu/System.h" #include +#include #ifdef _MSC_VER #pragma warning(push, 0) diff --git a/app/src/main/cpp/rpcs3/rpcs3/util/media_utils.h b/app/src/main/cpp/rpcs3/rpcs3/util/media_utils.h index 9666e53..471bda6 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/util/media_utils.h +++ b/app/src/main/cpp/rpcs3/rpcs3/util/media_utils.h @@ -2,13 +2,11 @@ #include "Utilities/StrUtil.h" #include "Utilities/Thread.h" -#include "util/video_provider.h" +#include "util/video_sink.h" #include "Emu/Cell/Modules/cellMusic.h" #include #include -#include -#include namespace utils { diff --git a/app/src/main/cpp/rpcs3/rpcs3/util/serialization_ext.cpp b/app/src/main/cpp/rpcs3/rpcs3/util/serialization_ext.cpp index 62874d9..508cd79 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/util/serialization_ext.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/util/serialization_ext.cpp @@ -1,9 +1,8 @@ #include "util/types.hpp" #include "util/logs.hpp" #include "util/asm.hpp" -#include "util/simd.hpp" +#include "util/sysinfo.hpp" #include "util/endian.hpp" - #include "Utilities/lockless.h" #include "Utilities/File.h" #include "Utilities/StrFmt.h" diff --git a/app/src/main/cpp/rpcs3/rpcs3/util/serialization_ext.hpp b/app/src/main/cpp/rpcs3/rpcs3/util/serialization_ext.hpp index 75b6212..51071e7 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/util/serialization_ext.hpp +++ b/app/src/main/cpp/rpcs3/rpcs3/util/serialization_ext.hpp @@ -187,7 +187,6 @@ private: void initialize(utils::serial& ar); void stream_data_prepare_thread_op(); void file_writer_thread_op(); - void blocked_compressed_write(const std::vector& data); }; template requires (std::is_same_v, fs::file>) diff --git a/app/src/main/cpp/rpcs3/rpcs3/util/shared_ptr.hpp b/app/src/main/cpp/rpcs3/rpcs3/util/shared_ptr.hpp index fb3c2c4..093d90e 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/util/shared_ptr.hpp +++ b/app/src/main/cpp/rpcs3/rpcs3/util/shared_ptr.hpp @@ -1,6 +1,5 @@ #pragma once // No BOM and only basic ASCII in this header, or a neko will die -#include #include #include #include "atomic.hpp" @@ -20,14 +19,8 @@ namespace stx template class atomic_ptr; - // Basic assumption of userspace pointer size - constexpr uint c_ptr_size = 48; - - // Use lower 16 bits as atomic_ptr internal counter of borrowed refs (pointer itself is shifted) - constexpr uint c_ref_mask = 0xffff, c_ref_size = 16; - - // Remaining pointer bits - constexpr uptr c_ptr_mask = static_cast(-1) << c_ref_size; + // Use 16 bits as atomic_ptr internal counter of borrowed refs + constexpr uint c_ref_mask = 0xffff; struct shared_counter { @@ -361,13 +354,8 @@ namespace stx [[deprecated("Use null_ptr")]] shared_ptr(std::nullptr_t) = delete; // Not-so-aliasing constructor: emulates std::enable_shared_from_this without its overhead - explicit shared_ptr(T* _this) noexcept - : m_ptr(_this) - { - // Random checks which may fail on invalid pointer - ensure((reinterpret_cast(d()->destroy) - 0x10000) >> 47 == 0); - ensure((d()->refs++ - 1) >> 58 == 0); - } + template + friend shared_ptr make_shared_from_this(const Type* _this) noexcept; template requires same_ptr_implicit_v shared_ptr(const shared_ptr& r) noexcept @@ -562,20 +550,45 @@ namespace stx template requires (std::is_constructible_v, T&&>) - static shared_ptr> make_shared_value(T&& value) + static shared_ptr> make_shared_value(T&& value) noexcept { return make_single_value(std::forward(value)); } + // Not-so-aliasing constructor: emulates std::enable_shared_from_this without its overhead + template + static shared_ptr make_shared_from_this(const T* _this) noexcept + { + shared_ptr r; + r.m_ptr = const_cast(_this); + + if (!_this) [[unlikely]] + { + return r; + } + + // Random checks which may fail on invalid pointer + ensure((r.d()->refs++ - 1) >> 58 == 0); + return r; + } + // Atomic simplified shared pointer template class atomic_ptr { - mutable atomic_t m_val{0}; - - static shared_counter* d(uptr val) noexcept + private: + struct fat_ptr { - return std::launder(reinterpret_cast((val >> c_ref_size) - sizeof(shared_counter))); + uptr ptr{}; + u32 is_non_null{}; + u32 ref_ctr{}; + }; + + mutable atomic_t m_val{fat_ptr{}}; + + static shared_counter* d(fat_ptr val) noexcept + { + return std::launder(reinterpret_cast(val.ptr - sizeof(shared_counter))); } shared_counter* d() const noexcept @@ -583,14 +596,19 @@ namespace stx return d(m_val); } - static uptr to_val(const volatile std::remove_extent_t* ptr) noexcept + static fat_ptr to_val(const volatile std::remove_extent_t* ptr) noexcept { - return (reinterpret_cast(ptr) << c_ref_size); + return fat_ptr{reinterpret_cast(ptr), ptr != nullptr, 0}; } - static std::remove_extent_t* ptr_to(uptr val) noexcept + static fat_ptr to_val(uptr ptr) noexcept { - return reinterpret_cast*>(val >> c_ref_size); + return fat_ptr{ptr, ptr != 0, 0}; + } + + static std::remove_extent_t* ptr_to(fat_ptr val) noexcept + { + return reinterpret_cast*>(val.ptr); } template @@ -633,7 +651,7 @@ namespace stx atomic_ptr(const shared_ptr& r) noexcept { // Obtain a ref + as many refs as an atomic_ptr can additionally reference - if (uptr rval = to_val(r.m_ptr)) + if (fat_ptr rval = to_val(r.m_ptr); rval.ptr != 0) { m_val.raw() = rval; d(rval)->refs += c_ref_mask + 1; @@ -643,7 +661,7 @@ namespace stx template requires same_ptr_implicit_v atomic_ptr(shared_ptr&& r) noexcept { - if (uptr rval = to_val(r.m_ptr)) + if (fat_ptr rval = to_val(r.m_ptr); rval.ptr != 0) { m_val.raw() = rval; d(rval)->refs += c_ref_mask; @@ -655,7 +673,7 @@ namespace stx template requires same_ptr_implicit_v atomic_ptr(single_ptr&& r) noexcept { - if (uptr rval = to_val(r.m_ptr)) + if (fat_ptr rval = to_val(r.m_ptr); rval.ptr != 0) { m_val.raw() = rval; d(rval)->refs += c_ref_mask; @@ -666,13 +684,13 @@ namespace stx ~atomic_ptr() noexcept { - const uptr v = m_val.raw(); + const fat_ptr v = m_val.raw(); - if (v >> c_ref_size) + if (v.ptr) { const auto o = d(v); - if (!o->refs.sub_fetch(c_ref_mask + 1 - (v & c_ref_mask))) + if (!o->refs.sub_fetch(c_ref_mask + 1 - (v.ref_ctr & c_ref_mask))) { o->destroy.load()(o); } @@ -721,11 +739,11 @@ namespace stx shared_type r; // Add reference - const auto [prev, did_ref] = m_val.fetch_op([](uptr& val) + const auto [prev, did_ref] = m_val.fetch_op([](fat_ptr& val) { - if (val >> c_ref_size) + if (val.ptr) { - val++; + val.ref_ctr++; return true; } @@ -743,11 +761,11 @@ namespace stx r.d()->refs++; // Dereference if still the same pointer - const auto [_, did_deref] = m_val.fetch_op([prev = prev](uptr& val) + const auto [_, did_deref] = m_val.fetch_op([prev = prev](fat_ptr& val) { - if (val >> c_ref_size == prev >> c_ref_size) + if (val.ptr == prev.ptr) { - val--; + val.ref_ctr--; return true; } @@ -770,11 +788,11 @@ namespace stx shared_type r; // Add reference - const auto [prev, did_ref] = m_val.fetch_op([](uptr& val) + const auto [prev, did_ref] = m_val.fetch_op([](fat_ptr& val) { - if (val >> c_ref_size) + if (val.ptr) { - val++; + val.ref_ctr++; return true; } @@ -811,11 +829,11 @@ namespace stx } // Dereference if still the same pointer - const auto [_, did_deref] = m_val.fetch_op([prev = prev](uptr& val) + const auto [_, did_deref] = m_val.fetch_op([prev = prev](fat_ptr& val) { - if (val >> c_ref_size == prev >> c_ref_size) + if (val.ptr == prev.ptr) { - val--; + val.ref_ctr--; return true; } @@ -876,7 +894,7 @@ namespace stx atomic_ptr old; old.m_val.raw() = m_val.exchange(to_val(r.m_ptr)); - old.m_val.raw() += 1; + old.m_val.raw().ref_ctr += 1; r.m_ptr = std::launder(ptr_to(old.m_val)); return r; @@ -892,7 +910,7 @@ namespace stx atomic_ptr old; old.m_val.raw() = m_val.exchange(to_val(value.m_ptr)); - old.m_val.raw() += 1; + old.m_val.raw().ref_ctr += 1; value.m_ptr = std::launder(ptr_to(old.m_val)); return value; @@ -911,21 +929,21 @@ namespace stx atomic_ptr old; - const uptr _val = m_val.fetch_op([&](uptr& val) + const fat_ptr _val = m_val.fetch_op([&](fat_ptr& val) { - if (val >> c_ref_size == _old) + if (val.ptr == _old) { // Set new value - val = _new << c_ref_size; + val = to_val(_new); } - else if (val) + else if (val.ptr != 0) { // Reference previous value - val++; + val.ref_ctr++; } }); - if (_val >> c_ref_size == _old) + if (_val.ptr == _old) { // Success (exch is consumed, cmp_and_old is unchanged) if (exch.m_ptr) @@ -942,9 +960,10 @@ namespace stx old_exch.m_val.raw() = to_val(std::exchange(exch.m_ptr, nullptr)); // Set to reset old cmp_and_old value - old.m_val.raw() = to_val(cmp_and_old.m_ptr) | c_ref_mask; + old.m_val.raw() = to_val(cmp_and_old.m_ptr); + old.m_val.raw().ref_ctr |= c_ref_mask; - if (!_val) + if (!_val.ptr) { return false; } @@ -954,11 +973,11 @@ namespace stx cmp_and_old.d()->refs++; // Dereference if still the same pointer - const auto [_, did_deref] = m_val.fetch_op([_val](uptr& val) + const auto [_, did_deref] = m_val.fetch_op([_val](fat_ptr& val) { - if (val >> c_ref_size == _val >> c_ref_size) + if (val.ptr == _val.ptr) { - val--; + val.ref_ctr--; return true; } @@ -997,12 +1016,12 @@ namespace stx atomic_ptr old; - const auto [_val, ok] = m_val.fetch_op([&](uptr& val) + const auto [_val, ok] = m_val.fetch_op([&](fat_ptr& val) { - if (val >> c_ref_size == _old) + if (val.ptr == _old) { // Set new value - val = _new << c_ref_size; + val = to_val(_new); return true; } @@ -1059,9 +1078,9 @@ namespace stx do { // Update old head with current value - next.m_ptr = reinterpret_cast(old.m_val.raw() >> c_ref_size); + next.m_ptr = std::launder(ptr_to(old.m_val.raw())); - } while (!m_val.compare_exchange(old.m_val.raw(), reinterpret_cast(exch.m_ptr) << c_ref_size)); + } while (!m_val.compare_exchange(old.m_val.raw(), to_val(exch.m_ptr))); // This argument is consumed (moved from) exch.m_ptr = nullptr; @@ -1069,19 +1088,19 @@ namespace stx if (next.m_ptr) { // Compensation for `next` assignment - old.m_val.raw() += 1; + old.m_val.raw().ref_ctr += 1; } } // Simple atomic load is much more effective than load(), but it's a non-owning reference T* observe() const noexcept { - return reinterpret_cast(m_val >> c_ref_size); + return std::launder(ptr_to(m_val)); } explicit constexpr operator bool() const noexcept { - return m_val != 0; + return observe() != nullptr; } template requires same_ptr_implicit_v @@ -1096,19 +1115,24 @@ namespace stx return static_cast(observe()) == r.get(); } + atomic_t &get_wait_atomic() + { + return *utils::bless>(&m_val.raw().is_non_null); + } + void wait(std::nullptr_t, atomic_wait_timeout timeout = atomic_wait_timeout::inf) { - utils::bless>(&m_val)[1].wait(0, timeout); + get_wait_atomic().wait(0, timeout); } void notify_one() { - utils::bless>(&m_val)[1].notify_one(); + get_wait_atomic().notify_one(); } void notify_all() { - utils::bless>(&m_val)[1].notify_all(); + get_wait_atomic().notify_all(); } }; @@ -1138,11 +1162,6 @@ namespace stx return false; } - constexpr std::nullptr_t get() const noexcept - { - return nullptr; - } - } null_ptr; } diff --git a/app/src/main/cpp/rpcs3/rpcs3/util/types.hpp b/app/src/main/cpp/rpcs3/rpcs3/util/types.hpp index c0f3531..690f51c 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/util/types.hpp +++ b/app/src/main/cpp/rpcs3/rpcs3/util/types.hpp @@ -213,8 +213,9 @@ template using atomic_be_t = atomic_t, Align>; template using atomic_le_t = atomic_t, Align>; -template +// Removes be_t<> wrapper from type be_ with nop fallback for unwrapped T +template struct remove_be { using type = T; }; template struct remove_be> { using type = T; }; @@ -1199,7 +1200,7 @@ constexpr void write_to_ptr(U&& array, usz pos, const T& value) { static_assert(sizeof(T) % sizeof(array[0]) == 0); if (!std::is_constant_evaluated()) - std::memcpy(&array[pos], &value, sizeof(value)); + std::memcpy(static_cast(&array[pos]), &value, sizeof(value)); else ensure(!"Unimplemented"); } @@ -1209,7 +1210,7 @@ constexpr void write_to_ptr(U&& array, const T& value) { static_assert(sizeof(T) % sizeof(array[0]) == 0); if (!std::is_constant_evaluated()) - std::memcpy(&array[0], &value, sizeof(value)); + std::memcpy(static_cast(&array[0]), &value, sizeof(value)); else ensure(!"Unimplemented"); } diff --git a/app/src/main/cpp/rpcs3/rpcs3/util/video_provider.cpp b/app/src/main/cpp/rpcs3/rpcs3/util/video_provider.cpp index 7088844..82f133b 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/util/video_provider.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/util/video_provider.cpp @@ -162,7 +162,7 @@ namespace utils } } - void video_provider::present_samples(u8* buf, u32 sample_count, u16 channels) + void video_provider::present_samples(const u8* buf, u32 sample_count, u16 channels) { if (!buf || !sample_count || !channels || !m_active) { diff --git a/app/src/main/cpp/rpcs3/rpcs3/util/video_provider.h b/app/src/main/cpp/rpcs3/rpcs3/util/video_provider.h index abe9c7a..e21b518 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/util/video_provider.h +++ b/app/src/main/cpp/rpcs3/rpcs3/util/video_provider.h @@ -23,7 +23,7 @@ namespace utils bool can_consume_frame(); void present_frame(std::vector& data, u32 pitch, u32 width, u32 height, bool is_bgra); - void present_samples(u8* buf, u32 sample_count, u16 channels); + void present_samples(const u8* buf, u32 sample_count, u16 channels); private: recording_mode check_mode(); @@ -33,7 +33,7 @@ namespace utils shared_mutex m_video_mutex{}; shared_mutex m_audio_mutex{}; atomic_t m_active{false}; - atomic_t m_start_time_us{static_cast(umax)}; + atomic_t m_start_time_us{umax}; s64 m_last_video_pts_incoming = -1; s64 m_last_audio_pts_incoming = -1; usz m_pause_time_us = 0; diff --git a/app/src/main/cpp/rpcs3/rpcs3/util/vm_native.cpp b/app/src/main/cpp/rpcs3/rpcs3/util/vm_native.cpp index 536b8b6..156af86 100644 --- a/app/src/main/cpp/rpcs3/rpcs3/util/vm_native.cpp +++ b/app/src/main/cpp/rpcs3/rpcs3/util/vm_native.cpp @@ -1,5 +1,4 @@ #include "stdafx.h" -#include "util/logs.hpp" #include "util/vm.hpp" #include "util/asm.hpp" #ifdef _WIN32 @@ -319,15 +318,15 @@ namespace utils ensure(::VirtualAlloc(pointer, size, MEM_COMMIT, +prot)); #else const u64 ptr64 = reinterpret_cast(pointer); - ensure(::mprotect(reinterpret_cast(ptr64 & -c_page_size), size + (ptr64 & (c_page_size - 1)), +prot) != -1); + ensure(::mprotect(reinterpret_cast(ptr64 & -get_page_size()), size + (ptr64 & (get_page_size() - 1)), +prot) != -1); if constexpr (c_madv_dump != 0) { - ensure(::madvise(reinterpret_cast(ptr64 & -c_page_size), size + (ptr64 & (c_page_size - 1)), c_madv_dump) != -1); + ensure(::madvise(reinterpret_cast(ptr64 & -get_page_size()), size + (ptr64 & (get_page_size() - 1)), c_madv_dump) != -1); } else { - ensure(::madvise(reinterpret_cast(ptr64 & -c_page_size), size + (ptr64 & (c_page_size - 1)), MADV_WILLNEED) != -1); + ensure(::madvise(reinterpret_cast(ptr64 & -get_page_size()), size + (ptr64 & (get_page_size() - 1)), MADV_WILLNEED) != -1); } #endif } @@ -356,11 +355,11 @@ namespace utils if constexpr (c_madv_no_dump != 0) { - ensure(::madvise(reinterpret_cast(ptr64 & -c_page_size), size + (ptr64 & (c_page_size - 1)), c_madv_no_dump) != -1); + ensure(::madvise(reinterpret_cast(ptr64 & -get_page_size()), size + (ptr64 & (get_page_size() - 1)), c_madv_no_dump) != -1); } else { - ensure(::madvise(reinterpret_cast(ptr64 & -c_page_size), size + (ptr64 & (c_page_size - 1)), c_madv_free) != -1); + ensure(::madvise(reinterpret_cast(ptr64 & -get_page_size()), size + (ptr64 & (get_page_size() - 1)), c_madv_free) != -1); } #endif } @@ -388,17 +387,17 @@ namespace utils { if (size % 0x200000 == 0) { - ::madvise(reinterpret_cast(ptr64 & -c_page_size), size + (ptr64 & (c_page_size - 1)), c_madv_hugepage); + ::madvise(reinterpret_cast(ptr64 & -get_page_size()), size + (ptr64 & (get_page_size() - 1)), c_madv_hugepage); } } if constexpr (c_madv_dump != 0) { - ensure(::madvise(reinterpret_cast(ptr64 & -c_page_size), size + (ptr64 & (c_page_size - 1)), c_madv_dump) != -1); + ensure(::madvise(reinterpret_cast(ptr64 & -get_page_size()), size + (ptr64 & (get_page_size() - 1)), c_madv_dump) != -1); } else { - ensure(::madvise(reinterpret_cast(ptr64 & -c_page_size), size + (ptr64 & (c_page_size - 1)), MADV_WILLNEED) != -1); + ensure(::madvise(reinterpret_cast(ptr64 & -get_page_size()), size + (ptr64 & (get_page_size() - 1)), MADV_WILLNEED) != -1); } #endif } @@ -448,7 +447,7 @@ namespace utils } #else const u64 ptr64 = reinterpret_cast(pointer); - ensure(::mprotect(reinterpret_cast(ptr64 & -c_page_size), size + (ptr64 & (c_page_size - 1)), +prot) != -1); + ensure(::mprotect(reinterpret_cast(ptr64 & -get_page_size()), size + (ptr64 & (get_page_size() - 1)), +prot) != -1); #endif } @@ -687,9 +686,8 @@ namespace utils #else #ifdef __linux__ - -#if defined(__ANDROID__) - if (const char c = 1;c) +#ifdef ANDROID + if constexpr (constexpr char c = '?') #else if (const char c = fs::file("/proc/sys/vm/overcommit_memory").read(); c == '0' || c == '1') #endif @@ -971,20 +969,24 @@ namespace utils { void* ptr = m_ptr; - while (!ptr) + for (void* mapped = nullptr; !ptr;) { - const auto mapped = this->map(nullptr, prot); + if (!mapped) + { + mapped = this->map(nullptr, prot); + } // Install mapped memory - if (!m_ptr.compare_exchange(ptr, mapped)) - { - // Mapped already, nothing to do. - this->unmap(mapped); - } - else + if (m_ptr.compare_exchange(ptr, mapped)) { ptr = mapped; } + else if (ptr) + { + // Mapped already, nothing to do. + ensure(ptr != mapped); + this->unmap(mapped); + } } return static_cast(ptr); @@ -1061,4 +1063,4 @@ namespace utils this->unmap(ptr); } } -} +} // namespace utils diff --git a/app/src/main/res/xml/emulator_settings.xml b/app/src/main/res/xml/emulator_settings.xml index 8d69fd9..152aaf8 100644 --- a/app/src/main/res/xml/emulator_settings.xml +++ b/app/src/main/res/xml/emulator_settings.xml @@ -73,7 +73,7 @@