diff --git a/README.md b/README.md index dff1889123..6b034b3ed4 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ __Windows__ * [Visual C++ Redistributable Packages for Visual Studio 2013](http://www.microsoft.com/en-us/download/details.aspx?id=40784) __Linux__ -* Debian & Ubuntu: `sudo apt-get install libopenal-dev libwxgtk3.0-dev build-essential` +* Debian & Ubuntu: `sudo apt-get install libopenal-dev libwxgtk3.0-dev build-essential libglew-dev` __Mac OSX__ * Install with Homebrew: `brew install glew wxwidgets` diff --git a/Utilities/Log.cpp b/Utilities/Log.cpp index 1f736617cf..562be95d8a 100644 --- a/Utilities/Log.cpp +++ b/Utilities/Log.cpp @@ -11,13 +11,13 @@ using namespace Log; LogManager *gLogManager = nullptr; -u32 LogMessage::size() +u32 LogMessage::size() const { //1 byte for NULL terminator return (u32)(sizeof(LogMessage::size_type) + sizeof(LogType) + sizeof(LogSeverity) + sizeof(std::string::value_type) * mText.size() + 1); } -void LogMessage::serialize(char *output) +void LogMessage::serialize(char *output) const { LogMessage::size_type size = this->size(); memcpy(output, &size, sizeof(LogMessage::size_type)); @@ -60,7 +60,7 @@ LogChannel::LogChannel(const std::string& name) : , mLogLevel(Warning) {} -void LogChannel::log(LogMessage msg) +void LogChannel::log(const LogMessage &msg) { std::lock_guard lock(mListenerLock); for (auto &listener : mListeners) @@ -82,7 +82,7 @@ void LogChannel::removeListener(std::shared_ptr listener) struct CoutListener : LogListener { - void log(LogMessage msg) + void log(const LogMessage &msg) { std::cerr << msg.mText << std::endl; } @@ -103,13 +103,15 @@ struct FileListener : LogListener } } - void log(LogMessage msg) + void log(const LogMessage &msg) { + std::string text = msg.mText; if (mPrependChannelName) { - msg.mText.insert(0, gTypeNameTable[static_cast(msg.mType)].mName); + text.insert(0, gTypeNameTable[static_cast(msg.mType)].mName); + } - mFile.Write(msg.mText); + mFile.Write(text); } }; diff --git a/Utilities/Log.h b/Utilities/Log.h index 46fc604f5a..c40d2a82c6 100644 --- a/Utilities/Log.h +++ b/Utilities/Log.h @@ -63,15 +63,15 @@ namespace Log LogSeverity mServerity; std::string mText; - u32 size(); - void serialize(char *output); + u32 size() const; + void serialize(char *output) const; static LogMessage deserialize(char *input, u32* size_out=nullptr); }; struct LogListener { virtual ~LogListener() {}; - virtual void log(LogMessage msg) = 0; + virtual void log(const LogMessage &msg) = 0; }; struct LogChannel @@ -80,7 +80,7 @@ namespace Log LogChannel(const std::string& name); LogChannel(LogChannel& other) = delete; LogChannel& operator = (LogChannel& other) = delete; - void log(LogMessage msg); + void log(const LogMessage &msg); void addListener(std::shared_ptr listener); void removeListener(std::shared_ptr listener); std::string name; diff --git a/Utilities/MTRingbuffer.h b/Utilities/MTRingbuffer.h index 991dbc077b..91b44d5a5b 100644 --- a/Utilities/MTRingbuffer.h +++ b/Utilities/MTRingbuffer.h @@ -30,7 +30,7 @@ public: { //wait until there's actually something to get //throwing an exception might be better, blocking here is a little awkward - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } size_t ret = mGet; mGet = moveGet(); @@ -45,7 +45,7 @@ public: { //if this is reached a lot it's time to increase the buffer size //or implement dynamic re-sizing - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } mBuffer[mPut] = std::forward(putEle); mPut = movePut(); @@ -94,7 +94,7 @@ public: { //if this is reached a lot it's time to increase the buffer size //or implement dynamic re-sizing - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } if (mPut + length <= mBuffer.size()) { diff --git a/Utilities/SMutex.cpp b/Utilities/SMutex.cpp deleted file mode 100644 index e10296bd68..0000000000 --- a/Utilities/SMutex.cpp +++ /dev/null @@ -1,10 +0,0 @@ -#include "stdafx.h" -#include "Emu/System.h" -#include "Emu/CPU/CPUThread.h" - -#include "Utilities/SMutex.h" - -bool SM_IsAborted() -{ - return Emu.IsStopped(); -} diff --git a/Utilities/SMutex.h b/Utilities/SMutex.h deleted file mode 100644 index 5d50fe18e1..0000000000 --- a/Utilities/SMutex.h +++ /dev/null @@ -1,129 +0,0 @@ -#pragma once -#include "Emu/Memory/atomic_type.h" - -bool SM_IsAborted(); - -enum SMutexResult -{ - SMR_OK = 0, // succeeded (lock, trylock, unlock) - SMR_FAILED, // failed (trylock, unlock) - SMR_DEADLOCK, // mutex reached deadlock (lock, trylock) - SMR_SIGNAL = SMR_DEADLOCK, // unlock can be used for signaling specific thread - SMR_PERMITTED, // not owner of the mutex (unlock) - SMR_ABORT, // emulator has been stopped (lock, trylock, unlock) - SMR_DESTROYED, // mutex has been destroyed (lock, trylock, unlock) - SMR_TIMEOUT, // timed out (lock) -}; - -template -< - typename T, - const u64 free_value = 0, - const u64 dead_value = 0xffffffffffffffffull -> -class SMutexBase -{ - static_assert(sizeof(T) == sizeof(atomic_le_t), "Invalid SMutexBase type"); - T owner; - typedef atomic_le_t AT; - -public: - static const T GetFreeValue() - { - static const u64 value = free_value; - return (T&)value; - } - - static const T GetDeadValue() - { - static const u64 value = dead_value; - return (T&)value; - } - - void initialize() - { - owner = GetFreeValue(); - } - - void finalize() - { - owner = GetDeadValue(); - } - - __forceinline T GetOwner() const - { - return (T&)owner; - } - - SMutexResult trylock(T tid) - { - if (SM_IsAborted()) - { - return SMR_ABORT; - } - T old = reinterpret_cast(owner).compare_and_swap(GetFreeValue(), tid); - - if (old != GetFreeValue()) - { - if (old == tid) - { - return SMR_DEADLOCK; - } - if (old == GetDeadValue()) - { - return SMR_DESTROYED; - } - return SMR_FAILED; - } - - return SMR_OK; - } - - SMutexResult unlock(T tid, T to = GetFreeValue()) - { - if (SM_IsAborted()) - { - return SMR_ABORT; - } - T old = reinterpret_cast(owner).compare_and_swap(tid, to); - - if (old != tid) - { - if (old == GetFreeValue()) - { - return SMR_FAILED; - } - if (old == GetDeadValue()) - { - return SMR_DESTROYED; - } - - return SMR_PERMITTED; - } - - return SMR_OK; - } - - SMutexResult lock(T tid, u64 timeout = 0) - { - u64 counter = 0; - - while (true) - { - switch (SMutexResult res = trylock(tid)) - { - case SMR_FAILED: break; - default: return res; - } - - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - - if (timeout && counter++ > timeout) - { - return SMR_TIMEOUT; - } - } - } -}; - -typedef SMutexBase SMutex; diff --git a/Utilities/SQueue.h b/Utilities/SQueue.h deleted file mode 100644 index aa131b69a6..0000000000 --- a/Utilities/SQueue.h +++ /dev/null @@ -1,118 +0,0 @@ -#pragma once - -static const volatile bool sq_no_wait = true; - -template -class SQueue -{ - mutable std::mutex m_mutex; - u32 m_pos; - u32 m_count; - T m_data[SQSize]; - -public: - SQueue() - : m_pos(0) - , m_count(0) - { - } - - u32 GetSize() const - { - return SQSize; - } - - bool IsFull() const volatile - { - return m_count == SQSize; - } - - bool Push(const T& data, const volatile bool* do_exit) - { - while (true) - { - if (m_count >= SQSize) - { - if (Emu.IsStopped() || (do_exit && *do_exit)) - { - return false; - } - - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - continue; - } - - { - std::lock_guard lock(m_mutex); - - if (m_count >= SQSize) continue; - - m_data[(m_pos + m_count++) % SQSize] = data; - - return true; - } - } - } - - bool Pop(T& data, const volatile bool* do_exit) - { - while (true) - { - if (!m_count) - { - if (Emu.IsStopped() || (do_exit && *do_exit)) - { - return false; - } - - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - continue; - } - - { - std::lock_guard lock(m_mutex); - - if (!m_count) continue; - - data = m_data[m_pos]; - m_pos = (m_pos + 1) % SQSize; - m_count--; - - return true; - } - } - } - - void Clear() - { - std::lock_guard lock(m_mutex); - m_count = 0; - } - - bool Peek(T& data, const volatile bool* do_exit, u32 pos = 0) - { - while (true) - { - if (m_count <= pos) - { - if (Emu.IsStopped() || (do_exit && *do_exit)) - { - return false; - } - - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - continue; - } - - { - std::lock_guard lock(m_mutex); - if (m_count > pos) - { - break; - } - } - } - data = m_data[(m_pos + pos) % SQSize]; - return true; - } -}; diff --git a/Utilities/StrFmt.cpp b/Utilities/StrFmt.cpp index 991f63ec35..1d3e6144e0 100644 --- a/Utilities/StrFmt.cpp +++ b/Utilities/StrFmt.cpp @@ -137,23 +137,42 @@ std::vector fmt::split(const std::string& source, std::initializer_ std::string fmt::merge(std::vector source, const std::string& separator) { - std::string result; - - for (auto &s : source) + if (!source.size()) { - result += s + separator; + return ""; } - return result; + std::string result; + + for (int i = 0; i < source.size() - 1; ++i) + { + result += source[i] + separator; + } + + return result + source[source.size() - 1]; } std::string fmt::merge(std::initializer_list> sources, const std::string& separator) { + if (!sources.size()) + { + return ""; + } + std::string result; + bool first = true; for (auto &v : sources) { - result += fmt::merge(v, separator); + if (first) + { + result = fmt::merge(v, separator); + first = false; + } + else + { + result += separator + fmt::merge(v, separator); + } } return result; @@ -164,4 +183,4 @@ std::string fmt::tolower(std::string source) std::transform(source.begin(), source.end(), source.begin(), ::tolower); return source; -} \ No newline at end of file +} diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index b7df2a5c96..6014c607bf 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -249,7 +249,7 @@ bool waiter_map_t::is_stopped(u64 signal_id) { if (Emu.IsStopped()) { - LOG_WARNING(Log::HLE, "%s.waiter_op() aborted (signal_id=0x%llx)", m_name.c_str(), signal_id); + LOG_WARNING(Log::HLE, "%s: waiter_op() aborted (signal_id=0x%llx)", m_name.c_str(), signal_id); return true; } return false; @@ -257,48 +257,56 @@ bool waiter_map_t::is_stopped(u64 signal_id) void waiter_map_t::waiter_reg_t::init() { - if (thread) return; + if (!thread) + { + thread = GetCurrentNamedThread(); - thread = GetCurrentNamedThread(); + std::lock_guard lock(map.m_mutex); - std::lock_guard lock(map.m_mutex); - - // add waiter - map.m_waiters.push_back({ signal_id, thread }); + // add waiter + map.m_waiters.push_back({ signal_id, thread }); + } } waiter_map_t::waiter_reg_t::~waiter_reg_t() { - if (!thread) return; - - std::lock_guard lock(map.m_mutex); - - // remove waiter - for (s64 i = map.m_waiters.size() - 1; i >= 0; i--) + if (thread) { - if (map.m_waiters[i].signal_id == signal_id && map.m_waiters[i].thread == thread) - { - map.m_waiters.erase(map.m_waiters.begin() + i); - return; - } - } + std::lock_guard lock(map.m_mutex); - LOG_ERROR(HLE, "%s(): waiter not found (signal_id=0x%llx, map='%s')", __FUNCTION__, signal_id, map.m_name.c_str()); - Emu.Pause(); + // remove waiter + for (s64 i = map.m_waiters.size() - 1; i >= 0; i--) + { + if (map.m_waiters[i].signal_id == signal_id && map.m_waiters[i].thread == thread) + { + map.m_waiters.erase(map.m_waiters.begin() + i); + return; + } + } + + LOG_ERROR(HLE, "%s(): waiter not found (signal_id=0x%llx, map='%s')", __FUNCTION__, signal_id, map.m_name.c_str()); + Emu.Pause(); + } } void waiter_map_t::notify(u64 signal_id) { - if (!m_waiters.size()) return; - - std::lock_guard lock(m_mutex); - - // find waiter and signal - for (auto& v : m_waiters) + if (m_waiters.size()) { - if (v.signal_id == signal_id) + std::lock_guard lock(m_mutex); + + // find waiter and signal + for (auto& v : m_waiters) { - v.thread->Notify(); + if (v.signal_id == signal_id) + { + v.thread->Notify(); + } } } } + +bool squeue_test_exit(const volatile bool* do_exit) +{ + return Emu.IsStopped() || (do_exit && *do_exit); +} diff --git a/Utilities/Thread.h b/Utilities/Thread.h index 09334171dc..4b54317bec 100644 --- a/Utilities/Thread.h +++ b/Utilities/Thread.h @@ -1,4 +1,5 @@ #pragma once +#include "Emu/Memory/atomic_type.h" static std::thread::id main_thread; @@ -71,33 +72,6 @@ public: bool joinable() const; }; -class s_mutex_t -{ - -}; - -class s_shared_mutex_t -{ - -}; - -class s_cond_var_t -{ - -//public: -// s_cond_var_t(); -// ~s_cond_var_t(); -// -// s_cond_var_t(s_cond_var_t& right) = delete; -// s_cond_var_t& operator = (s_cond_var_t& right) = delete; -// -// void wait(); -// void wait_for(); -// -// void notify(); -// void notify_all(); -}; - class slw_mutex_t { @@ -160,10 +134,10 @@ public: // register waiter waiter_reg_t waiter(*this, signal_id); - // check condition or if emulator is stopped + // check the condition or if the emulator is stopped while (!waiter_func() && !is_stopped(signal_id)) { - // initialize waiter (only first time) + // initialize waiter (only once) waiter.init(); // wait for 1 ms or until signal arrived waiter.thread->WaitForAnySignal(1); @@ -173,3 +147,313 @@ public: // signal all threads waiting on waiter_op() with the same signal_id (signaling only hints those threads that corresponding conditions are *probably* met) void notify(u64 signal_id); }; + +bool squeue_test_exit(const volatile bool* do_exit); + +template +class squeue_t +{ + struct squeue_sync_var_t + { + struct + { + u32 position : 31; + u32 pop_lock : 1; + }; + struct + { + u32 count : 31; + u32 push_lock : 1; + }; + }; + + atomic_le_t m_sync; + + mutable std::mutex m_rcv_mutex; + mutable std::mutex m_wcv_mutex; + mutable std::condition_variable m_rcv; + mutable std::condition_variable m_wcv; + + T m_data[sq_size]; + + enum squeue_sync_var_result : u32 + { + SQSVR_OK = 0, + SQSVR_LOCKED = 1, + SQSVR_FAILED = 2, + }; + +public: + squeue_t() + { + m_sync.write_relaxed({}); + } + + u32 get_max_size() const + { + return sq_size; + } + + bool is_full() const volatile + { + return m_sync.read_relaxed().count == sq_size; + } + + bool push(const T& data, const volatile bool* do_exit = nullptr) + { + u32 pos = 0; + + while (u32 res = m_sync.atomic_op_sync(SQSVR_OK, [&pos](squeue_sync_var_t& sync) -> u32 + { + assert(sync.count <= sq_size); + assert(sync.position < sq_size); + + if (sync.push_lock) + { + return SQSVR_LOCKED; + } + if (sync.count == sq_size) + { + return SQSVR_FAILED; + } + + sync.push_lock = 1; + pos = sync.position + sync.count; + return SQSVR_OK; + })) + { + if (res == SQSVR_FAILED && squeue_test_exit(do_exit)) + { + return false; + } + + std::unique_lock wcv_lock(m_wcv_mutex); + m_wcv.wait_for(wcv_lock, std::chrono::milliseconds(1)); + } + + m_data[pos >= sq_size ? pos - sq_size : pos] = data; + + m_sync.atomic_op([](squeue_sync_var_t& sync) + { + assert(sync.count <= sq_size); + assert(sync.position < sq_size); + assert(sync.push_lock); + sync.push_lock = 0; + sync.count++; + }); + + m_rcv.notify_one(); + m_wcv.notify_one(); + return true; + } + + bool try_push(const T& data) + { + static const volatile bool no_wait = true; + + return push(data, &no_wait); + } + + bool pop(T& data, const volatile bool* do_exit = nullptr) + { + u32 pos = 0; + + while (u32 res = m_sync.atomic_op_sync(SQSVR_OK, [&pos](squeue_sync_var_t& sync) -> u32 + { + assert(sync.count <= sq_size); + assert(sync.position < sq_size); + + if (!sync.count) + { + return SQSVR_FAILED; + } + if (sync.pop_lock) + { + return SQSVR_LOCKED; + } + + sync.pop_lock = 1; + pos = sync.position; + return SQSVR_OK; + })) + { + if (res == SQSVR_FAILED && squeue_test_exit(do_exit)) + { + return false; + } + + std::unique_lock rcv_lock(m_rcv_mutex); + m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1)); + } + + data = m_data[pos]; + + m_sync.atomic_op([](squeue_sync_var_t& sync) + { + assert(sync.count <= sq_size); + assert(sync.position < sq_size); + assert(sync.pop_lock); + sync.pop_lock = 0; + sync.position++; + sync.count--; + if (sync.position == sq_size) + { + sync.position = 0; + } + }); + + m_rcv.notify_one(); + m_wcv.notify_one(); + return true; + } + + bool try_pop(T& data) + { + static const volatile bool no_wait = true; + + return pop(data, &no_wait); + } + + bool peek(T& data, u32 start_pos = 0, const volatile bool* do_exit = nullptr) + { + assert(start_pos < sq_size); + u32 pos = 0; + + while (u32 res = m_sync.atomic_op_sync(SQSVR_OK, [&pos, start_pos](squeue_sync_var_t& sync) -> u32 + { + assert(sync.count <= sq_size); + assert(sync.position < sq_size); + + if (sync.count <= start_pos) + { + return SQSVR_FAILED; + } + if (sync.pop_lock) + { + return SQSVR_LOCKED; + } + + sync.pop_lock = 1; + pos = sync.position + start_pos; + return SQSVR_OK; + })) + { + if (res == SQSVR_FAILED && squeue_test_exit(do_exit)) + { + return false; + } + + std::unique_lock rcv_lock(m_rcv_mutex); + m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1)); + } + + data = m_data[pos >= sq_size ? pos - sq_size : pos]; + + m_sync.atomic_op([](squeue_sync_var_t& sync) + { + assert(sync.count <= sq_size); + assert(sync.position < sq_size); + assert(sync.pop_lock); + sync.pop_lock = 0; + }); + + m_rcv.notify_one(); + return true; + } + + bool try_peek(T& data, u32 start_pos = 0) + { + static const volatile bool no_wait = true; + + return peek(data, start_pos, &no_wait); + } + + class squeue_data_t + { + T* const m_data; + const u32 m_pos; + const u32 m_count; + + squeue_data_t(T* data, u32 pos, u32 count) + : m_data(data) + , m_pos(pos) + , m_count(count) + { + } + + public: + T& operator [] (u32 index) + { + assert(index < m_count); + index += m_pos; + index = index < sq_size ? index : index - sq_size; + return m_data[index]; + } + }; + + void process(void(*proc)(squeue_data_t data)) + { + u32 pos, count; + + while (m_sync.atomic_op_sync(SQSVR_OK, [&pos, &count](squeue_sync_var_t& sync) -> u32 + { + assert(sync.count <= sq_size); + assert(sync.position < sq_size); + + if (sync.pop_lock || sync.push_lock) + { + return SQSVR_LOCKED; + } + + pos = sync.position; + count = sync.count; + sync.pop_lock = 1; + sync.push_lock = 1; + return SQSVR_OK; + })) + { + std::unique_lock rcv_lock(m_rcv_mutex); + m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1)); + } + + proc(squeue_data_t(m_data, pos, count)); + + m_sync.atomic_op([](squeue_sync_var_t& sync) + { + assert(sync.count <= sq_size); + assert(sync.position < sq_size); + assert(sync.pop_lock && sync.push_lock); + sync.pop_lock = 0; + sync.push_lock = 0; + }); + + m_wcv.notify_one(); + m_rcv.notify_one(); + } + + void clear() + { + while (m_sync.atomic_op_sync(SQSVR_OK, [](squeue_sync_var_t& sync) -> u32 + { + assert(sync.count <= sq_size); + assert(sync.position < sq_size); + + if (sync.pop_lock || sync.push_lock) + { + return SQSVR_LOCKED; + } + + sync.pop_lock = 1; + sync.push_lock = 1; + return SQSVR_OK; + })) + { + std::unique_lock rcv_lock(m_rcv_mutex); + m_rcv.wait_for(rcv_lock, std::chrono::milliseconds(1)); + } + + m_sync.exchange({}); + m_wcv.notify_one(); + m_rcv.notify_one(); + } +}; diff --git a/asmjit b/asmjit index 1318c9aff7..48da90ded7 160000 --- a/asmjit +++ b/asmjit @@ -1 +1 @@ -Subproject commit 1318c9aff7137b30aec7dee2ababb2b313ae0f06 +Subproject commit 48da90ded775fa2ba0fd3f15522890ad631ad6de diff --git a/ffmpeg b/ffmpeg index 352fdfbbfa..79a2d7a9f7 160000 --- a/ffmpeg +++ b/ffmpeg @@ -1 +1 @@ -Subproject commit 352fdfbbfa6d7b26142f00b43d7e1802a03c68a8 +Subproject commit 79a2d7a9f780ad27d1622010cb1cb8396c3701e9 diff --git a/rpcs3/Crypto/unpkg.cpp b/rpcs3/Crypto/unpkg.cpp index 39f4bf99a8..5d7846046f 100644 --- a/rpcs3/Crypto/unpkg.cpp +++ b/rpcs3/Crypto/unpkg.cpp @@ -43,13 +43,13 @@ bool CheckHeader(rFile& pkg_f, PKGHeader* m_header) } if (m_header->pkg_size != pkg_f.Length()) { - LOG_ERROR(LOADER, "PKG: File size mismatch."); - return false; + LOG_WARNING(LOADER, "PKG: File size mismatch."); + //return false; } if (m_header->data_size + m_header->data_offset + 0x60 != pkg_f.Length()) { - LOG_ERROR(LOADER, "PKG: Data size mismatch."); - return false; + LOG_WARNING(LOADER, "PKG: Data size mismatch."); + //return false; } return true; diff --git a/rpcs3/Emu/ARMv7/ARMv7Decoder.h b/rpcs3/Emu/ARMv7/ARMv7Decoder.h index 81b58e9939..2a7de502f6 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Decoder.h +++ b/rpcs3/Emu/ARMv7/ARMv7Decoder.h @@ -1,35 +1,48 @@ #pragma once -#include "Emu/CPU/CPUDecoder.h" -#include "ARMv7Opcodes.h" +#include "Emu/CPU/CPUDecoder.h" +#include "ARMv7Thread.h" +#include "ARMv7Interpreter.h" +#include "ARMv7Opcodes.h" +#include "Utilities/Log.h" class ARMv7Decoder : public CPUDecoder { - ARMv7Opcodes& m_op; - u8 m_last_instr_size; + ARMv7Thread& m_thr; public: - ARMv7Decoder(ARMv7Opcodes& op) : m_op(op) + ARMv7Decoder(ARMv7Thread& thr) : m_thr(thr) { } virtual u8 DecodeMemory(const u32 address) { - const u32 code0 = vm::psv::read16(address & ~1); - const u32 code1 = vm::psv::read16(address + 2 & ~1); - const u32 data = code0 << 16 | code1; - const u32 arg = address & 1 ? code1 << 16 | code0 : data; + m_thr.update_code(address & ~1); + // LOG_NOTICE(GENERAL, "code0 = 0x%04x, code1 = 0x%04x, data = 0x%08x", m_thr.code.code0, m_thr.code.code1, m_thr.code.data); + // LOG_NOTICE(GENERAL, "arg = 0x%08x", m_thr.m_arg); + // Emu.Pause(); + + // old decoding algorithm + /* for (auto& opcode : ARMv7_opcode_table) { - if ((opcode.type < A1) == ((address & 1) == 0) && (arg & opcode.mask) == opcode.code) + if ((opcode.type < A1) == ((address & 0x1) == 0) && (m_thr.m_arg & opcode.mask) == opcode.code) { - (m_op.*opcode.func)(opcode.length == 2 ? code0 : arg, opcode.type); + m_thr.code.data = opcode.length == 2 ? m_thr.code.code0 : m_thr.m_arg; + (*opcode.func)(&m_thr, opcode.type); + // LOG_NOTICE(GENERAL, "%s, %d \n\n", opcode.name, opcode.length); return opcode.length; } } - m_op.UNK(data); - return address & 1 ? 4 : 2; + ARMv7_instrs::UNK(&m_thr); + return address & 0x1 ? 4 : 2; + */ + + execute_main_group(&m_thr); + // LOG_NOTICE(GENERAL, "%s, %d \n\n", m_thr.m_last_instr_name, m_thr.m_last_instr_size); + m_thr.m_last_instr_name = "Unknown"; + return m_thr.m_last_instr_size; } -}; +}; \ No newline at end of file diff --git a/rpcs3/Emu/ARMv7/ARMv7DisAsm.h b/rpcs3/Emu/ARMv7/ARMv7DisAsm.h index 7eb712d24c..05375dc167 100644 --- a/rpcs3/Emu/ARMv7/ARMv7DisAsm.h +++ b/rpcs3/Emu/ARMv7/ARMv7DisAsm.h @@ -12,10 +12,9 @@ static const char* g_arm_cond_name[16] = class ARMv7DisAsm : public CPUDisAsm - , public ARMv7Opcodes { public: - ARMv7DisAsm(CPUDisAsmMode mode) : CPUDisAsm(mode) + ARMv7DisAsm() : CPUDisAsm(CPUDisAsm_InterpreterMode) { } diff --git a/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp b/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp index 87d33e05c6..aa963e583b 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7Interpreter.cpp @@ -6,46 +6,293 @@ #include "PSVFuncList.h" #include "ARMv7Interpreter.h" -void ARMv7Interpreter::UNK(const u32 data) +template +u8 ARMv7_instrs::BitCount(T x, u8 len) { - LOG_ERROR(HLE, "Unknown/illegal opcode! (0x%04x : 0x%04x)", data >> 16, data & 0xffff); + u8 result = 0; + + for (u8 mask = 1 << (len - 1); mask; mask >>= 1) + { + if (x & mask) result++; + } + + return result; +} + +template +s8 ARMv7_instrs::LowestSetBit(T x, u8 len) +{ + if (!x) return len; + + u8 result = 0; + + for (T mask = 1, i = 0; i +s8 ARMv7_instrs::HighestSetBit(T x, u8 len) +{ + if (!x) return -1; + + u8 result = len; + + for (T mask = T(1) << (len - 1); (x & mask) == 0; mask >>= 1) + { + result--; + } + + return result; +} + +template +s8 ARMv7_instrs::CountLeadingZeroBits(T x, u8 len) +{ + return len - 1 - HighestSetBit(x, len); +} + +SRType ARMv7_instrs::DecodeImmShift(u32 type, u32 imm5, u32* shift_n) +{ + SRType shift_t = SRType_None; + + switch (type) + { + case 0: shift_t = SRType_LSL; if (shift_n) *shift_n = imm5; break; + case 1: shift_t = SRType_LSR; if (shift_n) *shift_n = imm5 == 0 ? 32 : imm5; break; + case 2: shift_t = SRType_ASR; if (shift_n) *shift_n = imm5 == 0 ? 32 : imm5; break; + case 3: + if (imm5 == 0) + { + shift_t = SRType_RRX; if (shift_n) *shift_n = 1; + } + else + { + shift_t = SRType_ROR; if (shift_n) *shift_n = imm5; + } + break; + } + + return shift_t; +} + +SRType ARMv7_instrs::DecodeRegShift(u8 type) +{ + SRType shift_t = SRType_None; + + switch (type) + { + case 0: shift_t = SRType_LSL; break; + case 1: shift_t = SRType_LSR; break; + case 2: shift_t = SRType_ASR; break; + case 3: shift_t = SRType_ROR; break; + } + + return shift_t; +} + +u32 ARMv7_instrs::LSL_C(u32 x, s32 shift, bool& carry_out) +{ + assert(shift > 0); + carry_out = shift <= 32 ? x & (1 << (32 - shift)) : false; + return shift < 32 ? x << shift : 0; +} + +u32 ARMv7_instrs::LSL(u32 x, s32 shift) +{ + assert(shift >= 0); + return shift < 32 ? x << shift : 0; +} + +u32 ARMv7_instrs::LSR_C(u32 x, s32 shift, bool& carry_out) +{ + assert(shift > 0); + carry_out = shift <= 32 ? x & (1 << (shift - 1)) : false; + return shift < 32 ? x >> shift : 0; +} + +u32 ARMv7_instrs::LSR(u32 x, s32 shift) +{ + assert(shift >= 0); + return shift < 32 ? x >> shift : 0; +} + +s32 ARMv7_instrs::ASR_C(s32 x, s32 shift, bool& carry_out) +{ + assert(shift > 0); + carry_out = shift <= 32 ? x & (1 << (shift - 1)) : false; + return shift < 32 ? x >> shift : x >> 31; +} + +s32 ARMv7_instrs::ASR(s32 x, s32 shift) +{ + assert(shift >= 0); + return shift < 32 ? x >> shift : x >> 31; +} + +u32 ARMv7_instrs::ROR_C(u32 x, s32 shift, bool& carry_out) +{ + assert(shift); + carry_out = x & (1 << (shift - 1)); + return x >> shift | x << (32 - shift); +} + +u32 ARMv7_instrs::ROR(u32 x, s32 shift) +{ + return x >> shift | x << (32 - shift); +} + +u32 ARMv7_instrs::RRX_C(u32 x, bool carry_in, bool& carry_out) +{ + carry_out = x & 0x1; + return ((u32)carry_in << 31) | (x >> 1); +} + +u32 ARMv7_instrs::RRX(u32 x, bool carry_in) +{ + return ((u32)carry_in << 31) | (x >> 1); +} + +template T ARMv7_instrs::Shift_C(T value, SRType type, s32 amount, bool carry_in, bool& carry_out) +{ + assert(type != SRType_RRX || amount == 1); + + if (amount) + { + switch (type) + { + case SRType_LSL: return LSL_C(value, amount, carry_out); + case SRType_LSR: return LSR_C(value, amount, carry_out); + case SRType_ASR: return ASR_C(value, amount, carry_out); + case SRType_ROR: return ROR_C(value, amount, carry_out); + case SRType_RRX: return RRX_C(value, carry_in, carry_out); + default: throw __FUNCTION__; + } + } + + carry_out = carry_in; + return value; +} + +template T ARMv7_instrs::Shift(T value, SRType type, s32 amount, bool carry_in) +{ + bool carry_out; + return Shift_C(value, type, amount, carry_in, carry_out); +} + +template T ARMv7_instrs::AddWithCarry(T x, T y, bool carry_in, bool& carry_out, bool& overflow) +{ + const T sign_mask = (T)1 << (sizeof(T) - 1); + + T result = x + y; + carry_out = ((x & y) | ((x ^ y) & ~result)) & sign_mask; + overflow = (x ^ result) & (y ^ result) & sign_mask; + if (carry_in) + { + result += 1; + carry_out ^= (result == 0); + overflow ^= (result == sign_mask); + } + return result; +} + +u32 ARMv7_instrs::ThumbExpandImm_C(u32 imm12, bool carry_in, bool& carry_out) +{ + if ((imm12 & 0xc00) >> 10) + { + u32 unrotated_value = (imm12 & 0x7f) | 0x80; + + return ROR_C(unrotated_value, (imm12 & 0xf80) >> 7, carry_out); + } + else + { + carry_out = carry_in; + + u32 imm8 = imm12 & 0xff; + switch ((imm12 & 0x300) >> 8) + { + case 0: return imm8; + case 1: return imm8 << 16 | imm8; + case 2: return imm8 << 24 | imm8 << 8; + default: return imm8 << 24 | imm8 << 16 | imm8 << 8 | imm8; + } + } +} + +u32 ARMv7_instrs::ThumbExpandImm(ARMv7Thread* CPU, u32 imm12) +{ + bool carry = CPU->APSR.C; + return ThumbExpandImm_C(imm12, carry, carry); +} + +bool ARMv7_instrs::ConditionPassed(ARMv7Thread* CPU, u32 cond) +{ + bool result = false; + + switch (cond >> 1) + { + case 0: result = CPU->APSR.Z == 1; break; + case 1: result = CPU->APSR.C == 1; break; + case 2: result = CPU->APSR.N == 1; break; + case 3: result = CPU->APSR.V == 1; break; + case 4: result = CPU->APSR.C == 1 && CPU->APSR.Z == 0; break; + case 5: result = CPU->APSR.N == CPU->APSR.V; break; + case 6: result = CPU->APSR.N == CPU->APSR.V && CPU->APSR.Z == 0; break; + case 7: return true; + } + + if (cond & 0x1) + { + return !result; + } + + return result; +} + +// instructions +void ARMv7_instrs::UNK(ARMv7Thread* thr) +{ + LOG_ERROR(HLE, "Unknown/illegal opcode! (0x%04x : 0x%04x)", thr->code.data >> 16, thr->code.data & 0xffff); Emu.Pause(); } -void ARMv7Interpreter::NULL_OP(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::NULL_OP(ARMv7Thread* thr, const ARMv7_encoding type) { - LOG_ERROR(HLE, "Null opcode found"); + LOG_ERROR(HLE, "Null opcode found: data = 0x%x", thr->m_arg); Emu.Pause(); } -void ARMv7Interpreter::HACK(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::HACK(ARMv7Thread* thr, const ARMv7_encoding type) { - u32 cond = CPU.ITSTATE.advance(); + u32 cond = thr->ITSTATE.advance(); u32 code = 0; switch (type) { case T1: { - code = data & 0xffff; + code = thr->code.data & 0xffff; break; } case A1: { - cond = data >> 28; - code = (data & 0xfff00) >> 4 | (data & 0xf); + cond = thr->code.data >> 28; + code = (thr->code.data & 0xfff00) >> 4 | (thr->code.data & 0xf); break; } default: throw __FUNCTION__; } - if (ConditionPassed(cond)) + if (ConditionPassed(thr, cond)) { - execute_psv_func_by_index(CPU, code); + execute_psv_func_by_index(*thr, code); } } -void ARMv7Interpreter::ADC_IMM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::ADC_IMM(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -54,7 +301,7 @@ void ARMv7Interpreter::ADC_IMM(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::ADC_REG(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::ADC_REG(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -63,7 +310,7 @@ void ARMv7Interpreter::ADC_REG(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::ADC_RSR(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::ADC_RSR(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -73,10 +320,10 @@ void ARMv7Interpreter::ADC_RSR(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::ADD_IMM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::ADD_IMM(ARMv7Thread* thr, const ARMv7_encoding type) { - bool set_flags = !CPU.ITSTATE; - u32 cond = CPU.ITSTATE.advance(); + bool set_flags = !thr->ITSTATE; + u32 cond = thr->ITSTATE.advance(); u32 d = 0; u32 n = 0; u32 imm32 = 0; @@ -85,23 +332,23 @@ void ARMv7Interpreter::ADD_IMM(const u32 data, const ARMv7_encoding type) { case T1: { - d = (data & 0x7); - n = (data & 0x38) >> 3; - imm32 = (data & 0x1c0) >> 6; + d = (thr->code.data & 0x7); + n = (thr->code.data & 0x38) >> 3; + imm32 = (thr->code.data & 0x1c0) >> 6; break; } case T2: { - d = n = (data & 0x700) >> 8; - imm32 = (data & 0xff); + d = n = (thr->code.data & 0x700) >> 8; + imm32 = (thr->code.data & 0xff); break; } case T3: { - d = (data & 0xf00) >> 8; - n = (data & 0xf0000) >> 16; - set_flags = (data & 0x100000); - imm32 = ThumbExpandImm((data & 0x4000000) >> 15 | (data & 0x7000) >> 4 | (data & 0xff)); + d = (thr->code.data & 0xf00) >> 8; + n = (thr->code.data & 0xf0000) >> 16; + set_flags = (thr->code.data & 0x100000); + imm32 = ThumbExpandImm(thr, (thr->code.data & 0x4000000) >> 15 | (thr->code.data & 0x7000) >> 4 | (thr->code.data & 0xff)); if (d == 15 && set_flags) { @@ -115,10 +362,10 @@ void ARMv7Interpreter::ADD_IMM(const u32 data, const ARMv7_encoding type) } case T4: { - d = (data & 0xf00) >> 8; - n = (data & 0xf0000) >> 16; + d = (thr->code.data & 0xf00) >> 8; + n = (thr->code.data & 0xf0000) >> 16; set_flags = false; - imm32 = (data & 0x4000000) >> 15 | (data & 0x7000) >> 4 | (data & 0xff); + imm32 = (thr->code.data & 0x4000000) >> 15 | (thr->code.data & 0x7000) >> 4 | (thr->code.data & 0xff); if (n == 15) { @@ -134,29 +381,29 @@ void ARMv7Interpreter::ADD_IMM(const u32 data, const ARMv7_encoding type) default: throw __FUNCTION__; } - if (ConditionPassed(cond)) + if (ConditionPassed(thr, cond)) { if (set_flags) { bool carry, overflow; - const u32 res = AddWithCarry(CPU.read_gpr(n), imm32, false, carry, overflow); - CPU.write_gpr(d, res); - CPU.APSR.N = res >> 31; - CPU.APSR.Z = res == 0; - CPU.APSR.C = carry; - CPU.APSR.V = overflow; + const u32 res = AddWithCarry(thr->read_gpr(n), imm32, false, carry, overflow); + thr->write_gpr(d, res); + thr->APSR.N = res >> 31; + thr->APSR.Z = res == 0; + thr->APSR.C = carry; + thr->APSR.V = overflow; } else { - CPU.write_gpr(d, CPU.read_gpr(n) + imm32); + thr->write_gpr(d, thr->read_gpr(n) + imm32); } } } -void ARMv7Interpreter::ADD_REG(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::ADD_REG(ARMv7Thread* thr, const ARMv7_encoding type) { - bool set_flags = !CPU.ITSTATE; - u32 cond = CPU.ITSTATE.advance(); + bool set_flags = !thr->ITSTATE; + u32 cond = thr->ITSTATE.advance(); u32 d = 0; u32 n = 0; u32 m = 0; @@ -167,15 +414,15 @@ void ARMv7Interpreter::ADD_REG(const u32 data, const ARMv7_encoding type) { case T1: { - d = (data & 0x7); - n = (data & 0x38) >> 3; - m = (data & 0x1c0) >> 6; + d = (thr->code.data & 0x7); + n = (thr->code.data & 0x38) >> 3; + m = (thr->code.data & 0x1c0) >> 6; break; } case T2: { - n = d = (data & 0x80) >> 4 | (data & 0x7); - m = (data & 0x78) >> 3; + n = d = (thr->code.data & 0x80) >> 4 | (thr->code.data & 0x7); + m = (thr->code.data & 0x78) >> 3; set_flags = false; if (n == 13 || m == 13) @@ -186,11 +433,11 @@ void ARMv7Interpreter::ADD_REG(const u32 data, const ARMv7_encoding type) } case T3: { - d = (data & 0xf00) >> 8; - n = (data & 0xf0000) >> 16; - m = (data & 0xf); - set_flags = (data & 0x100000); - shift_t = DecodeImmShift((data & 0x30) >> 4, (data & 0x7000) >> 10 | (data & 0xc0) >> 6, &shift_n); + d = (thr->code.data & 0xf00) >> 8; + n = (thr->code.data & 0xf0000) >> 16; + m = (thr->code.data & 0xf); + set_flags = (thr->code.data & 0x100000); + shift_t = DecodeImmShift((thr->code.data & 0x30) >> 4, (thr->code.data & 0x7000) >> 10 | (thr->code.data & 0xc0) >> 6, &shift_n); if (d == 15 && set_flags) { @@ -206,27 +453,27 @@ void ARMv7Interpreter::ADD_REG(const u32 data, const ARMv7_encoding type) default: throw __FUNCTION__; } - if (ConditionPassed(cond)) + if (ConditionPassed(thr, cond)) { - const u32 shifted = Shift(CPU.read_gpr(m), shift_t, shift_n, true); + const u32 shifted = Shift(thr->read_gpr(m), shift_t, shift_n, true); if (set_flags) { bool carry, overflow; - const u32 res = AddWithCarry(CPU.read_gpr(n), shifted, false, carry, overflow); - CPU.write_gpr(d, res); - CPU.APSR.N = res >> 31; - CPU.APSR.Z = res == 0; - CPU.APSR.C = carry; - CPU.APSR.V = overflow; + const u32 res = AddWithCarry(thr->read_gpr(n), shifted, false, carry, overflow); + thr->write_gpr(d, res); + thr->APSR.N = res >> 31; + thr->APSR.Z = res == 0; + thr->APSR.C = carry; + thr->APSR.V = overflow; } else { - CPU.write_gpr(d, CPU.read_gpr(n) + shifted); + thr->write_gpr(d, thr->read_gpr(n) + shifted); } } } -void ARMv7Interpreter::ADD_RSR(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::ADD_RSR(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -235,9 +482,9 @@ void ARMv7Interpreter::ADD_RSR(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::ADD_SPI(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::ADD_SPI(ARMv7Thread* thr, const ARMv7_encoding type) { - u32 cond = CPU.ITSTATE.advance(); + u32 cond = thr->ITSTATE.advance(); u32 d = 13; bool set_flags = false; u32 imm32 = 0; @@ -246,20 +493,20 @@ void ARMv7Interpreter::ADD_SPI(const u32 data, const ARMv7_encoding type) { case T1: { - d = (data & 0x700) >> 8; - imm32 = (data & 0xff) << 2; + d = (thr->code.data & 0x700) >> 8; + imm32 = (thr->code.data & 0xff) << 2; break; } case T2: { - imm32 = (data & 0x7f) << 2; + imm32 = (thr->code.data & 0x7f) << 2; break; } case T3: { - d = (data & 0xf00) >> 8; - set_flags = (data & 0x100000); - imm32 = ThumbExpandImm((data & 0x4000000) >> 15 | (data & 0x7000) >> 4 | (data & 0xff)); + d = (thr->code.data & 0xf00) >> 8; + set_flags = (thr->code.data & 0x100000); + imm32 = ThumbExpandImm(thr, (thr->code.data & 0x4000000) >> 15 | (thr->code.data & 0x7000) >> 4 | (thr->code.data & 0xff)); if (d == 15 && set_flags) { @@ -269,37 +516,37 @@ void ARMv7Interpreter::ADD_SPI(const u32 data, const ARMv7_encoding type) } case T4: { - d = (data & 0xf00) >> 8; + d = (thr->code.data & 0xf00) >> 8; set_flags = false; - imm32 = (data & 0x4000000) >> 15 | (data & 0x7000) >> 4 | (data & 0xff); + imm32 = (thr->code.data & 0x4000000) >> 15 | (thr->code.data & 0x7000) >> 4 | (thr->code.data & 0xff); break; } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } - if (ConditionPassed(cond)) + if (ConditionPassed(thr, cond)) { if (set_flags) { bool carry, overflow; - const u32 res = AddWithCarry(CPU.SP, imm32, false, carry, overflow); - CPU.write_gpr(d, res); - CPU.APSR.N = res >> 31; - CPU.APSR.Z = res == 0; - CPU.APSR.C = carry; - CPU.APSR.V = overflow; + const u32 res = AddWithCarry(thr->SP, imm32, false, carry, overflow); + thr->write_gpr(d, res); + thr->APSR.N = res >> 31; + thr->APSR.Z = res == 0; + thr->APSR.C = carry; + thr->APSR.V = overflow; } else { - CPU.write_gpr(d, CPU.SP + imm32); + thr->write_gpr(d, thr->SP + imm32); } } } -void ARMv7Interpreter::ADD_SPR(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::ADD_SPR(ARMv7Thread* thr, const ARMv7_encoding type) { - u32 cond = CPU.ITSTATE.advance(); + u32 cond = thr->ITSTATE.advance(); u32 d = 13; u32 m = 0; bool set_flags = false; @@ -310,12 +557,12 @@ void ARMv7Interpreter::ADD_SPR(const u32 data, const ARMv7_encoding type) { case T1: { - m = d = (data & 0x80) >> 4 | (data & 0x7); + m = d = (thr->code.data & 0x80) >> 4 | (thr->code.data & 0x7); break; } case T2: { - m = (data & 0x78) >> 3; + m = (thr->code.data & 0x78) >> 3; if (m == 13) { @@ -325,38 +572,38 @@ void ARMv7Interpreter::ADD_SPR(const u32 data, const ARMv7_encoding type) } case T3: { - d = (data & 0xf00) >> 8; - m = (data & 0xf); - set_flags = (data & 0x100000); - shift_t = DecodeImmShift((data & 0x30) >> 4, (data & 0x7000) >> 10 | (data & 0xc0) >> 6, &shift_n); + d = (thr->code.data & 0xf00) >> 8; + m = (thr->code.data & 0xf); + set_flags = (thr->code.data & 0x100000); + shift_t = DecodeImmShift((thr->code.data & 0x30) >> 4, (thr->code.data & 0x7000) >> 10 | (thr->code.data & 0xc0) >> 6, &shift_n); break; } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } - if (ConditionPassed(cond)) + if (ConditionPassed(thr, cond)) { - const u32 shifted = Shift(CPU.read_gpr(m), shift_t, shift_n, CPU.APSR.C); + const u32 shifted = Shift(thr->read_gpr(m), shift_t, shift_n, thr->APSR.C); if (set_flags) { bool carry, overflow; - const u32 res = AddWithCarry(CPU.SP, shifted, false, carry, overflow); - CPU.write_gpr(d, res); - CPU.APSR.N = res >> 31; - CPU.APSR.Z = res == 0; - CPU.APSR.C = carry; - CPU.APSR.V = overflow; + const u32 res = AddWithCarry(thr->SP, shifted, false, carry, overflow); + thr->write_gpr(d, res); + thr->APSR.N = res >> 31; + thr->APSR.Z = res == 0; + thr->APSR.C = carry; + thr->APSR.V = overflow; } else { - CPU.write_gpr(d, CPU.SP + CPU.read_gpr(m)); + thr->write_gpr(d, thr->SP + thr->read_gpr(m)); } } } -void ARMv7Interpreter::ADR(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::ADR(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -366,7 +613,7 @@ void ARMv7Interpreter::ADR(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::AND_IMM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::AND_IMM(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -375,7 +622,7 @@ void ARMv7Interpreter::AND_IMM(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::AND_REG(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::AND_REG(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -384,7 +631,7 @@ void ARMv7Interpreter::AND_REG(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::AND_RSR(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::AND_RSR(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -394,7 +641,7 @@ void ARMv7Interpreter::AND_RSR(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::ASR_IMM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::ASR_IMM(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -403,7 +650,7 @@ void ARMv7Interpreter::ASR_IMM(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::ASR_REG(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::ASR_REG(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -413,67 +660,68 @@ void ARMv7Interpreter::ASR_REG(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::B(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::B(ARMv7Thread* thr, const ARMv7_encoding type) { - u32 cond = CPU.ITSTATE.advance(); + u32 cond = thr->ITSTATE.advance(); u32 jump = 0; // jump = instr_size + imm32 ??? switch (type) { case T1: { - cond = (data >> 8) & 0xf; + cond = (thr->code.data >> 8) & 0xf; if (cond == 0xf) { throw "SVC"; } - jump = 4 + sign<9, u32>((data & 0xff) << 1); + jump = 4 + sign<9, u32>((thr->code.data & 0xff) << 1); break; } case T2: { - jump = 4 + sign<12, u32>((data & 0x7ff) << 1); + jump = 4 + sign<12, u32>((thr->code.data & 0x7ff) << 1); break; } case T3: { - cond = (data >> 6) & 0xf; + cond = (thr->code.data >> 6) & 0xf; if (cond >= 0xe) { throw "B_T3: Related encodings"; } - u32 s = (data >> 26) & 0x1; - u32 j1 = (data >> 13) & 0x1; - u32 j2 = (data >> 11) & 0x1; - jump = 4 + sign<21, u32>(s << 20 | j2 << 19 | j1 << 18 | (data & 0x3f0000) >> 4 | (data & 0x7ff) << 1); + u32 s = (thr->code.data >> 26) & 0x1; + u32 j1 = (thr->code.data >> 13) & 0x1; + u32 j2 = (thr->code.data >> 11) & 0x1; + jump = 4 + sign<21, u32>(s << 20 | j2 << 19 | j1 << 18 | (thr->code.data & 0x3f0000) >> 4 | (thr->code.data & 0x7ff) << 1); break; } case T4: { - u32 s = (data >> 26) & 0x1; - u32 i1 = (data >> 13) & 0x1 ^ s ^ 1; - u32 i2 = (data >> 11) & 0x1 ^ s ^ 1; - jump = 4 + sign<25, u32>(s << 24 | i2 << 23 | i1 << 22 | (data & 0x3ff0000) >> 4 | (data & 0x7ff) << 1); + u32 s = (thr->code.data >> 26) & 0x1; + u32 i1 = (thr->code.data >> 13) & 0x1 ^ s ^ 1; + u32 i2 = (thr->code.data >> 11) & 0x1 ^ s ^ 1; + jump = 4 + sign<25, u32>(s << 24 | i2 << 23 | i1 << 22 | (thr->code.data & 0x3ff0000) >> 4 | (thr->code.data & 0x7ff) << 1); break; } case A1: { - cond = data >> 28; - jump = 1 + 4 + sign<26, u32>((data & 0xffffff) << 2); + cond = thr->code.data >> 28; + jump = 1 + 4 + sign<26, u32>((thr->code.data & 0xffffff) << 2); break; } + default: throw __FUNCTION__; } - if (ConditionPassed(cond)) + if (ConditionPassed(thr, cond)) { - CPU.SetBranch(CPU.PC + jump); + thr->SetBranch(thr->PC + jump); } } -void ARMv7Interpreter::BFC(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::BFC(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -482,7 +730,7 @@ void ARMv7Interpreter::BFC(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::BFI(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::BFI(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -492,7 +740,7 @@ void ARMv7Interpreter::BFI(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::BIC_IMM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::BIC_IMM(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -501,7 +749,7 @@ void ARMv7Interpreter::BIC_IMM(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::BIC_REG(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::BIC_REG(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -510,7 +758,7 @@ void ARMv7Interpreter::BIC_REG(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::BIC_RSR(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::BIC_RSR(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -520,7 +768,7 @@ void ARMv7Interpreter::BIC_RSR(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::BKPT(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::BKPT(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -530,132 +778,132 @@ void ARMv7Interpreter::BKPT(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::BL(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::BL(ARMv7Thread* thr, const ARMv7_encoding type) { - u32 cond = CPU.ITSTATE.advance(); - u32 newLR = CPU.PC; + u32 cond = thr->ITSTATE.advance(); + u32 newLR = thr->PC; u32 imm32 = 0; switch (type) { case T1: { - u32 s = (data >> 26) & 0x1; - u32 i1 = (data >> 13) & 0x1 ^ s ^ 1; - u32 i2 = (data >> 11) & 0x1 ^ s ^ 1; - imm32 = 4 + sign<25, u32>(s << 24 | i2 << 23 | i1 << 22 | (data & 0x3ff0000) >> 4 | (data & 0x7ff) << 1); - newLR = (CPU.PC + 4) | 1; + u32 s = (thr->code.data >> 26) & 0x1; + u32 i1 = (thr->code.data >> 13) & 0x1 ^ s ^ 1; + u32 i2 = (thr->code.data >> 11) & 0x1 ^ s ^ 1; + imm32 = 4 + sign<25, u32>(s << 24 | i2 << 23 | i1 << 22 | (thr->code.data & 0x3ff0000) >> 4 | (thr->code.data & 0x7ff) << 1); + newLR = (thr->PC + 4) | 1; break; } case A1: { - cond = data >> 28; - imm32 = 4 + sign<26, u32>((data & 0xffffff) << 2); - newLR = (CPU.PC + 4) - 4; + cond = thr->code.data >> 28; + imm32 = 4 + sign<26, u32>((thr->code.data & 0xffffff) << 2); + newLR = (thr->PC + 4) - 4; break; } default: throw __FUNCTION__; } - if (ConditionPassed(cond)) + if (ConditionPassed(thr, cond)) { - CPU.LR = newLR; - CPU.SetBranch(CPU.PC + imm32); + thr->LR = newLR; + thr->SetBranch(thr->PC + imm32); } } -void ARMv7Interpreter::BLX(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::BLX(ARMv7Thread* thr, const ARMv7_encoding type) { - u32 cond = CPU.ITSTATE.advance(); - u32 newLR = CPU.PC; + u32 cond = thr->ITSTATE.advance(); + u32 newLR = thr->PC; u32 target = 0; switch (type) { case T1: { - target = CPU.read_gpr((data >> 3) & 0xf); - newLR = (CPU.PC + 2) | 1; // ??? + target = thr->read_gpr((thr->code.data >> 3) & 0xf); + newLR = (thr->PC + 2) | 1; // ??? break; } case T2: { - u32 s = (data >> 26) & 0x1; - u32 i1 = (data >> 13) & 0x1 ^ s ^ 1; - u32 i2 = (data >> 11) & 0x1 ^ s ^ 1; - target = (CPU.PC + 4 & ~3) + sign<25, u32>(s << 24 | i2 << 23 | i1 << 22 | (data & 0x3ff0000) >> 4 | (data & 0x7ff) << 1); - newLR = (CPU.PC + 4) | 1; + u32 s = (thr->code.data >> 26) & 0x1; + u32 i1 = (thr->code.data >> 13) & 0x1 ^ s ^ 1; + u32 i2 = (thr->code.data >> 11) & 0x1 ^ s ^ 1; + target = (thr->PC + 4 & ~3) + sign<25, u32>(s << 24 | i2 << 23 | i1 << 22 | (thr->code.data & 0x3ff0000) >> 4 | (thr->code.data & 0x7ff) << 1); + newLR = (thr->PC + 4) | 1; break; } case A1: { - cond = data >> 28; - target = CPU.read_gpr(data & 0xf); - newLR = (CPU.PC + 4) - 4; + cond = thr->code.data >> 28; + target = thr->read_gpr(thr->code.data & 0xf); + newLR = (thr->PC + 4) - 4; break; } case A2: { - target = (CPU.PC + 4 | 1) + sign<25, u32>((data & 0xffffff) << 2 | (data & 0x1000000) >> 23); - newLR = (CPU.PC + 4) - 4; + target = (thr->PC + 4 | 1) + sign<25, u32>((thr->code.data & 0xffffff) << 2 | (thr->code.data & 0x1000000) >> 23); + newLR = (thr->PC + 4) - 4; break; } default: throw __FUNCTION__; } - if (ConditionPassed(cond)) + if (ConditionPassed(thr, cond)) { - CPU.LR = newLR; + thr->LR = newLR; if (target & 1) { - CPU.ISET = Thumb; - CPU.SetBranch(target & ~1); + thr->ISET = Thumb; + thr->SetBranch(target & ~1); } else { - CPU.ISET = ARM; - CPU.SetBranch(target); + thr->ISET = ARM; + thr->SetBranch(target); } } } -void ARMv7Interpreter::BX(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::BX(ARMv7Thread* thr, const ARMv7_encoding type) { - u32 cond = CPU.ITSTATE.advance(); + u32 cond = thr->ITSTATE.advance(); u32 target = 0; switch (type) { case T1: { - target = CPU.read_gpr((data >> 3) & 0xf); + target = thr->read_gpr((thr->code.data >> 3) & 0xf); break; } case A1: { - cond = data >> 28; - target = CPU.read_gpr(data & 0xf); + cond = thr->code.data >> 28; + target = thr->read_gpr(thr->code.data & 0xf); } default: throw __FUNCTION__; } - if (ConditionPassed(cond)) + if (ConditionPassed(thr, cond)) { if (target & 1) { - CPU.ISET = Thumb; - CPU.SetBranch(target & ~1); + thr->ISET = Thumb; + thr->SetBranch(target & ~1); } else { - CPU.ISET = ARM; - CPU.SetBranch(target); + thr->ISET = ARM; + thr->SetBranch(target); } } } -void ARMv7Interpreter::CB_Z(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::CB_Z(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -663,14 +911,14 @@ void ARMv7Interpreter::CB_Z(const u32 data, const ARMv7_encoding type) default: throw __FUNCTION__; } - if ((CPU.read_gpr(data & 0x7) == 0) ^ ((data & 0x800) != 0)) + if ((thr->read_gpr(thr->code.data & 0x7) == 0) ^ ((thr->code.data & 0x800) != 0)) { - CPU.SetBranch(CPU.PC + 2 + ((data & 0xf8) >> 2) + ((data & 0x200) >> 3)); + thr->SetBranch(thr->PC + 2 + ((thr->code.data & 0xf8) >> 2) + ((thr->code.data & 0x200) >> 3)); } } -void ARMv7Interpreter::CLZ(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::CLZ(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -680,7 +928,7 @@ void ARMv7Interpreter::CLZ(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::CMN_IMM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::CMN_IMM(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -689,7 +937,7 @@ void ARMv7Interpreter::CMN_IMM(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::CMN_REG(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::CMN_REG(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -698,7 +946,7 @@ void ARMv7Interpreter::CMN_REG(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::CMN_RSR(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::CMN_RSR(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -708,9 +956,9 @@ void ARMv7Interpreter::CMN_RSR(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::CMP_IMM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::CMP_IMM(ARMv7Thread* thr, const ARMv7_encoding type) { - u32 cond = CPU.ITSTATE.advance(); + u32 cond = thr->ITSTATE.advance(); u32 n = 0; u32 imm32 = 0; @@ -718,34 +966,34 @@ void ARMv7Interpreter::CMP_IMM(const u32 data, const ARMv7_encoding type) { case T1: { - n = (data & 0x700) >> 8; - imm32 = (data & 0xff); + n = (thr->code.data & 0x700) >> 8; + imm32 = (thr->code.data & 0xff); break; } case T2: { - n = (data & 0xf0000) >> 16; - imm32 = ThumbExpandImm((data & 0x4000000) >> 15 | (data & 0x7000) >> 4 | (data & 0xff)); + n = (thr->code.data & 0xf0000) >> 16; + imm32 = ThumbExpandImm(thr, (thr->code.data & 0x4000000) >> 15 | (thr->code.data & 0x7000) >> 4 | (thr->code.data & 0xff)); break; } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } - if (ConditionPassed(cond)) + if (ConditionPassed(thr, cond)) { bool carry, overflow; - const u32 res = AddWithCarry(CPU.read_gpr(n), ~imm32, true, carry, overflow); - CPU.APSR.N = res >> 31; - CPU.APSR.Z = res == 0; - CPU.APSR.C = carry; - CPU.APSR.V = overflow; + const u32 res = AddWithCarry(thr->read_gpr(n), ~imm32, true, carry, overflow); + thr->APSR.N = res >> 31; + thr->APSR.Z = res == 0; + thr->APSR.C = carry; + thr->APSR.V = overflow; } } -void ARMv7Interpreter::CMP_REG(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::CMP_REG(ARMv7Thread* thr, const ARMv7_encoding type) { - u32 cond = CPU.ITSTATE.advance(); + u32 cond = thr->ITSTATE.advance(); u32 n = 0; u32 m = 0; auto shift_t = SRType_LSL; @@ -755,40 +1003,40 @@ void ARMv7Interpreter::CMP_REG(const u32 data, const ARMv7_encoding type) { case T1: { - n = (data & 0x7); - m = (data & 0x38) >> 3; + n = (thr->code.data & 0x7); + m = (thr->code.data & 0x38) >> 3; break; } case T2: { - n = (data & 0x80) >> 4 | (data & 0x7); - m = (data & 0x78) >> 3; + n = (thr->code.data & 0x80) >> 4 | (thr->code.data & 0x7); + m = (thr->code.data & 0x78) >> 3; break; } case T3: { - n = (data & 0xf0000) >> 16; - m = (data & 0xf); - shift_t = DecodeImmShift((data & 0x30) >> 4, (data & 0x7000) >> 10 | (data & 0xc0) >> 6, &shift_n); + n = (thr->code.data & 0xf0000) >> 16; + m = (thr->code.data & 0xf); + shift_t = DecodeImmShift((thr->code.data & 0x30) >> 4, (thr->code.data & 0x7000) >> 10 | (thr->code.data & 0xc0) >> 6, &shift_n); break; } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } - if (ConditionPassed(cond)) + if (ConditionPassed(thr, cond)) { bool carry, overflow; - const u32 shifted = Shift(CPU.read_gpr(m), shift_t, shift_n, true); - const u32 res = AddWithCarry(CPU.read_gpr(n), ~shifted, true, carry, overflow); - CPU.APSR.N = res >> 31; - CPU.APSR.Z = res == 0; - CPU.APSR.C = carry; - CPU.APSR.V = overflow; + const u32 shifted = Shift(thr->read_gpr(m), shift_t, shift_n, true); + const u32 res = AddWithCarry(thr->read_gpr(n), ~shifted, true, carry, overflow); + thr->APSR.N = res >> 31; + thr->APSR.Z = res == 0; + thr->APSR.C = carry; + thr->APSR.V = overflow; } } -void ARMv7Interpreter::CMP_RSR(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::CMP_RSR(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -798,7 +1046,7 @@ void ARMv7Interpreter::CMP_RSR(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::EOR_IMM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::EOR_IMM(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -807,7 +1055,7 @@ void ARMv7Interpreter::EOR_IMM(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::EOR_REG(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::EOR_REG(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -816,7 +1064,7 @@ void ARMv7Interpreter::EOR_REG(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::EOR_RSR(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::EOR_RSR(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -826,18 +1074,18 @@ void ARMv7Interpreter::EOR_RSR(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::IT(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::IT(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { case T1: { - if ((data & 0xf) == 0) + if ((thr->code.data & 0xf) == 0) { throw "IT_T1: Related encodings"; } - CPU.ITSTATE.IT = data & 0xff; + thr->ITSTATE.IT = thr->code.data & 0xff; return; } default: throw __FUNCTION__; @@ -845,7 +1093,7 @@ void ARMv7Interpreter::IT(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::LDM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::LDM(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -854,7 +1102,7 @@ void ARMv7Interpreter::LDM(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::LDMDA(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::LDMDA(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -863,7 +1111,7 @@ void ARMv7Interpreter::LDMDA(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::LDMDB(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::LDMDB(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -872,7 +1120,7 @@ void ARMv7Interpreter::LDMDB(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::LDMIB(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::LDMIB(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -882,9 +1130,9 @@ void ARMv7Interpreter::LDMIB(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::LDR_IMM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::LDR_IMM(ARMv7Thread* thr, const ARMv7_encoding type) { - u32 cond = CPU.ITSTATE.advance(); + u32 cond = thr->ITSTATE.advance(); u32 t = 0; u32 n = 13; u32 imm32 = 0; @@ -896,22 +1144,22 @@ void ARMv7Interpreter::LDR_IMM(const u32 data, const ARMv7_encoding type) { case T1: { - t = (data & 0x7); - n = (data & 0x38) >> 3; - imm32 = (data & 0x7c0) >> 4; + t = (thr->code.data & 0x7); + n = (thr->code.data & 0x38) >> 3; + imm32 = (thr->code.data & 0x7c0) >> 4; break; } case T2: { - t = (data & 0x700) >> 8; - imm32 = (data & 0xff) << 2; + t = (thr->code.data & 0x700) >> 8; + imm32 = (thr->code.data & 0xff) << 2; break; } case T3: { - t = (data & 0xf000) >> 12; - n = (data & 0xf0000) >> 16; - imm32 = (data & 0xfff); + t = (thr->code.data & 0xf000) >> 12; + n = (thr->code.data & 0xf0000) >> 16; + imm32 = (thr->code.data & 0xfff); if (n == 15) { @@ -921,12 +1169,12 @@ void ARMv7Interpreter::LDR_IMM(const u32 data, const ARMv7_encoding type) } case T4: { - t = (data & 0xf000) >> 12; - n = (data & 0xf0000) >> 16; - imm32 = (data & 0xff); - index = (data & 0x400); - add = (data & 0x200); - wback = (data & 0x100); + t = (thr->code.data & 0xf000) >> 12; + n = (thr->code.data & 0xf0000) >> 16; + imm32 = (thr->code.data & 0xff); + index = (thr->code.data & 0x400); + add = (thr->code.data & 0x200); + wback = (thr->code.data & 0x100); if (n == 15) { @@ -949,21 +1197,21 @@ void ARMv7Interpreter::LDR_IMM(const u32 data, const ARMv7_encoding type) default: throw __FUNCTION__; } - if (ConditionPassed(cond)) + if (ConditionPassed(thr, cond)) { - const u32 offset_addr = add ? CPU.read_gpr(n) + imm32 : CPU.read_gpr(n) - imm32; - const u32 addr = index ? offset_addr : CPU.read_gpr(n); + const u32 offset_addr = add ? thr->read_gpr(n) + imm32 : thr->read_gpr(n) - imm32; + const u32 addr = index ? offset_addr : thr->read_gpr(n); if (wback) { - CPU.write_gpr(n, offset_addr); + thr->write_gpr(n, offset_addr); } - CPU.write_gpr(t, vm::psv::read32(addr)); + thr->write_gpr(t, vm::psv::read32(addr)); } } -void ARMv7Interpreter::LDR_LIT(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::LDR_LIT(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -972,7 +1220,7 @@ void ARMv7Interpreter::LDR_LIT(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::LDR_REG(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::LDR_REG(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -982,7 +1230,7 @@ void ARMv7Interpreter::LDR_REG(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::LDRB_IMM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::LDRB_IMM(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -991,7 +1239,7 @@ void ARMv7Interpreter::LDRB_IMM(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::LDRB_LIT(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::LDRB_LIT(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1000,7 +1248,7 @@ void ARMv7Interpreter::LDRB_LIT(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::LDRB_REG(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::LDRB_REG(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1010,7 +1258,7 @@ void ARMv7Interpreter::LDRB_REG(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::LDRD_IMM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::LDRD_IMM(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1019,7 +1267,7 @@ void ARMv7Interpreter::LDRD_IMM(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::LDRD_LIT(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::LDRD_LIT(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1028,7 +1276,7 @@ void ARMv7Interpreter::LDRD_LIT(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::LDRD_REG(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::LDRD_REG(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1038,7 +1286,7 @@ void ARMv7Interpreter::LDRD_REG(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::LDRH_IMM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::LDRH_IMM(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1047,7 +1295,7 @@ void ARMv7Interpreter::LDRH_IMM(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::LDRH_LIT(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::LDRH_LIT(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1056,7 +1304,7 @@ void ARMv7Interpreter::LDRH_LIT(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::LDRH_REG(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::LDRH_REG(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1066,7 +1314,7 @@ void ARMv7Interpreter::LDRH_REG(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::LDRSB_IMM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::LDRSB_IMM(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1075,7 +1323,7 @@ void ARMv7Interpreter::LDRSB_IMM(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::LDRSB_LIT(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::LDRSB_LIT(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1084,7 +1332,7 @@ void ARMv7Interpreter::LDRSB_LIT(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::LDRSB_REG(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::LDRSB_REG(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1094,7 +1342,7 @@ void ARMv7Interpreter::LDRSB_REG(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::LDRSH_IMM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::LDRSH_IMM(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1103,7 +1351,7 @@ void ARMv7Interpreter::LDRSH_IMM(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::LDRSH_LIT(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::LDRSH_LIT(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1112,7 +1360,7 @@ void ARMv7Interpreter::LDRSH_LIT(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::LDRSH_REG(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::LDRSH_REG(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1122,10 +1370,10 @@ void ARMv7Interpreter::LDRSH_REG(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::LSL_IMM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::LSL_IMM(ARMv7Thread* thr, const ARMv7_encoding type) { - bool set_flags = !CPU.ITSTATE; - u32 cond = CPU.ITSTATE.advance(); + bool set_flags = !thr->ITSTATE; + u32 cond = thr->ITSTATE.advance(); u32 d = 0; u32 m = 0; u32 shift_n = 0; @@ -1134,9 +1382,9 @@ void ARMv7Interpreter::LSL_IMM(const u32 data, const ARMv7_encoding type) { case T1: { - d = (data & 0x7); - m = (data & 0x38) >> 3; - shift_n = (data & 0x7c0) >> 6; + d = (thr->code.data & 0x7); + m = (thr->code.data & 0x38) >> 3; + shift_n = (thr->code.data & 0x7c0) >> 6; if (!shift_n) { @@ -1146,10 +1394,10 @@ void ARMv7Interpreter::LSL_IMM(const u32 data, const ARMv7_encoding type) } case T2: { - d = (data & 0xf00) >> 8; - m = (data & 0xf); - set_flags = (data & 0x100000); - shift_n = (data & 0x7000) >> 10 | (data & 0xc0) >> 6; + d = (thr->code.data & 0xf00) >> 8; + m = (thr->code.data & 0xf); + set_flags = (thr->code.data & 0x100000); + shift_n = (thr->code.data & 0x7000) >> 10 | (thr->code.data & 0xc0) >> 6; if (!shift_n) { @@ -1161,24 +1409,24 @@ void ARMv7Interpreter::LSL_IMM(const u32 data, const ARMv7_encoding type) default: throw __FUNCTION__; } - if (ConditionPassed(cond)) + if (ConditionPassed(thr, cond)) { bool carry; - const u32 res = Shift_C(CPU.read_gpr(m), SRType_LSL, shift_n, CPU.APSR.C, carry); - CPU.write_gpr(d, res); + const u32 res = Shift_C(thr->read_gpr(m), SRType_LSL, shift_n, thr->APSR.C, carry); + thr->write_gpr(d, res); if (set_flags) { - CPU.APSR.N = res >> 31; - CPU.APSR.Z = res == 0; - CPU.APSR.C = carry; + thr->APSR.N = res >> 31; + thr->APSR.Z = res == 0; + thr->APSR.C = carry; } } } -void ARMv7Interpreter::LSL_REG(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::LSL_REG(ARMv7Thread* thr, const ARMv7_encoding type) { - bool set_flags = !CPU.ITSTATE; - u32 cond = CPU.ITSTATE.advance(); + bool set_flags = !thr->ITSTATE; + u32 cond = thr->ITSTATE.advance(); u32 d = 0; u32 n = 0; u32 m = 0; @@ -1187,38 +1435,38 @@ void ARMv7Interpreter::LSL_REG(const u32 data, const ARMv7_encoding type) { case T1: { - d = n = (data & 0x7); - m = (data & 0x38) >> 3; + d = n = (thr->code.data & 0x7); + m = (thr->code.data & 0x38) >> 3; break; } case T2: { - d = (data & 0xf00) >> 8; - n = (data & 0xf0000) >> 16; - m = (data & 0xf); - set_flags = (data & 0x100000); + d = (thr->code.data & 0xf00) >> 8; + n = (thr->code.data & 0xf0000) >> 16; + m = (thr->code.data & 0xf); + set_flags = (thr->code.data & 0x100000); break; } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } - if (ConditionPassed(cond)) + if (ConditionPassed(thr, cond)) { bool carry; - const u32 res = Shift_C(CPU.read_gpr(n), SRType_LSL, (CPU.read_gpr(m) & 0xff), CPU.APSR.C, carry); - CPU.write_gpr(d, res); + const u32 res = Shift_C(thr->read_gpr(n), SRType_LSL, (thr->read_gpr(m) & 0xff), thr->APSR.C, carry); + thr->write_gpr(d, res); if (set_flags) { - CPU.APSR.N = res >> 31; - CPU.APSR.Z = res == 0; - CPU.APSR.C = carry; + thr->APSR.N = res >> 31; + thr->APSR.Z = res == 0; + thr->APSR.C = carry; } } } -void ARMv7Interpreter::LSR_IMM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::LSR_IMM(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1227,7 +1475,7 @@ void ARMv7Interpreter::LSR_IMM(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::LSR_REG(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::LSR_REG(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1237,7 +1485,7 @@ void ARMv7Interpreter::LSR_REG(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::MLA(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::MLA(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1246,7 +1494,7 @@ void ARMv7Interpreter::MLA(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::MLS(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::MLS(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1256,11 +1504,11 @@ void ARMv7Interpreter::MLS(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::MOV_IMM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::MOV_IMM(ARMv7Thread* thr, const ARMv7_encoding type) { - bool set_flags = !CPU.ITSTATE; - bool carry = CPU.APSR.C; - u32 cond = CPU.ITSTATE.advance(); + bool set_flags = !thr->ITSTATE; + bool carry = thr->APSR.C; + u32 cond = thr->ITSTATE.advance(); u32 d = 0; u32 imm32 = 0; @@ -1268,42 +1516,42 @@ void ARMv7Interpreter::MOV_IMM(const u32 data, const ARMv7_encoding type) { case T1: { - d = (data >> 8) & 0x7; - imm32 = sign<8, u32>(data & 0xff); + d = (thr->code.data >> 8) & 0x7; + imm32 = sign<8, u32>(thr->code.data & 0xff); break; } case T2: { - set_flags = data & 0x100000; - d = (data >> 8) & 0xf; - imm32 = ThumbExpandImm_C((data & 0x4000000) >> 15 | (data & 0x7000) >> 4 | (data & 0xff), carry, carry); + set_flags = thr->code.data & 0x100000; + d = (thr->code.data >> 8) & 0xf; + imm32 = ThumbExpandImm_C((thr->code.data & 0x4000000) >> 15 | (thr->code.data & 0x7000) >> 4 | (thr->code.data & 0xff), carry, carry); break; } case T3: { set_flags = false; - d = (data >> 8) & 0xf; - imm32 = (data & 0xf0000) >> 4 | (data & 0x4000000) >> 15 | (data & 0x7000) >> 4 | (data & 0xff); + d = (thr->code.data >> 8) & 0xf; + imm32 = (thr->code.data & 0xf0000) >> 4 | (thr->code.data & 0x4000000) >> 15 | (thr->code.data & 0x7000) >> 4 | (thr->code.data & 0xff); break; } default: throw __FUNCTION__; } - if (ConditionPassed(cond)) + if (ConditionPassed(thr, cond)) { - CPU.write_gpr(d, imm32); + thr->write_gpr(d, imm32); if (set_flags) { - CPU.APSR.N = imm32 >> 31; - CPU.APSR.Z = imm32 == 0; - CPU.APSR.C = carry; + thr->APSR.N = imm32 >> 31; + thr->APSR.Z = imm32 == 0; + thr->APSR.C = carry; } } } -void ARMv7Interpreter::MOV_REG(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::MOV_REG(ARMv7Thread* thr, const ARMv7_encoding type) { - u32 cond = CPU.ITSTATE.advance(); + u32 cond = thr->ITSTATE.advance(); u32 d = 0; u32 m = 0; bool set_flags = false; @@ -1312,44 +1560,44 @@ void ARMv7Interpreter::MOV_REG(const u32 data, const ARMv7_encoding type) { case T1: { - d = (data & 0x80) >> 4 | (data & 0x7); - m = (data & 0x78) >> 3; + d = (thr->code.data & 0x80) >> 4 | (thr->code.data & 0x7); + m = (thr->code.data & 0x78) >> 3; break; } case T2: { - d = (data & 0x7); - m = (data & 0x38) >> 3; + d = (thr->code.data & 0x7); + m = (thr->code.data & 0x38) >> 3; set_flags = true; break; } case T3: { - d = (data & 0xf00) >> 8; - m = (data & 0xf); - set_flags = (data & 0x100000); + d = (thr->code.data & 0xf00) >> 8; + m = (thr->code.data & 0xf); + set_flags = (thr->code.data & 0x100000); break; } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } - if (ConditionPassed(cond)) + if (ConditionPassed(thr, cond)) { - const u32 res = CPU.read_gpr(m); - CPU.write_gpr(d, res); + const u32 res = thr->read_gpr(m); + thr->write_gpr(d, res); if (set_flags) { - CPU.APSR.N = res >> 31; - CPU.APSR.Z = res == 0; - //CPU.APSR.C = ? + thr->APSR.N = res >> 31; + thr->APSR.Z = res == 0; + //thr->APSR.C = ? } } } -void ARMv7Interpreter::MOVT(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::MOVT(ARMv7Thread* thr, const ARMv7_encoding type) { - u32 cond = CPU.ITSTATE.advance(); + u32 cond = thr->ITSTATE.advance(); u32 d = 0; u32 imm16 = 0; @@ -1357,22 +1605,22 @@ void ARMv7Interpreter::MOVT(const u32 data, const ARMv7_encoding type) { case T1: { - d = (data & 0xf00) >> 8; - imm16 = (data & 0xf0000) >> 4 | (data & 0x4000000) >> 14 | (data & 0x7000) >> 4 | (data & 0xff); + d = (thr->code.data & 0xf00) >> 8; + imm16 = (thr->code.data & 0xf0000) >> 4 | (thr->code.data & 0x4000000) >> 14 | (thr->code.data & 0x7000) >> 4 | (thr->code.data & 0xff); break; } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } - if (ConditionPassed(cond)) + if (ConditionPassed(thr, cond)) { - CPU.write_gpr(d, (CPU.read_gpr(d) & 0xffff) | (imm16 << 16)); + thr->write_gpr(d, (thr->read_gpr(d) & 0xffff) | (imm16 << 16)); } } -void ARMv7Interpreter::MRS(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::MRS(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1381,7 +1629,7 @@ void ARMv7Interpreter::MRS(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::MSR_IMM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::MSR_IMM(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1390,7 +1638,7 @@ void ARMv7Interpreter::MSR_IMM(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::MSR_REG(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::MSR_REG(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1400,7 +1648,7 @@ void ARMv7Interpreter::MSR_REG(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::MUL(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::MUL(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1410,7 +1658,7 @@ void ARMv7Interpreter::MUL(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::MVN_IMM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::MVN_IMM(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1419,7 +1667,7 @@ void ARMv7Interpreter::MVN_IMM(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::MVN_REG(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::MVN_REG(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1428,7 +1676,7 @@ void ARMv7Interpreter::MVN_REG(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::MVN_RSR(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::MVN_RSR(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1438,9 +1686,9 @@ void ARMv7Interpreter::MVN_RSR(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::NOP(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::NOP(ARMv7Thread* thr, const ARMv7_encoding type) { - u32 cond = CPU.ITSTATE.advance(); + u32 cond = thr->ITSTATE.advance(); switch (type) { @@ -1454,19 +1702,19 @@ void ARMv7Interpreter::NOP(const u32 data, const ARMv7_encoding type) } case A1: { - cond = data >> 28; + cond = thr->code.data >> 28; break; } default: throw __FUNCTION__; } - if (ConditionPassed(cond)) + if (ConditionPassed(thr, cond)) { } } -void ARMv7Interpreter::ORN_IMM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::ORN_IMM(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1475,7 +1723,7 @@ void ARMv7Interpreter::ORN_IMM(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::ORN_REG(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::ORN_REG(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1485,7 +1733,7 @@ void ARMv7Interpreter::ORN_REG(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::ORR_IMM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::ORR_IMM(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1494,7 +1742,7 @@ void ARMv7Interpreter::ORR_IMM(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::ORR_REG(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::ORR_REG(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1503,7 +1751,7 @@ void ARMv7Interpreter::ORR_REG(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::ORR_RSR(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::ORR_RSR(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1513,7 +1761,7 @@ void ARMv7Interpreter::ORR_RSR(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::PKH(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::PKH(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1523,32 +1771,32 @@ void ARMv7Interpreter::PKH(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::POP(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::POP(ARMv7Thread* thr, const ARMv7_encoding type) { - u32 cond = CPU.ITSTATE.advance(); + u32 cond = thr->ITSTATE.advance(); u16 reg_list = 0; switch (type) { case T1: { - reg_list = ((data & 0x100) << 7) | (data & 0xff); + reg_list = ((thr->code.data & 0x100) << 7) | (thr->code.data & 0xff); break; } case T2: { - reg_list = data & 0xdfff; + reg_list = thr->code.data & 0xdfff; break; } case T3: { - reg_list = 1 << (data >> 12); + reg_list = 1 << (thr->code.data >> 12); break; } case A1: { - cond = data >> 28; - reg_list = data & 0xffff; + cond = thr->code.data >> 28; + reg_list = thr->code.data & 0xffff; if (BitCount(reg_list) < 2) { throw "LDM / LDMIA / LDMFD"; @@ -1557,52 +1805,52 @@ void ARMv7Interpreter::POP(const u32 data, const ARMv7_encoding type) } case A2: { - cond = data >> 28; - reg_list = 1 << ((data >> 12) & 0xf); + cond = thr->code.data >> 28; + reg_list = 1 << ((thr->code.data >> 12) & 0xf); break; } default: throw __FUNCTION__; } - if (ConditionPassed(cond)) + if (ConditionPassed(thr, cond)) { for (u16 mask = 1, i = 0; mask; mask <<= 1, i++) { if (reg_list & mask) { - CPU.write_gpr(i, vm::psv::read32(CPU.SP)); - CPU.SP += 4; + thr->write_gpr(i, vm::psv::read32(thr->SP)); + thr->SP += 4; } } } } -void ARMv7Interpreter::PUSH(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::PUSH(ARMv7Thread* thr, const ARMv7_encoding type) { - u32 cond = CPU.ITSTATE.advance(); + u32 cond = thr->ITSTATE.advance(); u16 reg_list = 0; switch (type) { case T1: { - reg_list = ((data & 0x100) << 6) | (data & 0xff); + reg_list = ((thr->code.data & 0x100) << 6) | (thr->code.data & 0xff); break; } case T2: { - reg_list = data & 0x5fff; + reg_list = thr->code.data & 0x5fff; break; } case T3: { - reg_list = 1 << (data >> 12); + reg_list = 1 << (thr->code.data >> 12); break; } case A1: { - cond = data >> 28; - reg_list = data & 0xffff; + cond = thr->code.data >> 28; + reg_list = thr->code.data & 0xffff; if (BitCount(reg_list) < 2) { throw "STMDB / STMFD"; @@ -1611,28 +1859,28 @@ void ARMv7Interpreter::PUSH(const u32 data, const ARMv7_encoding type) } case A2: { - cond = data >> 28; - reg_list = 1 << ((data >> 12) & 0xf); + cond = thr->code.data >> 28; + reg_list = 1 << ((thr->code.data >> 12) & 0xf); break; } default: throw __FUNCTION__; } - if (ConditionPassed(cond)) + if (ConditionPassed(thr, cond)) { for (u16 mask = 1 << 15, i = 15; mask; mask >>= 1, i--) { if (reg_list & mask) { - CPU.SP -= 4; - vm::psv::write32(CPU.SP, CPU.read_gpr(i)); + thr->SP -= 4; + vm::psv::write32(thr->SP, thr->read_gpr(i)); } } } } -void ARMv7Interpreter::QADD(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::QADD(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1641,7 +1889,7 @@ void ARMv7Interpreter::QADD(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::QADD16(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::QADD16(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1650,7 +1898,7 @@ void ARMv7Interpreter::QADD16(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::QADD8(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::QADD8(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1659,7 +1907,7 @@ void ARMv7Interpreter::QADD8(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::QASX(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::QASX(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1668,7 +1916,7 @@ void ARMv7Interpreter::QASX(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::QDADD(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::QDADD(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1677,7 +1925,7 @@ void ARMv7Interpreter::QDADD(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::QDSUB(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::QDSUB(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1686,7 +1934,7 @@ void ARMv7Interpreter::QDSUB(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::QSAX(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::QSAX(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1695,7 +1943,7 @@ void ARMv7Interpreter::QSAX(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::QSUB(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::QSUB(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1704,7 +1952,7 @@ void ARMv7Interpreter::QSUB(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::QSUB16(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::QSUB16(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1713,7 +1961,7 @@ void ARMv7Interpreter::QSUB16(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::QSUB8(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::QSUB8(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1723,7 +1971,7 @@ void ARMv7Interpreter::QSUB8(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::RBIT(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::RBIT(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1732,7 +1980,7 @@ void ARMv7Interpreter::RBIT(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::REV(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::REV(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1741,7 +1989,7 @@ void ARMv7Interpreter::REV(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::REV16(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::REV16(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1750,7 +1998,7 @@ void ARMv7Interpreter::REV16(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::REVSH(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::REVSH(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1760,7 +2008,7 @@ void ARMv7Interpreter::REVSH(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::ROR_IMM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::ROR_IMM(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1769,7 +2017,7 @@ void ARMv7Interpreter::ROR_IMM(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::ROR_REG(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::ROR_REG(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1779,7 +2027,7 @@ void ARMv7Interpreter::ROR_REG(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::RRX(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::RRX(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1789,7 +2037,7 @@ void ARMv7Interpreter::RRX(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::RSB_IMM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::RSB_IMM(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1798,7 +2046,7 @@ void ARMv7Interpreter::RSB_IMM(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::RSB_REG(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::RSB_REG(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1807,7 +2055,7 @@ void ARMv7Interpreter::RSB_REG(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::RSB_RSR(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::RSB_RSR(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1817,7 +2065,7 @@ void ARMv7Interpreter::RSB_RSR(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::RSC_IMM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::RSC_IMM(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1826,7 +2074,7 @@ void ARMv7Interpreter::RSC_IMM(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::RSC_REG(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::RSC_REG(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1835,7 +2083,7 @@ void ARMv7Interpreter::RSC_REG(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::RSC_RSR(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::RSC_RSR(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1845,7 +2093,7 @@ void ARMv7Interpreter::RSC_RSR(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::SADD16(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SADD16(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1854,7 +2102,7 @@ void ARMv7Interpreter::SADD16(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SADD8(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SADD8(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1863,7 +2111,7 @@ void ARMv7Interpreter::SADD8(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SASX(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SASX(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1873,7 +2121,7 @@ void ARMv7Interpreter::SASX(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::SBC_IMM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SBC_IMM(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1882,7 +2130,7 @@ void ARMv7Interpreter::SBC_IMM(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SBC_REG(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SBC_REG(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1891,7 +2139,7 @@ void ARMv7Interpreter::SBC_REG(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SBC_RSR(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SBC_RSR(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1901,7 +2149,7 @@ void ARMv7Interpreter::SBC_RSR(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::SBFX(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SBFX(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1911,7 +2159,7 @@ void ARMv7Interpreter::SBFX(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::SDIV(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SDIV(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1921,7 +2169,7 @@ void ARMv7Interpreter::SDIV(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::SEL(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SEL(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1931,7 +2179,7 @@ void ARMv7Interpreter::SEL(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::SHADD16(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SHADD16(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1940,7 +2188,7 @@ void ARMv7Interpreter::SHADD16(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SHADD8(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SHADD8(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1949,7 +2197,7 @@ void ARMv7Interpreter::SHADD8(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SHASX(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SHASX(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1958,7 +2206,7 @@ void ARMv7Interpreter::SHASX(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SHSAX(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SHSAX(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1967,7 +2215,7 @@ void ARMv7Interpreter::SHSAX(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SHSUB16(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SHSUB16(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1976,7 +2224,7 @@ void ARMv7Interpreter::SHSUB16(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SHSUB8(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SHSUB8(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1986,7 +2234,7 @@ void ARMv7Interpreter::SHSUB8(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::SMLA__(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SMLA__(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -1995,7 +2243,7 @@ void ARMv7Interpreter::SMLA__(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SMLAD(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SMLAD(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2004,7 +2252,7 @@ void ARMv7Interpreter::SMLAD(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SMLAL(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SMLAL(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2013,7 +2261,7 @@ void ARMv7Interpreter::SMLAL(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SMLAL__(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SMLAL__(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2022,7 +2270,7 @@ void ARMv7Interpreter::SMLAL__(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SMLALD(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SMLALD(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2031,7 +2279,7 @@ void ARMv7Interpreter::SMLALD(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SMLAW_(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SMLAW_(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2040,7 +2288,7 @@ void ARMv7Interpreter::SMLAW_(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SMLSD(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SMLSD(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2049,7 +2297,7 @@ void ARMv7Interpreter::SMLSD(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SMLSLD(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SMLSLD(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2058,7 +2306,7 @@ void ARMv7Interpreter::SMLSLD(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SMMLA(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SMMLA(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2067,7 +2315,7 @@ void ARMv7Interpreter::SMMLA(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SMMLS(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SMMLS(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2076,7 +2324,7 @@ void ARMv7Interpreter::SMMLS(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SMMUL(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SMMUL(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2085,7 +2333,7 @@ void ARMv7Interpreter::SMMUL(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SMUAD(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SMUAD(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2094,7 +2342,7 @@ void ARMv7Interpreter::SMUAD(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SMUL__(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SMUL__(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2103,7 +2351,7 @@ void ARMv7Interpreter::SMUL__(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SMULL(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SMULL(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2112,7 +2360,7 @@ void ARMv7Interpreter::SMULL(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SMULW_(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SMULW_(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2121,7 +2369,7 @@ void ARMv7Interpreter::SMULW_(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SMUSD(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SMUSD(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2131,7 +2379,7 @@ void ARMv7Interpreter::SMUSD(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::SSAT(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SSAT(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2140,7 +2388,7 @@ void ARMv7Interpreter::SSAT(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SSAT16(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SSAT16(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2149,7 +2397,7 @@ void ARMv7Interpreter::SSAT16(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SSAX(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SSAX(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2158,7 +2406,7 @@ void ARMv7Interpreter::SSAX(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SSUB16(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SSUB16(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2167,7 +2415,7 @@ void ARMv7Interpreter::SSUB16(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SSUB8(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SSUB8(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2177,7 +2425,7 @@ void ARMv7Interpreter::SSUB8(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::STM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::STM(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2186,7 +2434,7 @@ void ARMv7Interpreter::STM(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::STMDA(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::STMDA(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2195,7 +2443,7 @@ void ARMv7Interpreter::STMDA(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::STMDB(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::STMDB(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2204,7 +2452,7 @@ void ARMv7Interpreter::STMDB(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::STMIB(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::STMIB(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2214,9 +2462,9 @@ void ARMv7Interpreter::STMIB(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::STR_IMM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::STR_IMM(ARMv7Thread* thr, const ARMv7_encoding type) { - u32 cond = CPU.ITSTATE.advance(); + u32 cond = thr->ITSTATE.advance(); u32 t = 16; u32 n = 13; u32 imm32 = 0; @@ -2228,22 +2476,22 @@ void ARMv7Interpreter::STR_IMM(const u32 data, const ARMv7_encoding type) { case T1: { - t = (data & 0x7); - n = (data & 0x38) >> 3; - imm32 = (data & 0x7c0) >> 4; + t = (thr->code.data & 0x7); + n = (thr->code.data & 0x38) >> 3; + imm32 = (thr->code.data & 0x7c0) >> 4; break; } case T2: { - t = (data & 0x700) >> 8; - imm32 = (data & 0xff) << 2; + t = (thr->code.data & 0x700) >> 8; + imm32 = (thr->code.data & 0xff) << 2; break; } case T3: { - t = (data & 0xf000) >> 12; - n = (data & 0xf0000) >> 16; - imm32 = (data & 0xfff); + t = (thr->code.data & 0xf000) >> 12; + n = (thr->code.data & 0xf0000) >> 16; + imm32 = (thr->code.data & 0xfff); if (n == 0xf) { @@ -2253,12 +2501,12 @@ void ARMv7Interpreter::STR_IMM(const u32 data, const ARMv7_encoding type) } case T4: { - t = (data & 0xf000) >> 12; - n = (data & 0xf0000) >> 16; - imm32 = (data & 0xff); - index = (data & 0x400); - add = (data & 0x200); - wback = (data & 0x100); + t = (thr->code.data & 0xf000) >> 12; + n = (thr->code.data & 0xf0000) >> 16; + imm32 = (thr->code.data & 0xff); + index = (thr->code.data & 0x400); + add = (thr->code.data & 0x200); + wback = (thr->code.data & 0x100); if (index && add && !wback) { @@ -2278,23 +2526,23 @@ void ARMv7Interpreter::STR_IMM(const u32 data, const ARMv7_encoding type) default: throw __FUNCTION__; } - if (ConditionPassed(cond)) + if (ConditionPassed(thr, cond)) { - const u32 offset_addr = add ? CPU.read_gpr(n) + imm32 : CPU.read_gpr(n) - imm32; - const u32 addr = index ? offset_addr : CPU.read_gpr(n); + const u32 offset_addr = add ? thr->read_gpr(n) + imm32 : thr->read_gpr(n) - imm32; + const u32 addr = index ? offset_addr : thr->read_gpr(n); - vm::psv::write32(addr, CPU.read_gpr(t)); + vm::psv::write32(addr, thr->read_gpr(t)); if (wback) { - CPU.write_gpr(n, offset_addr); + thr->write_gpr(n, offset_addr); } } } -void ARMv7Interpreter::STR_REG(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::STR_REG(ARMv7Thread* thr, const ARMv7_encoding type) { - u32 cond = CPU.ITSTATE.advance(); + u32 cond = thr->ITSTATE.advance(); u32 t = 0; u32 n = 0; u32 m = 0; @@ -2308,17 +2556,17 @@ void ARMv7Interpreter::STR_REG(const u32 data, const ARMv7_encoding type) { case T1: { - t = (data & 0x7); - n = (data & 0x38) >> 3; - m = (data & 0x1c0) >> 6; + t = (thr->code.data & 0x7); + n = (thr->code.data & 0x38) >> 3; + m = (thr->code.data & 0x1c0) >> 6; break; } case T2: { - t = (data & 0xf000) >> 12; - n = (data & 0xf0000) >> 16; - m = (data & 0xf); - shift_n = (data & 0x30) >> 4; + t = (thr->code.data & 0xf000) >> 12; + n = (thr->code.data & 0xf0000) >> 16; + m = (thr->code.data & 0xf); + shift_n = (thr->code.data & 0x30) >> 4; if (n == 15) { @@ -2330,23 +2578,23 @@ void ARMv7Interpreter::STR_REG(const u32 data, const ARMv7_encoding type) default: throw __FUNCTION__; } - if (ConditionPassed(cond)) + if (ConditionPassed(thr, cond)) { - const u32 offset = Shift(CPU.read_gpr(m), shift_t, shift_n, CPU.APSR.C); - const u32 offset_addr = add ? CPU.read_gpr(n) + offset : CPU.read_gpr(n) - offset; - const u32 addr = index ? offset_addr : CPU.read_gpr(n); + const u32 offset = Shift(thr->read_gpr(m), shift_t, shift_n, thr->APSR.C); + const u32 offset_addr = add ? thr->read_gpr(n) + offset : thr->read_gpr(n) - offset; + const u32 addr = index ? offset_addr : thr->read_gpr(n); - vm::psv::write32(addr, CPU.read_gpr(t)); + vm::psv::write32(addr, thr->read_gpr(t)); if (wback) { - CPU.write_gpr(n, offset_addr); + thr->write_gpr(n, offset_addr); } } } -void ARMv7Interpreter::STRB_IMM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::STRB_IMM(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2355,7 +2603,7 @@ void ARMv7Interpreter::STRB_IMM(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::STRB_REG(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::STRB_REG(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2365,7 +2613,7 @@ void ARMv7Interpreter::STRB_REG(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::STRD_IMM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::STRD_IMM(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2374,7 +2622,7 @@ void ARMv7Interpreter::STRD_IMM(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::STRD_REG(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::STRD_REG(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2384,7 +2632,7 @@ void ARMv7Interpreter::STRD_REG(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::STRH_IMM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::STRH_IMM(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2393,7 +2641,7 @@ void ARMv7Interpreter::STRH_IMM(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::STRH_REG(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::STRH_REG(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2403,10 +2651,10 @@ void ARMv7Interpreter::STRH_REG(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::SUB_IMM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SUB_IMM(ARMv7Thread* thr, const ARMv7_encoding type) { - bool set_flags = !CPU.ITSTATE; - u32 cond = CPU.ITSTATE.advance(); + bool set_flags = !thr->ITSTATE; + u32 cond = thr->ITSTATE.advance(); u32 d = 0; u32 n = 0; u32 imm32 = 0; @@ -2415,23 +2663,23 @@ void ARMv7Interpreter::SUB_IMM(const u32 data, const ARMv7_encoding type) { case T1: { - d = (data & 0x7); - n = (data & 0x38) >> 3; - imm32 = (data & 0x1c) >> 6; + d = (thr->code.data & 0x7); + n = (thr->code.data & 0x38) >> 3; + imm32 = (thr->code.data & 0x1c) >> 6; break; } case T2: { - d = n = (data & 0x700) >> 8; - imm32 = (data & 0xff); + d = n = (thr->code.data & 0x700) >> 8; + imm32 = (thr->code.data & 0xff); break; } case T3: { - d = (data & 0xf00) >> 8; - n = (data & 0xf0000) >> 16; - set_flags = (data & 0x100000); - imm32 = ThumbExpandImm((data & 0x4000000) >> 15 | (data & 0x7000) >> 4 | (data & 0xff)); + d = (thr->code.data & 0xf00) >> 8; + n = (thr->code.data & 0xf0000) >> 16; + set_flags = (thr->code.data & 0x100000); + imm32 = ThumbExpandImm(thr, (thr->code.data & 0x4000000) >> 15 | (thr->code.data & 0x7000) >> 4 | (thr->code.data & 0xff)); if (d == 15 && set_flags) { @@ -2445,10 +2693,10 @@ void ARMv7Interpreter::SUB_IMM(const u32 data, const ARMv7_encoding type) } case T4: { - d = (data & 0xf00) >> 8; - n = (data & 0xf0000) >> 16; + d = (thr->code.data & 0xf00) >> 8; + n = (thr->code.data & 0xf0000) >> 16; set_flags = false; - imm32 = (data & 0x4000000) >> 15 | (data & 0x7000) >> 4 | (data & 0xff); + imm32 = (thr->code.data & 0x4000000) >> 15 | (thr->code.data & 0x7000) >> 4 | (thr->code.data & 0xff); if (d == 15) { @@ -2464,29 +2712,29 @@ void ARMv7Interpreter::SUB_IMM(const u32 data, const ARMv7_encoding type) default: throw __FUNCTION__; } - if (ConditionPassed(cond)) + if (ConditionPassed(thr, cond)) { if (set_flags) { bool carry, overflow; - const u32 res = AddWithCarry(CPU.read_gpr(n), ~imm32, true, carry, overflow); - CPU.write_gpr(d, res); - CPU.APSR.N = res >> 31; - CPU.APSR.Z = res == 0; - CPU.APSR.C = carry; - CPU.APSR.V = overflow; + const u32 res = AddWithCarry(thr->read_gpr(n), ~imm32, true, carry, overflow); + thr->write_gpr(d, res); + thr->APSR.N = res >> 31; + thr->APSR.Z = res == 0; + thr->APSR.C = carry; + thr->APSR.V = overflow; } else { - CPU.write_gpr(d, CPU.read_gpr(n) - imm32); + thr->write_gpr(d, thr->read_gpr(n) - imm32); } } } -void ARMv7Interpreter::SUB_REG(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SUB_REG(ARMv7Thread* thr, const ARMv7_encoding type) { - bool set_flags = !CPU.ITSTATE; - u32 cond = CPU.ITSTATE.advance(); + bool set_flags = !thr->ITSTATE; + u32 cond = thr->ITSTATE.advance(); u32 d = 0; u32 n = 0; u32 m = 0; @@ -2497,18 +2745,18 @@ void ARMv7Interpreter::SUB_REG(const u32 data, const ARMv7_encoding type) { case T1: { - d = (data & 0x7); - n = (data & 0x38) >> 3; - m = (data & 0x1c0) >> 6; + d = (thr->code.data & 0x7); + n = (thr->code.data & 0x38) >> 3; + m = (thr->code.data & 0x1c0) >> 6; break; } case T2: { - d = (data & 0xf00) >> 8; - n = (data & 0xf0000) >> 16; - m = (data & 0xf); - set_flags = (data & 0x100000); - shift_t = DecodeImmShift((data & 0x30) >> 4, (data & 0x7000) >> 10 | (data & 0xc0) >> 6, &shift_n); + d = (thr->code.data & 0xf00) >> 8; + n = (thr->code.data & 0xf0000) >> 16; + m = (thr->code.data & 0xf); + set_flags = (thr->code.data & 0x100000); + shift_t = DecodeImmShift((thr->code.data & 0x30) >> 4, (thr->code.data & 0x7000) >> 10 | (thr->code.data & 0xc0) >> 6, &shift_n); if (d == 15 && set_flags) { @@ -2524,27 +2772,27 @@ void ARMv7Interpreter::SUB_REG(const u32 data, const ARMv7_encoding type) default: throw __FUNCTION__; } - if (ConditionPassed(cond)) + if (ConditionPassed(thr, cond)) { - const u32 shifted = Shift(CPU.read_gpr(m), shift_t, shift_n, CPU.APSR.C); + const u32 shifted = Shift(thr->read_gpr(m), shift_t, shift_n, thr->APSR.C); if (set_flags) { bool carry, overflow; - const u32 res = AddWithCarry(CPU.read_gpr(n), ~shifted, true, carry, overflow); - CPU.write_gpr(d, res); - CPU.APSR.N = res >> 31; - CPU.APSR.Z = res == 0; - CPU.APSR.C = carry; - CPU.APSR.V = overflow; + const u32 res = AddWithCarry(thr->read_gpr(n), ~shifted, true, carry, overflow); + thr->write_gpr(d, res); + thr->APSR.N = res >> 31; + thr->APSR.Z = res == 0; + thr->APSR.C = carry; + thr->APSR.V = overflow; } else { - CPU.write_gpr(d, CPU.read_gpr(n) - shifted); + thr->write_gpr(d, thr->read_gpr(n) - shifted); } } } -void ARMv7Interpreter::SUB_RSR(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SUB_RSR(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2553,9 +2801,9 @@ void ARMv7Interpreter::SUB_RSR(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SUB_SPI(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SUB_SPI(ARMv7Thread* thr, const ARMv7_encoding type) { - u32 cond = CPU.ITSTATE.advance(); + u32 cond = thr->ITSTATE.advance(); u32 d = 13; bool set_flags = false; u32 imm32 = 0; @@ -2564,14 +2812,14 @@ void ARMv7Interpreter::SUB_SPI(const u32 data, const ARMv7_encoding type) { case T1: { - imm32 = (data & 0x7f) << 2; + imm32 = (thr->code.data & 0x7f) << 2; break; } case T2: { - d = (data & 0xf00) >> 8; - set_flags = (data & 0x100000); - imm32 = ThumbExpandImm((data & 0x4000000) >> 15 | (data & 0x7000) >> 4 | (data & 0xff)); + d = (thr->code.data & 0xf00) >> 8; + set_flags = (thr->code.data & 0x100000); + imm32 = ThumbExpandImm(thr, (thr->code.data & 0x4000000) >> 15 | (thr->code.data & 0x7000) >> 4 | (thr->code.data & 0xff)); if (d == 15 && set_flags) { @@ -2581,35 +2829,35 @@ void ARMv7Interpreter::SUB_SPI(const u32 data, const ARMv7_encoding type) } case T3: { - d = (data & 0xf00) >> 8; + d = (thr->code.data & 0xf00) >> 8; set_flags = false; - imm32 = (data & 0x4000000) >> 15 | (data & 0x7000) >> 4 | (data & 0xff); + imm32 = (thr->code.data & 0x4000000) >> 15 | (thr->code.data & 0x7000) >> 4 | (thr->code.data & 0xff); break; } case A1: throw __FUNCTION__; default: throw __FUNCTION__; } - if (ConditionPassed(cond)) + if (ConditionPassed(thr, cond)) { if (set_flags) { bool carry, overflow; - const u32 res = AddWithCarry(CPU.SP, ~imm32, true, carry, overflow); - CPU.write_gpr(d, res); - CPU.APSR.N = res >> 31; - CPU.APSR.Z = res == 0; - CPU.APSR.C = carry; - CPU.APSR.V = overflow; + const u32 res = AddWithCarry(thr->SP, ~imm32, true, carry, overflow); + thr->write_gpr(d, res); + thr->APSR.N = res >> 31; + thr->APSR.Z = res == 0; + thr->APSR.C = carry; + thr->APSR.V = overflow; } else { - CPU.write_gpr(d, CPU.SP - imm32); + thr->write_gpr(d, thr->SP - imm32); } } } -void ARMv7Interpreter::SUB_SPR(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SUB_SPR(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2619,7 +2867,7 @@ void ARMv7Interpreter::SUB_SPR(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::SVC(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SVC(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2629,7 +2877,7 @@ void ARMv7Interpreter::SVC(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::SXTAB(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SXTAB(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2638,7 +2886,7 @@ void ARMv7Interpreter::SXTAB(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SXTAB16(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SXTAB16(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2647,7 +2895,7 @@ void ARMv7Interpreter::SXTAB16(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SXTAH(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SXTAH(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2656,7 +2904,7 @@ void ARMv7Interpreter::SXTAH(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SXTB(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SXTB(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2665,7 +2913,7 @@ void ARMv7Interpreter::SXTB(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SXTB16(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SXTB16(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2674,7 +2922,7 @@ void ARMv7Interpreter::SXTB16(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::SXTH(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::SXTH(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2684,7 +2932,7 @@ void ARMv7Interpreter::SXTH(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::TB_(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::TB_(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2694,7 +2942,7 @@ void ARMv7Interpreter::TB_(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::TEQ_IMM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::TEQ_IMM(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2703,7 +2951,7 @@ void ARMv7Interpreter::TEQ_IMM(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::TEQ_REG(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::TEQ_REG(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2712,7 +2960,7 @@ void ARMv7Interpreter::TEQ_REG(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::TEQ_RSR(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::TEQ_RSR(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2722,7 +2970,7 @@ void ARMv7Interpreter::TEQ_RSR(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::TST_IMM(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::TST_IMM(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2731,7 +2979,7 @@ void ARMv7Interpreter::TST_IMM(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::TST_REG(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::TST_REG(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2740,7 +2988,7 @@ void ARMv7Interpreter::TST_REG(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::TST_RSR(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::TST_RSR(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2750,7 +2998,7 @@ void ARMv7Interpreter::TST_RSR(const u32 data, const ARMv7_encoding type) } -void ARMv7Interpreter::UADD16(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::UADD16(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2759,7 +3007,7 @@ void ARMv7Interpreter::UADD16(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::UADD8(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::UADD8(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2768,7 +3016,7 @@ void ARMv7Interpreter::UADD8(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::UASX(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::UASX(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2777,7 +3025,7 @@ void ARMv7Interpreter::UASX(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::UBFX(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::UBFX(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2786,7 +3034,7 @@ void ARMv7Interpreter::UBFX(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::UDIV(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::UDIV(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2795,7 +3043,7 @@ void ARMv7Interpreter::UDIV(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::UHADD16(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::UHADD16(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2804,7 +3052,7 @@ void ARMv7Interpreter::UHADD16(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::UHADD8(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::UHADD8(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2813,7 +3061,7 @@ void ARMv7Interpreter::UHADD8(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::UHASX(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::UHASX(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2822,7 +3070,7 @@ void ARMv7Interpreter::UHASX(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::UHSAX(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::UHSAX(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2831,7 +3079,7 @@ void ARMv7Interpreter::UHSAX(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::UHSUB16(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::UHSUB16(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2840,7 +3088,7 @@ void ARMv7Interpreter::UHSUB16(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::UHSUB8(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::UHSUB8(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2849,7 +3097,7 @@ void ARMv7Interpreter::UHSUB8(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::UMAAL(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::UMAAL(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2858,7 +3106,7 @@ void ARMv7Interpreter::UMAAL(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::UMLAL(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::UMLAL(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2867,7 +3115,7 @@ void ARMv7Interpreter::UMLAL(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::UMULL(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::UMULL(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2876,7 +3124,7 @@ void ARMv7Interpreter::UMULL(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::UQADD16(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::UQADD16(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2885,7 +3133,7 @@ void ARMv7Interpreter::UQADD16(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::UQADD8(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::UQADD8(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2894,7 +3142,7 @@ void ARMv7Interpreter::UQADD8(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::UQASX(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::UQASX(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2903,7 +3151,7 @@ void ARMv7Interpreter::UQASX(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::UQSAX(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::UQSAX(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2912,7 +3160,7 @@ void ARMv7Interpreter::UQSAX(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::UQSUB16(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::UQSUB16(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2921,7 +3169,7 @@ void ARMv7Interpreter::UQSUB16(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::UQSUB8(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::UQSUB8(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2930,7 +3178,7 @@ void ARMv7Interpreter::UQSUB8(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::USAD8(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::USAD8(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2939,7 +3187,7 @@ void ARMv7Interpreter::USAD8(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::USADA8(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::USADA8(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2948,7 +3196,7 @@ void ARMv7Interpreter::USADA8(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::USAT(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::USAT(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2957,7 +3205,7 @@ void ARMv7Interpreter::USAT(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::USAT16(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::USAT16(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2966,7 +3214,7 @@ void ARMv7Interpreter::USAT16(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::USAX(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::USAX(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2975,7 +3223,7 @@ void ARMv7Interpreter::USAX(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::USUB16(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::USUB16(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2984,7 +3232,7 @@ void ARMv7Interpreter::USUB16(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::USUB8(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::USUB8(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -2993,7 +3241,7 @@ void ARMv7Interpreter::USUB8(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::UXTAB(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::UXTAB(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -3002,7 +3250,7 @@ void ARMv7Interpreter::UXTAB(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::UXTAB16(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::UXTAB16(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -3011,7 +3259,7 @@ void ARMv7Interpreter::UXTAB16(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::UXTAH(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::UXTAH(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -3020,7 +3268,7 @@ void ARMv7Interpreter::UXTAH(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::UXTB(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::UXTB(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -3029,7 +3277,7 @@ void ARMv7Interpreter::UXTB(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::UXTB16(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::UXTB16(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { @@ -3038,11 +3286,11 @@ void ARMv7Interpreter::UXTB16(const u32 data, const ARMv7_encoding type) } } -void ARMv7Interpreter::UXTH(const u32 data, const ARMv7_encoding type) +void ARMv7_instrs::UXTH(ARMv7Thread* thr, const ARMv7_encoding type) { switch (type) { case A1: throw __FUNCTION__; default: throw __FUNCTION__; } -} +} \ No newline at end of file diff --git a/rpcs3/Emu/ARMv7/ARMv7Interpreter.h b/rpcs3/Emu/ARMv7/ARMv7Interpreter.h index bb8d71b1fc..0cd02aecf7 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Interpreter.h +++ b/rpcs3/Emu/ARMv7/ARMv7Interpreter.h @@ -1,565 +1,759 @@ #pragma once -#include "Emu/ARMv7/ARMv7Opcodes.h" -class ARMv7Interpreter : public ARMv7Opcodes +#include "Emu/ARMv7/ARMv7Thread.h" +#include "Emu/System.h" +#include "Utilities/Log.h" + +enum ARMv7_encoding { - ARMv7Thread& CPU; + T1, T2, T3, T4, A1, A2 +}; -public: - ARMv7Interpreter(ARMv7Thread& cpu) : CPU(cpu) - { - } - - enum SRType : u32 - { - SRType_None, - SRType_LSL, - SRType_LSR, - SRType_ASR, - SRType_ROR, - SRType_RRX, - }; +enum SRType : u32 +{ + SRType_None, + SRType_LSL, + SRType_LSR, + SRType_ASR, + SRType_ROR, + SRType_RRX +}; +namespace ARMv7_instrs +{ template - bool IsZero(T x) + static bool IsZero(T x) { return x == T(0); } template - bool IsOnes(T x) + static bool IsOnes(T x) { return x == ~T(0); } template - u8 IsZeroBit(T x) + static u8 IsZeroBit(T x) { return IsZero(x) ? 1 : 0; } template - bool IsOnesBit(T x, u8 len = sizeof(T) * 8) + static bool IsOnesBit(T x, u8 len = sizeof(T) * 8) { return IsOnes(x) ? 1 : 0; } template - u8 BitCount(T x, u8 len = sizeof(T) * 8) - { - u8 result = 0; - - for(u8 mask=1 << (len - 1); mask; mask >>= 1) - { - if(x & mask) result++; - } - - return result; - } + u8 BitCount(T x, u8 len = sizeof(T) * 8); template - s8 LowestSetBit(T x, u8 len = sizeof(T) * 8) - { - if(!x) return len; - - u8 result = 0; - - for(T mask=1, i=0; i - s8 HighestSetBit(T x, u8 len = sizeof(T) * 8) - { - if(!x) return -1; - - u8 result = len; - - for(T mask=T(1) << (len - 1); (x & mask) == 0; mask >>= 1) - { - result--; - } - - return result; - } + s8 HighestSetBit(T x, u8 len = sizeof(T) * 8); template - s8 CountLeadingZeroBits(T x, u8 len = sizeof(T) * 8) - { - return len - 1 - HighestSetBit(x, len); - } - - SRType DecodeImmShift(u32 type, u32 imm5, u32* shift_n) - { - SRType shift_t = SRType_None; - - switch(type) - { - case 0: shift_t = SRType_LSL; if(shift_n) *shift_n = imm5; break; - case 1: shift_t = SRType_LSR; if(shift_n) *shift_n = imm5 == 0 ? 32 : imm5; break; - case 2: shift_t = SRType_ASR; if(shift_n) *shift_n = imm5 == 0 ? 32 : imm5; break; - case 3: - if(imm5 == 0) - { - shift_t = SRType_RRX; if(shift_n) *shift_n = 1; - } - else - { - shift_t = SRType_ROR; if(shift_n) *shift_n = imm5; - } - break; - } - - return shift_t; - } - - SRType DecodeRegShift(u8 type) - { - SRType shift_t = SRType_None; - - switch(type) - { - case 0: shift_t = SRType_LSL; break; - case 1: shift_t = SRType_LSR; break; - case 2: shift_t = SRType_ASR; break; - case 3: shift_t = SRType_ROR; break; - } - - return shift_t; - } - - u32 LSL_C(u32 x, s32 shift, bool& carry_out) - { - assert(shift > 0); - carry_out = shift <= 32 ? x & (1 << (32 - shift)) : false; - return shift < 32 ? x << shift : 0; - } - - u32 LSL(u32 x, s32 shift) - { - assert(shift >= 0); - return shift < 32 ? x << shift : 0; - } - - u32 LSR_C(u32 x, s32 shift, bool& carry_out) - { - assert(shift > 0); - carry_out = shift <= 32 ? x & (1 << (shift - 1)) : false; - return shift < 32 ? x >> shift : 0; - } - - u32 LSR(u32 x, s32 shift) - { - assert(shift >= 0); - return shift < 32 ? x >> shift : 0; - } - - s32 ASR_C(s32 x, s32 shift, bool& carry_out) - { - assert(shift > 0); - carry_out = shift <= 32 ? x & (1 << (shift - 1)) : false; - return shift < 32 ? x >> shift : x >> 31; - } - - s32 ASR(s32 x, s32 shift) - { - assert(shift >= 0); - return shift < 32 ? x >> shift : x >> 31; - } - - u32 ROR_C(u32 x, s32 shift, bool& carry_out) - { - assert(shift); - carry_out = x & (1 << (shift - 1)); - return x >> shift | x << (32 - shift); - } - - u32 ROR(u32 x, s32 shift) - { - return x >> shift | x << (32 - shift); - } - - u32 RRX_C(u32 x, bool carry_in, bool& carry_out) - { - carry_out = x & 0x1; - return ((u32)carry_in << 31) | (x >> 1); - } - - u32 RRX(u32 x, bool carry_in) - { - return ((u32)carry_in << 31) | (x >> 1); - } - - template T Shift_C(T value, SRType type, s32 amount, bool carry_in, bool& carry_out) - { - assert(type != SRType_RRX || amount == 1); - - if(amount) - { - switch(type) - { - case SRType_LSL: return LSL_C(value, amount, carry_out); - case SRType_LSR: return LSR_C(value, amount, carry_out); - case SRType_ASR: return ASR_C(value, amount, carry_out); - case SRType_ROR: return ROR_C(value, amount, carry_out); - case SRType_RRX: return RRX_C(value, carry_in, carry_out); - } - } - - carry_out = carry_in; - return value; - } - - template T Shift(T value, SRType type, s32 amount, bool carry_in) - { - bool carry_out; - return Shift_C(value, type, amount, carry_in, carry_out); - } - - template T AddWithCarry(T x, T y, bool carry_in, bool& carry_out, bool& overflow) - { - const T sign_mask = (T)1 << (sizeof(T) - 1); - - T result = x + y; - carry_out = ((x & y) | ((x ^ y) & ~result)) & sign_mask; - overflow = (x ^ result) & (y ^ result) & sign_mask; - if (carry_in) - { - result += 1; - carry_out ^= (result == 0); - overflow ^= (result == sign_mask); - } - return result; - } - - u32 ThumbExpandImm_C(u32 imm12, bool carry_in, bool& carry_out) - { - if ((imm12 & 0xc00) >> 10) - { - u32 unrotated_value = (imm12 & 0x7f) | 0x80; - - return ROR_C(unrotated_value, (imm12 & 0xf80) >> 7, carry_out); - } - else - { - carry_out = carry_in; - - u32 imm8 = imm12 & 0xff; - switch ((imm12 & 0x300) >> 8) - { - case 0: return imm8; - case 1: return imm8 << 16 | imm8; - case 2: return imm8 << 24 | imm8 << 8; - default: return imm8 << 24 | imm8 << 16 | imm8 << 8 | imm8; - } - } - } - - u32 ThumbExpandImm(u32 imm12) - { - bool carry = CPU.APSR.C; - return ThumbExpandImm_C(imm12, carry, carry); - } - - bool ConditionPassed(u32 cond) const - { - bool result = false; - - switch(cond >> 1) - { - case 0: result = CPU.APSR.Z == 1; break; - case 1: result = CPU.APSR.C == 1; break; - case 2: result = CPU.APSR.N == 1; break; - case 3: result = CPU.APSR.V == 1; break; - case 4: result = CPU.APSR.C == 1 && CPU.APSR.Z == 0; break; - case 5: result = CPU.APSR.N == CPU.APSR.V; break; - case 6: result = CPU.APSR.N == CPU.APSR.V && CPU.APSR.Z == 0; break; - case 7: return true; - } - - if(cond & 0x1) - { - return !result; - } - - return result; - } - -protected: - virtual void UNK(const u32 data); - - virtual void NULL_OP(const u32 data, const ARMv7_encoding type); - - virtual void HACK(const u32 data, const ARMv7_encoding type); - - virtual void ADC_IMM(const u32 data, const ARMv7_encoding type); - virtual void ADC_REG(const u32 data, const ARMv7_encoding type); - virtual void ADC_RSR(const u32 data, const ARMv7_encoding type); - - virtual void ADD_IMM(const u32 data, const ARMv7_encoding type); - virtual void ADD_REG(const u32 data, const ARMv7_encoding type); - virtual void ADD_RSR(const u32 data, const ARMv7_encoding type); - virtual void ADD_SPI(const u32 data, const ARMv7_encoding type); - virtual void ADD_SPR(const u32 data, const ARMv7_encoding type); - - virtual void ADR(const u32 data, const ARMv7_encoding type); - - virtual void AND_IMM(const u32 data, const ARMv7_encoding type); - virtual void AND_REG(const u32 data, const ARMv7_encoding type); - virtual void AND_RSR(const u32 data, const ARMv7_encoding type); - - virtual void ASR_IMM(const u32 data, const ARMv7_encoding type); - virtual void ASR_REG(const u32 data, const ARMv7_encoding type); - - virtual void B(const u32 data, const ARMv7_encoding type); - - virtual void BFC(const u32 data, const ARMv7_encoding type); - virtual void BFI(const u32 data, const ARMv7_encoding type); - - virtual void BIC_IMM(const u32 data, const ARMv7_encoding type); - virtual void BIC_REG(const u32 data, const ARMv7_encoding type); - virtual void BIC_RSR(const u32 data, const ARMv7_encoding type); - - virtual void BKPT(const u32 data, const ARMv7_encoding type); - - virtual void BL(const u32 data, const ARMv7_encoding type); - virtual void BLX(const u32 data, const ARMv7_encoding type); - virtual void BX(const u32 data, const ARMv7_encoding type); - - virtual void CB_Z(const u32 data, const ARMv7_encoding type); - - virtual void CLZ(const u32 data, const ARMv7_encoding type); + s8 CountLeadingZeroBits(T x, u8 len = sizeof(T) * 8); - virtual void CMN_IMM(const u32 data, const ARMv7_encoding type); - virtual void CMN_REG(const u32 data, const ARMv7_encoding type); - virtual void CMN_RSR(const u32 data, const ARMv7_encoding type); + SRType DecodeImmShift(u32 type, u32 imm5, u32* shift_n); + SRType DecodeRegShift(u8 type); - virtual void CMP_IMM(const u32 data, const ARMv7_encoding type); - virtual void CMP_REG(const u32 data, const ARMv7_encoding type); - virtual void CMP_RSR(const u32 data, const ARMv7_encoding type); + u32 LSL_C(u32 x, s32 shift, bool& carry_out); + u32 LSL(u32 x, s32 shift); + u32 LSR_C(u32 x, s32 shift, bool& carry_out); + u32 LSR(u32 x, s32 shift); - virtual void EOR_IMM(const u32 data, const ARMv7_encoding type); - virtual void EOR_REG(const u32 data, const ARMv7_encoding type); - virtual void EOR_RSR(const u32 data, const ARMv7_encoding type); + s32 ASR_C(s32 x, s32 shift, bool& carry_out); + s32 ASR(s32 x, s32 shift); - virtual void IT(const u32 data, const ARMv7_encoding type); + u32 ROR_C(u32 x, s32 shift, bool& carry_out); + u32 ROR(u32 x, s32 shift); - virtual void LDM(const u32 data, const ARMv7_encoding type); - virtual void LDMDA(const u32 data, const ARMv7_encoding type); - virtual void LDMDB(const u32 data, const ARMv7_encoding type); - virtual void LDMIB(const u32 data, const ARMv7_encoding type); + u32 RRX_C(u32 x, bool carry_in, bool& carry_out); + u32 RRX(u32 x, bool carry_in); - virtual void LDR_IMM(const u32 data, const ARMv7_encoding type); - virtual void LDR_LIT(const u32 data, const ARMv7_encoding type); - virtual void LDR_REG(const u32 data, const ARMv7_encoding type); + template T Shift_C(T value, SRType type, s32 amount, bool carry_in, bool& carry_out); - virtual void LDRB_IMM(const u32 data, const ARMv7_encoding type); - virtual void LDRB_LIT(const u32 data, const ARMv7_encoding type); - virtual void LDRB_REG(const u32 data, const ARMv7_encoding type); + template T Shift(T value, SRType type, s32 amount, bool carry_in); - virtual void LDRD_IMM(const u32 data, const ARMv7_encoding type); - virtual void LDRD_LIT(const u32 data, const ARMv7_encoding type); - virtual void LDRD_REG(const u32 data, const ARMv7_encoding type); + template T AddWithCarry(T x, T y, bool carry_in, bool& carry_out, bool& overflow); - virtual void LDRH_IMM(const u32 data, const ARMv7_encoding type); - virtual void LDRH_LIT(const u32 data, const ARMv7_encoding type); - virtual void LDRH_REG(const u32 data, const ARMv7_encoding type); + u32 ThumbExpandImm_C(u32 imm12, bool carry_in, bool& carry_out); + u32 ThumbExpandImm(ARMv7Thread* CPU, u32 imm12); - virtual void LDRSB_IMM(const u32 data, const ARMv7_encoding type); - virtual void LDRSB_LIT(const u32 data, const ARMv7_encoding type); - virtual void LDRSB_REG(const u32 data, const ARMv7_encoding type); + bool ConditionPassed(ARMv7Thread* CPU, u32 cond); - virtual void LDRSH_IMM(const u32 data, const ARMv7_encoding type); - virtual void LDRSH_LIT(const u32 data, const ARMv7_encoding type); - virtual void LDRSH_REG(const u32 data, const ARMv7_encoding type); + // instructions + void UNK(ARMv7Thread* thr); - virtual void LSL_IMM(const u32 data, const ARMv7_encoding type); - virtual void LSL_REG(const u32 data, const ARMv7_encoding type); + void NULL_OP(ARMv7Thread* thr, const ARMv7_encoding type); - virtual void LSR_IMM(const u32 data, const ARMv7_encoding type); - virtual void LSR_REG(const u32 data, const ARMv7_encoding type); + void HACK(ARMv7Thread* thr, const ARMv7_encoding type); - virtual void MLA(const u32 data, const ARMv7_encoding type); - virtual void MLS(const u32 data, const ARMv7_encoding type); + void ADC_IMM(ARMv7Thread* thr, const ARMv7_encoding type); + void ADC_REG(ARMv7Thread* thr, const ARMv7_encoding type); + void ADC_RSR(ARMv7Thread* thr, const ARMv7_encoding type); - virtual void MOV_IMM(const u32 data, const ARMv7_encoding type); - virtual void MOV_REG(const u32 data, const ARMv7_encoding type); - virtual void MOVT(const u32 data, const ARMv7_encoding type); + void ADD_IMM(ARMv7Thread* thr, const ARMv7_encoding type); + void ADD_REG(ARMv7Thread* thr, const ARMv7_encoding type); + void ADD_RSR(ARMv7Thread* thr, const ARMv7_encoding type); + void ADD_SPI(ARMv7Thread* thr, const ARMv7_encoding type); + void ADD_SPR(ARMv7Thread* thr, const ARMv7_encoding type); - virtual void MRS(const u32 data, const ARMv7_encoding type); - virtual void MSR_IMM(const u32 data, const ARMv7_encoding type); - virtual void MSR_REG(const u32 data, const ARMv7_encoding type); + void ADR(ARMv7Thread* thr, const ARMv7_encoding type); - virtual void MUL(const u32 data, const ARMv7_encoding type); + void AND_IMM(ARMv7Thread* thr, const ARMv7_encoding type); + void AND_REG(ARMv7Thread* thr, const ARMv7_encoding type); + void AND_RSR(ARMv7Thread* thr, const ARMv7_encoding type); - virtual void MVN_IMM(const u32 data, const ARMv7_encoding type); - virtual void MVN_REG(const u32 data, const ARMv7_encoding type); - virtual void MVN_RSR(const u32 data, const ARMv7_encoding type); + void ASR_IMM(ARMv7Thread* thr, const ARMv7_encoding type); + void ASR_REG(ARMv7Thread* thr, const ARMv7_encoding type); - virtual void NOP(const u32 data, const ARMv7_encoding type); + void B(ARMv7Thread* thr, const ARMv7_encoding type); - virtual void ORN_IMM(const u32 data, const ARMv7_encoding type); - virtual void ORN_REG(const u32 data, const ARMv7_encoding type); + void BFC(ARMv7Thread* thr, const ARMv7_encoding type); + void BFI(ARMv7Thread* thr, const ARMv7_encoding type); - virtual void ORR_IMM(const u32 data, const ARMv7_encoding type); - virtual void ORR_REG(const u32 data, const ARMv7_encoding type); - virtual void ORR_RSR(const u32 data, const ARMv7_encoding type); + void BIC_IMM(ARMv7Thread* thr, const ARMv7_encoding type); + void BIC_REG(ARMv7Thread* thr, const ARMv7_encoding type); + void BIC_RSR(ARMv7Thread* thr, const ARMv7_encoding type); - virtual void PKH(const u32 data, const ARMv7_encoding type); + void BKPT(ARMv7Thread* thr, const ARMv7_encoding type); - virtual void POP(const u32 data, const ARMv7_encoding type); - virtual void PUSH(const u32 data, const ARMv7_encoding type); + void BL(ARMv7Thread* thr, const ARMv7_encoding type); + void BLX(ARMv7Thread* thr, const ARMv7_encoding type); + void BX(ARMv7Thread* thr, const ARMv7_encoding type); - virtual void QADD(const u32 data, const ARMv7_encoding type); - virtual void QADD16(const u32 data, const ARMv7_encoding type); - virtual void QADD8(const u32 data, const ARMv7_encoding type); - virtual void QASX(const u32 data, const ARMv7_encoding type); - virtual void QDADD(const u32 data, const ARMv7_encoding type); - virtual void QDSUB(const u32 data, const ARMv7_encoding type); - virtual void QSAX(const u32 data, const ARMv7_encoding type); - virtual void QSUB(const u32 data, const ARMv7_encoding type); - virtual void QSUB16(const u32 data, const ARMv7_encoding type); - virtual void QSUB8(const u32 data, const ARMv7_encoding type); + void CB_Z(ARMv7Thread* thr, const ARMv7_encoding type); - virtual void RBIT(const u32 data, const ARMv7_encoding type); - virtual void REV(const u32 data, const ARMv7_encoding type); - virtual void REV16(const u32 data, const ARMv7_encoding type); - virtual void REVSH(const u32 data, const ARMv7_encoding type); + void CLZ(ARMv7Thread* thr, const ARMv7_encoding type); - virtual void ROR_IMM(const u32 data, const ARMv7_encoding type); - virtual void ROR_REG(const u32 data, const ARMv7_encoding type); - - virtual void RRX(const u32 data, const ARMv7_encoding type); - - virtual void RSB_IMM(const u32 data, const ARMv7_encoding type); - virtual void RSB_REG(const u32 data, const ARMv7_encoding type); - virtual void RSB_RSR(const u32 data, const ARMv7_encoding type); - - virtual void RSC_IMM(const u32 data, const ARMv7_encoding type); - virtual void RSC_REG(const u32 data, const ARMv7_encoding type); - virtual void RSC_RSR(const u32 data, const ARMv7_encoding type); - - virtual void SADD16(const u32 data, const ARMv7_encoding type); - virtual void SADD8(const u32 data, const ARMv7_encoding type); - virtual void SASX(const u32 data, const ARMv7_encoding type); - - virtual void SBC_IMM(const u32 data, const ARMv7_encoding type); - virtual void SBC_REG(const u32 data, const ARMv7_encoding type); - virtual void SBC_RSR(const u32 data, const ARMv7_encoding type); - - virtual void SBFX(const u32 data, const ARMv7_encoding type); - - virtual void SDIV(const u32 data, const ARMv7_encoding type); - - virtual void SEL(const u32 data, const ARMv7_encoding type); - - virtual void SHADD16(const u32 data, const ARMv7_encoding type); - virtual void SHADD8(const u32 data, const ARMv7_encoding type); - virtual void SHASX(const u32 data, const ARMv7_encoding type); - virtual void SHSAX(const u32 data, const ARMv7_encoding type); - virtual void SHSUB16(const u32 data, const ARMv7_encoding type); - virtual void SHSUB8(const u32 data, const ARMv7_encoding type); - - virtual void SMLA__(const u32 data, const ARMv7_encoding type); - virtual void SMLAD(const u32 data, const ARMv7_encoding type); - virtual void SMLAL(const u32 data, const ARMv7_encoding type); - virtual void SMLAL__(const u32 data, const ARMv7_encoding type); - virtual void SMLALD(const u32 data, const ARMv7_encoding type); - virtual void SMLAW_(const u32 data, const ARMv7_encoding type); - virtual void SMLSD(const u32 data, const ARMv7_encoding type); - virtual void SMLSLD(const u32 data, const ARMv7_encoding type); - virtual void SMMLA(const u32 data, const ARMv7_encoding type); - virtual void SMMLS(const u32 data, const ARMv7_encoding type); - virtual void SMMUL(const u32 data, const ARMv7_encoding type); - virtual void SMUAD(const u32 data, const ARMv7_encoding type); - virtual void SMUL__(const u32 data, const ARMv7_encoding type); - virtual void SMULL(const u32 data, const ARMv7_encoding type); - virtual void SMULW_(const u32 data, const ARMv7_encoding type); - virtual void SMUSD(const u32 data, const ARMv7_encoding type); - - virtual void SSAT(const u32 data, const ARMv7_encoding type); - virtual void SSAT16(const u32 data, const ARMv7_encoding type); - virtual void SSAX(const u32 data, const ARMv7_encoding type); - virtual void SSUB16(const u32 data, const ARMv7_encoding type); - virtual void SSUB8(const u32 data, const ARMv7_encoding type); - - virtual void STM(const u32 data, const ARMv7_encoding type); - virtual void STMDA(const u32 data, const ARMv7_encoding type); - virtual void STMDB(const u32 data, const ARMv7_encoding type); - virtual void STMIB(const u32 data, const ARMv7_encoding type); - - virtual void STR_IMM(const u32 data, const ARMv7_encoding type); - virtual void STR_REG(const u32 data, const ARMv7_encoding type); - - virtual void STRB_IMM(const u32 data, const ARMv7_encoding type); - virtual void STRB_REG(const u32 data, const ARMv7_encoding type); - - virtual void STRD_IMM(const u32 data, const ARMv7_encoding type); - virtual void STRD_REG(const u32 data, const ARMv7_encoding type); - - virtual void STRH_IMM(const u32 data, const ARMv7_encoding type); - virtual void STRH_REG(const u32 data, const ARMv7_encoding type); - - virtual void SUB_IMM(const u32 data, const ARMv7_encoding type); - virtual void SUB_REG(const u32 data, const ARMv7_encoding type); - virtual void SUB_RSR(const u32 data, const ARMv7_encoding type); - virtual void SUB_SPI(const u32 data, const ARMv7_encoding type); - virtual void SUB_SPR(const u32 data, const ARMv7_encoding type); - - virtual void SVC(const u32 data, const ARMv7_encoding type); - - virtual void SXTAB(const u32 data, const ARMv7_encoding type); - virtual void SXTAB16(const u32 data, const ARMv7_encoding type); - virtual void SXTAH(const u32 data, const ARMv7_encoding type); - virtual void SXTB(const u32 data, const ARMv7_encoding type); - virtual void SXTB16(const u32 data, const ARMv7_encoding type); - virtual void SXTH(const u32 data, const ARMv7_encoding type); - - virtual void TB_(const u32 data, const ARMv7_encoding type); - - virtual void TEQ_IMM(const u32 data, const ARMv7_encoding type); - virtual void TEQ_REG(const u32 data, const ARMv7_encoding type); - virtual void TEQ_RSR(const u32 data, const ARMv7_encoding type); - - virtual void TST_IMM(const u32 data, const ARMv7_encoding type); - virtual void TST_REG(const u32 data, const ARMv7_encoding type); - virtual void TST_RSR(const u32 data, const ARMv7_encoding type); - - virtual void UADD16(const u32 data, const ARMv7_encoding type); - virtual void UADD8(const u32 data, const ARMv7_encoding type); - virtual void UASX(const u32 data, const ARMv7_encoding type); - virtual void UBFX(const u32 data, const ARMv7_encoding type); - virtual void UDIV(const u32 data, const ARMv7_encoding type); - virtual void UHADD16(const u32 data, const ARMv7_encoding type); - virtual void UHADD8(const u32 data, const ARMv7_encoding type); - virtual void UHASX(const u32 data, const ARMv7_encoding type); - virtual void UHSAX(const u32 data, const ARMv7_encoding type); - virtual void UHSUB16(const u32 data, const ARMv7_encoding type); - virtual void UHSUB8(const u32 data, const ARMv7_encoding type); - virtual void UMAAL(const u32 data, const ARMv7_encoding type); - virtual void UMLAL(const u32 data, const ARMv7_encoding type); - virtual void UMULL(const u32 data, const ARMv7_encoding type); - virtual void UQADD16(const u32 data, const ARMv7_encoding type); - virtual void UQADD8(const u32 data, const ARMv7_encoding type); - virtual void UQASX(const u32 data, const ARMv7_encoding type); - virtual void UQSAX(const u32 data, const ARMv7_encoding type); - virtual void UQSUB16(const u32 data, const ARMv7_encoding type); - virtual void UQSUB8(const u32 data, const ARMv7_encoding type); - virtual void USAD8(const u32 data, const ARMv7_encoding type); - virtual void USADA8(const u32 data, const ARMv7_encoding type); - virtual void USAT(const u32 data, const ARMv7_encoding type); - virtual void USAT16(const u32 data, const ARMv7_encoding type); - virtual void USAX(const u32 data, const ARMv7_encoding type); - virtual void USUB16(const u32 data, const ARMv7_encoding type); - virtual void USUB8(const u32 data, const ARMv7_encoding type); - virtual void UXTAB(const u32 data, const ARMv7_encoding type); - virtual void UXTAB16(const u32 data, const ARMv7_encoding type); - virtual void UXTAH(const u32 data, const ARMv7_encoding type); - virtual void UXTB(const u32 data, const ARMv7_encoding type); - virtual void UXTB16(const u32 data, const ARMv7_encoding type); - virtual void UXTH(const u32 data, const ARMv7_encoding type); + void CMN_IMM(ARMv7Thread* thr, const ARMv7_encoding type); + void CMN_REG(ARMv7Thread* thr, const ARMv7_encoding type); + void CMN_RSR(ARMv7Thread* thr, const ARMv7_encoding type); + + void CMP_IMM(ARMv7Thread* thr, const ARMv7_encoding type); + void CMP_REG(ARMv7Thread* thr, const ARMv7_encoding type); + void CMP_RSR(ARMv7Thread* thr, const ARMv7_encoding type); + + void EOR_IMM(ARMv7Thread* thr, const ARMv7_encoding type); + void EOR_REG(ARMv7Thread* thr, const ARMv7_encoding type); + void EOR_RSR(ARMv7Thread* thr, const ARMv7_encoding type); + + void IT(ARMv7Thread* thr, const ARMv7_encoding type); + + void LDM(ARMv7Thread* thr, const ARMv7_encoding type); + void LDMDA(ARMv7Thread* thr, const ARMv7_encoding type); + void LDMDB(ARMv7Thread* thr, const ARMv7_encoding type); + void LDMIB(ARMv7Thread* thr, const ARMv7_encoding type); + + void LDR_IMM(ARMv7Thread* thr, const ARMv7_encoding type); + void LDR_LIT(ARMv7Thread* thr, const ARMv7_encoding type); + void LDR_REG(ARMv7Thread* thr, const ARMv7_encoding type); + + void LDRB_IMM(ARMv7Thread* thr, const ARMv7_encoding type); + void LDRB_LIT(ARMv7Thread* thr, const ARMv7_encoding type); + void LDRB_REG(ARMv7Thread* thr, const ARMv7_encoding type); + + void LDRD_IMM(ARMv7Thread* thr, const ARMv7_encoding type); + void LDRD_LIT(ARMv7Thread* thr, const ARMv7_encoding type); + void LDRD_REG(ARMv7Thread* thr, const ARMv7_encoding type); + + void LDRH_IMM(ARMv7Thread* thr, const ARMv7_encoding type); + void LDRH_LIT(ARMv7Thread* thr, const ARMv7_encoding type); + void LDRH_REG(ARMv7Thread* thr, const ARMv7_encoding type); + + void LDRSB_IMM(ARMv7Thread* thr, const ARMv7_encoding type); + void LDRSB_LIT(ARMv7Thread* thr, const ARMv7_encoding type); + void LDRSB_REG(ARMv7Thread* thr, const ARMv7_encoding type); + + void LDRSH_IMM(ARMv7Thread* thr, const ARMv7_encoding type); + void LDRSH_LIT(ARMv7Thread* thr, const ARMv7_encoding type); + void LDRSH_REG(ARMv7Thread* thr, const ARMv7_encoding type); + + void LSL_IMM(ARMv7Thread* thr, const ARMv7_encoding type); + void LSL_REG(ARMv7Thread* thr, const ARMv7_encoding type); + + void LSR_IMM(ARMv7Thread* thr, const ARMv7_encoding type); + void LSR_REG(ARMv7Thread* thr, const ARMv7_encoding type); + + void MLA(ARMv7Thread* thr, const ARMv7_encoding type); + void MLS(ARMv7Thread* thr, const ARMv7_encoding type); + + void MOV_IMM(ARMv7Thread* thr, const ARMv7_encoding type); + void MOV_REG(ARMv7Thread* thr, const ARMv7_encoding type); + void MOVT(ARMv7Thread* thr, const ARMv7_encoding type); + + void MRS(ARMv7Thread* thr, const ARMv7_encoding type); + void MSR_IMM(ARMv7Thread* thr, const ARMv7_encoding type); + void MSR_REG(ARMv7Thread* thr, const ARMv7_encoding type); + + void MUL(ARMv7Thread* thr, const ARMv7_encoding type); + + void MVN_IMM(ARMv7Thread* thr, const ARMv7_encoding type); + void MVN_REG(ARMv7Thread* thr, const ARMv7_encoding type); + void MVN_RSR(ARMv7Thread* thr, const ARMv7_encoding type); + + void NOP(ARMv7Thread* thr, const ARMv7_encoding type); + + void ORN_IMM(ARMv7Thread* thr, const ARMv7_encoding type); + void ORN_REG(ARMv7Thread* thr, const ARMv7_encoding type); + + void ORR_IMM(ARMv7Thread* thr, const ARMv7_encoding type); + void ORR_REG(ARMv7Thread* thr, const ARMv7_encoding type); + void ORR_RSR(ARMv7Thread* thr, const ARMv7_encoding type); + + void PKH(ARMv7Thread* thr, const ARMv7_encoding type); + + void POP(ARMv7Thread* thr, const ARMv7_encoding type); + void PUSH(ARMv7Thread* thr, const ARMv7_encoding type); + + void QADD(ARMv7Thread* thr, const ARMv7_encoding type); + void QADD16(ARMv7Thread* thr, const ARMv7_encoding type); + void QADD8(ARMv7Thread* thr, const ARMv7_encoding type); + void QASX(ARMv7Thread* thr, const ARMv7_encoding type); + void QDADD(ARMv7Thread* thr, const ARMv7_encoding type); + void QDSUB(ARMv7Thread* thr, const ARMv7_encoding type); + void QSAX(ARMv7Thread* thr, const ARMv7_encoding type); + void QSUB(ARMv7Thread* thr, const ARMv7_encoding type); + void QSUB16(ARMv7Thread* thr, const ARMv7_encoding type); + void QSUB8(ARMv7Thread* thr, const ARMv7_encoding type); + + void RBIT(ARMv7Thread* thr, const ARMv7_encoding type); + void REV(ARMv7Thread* thr, const ARMv7_encoding type); + void REV16(ARMv7Thread* thr, const ARMv7_encoding type); + void REVSH(ARMv7Thread* thr, const ARMv7_encoding type); + + void ROR_IMM(ARMv7Thread* thr, const ARMv7_encoding type); + void ROR_REG(ARMv7Thread* thr, const ARMv7_encoding type); + + void RRX(ARMv7Thread* thr, const ARMv7_encoding type); + + void RSB_IMM(ARMv7Thread* thr, const ARMv7_encoding type); + void RSB_REG(ARMv7Thread* thr, const ARMv7_encoding type); + void RSB_RSR(ARMv7Thread* thr, const ARMv7_encoding type); + + void RSC_IMM(ARMv7Thread* thr, const ARMv7_encoding type); + void RSC_REG(ARMv7Thread* thr, const ARMv7_encoding type); + void RSC_RSR(ARMv7Thread* thr, const ARMv7_encoding type); + + void SADD16(ARMv7Thread* thr, const ARMv7_encoding type); + void SADD8(ARMv7Thread* thr, const ARMv7_encoding type); + void SASX(ARMv7Thread* thr, const ARMv7_encoding type); + + void SBC_IMM(ARMv7Thread* thr, const ARMv7_encoding type); + void SBC_REG(ARMv7Thread* thr, const ARMv7_encoding type); + void SBC_RSR(ARMv7Thread* thr, const ARMv7_encoding type); + + void SBFX(ARMv7Thread* thr, const ARMv7_encoding type); + + void SDIV(ARMv7Thread* thr, const ARMv7_encoding type); + + void SEL(ARMv7Thread* thr, const ARMv7_encoding type); + + void SHADD16(ARMv7Thread* thr, const ARMv7_encoding type); + void SHADD8(ARMv7Thread* thr, const ARMv7_encoding type); + void SHASX(ARMv7Thread* thr, const ARMv7_encoding type); + void SHSAX(ARMv7Thread* thr, const ARMv7_encoding type); + void SHSUB16(ARMv7Thread* thr, const ARMv7_encoding type); + void SHSUB8(ARMv7Thread* thr, const ARMv7_encoding type); + + void SMLA__(ARMv7Thread* thr, const ARMv7_encoding type); + void SMLAD(ARMv7Thread* thr, const ARMv7_encoding type); + void SMLAL(ARMv7Thread* thr, const ARMv7_encoding type); + void SMLAL__(ARMv7Thread* thr, const ARMv7_encoding type); + void SMLALD(ARMv7Thread* thr, const ARMv7_encoding type); + void SMLAW_(ARMv7Thread* thr, const ARMv7_encoding type); + void SMLSD(ARMv7Thread* thr, const ARMv7_encoding type); + void SMLSLD(ARMv7Thread* thr, const ARMv7_encoding type); + void SMMLA(ARMv7Thread* thr, const ARMv7_encoding type); + void SMMLS(ARMv7Thread* thr, const ARMv7_encoding type); + void SMMUL(ARMv7Thread* thr, const ARMv7_encoding type); + void SMUAD(ARMv7Thread* thr, const ARMv7_encoding type); + void SMUL__(ARMv7Thread* thr, const ARMv7_encoding type); + void SMULL(ARMv7Thread* thr, const ARMv7_encoding type); + void SMULW_(ARMv7Thread* thr, const ARMv7_encoding type); + void SMUSD(ARMv7Thread* thr, const ARMv7_encoding type); + + void SSAT(ARMv7Thread* thr, const ARMv7_encoding type); + void SSAT16(ARMv7Thread* thr, const ARMv7_encoding type); + void SSAX(ARMv7Thread* thr, const ARMv7_encoding type); + void SSUB16(ARMv7Thread* thr, const ARMv7_encoding type); + void SSUB8(ARMv7Thread* thr, const ARMv7_encoding type); + + void STM(ARMv7Thread* thr, const ARMv7_encoding type); + void STMDA(ARMv7Thread* thr, const ARMv7_encoding type); + void STMDB(ARMv7Thread* thr, const ARMv7_encoding type); + void STMIB(ARMv7Thread* thr, const ARMv7_encoding type); + + void STR_IMM(ARMv7Thread* thr, const ARMv7_encoding type); + void STR_REG(ARMv7Thread* thr, const ARMv7_encoding type); + + void STRB_IMM(ARMv7Thread* thr, const ARMv7_encoding type); + void STRB_REG(ARMv7Thread* thr, const ARMv7_encoding type); + + void STRD_IMM(ARMv7Thread* thr, const ARMv7_encoding type); + void STRD_REG(ARMv7Thread* thr, const ARMv7_encoding type); + + void STRH_IMM(ARMv7Thread* thr, const ARMv7_encoding type); + void STRH_REG(ARMv7Thread* thr, const ARMv7_encoding type); + + void SUB_IMM(ARMv7Thread* thr, const ARMv7_encoding type); + void SUB_REG(ARMv7Thread* thr, const ARMv7_encoding type); + void SUB_RSR(ARMv7Thread* thr, const ARMv7_encoding type); + void SUB_SPI(ARMv7Thread* thr, const ARMv7_encoding type); + void SUB_SPR(ARMv7Thread* thr, const ARMv7_encoding type); + + void SVC(ARMv7Thread* thr, const ARMv7_encoding type); + + void SXTAB(ARMv7Thread* thr, const ARMv7_encoding type); + void SXTAB16(ARMv7Thread* thr, const ARMv7_encoding type); + void SXTAH(ARMv7Thread* thr, const ARMv7_encoding type); + void SXTB(ARMv7Thread* thr, const ARMv7_encoding type); + void SXTB16(ARMv7Thread* thr, const ARMv7_encoding type); + void SXTH(ARMv7Thread* thr, const ARMv7_encoding type); + + void TB_(ARMv7Thread* thr, const ARMv7_encoding type); + + void TEQ_IMM(ARMv7Thread* thr, const ARMv7_encoding type); + void TEQ_REG(ARMv7Thread* thr, const ARMv7_encoding type); + void TEQ_RSR(ARMv7Thread* thr, const ARMv7_encoding type); + + void TST_IMM(ARMv7Thread* thr, const ARMv7_encoding type); + void TST_REG(ARMv7Thread* thr, const ARMv7_encoding type); + void TST_RSR(ARMv7Thread* thr, const ARMv7_encoding type); + + void UADD16(ARMv7Thread* thr, const ARMv7_encoding type); + void UADD8(ARMv7Thread* thr, const ARMv7_encoding type); + void UASX(ARMv7Thread* thr, const ARMv7_encoding type); + void UBFX(ARMv7Thread* thr, const ARMv7_encoding type); + void UDIV(ARMv7Thread* thr, const ARMv7_encoding type); + void UHADD16(ARMv7Thread* thr, const ARMv7_encoding type); + void UHADD8(ARMv7Thread* thr, const ARMv7_encoding type); + void UHASX(ARMv7Thread* thr, const ARMv7_encoding type); + void UHSAX(ARMv7Thread* thr, const ARMv7_encoding type); + void UHSUB16(ARMv7Thread* thr, const ARMv7_encoding type); + void UHSUB8(ARMv7Thread* thr, const ARMv7_encoding type); + void UMAAL(ARMv7Thread* thr, const ARMv7_encoding type); + void UMLAL(ARMv7Thread* thr, const ARMv7_encoding type); + void UMULL(ARMv7Thread* thr, const ARMv7_encoding type); + void UQADD16(ARMv7Thread* thr, const ARMv7_encoding type); + void UQADD8(ARMv7Thread* thr, const ARMv7_encoding type); + void UQASX(ARMv7Thread* thr, const ARMv7_encoding type); + void UQSAX(ARMv7Thread* thr, const ARMv7_encoding type); + void UQSUB16(ARMv7Thread* thr, const ARMv7_encoding type); + void UQSUB8(ARMv7Thread* thr, const ARMv7_encoding type); + void USAD8(ARMv7Thread* thr, const ARMv7_encoding type); + void USADA8(ARMv7Thread* thr, const ARMv7_encoding type); + void USAT(ARMv7Thread* thr, const ARMv7_encoding type); + void USAT16(ARMv7Thread* thr, const ARMv7_encoding type); + void USAX(ARMv7Thread* thr, const ARMv7_encoding type); + void USUB16(ARMv7Thread* thr, const ARMv7_encoding type); + void USUB8(ARMv7Thread* thr, const ARMv7_encoding type); + void UXTAB(ARMv7Thread* thr, const ARMv7_encoding type); + void UXTAB16(ARMv7Thread* thr, const ARMv7_encoding type); + void UXTAH(ARMv7Thread* thr, const ARMv7_encoding type); + void UXTB(ARMv7Thread* thr, const ARMv7_encoding type); + void UXTB16(ARMv7Thread* thr, const ARMv7_encoding type); + void UXTH(ARMv7Thread* thr, const ARMv7_encoding type); }; + + +// old instructions table for debugging and information, delete this later +using namespace ARMv7_instrs; + +struct ARMv7_opcode_t +{ + u32 mask; + u32 code; + u32 length; // 2 or 4 + const char* name; + ARMv7_encoding type; + void(*func)(ARMv7Thread* thr, const ARMv7_encoding type); +}; + +// single 16-bit value +#define ARMv7_OP2(mask, code, type, name) { (u32)((mask) << 16), (u32)((code) << 16), 2, #name "_" #type, type, name } +// two 16-bit values +#define ARMv7_OP4(mask0, mask1, code0, code1, type, name) { (u32)((mask0) << 16) | (mask1), (u32)((code0) << 16) | (code1), 4, #name "_" #type, type, name } + +static const ARMv7_opcode_t ARMv7_opcode_table[] = +{ + ARMv7_OP2(0xffff, 0x0000, T1, NULL_OP), // ??? + + ARMv7_OP4(0xffff, 0x0000, 0xf870, 0x0000, T1, HACK), // "Undefined" Thumb opcode + ARMv7_OP4(0x0ff0, 0x00f0, 0x0070, 0x0090, A1, HACK), // "Undefined" ARM opcode + + ARMv7_OP4(0xfbe0, 0x8000, 0xf140, 0x0000, T1, ADC_IMM), + ARMv7_OP4(0x0fe0, 0x0000, 0x02a0, 0x0000, A1, ADC_IMM), + ARMv7_OP2(0xffc0, 0x4040, T1, ADC_REG), + ARMv7_OP4(0xffe0, 0x8000, 0xeb40, 0x0000, T2, ADC_REG), + ARMv7_OP4(0x0fe0, 0x0010, 0x00a0, 0x0000, A1, ADC_REG), + ARMv7_OP4(0x0fe0, 0x0090, 0x00a0, 0x0010, A1, ADC_RSR), + + ARMv7_OP2(0xf800, 0xa800, T1, ADD_SPI), + ARMv7_OP2(0xff80, 0xb000, T2, ADD_SPI), + ARMv7_OP4(0xfbef, 0x8000, 0xf10d, 0x0000, T3, ADD_SPI), + ARMv7_OP4(0xfbff, 0x8000, 0xf20d, 0x0000, T4, ADD_SPI), + ARMv7_OP4(0x0fef, 0x0000, 0x028d, 0x0000, A1, ADD_SPI), + ARMv7_OP2(0xff78, 0x4468, T1, ADD_SPR), + ARMv7_OP2(0xff87, 0x4485, T2, ADD_SPR), + ARMv7_OP4(0xffef, 0x8000, 0xeb0d, 0x0000, T3, ADD_SPR), + ARMv7_OP4(0x0fef, 0x0010, 0x008d, 0x0000, A1, ADD_SPR), + ARMv7_OP2(0xfe00, 0x1c00, T1, ADD_IMM), + ARMv7_OP2(0xf800, 0x3000, T2, ADD_IMM), + ARMv7_OP4(0xfbe0, 0x8000, 0xf100, 0x0000, T3, ADD_IMM), + ARMv7_OP4(0xfbf0, 0x8000, 0xf200, 0x0000, T4, ADD_IMM), + ARMv7_OP4(0x0fe0, 0x0000, 0x0280, 0x0000, A1, ADD_IMM), + ARMv7_OP2(0xfe00, 0x1800, T1, ADD_REG), + ARMv7_OP2(0xff00, 0x4400, T2, ADD_REG), + ARMv7_OP4(0xffe0, 0x8000, 0xeb00, 0x0000, T3, ADD_REG), + ARMv7_OP4(0x0fe0, 0x0010, 0x0080, 0x0000, A1, ADD_REG), + ARMv7_OP4(0x0fe0, 0x0090, 0x0080, 0x0010, A1, ADD_RSR), + + ARMv7_OP2(0xf800, 0xa000, T1, ADR), + ARMv7_OP4(0xfbff, 0x8000, 0xf2af, 0x0000, T2, ADR), + ARMv7_OP4(0xfbff, 0x8000, 0xf20f, 0x0000, T3, ADR), + ARMv7_OP4(0x0fff, 0x0000, 0x028f, 0x0000, A1, ADR), + ARMv7_OP4(0x0fff, 0x0000, 0x024f, 0x0000, A2, ADR), + + ARMv7_OP4(0xfbe0, 0x8000, 0xf000, 0x0000, T1, AND_IMM), + ARMv7_OP4(0x0fe0, 0x0000, 0x0200, 0x0000, A1, AND_IMM), + ARMv7_OP2(0xffc0, 0x4000, T1, AND_REG), + ARMv7_OP4(0xffe0, 0x8000, 0xea00, 0x0000, T2, AND_REG), + ARMv7_OP4(0x0fe0, 0x0010, 0x0000, 0x0000, A1, AND_REG), + ARMv7_OP4(0x0fe0, 0x0090, 0x0000, 0x0010, A1, AND_RSR), + + ARMv7_OP2(0xf800, 0x1000, T1, ASR_IMM), + ARMv7_OP4(0xffef, 0x8030, 0xea4f, 0x0020, T2, ASR_IMM), + ARMv7_OP4(0x0fef, 0x0070, 0x01a0, 0x0040, A1, ASR_IMM), + ARMv7_OP2(0xffc0, 0x4100, T1, ASR_REG), + ARMv7_OP4(0xffe0, 0xf0f0, 0xfa40, 0xf000, T2, ASR_REG), + ARMv7_OP4(0x0fef, 0x00f0, 0x01a0, 0x0050, A1, ASR_REG), + + ARMv7_OP2(0xf000, 0xd000, T1, B), + ARMv7_OP2(0xf800, 0xe000, T2, B), + ARMv7_OP4(0xf800, 0xd000, 0xf000, 0x8000, T3, B), + ARMv7_OP4(0xf800, 0xd000, 0xf000, 0x9000, T4, B), + ARMv7_OP4(0x0f00, 0x0000, 0x0a00, 0x0000, A1, B), + + ARMv7_OP4(0xffff, 0x8020, 0xf36f, 0x0000, T1, BFC), + ARMv7_OP4(0x0fe0, 0x007f, 0x07c0, 0x001f, A1, BFC), + ARMv7_OP4(0xfff0, 0x8020, 0xf360, 0x0000, T1, BFI), + ARMv7_OP4(0x0fe0, 0x0070, 0x07c0, 0x0010, A1, BFI), + + ARMv7_OP4(0xfbe0, 0x8000, 0xf020, 0x0000, T1, BIC_IMM), + ARMv7_OP4(0x0fe0, 0x0000, 0x03c0, 0x0000, A1, BIC_IMM), + ARMv7_OP2(0xffc0, 0x4380, T1, BIC_REG), + ARMv7_OP4(0xffe0, 0x8000, 0xea20, 0x0000, T2, BIC_REG), + ARMv7_OP4(0x0fe0, 0x0010, 0x01c0, 0x0000, A1, BIC_REG), + ARMv7_OP4(0x0fe0, 0x0090, 0x01c0, 0x0010, A1, BIC_RSR), + + ARMv7_OP2(0xff00, 0xbe00, T1, BKPT), + ARMv7_OP4(0x0ff0, 0x00f0, 0x0120, 0x0070, A1, BKPT), + + ARMv7_OP4(0xf800, 0xd000, 0xf000, 0xd000, T1, BL), + ARMv7_OP4(0x0f00, 0x0000, 0x0b00, 0x0000, A1, BL), + ARMv7_OP2(0xff80, 0x4780, T1, BLX), + ARMv7_OP4(0xf800, 0xc001, 0xf000, 0xc000, T2, BLX), + ARMv7_OP4(0x0fff, 0xfff0, 0x012f, 0xff30, A1, BLX), + ARMv7_OP4(0xfe00, 0x0000, 0xfa00, 0x0000, A2, BLX), + + ARMv7_OP2(0xff87, 0x4700, T1, BX), + ARMv7_OP4(0x0fff, 0xfff0, 0x012f, 0xff10, A1, BX), + + ARMv7_OP2(0xf500, 0xb100, T1, CB_Z), + + ARMv7_OP4(0xfff0, 0xf0f0, 0xfab0, 0xf080, T1, CLZ), + ARMv7_OP4(0x0fff, 0x0ff0, 0x016f, 0x0f10, A1, CLZ), + + ARMv7_OP4(0xfbf0, 0x8f00, 0xf110, 0x0f00, T1, CMN_IMM), + ARMv7_OP4(0x0ff0, 0xf000, 0x0370, 0x0000, A1, CMN_IMM), + ARMv7_OP2(0xffc0, 0x42c0, T1, CMN_REG), + ARMv7_OP4(0xfff0, 0x8f00, 0xeb10, 0x0f00, T2, CMN_REG), + ARMv7_OP4(0x0ff0, 0xf010, 0x0170, 0x0000, A1, CMN_REG), + ARMv7_OP4(0x0ff0, 0xf090, 0x0170, 0x0010, A1, CMN_RSR), + + ARMv7_OP2(0xf800, 0x2800, T1, CMP_IMM), + ARMv7_OP4(0xfbf0, 0x8f00, 0xf1b0, 0x0f00, T2, CMP_IMM), + ARMv7_OP4(0x0ff0, 0xf000, 0x0350, 0x0000, A1, CMP_IMM), + ARMv7_OP2(0xffc0, 0x4280, T1, CMP_REG), + ARMv7_OP2(0xff00, 0x4500, T2, CMP_REG), + ARMv7_OP4(0xfff0, 0x8f00, 0xebb0, 0x0f00, T3, CMP_REG), + ARMv7_OP4(0x0ff0, 0xf010, 0x0150, 0x0000, A1, CMP_REG), + ARMv7_OP4(0x0ff0, 0xf090, 0x0150, 0x0010, A1, CMP_RSR), + + ARMv7_OP4(0xfbe0, 0x8000, 0xf080, 0x0000, T1, EOR_IMM), + ARMv7_OP4(0x0fe0, 0x0000, 0x0220, 0x0000, A1, EOR_IMM), + ARMv7_OP2(0xffc0, 0x4040, T1, EOR_REG), + ARMv7_OP4(0xffe0, 0x8000, 0xea80, 0x0000, T2, EOR_REG), + ARMv7_OP4(0x0fe0, 0x0010, 0x0020, 0x0000, A1, EOR_REG), + ARMv7_OP4(0x0fe0, 0x0090, 0x0020, 0x0010, A1, EOR_RSR), + + ARMv7_OP2(0xff00, 0xbf00, T1, IT), + + ARMv7_OP2(0xf800, 0xc800, T1, LDM), + ARMv7_OP4(0xffd0, 0x2000, 0xe890, 0x0000, T2, LDM), + ARMv7_OP4(0x0fd0, 0x0000, 0x0890, 0x0000, A1, LDM), + ARMv7_OP4(0x0fd0, 0x0000, 0x0810, 0x0000, A1, LDMDA), + ARMv7_OP4(0xffd0, 0x2000, 0xe910, 0x0000, T1, LDMDB), + ARMv7_OP4(0x0fd0, 0x0000, 0x0910, 0x0000, A1, LDMDB), + ARMv7_OP4(0x0fd0, 0x0000, 0x0990, 0x0000, A1, LDMIB), + + ARMv7_OP2(0xf800, 0x6800, T1, LDR_IMM), + ARMv7_OP2(0xf800, 0x9800, T2, LDR_IMM), + ARMv7_OP4(0xfff0, 0x0000, 0xf8d0, 0x0000, T3, LDR_IMM), + ARMv7_OP4(0xfff0, 0x0800, 0xf850, 0x0800, T4, LDR_IMM), + ARMv7_OP4(0x0e50, 0x0000, 0x0410, 0x0000, A1, LDR_IMM), + ARMv7_OP2(0xf800, 0x4800, T1, LDR_LIT), + ARMv7_OP4(0xff7f, 0x0000, 0xf85f, 0x0000, T2, LDR_LIT), + ARMv7_OP4(0x0f7f, 0x0000, 0x051f, 0x0000, A1, LDR_LIT), + ARMv7_OP2(0xfe00, 0x5800, T1, LDR_REG), + ARMv7_OP4(0xfff0, 0x0fc0, 0xf850, 0x0000, T2, LDR_REG), + ARMv7_OP4(0x0e50, 0x0010, 0x0610, 0x0000, A1, LDR_REG), + + ARMv7_OP2(0xf800, 0x7800, T1, LDRB_IMM), + ARMv7_OP4(0xfff0, 0x0000, 0xf890, 0x0000, T2, LDRB_IMM), + ARMv7_OP4(0xfff0, 0x0800, 0xf810, 0x0800, T3, LDRB_IMM), + ARMv7_OP4(0x0e50, 0x0000, 0x0450, 0x0000, A1, LDRB_IMM), + ARMv7_OP4(0xff7f, 0x0000, 0xf81f, 0x0000, T1, LDRB_LIT), + ARMv7_OP4(0x0f7f, 0x0000, 0x055f, 0x0000, A1, LDRB_LIT), + ARMv7_OP2(0xfe00, 0x5c00, T1, LDRB_REG), + ARMv7_OP4(0xfff0, 0x0fc0, 0xf810, 0x0000, T2, LDRB_REG), + ARMv7_OP4(0x0e50, 0x0010, 0x0650, 0x0000, A1, LDRB_REG), + + ARMv7_OP4(0xfe50, 0x0000, 0xe850, 0x0000, T1, LDRD_IMM), + ARMv7_OP4(0x0e50, 0x00f0, 0x0040, 0x00d0, A1, LDRD_IMM), + ARMv7_OP4(0xfe7f, 0x0000, 0xe85f, 0x0000, T1, LDRD_LIT), + ARMv7_OP4(0x0f7f, 0x00f0, 0x014f, 0x00d0, A1, LDRD_LIT), + ARMv7_OP4(0x0e50, 0x0ff0, 0x0000, 0x00d0, A1, LDRD_REG), + + ARMv7_OP4(0xfff0, 0x0000, 0xf990, 0x0000, T1, LDRSB_IMM), + ARMv7_OP4(0xfff0, 0x0800, 0xf910, 0x0800, T2, LDRSB_IMM), + ARMv7_OP4(0x0e50, 0x00f0, 0x0050, 0x00d0, A1, LDRSB_IMM), + ARMv7_OP4(0xff7f, 0x0000, 0xf91f, 0x0000, T1, LDRSB_LIT), + ARMv7_OP4(0x0f7f, 0x00f0, 0x015f, 0x00d0, A1, LDRSB_LIT), + ARMv7_OP2(0xfe00, 0x5600, T1, LDRSB_REG), + ARMv7_OP4(0xfff0, 0x0fc0, 0xf910, 0x0000, T2, LDRSB_REG), + ARMv7_OP4(0x0e50, 0x0ff0, 0x0010, 0x00d0, A1, LDRSB_REG), + + ARMv7_OP4(0xfff0, 0x0000, 0xf9b0, 0x0000, T1, LDRSH_IMM), + ARMv7_OP4(0xfff0, 0x0800, 0xf930, 0x0800, T2, LDRSH_IMM), + ARMv7_OP4(0x0e50, 0x00f0, 0x0050, 0x00f0, A1, LDRSH_IMM), + ARMv7_OP4(0xff7f, 0x0000, 0xf93f, 0x0000, T1, LDRSH_LIT), + ARMv7_OP4(0x0f7f, 0x00f0, 0x015f, 0x00f0, A1, LDRSH_LIT), + ARMv7_OP2(0xfe00, 0x5e00, T1, LDRSH_REG), + ARMv7_OP4(0xfff0, 0x0fc0, 0xf930, 0x0000, T2, LDRSH_REG), + ARMv7_OP4(0x0e50, 0x0ff0, 0x0010, 0x00f0, A1, LDRSH_REG), + + ARMv7_OP2(0xf800, 0x0000, T1, LSL_IMM), + ARMv7_OP4(0xffef, 0x8030, 0xea4f, 0x0000, T2, LSL_IMM), + ARMv7_OP4(0x0fef, 0x0070, 0x01a0, 0x0000, A1, LSL_IMM), + ARMv7_OP2(0xffc0, 0x4080, T1, LSL_REG), + ARMv7_OP4(0xffe0, 0xf0f0, 0xfa00, 0xf000, T2, LSL_REG), + ARMv7_OP4(0x0fef, 0x00f0, 0x01a0, 0x0010, A1, LSL_REG), + + ARMv7_OP2(0xf800, 0x0800, T1, LSR_IMM), + ARMv7_OP4(0xffef, 0x8030, 0xea4f, 0x0010, T2, LSR_IMM), + ARMv7_OP4(0x0fef, 0x0030, 0x01a0, 0x0020, A1, LSR_IMM), + ARMv7_OP2(0xffc0, 0x40c0, T1, LSR_REG), + ARMv7_OP4(0xffe0, 0xf0f0, 0xfa20, 0xf000, T2, LSR_REG), + ARMv7_OP4(0x0fef, 0x00f0, 0x01a0, 0x0030, A1, LSR_REG), + + ARMv7_OP4(0xfff0, 0x00f0, 0xfb00, 0x0000, T1, MLA), + ARMv7_OP4(0x0fe0, 0x00f0, 0x0020, 0x0090, A1, MLA), + + ARMv7_OP4(0xfff0, 0x00f0, 0xfb00, 0x0010, T1, MLS), + ARMv7_OP4(0x0ff0, 0x00f0, 0x0060, 0x0090, A1, MLS), + + ARMv7_OP2(0xf800, 0x2000, T1, MOV_IMM), + ARMv7_OP4(0xfbef, 0x8000, 0xf04f, 0x0000, T2, MOV_IMM), + ARMv7_OP4(0xfbf0, 0x8000, 0xf240, 0x0000, T3, MOV_IMM), + ARMv7_OP4(0x0fef, 0x0000, 0x03a0, 0x0000, A1, MOV_IMM), + ARMv7_OP4(0x0ff0, 0x0000, 0x0300, 0x0000, A2, MOV_IMM), + ARMv7_OP2(0xff00, 0x4600, T1, MOV_REG), + ARMv7_OP2(0xffc0, 0x0000, T2, MOV_REG), + ARMv7_OP4(0xffef, 0xf0f0, 0xea4f, 0x0000, T3, MOV_REG), + ARMv7_OP4(0x0fef, 0x0ff0, 0x01a0, 0x0000, A1, MOV_REG), + ARMv7_OP4(0xfbf0, 0x8000, 0xf2c0, 0x0000, T1, MOVT), + ARMv7_OP4(0x0ff0, 0x0000, 0x0340, 0x0000, A1, MOVT), + + ARMv7_OP4(0xffff, 0xf0ff, 0xf3ef, 0x8000, T1, MRS), + ARMv7_OP4(0x0fff, 0x0fff, 0x010f, 0x0000, A1, MRS), + ARMv7_OP4(0x0ff3, 0xf000, 0x0320, 0xf000, A1, MSR_IMM), + ARMv7_OP4(0xfff0, 0xf3ff, 0xf380, 0x8000, T1, MSR_REG), + ARMv7_OP4(0x0ff3, 0xfff0, 0x0120, 0xf000, A1, MSR_REG), + + ARMv7_OP2(0xffc0, 0x4340, T1, MUL), + ARMv7_OP4(0xfff0, 0xf0f0, 0xfb00, 0xf000, T2, MUL), + ARMv7_OP4(0x0fe0, 0xf0f0, 0x0000, 0x0090, A1, MUL), + + ARMv7_OP4(0xfbef, 0x8000, 0xf06f, 0x0000, T1, MVN_IMM), + ARMv7_OP4(0x0fef, 0x0000, 0x03e0, 0x0000, A1, MVN_IMM), + ARMv7_OP2(0xffc0, 0x43c0, T1, MVN_REG), + ARMv7_OP4(0xffef, 0x8000, 0xea6f, 0x0000, T2, MVN_REG), + ARMv7_OP4(0xffef, 0x0010, 0x01e0, 0x0000, A1, MVN_REG), + ARMv7_OP4(0x0fef, 0x0090, 0x01e0, 0x0010, A1, MVN_RSR), + + ARMv7_OP2(0xffff, 0xbf00, T1, NOP), + ARMv7_OP4(0xffff, 0xffff, 0xf3af, 0x8000, T2, NOP), + ARMv7_OP4(0x0fff, 0xffff, 0x0320, 0xf000, A1, NOP), + + ARMv7_OP4(0xfbe0, 0x8000, 0xf060, 0x0000, T1, ORN_IMM), + ARMv7_OP4(0xffe0, 0x8000, 0xea60, 0x0000, T1, ORN_REG), + + ARMv7_OP4(0xfbe0, 0x8000, 0xf040, 0x0000, T1, ORR_IMM), + ARMv7_OP4(0x0fe0, 0x0000, 0x0380, 0x0000, A1, ORR_IMM), + ARMv7_OP2(0xffc0, 0x4300, T1, ORR_REG), + ARMv7_OP4(0xffe0, 0x8000, 0xea40, 0x0000, T2, ORR_REG), + ARMv7_OP4(0x0fe0, 0x0010, 0x0180, 0x0000, A1, ORR_REG), + ARMv7_OP4(0x0fe0, 0x0090, 0x0180, 0x0010, A1, ORR_RSR), + + ARMv7_OP4(0xfff0, 0x8010, 0xeac0, 0x0000, T1, PKH), + ARMv7_OP4(0x0ff0, 0x0030, 0x0680, 0x0010, A1, PKH), + + ARMv7_OP2(0xfe00, 0xbc00, T1, POP), + ARMv7_OP4(0xffff, 0x0000, 0xe8bd, 0x0000, T2, POP), + ARMv7_OP4(0xffff, 0x0fff, 0xf85d, 0x0b04, T3, POP), + ARMv7_OP4(0x0fff, 0x0000, 0x08bd, 0x0000, A1, POP), + ARMv7_OP4(0x0fff, 0x0fff, 0x049d, 0x0004, A2, POP), + + ARMv7_OP2(0xfe00, 0xb400, T1, PUSH), + ARMv7_OP4(0xffff, 0x0000, 0xe92d, 0x0000, T2, PUSH), // had an error in arch ref + ARMv7_OP4(0xffff, 0x0fff, 0xf84d, 0x0d04, T3, PUSH), + ARMv7_OP4(0x0fff, 0x0000, 0x092d, 0x0000, A1, PUSH), + ARMv7_OP4(0x0fff, 0x0fff, 0x052d, 0x0004, A2, PUSH), + + // TODO (Q*...) + + ARMv7_OP4(0xfff0, 0xf0f0, 0xfa90, 0xf0a0, T1, RBIT), + ARMv7_OP4(0x0fff, 0x0ff0, 0x06ff, 0x0f30, A1, RBIT), + + ARMv7_OP2(0xffc0, 0xba00, T1, REV), + ARMv7_OP4(0xfff0, 0xf0f0, 0xfa90, 0xf080, T2, REV), + ARMv7_OP4(0x0fff, 0x0ff0, 0x06bf, 0x0f30, A1, REV), + ARMv7_OP2(0xffc0, 0xba40, T1, REV16), + ARMv7_OP4(0xfff0, 0xf0f0, 0xfa90, 0xf090, T2, REV16), + ARMv7_OP4(0x0fff, 0x0ff0, 0x06bf, 0x0fb0, A1, REV16), + ARMv7_OP2(0xffc0, 0xbac0, T1, REVSH), + ARMv7_OP4(0xfff0, 0xf0f0, 0xfa90, 0xf0b0, T2, REVSH), + ARMv7_OP4(0x0fff, 0x0ff0, 0x06ff, 0x0fb0, A1, REVSH), + + ARMv7_OP4(0xffef, 0x8030, 0xea4f, 0x0030, T1, ROR_IMM), + ARMv7_OP4(0x0fef, 0x0070, 0x01a0, 0x0060, A1, ROR_IMM), + ARMv7_OP2(0xffc0, 0x41c0, T1, ROR_REG), + ARMv7_OP4(0xffe0, 0xf0f0, 0xfa60, 0xf000, T2, ROR_REG), + ARMv7_OP4(0x0fef, 0x00f0, 0x01a0, 0x0070, A1, ROR_REG), + ARMv7_OP4(0xffef, 0xf0f0, 0xea4f, 0x0030, T1, RRX), + ARMv7_OP4(0x0fef, 0x0ff0, 0x01a0, 0x0060, A1, RRX), + + ARMv7_OP2(0xffc0, 0x4240, T1, RSB_IMM), + ARMv7_OP4(0xfbe0, 0x8000, 0xf1c0, 0x0000, T2, RSB_IMM), + ARMv7_OP4(0x0fe0, 0x0000, 0x0260, 0x0000, A1, RSB_IMM), + ARMv7_OP4(0xffe0, 0x8000, 0xebc0, 0x0000, T1, RSB_REG), + ARMv7_OP4(0x0fe0, 0x0010, 0x0060, 0x0000, A1, RSB_REG), + ARMv7_OP4(0x0fe0, 0x0090, 0x0060, 0x0010, A1, RSB_RSR), + + ARMv7_OP4(0x0fe0, 0x0000, 0x02e0, 0x0000, A1, RSC_IMM), + ARMv7_OP4(0x0fe0, 0x0010, 0x00e0, 0x0000, A1, RSC_REG), + ARMv7_OP4(0x0fe0, 0x0090, 0x00e0, 0x0010, A1, RSC_RSR), + + // TODO (SADD16, SADD8, SASX) + + ARMv7_OP4(0xfbe0, 0x8000, 0xf160, 0x0000, T1, SBC_IMM), + ARMv7_OP4(0x0fe0, 0x0000, 0x02c0, 0x0000, A1, SBC_IMM), + ARMv7_OP2(0xffc0, 0x4180, T1, SBC_REG), + ARMv7_OP4(0xffe0, 0x8000, 0xeb60, 0x0000, T2, SBC_REG), + ARMv7_OP4(0x0fe0, 0x0010, 0x00c0, 0x0000, A1, SBC_REG), + ARMv7_OP4(0x0fe0, 0x0090, 0x00c0, 0x0010, A1, SBC_RSR), + + ARMv7_OP4(0xfff0, 0x8020, 0xf340, 0x0000, T1, SBFX), + ARMv7_OP4(0x0fe0, 0x0070, 0x07a0, 0x0050, A1, SBFX), + + ARMv7_OP4(0xfff0, 0xf0f0, 0xfb90, 0xf0f0, T1, SDIV), // ??? + + ARMv7_OP4(0xfff0, 0xf0f0, 0xfaa0, 0xf080, T1, SEL), + ARMv7_OP4(0x0ff0, 0x0ff0, 0x0680, 0x0fb0, A1, SEL), + + // TODO (SH*, SM*, SS*) + + ARMv7_OP2(0xf800, 0xc000, T1, STM), + ARMv7_OP4(0xffd0, 0xa000, 0xe880, 0x0000, T2, STM), + ARMv7_OP4(0x0fd0, 0x0000, 0x0880, 0x0000, A1, STM), + ARMv7_OP4(0x0fd0, 0x0000, 0x0800, 0x0000, A1, STMDA), + ARMv7_OP4(0xffd0, 0xa000, 0xe900, 0x0000, T1, STMDB), + ARMv7_OP4(0x0fd0, 0x0000, 0x0900, 0x0000, A1, STMDB), + ARMv7_OP4(0x0fd0, 0x0000, 0x0980, 0x0000, A1, STMIB), + + ARMv7_OP2(0xf800, 0x6000, T1, STR_IMM), + ARMv7_OP2(0xf800, 0x9000, T2, STR_IMM), + ARMv7_OP4(0xfff0, 0x0000, 0xf8c0, 0x0000, T3, STR_IMM), + ARMv7_OP4(0xfff0, 0x0800, 0xf840, 0x0800, T4, STR_IMM), + ARMv7_OP4(0x0e50, 0x0000, 0x0400, 0x0000, A1, STR_IMM), + ARMv7_OP2(0xfe00, 0x5000, T1, STR_REG), + ARMv7_OP4(0xfff0, 0x0fc0, 0xf840, 0x0000, T2, STR_REG), + ARMv7_OP4(0x0e50, 0x0010, 0x0600, 0x0000, A1, STR_REG), + + ARMv7_OP2(0xf800, 0x7000, T1, STRB_IMM), + ARMv7_OP4(0xfff0, 0x0000, 0xf880, 0x0000, T2, STRB_IMM), + ARMv7_OP4(0xfff0, 0x0800, 0xf800, 0x0800, T3, STRB_IMM), + ARMv7_OP4(0x0e50, 0x0000, 0x0440, 0x0000, A1, STRB_IMM), + ARMv7_OP2(0xfe00, 0x5400, T1, STRB_REG), + ARMv7_OP4(0xfff0, 0x0fc0, 0xf800, 0x0000, T2, STRB_REG), + ARMv7_OP4(0x0e50, 0x0010, 0x0640, 0x0000, A1, STRB_REG), + + ARMv7_OP4(0xfe50, 0x0000, 0xe840, 0x0000, T1, STRD_IMM), + ARMv7_OP4(0x0e50, 0x00f0, 0x0040, 0x00f0, A1, STRD_IMM), + ARMv7_OP4(0x0e50, 0x0ff0, 0x0000, 0x00f0, A1, STRD_REG), + + ARMv7_OP2(0xf800, 0x8000, T1, STRH_IMM), + ARMv7_OP4(0xfff0, 0x0000, 0xf8a0, 0x0000, T2, STRH_IMM), + ARMv7_OP4(0xfff0, 0x0800, 0xf820, 0x0800, T3, STRH_IMM), + ARMv7_OP4(0x0e50, 0x00f0, 0x0040, 0x00b0, A1, STRH_IMM), + ARMv7_OP2(0xfe00, 0x5200, T1, STRH_REG), + ARMv7_OP4(0xfff0, 0x0fc0, 0xf820, 0x0000, T2, STRH_REG), + ARMv7_OP4(0x0e50, 0x0ff0, 0x0000, 0x00b0, A1, STRH_REG), + + ARMv7_OP2(0xff80, 0xb080, T1, SUB_SPI), + ARMv7_OP4(0xfbef, 0x8000, 0xf1ad, 0x0000, T2, SUB_SPI), + ARMv7_OP4(0xfbff, 0x8000, 0xf2ad, 0x0000, T3, SUB_SPI), + ARMv7_OP4(0x0fef, 0x0000, 0x024d, 0x0000, A1, SUB_SPI), + ARMv7_OP4(0xffef, 0x8000, 0xebad, 0x0000, T1, SUB_SPR), + ARMv7_OP4(0x0fef, 0x0010, 0x004d, 0x0000, A1, SUB_SPR), + ARMv7_OP2(0xfe00, 0x1e00, T1, SUB_IMM), + ARMv7_OP2(0xf800, 0x3800, T2, SUB_IMM), + ARMv7_OP4(0xfbe0, 0x8000, 0xf1a0, 0x0000, T3, SUB_IMM), + ARMv7_OP4(0xfbf0, 0x8000, 0xf2a0, 0x0000, T4, SUB_IMM), + ARMv7_OP4(0x0fe0, 0x0000, 0x0240, 0x0000, A1, SUB_IMM), + ARMv7_OP2(0xfe00, 0x1a00, T1, SUB_REG), + ARMv7_OP4(0xffe0, 0x8000, 0xeba0, 0x0000, T2, SUB_REG), + ARMv7_OP4(0x0fe0, 0x0010, 0x0040, 0x0000, A1, SUB_REG), + ARMv7_OP4(0x0fe0, 0x0090, 0x0040, 0x0010, A1, SUB_RSR), + + ARMv7_OP2(0xff00, 0xdf00, T1, SVC), + ARMv7_OP4(0x0f00, 0x0000, 0x0f00, 0x0000, A1, SVC), + + // TODO (SX*) + + ARMv7_OP4(0xfff0, 0xffe0, 0xe8d0, 0xf000, T1, TB_), + + ARMv7_OP4(0xfbf0, 0x8f00, 0xf090, 0x0f00, T1, TEQ_IMM), + ARMv7_OP4(0x0ff0, 0xf000, 0x0330, 0x0000, A1, TEQ_IMM), + ARMv7_OP4(0xfff0, 0x8f00, 0xea90, 0x0f00, T1, TEQ_REG), + ARMv7_OP4(0x0ff0, 0xf010, 0x0130, 0x0000, A1, TEQ_REG), + ARMv7_OP4(0x0ff0, 0xf090, 0x0130, 0x0010, A1, TEQ_RSR), + + ARMv7_OP4(0xfbf0, 0x8f00, 0xf010, 0x0f00, T1, TST_IMM), + ARMv7_OP4(0x0ff0, 0xf000, 0x0310, 0x0000, A1, TST_IMM), + ARMv7_OP2(0xffc0, 0x4200, T1, TST_REG), + ARMv7_OP4(0xfff0, 0x8f00, 0xea10, 0x0f00, T2, TST_REG), + ARMv7_OP4(0x0ff0, 0xf010, 0x0110, 0x0000, A1, TST_REG), + ARMv7_OP4(0x0ff0, 0xf090, 0x0110, 0x0010, A1, TST_RSR) + + // TODO (U*, V*) +}; + +#undef ARMv7_OP2 +#undef ARMv7_OP4 diff --git a/rpcs3/Emu/ARMv7/ARMv7Opcodes.h b/rpcs3/Emu/ARMv7/ARMv7Opcodes.h index ddd6962885..2d079aa6f9 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Opcodes.h +++ b/rpcs3/Emu/ARMv7/ARMv7Opcodes.h @@ -1,5 +1,10 @@ #pragma once +#include "Emu/ARMv7/ARMv7Thread.h" +#include "Emu/ARMv7/ARMv7Interpreter.h" +#include "Emu/System.h" +#include "Utilities/Log.h" + static const char* g_arm_reg_name[16] = { "r0", "r1", "r2", "r3", @@ -8,710 +13,2013 @@ static const char* g_arm_reg_name[16] = "r12", "sp", "lr", "pc", }; -namespace ARMv7_opcodes +using namespace ARMv7_instrs; + +struct ARMv7_Instruction { - enum ARMv7_T1Opcodes - { - T1_CBZ = 0xb, - T1_B = 0xd, - T1_PUSH = 0x1d, - T1_POP = 0x5e, - T1_NOP = 0xBF00, - }; + void(*func)(ARMv7Thread* thr, const ARMv7_encoding type); + u8 size; + ARMv7_encoding type; + const char* name; +}; - enum ARMv7_T2Opcodes - { - T2_B = 0x1c, - T2_PUSH = 0xe92d, - T2_POP = 0xe8bd, - }; - enum ARMv7_T3Opcodes - { - T3_B = 0x1e, - }; +#define ARMv7_OP_2(func, type) { func, 2, type, #func "_" #type } +#define ARMv7_OP_4(func, type) { func, 4, type, #func "_" #type } +#define ARMv7_NULL_OP { NULL_OP, 2, T1, "NULL_OP" } + + +// 0x1... +static void group_0x1(ARMv7Thread* thr, const ARMv7_encoding type); + +static const ARMv7_Instruction g_table_0x1_main[] = +{ + ARMv7_OP_2(ASR_IMM, T1), // 0 0xf800 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_OP_2(ADD_REG, T1), // 8 0xfe00 + ARMv7_NULL_OP, // 9 + ARMv7_OP_2(SUB_REG, T1), // A 0xfe00 + ARMv7_NULL_OP, // B + ARMv7_OP_2(ADD_IMM, T1), // C 0xfe00 + ARMv7_NULL_OP, // D + ARMv7_OP_2(SUB_IMM, T1) // E 0xfe00 +}; + +static const ARMv7_Instruction g_table_0x1[] = +{ + { group_0x1 } +}; + +static void group_0x1(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = (thr->code.code0 & 0x0e00) >> 8; + + if ((thr->code.code0 & 0xf800) == 0x1000) index = 0x0; + + thr->m_last_instr_name = g_table_0x1_main[index].name; + thr->m_last_instr_size = g_table_0x1_main[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0x1_main[index].func(thr, g_table_0x1_main[index].type); } -enum ARMv7_encoding +// 0x2... +static void group_0x2(ARMv7Thread* thr, const ARMv7_encoding type); + +static const ARMv7_Instruction g_table_0x2_main[] = { - T1, - T2, - T3, - T4, - A1, - A2, + ARMv7_OP_2(MOV_IMM, T1), // 0 0xf800 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_OP_2(CMP_IMM, T1) // 8 0xf800 }; -class ARMv7Opcodes +static const ARMv7_Instruction g_table_0x2[] = { -public: - virtual void UNK(const u32 data) = 0; - - virtual void NULL_OP(const u32 data, const ARMv7_encoding type) = 0; - - virtual void HACK(const u32 data, const ARMv7_encoding type) = 0; - - virtual void ADC_IMM(const u32 data, const ARMv7_encoding type) = 0; - virtual void ADC_REG(const u32 data, const ARMv7_encoding type) = 0; - virtual void ADC_RSR(const u32 data, const ARMv7_encoding type) = 0; - - virtual void ADD_IMM(const u32 data, const ARMv7_encoding type) = 0; - virtual void ADD_REG(const u32 data, const ARMv7_encoding type) = 0; - virtual void ADD_RSR(const u32 data, const ARMv7_encoding type) = 0; - virtual void ADD_SPI(const u32 data, const ARMv7_encoding type) = 0; - virtual void ADD_SPR(const u32 data, const ARMv7_encoding type) = 0; - - virtual void ADR(const u32 data, const ARMv7_encoding type) = 0; - - virtual void AND_IMM(const u32 data, const ARMv7_encoding type) = 0; - virtual void AND_REG(const u32 data, const ARMv7_encoding type) = 0; - virtual void AND_RSR(const u32 data, const ARMv7_encoding type) = 0; - - virtual void ASR_IMM(const u32 data, const ARMv7_encoding type) = 0; - virtual void ASR_REG(const u32 data, const ARMv7_encoding type) = 0; - - virtual void B(const u32 data, const ARMv7_encoding type) = 0; - - virtual void BFC(const u32 data, const ARMv7_encoding type) = 0; - virtual void BFI(const u32 data, const ARMv7_encoding type) = 0; - - virtual void BIC_IMM(const u32 data, const ARMv7_encoding type) = 0; - virtual void BIC_REG(const u32 data, const ARMv7_encoding type) = 0; - virtual void BIC_RSR(const u32 data, const ARMv7_encoding type) = 0; - - virtual void BKPT(const u32 data, const ARMv7_encoding type) = 0; - - virtual void BL(const u32 data, const ARMv7_encoding type) = 0; - virtual void BLX(const u32 data, const ARMv7_encoding type) = 0; - virtual void BX(const u32 data, const ARMv7_encoding type) = 0; - - virtual void CB_Z(const u32 data, const ARMv7_encoding type) = 0; - - virtual void CLZ(const u32 data, const ARMv7_encoding type) = 0; - - virtual void CMN_IMM(const u32 data, const ARMv7_encoding type) = 0; - virtual void CMN_REG(const u32 data, const ARMv7_encoding type) = 0; - virtual void CMN_RSR(const u32 data, const ARMv7_encoding type) = 0; - - virtual void CMP_IMM(const u32 data, const ARMv7_encoding type) = 0; - virtual void CMP_REG(const u32 data, const ARMv7_encoding type) = 0; - virtual void CMP_RSR(const u32 data, const ARMv7_encoding type) = 0; - - virtual void EOR_IMM(const u32 data, const ARMv7_encoding type) = 0; - virtual void EOR_REG(const u32 data, const ARMv7_encoding type) = 0; - virtual void EOR_RSR(const u32 data, const ARMv7_encoding type) = 0; - - virtual void IT(const u32 data, const ARMv7_encoding type) = 0; - - virtual void LDM(const u32 data, const ARMv7_encoding type) = 0; - virtual void LDMDA(const u32 data, const ARMv7_encoding type) = 0; - virtual void LDMDB(const u32 data, const ARMv7_encoding type) = 0; - virtual void LDMIB(const u32 data, const ARMv7_encoding type) = 0; - - virtual void LDR_IMM(const u32 data, const ARMv7_encoding type) = 0; - virtual void LDR_LIT(const u32 data, const ARMv7_encoding type) = 0; - virtual void LDR_REG(const u32 data, const ARMv7_encoding type) = 0; - - virtual void LDRB_IMM(const u32 data, const ARMv7_encoding type) = 0; - virtual void LDRB_LIT(const u32 data, const ARMv7_encoding type) = 0; - virtual void LDRB_REG(const u32 data, const ARMv7_encoding type) = 0; - - virtual void LDRD_IMM(const u32 data, const ARMv7_encoding type) = 0; - virtual void LDRD_LIT(const u32 data, const ARMv7_encoding type) = 0; - virtual void LDRD_REG(const u32 data, const ARMv7_encoding type) = 0; - - virtual void LDRH_IMM(const u32 data, const ARMv7_encoding type) = 0; - virtual void LDRH_LIT(const u32 data, const ARMv7_encoding type) = 0; - virtual void LDRH_REG(const u32 data, const ARMv7_encoding type) = 0; - - virtual void LDRSB_IMM(const u32 data, const ARMv7_encoding type) = 0; - virtual void LDRSB_LIT(const u32 data, const ARMv7_encoding type) = 0; - virtual void LDRSB_REG(const u32 data, const ARMv7_encoding type) = 0; - - virtual void LDRSH_IMM(const u32 data, const ARMv7_encoding type) = 0; - virtual void LDRSH_LIT(const u32 data, const ARMv7_encoding type) = 0; - virtual void LDRSH_REG(const u32 data, const ARMv7_encoding type) = 0; - - virtual void LSL_IMM(const u32 data, const ARMv7_encoding type) = 0; - virtual void LSL_REG(const u32 data, const ARMv7_encoding type) = 0; - - virtual void LSR_IMM(const u32 data, const ARMv7_encoding type) = 0; - virtual void LSR_REG(const u32 data, const ARMv7_encoding type) = 0; - - virtual void MLA(const u32 data, const ARMv7_encoding type) = 0; - virtual void MLS(const u32 data, const ARMv7_encoding type) = 0; - - virtual void MOV_IMM(const u32 data, const ARMv7_encoding type) = 0; - virtual void MOV_REG(const u32 data, const ARMv7_encoding type) = 0; - virtual void MOVT(const u32 data, const ARMv7_encoding type) = 0; - - virtual void MRS(const u32 data, const ARMv7_encoding type) = 0; - virtual void MSR_IMM(const u32 data, const ARMv7_encoding type) = 0; - virtual void MSR_REG(const u32 data, const ARMv7_encoding type) = 0; - - virtual void MUL(const u32 data, const ARMv7_encoding type) = 0; - - virtual void MVN_IMM(const u32 data, const ARMv7_encoding type) = 0; - virtual void MVN_REG(const u32 data, const ARMv7_encoding type) = 0; - virtual void MVN_RSR(const u32 data, const ARMv7_encoding type) = 0; - - virtual void NOP(const u32 data, const ARMv7_encoding type) = 0; - - virtual void ORN_IMM(const u32 data, const ARMv7_encoding type) = 0; - virtual void ORN_REG(const u32 data, const ARMv7_encoding type) = 0; - - virtual void ORR_IMM(const u32 data, const ARMv7_encoding type) = 0; - virtual void ORR_REG(const u32 data, const ARMv7_encoding type) = 0; - virtual void ORR_RSR(const u32 data, const ARMv7_encoding type) = 0; - - virtual void PKH(const u32 data, const ARMv7_encoding type) = 0; - - virtual void POP(const u32 data, const ARMv7_encoding type) = 0; - virtual void PUSH(const u32 data, const ARMv7_encoding type) = 0; - - virtual void QADD(const u32 data, const ARMv7_encoding type) = 0; - virtual void QADD16(const u32 data, const ARMv7_encoding type) = 0; - virtual void QADD8(const u32 data, const ARMv7_encoding type) = 0; - virtual void QASX(const u32 data, const ARMv7_encoding type) = 0; - virtual void QDADD(const u32 data, const ARMv7_encoding type) = 0; - virtual void QDSUB(const u32 data, const ARMv7_encoding type) = 0; - virtual void QSAX(const u32 data, const ARMv7_encoding type) = 0; - virtual void QSUB(const u32 data, const ARMv7_encoding type) = 0; - virtual void QSUB16(const u32 data, const ARMv7_encoding type) = 0; - virtual void QSUB8(const u32 data, const ARMv7_encoding type) = 0; - - virtual void RBIT(const u32 data, const ARMv7_encoding type) = 0; - virtual void REV(const u32 data, const ARMv7_encoding type) = 0; - virtual void REV16(const u32 data, const ARMv7_encoding type) = 0; - virtual void REVSH(const u32 data, const ARMv7_encoding type) = 0; - - virtual void ROR_IMM(const u32 data, const ARMv7_encoding type) = 0; - virtual void ROR_REG(const u32 data, const ARMv7_encoding type) = 0; - - virtual void RRX(const u32 data, const ARMv7_encoding type) = 0; - - virtual void RSB_IMM(const u32 data, const ARMv7_encoding type) = 0; - virtual void RSB_REG(const u32 data, const ARMv7_encoding type) = 0; - virtual void RSB_RSR(const u32 data, const ARMv7_encoding type) = 0; - - virtual void RSC_IMM(const u32 data, const ARMv7_encoding type) = 0; - virtual void RSC_REG(const u32 data, const ARMv7_encoding type) = 0; - virtual void RSC_RSR(const u32 data, const ARMv7_encoding type) = 0; - - virtual void SADD16(const u32 data, const ARMv7_encoding type) = 0; - virtual void SADD8(const u32 data, const ARMv7_encoding type) = 0; - virtual void SASX(const u32 data, const ARMv7_encoding type) = 0; - - virtual void SBC_IMM(const u32 data, const ARMv7_encoding type) = 0; - virtual void SBC_REG(const u32 data, const ARMv7_encoding type) = 0; - virtual void SBC_RSR(const u32 data, const ARMv7_encoding type) = 0; - - virtual void SBFX(const u32 data, const ARMv7_encoding type) = 0; - - virtual void SDIV(const u32 data, const ARMv7_encoding type) = 0; - - virtual void SEL(const u32 data, const ARMv7_encoding type) = 0; - - virtual void SHADD16(const u32 data, const ARMv7_encoding type) = 0; - virtual void SHADD8(const u32 data, const ARMv7_encoding type) = 0; - virtual void SHASX(const u32 data, const ARMv7_encoding type) = 0; - virtual void SHSAX(const u32 data, const ARMv7_encoding type) = 0; - virtual void SHSUB16(const u32 data, const ARMv7_encoding type) = 0; - virtual void SHSUB8(const u32 data, const ARMv7_encoding type) = 0; - - virtual void SMLA__(const u32 data, const ARMv7_encoding type) = 0; - virtual void SMLAD(const u32 data, const ARMv7_encoding type) = 0; - virtual void SMLAL(const u32 data, const ARMv7_encoding type) = 0; - virtual void SMLAL__(const u32 data, const ARMv7_encoding type) = 0; - virtual void SMLALD(const u32 data, const ARMv7_encoding type) = 0; - virtual void SMLAW_(const u32 data, const ARMv7_encoding type) = 0; - virtual void SMLSD(const u32 data, const ARMv7_encoding type) = 0; - virtual void SMLSLD(const u32 data, const ARMv7_encoding type) = 0; - virtual void SMMLA(const u32 data, const ARMv7_encoding type) = 0; - virtual void SMMLS(const u32 data, const ARMv7_encoding type) = 0; - virtual void SMMUL(const u32 data, const ARMv7_encoding type) = 0; - virtual void SMUAD(const u32 data, const ARMv7_encoding type) = 0; - virtual void SMUL__(const u32 data, const ARMv7_encoding type) = 0; - virtual void SMULL(const u32 data, const ARMv7_encoding type) = 0; - virtual void SMULW_(const u32 data, const ARMv7_encoding type) = 0; - virtual void SMUSD(const u32 data, const ARMv7_encoding type) = 0; - - virtual void SSAT(const u32 data, const ARMv7_encoding type) = 0; - virtual void SSAT16(const u32 data, const ARMv7_encoding type) = 0; - virtual void SSAX(const u32 data, const ARMv7_encoding type) = 0; - virtual void SSUB16(const u32 data, const ARMv7_encoding type) = 0; - virtual void SSUB8(const u32 data, const ARMv7_encoding type) = 0; - - virtual void STM(const u32 data, const ARMv7_encoding type) = 0; - virtual void STMDA(const u32 data, const ARMv7_encoding type) = 0; - virtual void STMDB(const u32 data, const ARMv7_encoding type) = 0; - virtual void STMIB(const u32 data, const ARMv7_encoding type) = 0; - - virtual void STR_IMM(const u32 data, const ARMv7_encoding type) = 0; - virtual void STR_REG(const u32 data, const ARMv7_encoding type) = 0; - - virtual void STRB_IMM(const u32 data, const ARMv7_encoding type) = 0; - virtual void STRB_REG(const u32 data, const ARMv7_encoding type) = 0; - - virtual void STRD_IMM(const u32 data, const ARMv7_encoding type) = 0; - virtual void STRD_REG(const u32 data, const ARMv7_encoding type) = 0; - - virtual void STRH_IMM(const u32 data, const ARMv7_encoding type) = 0; - virtual void STRH_REG(const u32 data, const ARMv7_encoding type) = 0; - - virtual void SUB_IMM(const u32 data, const ARMv7_encoding type) = 0; - virtual void SUB_REG(const u32 data, const ARMv7_encoding type) = 0; - virtual void SUB_RSR(const u32 data, const ARMv7_encoding type) = 0; - virtual void SUB_SPI(const u32 data, const ARMv7_encoding type) = 0; - virtual void SUB_SPR(const u32 data, const ARMv7_encoding type) = 0; - - virtual void SVC(const u32 data, const ARMv7_encoding type) = 0; - - virtual void SXTAB(const u32 data, const ARMv7_encoding type) = 0; - virtual void SXTAB16(const u32 data, const ARMv7_encoding type) = 0; - virtual void SXTAH(const u32 data, const ARMv7_encoding type) = 0; - virtual void SXTB(const u32 data, const ARMv7_encoding type) = 0; - virtual void SXTB16(const u32 data, const ARMv7_encoding type) = 0; - virtual void SXTH(const u32 data, const ARMv7_encoding type) = 0; - - virtual void TB_(const u32 data, const ARMv7_encoding type) = 0; - - virtual void TEQ_IMM(const u32 data, const ARMv7_encoding type) = 0; - virtual void TEQ_REG(const u32 data, const ARMv7_encoding type) = 0; - virtual void TEQ_RSR(const u32 data, const ARMv7_encoding type) = 0; - - virtual void TST_IMM(const u32 data, const ARMv7_encoding type) = 0; - virtual void TST_REG(const u32 data, const ARMv7_encoding type) = 0; - virtual void TST_RSR(const u32 data, const ARMv7_encoding type) = 0; - - virtual void UADD16(const u32 data, const ARMv7_encoding type) = 0; - virtual void UADD8(const u32 data, const ARMv7_encoding type) = 0; - virtual void UASX(const u32 data, const ARMv7_encoding type) = 0; - virtual void UBFX(const u32 data, const ARMv7_encoding type) = 0; - virtual void UDIV(const u32 data, const ARMv7_encoding type) = 0; - virtual void UHADD16(const u32 data, const ARMv7_encoding type) = 0; - virtual void UHADD8(const u32 data, const ARMv7_encoding type) = 0; - virtual void UHASX(const u32 data, const ARMv7_encoding type) = 0; - virtual void UHSAX(const u32 data, const ARMv7_encoding type) = 0; - virtual void UHSUB16(const u32 data, const ARMv7_encoding type) = 0; - virtual void UHSUB8(const u32 data, const ARMv7_encoding type) = 0; - virtual void UMAAL(const u32 data, const ARMv7_encoding type) = 0; - virtual void UMLAL(const u32 data, const ARMv7_encoding type) = 0; - virtual void UMULL(const u32 data, const ARMv7_encoding type) = 0; - virtual void UQADD16(const u32 data, const ARMv7_encoding type) = 0; - virtual void UQADD8(const u32 data, const ARMv7_encoding type) = 0; - virtual void UQASX(const u32 data, const ARMv7_encoding type) = 0; - virtual void UQSAX(const u32 data, const ARMv7_encoding type) = 0; - virtual void UQSUB16(const u32 data, const ARMv7_encoding type) = 0; - virtual void UQSUB8(const u32 data, const ARMv7_encoding type) = 0; - virtual void USAD8(const u32 data, const ARMv7_encoding type) = 0; - virtual void USADA8(const u32 data, const ARMv7_encoding type) = 0; - virtual void USAT(const u32 data, const ARMv7_encoding type) = 0; - virtual void USAT16(const u32 data, const ARMv7_encoding type) = 0; - virtual void USAX(const u32 data, const ARMv7_encoding type) = 0; - virtual void USUB16(const u32 data, const ARMv7_encoding type) = 0; - virtual void USUB8(const u32 data, const ARMv7_encoding type) = 0; - virtual void UXTAB(const u32 data, const ARMv7_encoding type) = 0; - virtual void UXTAB16(const u32 data, const ARMv7_encoding type) = 0; - virtual void UXTAH(const u32 data, const ARMv7_encoding type) = 0; - virtual void UXTB(const u32 data, const ARMv7_encoding type) = 0; - virtual void UXTB16(const u32 data, const ARMv7_encoding type) = 0; - virtual void UXTH(const u32 data, const ARMv7_encoding type) = 0; - - // TODO: vector ops + something + { group_0x2 } }; -struct ARMv7_opcode_t +static void group_0x2(ARMv7Thread* thr, const ARMv7_encoding type) { - u32 mask; - u32 code; - u32 length; // 2 or 4 - const char* name; - ARMv7_encoding type; - void (ARMv7Opcodes::*func)(const u32 data, const ARMv7_encoding type); + const u32 index = (thr->code.code0 & 0x0800) >> 8; + thr->m_last_instr_name = g_table_0x2_main[index].name; + thr->m_last_instr_size = g_table_0x2_main[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0x2_main[index].func(thr, g_table_0x2_main[index].type); +} + +// 0x3... +static void group_0x3(ARMv7Thread* thr, const ARMv7_encoding type); + +static const ARMv7_Instruction g_table_0x3_main[] = +{ + ARMv7_OP_2(ADD_IMM, T2), // 0 0xf800 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_OP_2(SUB_IMM, T2) // 8 0xf800 }; -// single 16-bit value -#define ARMv7_OP2(mask, code, type, name) { (u32)((mask) << 16), (u32)((code) << 16), 2, #name "_" #type, type, &ARMv7Opcodes::name } -// two 16-bit values -#define ARMv7_OP4(mask0, mask1, code0, code1, type, name) { (u32)((mask0) << 16) | (mask1), (u32)((code0) << 16) | (code1), 4, #name "_" #type, type, &ARMv7Opcodes::name } - -static const ARMv7_opcode_t ARMv7_opcode_table[] = +static const ARMv7_Instruction g_table_0x3[] = { - ARMv7_OP2(0xffff, 0x0000, T1, NULL_OP), // ??? - - ARMv7_OP4(0xffff, 0x0000, 0xf870, 0x0000, T1, HACK), // "Undefined" Thumb opcode - ARMv7_OP4(0x0ff0, 0x00f0, 0x0070, 0x0090, A1, HACK), // "Undefined" ARM opcode - - ARMv7_OP4(0xfbe0, 0x8000, 0xf140, 0x0000, T1, ADC_IMM), - ARMv7_OP4(0x0fe0, 0x0000, 0x02a0, 0x0000, A1, ADC_IMM), - ARMv7_OP2(0xffc0, 0x4040, T1, ADC_REG), - ARMv7_OP4(0xffe0, 0x8000, 0xeb40, 0x0000, T2, ADC_REG), - ARMv7_OP4(0x0fe0, 0x0010, 0x00a0, 0x0000, A1, ADC_REG), - ARMv7_OP4(0x0fe0, 0x0090, 0x00a0, 0x0010, A1, ADC_RSR), - - ARMv7_OP2(0xf800, 0xa800, T1, ADD_SPI), - ARMv7_OP2(0xff80, 0xb000, T2, ADD_SPI), - ARMv7_OP4(0xfbef, 0x8000, 0xf10d, 0x0000, T3, ADD_SPI), - ARMv7_OP4(0xfbff, 0x8000, 0xf20d, 0x0000, T4, ADD_SPI), - ARMv7_OP4(0x0fef, 0x0000, 0x028d, 0x0000, A1, ADD_SPI), - ARMv7_OP2(0xff78, 0x4468, T1, ADD_SPR), - ARMv7_OP2(0xff87, 0x4485, T2, ADD_SPR), - ARMv7_OP4(0xffef, 0x8000, 0xeb0d, 0x0000, T3, ADD_SPR), - ARMv7_OP4(0x0fef, 0x0010, 0x008d, 0x0000, A1, ADD_SPR), - ARMv7_OP2(0xfe00, 0x1c00, T1, ADD_IMM), - ARMv7_OP2(0xf800, 0x3000, T2, ADD_IMM), - ARMv7_OP4(0xfbe0, 0x8000, 0xf100, 0x0000, T3, ADD_IMM), - ARMv7_OP4(0xfbf0, 0x8000, 0xf200, 0x0000, T4, ADD_IMM), - ARMv7_OP4(0x0fe0, 0x0000, 0x0280, 0x0000, A1, ADD_IMM), - ARMv7_OP2(0xfe00, 0x1800, T1, ADD_REG), - ARMv7_OP2(0xff00, 0x4400, T2, ADD_REG), - ARMv7_OP4(0xffe0, 0x8000, 0xeb00, 0x0000, T3, ADD_REG), - ARMv7_OP4(0x0fe0, 0x0010, 0x0080, 0x0000, A1, ADD_REG), - ARMv7_OP4(0x0fe0, 0x0090, 0x0080, 0x0010, A1, ADD_RSR), - - ARMv7_OP2(0xf800, 0xa000, T1, ADR), - ARMv7_OP4(0xfbff, 0x8000, 0xf2af, 0x0000, T2, ADR), - ARMv7_OP4(0xfbff, 0x8000, 0xf20f, 0x0000, T3, ADR), - ARMv7_OP4(0x0fff, 0x0000, 0x028f, 0x0000, A1, ADR), - ARMv7_OP4(0x0fff, 0x0000, 0x024f, 0x0000, A2, ADR), - - ARMv7_OP4(0xfbe0, 0x8000, 0xf000, 0x0000, T1, AND_IMM), - ARMv7_OP4(0x0fe0, 0x0000, 0x0200, 0x0000, A1, AND_IMM), - ARMv7_OP2(0xffc0, 0x4000, T1, AND_REG), - ARMv7_OP4(0xffe0, 0x8000, 0xea00, 0x0000, T2, AND_REG), - ARMv7_OP4(0x0fe0, 0x0010, 0x0000, 0x0000, A1, AND_REG), - ARMv7_OP4(0x0fe0, 0x0090, 0x0000, 0x0010, A1, AND_RSR), - - ARMv7_OP2(0xf800, 0x1000, T1, ASR_IMM), - ARMv7_OP4(0xffef, 0x8030, 0xea4f, 0x0020, T2, ASR_IMM), - ARMv7_OP4(0x0fef, 0x0070, 0x01a0, 0x0040, A1, ASR_IMM), - ARMv7_OP2(0xffc0, 0x4100, T1, ASR_REG), - ARMv7_OP4(0xffe0, 0xf0f0, 0xfa40, 0xf000, T2, ASR_REG), - ARMv7_OP4(0x0fef, 0x00f0, 0x01a0, 0x0050, A1, ASR_REG), - - ARMv7_OP2(0xf000, 0xd000, T1, B), - ARMv7_OP2(0xf800, 0xe000, T2, B), - ARMv7_OP4(0xf800, 0xd000, 0xf000, 0x8000, T3, B), - ARMv7_OP4(0xf800, 0xd000, 0xf000, 0x9000, T4, B), - ARMv7_OP4(0x0f00, 0x0000, 0x0a00, 0x0000, A1, B), - - ARMv7_OP4(0xffff, 0x8020, 0xf36f, 0x0000, T1, BFC), - ARMv7_OP4(0x0fe0, 0x007f, 0x07c0, 0x001f, A1, BFC), - ARMv7_OP4(0xfff0, 0x8020, 0xf360, 0x0000, T1, BFI), - ARMv7_OP4(0x0fe0, 0x0070, 0x07c0, 0x0010, A1, BFI), - - ARMv7_OP4(0xfbe0, 0x8000, 0xf020, 0x0000, T1, BIC_IMM), - ARMv7_OP4(0x0fe0, 0x0000, 0x03c0, 0x0000, A1, BIC_IMM), - ARMv7_OP2(0xffc0, 0x4380, T1, BIC_REG), - ARMv7_OP4(0xffe0, 0x8000, 0xea20, 0x0000, T2, BIC_REG), - ARMv7_OP4(0x0fe0, 0x0010, 0x01c0, 0x0000, A1, BIC_REG), - ARMv7_OP4(0x0fe0, 0x0090, 0x01c0, 0x0010, A1, BIC_RSR), - - ARMv7_OP2(0xff00, 0xbe00, T1, BKPT), - ARMv7_OP4(0x0ff0, 0x00f0, 0x0120, 0x0070, A1, BKPT), - - ARMv7_OP4(0xf800, 0xd000, 0xf000, 0xd000, T1, BL), - ARMv7_OP4(0x0f00, 0x0000, 0x0b00, 0x0000, A1, BL), - ARMv7_OP2(0xff80, 0x4780, T1, BLX), - ARMv7_OP4(0xf800, 0xc001, 0xf000, 0xc000, T2, BLX), - ARMv7_OP4(0x0fff, 0xfff0, 0x012f, 0xff30, A1, BLX), - ARMv7_OP4(0xfe00, 0x0000, 0xfa00, 0x0000, A2, BLX), - - ARMv7_OP2(0xff87, 0x4700, T1, BX), - ARMv7_OP4(0x0fff, 0xfff0, 0x012f, 0xff10, A1, BX), - - ARMv7_OP2(0xf500, 0xb100, T1, CB_Z), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfab0, 0xf080, T1, CLZ), - ARMv7_OP4(0x0fff, 0x0ff0, 0x016f, 0x0f10, A1, CLZ), - - ARMv7_OP4(0xfbf0, 0x8f00, 0xf110, 0x0f00, T1, CMN_IMM), - ARMv7_OP4(0x0ff0, 0xf000, 0x0370, 0x0000, A1, CMN_IMM), - ARMv7_OP2(0xffc0, 0x42c0, T1, CMN_REG), - ARMv7_OP4(0xfff0, 0x8f00, 0xeb10, 0x0f00, T2, CMN_REG), - ARMv7_OP4(0x0ff0, 0xf010, 0x0170, 0x0000, A1, CMN_REG), - ARMv7_OP4(0x0ff0, 0xf090, 0x0170, 0x0010, A1, CMN_RSR), - - ARMv7_OP2(0xf800, 0x2800, T1, CMP_IMM), - ARMv7_OP4(0xfbf0, 0x8f00, 0xf1b0, 0x0f00, T2, CMP_IMM), - ARMv7_OP4(0x0ff0, 0xf000, 0x0350, 0x0000, A1, CMP_IMM), - ARMv7_OP2(0xffc0, 0x4280, T1, CMP_REG), - ARMv7_OP2(0xff00, 0x4500, T2, CMP_REG), - ARMv7_OP4(0xfff0, 0x8f00, 0xebb0, 0x0f00, T3, CMP_REG), - ARMv7_OP4(0x0ff0, 0xf010, 0x0150, 0x0000, A1, CMP_REG), - ARMv7_OP4(0x0ff0, 0xf090, 0x0150, 0x0010, A1, CMP_RSR), - - ARMv7_OP4(0xfbe0, 0x8000, 0xf080, 0x0000, T1, EOR_IMM), - ARMv7_OP4(0x0fe0, 0x0000, 0x0220, 0x0000, A1, EOR_IMM), - ARMv7_OP2(0xffc0, 0x4040, T1, EOR_REG), - ARMv7_OP4(0xffe0, 0x8000, 0xea80, 0x0000, T2, EOR_REG), - ARMv7_OP4(0x0fe0, 0x0010, 0x0020, 0x0000, A1, EOR_REG), - ARMv7_OP4(0x0fe0, 0x0090, 0x0020, 0x0010, A1, EOR_RSR), - - ARMv7_OP2(0xff00, 0xbf00, T1, IT), - - ARMv7_OP2(0xf800, 0xc800, T1, LDM), - ARMv7_OP4(0xffd0, 0x2000, 0xe890, 0x0000, T2, LDM), - ARMv7_OP4(0x0fd0, 0x0000, 0x0890, 0x0000, A1, LDM), - ARMv7_OP4(0x0fd0, 0x0000, 0x0810, 0x0000, A1, LDMDA), - ARMv7_OP4(0xffd0, 0x2000, 0xe910, 0x0000, T1, LDMDB), - ARMv7_OP4(0x0fd0, 0x0000, 0x0910, 0x0000, A1, LDMDB), - ARMv7_OP4(0x0fd0, 0x0000, 0x0990, 0x0000, A1, LDMIB), - - ARMv7_OP2(0xf800, 0x6800, T1, LDR_IMM), - ARMv7_OP2(0xf800, 0x9800, T2, LDR_IMM), - ARMv7_OP4(0xfff0, 0x0000, 0xf8d0, 0x0000, T3, LDR_IMM), - ARMv7_OP4(0xfff0, 0x0800, 0xf850, 0x0800, T4, LDR_IMM), - ARMv7_OP4(0x0e50, 0x0000, 0x0410, 0x0000, A1, LDR_IMM), - ARMv7_OP2(0xf800, 0x4800, T1, LDR_LIT), - ARMv7_OP4(0xff7f, 0x0000, 0xf85f, 0x0000, T2, LDR_LIT), - ARMv7_OP4(0x0f7f, 0x0000, 0x051f, 0x0000, A1, LDR_LIT), - ARMv7_OP2(0xfe00, 0x5800, T1, LDR_REG), - ARMv7_OP4(0xfff0, 0x0fc0, 0xf850, 0x0000, T2, LDR_REG), - ARMv7_OP4(0x0e50, 0x0010, 0x0610, 0x0000, A1, LDR_REG), - - ARMv7_OP2(0xf800, 0x7800, T1, LDRB_IMM), - ARMv7_OP4(0xfff0, 0x0000, 0xf890, 0x0000, T2, LDRB_IMM), - ARMv7_OP4(0xfff0, 0x0800, 0xf810, 0x0800, T3, LDRB_IMM), - ARMv7_OP4(0x0e50, 0x0000, 0x0450, 0x0000, A1, LDRB_IMM), - ARMv7_OP4(0xff7f, 0x0000, 0xf81f, 0x0000, T1, LDRB_LIT), - ARMv7_OP4(0x0f7f, 0x0000, 0x055f, 0x0000, A1, LDRB_LIT), - ARMv7_OP2(0xfe00, 0x5c00, T1, LDRB_REG), - ARMv7_OP4(0xfff0, 0x0fc0, 0xf810, 0x0000, T2, LDRB_REG), - ARMv7_OP4(0x0e50, 0x0010, 0x0650, 0x0000, A1, LDRB_REG), - - ARMv7_OP4(0xfe50, 0x0000, 0xe850, 0x0000, T1, LDRD_IMM), - ARMv7_OP4(0x0e50, 0x00f0, 0x0040, 0x00d0, A1, LDRD_IMM), - ARMv7_OP4(0xfe7f, 0x0000, 0xe85f, 0x0000, T1, LDRD_LIT), - ARMv7_OP4(0x0f7f, 0x00f0, 0x014f, 0x00d0, A1, LDRD_LIT), - ARMv7_OP4(0x0e50, 0x0ff0, 0x0000, 0x00d0, A1, LDRD_REG), - - ARMv7_OP4(0xfff0, 0x0000, 0xf990, 0x0000, T1, LDRSB_IMM), - ARMv7_OP4(0xfff0, 0x0800, 0xf910, 0x0800, T2, LDRSB_IMM), - ARMv7_OP4(0x0e50, 0x00f0, 0x0050, 0x00d0, A1, LDRSB_IMM), - ARMv7_OP4(0xff7f, 0x0000, 0xf91f, 0x0000, T1, LDRSB_LIT), - ARMv7_OP4(0x0f7f, 0x00f0, 0x015f, 0x00d0, A1, LDRSB_LIT), - ARMv7_OP2(0xfe00, 0x5600, T1, LDRSB_REG), - ARMv7_OP4(0xfff0, 0x0fc0, 0xf910, 0x0000, T2, LDRSB_REG), - ARMv7_OP4(0x0e50, 0x0ff0, 0x0010, 0x00d0, A1, LDRSB_REG), - - ARMv7_OP4(0xfff0, 0x0000, 0xf9b0, 0x0000, T1, LDRSH_IMM), - ARMv7_OP4(0xfff0, 0x0800, 0xf930, 0x0800, T2, LDRSH_IMM), - ARMv7_OP4(0x0e50, 0x00f0, 0x0050, 0x00f0, A1, LDRSH_IMM), - ARMv7_OP4(0xff7f, 0x0000, 0xf93f, 0x0000, T1, LDRSH_LIT), - ARMv7_OP4(0x0f7f, 0x00f0, 0x015f, 0x00f0, A1, LDRSH_LIT), - ARMv7_OP2(0xfe00, 0x5e00, T1, LDRSH_REG), - ARMv7_OP4(0xfff0, 0x0fc0, 0xf930, 0x0000, T2, LDRSH_REG), - ARMv7_OP4(0x0e50, 0x0ff0, 0x0010, 0x00f0, A1, LDRSH_REG), - - ARMv7_OP2(0xf800, 0x0000, T1, LSL_IMM), - ARMv7_OP4(0xffef, 0x8030, 0xea4f, 0x0000, T2, LSL_IMM), - ARMv7_OP4(0x0fef, 0x0070, 0x01a0, 0x0000, A1, LSL_IMM), - ARMv7_OP2(0xffc0, 0x4080, T1, LSL_REG), - ARMv7_OP4(0xffe0, 0xf0f0, 0xfa00, 0xf000, T2, LSL_REG), - ARMv7_OP4(0x0fef, 0x00f0, 0x01a0, 0x0010, A1, LSL_REG), - - ARMv7_OP2(0xf800, 0x0800, T1, LSR_IMM), - ARMv7_OP4(0xffef, 0x8030, 0xea4f, 0x0010, T2, LSR_IMM), - ARMv7_OP4(0x0fef, 0x0030, 0x01a0, 0x0020, A1, LSR_IMM), - ARMv7_OP2(0xffc0, 0x40c0, T1, LSR_REG), - ARMv7_OP4(0xffe0, 0xf0f0, 0xfa20, 0xf000, T2, LSR_REG), - ARMv7_OP4(0x0fef, 0x00f0, 0x01a0, 0x0030, A1, LSR_REG), - - ARMv7_OP4(0xfff0, 0x00f0, 0xfb00, 0x0000, T1, MLA), - ARMv7_OP4(0x0fe0, 0x00f0, 0x0020, 0x0090, A1, MLA), - - ARMv7_OP4(0xfff0, 0x00f0, 0xfb00, 0x0010, T1, MLS), - ARMv7_OP4(0x0ff0, 0x00f0, 0x0060, 0x0090, A1, MLS), - - ARMv7_OP2(0xf800, 0x2000, T1, MOV_IMM), - ARMv7_OP4(0xfbef, 0x8000, 0xf04f, 0x0000, T2, MOV_IMM), - ARMv7_OP4(0xfbf0, 0x8000, 0xf240, 0x0000, T3, MOV_IMM), - ARMv7_OP4(0x0fef, 0x0000, 0x03a0, 0x0000, A1, MOV_IMM), - ARMv7_OP4(0x0ff0, 0x0000, 0x0300, 0x0000, A2, MOV_IMM), - ARMv7_OP2(0xff00, 0x4600, T1, MOV_REG), - ARMv7_OP2(0xffc0, 0x0000, T2, MOV_REG), - ARMv7_OP4(0xffef, 0xf0f0, 0xea4f, 0x0000, T3, MOV_REG), - ARMv7_OP4(0x0fef, 0x0ff0, 0x01a0, 0x0000, A1, MOV_REG), - ARMv7_OP4(0xfbf0, 0x8000, 0xf2c0, 0x0000, T1, MOVT), - ARMv7_OP4(0x0ff0, 0x0000, 0x0340, 0x0000, A1, MOVT), - - ARMv7_OP4(0xffff, 0xf0ff, 0xf3ef, 0x8000, T1, MRS), - ARMv7_OP4(0x0fff, 0x0fff, 0x010f, 0x0000, A1, MRS), - ARMv7_OP4(0x0ff3, 0xf000, 0x0320, 0xf000, A1, MSR_IMM), - ARMv7_OP4(0xfff0, 0xf3ff, 0xf380, 0x8000, T1, MSR_REG), - ARMv7_OP4(0x0ff3, 0xfff0, 0x0120, 0xf000, A1, MSR_REG), - - ARMv7_OP2(0xffc0, 0x4340, T1, MUL), - ARMv7_OP4(0xfff0, 0xf0f0, 0xfb00, 0xf000, T2, MUL), - ARMv7_OP4(0x0fe0, 0xf0f0, 0x0000, 0x0090, A1, MUL), - - ARMv7_OP4(0xfbef, 0x8000, 0xf06f, 0x0000, T1, MVN_IMM), - ARMv7_OP4(0x0fef, 0x0000, 0x03e0, 0x0000, A1, MVN_IMM), - ARMv7_OP2(0xffc0, 0x43c0, T1, MVN_REG), - ARMv7_OP4(0xffef, 0x8000, 0xea6f, 0x0000, T2, MVN_REG), - ARMv7_OP4(0xffef, 0x0010, 0x01e0, 0x0000, A1, MVN_REG), - ARMv7_OP4(0x0fef, 0x0090, 0x01e0, 0x0010, A1, MVN_RSR), - - ARMv7_OP2(0xffff, 0xbf00, T1, NOP), - ARMv7_OP4(0xffff, 0xffff, 0xf3af, 0x8000, T2, NOP), - ARMv7_OP4(0x0fff, 0xffff, 0x0320, 0xf000, A1, NOP), - - ARMv7_OP4(0xfbe0, 0x8000, 0xf060, 0x0000, T1, ORN_IMM), - ARMv7_OP4(0xffe0, 0x8000, 0xea60, 0x0000, T1, ORN_REG), - - ARMv7_OP4(0xfbe0, 0x8000, 0xf040, 0x0000, T1, ORR_IMM), - ARMv7_OP4(0x0fe0, 0x0000, 0x0380, 0x0000, A1, ORR_IMM), - ARMv7_OP2(0xffc0, 0x4300, T1, ORR_REG), - ARMv7_OP4(0xffe0, 0x8000, 0xea40, 0x0000, T2, ORR_REG), - ARMv7_OP4(0x0fe0, 0x0010, 0x0180, 0x0000, A1, ORR_REG), - ARMv7_OP4(0x0fe0, 0x0090, 0x0180, 0x0010, A1, ORR_RSR), - - ARMv7_OP4(0xfff0, 0x8010, 0xeac0, 0x0000, T1, PKH), - ARMv7_OP4(0x0ff0, 0x0030, 0x0680, 0x0010, A1, PKH), - - ARMv7_OP2(0xfe00, 0xbc00, T1, POP), - ARMv7_OP4(0xffff, 0x0000, 0xe8bd, 0x0000, T2, POP), - ARMv7_OP4(0xffff, 0x0fff, 0xf85d, 0x0b04, T3, POP), - ARMv7_OP4(0x0fff, 0x0000, 0x08bd, 0x0000, A1, POP), - ARMv7_OP4(0x0fff, 0x0fff, 0x049d, 0x0004, A2, POP), - - ARMv7_OP2(0xfe00, 0xb400, T1, PUSH), - ARMv7_OP4(0xffff, 0x0000, 0xe92d, 0x0000, T2, PUSH), // had an error in arch ref - ARMv7_OP4(0xffff, 0x0fff, 0xf84d, 0x0d04, T3, PUSH), - ARMv7_OP4(0x0fff, 0x0000, 0x092d, 0x0000, A1, PUSH), - ARMv7_OP4(0x0fff, 0x0fff, 0x052d, 0x0004, A2, PUSH), - - // TODO (Q*...) - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfa90, 0xf0a0, T1, RBIT), - ARMv7_OP4(0x0fff, 0x0ff0, 0x06ff, 0x0f30, A1, RBIT), - - ARMv7_OP2(0xffc0, 0xba00, T1, REV), - ARMv7_OP4(0xfff0, 0xf0f0, 0xfa90, 0xf080, T2, REV), - ARMv7_OP4(0x0fff, 0x0ff0, 0x06bf, 0x0f30, A1, REV), - ARMv7_OP2(0xffc0, 0xba40, T1, REV16), - ARMv7_OP4(0xfff0, 0xf0f0, 0xfa90, 0xf090, T2, REV16), - ARMv7_OP4(0x0fff, 0x0ff0, 0x06bf, 0x0fb0, A1, REV16), - ARMv7_OP2(0xffc0, 0xbac0, T1, REVSH), - ARMv7_OP4(0xfff0, 0xf0f0, 0xfa90, 0xf0b0, T2, REVSH), - ARMv7_OP4(0x0fff, 0x0ff0, 0x06ff, 0x0fb0, A1, REVSH), - - ARMv7_OP4(0xffef, 0x8030, 0xea4f, 0x0030, T1, ROR_IMM), - ARMv7_OP4(0x0fef, 0x0070, 0x01a0, 0x0060, A1, ROR_IMM), - ARMv7_OP2(0xffc0, 0x41c0, T1, ROR_REG), - ARMv7_OP4(0xffe0, 0xf0f0, 0xfa60, 0xf000, T2, ROR_REG), - ARMv7_OP4(0x0fef, 0x00f0, 0x01a0, 0x0070, A1, ROR_REG), - ARMv7_OP4(0xffef, 0xf0f0, 0xea4f, 0x0030, T1, RRX), - ARMv7_OP4(0x0fef, 0x0ff0, 0x01a0, 0x0060, A1, RRX), - - ARMv7_OP2(0xffc0, 0x4240, T1, RSB_IMM), - ARMv7_OP4(0xfbe0, 0x8000, 0xf1c0, 0x0000, T2, RSB_IMM), - ARMv7_OP4(0x0fe0, 0x0000, 0x0260, 0x0000, A1, RSB_IMM), - ARMv7_OP4(0xffe0, 0x8000, 0xebc0, 0x0000, T1, RSB_REG), - ARMv7_OP4(0x0fe0, 0x0010, 0x0060, 0x0000, A1, RSB_REG), - ARMv7_OP4(0x0fe0, 0x0090, 0x0060, 0x0010, A1, RSB_RSR), - - ARMv7_OP4(0x0fe0, 0x0000, 0x02e0, 0x0000, A1, RSC_IMM), - ARMv7_OP4(0x0fe0, 0x0010, 0x00e0, 0x0000, A1, RSC_REG), - ARMv7_OP4(0x0fe0, 0x0090, 0x00e0, 0x0010, A1, RSC_RSR), - - // TODO (SADD16, SADD8, SASX) - - ARMv7_OP4(0xfbe0, 0x8000, 0xf160, 0x0000, T1, SBC_IMM), - ARMv7_OP4(0x0fe0, 0x0000, 0x02c0, 0x0000, A1, SBC_IMM), - ARMv7_OP2(0xffc0, 0x4180, T1, SBC_REG), - ARMv7_OP4(0xffe0, 0x8000, 0xeb60, 0x0000, T2, SBC_REG), - ARMv7_OP4(0x0fe0, 0x0010, 0x00c0, 0x0000, A1, SBC_REG), - ARMv7_OP4(0x0fe0, 0x0090, 0x00c0, 0x0010, A1, SBC_RSR), - - ARMv7_OP4(0xfff0, 0x8020, 0xf340, 0x0000, T1, SBFX), - ARMv7_OP4(0x0fe0, 0x0070, 0x07a0, 0x0050, A1, SBFX), - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfb90, 0xf0f0, T1, SDIV), // ??? - - ARMv7_OP4(0xfff0, 0xf0f0, 0xfaa0, 0xf080, T1, SEL), - ARMv7_OP4(0x0ff0, 0x0ff0, 0x0680, 0x0fb0, A1, SEL), - - // TODO (SH*, SM*, SS*) - - ARMv7_OP2(0xf800, 0xc000, T1, STM), - ARMv7_OP4(0xffd0, 0xa000, 0xe880, 0x0000, T2, STM), - ARMv7_OP4(0x0fd0, 0x0000, 0x0880, 0x0000, A1, STM), - ARMv7_OP4(0x0fd0, 0x0000, 0x0800, 0x0000, A1, STMDA), - ARMv7_OP4(0xffd0, 0xa000, 0xe900, 0x0000, T1, STMDB), - ARMv7_OP4(0x0fd0, 0x0000, 0x0900, 0x0000, A1, STMDB), - ARMv7_OP4(0x0fd0, 0x0000, 0x0980, 0x0000, A1, STMIB), - - ARMv7_OP2(0xf800, 0x6000, T1, STR_IMM), - ARMv7_OP2(0xf800, 0x9000, T2, STR_IMM), - ARMv7_OP4(0xfff0, 0x0000, 0xf8c0, 0x0000, T3, STR_IMM), - ARMv7_OP4(0xfff0, 0x0800, 0xf840, 0x0800, T4, STR_IMM), - ARMv7_OP4(0x0e50, 0x0000, 0x0400, 0x0000, A1, STR_IMM), - ARMv7_OP2(0xfe00, 0x5000, T1, STR_REG), - ARMv7_OP4(0xfff0, 0x0fc0, 0xf840, 0x0000, T2, STR_REG), - ARMv7_OP4(0x0e50, 0x0010, 0x0600, 0x0000, A1, STR_REG), - - ARMv7_OP2(0xf800, 0x7000, T1, STRB_IMM), - ARMv7_OP4(0xfff0, 0x0000, 0xf880, 0x0000, T2, STRB_IMM), - ARMv7_OP4(0xfff0, 0x0800, 0xf800, 0x0800, T3, STRB_IMM), - ARMv7_OP4(0x0e50, 0x0000, 0x0440, 0x0000, A1, STRB_IMM), - ARMv7_OP2(0xfe00, 0x5400, T1, STRB_REG), - ARMv7_OP4(0xfff0, 0x0fc0, 0xf800, 0x0000, T2, STRB_REG), - ARMv7_OP4(0x0e50, 0x0010, 0x0640, 0x0000, A1, STRB_REG), - - ARMv7_OP4(0xfe50, 0x0000, 0xe840, 0x0000, T1, STRD_IMM), - ARMv7_OP4(0x0e50, 0x00f0, 0x0040, 0x00f0, A1, STRD_IMM), - ARMv7_OP4(0x0e50, 0x0ff0, 0x0000, 0x00f0, A1, STRD_REG), - - ARMv7_OP2(0xf800, 0x8000, T1, STRH_IMM), - ARMv7_OP4(0xfff0, 0x0000, 0xf8a0, 0x0000, T2, STRH_IMM), - ARMv7_OP4(0xfff0, 0x0800, 0xf820, 0x0800, T3, STRH_IMM), - ARMv7_OP4(0x0e50, 0x00f0, 0x0040, 0x00b0, A1, STRH_IMM), - ARMv7_OP2(0xfe00, 0x5200, T1, STRH_REG), - ARMv7_OP4(0xfff0, 0x0fc0, 0xf820, 0x0000, T2, STRH_REG), - ARMv7_OP4(0x0e50, 0x0ff0, 0x0000, 0x00b0, A1, STRH_REG), - - ARMv7_OP2(0xff80, 0xb080, T1, SUB_SPI), - ARMv7_OP4(0xfbef, 0x8000, 0xf1ad, 0x0000, T2, SUB_SPI), - ARMv7_OP4(0xfbff, 0x8000, 0xf2ad, 0x0000, T3, SUB_SPI), - ARMv7_OP4(0x0fef, 0x0000, 0x024d, 0x0000, A1, SUB_SPI), - ARMv7_OP4(0xffef, 0x8000, 0xebad, 0x0000, T1, SUB_SPR), - ARMv7_OP4(0x0fef, 0x0010, 0x004d, 0x0000, A1, SUB_SPR), - ARMv7_OP2(0xfe00, 0x1e00, T1, SUB_IMM), - ARMv7_OP2(0xf800, 0x3800, T2, SUB_IMM), - ARMv7_OP4(0xfbe0, 0x8000, 0xf1a0, 0x0000, T3, SUB_IMM), - ARMv7_OP4(0xfbf0, 0x8000, 0xf2a0, 0x0000, T4, SUB_IMM), - ARMv7_OP4(0x0fe0, 0x0000, 0x0240, 0x0000, A1, SUB_IMM), - ARMv7_OP2(0xfe00, 0x1a00, T1, SUB_REG), - ARMv7_OP4(0xffe0, 0x8000, 0xeba0, 0x0000, T2, SUB_REG), - ARMv7_OP4(0x0fe0, 0x0010, 0x0040, 0x0000, A1, SUB_REG), - ARMv7_OP4(0x0fe0, 0x0090, 0x0040, 0x0010, A1, SUB_RSR), - - ARMv7_OP2(0xff00, 0xdf00, T1, SVC), - ARMv7_OP4(0x0f00, 0x0000, 0x0f00, 0x0000, A1, SVC), - - // TODO (SX*) - - ARMv7_OP4(0xfff0, 0xffe0, 0xe8d0, 0xf000, T1, TB_), - - ARMv7_OP4(0xfbf0, 0x8f00, 0xf090, 0x0f00, T1, TEQ_IMM), - ARMv7_OP4(0x0ff0, 0xf000, 0x0330, 0x0000, A1, TEQ_IMM), - ARMv7_OP4(0xfff0, 0x8f00, 0xea90, 0x0f00, T1, TEQ_REG), - ARMv7_OP4(0x0ff0, 0xf010, 0x0130, 0x0000, A1, TEQ_REG), - ARMv7_OP4(0x0ff0, 0xf090, 0x0130, 0x0010, A1, TEQ_RSR), - - ARMv7_OP4(0xfbf0, 0x8f00, 0xf010, 0x0f00, T1, TST_IMM), - ARMv7_OP4(0x0ff0, 0xf000, 0x0310, 0x0000, A1, TST_IMM), - ARMv7_OP2(0xffc0, 0x4200, T1, TST_REG), - ARMv7_OP4(0xfff0, 0x8f00, 0xea10, 0x0f00, T2, TST_REG), - ARMv7_OP4(0x0ff0, 0xf010, 0x0110, 0x0000, A1, TST_REG), - ARMv7_OP4(0x0ff0, 0xf090, 0x0110, 0x0010, A1, TST_RSR), - - // TODO (U*, V*) + { group_0x3 } }; -#undef ARMv7_OP -#undef ARMv7_OPP +static void group_0x3(ARMv7Thread* thr, const ARMv7_encoding type) +{ + const u32 index = (thr->code.code0 & 0x0800) >> 8; + thr->m_last_instr_name = g_table_0x3_main[index].name; + thr->m_last_instr_size = g_table_0x3_main[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0x3_main[index].func(thr, g_table_0x3_main[index].type); +} +// 0x4... +static void group_0x4(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0x40(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0x41(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0x42(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0x43(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0x44(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0x47(ARMv7Thread* thr, const ARMv7_encoding type); + +static const ARMv7_Instruction g_table_0x4[] = +{ + { group_0x4 } +}; + +static const ARMv7_Instruction g_table_0x40[] = +{ + ARMv7_OP_2(AND_REG, T1), // 0 0xffc0 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_OP_2(ADC_REG, T1), // 4 0xffc0 + // ARMv7_OP_2(EOR_REG, T1), // 4 0xffc0 code(ADC_REG, T1) == code(EOR_REG, T1) ??? + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_OP_2(LSL_REG, T1), // 8 0xffc0 + ARMv7_NULL_OP, // 9 + ARMv7_NULL_OP, // A + ARMv7_NULL_OP, // B + ARMv7_OP_2(LSR_REG, T1) // C 0xffc0 +}; + +static void group_0x40(ARMv7Thread* thr, const ARMv7_encoding type) +{ + const u32 index = (thr->code.code0 & 0x00c0) >> 4; + thr->m_last_instr_name = g_table_0x40[index].name; + thr->m_last_instr_size = g_table_0x40[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0x40[index].func(thr, g_table_0x40[index].type); +} + +static const ARMv7_Instruction g_table_0x41[] = +{ + ARMv7_OP_2(ASR_REG, T1), // 0 0xffc0 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_OP_2(SBC_REG, T1), // 8 0xffc0 + ARMv7_NULL_OP, // 9 + ARMv7_NULL_OP, // A + ARMv7_NULL_OP, // B + ARMv7_OP_2(ROR_REG, T1) // C 0xffc0 +}; + +static void group_0x41(ARMv7Thread* thr, const ARMv7_encoding type) +{ + const u32 index = (thr->code.code0 & 0x00c0) >> 4; + thr->m_last_instr_name = g_table_0x41[index].name; + thr->m_last_instr_size = g_table_0x41[index].size; + g_table_0x41[index].func(thr, g_table_0x41[index].type); +} + +static const ARMv7_Instruction g_table_0x42[] = +{ + ARMv7_OP_2(TST_REG, T1), // 0 0xffc0 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_OP_2(RSB_IMM, T1), // 4 0xffc0 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_OP_2(CMP_REG, T1), // 8 0xffc0 + ARMv7_NULL_OP, // 9 + ARMv7_NULL_OP, // A + ARMv7_NULL_OP, // B + ARMv7_OP_2(CMN_REG, T1) // C 0xffc0 +}; + +static void group_0x42(ARMv7Thread* thr, const ARMv7_encoding type) +{ + const u32 index = (thr->code.code0 & 0x00c0) >> 4; + thr->m_last_instr_name = g_table_0x42[index].name; + thr->m_last_instr_size = g_table_0x42[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0x42[index].func(thr, g_table_0x42[index].type); +} + +static const ARMv7_Instruction g_table_0x43[] = +{ + ARMv7_OP_2(ORR_REG, T1), // 0 0xffc0 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_OP_2(MUL, T1), // 4 0xffc0 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_OP_2(BIC_REG, T1), // 8 0xffc0 + ARMv7_NULL_OP, // 9 + ARMv7_NULL_OP, // A + ARMv7_NULL_OP, // B + ARMv7_OP_2(MVN_REG, T1) // C 0xffc0 +}; + +static void group_0x43(ARMv7Thread* thr, const ARMv7_encoding type) +{ + const u32 index = (thr->code.code0 & 0x00c0) >> 4; + thr->m_last_instr_name = g_table_0x43[index].name; + thr->m_last_instr_size = g_table_0x43[index].size; + g_table_0x43[index].func(thr, g_table_0x43[index].type); +} + +static const ARMv7_Instruction g_table_0x44[] = +{ + ARMv7_OP_2(ADD_REG, T2), // 0 0xff00 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_OP_2(ADD_SPR, T1), // 6 0xff78 + ARMv7_NULL_OP, // 7 + ARMv7_OP_2(ADD_SPR, T2) // 8 0xff87 +}; + +static void group_0x44(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = (thr->code.code0 & 0x0080) >> 4; + + if ((thr->code.code0 & 0xff00) == 0x4400) index = 0x0; + if ((thr->code.code0 & 0xff78) == 0x4468) index = 0x6; + + thr->m_last_instr_name = g_table_0x44[index].name; + thr->m_last_instr_size = g_table_0x44[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0x44[index].func(thr, g_table_0x44[index].type); +} + +static const ARMv7_Instruction g_table_0x47[] = +{ + ARMv7_OP_2(BX, T1), // 0 0xff87 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_OP_2(BLX, T1) // 8 0xff80 +}; + +static void group_0x47(ARMv7Thread* thr, const ARMv7_encoding type) +{ + const u32 index = (thr->code.code0 & 0x0080) >> 4; + thr->m_last_instr_name = g_table_0x47[index].name; + thr->m_last_instr_size = g_table_0x47[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0x47[index].func(thr, g_table_0x47[index].type); +} + +static const ARMv7_Instruction g_table_0x4_main[] = +{ + { group_0x40 }, // 0 + { group_0x41 }, // 1 + { group_0x42 }, // 2 + { group_0x43 }, // 3 + { group_0x44 }, // 4 + ARMv7_OP_2(CMP_REG, T2), // 5 0xff00 + ARMv7_OP_2(MOV_REG, T1), // 6 0xff00 + { group_0x47 }, // 7 + ARMv7_OP_2(LDR_LIT, T1) // 8 0xf800 +}; + +static void group_0x4(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = (thr->code.code0 & 0x0f00) >> 8; + + if ((index & 0xf800) == 0x4800) index = 0x8; + + thr->m_last_instr_name = g_table_0x4_main[index].name; + thr->m_last_instr_size = g_table_0x4_main[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0x4_main[index].func(thr, g_table_0x4_main[index].type); +} + +// 0x5... +static void group_0x5(ARMv7Thread* thr, const ARMv7_encoding type); + +static const ARMv7_Instruction g_table_0x5_main[] = +{ + ARMv7_OP_2(STR_REG, T1), // 0 0xfe00 + ARMv7_NULL_OP, // 1 + ARMv7_OP_2(STRH_REG, T1), // 2 0xfe00 + ARMv7_NULL_OP, // 3 + ARMv7_OP_2(STRB_REG, T1), // 4 0xfe00 + ARMv7_NULL_OP, // 5 + ARMv7_OP_2(LDRSB_REG, T1), // 6 0xfe00 + ARMv7_NULL_OP, // 7 + ARMv7_OP_2(LDR_REG, T1), // 8 0xfe00 + ARMv7_NULL_OP, // 9 + ARMv7_NULL_OP, // A + ARMv7_NULL_OP, // B + ARMv7_OP_2(LDRB_REG, T1), // C 0xfe00 + ARMv7_NULL_OP, // D + ARMv7_OP_2(LDRSH_REG, T1) // E 0xfe00 +}; + +static const ARMv7_Instruction g_table_0x5[] = +{ + { group_0x5 } +}; + +static void group_0x5(ARMv7Thread* thr, const ARMv7_encoding type) +{ + const u32 index = (thr->code.code0 & 0x0e00) >> 8; + thr->m_last_instr_name = g_table_0x5_main[index].name; + thr->m_last_instr_size = g_table_0x5_main[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0x5_main[index].func(thr, g_table_0x5_main[index].type); +} + +// 0x6... +static void group_0x6(ARMv7Thread* thr, const ARMv7_encoding type); + +static const ARMv7_Instruction g_table_0x6_main[] = +{ + ARMv7_OP_2(STR_IMM, T1), // 0 0xf800 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_OP_2(LDR_IMM, T1) // 8 0xf800 +}; + +static const ARMv7_Instruction g_table_0x6[] = +{ + { group_0x6 } +}; + +static void group_0x6(ARMv7Thread* thr, const ARMv7_encoding type) +{ + const u32 index = (thr->code.code0 & 0x0800) >> 8; + thr->m_last_instr_name = g_table_0x6_main[index].name; + thr->m_last_instr_size = g_table_0x6_main[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0x6_main[index].func(thr, g_table_0x6_main[index].type); +} + +// 0x7... +static void group_0x7(ARMv7Thread* thr, const ARMv7_encoding type); + +static const ARMv7_Instruction g_table_0x7_main[] = +{ + ARMv7_OP_2(STRB_IMM, T1), // 0 0xf800 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_OP_2(LDRB_IMM, T1) // 8 0xf800 +}; + +static const ARMv7_Instruction g_table_0x7[] = +{ + { group_0x7 } +}; + +static void group_0x7(ARMv7Thread* thr, const ARMv7_encoding type) +{ + const u32 index = (thr->code.code0 & 0x0800) >> 8; + thr->m_last_instr_name = g_table_0x7_main[index].name; + thr->m_last_instr_size = g_table_0x7_main[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0x7_main[index].func(thr, g_table_0x7_main[index].type); +} + +// 0x8... +static void group_0x8(ARMv7Thread* thr, const ARMv7_encoding type); + +static const ARMv7_Instruction g_table_0x8_main[] = +{ + ARMv7_OP_2(STRH_IMM, T1) // 0 0xf800 +}; + +static const ARMv7_Instruction g_table_0x8[] = +{ + { group_0x8 } +}; + +static void group_0x8(ARMv7Thread* thr, const ARMv7_encoding type) +{ + const u32 index = (thr->code.code0 & 0x0800) >> 8; + thr->m_last_instr_name = g_table_0x8_main[index].name; + thr->m_last_instr_size = g_table_0x8_main[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0x8_main[index].func(thr, g_table_0x8_main[index].type); +} + +// 0x9... +static void group_0x9(ARMv7Thread* thr, const ARMv7_encoding type); + +static const ARMv7_Instruction g_table_0x9_main[] = +{ + ARMv7_OP_2(STR_IMM, T2), // 0 0xf800 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_OP_2(LDR_IMM, T2) // 8 0xf800 +}; + +static const ARMv7_Instruction g_table_0x9[] = +{ + { group_0x9 } +}; + +static void group_0x9(ARMv7Thread* thr, const ARMv7_encoding type) +{ + const u32 index = (thr->code.code0 & 0x0800) >> 8; + thr->m_last_instr_name = g_table_0x9_main[index].name; + thr->m_last_instr_size = g_table_0x9_main[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0x9_main[index].func(thr, g_table_0x9_main[index].type); +} + +// 0xa... +static void group_0xa(ARMv7Thread* thr, const ARMv7_encoding type); + +static const ARMv7_Instruction g_table_0xa_main[] = +{ + ARMv7_OP_2(ADR, T1), // 0 0xf800 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_OP_2(ADD_SPI, T1) // 8 0xf800 +}; + +static const ARMv7_Instruction g_table_0xa[] = +{ + { group_0xa } +}; + +static void group_0xa(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = (thr->code.code0 & 0x0800) >> 8; + thr->m_last_instr_name = g_table_0xa_main[index].name; + thr->m_last_instr_size = g_table_0xa_main[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xa_main[index].func(thr, g_table_0xa_main[index].type); +} + +// 0xb... +static void group_0xb(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xb0(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xba(ARMv7Thread* thr, const ARMv7_encoding type); + +static const ARMv7_Instruction g_table_0xb0[] = +{ + ARMv7_OP_2(ADD_SPI, T2), // 0 0xff80 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_OP_2(SUB_SPI, T1) // 8 0xff80 +}; + +static void group_0xb0(ARMv7Thread* thr, const ARMv7_encoding type) +{ + const u32 index = (thr->code.code0 & 0x0080) >> 4; + thr->m_last_instr_name = g_table_0xb0[index].name; + thr->m_last_instr_size = g_table_0xb0[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xb0[index].func(thr, g_table_0xb0[index].type); +} + +static const ARMv7_Instruction g_table_0xba[] = +{ + ARMv7_OP_2(REV, T1), // 0 0xffc0 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_OP_2(REV16, T1), // 4 0xffc0 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_NULL_OP, // 8 + ARMv7_NULL_OP, // 9 + ARMv7_NULL_OP, // A + ARMv7_NULL_OP, // B + ARMv7_OP_2(REVSH, T1) // C 0xffc0 +}; + +static void group_0xba(ARMv7Thread* thr, const ARMv7_encoding type) +{ + const u32 index = (thr->code.code0 & 0x00c0) >> 4; // mask 0xffc0 + thr->m_last_instr_name = g_table_0xba[index].name; + thr->m_last_instr_size = g_table_0xba[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xba[index].func(thr, g_table_0xba[index].type); +} + +static const ARMv7_Instruction g_table_0xb_main[] = +{ + { group_0xb0 }, // 0 + ARMv7_OP_2(CB_Z, T1), // 1 0xf500 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_OP_2(PUSH, T1), // 4 0xfe00 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_NULL_OP, // 8 + ARMv7_NULL_OP, // 9 + { group_0xba }, // A + ARMv7_NULL_OP, // B + ARMv7_OP_2(POP, T1), // C 0xfe00 + ARMv7_NULL_OP, // D + ARMv7_OP_2(BKPT, T1), // E 0xff00 + ARMv7_OP_2(NOP, T1), // F 0xffff + ARMv7_OP_2(IT, T1), // 10 0xff00 +}; + +static const ARMv7_Instruction g_table_0xb[] = +{ + { group_0xb } +}; + +static void group_0xb(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = (thr->code.code0 & 0x0e00) >> 8; + + if ((thr->code.code0 & 0xf500) == 0xb100) index = 0x1; // CB_Z, T1 + if ((thr->code.code0 & 0xff00) == 0xbe00) index = 0xe; // BKPT, T1 + if ((thr->code.code0 & 0xffff) == 0xbf00) index = 0xf; // NOP, T1 + if ((thr->code.code0 & 0xff00) == 0xbf00) index = 0x10; // IT, T1 + + thr->m_last_instr_name = g_table_0xb_main[index].name; + thr->m_last_instr_size = g_table_0xb_main[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xb_main[index].func(thr, g_table_0xb_main[index].type); +} + +// 0xc... +static void group_0xc(ARMv7Thread* thr, const ARMv7_encoding type); + +static const ARMv7_Instruction g_table_0xc_main[] = +{ + ARMv7_OP_2(STM, T1), // 0 0xf800 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_OP_2(LDM, T1) // 8 0xf800 +}; + +static const ARMv7_Instruction g_table_0xc[] = +{ + { group_0xc } +}; + +static void group_0xc(ARMv7Thread* thr, const ARMv7_encoding type) +{ + const u32 index = (thr->code.code0 & 0x0800) >> 8; + thr->m_last_instr_name = g_table_0xc_main[index].name; + thr->m_last_instr_size = g_table_0xc_main[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xc_main[index].func(thr, g_table_0xc_main[index].type); +} + +// 0xd... +static void group_0xd(ARMv7Thread* thr, const ARMv7_encoding type); + +static const ARMv7_Instruction g_table_0xd_main[] = +{ + ARMv7_OP_2(B, T1), // 0 0xf000 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_NULL_OP, // 8 + ARMv7_NULL_OP, // 9 + ARMv7_NULL_OP, // A + ARMv7_NULL_OP, // B + ARMv7_NULL_OP, // C + ARMv7_NULL_OP, // D + ARMv7_NULL_OP, // E + ARMv7_OP_2(SVC, T1) // F 0xff00 +}; + +static const ARMv7_Instruction g_table_0xd[] = +{ + { group_0xd } +}; + +static void group_0xd(ARMv7Thread* thr, const ARMv7_encoding type) +{ + //u32 index = (thr->code.code0 & 0x0f00) >> 8; + //if ((thr->code.code0 & 0xf000) == 0xd000) index = 0; + + const u32 index = (thr->code.code0 & 0xff00) == 0xdf00 ? 0xf : 0x0; // check me + thr->m_last_instr_name = g_table_0xd_main[index].name; + thr->m_last_instr_size = g_table_0xd_main[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xd_main[index].func(thr, g_table_0xd_main[index].type); +} + +// 0xe... +static void group_0xe(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xe85(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xe8(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xe9(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xea(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xea4(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xea4f(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xea4f0000(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xea4f0030(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xea6(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xeb(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xeb0(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xeba(ARMv7Thread* thr, const ARMv7_encoding type); + + +static const ARMv7_Instruction g_table_0xe85[] = +{ + ARMv7_OP_4(LDRD_IMM, T1), // 0 0xfe50, 0x0000 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_NULL_OP, // 8 + ARMv7_NULL_OP, // 9 + ARMv7_NULL_OP, // A + ARMv7_NULL_OP, // B + ARMv7_NULL_OP, // C + ARMv7_NULL_OP, // D + ARMv7_NULL_OP, // E + ARMv7_OP_4(LDRD_LIT, T1) // F 0xfe7f, 0x0000 +}; + +static void group_0xe85(ARMv7Thread* thr, const ARMv7_encoding type) +{ + //u32 index = thr->code.code0 & 0x000f; + //if ((thr->code.code0 & 0xfe50) == 0xe850) index = 0x0; + + const u32 index = (thr->code.code0 & 0xfe7f) == 0xe85f ? 0xf : 0x0; // check me + thr->m_last_instr_name = g_table_0xe85[index].name; + thr->m_last_instr_size = g_table_0xe85[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xe85[index].func(thr, g_table_0xe85[index].type); +}; + +static const ARMv7_Instruction g_table_0xe8[] = +{ + ARMv7_NULL_OP, // 0 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_OP_4(STRD_IMM, T1), // 4 0xfe50, 0x0000 + { group_0xe85 }, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_OP_4(STM, T2), // 8 0xffd0, 0xa000 + ARMv7_OP_4(LDM, T2), // 9 0xffd0, 0x2000 + ARMv7_NULL_OP, // A + ARMv7_OP_4(POP, T2), // B 0xffff, 0x0000 + ARMv7_NULL_OP, // C + ARMv7_OP_4(TB_, T1) // D 0xfff0, 0xffe0 +}; + +static void group_0xe8(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = (thr->code.code0 & 0x00f0) >> 4; + + if ((thr->code.code0 & 0xfe50) == 0xe840) index = 0x4; + if ((thr->code.code0 & 0xffd0) == 0xe880) index = 0x8; + if ((thr->code.code0 & 0xffd0) == 0xe890) index = 0x9; + + thr->m_last_instr_name = g_table_0xe8[index].name; + thr->m_last_instr_size = g_table_0xe8[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xe8[index].func(thr, g_table_0xe8[index].type); +} + +static const ARMv7_Instruction g_table_0xe9[] = +{ + ARMv7_OP_4(STMDB, T1), // 0 0xffd0, 0xa000 + ARMv7_OP_4(LDMDB, T1), // 1 0xffd0, 0x2000 + ARMv7_OP_4(PUSH, T2) // 2 0xffff, 0x0000 +}; + +static void group_0xe9(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = (thr->code.code0 & 0x00d0) >> 4; + + if ((thr->code.code0 & 0xffff) == 0xe92d) index = 0x2; + + thr->m_last_instr_name = g_table_0xe9[index].name; + thr->m_last_instr_size = g_table_0xe9[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xe9[index].func(thr, g_table_0xe9[index].type); +} + +static const ARMv7_Instruction g_table_0xea4[] = +{ + ARMv7_OP_4(ORR_REG, T2), // 0 0xffe0, 0x8000 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_NULL_OP, // 8 + ARMv7_NULL_OP, // 9 + ARMv7_NULL_OP, // A + ARMv7_NULL_OP, // B + ARMv7_NULL_OP, // C + ARMv7_NULL_OP, // D + ARMv7_NULL_OP, // E + { group_0xea4f } // F +}; + +static void group_0xea4(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = 0x0; + if ((thr->code.code0 & 0xffef) == 0xea4f) index = 0xf; // check me + + thr->m_last_instr_name = g_table_0xea4[index].name; + thr->m_last_instr_size = g_table_0xea4[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xea4[index].func(thr, g_table_0xea4[index].type); +} + +static const ARMv7_Instruction g_table_0xea4f[] = +{ + { group_0xea4f0000 }, // 0 + ARMv7_OP_4(ASR_IMM, T2), // 1 0xffef, 0x8030 + ARMv7_OP_4(ASR_IMM, T2), // 2 0xffef, 0x8030 + { group_0xea4f0030 } // 3 +}; + +static void group_0xea4f(ARMv7Thread* thr, const ARMv7_encoding type) +{ + const u32 index = (thr->code.code1 & 0x0030) >> 4; + thr->m_last_instr_name = g_table_0xea4f[index].name; + thr->m_last_instr_size = g_table_0xea4f[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xea4f[index].func(thr, g_table_0xea4f[index].type); +} + +static const ARMv7_Instruction g_table_0xea4f0000[] = +{ + ARMv7_OP_4(MOV_REG, T3), // 0 0xffef, 0xf0f0 + ARMv7_OP_4(LSL_IMM, T2) // 1 0xffef, 0x8030 +}; + +static void group_0xea4f0000(ARMv7Thread* thr, const ARMv7_encoding type) +{ + const u32 index = thr->code.code1 & 0x8030 ? 0x0 : 0x1; + thr->m_last_instr_name = g_table_0xea4f0000[index].name; + thr->m_last_instr_size = g_table_0xea4f0000[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xea4f0000[index].func(thr, g_table_0xea4f0000[index].type); +} + +static const ARMv7_Instruction g_table_0xea4f0030[] = +{ + ARMv7_OP_4(RRX, T1), // 1 0xffef, 0xf0f0 + ARMv7_OP_4(ROR_IMM, T1) // 2 0xffef, 0x8030 +}; + +static void group_0xea4f0030(ARMv7Thread* thr, const ARMv7_encoding type) +{ + const u32 index = thr->code.code1 & 0x8030 ? 0x0 : 0x1; + thr->m_last_instr_name = g_table_0xea4f0030[index].name; + thr->m_last_instr_size = g_table_0xea4f0030[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xea4f0030[index].func(thr, g_table_0xea4f0030[index].type); +} + +static const ARMv7_Instruction g_table_0xea6[] = +{ + ARMv7_OP_4(ORN_REG, T1), // 0 0xffe0, 0x8000 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_NULL_OP, // 8 + ARMv7_NULL_OP, // 9 + ARMv7_NULL_OP, // A + ARMv7_NULL_OP, // B + ARMv7_NULL_OP, // C + ARMv7_NULL_OP, // D + ARMv7_NULL_OP, // E + ARMv7_OP_4(MVN_REG, T2) // F 0xffef, 0x8000 +}; + +static void group_0xea6(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = thr->code.code0 & 0x000f; + + if ((thr->m_arg & 0xffe08000) == 0xea600000) index = 0x0; + + thr->m_last_instr_name = g_table_0xea6[index].name; + thr->m_last_instr_size = g_table_0xea6[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xea6[index].func(thr, g_table_0xea6[index].type); +} + +static const ARMv7_Instruction g_table_0xea[] = +{ + ARMv7_OP_4(AND_REG, T2), // 0 0xffe0, 0x8000 + ARMv7_OP_4(TST_REG, T2), // 1 0xfff0, 0x8f00 + ARMv7_OP_4(BIC_REG, T2), // 2 0xffe0, 0x8000 + ARMv7_NULL_OP, // 3 + { group_0xea4 }, // 4 + ARMv7_NULL_OP, // 5 + { group_0xea6 }, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_OP_4(EOR_REG, T2), // 8 0xffe0, 0x8000 + ARMv7_OP_4(TEQ_REG, T1), // 9 0xfff0, 0x8f00 + ARMv7_NULL_OP, // A + ARMv7_NULL_OP, // B + ARMv7_OP_4(PKH, T1) // C 0xfff0, 0x8010 +}; + +static void group_0xea(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = (thr->code.code0 & 0x00e0) >> 4; + + if ((thr->m_arg & 0xfff08f00) == 0xea100f00) index = 0x1; + if ((thr->m_arg & 0xfff08f00) == 0xea900f00) index = 0x9; + if ((thr->m_arg & 0xfff08010) == 0xeac00000) index = 0xc; + + thr->m_last_instr_name = g_table_0xea[index].name; + thr->m_last_instr_size = g_table_0xea[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xea[index].func(thr, g_table_0xea[index].type); +} + +static const ARMv7_Instruction g_table_0xeb0[] = +{ + ARMv7_OP_4(ADD_REG, T3), // 0 0xffe0, 0x8000 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_NULL_OP, // 8 + ARMv7_NULL_OP, // 9 + ARMv7_NULL_OP, // A + ARMv7_NULL_OP, // B + ARMv7_NULL_OP, // C + ARMv7_OP_4(ADD_SPR, T3) // D 0xffef, 0x8000 +}; + +static void group_0xeb0(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = thr->code.code0 & 0x000f; + + if ((thr->m_arg & 0xffe08000) == 0xeb000000) index = 0x0; + + thr->m_last_instr_name = g_table_0xeb0[index].name; + thr->m_last_instr_size = g_table_0xeb0[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xeb0[index].func(thr, g_table_0xeb0[index].type); +} + +static const ARMv7_Instruction g_table_0xeba[] = +{ + ARMv7_OP_4(SUB_REG, T2), // 0 0xffe0, 0x8000 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_NULL_OP, // 8 + ARMv7_NULL_OP, // 9 + ARMv7_NULL_OP, // A + ARMv7_NULL_OP, // B + ARMv7_NULL_OP, // C + ARMv7_OP_4(SUB_SPR, T1) // D 0xffef, 0x8000 +}; + +static void group_0xeba(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = thr->code.code0 & 0x000f; + + if ((thr->m_arg & 0xffe08000) == 0xeba00000) index = 0x0; + + thr->m_last_instr_name = g_table_0xeba[index].name; + thr->m_last_instr_size = g_table_0xeba[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xeba[index].func(thr, g_table_0xeba[index].type); +} + +static const ARMv7_Instruction g_table_0xeb[] = +{ + { group_0xeb0 }, // 0 0xffe0 + ARMv7_OP_4(CMN_REG, T2), // 1 0xfff0, 0x8f00 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_OP_4(ADC_REG, T2), // 4 0xffe0, 0x8000 + ARMv7_NULL_OP, // 5 + ARMv7_OP_4(SBC_REG, T2), // 6 0xffe0, 0x8000 + ARMv7_NULL_OP, // 7 + ARMv7_NULL_OP, // 8 + ARMv7_NULL_OP, // 9 + { group_0xeba }, // A 0xffe0 + ARMv7_OP_4(CMP_REG, T3), // B 0xfff0, 0x8f00 + ARMv7_OP_4(RSB_REG, T1) // C 0xffe0, 0x8000 +}; + +static void group_0xeb(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = (thr->code.code0 & 0x00e0) >> 4; + + if ((thr->m_arg & 0xfff08f00) == 0xeb100f00) index = 0x1; + if ((thr->m_arg & 0xfff08f00) == 0xebb00f00) index = 0xb; + + thr->m_last_instr_name = g_table_0xeb[index].name; + thr->m_last_instr_size = g_table_0xeb[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xeb[index].func(thr, g_table_0xeb[index].type); +} + +static const ARMv7_Instruction g_table_0xe_main[] = +{ + ARMv7_OP_2(B, T2), // 0 0xf800 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + { group_0xe8 }, // 8 + { group_0xe9 }, // 9 + { group_0xea }, // A + { group_0xeb }, // B + ARMv7_NULL_OP, // C + ARMv7_NULL_OP, // D + ARMv7_NULL_OP, // E + ARMv7_NULL_OP, // F +}; + +static const ARMv7_Instruction g_table_0xe[] = +{ + { group_0xe } +}; + +static void group_0xe(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = (thr->code.code0 & 0x0f00) >> 8; + + if ((thr->code.code0 & 0xf800) == 0xe000) index = 0x0; + + thr->m_last_instr_name = g_table_0xe_main[index].name; + thr->m_last_instr_size = g_table_0xe_main[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xe_main[index].func(thr, g_table_0xe_main[index].type); +} + +// 0xf... +static void group_0xf(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xf000(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xf04(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xf06(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xf0(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xf1(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xf1a(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xf10(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xf20(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xf2a(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xf2(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xf36(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xf3(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xf810(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xf800(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xf81(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xf820(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xf840(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xf84(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xf850(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xf85(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xf8(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xf910(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xf91(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xf930(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xf93(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xf9(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xfa00(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xfa90(ARMv7Thread* thr, const ARMv7_encoding type); +static void group_0xfa(ARMv7Thread* thr, const ARMv7_encoding type); + +static const ARMv7_Instruction g_table_0xf000[] = +{ + ARMv7_OP_4(AND_IMM, T1), // 0 0xfbe0, 0x8000 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_OP_4(B, T3), // 8 0xf800, 0xd000 + ARMv7_OP_4(B, T4), // 9 0xf800, 0xd000 + ARMv7_NULL_OP, // A + ARMv7_NULL_OP, // B + ARMv7_OP_4(BLX, T2), // C 0xf800, 0xc001 + ARMv7_OP_4(BL, T1) // D 0xf800, 0xd000 +}; + +static void group_0xf000(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = (thr->code.code1 & 0xd000) >> 12; + + if ((thr->code.code1 & 0x8000) == 0x0000) index = 0x0; + if ((thr->code.code1 & 0xc001) == 0xc000) index = 0xc; + + thr->m_last_instr_size = g_table_0xf000[index].size; + thr->m_last_instr_name = g_table_0xf000[index].name; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xf000[index].func(thr, g_table_0xf000[index].type); +} + +static const ARMv7_Instruction g_table_0xf04[] = +{ + ARMv7_OP_4(ORR_IMM, T1), // 0 0xfbe0, 0x8000 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_NULL_OP, // 8 + ARMv7_NULL_OP, // 9 + ARMv7_NULL_OP, // A + ARMv7_NULL_OP, // B + ARMv7_NULL_OP, // C + ARMv7_NULL_OP, // D + ARMv7_NULL_OP, // E + ARMv7_OP_4(MOV_IMM, T2) // F 0xfbef, 0x8000 +}; + +static void group_0xf04(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = thr->code.code0 & 0x000f; + + if ((thr->m_arg & 0xfbe08000) == 0xf0400000) index = 0x0; + + thr->m_last_instr_size = g_table_0xf04[index].size; + thr->m_last_instr_name = g_table_0xf04[index].name; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xf04[index].func(thr, g_table_0xf04[index].type); +} + +static const ARMv7_Instruction g_table_0xf06[] = +{ + ARMv7_OP_4(ORN_IMM, T1), // 0 0xfbe0, 0x8000 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_NULL_OP, // 8 + ARMv7_NULL_OP, // 9 + ARMv7_NULL_OP, // A + ARMv7_NULL_OP, // B + ARMv7_NULL_OP, // C + ARMv7_NULL_OP, // D + ARMv7_NULL_OP, // E + ARMv7_OP_4(MVN_IMM, T1) // F 0xfbef, 0x8000 +}; + +static void group_0xf06(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = thr->code.code0 & 0x000f; + + if ((thr->m_arg & 0xfbe08000) == 0xf0600000) index = 0x0; + + thr->m_last_instr_size = g_table_0xf06[index].size; + thr->m_last_instr_name = g_table_0xf06[index].name; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xf06[index].func(thr, g_table_0xf06[index].type); +} + +static const ARMv7_Instruction g_table_0xf0[] = +{ + /* + { group_0xf000 }, // 0 0xfbe0 + ARMv7_OP_4(TST_IMM, T1), // 1 0xfbf0, 0x8f00 + ARMv7_OP_4(BIC_IMM, T1), // 2 0xfbe0, 0x8000 + ARMv7_NULL_OP, // 3 + { group_0xf04 }, // 4 0xfbef + ARMv7_NULL_OP, // 5 + { group_0xf06 }, // 6 0xfbef + ARMv7_NULL_OP, // 7 + ARMv7_OP_4(EOR_IMM, T1), // 8 0xfbe0, 0x8000 + ARMv7_OP_4(TEQ_IMM, T1) // 9 0xfbf0, 0x8f00 + */ + + ARMv7_OP_4(AND_IMM, T1), // f0 000 // 0 + ARMv7_OP_4(B, T3), // f0 008 // 1 + ARMv7_OP_4(B, T4), // f0 009 // 2 + ARMv7_OP_4(BLX, T2), // f0 00C // 3 + ARMv7_OP_4(BL, T1), // f0 00D // 4 + + ARMv7_OP_4(TST_IMM, T1), // f0 1 // 5 + ARMv7_OP_4(BIC_IMM, T1), // f0 2 // 6 + ARMv7_NULL_OP, // f0 3 // 7 + + + ARMv7_OP_4(ORR_IMM, T1), // f0 40 // 8 + ARMv7_OP_4(MOV_IMM, T2), // f0 4F // 9 + + ARMv7_NULL_OP, // f0 5 // A + + ARMv7_OP_4(ORN_IMM, T1), // f0 60 // B + ARMv7_OP_4(MVN_IMM, T1), // f0 6F // C + + ARMv7_NULL_OP, // f0 7 // D + ARMv7_OP_4(EOR_IMM, T1), // f0 8 // E + ARMv7_OP_4(TEQ_IMM, T1) // f0 9 // F + +}; + +static void group_0xf0(ARMv7Thread* thr, const ARMv7_encoding type) // TODO: optimize this group +{ + u32 index = 0; + if ((thr->m_arg & 0xfbe08000) == 0xf0000000) index = 0x0; + if ((thr->m_arg & 0xf800d000) == 0xf0008000) index = 0x1; + if ((thr->m_arg & 0xf800d000) == 0xf0009000) index = 0x2; + if ((thr->m_arg & 0xf800c001) == 0xf000c000) index = 0x3; + if ((thr->m_arg & 0xf800d000) == 0xf000d000) index = 0x4; + if ((thr->m_arg & 0xfbf08f00) == 0xf0100f00) index = 0x5; + if ((thr->m_arg & 0xfbe08000) == 0xf0200000) index = 0x6; + if ((thr->m_arg & 0xfbe08000) == 0xf0400000) index = 0x8; + if ((thr->m_arg & 0xfbef8000) == 0xf04f0000) index = 0x9; + if ((thr->m_arg & 0xfbe08000) == 0xf0600000) index = 0xb; + if ((thr->m_arg & 0xfbef8000) == 0xf06f0000) index = 0xc; + if ((thr->m_arg & 0xfbe08000) == 0xf0800000) index = 0xe; + if ((thr->m_arg & 0xfbf08f00) == 0xf0900f00) index = 0xf; + + /* + u32 index = (thr->code.code0 & 0x00e0) >> 4; // 0xfbef + + if ((thr->code.code0 & 0xfbf0) == 0xf010) index = 0x1; + if ((thr->code.code0 & 0xfbf0) == 0xf090) index = 0x9; + */ + + thr->m_last_instr_size = g_table_0xf0[index].size; + thr->m_last_instr_name = g_table_0xf0[index].name; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xf0[index].func(thr, g_table_0xf0[index].type); +} + +static const ARMv7_Instruction g_table_0xf10[] = +{ + ARMv7_OP_4(ADD_IMM, T3), // 0 0xfbe0, 0x8000 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_NULL_OP, // 8 + ARMv7_NULL_OP, // 9 + ARMv7_NULL_OP, // A + ARMv7_NULL_OP, // B + ARMv7_NULL_OP, // C + ARMv7_OP_4(ADD_SPI, T3) // D 0xfbef, 0x8000 +}; + +static void group_0xf10(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = thr->code.code0 & 0x000f; + + if ((thr->m_arg & 0xfbe08000) == 0xf1000000) index = 0x0; + + thr->m_last_instr_name = g_table_0xf10[index].name; + thr->m_last_instr_size = g_table_0xf10[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xf10[index].func(thr, g_table_0xf10[index].type); +} + +static const ARMv7_Instruction g_table_0xf1a[] = +{ + ARMv7_OP_4(SUB_IMM, T3), // 0 0xfbe0, 0x8000 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_NULL_OP, // 8 + ARMv7_NULL_OP, // 9 + ARMv7_NULL_OP, // A + ARMv7_NULL_OP, // B + ARMv7_NULL_OP, // C + ARMv7_OP_4(SUB_SPI, T2) // D 0xfbef, 0x8000 +}; + +static void group_0xf1a(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = thr->code.code0 & 0x000f; + + if ((thr->m_arg & 0xfbe08000) == 0xf1a00000) index = 0x0; + + thr->m_last_instr_name = g_table_0xf1a[index].name; + thr->m_last_instr_size = g_table_0xf1a[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xf1a[index].func(thr, g_table_0xf1a[index].type); +} + +static const ARMv7_Instruction g_table_0xf1[] = +{ + { group_0xf10 }, // 0 + ARMv7_OP_4(CMN_IMM, T1), // 1 0xfbf0, 0x8f00 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_OP_4(ADC_IMM, T1), // 4 0xfbe0, 0x8000 + ARMv7_NULL_OP, // 5 + ARMv7_OP_4(SBC_IMM, T1), // 6 0xfbe0, 0x8000 + ARMv7_NULL_OP, // 7 + ARMv7_NULL_OP, // 8 + ARMv7_NULL_OP, // 9 + { group_0xf1a }, // A + ARMv7_OP_4(CMP_IMM, T2), // B 0xfbf0, 0x8f00 + ARMv7_OP_4(RSB_IMM, T2) // C 0xfbe0, 0x8000 +}; + +static void group_0xf1(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = (thr->code.code0 & 0x00e0) >> 4; + + if ((thr->m_arg & 0xfbf08f00) == 0xf1100f00) index = 0x1; + if ((thr->m_arg & 0xfbf08f00) == 0xf1b00f00) index = 0xb; + + thr->m_last_instr_name = g_table_0xf1[index].name; + thr->m_last_instr_size = g_table_0xf1[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xf1[index].func(thr, g_table_0xf1[index].type); +} + +static const ARMv7_Instruction g_table_0xf20[] = +{ + ARMv7_OP_4(ADD_IMM, T4), // 0 0xfbf0, 0x8000 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_NULL_OP, // 8 + ARMv7_NULL_OP, // 9 + ARMv7_NULL_OP, // A + ARMv7_NULL_OP, // B + ARMv7_NULL_OP, // C + ARMv7_OP_4(ADD_SPI, T4), // D 0xfbff, 0x8000 + ARMv7_NULL_OP, // E + ARMv7_OP_4(ADR, T3) // F 0xfbff, 0x8000 +}; + +static void group_0xf20(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = thr->code.code0 & 0x000f; + + if ((thr->m_arg & 0xfbf08000) == 0xf2000000) index = 0x0; + + thr->m_last_instr_name = g_table_0xf20[index].name; + thr->m_last_instr_size = g_table_0xf20[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xf20[index].func(thr, g_table_0xf20[index].type); +} + +static const ARMv7_Instruction g_table_0xf2a[] = +{ + ARMv7_OP_4(SUB_IMM, T4), // 0 0xfbf0, 0x8000 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_NULL_OP, // 8 + ARMv7_NULL_OP, // 9 + ARMv7_NULL_OP, // A + ARMv7_NULL_OP, // B + ARMv7_NULL_OP, // C + ARMv7_OP_4(SUB_SPI, T3), // D 0xfbff, 0x8000 + ARMv7_NULL_OP, // E + ARMv7_OP_4(ADR, T2) // F 0xfbff, 0x8000 +}; + +static void group_0xf2a(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = thr->code.code0 & 0x000f; + + if ((thr->m_arg & 0xfbf08000) == 0xf2a00000) index = 0x0; + + thr->m_last_instr_name = g_table_0xf2a[index].name; + thr->m_last_instr_size = g_table_0xf2a[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xf2a[index].func(thr, g_table_0xf2a[index].type); +} + +static const ARMv7_Instruction g_table_0xf2[] = +{ + { group_0xf20 }, // 0 0xfbff + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_OP_4(MOV_IMM, T3), // 4 0xfbf0, 0x8000 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_NULL_OP, // 8 + ARMv7_NULL_OP, // 9 + { group_0xf2a }, // A 0xfbff + ARMv7_NULL_OP, // B + ARMv7_OP_4(MOVT, T1) // C 0xfbf0, 0x8000 +}; + +static void group_0xf2(ARMv7Thread* thr, const ARMv7_encoding type) +{ + const u32 index = (thr->code.code0 & 0x00f0) >> 4; // mask 0xfbf0 + thr->m_last_instr_name = g_table_0xf2[index].name; + thr->m_last_instr_size = g_table_0xf2[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xf2[index].func(thr, g_table_0xf2[index].type); +} + +static const ARMv7_Instruction g_table_0xf36[] = +{ + ARMv7_OP_4(BFI, T1), // 0 0xfff0, 0x8020 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_NULL_OP, // 8 + ARMv7_NULL_OP, // 9 + ARMv7_NULL_OP, // A + ARMv7_NULL_OP, // B + ARMv7_NULL_OP, // C + ARMv7_NULL_OP, // C + ARMv7_NULL_OP, // E + ARMv7_OP_4(BFC, T1) // F 0xffff, 0x8020 +}; + +static void group_0xf36(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = thr->code.code0 & 0x000f; + + if ((thr->m_arg & 0xfff08020) == 0xf3600000) index = 0x0; + + thr->m_last_instr_name = g_table_0xf36[index].name; + thr->m_last_instr_size = g_table_0xf36[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xf36[index].func(thr, g_table_0xf36[index].type); +} + +static const ARMv7_Instruction g_table_0xf3[] = +{ + ARMv7_NULL_OP, // 0 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_OP_4(SBFX, T1), // 4 0xfff0, 0x8020 + ARMv7_NULL_OP, // 5 + { group_0xf36 }, // 6 0xffff + ARMv7_NULL_OP, // 7 + ARMv7_OP_4(MSR_REG, T1), // 8 0xfff0, 0xf3ff + ARMv7_NULL_OP, // 9 + ARMv7_OP_4(NOP, T2), // A 0xffff, 0xffff + ARMv7_NULL_OP, // B + ARMv7_NULL_OP, // C + ARMv7_NULL_OP, // D + ARMv7_OP_4(MRS, T1), // E 0xffff, 0xf0ff +}; + +static void group_0xf3(ARMv7Thread* thr, const ARMv7_encoding type) +{ + const u32 index = (thr->code.code0 & 0x00f0) >> 4; + thr->m_last_instr_name = g_table_0xf3[index].name; + thr->m_last_instr_size = g_table_0xf3[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xf3[index].func(thr, g_table_0xf3[index].type); +} + +static const ARMv7_Instruction g_table_0xf800[] = +{ + ARMv7_OP_4(STRB_REG, T2), // 0 0xfff0, 0x0fc0 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_OP_4(STRB_IMM, T3) // 8 0xfff0, 0x0800 +}; + +static void group_0xf800(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = (thr->code.code1 & 0x0f00) >> 8; + + if ((thr->code.code1 & 0x0800) == 0x0800) index = 0x8; + + thr->m_last_instr_name = g_table_0xf800[index].name; + thr->m_last_instr_size = g_table_0xf800[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xf800[index].func(thr, g_table_0xf800[index].type); +} + +static const ARMv7_Instruction g_table_0xf810[] = +{ + ARMv7_OP_4(LDRB_REG, T2), // 0 0xfff0, 0x0fc0 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_OP_4(LDRB_IMM, T3) // 8 0xfff0, 0x0800 +}; + +static void group_0xf810(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = (thr->code.code1 & 0x0f00) >> 8; + + if ((thr->code.code1 & 0x0800) == 0x0800) index = 0x8; + + thr->m_last_instr_name = g_table_0xf810[index].name; + thr->m_last_instr_size = g_table_0xf810[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xf810[index].func(thr, g_table_0xf810[index].type); +} + +static const ARMv7_Instruction g_table_0xf81[] = +{ + { group_0xf810 }, // 0 0xfff0 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_NULL_OP, // 8 + ARMv7_NULL_OP, // 9 + ARMv7_NULL_OP, // A + ARMv7_NULL_OP, // B + ARMv7_NULL_OP, // C + ARMv7_NULL_OP, // C + ARMv7_NULL_OP, // E + ARMv7_OP_4(LDRB_LIT, T1) // F 0xff7f, 0x0000 +}; + +static void group_0xf81(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = thr->code.code0 & 0x000f; + + if (((thr->m_arg & 0xfff00fc0) == 0xf8100000) || ((thr->m_arg & 0xfff00800) == 0xf8100800)) index = 0x0; + + thr->m_last_instr_name = g_table_0xf81[index].name; + thr->m_last_instr_size = g_table_0xf81[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xf81[index].func(thr, g_table_0xf81[index].type); +} + +static const ARMv7_Instruction g_table_0xf820[] = +{ + ARMv7_OP_4(STRH_REG, T2), // 0 0xfff0, 0x0fc0 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_OP_4(STRH_IMM, T3) // 8 0xfff0, 0x0800 +}; + +static void group_0xf820(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = (thr->code.code1 & 0x0f00) >> 8; + + if ((thr->code.code1 & 0x0800) == 0x0800) index = 0x8; + + thr->m_last_instr_name = g_table_0xf820[index].name; + thr->m_last_instr_size = g_table_0xf820[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xf820[index].func(thr, g_table_0xf820[index].type); +} + +static const ARMv7_Instruction g_table_0xf840[] = +{ + ARMv7_OP_4(STR_REG, T2), // 0 0xfff0, 0x0fc0 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_OP_4(STR_IMM, T4) // 8 0xfff0, 0x0800 +}; + +static void group_0xf840(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = (thr->code.code1 & 0x0f00) >> 8; + + if ((thr->code.code1 & 0x0800) == 0x0800) index = 0x8; + + thr->m_last_instr_name = g_table_0xf840[index].name; + thr->m_last_instr_size = g_table_0xf840[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xf840[index].func(thr, g_table_0xf840[index].type); +} + +static const ARMv7_Instruction g_table_0xf84[] = +{ + { group_0xf840 }, // 0 0xfff0 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_NULL_OP, // 8 + ARMv7_NULL_OP, // 9 + ARMv7_NULL_OP, // A + ARMv7_NULL_OP, // B + ARMv7_NULL_OP, // C + ARMv7_OP_4(PUSH, T3) // D 0xffff, 0x0fff +}; + +static void group_0xf84(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = thr->code.code0 & 0x000f; + + if (((thr->m_arg & 0xfff00fc0) == 0xf8400000) || ((thr->m_arg & 0xfff00800) == 0xf8400800)) index = 0x0; + + thr->m_last_instr_name = g_table_0xf84[index].name; + thr->m_last_instr_size = g_table_0xf84[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xf84[index].func(thr, g_table_0xf84[index].type); +} + +static const ARMv7_Instruction g_table_0xf850[] = +{ + ARMv7_OP_4(LDR_REG, T2), // 0 0xfff0, 0x0fc0 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_OP_4(LDR_IMM, T4) // 8 0xfff0, 0x0800 +}; + +static void group_0xf850(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = (thr->code.code1 & 0x0f00) >> 8; + + if ((thr->code.code1 & 0x0800) == 0x0800) index = 0x8; + + thr->m_last_instr_name = g_table_0xf850[index].name; + thr->m_last_instr_size = g_table_0xf850[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xf850[index].func(thr, g_table_0xf850[index].type); +} + +static const ARMv7_Instruction g_table_0xf85[] = +{ + { group_0xf850 }, // 0 0xfff0 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_NULL_OP, // 8 + ARMv7_NULL_OP, // 9 + ARMv7_NULL_OP, // A + ARMv7_NULL_OP, // B + ARMv7_NULL_OP, // C + ARMv7_OP_4(POP, T3), // D 0xffff, 0x0fff + ARMv7_NULL_OP, // C + ARMv7_OP_4(LDR_LIT, T2) // F 0xff7f, 0x0000 +}; + +static void group_0xf85(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = thr->code.code0 & 0x000f; + + if (((thr->m_arg & 0xfff00fc0) == 0xf8500000) || ((thr->m_arg & 0xfff00800) == 0xf8500800)) index = 0x0; + + thr->m_last_instr_name = g_table_0xf85[index].name; + thr->m_last_instr_size = g_table_0xf85[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xf85[index].func(thr, g_table_0xf85[index].type); +} + +static const ARMv7_Instruction g_table_0xf8[] = +{ + { group_0xf800 }, // 0 0xfff0 + { group_0xf81 }, // 1 0xfff0 + { group_0xf820 }, // 2 0xfff0 + ARMv7_NULL_OP, // 3 + { group_0xf84 }, // 4 0xfff0 + { group_0xf85 }, // 5 0xfff0 + ARMv7_NULL_OP, // 6 + ARMv7_OP_4(HACK, T1), // 7 0xffff, 0x0000 + ARMv7_OP_4(STRB_IMM, T2), // 8 0xfff0, 0x0000 + ARMv7_OP_4(LDRB_IMM, T2), // 9 0xfff0, 0x0000 + ARMv7_OP_4(STRH_IMM, T2), // A 0xfff0, 0x0000 + ARMv7_NULL_OP, // B + ARMv7_OP_4(STR_IMM, T3), // C 0xfff0, 0x0000 + ARMv7_OP_4(LDR_IMM, T3) // D 0xfff0, 0x0000 +}; + +static void group_0xf8(ARMv7Thread* thr, const ARMv7_encoding type) +{ + const u32 index = (thr->code.code0 & 0x00f0) >> 4; + thr->m_last_instr_name = g_table_0xf8[index].name; + thr->m_last_instr_size = g_table_0xf8[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xf8[index].func(thr, g_table_0xf8[index].type); +} + +static const ARMv7_Instruction g_table_0xf910[] = +{ + ARMv7_OP_4(LDRSB_REG, T2), // 0 0xfff0, 0x0fc0 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_OP_4(LDRSB_IMM, T2) // 8 0xfff0, 0x0800 +}; + +static void group_0xf910(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = (thr->code.code1 & 0x0f00) >> 8; + + if ((thr->code.code1 & 0x0800) == 0x0800) index = 0x8; + + thr->m_last_instr_name = g_table_0xf910[index].name; + thr->m_last_instr_size = g_table_0xf910[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xf910[index].func(thr, g_table_0xf910[index].type); +} + +static const ARMv7_Instruction g_table_0xf91[] = +{ + { group_0xf910 }, // 0 0xfff0 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_NULL_OP, // 8 + ARMv7_NULL_OP, // 9 + ARMv7_NULL_OP, // A + ARMv7_NULL_OP, // B + ARMv7_NULL_OP, // C + ARMv7_NULL_OP, // D + ARMv7_NULL_OP, // C + ARMv7_OP_4(LDRSB_LIT, T1) // F 0xff7f, 0x0000 +}; + +static void group_0xf91(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = thr->code.code0 & 0x000f; + + if (((thr->m_arg & 0xfff00fc0) == 0xf9100000) || ((thr->m_arg & 0xfff00800) == 0xf9100800)) index = 0x0; + + thr->m_last_instr_name = g_table_0xf91[index].name; + thr->m_last_instr_size = g_table_0xf91[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xf91[index].func(thr, g_table_0xf91[index].type); +} + +static const ARMv7_Instruction g_table_0xf930[] = +{ + ARMv7_OP_4(LDRSH_REG, T2), // 0 0xfff0, 0x0fc0 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_OP_4(LDRSH_IMM, T2) // 8 0xfff0, 0x0800 +}; + +static void group_0xf930(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = (thr->code.code1 & 0x0f00) >> 8; + + if ((thr->code.code1 & 0x0800) == 0x0800) index = 0x8; + + thr->m_last_instr_name = g_table_0xf930[index].name; + thr->m_last_instr_size = g_table_0xf930[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xf930[index].func(thr, g_table_0xf930[index].type); +} + +static const ARMv7_Instruction g_table_0xf93[] = +{ + { group_0xf930 }, // 0 0xfff0 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_NULL_OP, // 8 + ARMv7_NULL_OP, // 9 + ARMv7_NULL_OP, // A + ARMv7_NULL_OP, // B + ARMv7_NULL_OP, // C + ARMv7_NULL_OP, // D + ARMv7_NULL_OP, // C + ARMv7_OP_4(LDRSH_LIT, T1) // F 0xff7f, 0x0000 +}; + +static void group_0xf93(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = thr->code.code0 & 0x000f; + + if (((thr->m_arg & 0xfff00fc0) == 0xf9300000) || ((thr->m_arg & 0xfff00800) == 0xf9300800)) index = 0x0; + + thr->m_last_instr_name = g_table_0xf93[index].name; + thr->m_last_instr_size = g_table_0xf93[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xf93[index].func(thr, g_table_0xf93[index].type); +} + +static const ARMv7_Instruction g_table_0xf9[] = +{ + ARMv7_NULL_OP, // 0 + { group_0xf91 }, // 1 0xff7f + ARMv7_NULL_OP, // 2 + { group_0xf93 }, // 3 0xff7f + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_NULL_OP, // 8 + ARMv7_OP_4(LDRSB_IMM, T1), // 9 0xfff0, 0x0000 + ARMv7_NULL_OP, // A + ARMv7_OP_4(LDRSH_IMM, T1), // B 0xfff0, 0x0000 +}; + +static void group_0xf9(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = (thr->code.code0 & 0x00f0) >> 4; + + if ((thr->code.code0 & 0xff7) == 0xf91) index = 0x1; // check me + if ((thr->code.code0 & 0xff7) == 0xf93) index = 0x3; + + thr->m_last_instr_name = g_table_0xf9[index].name; + thr->m_last_instr_size = g_table_0xf9[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xf9[index].func(thr, g_table_0xf9[index].type); +} + +static const ARMv7_Instruction g_table_0xfa00[] = +{ + ARMv7_OP_4(BLX, A2), // 0 0xfe00, 0x0000 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_NULL_OP, // 8 + ARMv7_NULL_OP, // 9 + ARMv7_NULL_OP, // A + ARMv7_NULL_OP, // B + ARMv7_NULL_OP, // C + ARMv7_NULL_OP, // D + ARMv7_NULL_OP, // E + ARMv7_OP_4(LSL_REG, T2) // F 0xffe0, 0xf0f0 +}; + +static void group_0xfa00(ARMv7Thread* thr, const ARMv7_encoding type) +{ + const u32 index = (thr->code.code1 & 0xf0f0) == 0xf000 ? 0xf : 0x0; + thr->m_last_instr_name = g_table_0xfa00[index].name; + thr->m_last_instr_size = g_table_0xfa00[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xfa00[index].func(thr, g_table_0xfa00[index].type); +} + +static const ARMv7_Instruction g_table_0xfa90[] = +{ + ARMv7_NULL_OP, // 0 + ARMv7_NULL_OP, // 1 + ARMv7_NULL_OP, // 2 + ARMv7_NULL_OP, // 3 + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + ARMv7_OP_4(REV, T2), // 8 0xfff0, 0xf0f0 + ARMv7_OP_4(REV16, T2), // 9 0xfff0, 0xf0f0 + ARMv7_OP_4(RBIT, T1), // A 0xfff0, 0xf0f0 + ARMv7_OP_4(REVSH, T2) // B 0xfff0, 0xf0f0 +}; + +static void group_0xfa90(ARMv7Thread* thr, const ARMv7_encoding type) +{ + const u32 index = (thr->code.code1 & 0x00f0) >> 4; + thr->m_last_instr_name = g_table_0xfa90[index].name; + thr->m_last_instr_size = g_table_0xfa90[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xfa90[index].func(thr, g_table_0xfa90[index].type); +} + +static const ARMv7_Instruction g_table_0xfa[] = +{ + { group_0xfa00 }, // 0 0xffe0 + ARMv7_NULL_OP, // 1 + ARMv7_OP_4(LSR_REG, T2), // 2 0xffe0, 0xf0f0 + ARMv7_NULL_OP, // 3 + ARMv7_OP_4(ASR_REG, T2), // 4 0xffe0, 0xf0f0 + ARMv7_NULL_OP, // 5 + ARMv7_OP_4(ROR_REG, T2), // 6 0xffe0, 0xf0f0 + ARMv7_NULL_OP, // 7 + ARMv7_NULL_OP, // 8 + { group_0xfa90 }, // 9 0xfff0 + ARMv7_OP_4(SEL, T1), // A 0xfff0, 0xf0f0 + ARMv7_OP_4(CLZ, T1) // B 0xfff0, 0xf0f0 +}; + +static void group_0xfa(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = (thr->code.code0 & 0x00e0) >> 4; + + switch ((thr->code.code0 & 0x00f0) >> 4) + { + case 0x9: index = 0x9; break; + case 0xa: index = 0xa; break; + case 0xb: index = 0xb; break; + + default: break; + } + + thr->m_last_instr_name = g_table_0xfa[index].name; + thr->m_last_instr_size = g_table_0xfa[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xfa[index].func(thr, g_table_0xfa[index].type); +} + +static const ARMv7_Instruction g_table_0xf_main[] = +{ + { group_0xf0 }, // 0 0xfbef + { group_0xf1 }, // 1 0xfbef + { group_0xf2 }, // 2 0xfbff + { group_0xf3 }, // 3 0xffff + ARMv7_NULL_OP, // 4 + ARMv7_NULL_OP, // 5 + ARMv7_NULL_OP, // 6 + ARMv7_NULL_OP, // 7 + { group_0xf8 }, // 8 0xfff0 + { group_0xf9 }, // 9 0xfff0 + { group_0xfa }, // A 0xfff0 + +}; + +static void group_0xf(ARMv7Thread* thr, const ARMv7_encoding type) +{ + u32 index = (thr->code.code0 & 0x0b00) >> 8; + + switch ((thr->m_arg & 0x0800d000) >> 12) + { + case 0x8: // B, T3 + case 0x9: // B, T4 + case 0xd: index = 0x0; break; // BL, T1 + + default: break; + } + + if ((thr->m_arg & 0xf800c001) == 0xf000c000) index = 0x0; // BLX, T2 + + switch ((thr->code.code0 & 0x0f00) >> 8) + { + case 0x3: index = 0x3; break; + case 0x8: index = 0x8; break; + case 0x9: index = 0x9; break; + case 0xa: index = 0xa; break; + + default: break; + } + + thr->m_last_instr_name = g_table_0xf_main[index].name; + thr->m_last_instr_size = g_table_0xf_main[index].size; + thr->code.data = thr->m_last_instr_size == 2 ? thr->code.code0 : thr->m_arg; + g_table_0xf_main[index].func(thr, g_table_0xf_main[index].type); +} + +static const ARMv7_Instruction g_table_0xf[] = +{ + { group_0xf } +}; + + +static void execute_main_group(ARMv7Thread* thr) +{ + switch ((thr->code.code0 & 0xf000) >> 12) + { + //case 0x0: (*g_table_0x0).func(thr, (*g_table_0x0).type); break; // TODO + case 0x1: (*g_table_0x1).func(thr, (*g_table_0x1).type); break; + case 0x2: (*g_table_0x2).func(thr, (*g_table_0x2).type); break; + case 0x3: (*g_table_0x3).func(thr, (*g_table_0x3).type); break; + case 0x4: (*g_table_0x4).func(thr, (*g_table_0x4).type); break; + case 0x5: (*g_table_0x5).func(thr, (*g_table_0x5).type); break; + case 0x6: (*g_table_0x6).func(thr, (*g_table_0x6).type); break; + case 0x7: (*g_table_0x7).func(thr, (*g_table_0x7).type); break; + case 0x8: (*g_table_0x8).func(thr, (*g_table_0x8).type); break; + case 0x9: (*g_table_0x9).func(thr, (*g_table_0x9).type); break; + case 0xa: (*g_table_0xa).func(thr, (*g_table_0xa).type); break; + case 0xb: (*g_table_0xb).func(thr, (*g_table_0xb).type); break; + case 0xc: (*g_table_0xc).func(thr, (*g_table_0xc).type); break; + case 0xd: (*g_table_0xd).func(thr, (*g_table_0xd).type); break; + case 0xe: (*g_table_0xe).func(thr, (*g_table_0xe).type); break; + case 0xf: (*g_table_0xf).func(thr, (*g_table_0xf).type); break; + + default: LOG_ERROR(GENERAL, "ARMv7Decoder: unknown group 0x%x", (thr->code.code0 & 0xf000) >> 12); Emu.Pause(); break; + } +} + +#undef ARMv7_OP_2 +#undef ARMv7_OP_4 +#undef ARMv7_NULL_OP diff --git a/rpcs3/Emu/ARMv7/ARMv7Thread.cpp b/rpcs3/Emu/ARMv7/ARMv7Thread.cpp index 40423d511d..c8a9e7c4b5 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Thread.cpp +++ b/rpcs3/Emu/ARMv7/ARMv7Thread.cpp @@ -10,7 +10,11 @@ #include "ARMv7DisAsm.h" #include "ARMv7Interpreter.h" -ARMv7Thread::ARMv7Thread() : CPUThread(CPU_THREAD_ARMv7) +ARMv7Thread::ARMv7Thread() + : CPUThread(CPU_THREAD_ARMv7) + , m_arg(0) + , m_last_instr_size(0) + , m_last_instr_name("UNK") { } @@ -81,7 +85,7 @@ void ARMv7Thread::DoRun() case 1: case 2: - m_dec = new ARMv7Decoder(*new ARMv7Interpreter(*this)); + m_dec = new ARMv7Decoder(*this); break; } } diff --git a/rpcs3/Emu/ARMv7/ARMv7Thread.h b/rpcs3/Emu/ARMv7/ARMv7Thread.h index 543b19cf0c..ce63376273 100644 --- a/rpcs3/Emu/ARMv7/ARMv7Thread.h +++ b/rpcs3/Emu/ARMv7/ARMv7Thread.h @@ -1,17 +1,23 @@ #pragma once + #include "Emu/CPU/CPUThread.h" +#include "Emu/Memory/Memory.h" enum ARMv7InstructionSet { ARM, Thumb, Jazelle, - ThumbEE, + ThumbEE }; class ARMv7Thread : public CPUThread { public: + u32 m_arg; + u8 m_last_instr_size; + const char* m_last_instr_name; + ARMv7Thread(); union @@ -61,6 +67,18 @@ public: } IPSR; + union + { + struct + { + u32 code1 : 16; + u32 code0 : 16; + }; + + u32 data; + + } code; + ARMv7InstructionSet ISET; union @@ -119,6 +137,13 @@ public: return PC; } + void update_code(const u32 address) + { + code.code0 = vm::psv::read16(address & ~1); + code.code1 = vm::psv::read16(address + 2 & ~1); + m_arg = address & 0x1 ? code.code1 << 16 | code.code0 : code.data; + } + public: virtual void InitRegs(); virtual void InitStack(); diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp index 151d12ae21..562193cb22 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLibKernel.cpp @@ -121,7 +121,7 @@ s32 sceKernelStartThread(s32 threadId, u32 argSize, vm::psv::ptr pAr { sceLibKernel.Error("sceKernelStartThread(threadId=%d, argSize=%d, pArgBlock_addr=0x%x)", threadId, argSize, pArgBlock.addr()); - CPUThread* t = Emu.GetCPU().GetThread(threadId); + std::shared_ptr t = Emu.GetCPU().GetThread(threadId); if (!t || t->GetType() != CPU_THREAD_ARMv7) { @@ -129,12 +129,12 @@ s32 sceKernelStartThread(s32 threadId, u32 argSize, vm::psv::ptr pAr } // push arg block onto the stack - u32 pos = (static_cast(t)->SP -= argSize); + u32 pos = (static_cast(t.get())->SP -= argSize); memcpy(vm::get_ptr(pos), pArgBlock.get_ptr(), argSize); // set SceKernelThreadEntry function arguments - static_cast(t)->write_gpr(0, argSize); - static_cast(t)->write_gpr(1, pos); + static_cast(t.get())->write_gpr(0, argSize); + static_cast(t.get())->write_gpr(1, pos); t->Exec(); return SCE_OK; diff --git a/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp b/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp index 8615526a68..a9173350a1 100644 --- a/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp +++ b/rpcs3/Emu/ARMv7/Modules/sceLibc.cpp @@ -1,4 +1,5 @@ #include "stdafx.h" +#include "Utilities/Log.h" #include "Emu/System.h" #include "Emu/Memory/Memory.h" #include "Emu/ARMv7/PSVFuncList.h" diff --git a/rpcs3/Emu/ARMv7/PSVFuncList.cpp b/rpcs3/Emu/ARMv7/PSVFuncList.cpp index d9901d8aca..d1d3d2b1a6 100644 --- a/rpcs3/Emu/ARMv7/PSVFuncList.cpp +++ b/rpcs3/Emu/ARMv7/PSVFuncList.cpp @@ -1,4 +1,5 @@ #include "stdafx.h" +#include "Utilities/Log.h" #include "Emu/System.h" #include "PSVFuncList.h" diff --git a/rpcs3/Emu/Audio/cellAudio.h b/rpcs3/Emu/Audio/cellAudio.h index ff6e463065..b6cabcea59 100644 --- a/rpcs3/Emu/Audio/cellAudio.h +++ b/rpcs3/Emu/Audio/cellAudio.h @@ -82,6 +82,9 @@ struct AudioPortConfig u64 attr; u64 tag; u64 counter; // copy of global counter + u32 addr; + u32 read_index_addr; + u32 size; }; struct AudioConfig //custom structure diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index 5990228a29..b3986e970d 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -21,8 +21,6 @@ CPUThread::CPUThread(CPUThreadType type) , m_stack_addr(0) , m_offset(0) , m_prio(0) - , m_sync_wait(false) - , m_wait_thread_id(-1) , m_dec(nullptr) , m_is_step(false) , m_is_branch(false) @@ -44,7 +42,7 @@ bool CPUThread::IsStopped() const { return m_status == Stopped; } void CPUThread::Close() { - ThreadBase::Stop(m_sync_wait); + ThreadBase::Stop(false); DoStop(); delete m_dec; @@ -55,9 +53,6 @@ void CPUThread::Reset() { CloseStack(); - m_sync_wait = 0; - m_wait_thread_id = -1; - SetPc(0); cycle = 0; m_is_branch = false; @@ -89,24 +84,6 @@ void CPUThread::SetName(const std::string& name) NamedThreadBase::SetThreadName(name); } -void CPUThread::Wait(bool wait) -{ - std::lock_guard lock(m_cs_sync); - m_sync_wait = wait; -} - -void CPUThread::Wait(const CPUThread& thr) -{ - std::lock_guard lock(m_cs_sync); - m_wait_thread_id = thr.GetId(); - m_sync_wait = true; -} - -bool CPUThread::Sync() -{ - return m_sync_wait; -} - int CPUThread::ThreadStatus() { if(Emu.IsStopped() || IsStopped() || IsPaused()) @@ -124,7 +101,7 @@ int CPUThread::ThreadStatus() return CPUThread_Step; } - if (Emu.IsPaused() || Sync()) + if (Emu.IsPaused()) { return CPUThread_Sleeping; } @@ -334,7 +311,7 @@ void CPUThread::Task() if (status == CPUThread_Sleeping) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack continue; } diff --git a/rpcs3/Emu/CPU/CPUThread.h b/rpcs3/Emu/CPU/CPUThread.h index 6bfbc0e8d4..6b1471705b 100644 --- a/rpcs3/Emu/CPU/CPUThread.h +++ b/rpcs3/Emu/CPU/CPUThread.h @@ -136,23 +136,6 @@ protected: public: virtual ~CPUThread(); - u32 m_wait_thread_id; - - std::mutex m_cs_sync; - bool m_sync_wait; - void Wait(bool wait); - void Wait(const CPUThread& thr); - bool Sync(); - - template - void WaitFor(T func) - { - while(func(ThreadStatus())) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - } - int ThreadStatus(); void NextPc(u8 instr_size); @@ -280,7 +263,7 @@ public: thread->SetJoinable(false); while (thread->IsRunning()) - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack return thread->GetExitStatus(); } diff --git a/rpcs3/Emu/CPU/CPUThreadManager.cpp b/rpcs3/Emu/CPU/CPUThreadManager.cpp index b745da0177..493d1896cc 100644 --- a/rpcs3/Emu/CPU/CPUThreadManager.cpp +++ b/rpcs3/Emu/CPU/CPUThreadManager.cpp @@ -28,28 +28,28 @@ CPUThread& CPUThreadManager::AddThread(CPUThreadType type) { std::lock_guard lock(m_mtx_thread); - CPUThread* new_thread; + std::shared_ptr new_thread; switch(type) { case CPU_THREAD_PPU: { - new_thread = new PPUThread(); + new_thread.reset(new PPUThread()); break; } case CPU_THREAD_SPU: { - new_thread = new SPUThread(); + new_thread.reset(new SPUThread()); break; } case CPU_THREAD_RAW_SPU: { - new_thread = new RawSPUThread(); + new_thread.reset(new RawSPUThread()); break; } case CPU_THREAD_ARMv7: { - new_thread = new ARMv7Thread(); + new_thread.reset(new ARMv7Thread()); break; } default: assert(0); @@ -58,7 +58,7 @@ CPUThread& CPUThreadManager::AddThread(CPUThreadType type) new_thread->SetId(Emu.GetIdManager().GetNewID(fmt::Format("%s Thread", new_thread->GetTypeString().c_str()), new_thread)); m_threads.push_back(new_thread); - SendDbgCommand(DID_CREATE_THREAD, new_thread); + SendDbgCommand(DID_CREATE_THREAD, new_thread.get()); return *new_thread; } @@ -67,17 +67,11 @@ void CPUThreadManager::RemoveThread(const u32 id) { std::lock_guard lock(m_mtx_thread); - CPUThread* thr = nullptr; + std::shared_ptr thr; u32 thread_index = 0; for (u32 i = 0; i < m_threads.size(); ++i) { - if (m_threads[i]->m_wait_thread_id == id) - { - m_threads[i]->Wait(false); - m_threads[i]->m_wait_thread_id = -1; - } - if (m_threads[i]->GetId() != id) continue; thr = m_threads[i]; @@ -86,7 +80,7 @@ void CPUThreadManager::RemoveThread(const u32 id) if (thr) { - SendDbgCommand(DID_REMOVE_THREAD, thr); + SendDbgCommand(DID_REMOVE_THREAD, thr.get()); thr->Close(); m_threads.erase(m_threads.begin() + thread_index); @@ -112,9 +106,9 @@ s32 CPUThreadManager::GetThreadNumById(CPUThreadType type, u32 id) return -1; } -CPUThread* CPUThreadManager::GetThread(u32 id) +std::shared_ptr CPUThreadManager::GetThread(u32 id) { - CPUThread* res; + std::shared_ptr res; if (!id) return nullptr; @@ -139,7 +133,7 @@ void CPUThreadManager::Exec() { std::lock_guard lock(m_mtx_thread); - for(u32 i=0; iExec(); } diff --git a/rpcs3/Emu/CPU/CPUThreadManager.h b/rpcs3/Emu/CPU/CPUThreadManager.h index d43a7506c3..e3fc1df32b 100644 --- a/rpcs3/Emu/CPU/CPUThreadManager.h +++ b/rpcs3/Emu/CPU/CPUThreadManager.h @@ -6,7 +6,7 @@ enum CPUThreadType : unsigned char; class CPUThreadManager { - std::vector m_threads; + std::vector> m_threads; std::mutex m_mtx_thread; public: @@ -18,9 +18,9 @@ public: CPUThread& AddThread(CPUThreadType type); void RemoveThread(const u32 id); - std::vector& GetThreads() { return m_threads; } + //std::vector>& GetThreads() { return m_threads; } s32 GetThreadNumById(CPUThreadType type, u32 id); - CPUThread* GetThread(u32 id); + std::shared_ptr GetThread(u32 id); RawSPUThread* GetRawSPUThread(u32 num); void Exec(); diff --git a/rpcs3/Emu/Cell/PPUDisAsm.h b/rpcs3/Emu/Cell/PPUDisAsm.h index 8a04164f2e..531b21bc37 100644 --- a/rpcs3/Emu/Cell/PPUDisAsm.h +++ b/rpcs3/Emu/Cell/PPUDisAsm.h @@ -1030,14 +1030,13 @@ private: Write(fmt::Format("bc [%x:%x:%x:%x:%x], cr%d[%x], 0x%x, %d, %d", bo0, bo1, bo2, bo3, bo4, bi/4, bi%4, bd, aa, lk)); } - void SC(u32 sc_code) + void SC(u32 lev) { - switch(sc_code) + switch (lev) { - case 0x1: Write("HyperCall"); break; - case 0x2: Write("sc"); break; - case 0x22: Write("HyperCall LV1"); break; - default: Write(fmt::Format("Unknown sc: 0x%x", sc_code)); + case 0x0: Write("sc"); break; + case 0x1: Write("HyperCall LV1"); break; + default: Write(fmt::Format("Unknown sc: 0x%x", lev)); } } void B(s32 ll, u32 aa, u32 lk) diff --git a/rpcs3/Emu/Cell/PPUInstrTable.h b/rpcs3/Emu/Cell/PPUInstrTable.h index 676f32fa79..c9f03c789d 100644 --- a/rpcs3/Emu/Cell/PPUInstrTable.h +++ b/rpcs3/Emu/Cell/PPUInstrTable.h @@ -162,8 +162,8 @@ namespace PPU_instr //This field mask is used to identify the CR fields that are to be updated by the mtcrf instruction. static CodeField<12, 19> CRM; - // - static CodeField<6, 31> SYS; + // This field is used to identify the system call level + static CodeField<20, 26> LEV; //Immediate field specifying a 16-bit signed two's complement integer that is sign-extended to 64 bits static CodeFieldSigned<16, 31> D; @@ -238,7 +238,7 @@ namespace PPU_instr bind_instr(main_list, ADDI, RD, RA, simm16); bind_instr(main_list, ADDIS, RD, RA, simm16); bind_instr(main_list, BC, BO, BI, BD, AA, LK); - bind_instr(main_list, SC, SYS); + bind_instr(main_list, SC, LEV); bind_instr(main_list, B, LI, AA, LK); bind_instr(main_list, RLWIMI, RA, RS, SH, MB, ME, RC); bind_instr(main_list, RLWINM, RA, RS, SH, MB, ME, RC); diff --git a/rpcs3/Emu/Cell/PPUInterpreter.h b/rpcs3/Emu/Cell/PPUInterpreter.h index 1fdfa88479..6349e52fd9 100644 --- a/rpcs3/Emu/Cell/PPUInterpreter.h +++ b/rpcs3/Emu/Cell/PPUInterpreter.h @@ -2164,13 +2164,13 @@ private: if(lk) CPU.LR = nextLR; } } - void SC(u32 sc_code) + void SC(u32 lev) { - switch(sc_code) + switch (lev) { - case 0x1: UNK(fmt::Format("HyperCall %d", CPU.GPR[0])); break; - case 0x2: SysCall(); break; - case 0x3: + case 0x0: SysCall(); break; + case 0x1: UNK("HyperCall LV1"); break; + case 0x2: Emu.GetSFuncManager().StaticExecute(CPU, (u32)CPU.GPR[11]); if (Ini.HLELogging.GetValue()) { @@ -2178,9 +2178,8 @@ private: Emu.GetSFuncManager()[CPU.GPR[11]]->name, CPU.GPR[3], CPU.PC); } break; - case 0x4: CPU.FastStop(); break; - case 0x22: UNK("HyperCall LV1"); break; - default: UNK(fmt::Format("Unknown sc: 0x%x", sc_code)); + case 0x3: CPU.FastStop(); break; + default: UNK(fmt::Format("Unknown sc: 0x%x", lev)); break; } } void B(s32 ll, u32 aa, u32 lk) @@ -3665,7 +3664,14 @@ private: void DCBZ(u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - auto const cache_line = vm::get_ptr(addr & ~127); + if ((u32)addr != addr) + { + LOG_ERROR(PPU, "%s(): invalid address (0x%llx)", __FUNCTION__, addr); + Emu.Pause(); + return; + } + + auto const cache_line = vm::get_ptr((u32)addr & ~127); if (cache_line) memset(cache_line, 0, 128); } diff --git a/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp b/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp index 34b2fb9c05..1451a80c27 100644 --- a/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp +++ b/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp @@ -1995,20 +1995,20 @@ void Compiler::BC(u32 bo, u32 bi, s32 bd, u32 aa, u32 lk) { CreateBranch(CheckBranchCondition(bo, bi), target_i32, lk ? true : false); } -void Compiler::SC(u32 sc_code) { - switch (sc_code) { - case 2: +void Compiler::SC(u32 lev) { + switch (lev) { + case 0: Call("SysCalls.DoSyscall", SysCalls::DoSyscall, m_state.args[CompileTaskState::Args::State], GetGpr(11)); break; - case 3: + case 2: Call("StaticFuncManager.StaticExecute", &StaticFuncManager::StaticExecute, m_ir_builder->getInt64((u64)&Emu.GetSFuncManager()), m_state.args[CompileTaskState::Args::State], GetGpr(11, 32)); break; - case 4: + case 3: Call("PPUThread.FastStop", &PPUThread::FastStop, m_state.args[CompileTaskState::Args::State]); break; default: - CompilationError(fmt::Format("SC %u", sc_code)); + CompilationError(fmt::Format("SC %u", lev)); break; } } diff --git a/rpcs3/Emu/Cell/PPUOpcodes.h b/rpcs3/Emu/Cell/PPUOpcodes.h index 9fbe5e8d79..39b9e08aa9 100644 --- a/rpcs3/Emu/Cell/PPUOpcodes.h +++ b/rpcs3/Emu/Cell/PPUOpcodes.h @@ -451,6 +451,8 @@ namespace PPU_opcodes class PPUOpcodes { public: + virtual ~PPUOpcodes() {} + static u32 branchTarget(const u32 pc, const u32 imm) { return pc + (imm & ~0x3ULL); @@ -628,7 +630,7 @@ public: virtual void ADDI(u32 rd, u32 ra, s32 simm16) = 0; virtual void ADDIS(u32 rd, u32 ra, s32 simm16) = 0; virtual void BC(u32 bo, u32 bi, s32 bd, u32 aa, u32 lk) = 0; - virtual void SC(u32 sc_code) = 0; + virtual void SC(u32 lev) = 0; virtual void B(s32 ll, u32 aa, u32 lk) = 0; virtual void MCRF(u32 crfd, u32 crfs) = 0; virtual void BCLR(u32 bo, u32 bi, u32 bh, u32 lk) = 0; diff --git a/rpcs3/Emu/Cell/SPUOpcodes.h b/rpcs3/Emu/Cell/SPUOpcodes.h index 1538accd18..dd8a99b082 100644 --- a/rpcs3/Emu/Cell/SPUOpcodes.h +++ b/rpcs3/Emu/Cell/SPUOpcodes.h @@ -229,6 +229,8 @@ namespace SPU_opcodes class SPUOpcodes { public: + virtual ~SPUOpcodes() {} + static u32 branchTarget(const u32 pc, const s32 imm) { return (pc + (imm << 2)) & 0x3fffc; diff --git a/rpcs3/Emu/Cell/SPURSManager.h b/rpcs3/Emu/Cell/SPURSManager.h index 001d244fa7..55bf5de181 100644 --- a/rpcs3/Emu/Cell/SPURSManager.h +++ b/rpcs3/Emu/Cell/SPURSManager.h @@ -1,7 +1,5 @@ #pragma once -#include "Emu/SysCalls/Modules/cellSpurs.h" - class SPURSManagerEventFlag { public: diff --git a/rpcs3/Emu/Cell/SPURecompilerCore.cpp b/rpcs3/Emu/Cell/SPURecompilerCore.cpp index c5edf35a7b..8d733bd8b4 100644 --- a/rpcs3/Emu/Cell/SPURecompilerCore.cpp +++ b/rpcs3/Emu/Cell/SPURecompilerCore.cpp @@ -25,7 +25,7 @@ SPURecompilerCore::SPURecompilerCore(SPUThread& cpu) memset(entry, 0, sizeof(entry)); X86CpuInfo inf; X86CpuUtil::detect(&inf); - if (!inf.hasFeature(kX86CpuFeatureSse41)) + if (!inf.hasFeature(kX86CpuFeatureSSE4_1)) { LOG_ERROR(SPU, "SPU JIT requires SSE4.1 instruction set support"); Emu.Pause(); diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index bc6d1d681f..c9f3fa6c5e 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -3,6 +3,7 @@ #include "Utilities/Log.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" +#include "Emu/Memory/atomic_type.h" #include "Emu/IdManager.h" #include "Emu/CPU/CPUThreadManager.h" @@ -37,6 +38,10 @@ SPUThread::SPUThread(CPUThreadType type) : PPCThread(type) assert(type == CPU_THREAD_SPU || type == CPU_THREAD_RAW_SPU); group = nullptr; + for (auto& p : SPUPs) + { + p.reset(new EventPort()); + } Reset(); } @@ -136,12 +141,12 @@ void SPUThread::DoClose() } for (u32 i = 0; i < 64; i++) { - EventPort& port = SPUPs[i]; - std::lock_guard lock(port.m_mutex); - if (port.eq) + std::shared_ptr port = SPUPs[i]; + std::lock_guard lock(port->m_mutex); + if (port->eq) { - port.eq->ports.remove(&port); - port.eq = nullptr; + port->eq->ports.remove(port); + port->eq = nullptr; } } } @@ -208,17 +213,17 @@ void SPUThread::ProcessCmd(u32 cmd, u32 tag, u32 lsa, u64 ea, u32 size) return; } - SPUThread* spu = (SPUThread*)Emu.GetCPU().GetThread(group->list[num]); + std::shared_ptr spu = Emu.GetCPU().GetThread(group->list[num]); u32 addr = (ea & SYS_SPU_THREAD_BASE_MASK) % SYS_SPU_THREAD_OFFSET; if ((addr <= 0x3ffff) && (addr + size <= 0x40000)) { // LS access - ea = spu->ls_offset + addr; + ea = ((SPUThread*)spu.get())->ls_offset + addr; } else if ((cmd & MFC_PUT_CMD) && size == 4 && (addr == SYS_SPU_THREAD_SNR1 || addr == SYS_SPU_THREAD_SNR2)) { - spu->WriteSNR(SYS_SPU_THREAD_SNR2 == addr, vm::read32(ls_offset + lsa)); + ((SPUThread*)spu.get())->WriteSNR(SYS_SPU_THREAD_SNR2 == addr, vm::read32(ls_offset + lsa)); return; } else @@ -587,7 +592,7 @@ void SPUThread::WriteChannel(u32 ch, const u128& r) if (Ini.HLELogging.GetValue()) LOG_NOTICE(Log::SPU, "SPU_WrOutIntrMbox: interrupt(v=0x%x)", v); while (!SPU.Out_IntrMBox.Push(v)) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack if (Emu.IsStopped()) { LOG_WARNING(Log::SPU, "%s(%s) aborted", __FUNCTION__, spu_ch_name[ch]); @@ -595,7 +600,7 @@ void SPUThread::WriteChannel(u32 ch, const u128& r) } } m_intrtag[2].stat |= 1; - if (CPUThread* t = Emu.GetCPU().GetThread(m_intrtag[2].thread)) + if (std::shared_ptr t = Emu.GetCPU().GetThread(m_intrtag[2].thread)) { if (t->GetType() == CPU_THREAD_PPU) { @@ -605,7 +610,7 @@ void SPUThread::WriteChannel(u32 ch, const u128& r) Emu.Pause(); return; } - PPUThread& ppu = *(PPUThread*)t; + PPUThread& ppu = *(PPUThread*)t.get(); ppu.GPR[3] = ppu.m_interrupt_arg; ppu.FastCall2(vm::read32(ppu.entry), vm::read32(ppu.entry + 4)); } @@ -632,18 +637,18 @@ void SPUThread::WriteChannel(u32 ch, const u128& r) LOG_NOTICE(Log::SPU, "sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x)", spup, v & 0x00ffffff, data); } - EventPort& port = SPUPs[spup]; + std::shared_ptr port = SPUPs[spup]; - std::lock_guard lock(port.m_mutex); + std::lock_guard lock(port->m_mutex); - if (!port.eq) + if (!port->eq) { LOG_WARNING(Log::SPU, "sys_spu_thread_send_event(spup=%d, data0=0x%x, data1=0x%x): event queue not connected", spup, (v & 0x00ffffff), data); SPU.In_MBox.PushUncond(CELL_ENOTCONN); // TODO: check error passing return; } - if (!port.eq->events.push(SYS_SPU_THREAD_EVENT_USER_KEY, GetId(), ((u64)spup << 32) | (v & 0x00ffffff), data)) + if (!port->eq->events.push(SYS_SPU_THREAD_EVENT_USER_KEY, GetId(), ((u64)spup << 32) | (v & 0x00ffffff), data)) { SPU.In_MBox.PushUncond(CELL_EBUSY); return; @@ -670,18 +675,18 @@ void SPUThread::WriteChannel(u32 ch, const u128& r) LOG_WARNING(Log::SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x)", spup, v & 0x00ffffff, data); } - EventPort& port = SPUPs[spup]; + std::shared_ptr port = SPUPs[spup]; - std::lock_guard lock(port.m_mutex); + std::lock_guard lock(port->m_mutex); - if (!port.eq) + if (!port->eq) { LOG_WARNING(Log::SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x): event queue not connected", spup, (v & 0x00ffffff), data); return; } // TODO: check passing spup value - if (!port.eq->events.push(SYS_SPU_THREAD_EVENT_USER_KEY, GetId(), ((u64)spup << 32) | (v & 0x00ffffff), data)) + if (!port->eq->events.push(SYS_SPU_THREAD_EVENT_USER_KEY, GetId(), ((u64)spup << 32) | (v & 0x00ffffff), data)) { LOG_WARNING(Log::SPU, "sys_spu_thread_throw_event(spup=%d, data0=0x%x, data1=0x%x) failed (queue is full)", spup, (v & 0x00ffffff), data); return; @@ -712,7 +717,7 @@ void SPUThread::WriteChannel(u32 ch, const u128& r) LOG_WARNING(Log::SPU, "sys_event_flag_set_bit(id=%d, v=0x%x (flag=%d))", data, v, flag); } - EventFlag* ef; + std::shared_ptr ef; if (!Emu.GetIdManager().GetIDData(data, ef)) { LOG_ERROR(Log::SPU, "sys_event_flag_set_bit(id=%d, v=0x%x (flag=%d)): EventFlag not found", data, v, flag); @@ -720,21 +725,13 @@ void SPUThread::WriteChannel(u32 ch, const u128& r) return; } - const u32 tid = GetId(); + std::lock_guard lock(ef->mutex); - ef->m_mutex.lock(tid); ef->flags |= (u64)1 << flag; if (u32 target = ef->check()) { - // if signal, leave both mutexes locked... - ef->signal.lock(target); - ef->m_mutex.unlock(tid, target); + ef->signal.push(target); } - else - { - ef->m_mutex.unlock(tid); - } - SPU.In_MBox.PushUncond(CELL_OK); return; } @@ -761,28 +758,20 @@ void SPUThread::WriteChannel(u32 ch, const u128& r) LOG_WARNING(Log::SPU, "sys_event_flag_set_bit_impatient(id=%d, v=0x%x (flag=%d))", data, v, flag); } - EventFlag* ef; + std::shared_ptr ef; if (!Emu.GetIdManager().GetIDData(data, ef)) { LOG_WARNING(Log::SPU, "sys_event_flag_set_bit_impatient(id=%d, v=0x%x (flag=%d)): EventFlag not found", data, v, flag); return; } - const u32 tid = GetId(); + std::lock_guard lock(ef->mutex); - ef->m_mutex.lock(tid); ef->flags |= (u64)1 << flag; if (u32 target = ef->check()) { - // if signal, leave both mutexes locked... - ef->signal.lock(target); - ef->m_mutex.unlock(tid, target); + ef->signal.push(target); } - else - { - ef->m_mutex.unlock(tid); - } - return; } else @@ -805,7 +794,10 @@ void SPUThread::WriteChannel(u32 ch, const u128& r) case SPU_WrOutMbox: { - while (!SPU.Out_MBox.Push(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); + while (!SPU.Out_MBox.Push(v) && !Emu.IsStopped()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + } break; } @@ -916,13 +908,19 @@ void SPUThread::ReadChannel(u128& r, u32 ch) { case SPU_RdInMbox: { - while (!SPU.In_MBox.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); + while (!SPU.In_MBox.Pop(v) && !Emu.IsStopped()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + } break; } case MFC_RdTagStat: { - while (!MFC1.TagStatus.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); + while (!MFC1.TagStatus.Pop(v) && !Emu.IsStopped()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + } break; } @@ -936,11 +934,17 @@ void SPUThread::ReadChannel(u128& r, u32 ch) { if (cfg.value & 1) { - while (!SPU.SNR[0].Pop_XCHG(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); + while (!SPU.SNR[0].Pop_XCHG(v) && !Emu.IsStopped()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + } } else { - while (!SPU.SNR[0].Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); + while (!SPU.SNR[0].Pop(v) && !Emu.IsStopped()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + } } break; } @@ -949,24 +953,36 @@ void SPUThread::ReadChannel(u128& r, u32 ch) { if (cfg.value & 2) { - while (!SPU.SNR[1].Pop_XCHG(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); + while (!SPU.SNR[1].Pop_XCHG(v) && !Emu.IsStopped()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + } } else { - while (!SPU.SNR[1].Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); + while (!SPU.SNR[1].Pop(v) && !Emu.IsStopped()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + } } break; } case MFC_RdAtomicStat: { - while (!MFC1.AtomicStat.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); + while (!MFC1.AtomicStat.Pop(v) && !Emu.IsStopped()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + } break; } case MFC_RdListStallStat: { - while (!StallStat.Pop(v) && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); + while (!StallStat.Pop(v) && !Emu.IsStopped()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + } break; } @@ -984,7 +1000,10 @@ void SPUThread::ReadChannel(u128& r, u32 ch) case SPU_RdEventStat: { - while (!CheckEvents() && !Emu.IsStopped()) std::this_thread::sleep_for(std::chrono::milliseconds(1)); + while (!CheckEvents() && !Emu.IsStopped()) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + } v = m_events & m_event_mask; break; } @@ -1057,7 +1076,7 @@ void SPUThread::StopAndSignal(u32 code) LOG_NOTICE(Log::SPU, "sys_spu_thread_receive_event(spuq=0x%x)", spuq); } - EventQueue* eq; + std::shared_ptr eq; if (!SPUQs.GetEventQueue(FIX_SPUQ(spuq), eq)) { SPU.In_MBox.PushUncond(CELL_EINVAL); // TODO: check error value @@ -1066,47 +1085,61 @@ void SPUThread::StopAndSignal(u32 code) u32 tid = GetId(); - eq->sq.push(tid); // add thread to sleep queue + eq->sq.push(tid, eq->protocol); // add thread to sleep queue while (true) { - switch (eq->owner.trylock(tid)) + u32 old_owner = eq->owner.compare_and_swap(0, tid); + + switch (s32 res = old_owner ? (old_owner == tid ? 1 : 2) : 0) { - case SMR_OK: - if (!eq->events.count()) + case 0: + { + const u32 next = eq->events.count() ? eq->sq.signal(eq->protocol) : 0; + if (next != tid) { - eq->owner.unlock(tid); + if (!eq->owner.compare_and_swap_test(tid, next)) + { + assert(!"sys_spu_thread_receive_event() failed (I)"); + } break; } - else - { - u32 next = (eq->protocol == SYS_SYNC_FIFO) ? eq->sq.pop() : eq->sq.pop_prio(); - if (next != tid) - { - eq->owner.unlock(tid, next); - break; - } - } - case SMR_SIGNAL: + // fallthrough + } + case 1: { sys_event_data event; eq->events.pop(event); - eq->owner.unlock(tid); + if (!eq->owner.compare_and_swap_test(tid, 0)) + { + assert(!"sys_spu_thread_receive_event() failed (II)"); + } SPU.In_MBox.PushUncond(CELL_OK); SPU.In_MBox.PushUncond((u32)event.data1); SPU.In_MBox.PushUncond((u32)event.data2); SPU.In_MBox.PushUncond((u32)event.data3); + if (!eq->sq.invalidate(tid, eq->protocol) && !eq->sq.pop(tid, eq->protocol)) + { + assert(!"sys_spu_thread_receive_event() failed (receiving)"); + } return; } - case SMR_FAILED: break; - default: eq->sq.invalidate(tid); SPU.In_MBox.PushUncond(CELL_ECANCELED); return; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + if (!~old_owner) + { + if (!eq->sq.invalidate(tid, eq->protocol)) + { + assert(!"sys_spu_thread_receive_event() failed (cancelling)"); + } + SPU.In_MBox.PushUncond(CELL_ECANCELED); + return; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack if (Emu.IsStopped()) { LOG_WARNING(Log::SPU, "sys_spu_thread_receive_event(spuq=0x%x) aborted", spuq); - eq->sq.invalidate(tid); return; } } @@ -1135,7 +1168,7 @@ void SPUThread::StopAndSignal(u32 code) group->m_exit_status = SPU.Out_MBox.GetValue(); for (auto& v : group->list) { - if (CPUThread* t = Emu.GetCPU().GetThread(v)) + if (std::shared_ptr t = Emu.GetCPU().GetThread(v)) { t->Stop(); } diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index 4bebaf1baf..323b5b25d2 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -1,10 +1,12 @@ #pragma once #include "Emu/Memory/atomic_type.h" #include "PPCThread.h" +#include "Emu/SysCalls/lv2/sleep_queue_type.h" +#include "Emu/SysCalls/lv2/sys_event.h" #include "Emu/Event.h" #include "MFC.h" -enum SPUchannels +enum SPUchannels { SPU_RdEventStat = 0, //Read event status with mask applied SPU_WrEventMask = 1, //Write event mask @@ -22,7 +24,7 @@ enum SPUchannels SPU_WrOutIntrMbox = 30, //Write outbound interrupt mailbox contents (interrupting PPU) }; -enum MFCchannels +enum MFCchannels { MFC_WrMSSyncReq = 9, //Write multisource synchronization request MFC_RdTagMask = 12, //Read tag mask @@ -281,9 +283,9 @@ public: u64 R_ADDR; // reservation address u64 R_DATA[16]; // lock line data (BE) - EventPort SPUPs[64]; // SPU Thread Event Ports + std::shared_ptr SPUPs[64]; // SPU Thread Event Ports EventManager SPUQs; // SPU Queue Mapping - SpuGroupInfo* group; // associated SPU Thread Group (null for raw spu) + std::shared_ptr group; // associated SPU Thread Group (null for raw spu) u64 m_dec_start; // timestamp of writing decrementer value u32 m_dec_value; // written decrementer value diff --git a/rpcs3/Emu/Event.cpp b/rpcs3/Emu/Event.cpp index 5dce5b6884..2f6be5f107 100644 --- a/rpcs3/Emu/Event.cpp +++ b/rpcs3/Emu/Event.cpp @@ -1,6 +1,9 @@ #include "stdafx.h" #include "Emu/Memory/Memory.h" -//#include "Emu/System.h" +#include "Emu/Memory/atomic_type.h" + +#include "Emu/SysCalls/lv2/sleep_queue_type.h" +#include "Emu/SysCalls/lv2/sys_event.h" #include "Event.h" void EventManager::Init() @@ -20,7 +23,7 @@ bool EventManager::CheckKey(u64 key) return key_map.find(key) != key_map.end(); } -bool EventManager::RegisterKey(EventQueue* data, u64 key) +bool EventManager::RegisterKey(std::shared_ptr& data, u64 key) { if (!key) return true; std::lock_guard lock(m_lock); @@ -37,7 +40,7 @@ bool EventManager::RegisterKey(EventQueue* data, u64 key) return true; } -bool EventManager::GetEventQueue(u64 key, EventQueue*& data) +bool EventManager::GetEventQueue(u64 key, std::shared_ptr& data) { data = nullptr; if (!key) return false; @@ -76,8 +79,7 @@ bool EventManager::SendEvent(u64 key, u64 source, u64 d1, u64 d2, u64 d3) { return false; } - EventQueue* eq = f->second; - - eq->events.push(source, d1, d2, d3); + + f->second->events.push(source, d1, d2, d3); return true; } diff --git a/rpcs3/Emu/Event.h b/rpcs3/Emu/Event.h index 31a33e3db5..eadcb533f3 100644 --- a/rpcs3/Emu/Event.h +++ b/rpcs3/Emu/Event.h @@ -1,18 +1,19 @@ #pragma once -#include "Emu/SysCalls/lv2/sys_event.h" #include +struct EventQueue; + class EventManager { std::mutex m_lock; - std::unordered_map key_map; + std::unordered_map> key_map; public: void Init(); void Clear(); bool CheckKey(u64 key); - bool RegisterKey(EventQueue* data, u64 key); - bool GetEventQueue(u64 key, EventQueue*& data); + bool RegisterKey(std::shared_ptr& data, u64 key); + bool GetEventQueue(u64 key, std::shared_ptr& data); bool UnregisterKey(u64 key); bool SendEvent(u64 key, u64 source, u64 d1, u64 d2, u64 d3); }; diff --git a/rpcs3/Emu/FS/VFS.cpp b/rpcs3/Emu/FS/VFS.cpp index d963d9c91f..01489759a6 100644 --- a/rpcs3/Emu/FS/VFS.cpp +++ b/rpcs3/Emu/FS/VFS.cpp @@ -32,21 +32,12 @@ std::string simplify_path(const std::string& path, bool is_dir) { std::vector path_blocks = simplify_path_blocks(path); - std::string result; - if (path_blocks.empty()) - return result; + return ""; - if (is_dir) - { - result = fmt::merge(path_blocks, "/"); - } - else - { - result = fmt::merge(std::vector(path_blocks.begin(), path_blocks.end() - 1), "/") + path_blocks[path_blocks.size() - 1]; - } + std::string result = fmt::merge(path_blocks, "/"); - return result; + return is_dir ? result + "/" : result; } VFS::~VFS() diff --git a/rpcs3/Emu/FS/vfsLocalFile.cpp b/rpcs3/Emu/FS/vfsLocalFile.cpp index aea1e02e0c..0e716c40af 100644 --- a/rpcs3/Emu/FS/vfsLocalFile.cpp +++ b/rpcs3/Emu/FS/vfsLocalFile.cpp @@ -75,7 +75,12 @@ bool vfsLocalFile::Create(const std::string& path) if(m != '/' && m != '\\' && !rExists(path)) // ??? { rFile f; - return f.Create(path); + if (!f.Create(path)) { + LOG_NOTICE(HLE, "vfsLocalFile::Create: couldn't create file"); + return false; + } + else + return true; } return true; diff --git a/rpcs3/Emu/GameInfo.h b/rpcs3/Emu/GameInfo.h index 2521599fda..0decbab7ac 100644 --- a/rpcs3/Emu/GameInfo.h +++ b/rpcs3/Emu/GameInfo.h @@ -4,6 +4,7 @@ struct GameInfo { std::string root; + std::string icon_path; std::string name; std::string serial; std::string app_ver; diff --git a/rpcs3/Emu/IdManager.h b/rpcs3/Emu/IdManager.h index a5ba1b1447..ef3c78aacd 100644 --- a/rpcs3/Emu/IdManager.h +++ b/rpcs3/Emu/IdManager.h @@ -48,14 +48,14 @@ public: m_destr(m_ptr); } - template T* get() + template std::shared_ptr get() { - return (T*)m_ptr; + return *(std::shared_ptr*)m_ptr; } - template const T* get() const + template std::shared_ptr get() const { - return (const T*)m_ptr; + return *(std::shared_ptr*)m_ptr; } }; @@ -67,11 +67,11 @@ class ID public: template - ID(const std::string& name, T* data, const IDType type) + ID(const std::string& name, std::shared_ptr& data, const IDType type) : m_name(name) , m_type(type) { - m_data = new IDData(data, [](void *ptr) -> void { delete (T*)ptr; }); + m_data = new IDData(new std::shared_ptr(data), [](void *ptr) -> void { delete (std::shared_ptr*)ptr; }); } ID() : m_data(nullptr) @@ -85,6 +85,7 @@ public: m_data = other.m_data; other.m_data = nullptr; } + ID& operator=(ID&& other) { std::swap(m_name,other.m_name); @@ -159,7 +160,7 @@ public: = char #endif > - u32 GetNewID(const std::string& name = "", T* data = nullptr, const IDType type = TYPE_OTHER) + u32 GetNewID(const std::string& name = "", std::shared_ptr& data = nullptr, const IDType type = TYPE_OTHER) { std::lock_guard lock(m_mtx_main); @@ -179,7 +180,7 @@ public: } template - bool GetIDData(const u32 id, T*& result) + bool GetIDData(const u32 id, std::shared_ptr& result) { std::lock_guard lock(m_mtx_main); @@ -226,15 +227,32 @@ public: u32 GetTypeCount(IDType type) { - if (type < TYPE_OTHER) { + std::lock_guard lock(m_mtx_main); + + if (type < TYPE_OTHER) + { return (u32)m_types[type].size(); } - return 1; + else + { + assert(!"Invalid ID type"); + return 0; + } } - const std::set& GetTypeIDs(IDType type) + std::set GetTypeIDs(IDType type) { - assert(type < TYPE_OTHER); - return m_types[type]; + // you cannot simply return reference to existing set + std::lock_guard lock(m_mtx_main); + + if (type < TYPE_OTHER) + { + return m_types[type]; + } + else + { + assert(!"Invalid ID type"); + return{}; + } } }; diff --git a/rpcs3/Emu/Memory/Memory.cpp b/rpcs3/Emu/Memory/Memory.cpp index ddb837d725..9aa328b14e 100644 --- a/rpcs3/Emu/Memory/Memory.cpp +++ b/rpcs3/Emu/Memory/Memory.cpp @@ -170,36 +170,28 @@ void MemoryBase::Close() MemoryBlocks.clear(); } -void MemoryBase::WriteMMIO32(u32 addr, const u32 data) +bool MemoryBase::WriteMMIO32(u32 addr, const u32 data) { - { - LV2_LOCK(0); + LV2_LOCK(0); - if (RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET] && - ((RawSPUThread*)RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET])->Write32(addr, data)) - { - return; - } + if (RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET] && ((RawSPUThread*)RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET])->Write32(addr, data)) + { + return true; } - *(u32*)((u8*)GetBaseAddr() + addr) = re32(data); // provoke error + return false; } -u32 MemoryBase::ReadMMIO32(u32 addr) +bool MemoryBase::ReadMMIO32(u32 addr, u32& res) { - u32 res; - { - LV2_LOCK(0); + LV2_LOCK(0); - if (RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET] && - ((RawSPUThread*)RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET])->Read32(addr, &res)) - { - return res; - } + if (RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET] && ((RawSPUThread*)RawSPUMem[(addr - RAW_SPU_BASE_ADDR) / RAW_SPU_OFFSET])->Read32(addr, &res)) + { + return true; } - res = re32(*(u32*)((u8*)GetBaseAddr() + addr)); // provoke error - return res; + return false; } bool MemoryBase::Map(const u64 addr, const u32 size) diff --git a/rpcs3/Emu/Memory/Memory.h b/rpcs3/Emu/Memory/Memory.h index 1fccab32b8..069e7a8609 100644 --- a/rpcs3/Emu/Memory/Memory.h +++ b/rpcs3/Emu/Memory/Memory.h @@ -127,9 +127,9 @@ public: void Close(); - __noinline void WriteMMIO32(u32 addr, const u32 data); + __noinline bool WriteMMIO32(u32 addr, const u32 data); - __noinline u32 ReadMMIO32(u32 addr); + __noinline bool ReadMMIO32(u32 addr, u32& res); u32 GetUserMemTotalSize() { diff --git a/rpcs3/Emu/Memory/vm.h b/rpcs3/Emu/Memory/vm.h index 87d173bbb5..ed78cf54c2 100644 --- a/rpcs3/Emu/Memory/vm.h +++ b/rpcs3/Emu/Memory/vm.h @@ -64,26 +64,20 @@ namespace vm static u32 read32(u32 addr) { - if (addr < RAW_SPU_BASE_ADDR || (addr % RAW_SPU_OFFSET) < RAW_SPU_PROB_OFFSET) + u32 res; + if (addr < RAW_SPU_BASE_ADDR || (addr % RAW_SPU_OFFSET) < RAW_SPU_PROB_OFFSET || !Memory.ReadMMIO32((u32)addr, res)) { - return re32(*(u32*)((u8*)g_base_addr + addr)); - } - else - { - return Memory.ReadMMIO32((u32)addr); + res = re32(*(u32*)((u8*)g_base_addr + addr)); } + return res; } static void write32(u32 addr, be_t value) { - if (addr < RAW_SPU_BASE_ADDR || (addr % RAW_SPU_OFFSET) < RAW_SPU_PROB_OFFSET) + if (addr < RAW_SPU_BASE_ADDR || (addr % RAW_SPU_OFFSET) < RAW_SPU_PROB_OFFSET || !Memory.WriteMMIO32((u32)addr, value)) { *(be_t*)((u8*)g_base_addr + addr) = value; } - else - { - Memory.WriteMMIO32((u32)addr, value); - } } static u64 read64(u32 addr) diff --git a/rpcs3/Emu/Memory/vm_ptr.h b/rpcs3/Emu/Memory/vm_ptr.h index 0970ad7996..60ae33900b 100644 --- a/rpcs3/Emu/Memory/vm_ptr.h +++ b/rpcs3/Emu/Memory/vm_ptr.h @@ -67,12 +67,12 @@ namespace vm __forceinline _ptr_base::value, typename to_be_t::type, AT>>& operator *() const { - return vm::get_ref<_ptr_base::value, typename to_be_t::type, AT>>>(m_addr); + return vm::get_ref<_ptr_base::value, typename to_be_t::type, AT>>>((u32)m_addr); } __forceinline _ptr_base::value, typename to_be_t::type, AT>>& operator [](AT index) const { - return vm::get_ref<_ptr_base::value, typename to_be_t::type, AT>>>(m_addr + sizeof(AT)* index); + return vm::get_ref<_ptr_base::value, typename to_be_t::type, AT>>>((u32)(m_addr + sizeof(AT)* index)); } //typedef typename invert_be_t::type AT2; @@ -160,17 +160,17 @@ namespace vm __forceinline T& operator *() const { - return vm::get_ref(m_addr); + return vm::get_ref((u32)m_addr); } __forceinline T& operator [](typename remove_be_t::type index) const { - return vm::get_ref(m_addr + sizeof(T)* index); + return vm::get_ref((u32)(m_addr + sizeof(T) * index)); } __forceinline T& operator [](typename to_be_t::forced_type index) const { - return vm::get_ref(m_addr + sizeof(T)* index); + return vm::get_ref((u32)(m_addr + sizeof(T)* index)); } __forceinline bool operator <(const _ptr_base& right) const { return m_addr < right.m_addr; } @@ -224,7 +224,7 @@ namespace vm T* get_ptr() const { - return vm::get_ptr(m_addr); + return vm::get_ptr((u32)m_addr); } static _ptr_base make(AT addr) @@ -356,9 +356,9 @@ namespace vm public: typedef RT(*type)(T...); - RT call(CPUThread& CPU, T... args) const; // call using specified CPU thread context, defined in CB_FUNC.h + RT call(CPUThread& CPU, T... args) const; // defined in CB_FUNC.h, call using specified CPU thread context - RT operator()(T... args) const; // call using current CPU thread context, defined in CB_FUNC.h + RT operator()(T... args) const; // defined in CB_FUNC.h, call using current CPU thread context AT addr() const { diff --git a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp index 0c65d26982..bca4dbc7c0 100644 --- a/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp +++ b/rpcs3/Emu/RSX/GL/GLFragmentProgram.cpp @@ -6,9 +6,9 @@ void GLFragmentDecompilerThread::SetDst(std::string code, bool append_mask) { - if(!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt) return; + if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt) return; - switch(src1.scale) + switch (src1.scale) { case 0: break; case 1: code = "(" + code + " * 2.0)"; break; @@ -21,27 +21,39 @@ void GLFragmentDecompilerThread::SetDst(std::string code, bool append_mask) default: LOG_ERROR(RSX, "Bad scale: %d", fmt::by_value(src1.scale)); Emu.Pause(); - break; + break; } - if(dst.saturate) + if (dst.saturate) { code = "clamp(" + code + ", 0.0, 1.0)"; } - std::string dest; + code += (append_mask ? "$m" : ""); + + if (dst.no_dest) + { + if (dst.set_cond) + { + AddCode("$ifcond " + m_parr.AddParam(PARAM_NONE, "vec4", "cc" + std::to_string(src0.cond_mod_reg_index)) + "$m = " + code + ";"); + } + else + { + AddCode("$ifcond " + code + ";"); + } + + return; + } + + std::string dest = AddReg(dst.dest_reg, dst.fp16) + "$m"; + + AddCodeCond(Format(dest), code); + //AddCode("$ifcond " + dest + code + (append_mask ? "$m;" : ";")); if (dst.set_cond) { - dest += m_parr.AddParam(PARAM_NONE, "vec4", "cc" + std::to_string(src0.cond_mod_reg_index)) + "$m = "; + AddCode(m_parr.AddParam(PARAM_NONE, "vec4", "cc" + std::to_string(src0.cond_mod_reg_index)) + "$m = " + dest + ";"); } - - if (!dst.no_dest) - { - dest += AddReg(dst.dest_reg, dst.fp16) + "$m = "; - } - - AddCode("$ifcond " + dest + code + (append_mask ? "$m;" : ";")); } void GLFragmentDecompilerThread::AddCode(const std::string& code) @@ -58,17 +70,17 @@ std::string GLFragmentDecompilerThread::GetMask() 'x', 'y', 'z', 'w', }; - if(dst.mask_x) ret += dst_mask[0]; - if(dst.mask_y) ret += dst_mask[1]; - if(dst.mask_z) ret += dst_mask[2]; - if(dst.mask_w) ret += dst_mask[3]; + if (dst.mask_x) ret += dst_mask[0]; + if (dst.mask_y) ret += dst_mask[1]; + if (dst.mask_z) ret += dst_mask[2]; + if (dst.mask_w) ret += dst_mask[3]; return ret.empty() || strncmp(ret.c_str(), dst_mask, 4) == 0 ? "" : ("." + ret); } std::string GLFragmentDecompilerThread::AddReg(u32 index, int fp16) { - return m_parr.AddParam(PARAM_NONE, "vec4", std::string(fp16 ? "h" : "r") + std::to_string(index), "vec4(0.0, 0.0, 0.0, 0.0)"); + return m_parr.AddParam(PARAM_NONE, "vec4", std::string(fp16 ? "h" : "r") + std::to_string(index), "vec4(0.0)"); } bool GLFragmentDecompilerThread::HasReg(u32 index, int fp16) @@ -79,13 +91,13 @@ bool GLFragmentDecompilerThread::HasReg(u32 index, int fp16) std::string GLFragmentDecompilerThread::AddCond() { - return m_parr.AddParam(PARAM_NONE , "vec4", "cc" + std::to_string(src0.cond_reg_index)); + return m_parr.AddParam(PARAM_NONE, "vec4", "cc" + std::to_string(src0.cond_reg_index)); } std::string GLFragmentDecompilerThread::AddConst() { std::string name = std::string("fc") + std::to_string(m_size + 4 * 4); - if(m_parr.HasParam(PARAM_UNIFORM, "vec4", name)) + if (m_parr.HasParam(PARAM_UNIFORM, "vec4", name)) { return name; } @@ -118,11 +130,11 @@ std::string GLFragmentDecompilerThread::Format(const std::string& code) { "$t", std::bind(std::mem_fn(&GLFragmentDecompilerThread::AddTex), this) }, { "$m", std::bind(std::mem_fn(&GLFragmentDecompilerThread::GetMask), this) }, { "$ifcond ", [this]() -> std::string - { - const std::string& cond = GetCond(); - if (cond == "true") return ""; - return "if(" + cond + ") "; - } + { + const std::string& cond = GetCond(); + if (cond == "true") return ""; + return "if(" + cond + ") "; + } }, { "$cond", std::bind(std::mem_fn(&GLFragmentDecompilerThread::GetCond), this) }, { "$c", std::bind(std::mem_fn(&GLFragmentDecompilerThread::AddConst), this) } @@ -179,15 +191,83 @@ std::string GLFragmentDecompilerThread::GetCond() return "any(" + cond + "(" + AddCond() + swizzle + ", vec4(0.0)))"; } +void GLFragmentDecompilerThread::AddCodeCond(const std::string& dst, const std::string& src) +{ + if (src0.exec_if_gr && src0.exec_if_lt && src0.exec_if_eq) + { + AddCode(dst + " = " + src + ";"); + return; + } + + if (!src0.exec_if_gr && !src0.exec_if_lt && !src0.exec_if_eq) + { + AddCode("//" + dst + " = " + src + ";"); + return; + } + + static const char f[4] = { 'x', 'y', 'z', 'w' }; + + std::string swizzle, cond; + swizzle += f[src0.cond_swizzle_x]; + swizzle += f[src0.cond_swizzle_y]; + swizzle += f[src0.cond_swizzle_z]; + swizzle += f[src0.cond_swizzle_w]; + swizzle = swizzle == "xyzw" ? "" : "." + swizzle; + + if (src0.exec_if_gr && src0.exec_if_eq) + { + cond = "greaterThanEqual"; + } + else if (src0.exec_if_lt && src0.exec_if_eq) + { + cond = "lessThanEqual"; + } + else if (src0.exec_if_gr && src0.exec_if_lt) + { + cond = "notEqual"; + } + else if (src0.exec_if_gr) + { + cond = "greaterThan"; + } + else if (src0.exec_if_lt) + { + cond = "lessThan"; + } + else //if(src0.exec_if_eq) + { + cond = "equal"; + } + + cond = cond + "(" + AddCond() + swizzle + ", vec4(0.0))"; + + ShaderVar dst_var(dst); + dst_var.symplify(); + + //const char *c_mask = f; + + if (dst_var.swizzles[0].length() == 1) + { + AddCode("if (" + cond + ".x) " + dst + " = vec4(" + src + ").x;"); + } + else + { + for (int i = 0; i < dst_var.swizzles[0].length(); ++i) + { + AddCode("if (" + cond + "." + f[i] + ") " + dst + "." + f[i] + " = " + src + "." + f[i] + ";"); + } + } +} + template std::string GLFragmentDecompilerThread::GetSRC(T src) { std::string ret; - switch(src.reg_type) + switch (src.reg_type) { case 0: //tmp ret += AddReg(src.tmp_reg_index, src.fp16); - break; + break; case 1: //input { @@ -200,11 +280,11 @@ template std::string GLFragmentDecompilerThread::GetSRC(T src) "ssa" }; - switch(dst.src_attr_reg_num) + switch (dst.src_attr_reg_num) { case 0x00: ret += reg_table[0]; break; default: - if(dst.src_attr_reg_num < sizeof(reg_table)/sizeof(reg_table[0])) + if (dst.src_attr_reg_num < sizeof(reg_table) / sizeof(reg_table[0])) { ret += m_parr.AddParam(PARAM_IN, "vec4", reg_table[dst.src_attr_reg_num]); } @@ -214,22 +294,22 @@ template std::string GLFragmentDecompilerThread::GetSRC(T src) ret += m_parr.AddParam(PARAM_IN, "vec4", "unk"); Emu.Pause(); } - break; + break; } } break; case 2: //const ret += AddConst(); - break; + break; default: LOG_ERROR(RSX, "Bad src type %d", fmt::by_value(src.reg_type)); Emu.Pause(); - break; + break; } - static const char f[4] = {'x', 'y', 'z', 'w'}; + static const char f[4] = { 'x', 'y', 'z', 'w' }; std::string swizzle = ""; swizzle += f[src.swizzle_x]; @@ -237,10 +317,10 @@ template std::string GLFragmentDecompilerThread::GetSRC(T src) swizzle += f[src.swizzle_z]; swizzle += f[src.swizzle_w]; - if(strncmp(swizzle.c_str(), f, 4) != 0) ret += "." + swizzle; + if (strncmp(swizzle.c_str(), f, 4) != 0) ret += "." + swizzle; - if(src.abs) ret = "abs(" + ret + ")"; - if(src.neg) ret = "-" + ret; + if (src.abs) ret = "abs(" + ret + ")"; + if (src.neg) ret = "-" + ret; return ret; } @@ -251,10 +331,9 @@ std::string GLFragmentDecompilerThread::BuildCode() const std::pair table[] = { { "ocol0", m_ctrl & 0x40 ? "r0" : "h0" }, - { "ocol1", m_ctrl & 0x40 ? "r2" : "h2" }, - { "ocol2", m_ctrl & 0x40 ? "r3" : "h4" }, - { "ocol3", m_ctrl & 0x40 ? "r4" : "h6" }, - { "ocol4", m_ctrl & 0x40 ? "r5" : "h8" }, + { "ocol1", m_ctrl & 0x40 ? "r2" : "h4" }, + { "ocol2", m_ctrl & 0x40 ? "r3" : "h6" }, + { "ocol3", m_ctrl & 0x40 ? "r4" : "h8" }, }; for (int i = 0; i < sizeof(table) / sizeof(*table); ++i) @@ -263,7 +342,7 @@ std::string GLFragmentDecompilerThread::BuildCode() AddCode(m_parr.AddParam(PARAM_OUT, "vec4", table[i].first, i) + " = " + table[i].second + ";"); } - if (m_ctrl & 0xe) main += "\tgl_FragDepth = r1.z;\n"; + if (m_ctrl & 0xe) main += m_ctrl & 0x40 ? "\tgl_FragDepth = r1.z;\n" : "\tgl_FragDepth = h2.z;\n"; std::string p; @@ -285,7 +364,16 @@ void GLFragmentDecompilerThread::Task() m_loop_count = 0; m_code_level = 1; - while(true) + enum + { + FORCE_NONE, + FORCE_SCT, + FORCE_SCB, + }; + + int forced_unit = FORCE_NONE; + + while (true) { for (auto finded = std::find(m_end_offsets.begin(), m_end_offsets.end(), m_size); finded != m_end_offsets.end(); @@ -318,126 +406,201 @@ void GLFragmentDecompilerThread::Task() const u32 opcode = dst.opcode | (src1.opcode_is_branch << 6); - switch(opcode) + auto SCT = [&]() + { + switch (opcode) + { + case RSX_FP_OPCODE_ADD: SetDst("($0 + $1)"); break; + case RSX_FP_OPCODE_DIV: SetDst("($0 / $1)"); break; + case RSX_FP_OPCODE_DIVSQ: SetDst("($0 / sqrt($1))"); break; + case RSX_FP_OPCODE_DP2: SetDst("vec4(dot($0.xy, $1.xy))"); break; + case RSX_FP_OPCODE_DP3: SetDst("vec4(dot($0.xyz, $1.xyz))"); break; + case RSX_FP_OPCODE_DP4: SetDst("vec4(dot($0, $1))"); break; + case RSX_FP_OPCODE_DP2A: SetDst("vec4($0.x * $1.x + $0.y * $1.y + $2.x)"); break; + case RSX_FP_OPCODE_MAD: SetDst("($0 * $1 + $2)"); break; + case RSX_FP_OPCODE_MAX: SetDst("max($0, $1)"); break; + case RSX_FP_OPCODE_MIN: SetDst("min($0, $1)"); break; + case RSX_FP_OPCODE_MOV: SetDst("$0"); break; + case RSX_FP_OPCODE_MUL: SetDst("($0 * $1)"); break; + case RSX_FP_OPCODE_RCP: SetDst("1 / $0"); break; + case RSX_FP_OPCODE_RSQ: SetDst("inversesqrt(abs($0))"); break; + case RSX_FP_OPCODE_SEQ: SetDst("vec4(equal($0, $1))"); break; + case RSX_FP_OPCODE_SFL: SetDst("vec4(0.0)"); break; + case RSX_FP_OPCODE_SGE: SetDst("vec4(greaterThanEqual($0, $1))"); break; + case RSX_FP_OPCODE_SGT: SetDst("vec4(greaterThan($0, $1))"); break; + case RSX_FP_OPCODE_SLE: SetDst("vec4(lessThanEqual($0, $1))"); break; + case RSX_FP_OPCODE_SLT: SetDst("vec4(lessThan($0, $1))"); break; + case RSX_FP_OPCODE_SNE: SetDst("vec4(notEqual($0, $1))"); break; + case RSX_FP_OPCODE_STR: SetDst("vec4(1.0)"); break; + + default: + return false; + } + + return true; + }; + + auto SCB = [&]() + { + switch (opcode) + { + case RSX_FP_OPCODE_ADD: SetDst("($0 + $1)"); break; + case RSX_FP_OPCODE_COS: SetDst("cos($0)"); break; + case RSX_FP_OPCODE_DP2: SetDst("vec4(dot($0.xy, $1.xy))"); break; + case RSX_FP_OPCODE_DP3: SetDst("vec4(dot($0.xyz, $1.xyz))"); break; + case RSX_FP_OPCODE_DP4: SetDst("vec4(dot($0, $1))"); break; + case RSX_FP_OPCODE_DP2A: SetDst("vec4($0.x * $1.x + $0.y * $1.y + $2.x)"); break; + case RSX_FP_OPCODE_DST: SetDst("vec4(distance($0, $1))"); break; + case RSX_FP_OPCODE_REFL: LOG_ERROR(RSX, "Unimplemented SCB instruction: REFL"); break; // TODO: Is this in the right category? + case RSX_FP_OPCODE_EX2: SetDst("exp2($0)"); break; + case RSX_FP_OPCODE_FLR: SetDst("floor($0)"); break; + case RSX_FP_OPCODE_FRC: SetDst("fract($0)"); break; + case RSX_FP_OPCODE_LIT: SetDst("vec4(1.0, $0.x, ($0.x > 0.0 ? exp($0.w * log2($0.y)) : 0.0), 1.0)"); break; + case RSX_FP_OPCODE_LIF: SetDst("vec4(1.0, $0.y, ($0.y > 0 ? pow(2.0, $0.w) : 0.0), 1.0)"); break; + case RSX_FP_OPCODE_LRP: LOG_ERROR(RSX, "Unimplemented SCB instruction: LRP"); break; // TODO: Is this in the right category? + case RSX_FP_OPCODE_LG2: SetDst("log2($0)"); break; + case RSX_FP_OPCODE_MAD: SetDst("($0 * $1 + $2)"); break; + case RSX_FP_OPCODE_MAX: SetDst("max($0, $1)"); break; + case RSX_FP_OPCODE_MIN: SetDst("min($0, $1)"); break; + case RSX_FP_OPCODE_MOV: SetDst("$0"); break; + case RSX_FP_OPCODE_MUL: SetDst("($0 * $1)"); break; + case RSX_FP_OPCODE_PK2: SetDst("packSnorm2x16($0)"); break; // TODO: More testing (Sonic The Hedgehog (NPUB-30442/NPEB-00478)) + case RSX_FP_OPCODE_PK4: SetDst("packSnorm4x8($0)"); break; // TODO: More testing (Sonic The Hedgehog (NPUB-30442/NPEB-00478)) + case RSX_FP_OPCODE_PK16: LOG_ERROR(RSX, "Unimplemented SCB instruction: PK16"); break; + case RSX_FP_OPCODE_PKB: LOG_ERROR(RSX, "Unimplemented SCB instruction: PKB"); break; + case RSX_FP_OPCODE_PKG: LOG_ERROR(RSX, "Unimplemented SCB instruction: PKG"); break; + case RSX_FP_OPCODE_SEQ: SetDst("vec4(equal($0, $1))"); break; + case RSX_FP_OPCODE_SFL: SetDst("vec4(0.0)"); break; + case RSX_FP_OPCODE_SGE: SetDst("vec4(greaterThanEqual($0, $1))"); break; + case RSX_FP_OPCODE_SGT: SetDst("vec4(greaterThan($0, $1))"); break; + case RSX_FP_OPCODE_SIN: SetDst("sin($0)"); break; + case RSX_FP_OPCODE_SLE: SetDst("vec4(lessThanEqual($0, $1))"); break; + case RSX_FP_OPCODE_SLT: SetDst("vec4(lessThan($0, $1))"); break; + case RSX_FP_OPCODE_SNE: SetDst("vec4(notEqual($0, $1))"); break; + case RSX_FP_OPCODE_STR: SetDst("vec4(1.0)"); break; + + default: + return false; + } + + return true; + }; + + auto TEX_SRB = [&]() + { + switch (opcode) + { + case RSX_FP_OPCODE_DDX: SetDst("dFdx($0)"); break; + case RSX_FP_OPCODE_DDY: SetDst("dFdy($0)"); break; + case RSX_FP_OPCODE_NRM: SetDst("normalize($0)"); break; + case RSX_FP_OPCODE_BEM: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: BEM"); break; + case RSX_FP_OPCODE_TEX: SetDst("texture($t, $0.xy)"); break; + case RSX_FP_OPCODE_TEXBEM: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: TEXBEM"); break; + case RSX_FP_OPCODE_TXP: SetDst("textureProj($t, $0.xy, $1)"); break; //TODO: More testing (Sonic The Hedgehog (NPUB-30442/NPEB-00478) and The Simpsons Arcade Game (NPUB30563)) + case RSX_FP_OPCODE_TXPBEM: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: TXPBEM"); break; + case RSX_FP_OPCODE_TXD: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: TXD"); break; + case RSX_FP_OPCODE_TXB: SetDst("texture($t, $0.xy, $1.x)"); break; + case RSX_FP_OPCODE_TXL: SetDst("textureLod($t, $0.xy, $1.x)"); break; + case RSX_FP_OPCODE_UP2: SetDst("unpackSnorm2x16($0)"); break; // TODO: More testing (Sonic The Hedgehog (NPUB-30442/NPEB-00478)) + case RSX_FP_OPCODE_UP4: SetDst("unpackSnorm4x8($0)"); break; // TODO: More testing (Sonic The Hedgehog (NPUB-30442/NPEB-00478)) + case RSX_FP_OPCODE_UP16: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: UP16"); break; + case RSX_FP_OPCODE_UPB: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: UPB"); break; + case RSX_FP_OPCODE_UPG: LOG_ERROR(RSX, "Unimplemented TEX_SRB instruction: UPG"); break; + + default: + return false; + } + + return true; + }; + + auto SIP = [&]() + { + switch (opcode) + { + case RSX_FP_OPCODE_BRK: SetDst("break"); break; + case RSX_FP_OPCODE_CAL: LOG_ERROR(RSX, "Unimplemented SIP instruction: CAL"); break; + case RSX_FP_OPCODE_FENCT: forced_unit = FORCE_SCT; break; + case RSX_FP_OPCODE_FENCB: forced_unit = FORCE_SCB; break; + case RSX_FP_OPCODE_IFE: + AddCode("if($cond)"); + m_else_offsets.push_back(src1.else_offset << 2); + m_end_offsets.push_back(src2.end_offset << 2); + AddCode("{"); + m_code_level++; + break; + case RSX_FP_OPCODE_LOOP: + if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt) + { + AddCode(fmt::Format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) {} //-> %u //LOOP", + m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment, src2.end_offset)); + } + else + { + AddCode(fmt::Format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) //LOOP", + m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment)); + m_loop_count++; + m_end_offsets.push_back(src2.end_offset << 2); + AddCode("{"); + m_code_level++; + } + break; + case RSX_FP_OPCODE_REP: + if (!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt) + { + AddCode(fmt::Format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) {} //-> %u //REP", + m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment, src2.end_offset)); + } + else + { + AddCode(fmt::Format("if($cond) for(int i%u = %u; i%u < %u; i%u += %u) //REP", + m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment)); + m_loop_count++; + m_end_offsets.push_back(src2.end_offset << 2); + AddCode("{"); + m_code_level++; + } + break; + case RSX_FP_OPCODE_RET: SetDst("return"); break; + + default: + return false; + } + + return true; + }; + + switch (opcode) { case RSX_FP_OPCODE_NOP: break; - case RSX_FP_OPCODE_MOV: SetDst("$0"); break; - case RSX_FP_OPCODE_MUL: SetDst("($0 * $1)"); break; - case RSX_FP_OPCODE_ADD: SetDst("($0 + $1)"); break; - case RSX_FP_OPCODE_MAD: SetDst("($0 * $1 + $2)"); break; - case RSX_FP_OPCODE_DP3: SetDst("vec4(dot($0.xyz, $1.xyz))"); break; - case RSX_FP_OPCODE_DP4: SetDst("vec4(dot($0, $1))"); break; - case RSX_FP_OPCODE_DST: SetDst("vec4(distance($0, $1))"); break; - case RSX_FP_OPCODE_MIN: SetDst("min($0, $1)"); break; - case RSX_FP_OPCODE_MAX: SetDst("max($0, $1)"); break; - case RSX_FP_OPCODE_SLT: SetDst("vec4(lessThan($0, $1))"); break; - case RSX_FP_OPCODE_SGE: SetDst("vec4(greaterThanEqual($0, $1))"); break; - case RSX_FP_OPCODE_SLE: SetDst("vec4(lessThanEqual($0, $1))"); break; - case RSX_FP_OPCODE_SGT: SetDst("vec4(greaterThan($0, $1))"); break; - case RSX_FP_OPCODE_SNE: SetDst("vec4(notEqual($0, $1))"); break; - case RSX_FP_OPCODE_SEQ: SetDst("vec4(equal($0, $1))"); break; - - case RSX_FP_OPCODE_FRC: SetDst("fract($0)"); break; - case RSX_FP_OPCODE_FLR: SetDst("floor($0)"); break; case RSX_FP_OPCODE_KIL: SetDst("discard", false); break; - //case RSX_FP_OPCODE_PK4: break; - //case RSX_FP_OPCODE_UP4: break; - case RSX_FP_OPCODE_DDX: SetDst("dFdx($0)"); break; - case RSX_FP_OPCODE_DDY: SetDst("dFdy($0)"); break; - case RSX_FP_OPCODE_TEX: SetDst("texture($t, $0.xy)"); break; - //case RSX_FP_OPCODE_TXP: break; - //case RSX_FP_OPCODE_TXD: break; - case RSX_FP_OPCODE_RCP: SetDst("(1 / $0)"); break; - case RSX_FP_OPCODE_RSQ: SetDst("inversesqrt(abs($0))"); break; - case RSX_FP_OPCODE_EX2: SetDst("exp2($0)"); break; - case RSX_FP_OPCODE_LG2: SetDst("log2($0)"); break; - case RSX_FP_OPCODE_LIT: SetDst("vec4(1.0, $0.x, ($0.x > 0 ? exp2($0.w * log2($0.y)) : 0.0), 1.0)"); break; - case RSX_FP_OPCODE_LRP: SetDst("($0 * ($1 - $2) + $2)"); break; - - case RSX_FP_OPCODE_STR: SetDst("vec4(equal($0, vec4(1.0)))"); break; - case RSX_FP_OPCODE_SFL: SetDst("vec4(equal($0, vec4(0.0)))"); break; - case RSX_FP_OPCODE_COS: SetDst("cos($0)"); break; - case RSX_FP_OPCODE_SIN: SetDst("sin($0)"); break; - //case RSX_FP_OPCODE_PK2: break; - //case RSX_FP_OPCODE_UP2: break; - case RSX_FP_OPCODE_POW: SetDst("pow($0, $1)"); break; - //case RSX_FP_OPCODE_PKB: break; - //case RSX_FP_OPCODE_UPB: break; - //case RSX_FP_OPCODE_PK16: break; - //case RSX_FP_OPCODE_UP16: break; - //case RSX_FP_OPCODE_BEM: break; - //case RSX_FP_OPCODE_PKG: break; - //case RSX_FP_OPCODE_UPG: break; - case RSX_FP_OPCODE_DP2A: SetDst("($0.x * $1.x + $0.y * $1.y + $2.x)"); break; - //case RSX_FP_OPCODE_TXL: break; - - //case RSX_FP_OPCODE_TXB: break; - //case RSX_FP_OPCODE_TEXBEM: break; - //case RSX_FP_OPCODE_TXPBEM: break; - //case RSX_FP_OPCODE_BEMLUM: break; - case RSX_FP_OPCODE_REFL: SetDst("($0 - 2.0 * $1 * dot($0, $1))"); break; - //case RSX_FP_OPCODE_TIMESWTEX: break; - case RSX_FP_OPCODE_DP2: SetDst("vec4(dot($0.xy, $1.xy))"); break; - case RSX_FP_OPCODE_NRM: SetDst("normalize($0.xyz)"); break; - case RSX_FP_OPCODE_DIV: SetDst("($0 / $1)"); break; - case RSX_FP_OPCODE_DIVSQ: SetDst("($0 / sqrt($1))"); break; - case RSX_FP_OPCODE_LIF: SetDst("vec4(1.0, $0.y, ($0.y > 0 ? pow(2.0, $0.w) : 0.0), 1.0)"); break; - case RSX_FP_OPCODE_FENCT: break; - case RSX_FP_OPCODE_FENCB: break; - - case RSX_FP_OPCODE_BRK: SetDst("break"); break; - //case RSX_FP_OPCODE_CAL: break; - case RSX_FP_OPCODE_IFE: - AddCode("if($cond)"); - m_else_offsets.push_back(src1.else_offset << 2); - m_end_offsets.push_back(src2.end_offset << 2); - AddCode("{"); - m_code_level++; - break; - - case RSX_FP_OPCODE_LOOP: - if(!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt) - { - AddCode(fmt::Format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) {} //-> %u //LOOP", - m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment, src2.end_offset)); - } - else - { - AddCode(fmt::Format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) //LOOP", - m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment)); - m_loop_count++; - m_end_offsets.push_back(src2.end_offset << 2); - AddCode("{"); - m_code_level++; - } - break; - case RSX_FP_OPCODE_REP: - if(!src0.exec_if_eq && !src0.exec_if_gr && !src0.exec_if_lt) - { - AddCode(fmt::Format("$ifcond for(int i%u = %u; i%u < %u; i%u += %u) {} //-> %u //REP", - m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment, src2.end_offset)); - } - else - { - AddCode(fmt::Format("if($cond) for(int i%u = %u; i%u < %u; i%u += %u) //REP", - m_loop_count, src1.init_counter, m_loop_count, src1.end_counter, m_loop_count, src1.increment)); - m_loop_count++; - m_end_offsets.push_back(src2.end_offset << 2); - AddCode("{"); - m_code_level++; - } - break; - //case RSX_FP_OPCODE_RET: SetDst("return"); break; default: - LOG_ERROR(RSX, "Unknown fp opcode 0x%x (inst %d)", opcode, m_size / (4 * 4)); - //Emu.Pause(); - break; + if (forced_unit == FORCE_NONE) + { + if (SIP()) break; + if (SCT()) break; + if (TEX_SRB()) break; + if (SCB()) break; + } + else if (forced_unit == FORCE_SCT) + { + forced_unit = FORCE_NONE; + if (SCT()) break; + } + else if (forced_unit == FORCE_SCB) + { + forced_unit = FORCE_NONE; + if (SCB()) break; + } + + LOG_ERROR(RSX, "Unknown/illegal instruction: 0x%x (forced unit %d)", opcode, forced_unit); + break; } m_size += m_offset; - if(dst.end) break; + if (dst.end) break; assert(m_offset % sizeof(u32) == 0); data += m_offset / sizeof(u32); @@ -450,22 +613,22 @@ void GLFragmentDecompilerThread::Task() m_parr.params.clear(); } -GLShaderProgram::GLShaderProgram() +GLFragmentProgram::GLFragmentProgram() : m_decompiler_thread(nullptr) - , m_id(0) + , id(0) { } -GLShaderProgram::~GLShaderProgram() +GLFragmentProgram::~GLFragmentProgram() { - if(m_decompiler_thread) + if (m_decompiler_thread) { Wait(); - if(m_decompiler_thread->IsAlive()) + if (m_decompiler_thread->IsAlive()) { m_decompiler_thread->Stop(); } - + delete m_decompiler_thread; m_decompiler_thread = nullptr; } @@ -473,93 +636,96 @@ GLShaderProgram::~GLShaderProgram() Delete(); } -void GLShaderProgram::Wait() +void GLFragmentProgram::Wait() { - if(m_decompiler_thread && m_decompiler_thread->IsAlive()) + if (m_decompiler_thread && m_decompiler_thread->IsAlive()) { m_decompiler_thread->Join(); } } -void GLShaderProgram::Decompile(RSXShaderProgram& prog) +void GLFragmentProgram::Decompile(RSXFragmentProgram& prog) { - GLFragmentDecompilerThread decompiler(m_shader, m_parr, prog.addr, prog.size, prog.ctrl); + GLFragmentDecompilerThread decompiler(shader, parr, prog.addr, prog.size, prog.ctrl); decompiler.Task(); } -void GLShaderProgram::DecompileAsync(RSXShaderProgram& prog) +void GLFragmentProgram::DecompileAsync(RSXFragmentProgram& prog) { - if(m_decompiler_thread) + if (m_decompiler_thread) { Wait(); - if(m_decompiler_thread->IsAlive()) + if (m_decompiler_thread->IsAlive()) { m_decompiler_thread->Stop(); } - + delete m_decompiler_thread; m_decompiler_thread = nullptr; } - m_decompiler_thread = new GLFragmentDecompilerThread(m_shader, m_parr, prog.addr, prog.size, prog.ctrl); + m_decompiler_thread = new GLFragmentDecompilerThread(shader, parr, prog.addr, prog.size, prog.ctrl); m_decompiler_thread->Start(); } -void GLShaderProgram::Compile() +void GLFragmentProgram::Compile() { - if (m_id) glDeleteShader(m_id); + if (id) + { + glDeleteShader(id); + } - m_id = glCreateShader(GL_FRAGMENT_SHADER); + id = glCreateShader(GL_FRAGMENT_SHADER); - const char* str = m_shader.c_str(); - const int strlen = m_shader.length(); + const char* str = shader.c_str(); + const int strlen = shader.length(); - glShaderSource(m_id, 1, &str, &strlen); - glCompileShader(m_id); + glShaderSource(id, 1, &str, &strlen); + glCompileShader(id); GLint compileStatus = GL_FALSE; - glGetShaderiv(m_id, GL_COMPILE_STATUS, &compileStatus); // Determine the result of the glCompileShader call + glGetShaderiv(id, GL_COMPILE_STATUS, &compileStatus); // Determine the result of the glCompileShader call if (compileStatus != GL_TRUE) // If the shader failed to compile... { GLint infoLength; - glGetShaderiv(m_id, GL_INFO_LOG_LENGTH, &infoLength); // Retrieve the length in bytes (including trailing NULL) of the shader info log + glGetShaderiv(id, GL_INFO_LOG_LENGTH, &infoLength); // Retrieve the length in bytes (including trailing NULL) of the shader info log if (infoLength > 0) { GLsizei len; char* buf = new char[infoLength]; // Buffer to store infoLog - glGetShaderInfoLog(m_id, infoLength, &len, buf); // Retrieve the shader info log into our buffer + glGetShaderInfoLog(id, infoLength, &len, buf); // Retrieve the shader info log into our buffer LOG_ERROR(RSX, "Failed to compile shader: %s", buf); // Write log to the console delete[] buf; } - LOG_NOTICE(RSX, m_shader.c_str()); // Log the text of the shader that failed to compile + LOG_NOTICE(RSX, shader.c_str()); // Log the text of the shader that failed to compile Emu.Pause(); // Pause the emulator, we can't really continue from here } } -void GLShaderProgram::Delete() +void GLFragmentProgram::Delete() { - for (auto& param : m_parr.params) { + for (auto& param : parr.params) { param.items.clear(); param.type.clear(); } - m_parr.params.clear(); - m_shader.clear(); + parr.params.clear(); + shader.clear(); - if (m_id) + if (id) { if (Emu.IsStopped()) { - LOG_WARNING(RSX, "GLShaderProgram::Delete(): glDeleteShader(%d) avoided", m_id); + LOG_WARNING(RSX, "GLFragmentProgram::Delete(): glDeleteShader(%d) avoided", id); } else { - glDeleteShader(m_id); + glDeleteShader(id); } - m_id = 0; + id = 0; } } diff --git a/rpcs3/Emu/RSX/GL/GLFragmentProgram.h b/rpcs3/Emu/RSX/GL/GLFragmentProgram.h index f05dfc30e0..ce40e77041 100644 --- a/rpcs3/Emu/RSX/GL/GLFragmentProgram.h +++ b/rpcs3/Emu/RSX/GL/GLFragmentProgram.h @@ -155,6 +155,7 @@ struct GLFragmentDecompilerThread : public ThreadBase std::string AddTex(); std::string Format(const std::string& code); + void AddCodeCond(const std::string& dst, const std::string& src); std::string GetCond(); template std::string GetSRC(T src); std::string BuildCode(); @@ -167,24 +168,28 @@ struct GLFragmentDecompilerThread : public ThreadBase /** Storage for an Fragment Program in the process of of recompilation. * This class calls OpenGL functions and should only be used from the RSX/Graphics thread. */ -class GLShaderProgram +class GLFragmentProgram { public: - GLShaderProgram(); - ~GLShaderProgram(); + GLFragmentProgram(); + ~GLFragmentProgram(); + + GLParamArray parr; + u32 id; + std::string shader; /** * Decompile a fragment shader located in the PS3's Memory. This function operates synchronously. * @param prog RSXShaderProgram specifying the location and size of the shader in memory */ - void Decompile(RSXShaderProgram& prog); + void Decompile(RSXFragmentProgram& prog); /** * Asynchronously decompile a fragment shader located in the PS3's Memory. * When this function is called you must call Wait() before GetShaderText() will return valid data. * @param prog RSXShaderProgram specifying the location and size of the shader in memory */ - void DecompileAsync(RSXShaderProgram& prog); + void DecompileAsync(RSXFragmentProgram& prog); /** Wait for the decompiler task to complete decompilation. */ void Wait(); @@ -192,37 +197,10 @@ public: /** Compile the decompiled fragment shader into a format we can use with OpenGL. */ void Compile(); - /** Get the source text for this shader */ - inline const std::string& GetShaderText() const { return m_shader; } - - /** - * Set the source text for this shader - * @param shaderText supplied shader text - */ - inline void SetShaderText(const std::string& shaderText) { m_shader = shaderText; } - - /** Get the OpenGL id this shader is bound to */ - inline u32 GetId() const { return m_id; } - - /** - * Set the OpenGL id this shader is bound to - * @param id supplied id - */ - inline void SetId(const u32 id) { m_id = id; } - private: /** Threaded fragment shader decompiler responsible for decompiling this program */ GLFragmentDecompilerThread* m_decompiler_thread; - /** Shader parameter storage */ - GLParamArray m_parr; - - /** Text of our decompiler shader */ - std::string m_shader; - - /** OpenGL id this shader is bound to */ - u32 m_id; - /** Deletes the shader and any stored information */ void Delete(); }; diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index 16fb3d73eb..ab6ed0302b 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -29,7 +29,7 @@ int last_width = 0, last_height = 0, last_depth_format = 0; GLenum g_last_gl_error = GL_NO_ERROR; void printGlError(GLenum err, const char* situation) { - if(err != GL_NO_ERROR) + if (err != GL_NO_ERROR) { LOG_ERROR(RSX, "%s: opengl error 0x%04x", situation, err); Emu.Pause(); @@ -98,7 +98,9 @@ float GLTexture::GetMaxAniso(int aniso) void GLTexture::Init(RSXTexture& tex) { if (tex.GetLocation() > 1) + { return; + } Bind(); @@ -108,8 +110,9 @@ void GLTexture::Init(RSXTexture& tex) LOG_ERROR(RSX, "Bad texture address=0x%x", texaddr); return; } - //ConLog.Warning("texture addr = 0x%x, width = %d, height = %d, max_aniso=%d, mipmap=%d, remap=0x%x, zfunc=0x%x, wraps=0x%x, wrapt=0x%x, wrapr=0x%x, minlod=0x%x, maxlod=0x%x", + //lOG_WARNING(RSX, "texture addr = 0x%x, width = %d, height = %d, max_aniso=%d, mipmap=%d, remap=0x%x, zfunc=0x%x, wraps=0x%x, wrapt=0x%x, wrapr=0x%x, minlod=0x%x, maxlod=0x%x", // m_offset, m_width, m_height, m_maxaniso, m_mipmap, m_remap, m_zfunc, m_wraps, m_wrapt, m_wrapr, m_minlod, m_maxlod); + //TODO: safe init checkForGlError("GLTexture::Init() -> glBindTexture"); @@ -132,7 +135,7 @@ void GLTexture::Init(RSXTexture& tex) static const GLint swizzleMaskB8[] = { GL_BLUE, GL_BLUE, GL_BLUE, GL_BLUE }; glRemap = swizzleMaskB8; } - break; + break; case CELL_GCM_TEXTURE_A1R5G5B5: glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE); @@ -144,7 +147,7 @@ void GLTexture::Init(RSXTexture& tex) glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_A1R5G5B5)"); - break; + break; case CELL_GCM_TEXTURE_A4R4G4B4: { @@ -155,7 +158,7 @@ void GLTexture::Init(RSXTexture& tex) static const GLint swizzleMaskA4R4G4B4[] = { GL_BLUE, GL_ALPHA, GL_RED, GL_GREEN }; glRemap = swizzleMaskA4R4G4B4; } - break; + break; case CELL_GCM_TEXTURE_R5G6B5: { @@ -168,9 +171,10 @@ void GLTexture::Init(RSXTexture& tex) glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_R5G6B5)"); } - break; + break; case CELL_GCM_TEXTURE_A8R8G8B8: + { if (is_swizzled) { u32 *src, *dst; @@ -183,18 +187,19 @@ void GLTexture::Init(RSXTexture& tex) log2width = log(tex.GetWidth()) / log(2); log2height = log(tex.GetHeight()) / log(2); - for (int i = 0; i glTexImage2D(CELL_GCM_TEXTURE_A8R8G8B8)"); - break; + } + break; case CELL_GCM_TEXTURE_COMPRESSED_DXT1: // Compressed 4x4 pixels into 8 bytes { @@ -203,7 +208,7 @@ void GLTexture::Init(RSXTexture& tex) glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, tex.GetWidth(), tex.GetHeight(), 0, size, pixels); checkForGlError("GLTexture::Init() -> glCompressedTexImage2D(CELL_GCM_TEXTURE_COMPRESSED_DXT1)"); } - break; + break; case CELL_GCM_TEXTURE_COMPRESSED_DXT23: // Compressed 4x4 pixels into 16 bytes { @@ -212,7 +217,7 @@ void GLTexture::Init(RSXTexture& tex) glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, tex.GetWidth(), tex.GetHeight(), 0, size, pixels); checkForGlError("GLTexture::Init() -> glCompressedTexImage2D(CELL_GCM_TEXTURE_COMPRESSED_DXT23)"); } - break; + break; case CELL_GCM_TEXTURE_COMPRESSED_DXT45: // Compressed 4x4 pixels into 16 bytes { @@ -221,7 +226,7 @@ void GLTexture::Init(RSXTexture& tex) glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, tex.GetWidth(), tex.GetHeight(), 0, size, pixels); checkForGlError("GLTexture::Init() -> glCompressedTexImage2D(CELL_GCM_TEXTURE_COMPRESSED_DXT45)"); } - break; + break; case CELL_GCM_TEXTURE_G8B8: { @@ -231,7 +236,7 @@ void GLTexture::Init(RSXTexture& tex) static const GLint swizzleMaskG8B8[] = { GL_RED, GL_GREEN, GL_RED, GL_GREEN }; glRemap = swizzleMaskG8B8; } - break; + break; case CELL_GCM_TEXTURE_R6G5B5: { @@ -252,27 +257,35 @@ void GLTexture::Init(RSXTexture& tex) free(unswizzledPixels); } - break; + break; case CELL_GCM_TEXTURE_DEPTH24_D8: // 24-bit unsigned fixed-point number and 8 bits of garbage + { glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, tex.GetWidth(), tex.GetHeight(), 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, pixels); checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_DEPTH24_D8)"); - break; + } + break; case CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT: // 24-bit unsigned float and 8 bits of garbage + { glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, tex.GetWidth(), tex.GetHeight(), 0, GL_DEPTH_COMPONENT, GL_FLOAT, pixels); checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT)"); - break; + } + break; case CELL_GCM_TEXTURE_DEPTH16: // 16-bit unsigned fixed-point number + { glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, tex.GetWidth(), tex.GetHeight(), 0, GL_DEPTH_COMPONENT, GL_SHORT, pixels); checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_DEPTH16)"); - break; + } + break; case CELL_GCM_TEXTURE_DEPTH16_FLOAT: // 16-bit unsigned float + { glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, tex.GetWidth(), tex.GetHeight(), 0, GL_DEPTH_COMPONENT, GL_FLOAT, pixels); checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_DEPTH16_FLOAT)"); - break; + } + break; case CELL_GCM_TEXTURE_X16: // A 16-bit fixed-point number { @@ -288,7 +301,7 @@ void GLTexture::Init(RSXTexture& tex) static const GLint swizzleMaskX16[] = { GL_RED, GL_ONE, GL_RED, GL_ONE }; glRemap = swizzleMaskX16; } - break; + break; case CELL_GCM_TEXTURE_Y16_X16: // Two 16-bit fixed-point numbers { @@ -304,9 +317,10 @@ void GLTexture::Init(RSXTexture& tex) static const GLint swizzleMaskX32_Y16_X16[] = { GL_GREEN, GL_RED, GL_GREEN, GL_RED }; glRemap = swizzleMaskX32_Y16_X16; } - break; + break; case CELL_GCM_TEXTURE_R5G5B5A1: + { glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE); checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_R5G5B5A1)"); @@ -315,9 +329,11 @@ void GLTexture::Init(RSXTexture& tex) glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_R5G5B5A1)"); - break; + } + break; case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT: // Four fp16 values + { glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_TRUE); checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT)"); @@ -326,12 +342,15 @@ void GLTexture::Init(RSXTexture& tex) glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT)"); - break; + } + break; case CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT: // Four fp32 values + { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.GetWidth(), tex.GetHeight(), 0, GL_BGRA, GL_FLOAT, pixels); checkForGlError("GLTexture::Init() -> glTexImage2D(CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT)"); - break; + } + break; case CELL_GCM_TEXTURE_X32_FLOAT: // One 32-bit floating-point number { @@ -341,7 +360,7 @@ void GLTexture::Init(RSXTexture& tex) static const GLint swizzleMaskX32_FLOAT[] = { GL_RED, GL_ONE, GL_ONE, GL_ONE }; glRemap = swizzleMaskX32_FLOAT; } - break; + break; case CELL_GCM_TEXTURE_D1R5G5B5: { @@ -358,7 +377,7 @@ void GLTexture::Init(RSXTexture& tex) glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE); checkForGlError("GLTexture::Init() -> glPixelStorei(CELL_GCM_TEXTURE_D1R5G5B5)"); } - break; + break; case CELL_GCM_TEXTURE_D8R8G8B8: // 8 bits of garbage and three unsigned 8-bit fixed-point numbers { @@ -368,7 +387,7 @@ void GLTexture::Init(RSXTexture& tex) static const GLint swizzleMaskX32_D8R8G8B8[] = { GL_ONE, GL_RED, GL_GREEN, GL_BLUE }; glRemap = swizzleMaskX32_D8R8G8B8; } - break; + break; case CELL_GCM_TEXTURE_Y16_X16_FLOAT: // Two fp16 values { @@ -384,9 +403,9 @@ void GLTexture::Init(RSXTexture& tex) static const GLint swizzleMaskX32_Y16_X16_FLOAT[] = { GL_RED, GL_GREEN, GL_RED, GL_GREEN }; glRemap = swizzleMaskX32_Y16_X16_FLOAT; } - break; + break; - case CELL_GCM_TEXTURE_COMPRESSED_B8R8_G8R8 & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN) : + case CELL_GCM_TEXTURE_COMPRESSED_B8R8_G8R8 & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN): { const u32 numPixels = tex.GetWidth() * tex.GetHeight(); unswizzledPixels = (u8 *)malloc(numPixels * 4); @@ -409,9 +428,9 @@ void GLTexture::Init(RSXTexture& tex) free(unswizzledPixels); } - break; + break; - case CELL_GCM_TEXTURE_COMPRESSED_R8B8_R8G8 & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN) : + case CELL_GCM_TEXTURE_COMPRESSED_R8B8_R8G8 & ~(CELL_GCM_TEXTURE_LN | CELL_GCM_TEXTURE_UN): { const u32 numPixels = tex.GetWidth() * tex.GetHeight(); unswizzledPixels = (u8 *)malloc(numPixels * 4); @@ -434,10 +453,10 @@ void GLTexture::Init(RSXTexture& tex) free(unswizzledPixels); } - break; + break; - default: LOG_ERROR(RSX, "Init tex error: Bad tex format (0x%x | %s | 0x%x)", format, - (is_swizzled ? "swizzled" : "linear"), tex.GetFormat() & 0x40); break; + default: LOG_ERROR(RSX, "Init tex error: Bad tex format (0x%x | %s | 0x%x)", format, (is_swizzled ? "swizzled" : "linear"), tex.GetFormat() & 0x40); + break; } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, tex.GetMipmap() - 1); @@ -636,7 +655,7 @@ void PostDrawObj::Initialize() InitializeShaders(); m_fp.Compile(); m_vp.Compile(); - m_program.Create(m_vp.id, m_fp.GetId()); + m_program.Create(m_vp.id, m_fp.id); m_program.Use(); InitializeLocations(); } @@ -676,8 +695,6 @@ void DrawCursorObj::Draw() if (m_update_texture) { - //m_update_texture = false; - glUniform2f(m_program.GetLocation("in_tc"), m_width, m_height); checkForGlError("DrawCursorObj : glUniform2f"); if (!m_tex_id) @@ -697,8 +714,6 @@ void DrawCursorObj::Draw() if (m_update_pos) { - //m_update_pos = false; - glUniform4f(m_program.GetLocation("in_pos"), m_pos_x, m_pos_y, m_pos_z, 1.0f); checkForGlError("DrawCursorObj : glUniform4f"); } @@ -710,10 +725,7 @@ void DrawCursorObj::Draw() checkForGlError("DrawCursorObj : m_fbo.Bind(GL_READ_FRAMEBUFFER)"); GLfbo::Bind(GL_DRAW_FRAMEBUFFER, 0); checkForGlError("DrawCursorObj : GLfbo::Bind(GL_DRAW_FRAMEBUFFER, 0)"); - GLfbo::Blit( - 0, 0, m_width, m_height, - 0, 0, m_width, m_height, - GL_COLOR_BUFFER_BIT, GL_NEAREST); + GLfbo::Blit(0, 0, m_width, m_height, 0, 0, m_width, m_height, GL_COLOR_BUFFER_BIT, GL_NEAREST); checkForGlError("DrawCursorObj : GLfbo::Blit"); m_fbo.Bind(); checkForGlError("DrawCursorObj : m_fbo.Bind"); @@ -734,7 +746,7 @@ void DrawCursorObj::InitializeShaders() " gl_Position = in_pos;\n" "}\n"; - m_fp.SetShaderText( + m_fp.shader = "#version 330\n" "\n" "in vec2 tc;\n" @@ -744,7 +756,7 @@ void DrawCursorObj::InitializeShaders() "void main()\n" "{\n" " res = texture(tex0, tc);\n" - "}\n"); + "}\n"; } void DrawCursorObj::SetTexture(void* pixels, int width, int height) @@ -766,7 +778,7 @@ void DrawCursorObj::SetPosition(float x, float y, float z) void DrawCursorObj::InitializeLocations() { - //ConLog.Warning("tex0 location = 0x%x", m_program.GetLocation("tex0")); + //LOG_WARNING(RSX, "tex0 location = 0x%x", m_program.GetLocation("tex0")); } GLGSRender::GLGSRender() @@ -785,25 +797,16 @@ GLGSRender::~GLGSRender() m_frame->DeleteContext(m_context); } -void GLGSRender::Enable(bool enable, const u32 cap) -{ - if(enable) - { - glEnable(cap); - } - else - { - glDisable(cap); - } -} - extern CellGcmContextData current_context; void GLGSRender::Close() { Stop(); - if(m_frame->IsShown()) m_frame->Hide(); + if (m_frame->IsShown()) + { + m_frame->Hide(); + } m_ctrl = nullptr; } @@ -814,7 +817,7 @@ void GLGSRender::EnableVertexData(bool indexed_draw) const u32 data_offset = indexed_draw ? 0 : m_draw_array_first; - for(u32 i=0; i 7) { + if (m_vertex_data[i].type < 1 || m_vertex_data[i].type > 7) + { LOG_ERROR(RSX, "GLGSRender::EnableVertexData: Bad vertex data type (%d)!", m_vertex_data[i].type); } - if(0 && !m_vertex_data[i].addr) + if (!m_vertex_data[i].addr) { - switch(m_vertex_data[i].type) + switch (m_vertex_data[i].type) { case CELL_GCM_VERTEX_S32K: case CELL_GCM_VERTEX_S1: @@ -983,7 +987,7 @@ void GLGSRender::EnableVertexData(bool indexed_draw) break; case CELL_GCM_VERTEX_F: - switch(m_vertex_data[i].size) + switch (m_vertex_data[i].size) { case 1: glVertexAttrib1f(i, (GLfloat&)m_vertex_data[i].data[0]); break; case 2: glVertexAttrib2fv(i, (GLfloat*)&m_vertex_data[i].data[0]); break; @@ -1016,9 +1020,9 @@ void GLGSRender::EnableVertexData(bool indexed_draw) void GLGSRender::DisableVertexData() { m_vdata.clear(); - for(u32 i=0; ioffset; + for (const RSXTransformConstant& c : m_fragment_constants) + { + u32 id = c.id - m_cur_fragment_prog->offset; //LOG_WARNING(RSX,"fc%u[0x%x - 0x%x] = (%f, %f, %f, %f)", id, c.id, m_cur_shader_prog->offset, c.x, c.y, c.z, c.w); @@ -1086,50 +1090,44 @@ void GLGSRender::InitFragmentData() checkForGlError("glUniform4f " + name + fmt::Format(" %u [%f %f %f %f]", l, c.x, c.y, c.z, c.w)); } - //if(m_fragment_constants.GetCount()) + //if (m_fragment_constants.GetCount()) // LOG_NOTICE(HLE, ""); } bool GLGSRender::LoadProgram() { - if(!m_cur_shader_prog) + if (!m_cur_fragment_prog) { LOG_WARNING(RSX, "LoadProgram: m_cur_shader_prog == NULL"); return false; } - m_cur_shader_prog->ctrl = m_shader_ctrl; + m_cur_fragment_prog->ctrl = m_shader_ctrl; - if(!m_cur_vertex_prog) + if (!m_cur_vertex_prog) { LOG_WARNING(RSX, "LoadProgram: m_cur_vertex_prog == NULL"); return false; } - m_fp_buf_num = m_prog_buffer.SearchFp(*m_cur_shader_prog, m_shader_prog); + m_fp_buf_num = m_prog_buffer.SearchFp(*m_cur_fragment_prog, m_fragment_prog); m_vp_buf_num = m_prog_buffer.SearchVp(*m_cur_vertex_prog, m_vertex_prog); - //ConLog.Write("Create program"); - - if(m_fp_buf_num == -1) + if (m_fp_buf_num == -1) { LOG_WARNING(RSX, "FP not found in buffer!"); - //m_shader_prog.DecompileAsync(*m_cur_shader_prog); - //m_shader_prog.Wait(); - m_shader_prog.Decompile(*m_cur_shader_prog); - m_shader_prog.Compile(); - checkForGlError("m_shader_prog.Compile"); + m_fragment_prog.Decompile(*m_cur_fragment_prog); + m_fragment_prog.Compile(); + checkForGlError("m_fragment_prog.Compile"); // TODO: This shouldn't use current dir rFile f("./FragmentProgram.txt", rFile::write); - f.Write(m_shader_prog.GetShaderText()); + f.Write(m_fragment_prog.shader); } - if(m_vp_buf_num == -1) + if (m_vp_buf_num == -1) { LOG_WARNING(RSX, "VP not found in buffer!"); - //m_vertex_prog.DecompileAsync(*m_cur_vertex_prog); - //m_vertex_prog.Wait(); m_vertex_prog.Decompile(*m_cur_vertex_prog); m_vertex_prog.Compile(); checkForGlError("m_vertex_prog.Compile"); @@ -1139,37 +1137,37 @@ bool GLGSRender::LoadProgram() f.Write(m_vertex_prog.shader); } - if(m_fp_buf_num != -1 && m_vp_buf_num != -1) + if (m_fp_buf_num != -1 && m_vp_buf_num != -1) { m_program.id = m_prog_buffer.GetProg(m_fp_buf_num, m_vp_buf_num); } - if(m_program.id) + if (m_program.id) { // RSX Debugger: Check if this program was modified and update it if (Ini.GSLogPrograms.GetValue()) { - for(auto& program : m_debug_programs) + for (auto& program : m_debug_programs) { if (program.id == m_program.id && program.modified) { // TODO: This isn't working perfectly. Is there any better/shorter way to update the program m_vertex_prog.shader = program.vp_shader; - m_shader_prog.SetShaderText(program.fp_shader); + m_fragment_prog.shader = program.fp_shader; m_vertex_prog.Wait(); m_vertex_prog.Compile(); checkForGlError("m_vertex_prog.Compile"); - m_shader_prog.Wait(); - m_shader_prog.Compile(); - checkForGlError("m_shader_prog.Compile"); + m_fragment_prog.Wait(); + m_fragment_prog.Compile(); + checkForGlError("m_fragment_prog.Compile"); glAttachShader(m_program.id, m_vertex_prog.id); - glAttachShader(m_program.id, m_shader_prog.GetId()); + glAttachShader(m_program.id, m_fragment_prog.id); glLinkProgram(m_program.id); checkForGlError("glLinkProgram"); glDetachShader(m_program.id, m_vertex_prog.id); - glDetachShader(m_program.id, m_shader_prog.GetId()); + glDetachShader(m_program.id, m_fragment_prog.id); program.vp_id = m_vertex_prog.id; - program.fp_id = m_shader_prog.GetId(); + program.fp_id = m_fragment_prog.id; program.modified = false; } } @@ -1178,9 +1176,9 @@ bool GLGSRender::LoadProgram() } else { - m_program.Create(m_vertex_prog.id, m_shader_prog.GetId()); + m_program.Create(m_vertex_prog.id, m_fragment_prog.id); checkForGlError("m_program.Create"); - m_prog_buffer.Add(m_program, m_shader_prog, *m_cur_shader_prog, m_vertex_prog, *m_cur_vertex_prog); + m_prog_buffer.Add(m_program, m_fragment_prog, *m_cur_fragment_prog, m_vertex_prog, *m_cur_vertex_prog); checkForGlError("m_prog_buffer.Add"); m_program.Use(); @@ -1190,9 +1188,9 @@ bool GLGSRender::LoadProgram() RSXDebuggerProgram program; program.id = m_program.id; program.vp_id = m_vertex_prog.id; - program.fp_id = m_shader_prog.GetId(); + program.fp_id = m_fragment_prog.id; program.vp_shader = m_vertex_prog.shader; - program.fp_shader = m_shader_prog.GetShaderText(); + program.fp_shader = m_fragment_prog.shader; m_debug_programs.push_back(program); } } @@ -1473,11 +1471,6 @@ void GLGSRender::OnInitThread() #ifdef _WIN32 glSwapInterval(Ini.GSVSyncEnable.GetValue() ? 1 : 0); -// Undefined reference: glXSwapIntervalEXT -/*#else - if (GLXDrawable drawable = glXGetCurrentDrawable()){ - glXSwapIntervalEXT(glXGetCurrentDisplay(), drawable, Ini.GSVSyncEnable.GetValue() ? 1 : 0); - }*/ #endif } @@ -1503,10 +1496,7 @@ void GLGSRender::OnReset() { m_program.UnUse(); - //m_shader_prog.id = 0; - //m_vertex_prog.id = 0; - - if(m_vbo.IsCreated()) + if (m_vbo.IsCreated()) { m_vbo.UnBind(); m_vbo.Delete(); @@ -1517,7 +1507,7 @@ void GLGSRender::OnReset() void GLGSRender::InitDrawBuffers() { - if(!m_fbo.IsCreated() || RSXThread::m_width != last_width || RSXThread::m_height != last_height || last_depth_format != m_surface_depth_format) + if (!m_fbo.IsCreated() || RSXThread::m_width != last_width || RSXThread::m_height != last_height || last_depth_format != m_surface_depth_format) { LOG_WARNING(RSX, "New FBO (%dx%d)", RSXThread::m_width, RSXThread::m_height); last_width = RSXThread::m_width; @@ -1531,7 +1521,7 @@ void GLGSRender::InitDrawBuffers() m_rbo.Create(4 + 1); checkForGlError("m_rbo.Create"); - for(int i=0; i<4; ++i) + for (int i = 0; i < 4; ++i) { m_rbo.Bind(i); m_rbo.Storage(GL_RGBA, RSXThread::m_width, RSXThread::m_height); @@ -1540,56 +1530,40 @@ void GLGSRender::InitDrawBuffers() m_rbo.Bind(4); - switch(m_surface_depth_format) + if (m_surface_depth_format == CELL_GCM_SURFACE_Z16) { - // case 0 found in BLJM60410-[Suzukaze no Melt - Days in the Sanctuary] - // [E : RSXThread]: Bad depth format! (0) - // [E : RSXThread]: glEnable: opengl error 0x0506 - // [E : RSXThread]: glDrawArrays: opengl error 0x0506 - case 0: - m_rbo.Storage(GL_DEPTH_COMPONENT, RSXThread::m_width, RSXThread::m_height); - checkForGlError("m_rbo.Storage(GL_DEPTH_COMPONENT)"); - break; - - case CELL_GCM_SURFACE_Z16: m_rbo.Storage(GL_DEPTH_COMPONENT16, RSXThread::m_width, RSXThread::m_height); checkForGlError("m_rbo.Storage(GL_DEPTH_COMPONENT16)"); - break; - case CELL_GCM_SURFACE_Z24S8: + m_fbo.Renderbuffer(GL_DEPTH_ATTACHMENT, m_rbo.GetId(4)); + checkForGlError("m_fbo.Renderbuffer(GL_DEPTH_ATTACHMENT)"); + } + else if (m_surface_depth_format == CELL_GCM_SURFACE_Z24S8) + { m_rbo.Storage(GL_DEPTH24_STENCIL8, RSXThread::m_width, RSXThread::m_height); checkForGlError("m_rbo.Storage(GL_DEPTH24_STENCIL8)"); - break; - default: - LOG_ERROR(RSX, "Bad depth format! (%d)", m_surface_depth_format); - assert(0); - break; + m_fbo.Renderbuffer(GL_DEPTH_ATTACHMENT, m_rbo.GetId(4)); + checkForGlError("m_fbo.Renderbuffer(GL_DEPTH_ATTACHMENT)"); + + m_fbo.Renderbuffer(GL_STENCIL_ATTACHMENT, m_rbo.GetId(4)); + checkForGlError("m_fbo.Renderbuffer(GL_STENCIL_ATTACHMENT)"); } - for(int i=0; i<4; ++i) + for (int i = 0; i < 4; ++i) { m_fbo.Renderbuffer(GL_COLOR_ATTACHMENT0 + i, m_rbo.GetId(i)); checkForGlError(fmt::Format("m_fbo.Renderbuffer(GL_COLOR_ATTACHMENT%d)", i)); } - - m_fbo.Renderbuffer(GL_DEPTH_ATTACHMENT, m_rbo.GetId(4)); - checkForGlError("m_fbo.Renderbuffer(GL_DEPTH_ATTACHMENT)"); - - if(m_surface_depth_format == 2) - { - m_fbo.Renderbuffer(GL_STENCIL_ATTACHMENT, m_rbo.GetId(4)); - checkForGlError("m_fbo.Renderbuffer(GL_STENCIL_ATTACHMENT)"); - } } - if(!m_set_surface_clip_horizontal) + if (!m_set_surface_clip_horizontal) { m_surface_clip_x = 0; m_surface_clip_w = RSXThread::m_width; } - if(!m_set_surface_clip_vertical) + if (!m_set_surface_clip_vertical) { m_surface_clip_y = 0; m_surface_clip_h = RSXThread::m_height; @@ -1599,10 +1573,10 @@ void GLGSRender::InitDrawBuffers() static const GLenum draw_buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3 }; - switch(m_surface_color_target) + switch (m_surface_color_target) { case CELL_GCM_SURFACE_TARGET_NONE: - break; + break; case CELL_GCM_SURFACE_TARGET_0: glDrawBuffer(draw_buffers[0]); @@ -1630,66 +1604,300 @@ void GLGSRender::InitDrawBuffers() LOG_ERROR(RSX, "Bad surface color target: %d", m_surface_color_target); break; } + + if (m_read_buffer) + { + u32 format = GL_BGRA; + CellGcmDisplayInfo* buffers = vm::get_ptr(m_gcm_buffers_addr); + u32 addr = GetAddress(buffers[m_gcm_current_buffer].offset, CELL_GCM_LOCATION_LOCAL); + + if (Memory.IsGoodAddr(addr)) + { + u32 width = buffers[m_gcm_current_buffer].width; + u32 height = buffers[m_gcm_current_buffer].height; + + glDrawPixels(width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, vm::get_ptr(addr)); + } + } } -void GLGSRender::ExecCMD(u32 cmd) +void GLGSRender::Enable(u32 cmd, u32 enable) +{ + switch (cmd) { + case NV4097_SET_DITHER_ENABLE: + enable ? glEnable(GL_DITHER) : glDisable(GL_DITHER); + break; + + case NV4097_SET_ALPHA_TEST_ENABLE: + enable ? glEnable(GL_ALPHA_TEST) : glDisable(GL_ALPHA_TEST); + break; + + case NV4097_SET_STENCIL_TEST_ENABLE: + enable ? glEnable(GL_STENCIL_TEST) : glDisable(GL_STENCIL_TEST); + break; + + case NV4097_SET_DEPTH_TEST_ENABLE: + enable ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST); + break; + + case NV4097_SET_CULL_FACE_ENABLE: + enable ? glEnable(GL_CULL_FACE) : glDisable(GL_CULL_FACE); + break; + + case NV4097_SET_BLEND_ENABLE: + enable ? glEnable(GL_BLEND) : glDisable(GL_BLEND); + break; + + case NV4097_SET_POLY_OFFSET_FILL_ENABLE: + enable ? glEnable(GL_POLYGON_OFFSET_FILL) : glDisable(GL_POLYGON_OFFSET_FILL); + break; + + case NV4097_SET_POLY_OFFSET_LINE_ENABLE: + enable ? glEnable(GL_POLYGON_OFFSET_LINE) : glDisable(GL_POLYGON_OFFSET_LINE); + break; + + case NV4097_SET_POLY_OFFSET_POINT_ENABLE: + enable ? glEnable(GL_POLYGON_OFFSET_POINT) : glDisable(GL_POLYGON_OFFSET_POINT); + break; + + case NV4097_SET_LOGIC_OP_ENABLE: + enable ? glEnable(GL_LOGIC_OP) : glDisable(GL_LOGIC_OP); + break; + + case NV4097_SET_SPECULAR_ENABLE: + enable ? glEnable(GL_LIGHTING) : glDisable(GL_LIGHTING); + break; + + case NV4097_SET_LINE_SMOOTH_ENABLE: + enable ? glEnable(GL_LINE_SMOOTH) : glDisable(GL_LINE_SMOOTH); + break; + + case NV4097_SET_POLY_SMOOTH_ENABLE: + enable ? glEnable(GL_POLYGON_SMOOTH) : glDisable(GL_POLYGON_SMOOTH); + break; + + case NV4097_SET_RESTART_INDEX_ENABLE: + enable ? glEnable(GL_PRIMITIVE_RESTART) : glDisable(GL_PRIMITIVE_RESTART); + break; + + case NV4097_SET_POINT_SPRITE_CONTROL: + enable ? glEnable(GL_POINT_SPRITE) : glDisable(GL_POINT_SPRITE); + break; + + case NV4097_SET_LINE_STIPPLE: + enable ? glEnable(GL_LINE_STIPPLE) : glDisable(GL_LINE_STIPPLE); + break; + + case NV4097_SET_POLYGON_STIPPLE: + enable ? glEnable(GL_POLYGON_STIPPLE) : glDisable(GL_POLYGON_STIPPLE); + break; + + case NV4097_SET_DEPTH_BOUNDS_TEST_ENABLE: + enable ? glEnable(GL_DEPTH_BOUNDS_TEST_EXT) : glDisable(GL_DEPTH_BOUNDS_TEST_EXT); + break; + + case NV4097_SET_USER_CLIP_PLANE_CONTROL: + const u32 clip_plane_0 = enable & 0xf; + const u32 clip_plane_1 = (enable >> 4) & 0xf; + const u32 clip_plane_2 = (enable >> 8) & 0xf; + const u32 clip_plane_3 = (enable >> 12) & 0xf; + const u32 clip_plane_4 = (enable >> 16) & 0xf; + const u32 clip_plane_5 = enable >> 20; + + clip_plane_0 ? glEnable(GL_CLIP_PLANE0) : glDisable(GL_CLIP_PLANE0); + clip_plane_1 ? glEnable(GL_CLIP_PLANE1) : glDisable(GL_CLIP_PLANE1); + clip_plane_2 ? glEnable(GL_CLIP_PLANE2) : glDisable(GL_CLIP_PLANE2); + clip_plane_3 ? glEnable(GL_CLIP_PLANE3) : glDisable(GL_CLIP_PLANE3); + clip_plane_4 ? glEnable(GL_CLIP_PLANE4) : glDisable(GL_CLIP_PLANE4); + clip_plane_5 ? glEnable(GL_CLIP_PLANE5) : glDisable(GL_CLIP_PLANE5); + break; + } +} + +void GLGSRender::ClearColor(u32 a, u32 r, u32 g, u32 b) +{ + glClearColor(r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f); + checkForGlError("glClearColor"); +} + +void GLGSRender::ClearStencil(u32 stencil) +{ + glClearStencil(stencil); + checkForGlError("glClearStencil"); +} + +void GLGSRender::ClearDepth(u32 depth) +{ + glClearDepth(depth / (float)0xffffff); + checkForGlError("glClearDepth"); +} + +void GLGSRender::ClearSurface(u32 mask) { - assert(cmd == NV4097_CLEAR_SURFACE); - InitDrawBuffers(); - if(m_set_color_mask) - { - glColorMask(m_color_mask_r, m_color_mask_g, m_color_mask_b, m_color_mask_a); - checkForGlError("glColorMask"); - } - - if (m_set_scissor_horizontal && m_set_scissor_vertical) - { - glScissor(m_scissor_x, m_scissor_y, m_scissor_w, m_scissor_h); - checkForGlError("glScissor"); - } - - GLbitfield f = 0; - - if (m_clear_surface_mask & 0x1) - { - glClearDepth(m_clear_surface_z / (float)0xffffff); - checkForGlError("glClearDepth"); - - f |= GL_DEPTH_BUFFER_BIT; - } - - if (m_clear_surface_mask & 0x2) - { - glClearStencil(m_clear_surface_s); - checkForGlError("glClearStencil"); - - f |= GL_STENCIL_BUFFER_BIT; - } - - if (m_clear_surface_mask & 0xF0) - { - glClearColor( - m_clear_surface_color_r / 255.0f, - m_clear_surface_color_g / 255.0f, - m_clear_surface_color_b / 255.0f, - m_clear_surface_color_a / 255.0f); - checkForGlError("glClearColor"); - - f |= GL_COLOR_BUFFER_BIT; - } - - glClear(f); - checkForGlError("glClear"); + GLbitfield clearMask = 0; + if (mask & 0x01) clearMask |= GL_DEPTH_BUFFER_BIT; + if (mask & 0x02) clearMask |= GL_STENCIL_BUFFER_BIT; + if (mask & 0xF0) clearMask |= GL_COLOR_BUFFER_BIT; + glClear(clearMask); + checkForGlError("glClear"); + WriteBuffers(); } +void GLGSRender::ColorMask(bool a, bool r, bool g, bool b) +{ + glColorMask(r, g, b, a); + checkForGlError("glColorMask"); +} + +void GLGSRender::AlphaFunc(u32 func, float ref) +{ + glAlphaFunc(func, ref); + checkForGlError("glAlphaFunc"); +} + +void GLGSRender::DepthFunc(u32 func) +{ + glDepthFunc(func); + checkForGlError("glDepthFunc"); +} + +void GLGSRender::DepthMask(u32 flag) +{ + glDepthMask(flag); + checkForGlError("glDepthMask"); +} + +void GLGSRender::PolygonMode(u32 face, u32 mode) +{ + switch (face) + { + case NV4097_SET_FRONT_POLYGON_MODE: + glPolygonMode(GL_FRONT, mode); + break; + case NV4097_SET_BACK_POLYGON_MODE: + glPolygonMode(GL_BACK, mode); + break; + } + checkForGlError("glPolygonMode"); +} + +void GLGSRender::PointSize(float size) +{ + glPointSize(m_point_size); + checkForGlError("glPointSize"); +} + +void GLGSRender::LogicOp(u32 opcdoe) +{ + glLogicOp(opcdoe); + checkForGlError("glLogicOp"); +} + +void GLGSRender::LineWidth(float width) +{ + glLineWidth(width); + checkForGlError("glLineWidth"); +} + +void GLGSRender::LineStipple(u16 factor, u16 pattern) +{ + glLineStipple(factor, pattern); + checkForGlError("glLineStipple"); +} + +void GLGSRender::PrimitiveRestartIndex(u32 index) +{ + glPrimitiveRestartIndex(index); + checkForGlError("glPrimitiveRestartIndex"); +} + +void GLGSRender::CullFace(u32 mode) +{ + glCullFace(mode); + checkForGlError("glCullFace"); +} + +void GLGSRender::FrontFace(u32 mode) +{ + glFrontFace(mode); + checkForGlError("glFrontFace"); +} + +void GLGSRender::Fogi(u32 mode) +{ + glFogi(GL_FOG_MODE, mode); + checkForGlError("glFogi(GL_FOG_MODE)"); +} + +void GLGSRender::Fogf(float start, float end) +{ + glFogf(GL_FOG_START, start); + checkForGlError("glFogf(GL_FOG_START)"); + glFogf(GL_FOG_END, end); + checkForGlError("glFogf(GL_FOG_END)"); +} + +void GLGSRender::PolygonOffset(float factor , float bias) +{ + glPolygonOffset(factor, bias); + checkForGlError("glPolygonOffset"); +} + +void GLGSRender::DepthRangef(float min, float max) +{ + glDepthRangef(min, max); + checkForGlError("glDepthRangef"); +} + +void GLGSRender::BlendEquationSeparate(u16 rgb, u16 a) +{ + glBlendEquationSeparate(rgb, a); + checkForGlError("glBlendEquationSeparate"); +} + +void GLGSRender::BlendFuncSeparate(u16 srcRGB, u16 dstRGB, u16 srcAlpha, u16 dstAlpha) +{ + glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); + checkForGlError("glBlendFuncSeparate"); +} + +void GLGSRender::BlendColor(u8 r, u8 g, u8 b, u8 a) +{ + glBlendColor(r, g, b, a); + checkForGlError("glBlendColor"); +} + +void GLGSRender::LightModeli(u32 enable) +{ + enable ? glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE) : glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE); + checkForGlError("glLightModeli"); +} + +void GLGSRender::ShadeModel(u32 mode) +{ + glShadeModel(m_shade_mode); + checkForGlError("glShadeModel"); +} + +void GLGSRender::DepthBoundsEXT(float min, float max) +{ + glDepthBoundsEXT(min, max); + checkForGlError("glDepthBoundsEXT"); +} + +void GLGSRender::Scissor(u16 x, u16 y, u16 width, u16 height) +{ + glScissor(x, y, width, height); + checkForGlError("glScissor"); +} + void GLGSRender::ExecCMD() { - //return; - if(!LoadProgram()) + if (!LoadProgram()) { LOG_ERROR(RSX, "LoadProgram failed."); Emu.Pause(); @@ -1697,134 +1905,40 @@ void GLGSRender::ExecCMD() } InitDrawBuffers(); - - if (m_set_color_mask) - { - glColorMask(m_color_mask_r, m_color_mask_g, m_color_mask_b, m_color_mask_a); - checkForGlError("glColorMask"); - } - - if (!m_indexed_array.m_count && !m_draw_array_count) - { - u32 min_vertex_size = ~0; - for(auto &i : m_vertex_data) - { - if (!i.size) - continue; - - u32 vertex_size = i.data.size() / (i.size * i.GetTypeSize()); - - if (min_vertex_size > vertex_size) - min_vertex_size = vertex_size; - } - - m_draw_array_count = min_vertex_size; - m_draw_array_first = 0; - } - - Enable(m_set_depth_test, GL_DEPTH_TEST); - Enable(m_set_alpha_test, GL_ALPHA_TEST); - Enable(m_set_depth_bounds_test, GL_DEPTH_BOUNDS_TEST_EXT); - Enable(m_set_blend || m_set_blend_mrt1 || m_set_blend_mrt2 || m_set_blend_mrt3, GL_BLEND); - Enable(m_set_scissor_horizontal && m_set_scissor_vertical, GL_SCISSOR_TEST); - Enable(m_set_logic_op, GL_LOGIC_OP); - Enable(m_set_cull_face, GL_CULL_FACE); - Enable(m_set_dither, GL_DITHER); - Enable(m_set_stencil_test, GL_STENCIL_TEST); - Enable(m_set_line_smooth, GL_LINE_SMOOTH); - Enable(m_set_poly_smooth, GL_POLYGON_SMOOTH); - Enable(m_set_point_sprite_control, GL_POINT_SPRITE); - Enable(m_set_specular, GL_LIGHTING); - Enable(m_set_poly_offset_fill, GL_POLYGON_OFFSET_FILL); - Enable(m_set_poly_offset_line, GL_POLYGON_OFFSET_LINE); - Enable(m_set_poly_offset_point, GL_POLYGON_OFFSET_POINT); - Enable(m_set_restart_index, GL_PRIMITIVE_RESTART); - Enable(m_set_line_stipple, GL_LINE_STIPPLE); - Enable(m_set_polygon_stipple, GL_POLYGON_STIPPLE); - if(m_set_clip_plane) + if (m_set_two_sided_stencil_test_enable) { - Enable(m_clip_plane_0, GL_CLIP_PLANE0); - Enable(m_clip_plane_1, GL_CLIP_PLANE1); - Enable(m_clip_plane_2, GL_CLIP_PLANE2); - Enable(m_clip_plane_3, GL_CLIP_PLANE3); - Enable(m_clip_plane_4, GL_CLIP_PLANE4); - Enable(m_clip_plane_5, GL_CLIP_PLANE5); - - checkForGlError("m_set_clip_plane"); - } - - checkForGlError("glEnable"); - - if (m_set_front_polygon_mode) - { - glPolygonMode(GL_FRONT, m_front_polygon_mode); - checkForGlError("glPolygonMode(Front)"); - } - - if (m_set_back_polygon_mode) - { - glPolygonMode(GL_BACK, m_back_polygon_mode); - checkForGlError("glPolygonMode(Back)"); - } - - if (m_set_point_size) - { - glPointSize(m_point_size); - checkForGlError("glPointSize"); - } - - if (m_set_poly_offset_mode) - { - glPolygonOffset(m_poly_offset_scale_factor, m_poly_offset_bias); - checkForGlError("glPolygonOffset"); - } - - if (m_set_logic_op) - { - glLogicOp(m_logic_op); - checkForGlError("glLogicOp"); - } - - if (m_set_scissor_horizontal && m_set_scissor_vertical) - { - glScissor(m_scissor_x, m_scissor_y, m_scissor_w, m_scissor_h); - checkForGlError("glScissor"); - } - - if(m_set_two_sided_stencil_test_enable) - { - if(m_set_stencil_fail && m_set_stencil_zfail && m_set_stencil_zpass) + if (m_set_stencil_fail && m_set_stencil_zfail && m_set_stencil_zpass) { glStencilOpSeparate(GL_FRONT, m_stencil_fail, m_stencil_zfail, m_stencil_zpass); checkForGlError("glStencilOpSeparate"); } - if(m_set_stencil_mask) + if (m_set_stencil_mask) { glStencilMaskSeparate(GL_FRONT, m_stencil_mask); checkForGlError("glStencilMaskSeparate"); } - if(m_set_stencil_func && m_set_stencil_func_ref && m_set_stencil_func_mask) + if (m_set_stencil_func && m_set_stencil_func_ref && m_set_stencil_func_mask) { glStencilFuncSeparate(GL_FRONT, m_stencil_func, m_stencil_func_ref, m_stencil_func_mask); checkForGlError("glStencilFuncSeparate"); } - if(m_set_back_stencil_fail && m_set_back_stencil_zfail && m_set_back_stencil_zpass) + if (m_set_back_stencil_fail && m_set_back_stencil_zfail && m_set_back_stencil_zpass) { glStencilOpSeparate(GL_BACK, m_back_stencil_fail, m_back_stencil_zfail, m_back_stencil_zpass); checkForGlError("glStencilOpSeparate(GL_BACK)"); } - if(m_set_back_stencil_mask) + if (m_set_back_stencil_mask) { glStencilMaskSeparate(GL_BACK, m_back_stencil_mask); checkForGlError("glStencilMaskSeparate(GL_BACK)"); } - if(m_set_back_stencil_func && m_set_back_stencil_func_ref && m_set_back_stencil_func_mask) + if (m_set_back_stencil_func && m_set_back_stencil_func_ref && m_set_back_stencil_func_mask) { glStencilFuncSeparate(GL_BACK, m_back_stencil_func, m_back_stencil_func_ref, m_back_stencil_func_mask); checkForGlError("glStencilFuncSeparate(GL_BACK)"); @@ -1832,141 +1946,39 @@ void GLGSRender::ExecCMD() } else { - if(m_set_stencil_fail && m_set_stencil_zfail && m_set_stencil_zpass) + if (m_set_stencil_fail && m_set_stencil_zfail && m_set_stencil_zpass) { glStencilOp(m_stencil_fail, m_stencil_zfail, m_stencil_zpass); checkForGlError("glStencilOp"); } - if(m_set_stencil_mask) + if (m_set_stencil_mask) { glStencilMask(m_stencil_mask); checkForGlError("glStencilMask"); } - if(m_set_stencil_func && m_set_stencil_func_ref && m_set_stencil_func_mask) + if (m_set_stencil_func && m_set_stencil_func_ref && m_set_stencil_func_mask) { glStencilFunc(m_stencil_func, m_stencil_func_ref, m_stencil_func_mask); checkForGlError("glStencilFunc"); } } - // TODO: Use other glLightModel functions? - glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, m_set_two_side_light_enable ? GL_TRUE : GL_FALSE); - checkForGlError("glLightModeli"); - - if(m_set_shade_mode) - { - glShadeModel(m_shade_mode); - checkForGlError("glShadeModel"); - } - - if(m_set_depth_mask) - { - glDepthMask(m_depth_mask); - checkForGlError("glDepthMask"); - } - - if(m_set_depth_func) - { - glDepthFunc(m_depth_func); - checkForGlError("glDepthFunc"); - } - - if(m_set_depth_bounds) - { - glDepthBoundsEXT(m_depth_bounds_min, m_depth_bounds_max); - checkForGlError("glDepthBounds"); - } - - if(m_set_clip) - { - glDepthRangef(m_clip_min, m_clip_max); - checkForGlError("glDepthRangef"); - } - - if(m_set_line_width) - { - glLineWidth(m_line_width); - checkForGlError("glLineWidth"); - } - - if (m_set_line_stipple) - { - glLineStipple(m_line_stipple_factor, m_line_stipple_pattern); - checkForGlError("glLineStipple"); - } - if (m_set_polygon_stipple) { glPolygonStipple((const GLubyte*)m_polygon_stipple_pattern); checkForGlError("glPolygonStipple"); } - - if(m_set_blend_equation) - { - glBlendEquationSeparate(m_blend_equation_rgb, m_blend_equation_alpha); - checkForGlError("glBlendEquationSeparate"); - } - if(m_set_blend_sfactor && m_set_blend_dfactor) - { - glBlendFuncSeparate(m_blend_sfactor_rgb, m_blend_dfactor_rgb, m_blend_sfactor_alpha, m_blend_dfactor_alpha); - checkForGlError("glBlendFuncSeparate"); - } - - if(m_set_blend_color) - { - glBlendColor(m_blend_color_r, m_blend_color_g, m_blend_color_b, m_blend_color_a); - checkForGlError("glBlendColor"); - } - - if(m_set_cull_face) - { - glCullFace(m_cull_face); - checkForGlError("glCullFace"); - } - - if (m_set_front_face) - { - glFrontFace(m_front_face); - checkForGlError("glFrontFace"); - } - - if(m_set_alpha_func && m_set_alpha_ref) - { - glAlphaFunc(m_alpha_func, m_alpha_ref); - checkForGlError("glAlphaFunc"); - } - - if(m_set_fog_mode) - { - glFogi(GL_FOG_MODE, m_fog_mode); - checkForGlError("glFogi(GL_FOG_MODE)"); - } - - if(m_set_fog_params) - { - glFogf(GL_FOG_START, m_fog_param0); - checkForGlError("glFogf(GL_FOG_START)"); - glFogf(GL_FOG_END, m_fog_param1); - checkForGlError("glFogf(GL_FOG_END)"); - } - - if(m_set_restart_index) - { - glPrimitiveRestartIndex(m_restart_index); - checkForGlError("glPrimitiveRestartIndex"); - } - - if(m_indexed_array.m_count && m_draw_array_count) + if (m_indexed_array.m_count && m_draw_array_count) { LOG_WARNING(RSX, "m_indexed_array.m_count && draw_array_count"); } - for(u32 i=0; i(m_gcm_buffers_addr); + u32 addr = GetAddress(buffers[m_gcm_current_buffer].offset, CELL_GCM_LOCATION_LOCAL); - if (m_read_buffer) + if (Memory.IsGoodAddr(addr)) { - format = GL_BGRA; - CellGcmDisplayInfo* buffers = vm::get_ptr(m_gcm_buffers_addr); - u32 addr = GetAddress(buffers[m_gcm_current_buffer].offset, CELL_GCM_LOCATION_LOCAL); - - if (Memory.IsGoodAddr(addr)) - { - width = buffers[m_gcm_current_buffer].width; - height = buffers[m_gcm_current_buffer].height; - src_buffer = vm::get_ptr(addr); - } - else - { - src_buffer = nullptr; - } - } - else if (m_fbo.IsCreated()) - { - format = GL_RGBA; - static std::vector pixels; - pixels.resize(RSXThread::m_width * RSXThread::m_height * 4); - m_fbo.Bind(GL_READ_FRAMEBUFFER); - glBindBuffer(GL_PIXEL_PACK_BUFFER, g_pbo[5]); - glBufferData(GL_PIXEL_PACK_BUFFER, RSXThread::m_width * RSXThread::m_height * 4, 0, GL_STREAM_READ); - glReadPixels(0, 0, RSXThread::m_width, RSXThread::m_height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, 0); - checkForGlError("Flip(): glReadPixels(GL_BGRA, GL_UNSIGNED_INT_8_8_8_8)"); - GLubyte *packed = (GLubyte *)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY); - if (packed) - { - memcpy(pixels.data(), packed, RSXThread::m_width * RSXThread::m_height * 4); - glUnmapBuffer(GL_PIXEL_PACK_BUFFER); - checkForGlError("Flip(): glUnmapBuffer"); - } - glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); - - src_buffer = pixels.data(); - width = RSXThread::m_width; - height = RSXThread::m_height; + width = buffers[m_gcm_current_buffer].width; + height = buffers[m_gcm_current_buffer].height; + src_buffer = vm::get_ptr(addr); } else - src_buffer = nullptr; - - if (src_buffer) { - glDisable(GL_STENCIL_TEST); - glDisable(GL_DEPTH_TEST); - glDisable(GL_CLIP_PLANE0); - glDisable(GL_CLIP_PLANE1); - glDisable(GL_CLIP_PLANE2); - glDisable(GL_CLIP_PLANE3); - glDisable(GL_CLIP_PLANE4); - glDisable(GL_CLIP_PLANE5); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, g_flip_tex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, format, GL_UNSIGNED_INT_8_8_8_8, src_buffer); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, 1, 0, 1, 0, 1); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - GLfbo::Bind(GL_DRAW_FRAMEBUFFER, 0); - - m_program.UnUse(); - m_program.Use(); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_ACCUM_BUFFER_BIT); - - glColor3f(1, 1, 1); - glBegin(GL_QUADS); - glTexCoord2i(0, 1); - glVertex2i(0, 0); - - glTexCoord2i(1, 1); - glVertex2i(1, 0); - - glTexCoord2i(1, 0); - glVertex2i(1, 1); - - glTexCoord2i(0, 0); - glVertex2i(0, 1); - glEnd(); + src_buffer = nullptr; } } - break; + else if (m_fbo.IsCreated()) + { + format = GL_RGBA; + static std::vector pixels; + pixels.resize(RSXThread::m_width * RSXThread::m_height * 4); + m_fbo.Bind(GL_READ_FRAMEBUFFER); + glBindBuffer(GL_PIXEL_PACK_BUFFER, g_pbo[5]); + glBufferData(GL_PIXEL_PACK_BUFFER, RSXThread::m_width * RSXThread::m_height * 4, 0, GL_STREAM_READ); + glReadPixels(0, 0, RSXThread::m_width, RSXThread::m_height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, 0); + checkForGlError("Flip(): glReadPixels(GL_BGRA, GL_UNSIGNED_INT_8_8_8_8)"); + GLubyte *packed = (GLubyte *)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY); + if (packed) + { + memcpy(pixels.data(), packed, RSXThread::m_width * RSXThread::m_height * 4); + glUnmapBuffer(GL_PIXEL_PACK_BUFFER); + checkForGlError("Flip(): glUnmapBuffer"); + } + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); + + src_buffer = pixels.data(); + width = RSXThread::m_width; + height = RSXThread::m_height; + } + else + { + src_buffer = nullptr; + } + + if (src_buffer) + { + glDisable(GL_STENCIL_TEST); + glDisable(GL_DEPTH_TEST); + glDisable(GL_CLIP_PLANE0); + glDisable(GL_CLIP_PLANE1); + glDisable(GL_CLIP_PLANE2); + glDisable(GL_CLIP_PLANE3); + glDisable(GL_CLIP_PLANE4); + glDisable(GL_CLIP_PLANE5); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, g_flip_tex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, format, GL_UNSIGNED_INT_8_8_8_8, src_buffer); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, 1, 0, 1, 0, 1); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + GLfbo::Bind(GL_DRAW_FRAMEBUFFER, 0); + + m_program.UnUse(); + m_program.Use(); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_ACCUM_BUFFER_BIT); + + glColor3f(1, 1, 1); + glBegin(GL_QUADS); + glTexCoord2i(0, 1); + glVertex2i(0, 0); + glTexCoord2i(1, 1); + glVertex2i(1, 0); + glTexCoord2i(1, 0); + glVertex2i(1, 1); + glTexCoord2i(0, 0); + glVertex2i(0, 1); + glEnd(); } // Draw Objects - for (uint i = 0; i>= 1; ++shift_count; --log2_width; } - if(log2_height){ + if (log2_height) + { offset |= (y & 0x01) << shift_count; y >>= 1; ++shift_count; --log2_height; } - if(log2_depth){ + if (log2_depth) + { offset |= (z & 0x01) << shift_count; z >>= 1; ++shift_count; diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.h b/rpcs3/Emu/RSX/GL/GLGSRender.h index a598404c8a..dbaa1135ea 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.h +++ b/rpcs3/Emu/RSX/GL/GLGSRender.h @@ -67,7 +67,7 @@ public: class PostDrawObj { protected: - GLShaderProgram m_fp; + GLFragmentProgram m_fp; GLVertexProgram m_vp; GLProgram m_program; GLfbo m_fbo; @@ -144,10 +144,11 @@ private: int m_vp_buf_num; GLProgramBuffer m_prog_buffer; - GLShaderProgram m_shader_prog; + GLFragmentProgram m_fragment_prog; GLVertexProgram m_vertex_prog; GLTexture m_gl_textures[m_textures_count]; + GLTexture m_gl_vertex_textures[m_textures_count]; GLvao m_vao; GLvbo m_vbo; @@ -170,7 +171,6 @@ private: void InitVertexData(); void InitFragmentData(); - void Enable(bool enable, const u32 cap); virtual void Close(); bool LoadProgram(); void WriteBuffers(); @@ -189,7 +189,34 @@ protected: virtual void OnInitThread(); virtual void OnExitThread(); virtual void OnReset(); - virtual void ExecCMD(u32 cmd); virtual void ExecCMD(); + virtual void Enable(u32 cmd, u32 enable); + virtual void ClearColor(u32 a, u32 r, u32 g, u32 b); + virtual void ClearStencil(u32 stencil); + virtual void ClearDepth(u32 depth); + virtual void ClearSurface(u32 mask); + virtual void ColorMask(bool a, bool r, bool g, bool b); + virtual void AlphaFunc(u32 func, float ref); + virtual void DepthFunc(u32 func); + virtual void DepthMask(u32 flag); + virtual void PolygonMode(u32 face, u32 mode); + virtual void PointSize(float size); + virtual void LogicOp(u32 opcdoe); + virtual void LineWidth(float width); + virtual void LineStipple(u16 factor, u16 pattern); + virtual void PrimitiveRestartIndex(u32 index); + virtual void CullFace(u32 mode); + virtual void FrontFace(u32 mode); + virtual void Fogi(u32 mode); + virtual void Fogf(float start, float end); + virtual void PolygonOffset(float factor, float bias); + virtual void DepthRangef(float min, float max); + virtual void BlendEquationSeparate(u16 rgb, u16 a); + virtual void BlendFuncSeparate(u16 srcRGB, u16 dstRGB, u16 srcAlpha, u16 dstAlpha); + virtual void BlendColor(u8 r, u8 g, u8 b, u8 a); + virtual void LightModeli(u32 enable); + virtual void ShadeModel(u32 mode); + virtual void DepthBoundsEXT(float min, float max); + virtual void Scissor(u16 x, u16 y, u16 width, u16 height); virtual void Flip(); }; diff --git a/rpcs3/Emu/RSX/GL/GLProgram.cpp b/rpcs3/Emu/RSX/GL/GLProgram.cpp index e7e7fdaa0a..32f9d709bd 100644 --- a/rpcs3/Emu/RSX/GL/GLProgram.cpp +++ b/rpcs3/Emu/RSX/GL/GLProgram.cpp @@ -98,6 +98,13 @@ void GLProgram::SetTex(u32 index) checkForGlError(fmt::Format("SetTex(%u - %d - %d)", id, index, loc)); } +void GLProgram::SetVTex(u32 index) +{ + int loc = GetLocation(fmt::Format("vtex%u", index)); + glProgramUniform1i(id, loc, index); + checkForGlError(fmt::Format("SetVTex(%u - %d - %d)", id, index, loc)); +} + void GLProgram::Delete() { if(!IsCreated()) return; diff --git a/rpcs3/Emu/RSX/GL/GLProgram.h b/rpcs3/Emu/RSX/GL/GLProgram.h index 321a2e3cf5..076b3ce01f 100644 --- a/rpcs3/Emu/RSX/GL/GLProgram.h +++ b/rpcs3/Emu/RSX/GL/GLProgram.h @@ -24,5 +24,6 @@ public: void Use(); void UnUse(); void SetTex(u32 index); + void SetVTex(u32 index); void Delete(); }; diff --git a/rpcs3/Emu/RSX/GL/GLProgramBuffer.cpp b/rpcs3/Emu/RSX/GL/GLProgramBuffer.cpp index 9550f8342b..f3a358940d 100644 --- a/rpcs3/Emu/RSX/GL/GLProgramBuffer.cpp +++ b/rpcs3/Emu/RSX/GL/GLProgramBuffer.cpp @@ -4,14 +4,14 @@ #include "GLProgramBuffer.h" -int GLProgramBuffer::SearchFp(const RSXShaderProgram& rsx_fp, GLShaderProgram& gl_fp) +int GLProgramBuffer::SearchFp(const RSXFragmentProgram& rsx_fp, GLFragmentProgram& gl_fp) { for(u32 i=0; i(rsx_fp.addr), m_buf[i].fp_data.size()) != 0) continue; - gl_fp.SetId(m_buf[i].fp_id); - gl_fp.SetShaderText(m_buf[i].fp_shader); + gl_fp.id = m_buf[i].fp_id; + gl_fp.shader = m_buf[i].fp_shader.c_str(); return i; } @@ -85,37 +85,37 @@ u32 GLProgramBuffer::GetProg(u32 fp, u32 vp) const return 0; } -void GLProgramBuffer::Add(GLProgram& prog, GLShaderProgram& gl_fp, RSXShaderProgram& rsx_fp, GLVertexProgram& gl_vp, RSXVertexProgram& rsx_vp) +void GLProgramBuffer::Add(GLProgram& prog, GLFragmentProgram& gl_fp, RSXFragmentProgram& rsx_fp, GLVertexProgram& gl_vp, RSXVertexProgram& rsx_vp) { GLBufferInfo new_buf; LOG_NOTICE(RSX, "Add program (%d):", m_buf.size()); LOG_NOTICE(RSX, "*** prog id = %d", prog.id); LOG_NOTICE(RSX, "*** vp id = %d", gl_vp.id); - LOG_NOTICE(RSX, "*** fp id = %d", gl_fp.GetId()); + LOG_NOTICE(RSX, "*** fp id = %d", gl_fp.id); LOG_NOTICE(RSX, "*** vp data size = %d", rsx_vp.data.size() * 4); LOG_NOTICE(RSX, "*** fp data size = %d", rsx_fp.size); LOG_NOTICE(RSX, "*** vp shader = \n%s", gl_vp.shader.c_str()); - LOG_NOTICE(RSX, "*** fp shader = \n%s", gl_fp.GetShaderText().c_str()); + LOG_NOTICE(RSX, "*** fp shader = \n%s", gl_fp.shader.c_str()); new_buf.prog_id = prog.id; new_buf.vp_id = gl_vp.id; - new_buf.fp_id = gl_fp.GetId(); + new_buf.fp_id = gl_fp.id; new_buf.fp_data.insert(new_buf.fp_data.end(), vm::get_ptr(rsx_fp.addr), vm::get_ptr(rsx_fp.addr + rsx_fp.size)); new_buf.vp_data = rsx_vp.data; new_buf.vp_shader = gl_vp.shader; - new_buf.fp_shader = gl_fp.GetShaderText(); + new_buf.fp_shader = gl_fp.shader; m_buf.push_back(new_buf); } void GLProgramBuffer::Clear() { - for(u32 i=0; i m_buf; - int SearchFp(const RSXShaderProgram& rsx_fp, GLShaderProgram& gl_fp); + int SearchFp(const RSXFragmentProgram& rsx_fp, GLFragmentProgram& gl_fp); int SearchVp(const RSXVertexProgram& rsx_vp, GLVertexProgram& gl_vp); bool CmpVP(const u32 a, const u32 b) const; @@ -24,6 +24,6 @@ struct GLProgramBuffer u32 GetProg(u32 fp, u32 vp) const; - void Add(GLProgram& prog, GLShaderProgram& gl_fp, RSXShaderProgram& rsx_fp, GLVertexProgram& gl_vp, RSXVertexProgram& rsx_vp); + void Add(GLProgram& prog, GLFragmentProgram& gl_fp, RSXFragmentProgram& rsx_fp, GLVertexProgram& gl_vp, RSXVertexProgram& rsx_vp); void Clear(); }; diff --git a/rpcs3/Emu/RSX/GL/GLShaderParam.h b/rpcs3/Emu/RSX/GL/GLShaderParam.h index 80fa5a3dec..f90402eda0 100644 --- a/rpcs3/Emu/RSX/GL/GLShaderParam.h +++ b/rpcs3/Emu/RSX/GL/GLShaderParam.h @@ -1,5 +1,6 @@ #pragma once #include "OpenGL.h" +#include enum GLParamFlag { @@ -41,9 +42,9 @@ struct GLParamType bool SearchName(const std::string& name) { - for(u32 i=0; iSearchName(name)) t->items.emplace_back(name, -1, value); + if (!t->SearchName(name)) t->items.emplace_back(name, -1, value); } else { @@ -125,9 +126,9 @@ struct GLParamArray type = GetParamFlag(flag) + type; GLParamType* t = SearchParam(type); - if(t) + if (t) { - if(!t->SearchName(name)) t->items.emplace_back(name, location); + if (!t->SearchName(name)) t->items.emplace_back(name, location); } else { @@ -139,3 +140,90 @@ struct GLParamArray return name; } }; + +class ShaderVar +{ +public: + std::string name; + std::vector swizzles; + + ShaderVar() = default; + ShaderVar(const std::string& var) + { + auto var_blocks = fmt::split(var, { "." }); + + if (var_blocks.size() == 0) + { + assert(0); + } + + name = var_blocks[0]; + + if (var_blocks.size() == 1) + { + swizzles.push_back("xyzw"); + } + else + { + swizzles = std::vector(var_blocks.begin() + 1, var_blocks.end()); + } + } + + int get_vector_size() const + { + return swizzles[swizzles.size() - 1].length(); + } + + ShaderVar& symplify() + { + std::unordered_map swizzle; + + static std::unordered_map pos_to_swizzle = + { + { 0, 'x' }, + { 1, 'y' }, + { 2, 'z' }, + { 3, 'w' } + }; + + for (auto &i : pos_to_swizzle) + { + swizzle[i.second] = swizzles[0].length() > i.first ? swizzles[0][i.first] : 0; + } + + for (int i = 1; i < swizzles.size(); ++i) + { + std::unordered_map new_swizzle; + + for (auto &sw : pos_to_swizzle) + { + new_swizzle[sw.second] = swizzle[swizzles[i].length() <= sw.first ? '\0' : swizzles[i][sw.first]]; + } + + swizzle = new_swizzle; + } + + swizzles.clear(); + std::string new_swizzle; + + for (auto &i : pos_to_swizzle) + { + if (swizzle[i.second] != '\0') + new_swizzle += swizzle[i.second]; + } + + swizzles.push_back(new_swizzle); + + return *this; + } + + std::string get() const + { + if (swizzles.size() == 1 && swizzles[0] == "xyzw") + { + return name; + } + + return name + "." + fmt::merge({ swizzles }, "."); + } +}; \ No newline at end of file diff --git a/rpcs3/Emu/RSX/GL/GLVertexProgram.cpp b/rpcs3/Emu/RSX/GL/GLVertexProgram.cpp index b67cccd255..28723bf0b6 100644 --- a/rpcs3/Emu/RSX/GL/GLVertexProgram.cpp +++ b/rpcs3/Emu/RSX/GL/GLVertexProgram.cpp @@ -8,19 +8,19 @@ std::string GLVertexDecompilerThread::GetMask(bool is_sca) { std::string ret; - if(is_sca) + if (is_sca) { - if(d3.sca_writemask_x) ret += "x"; - if(d3.sca_writemask_y) ret += "y"; - if(d3.sca_writemask_z) ret += "z"; - if(d3.sca_writemask_w) ret += "w"; + if (d3.sca_writemask_x) ret += "x"; + if (d3.sca_writemask_y) ret += "y"; + if (d3.sca_writemask_z) ret += "z"; + if (d3.sca_writemask_w) ret += "w"; } else { - if(d3.vec_writemask_x) ret += "x"; - if(d3.vec_writemask_y) ret += "y"; - if(d3.vec_writemask_z) ret += "z"; - if(d3.vec_writemask_w) ret += "w"; + if (d3.vec_writemask_x) ret += "x"; + if (d3.vec_writemask_y) ret += "y"; + if (d3.vec_writemask_z) ret += "z"; + if (d3.vec_writemask_w) ret += "w"; } return ret.empty() || ret == "xyzw" ? "" : ("." + ret); @@ -40,17 +40,17 @@ std::string GLVertexDecompilerThread::GetDST(bool isSca) { std::string ret; - switch(isSca ? 0x1f : d3.dst) + switch (isSca ? 0x1f : d3.dst) { case 0x1f: ret += m_parr.AddParam(PARAM_NONE, "vec4", std::string("tmp") + std::to_string(isSca ? d3.sca_dst_tmp : d0.dst_tmp)); - break; + break; default: if (d3.dst > 15) LOG_ERROR(RSX, "dst index out of range: %u", d3.dst); ret += m_parr.AddParam(PARAM_NONE, "vec4", std::string("dst_reg") + std::to_string(d3.dst), d3.dst == 0 ? "vec4(0.0f, 0.0f, 0.0f, 1.0f)" : "vec4(0.0)"); - break; + break; } return ret; @@ -58,7 +58,7 @@ std::string GLVertexDecompilerThread::GetDST(bool isSca) std::string GLVertexDecompilerThread::GetSRC(const u32 n) { - static const std::string reg_table[] = + static const std::string reg_table[] = { "in_pos", "in_weight", "in_normal", "in_diff_color", "in_spec_color", @@ -70,13 +70,13 @@ std::string GLVertexDecompilerThread::GetSRC(const u32 n) std::string ret; - switch(src[n].reg_type) + switch (src[n].reg_type) { case 1: //temp ret += m_parr.AddParam(PARAM_NONE, "vec4", "tmp" + std::to_string(src[n].tmp_src)); - break; + break; case 2: //input - if (d1.input_src < (sizeof(reg_table)/sizeof(reg_table[0]))) + if (d1.input_src < (sizeof(reg_table) / sizeof(reg_table[0]))) { ret += m_parr.AddParam(PARAM_IN, "vec4", reg_table[d1.input_src], d1.input_src); } @@ -85,16 +85,16 @@ std::string GLVertexDecompilerThread::GetSRC(const u32 n) LOG_ERROR(RSX, "Bad input src num: %d", fmt::by_value(d1.input_src)); ret += m_parr.AddParam(PARAM_IN, "vec4", "in_unk", d1.input_src); } - break; + break; case 3: //const m_parr.AddParam(PARAM_UNIFORM, "vec4", std::string("vc[468]")); ret += std::string("vc[") + std::to_string(d1.const_src) + (d3.index_const ? " + " + AddAddrReg() : "") + "]"; - break; + break; default: LOG_ERROR(RSX, "Bad src%u reg type: %d", n, fmt::by_value(src[n].reg_type)); Emu.Pause(); - break; + break; } static const std::string f = "xyzw"; @@ -106,26 +106,26 @@ std::string GLVertexDecompilerThread::GetSRC(const u32 n) swizzle += f[src[n].swz_z]; swizzle += f[src[n].swz_w]; - if(swizzle != f) ret += '.' + swizzle; + if (swizzle != f) ret += '.' + swizzle; bool abs; - - switch(n) + + switch (n) { case 0: abs = d0.src0_abs; break; case 1: abs = d0.src1_abs; break; case 2: abs = d0.src2_abs; break; } - - if(abs) ret = "abs(" + ret + ")"; - if(src[n].neg) ret = "-" + ret; + + if (abs) ret = "abs(" + ret + ")"; + if (src[n].neg) ret = "-" + ret; return ret; } void GLVertexDecompilerThread::SetDST(bool is_sca, std::string value) { - if(d0.cond == 0) return; + if (d0.cond == 0) return; enum { @@ -138,12 +138,12 @@ void GLVertexDecompilerThread::SetDST(bool is_sca, std::string value) value += mask; - if(is_sca && d0.vec_result) + if (is_sca && d0.vec_result) { - value = "vec4(" + value + ")" + mask; + //value = "vec4(" + value + ")"; } - if(d0.staturate) + if (d0.staturate) { value = "clamp(" + value + ", 0.0, 1.0)"; } @@ -152,22 +152,20 @@ void GLVertexDecompilerThread::SetDST(bool is_sca, std::string value) if (d0.cond_update_enable_0 && d0.cond_update_enable_1) { - dest += m_parr.AddParam(PARAM_NONE, "vec4", "cc" + std::to_string(d0.cond_reg_sel_1), "vec4(0.0)") + mask + " = "; + dest = m_parr.AddParam(PARAM_NONE, "vec4", "cc" + std::to_string(d0.cond_reg_sel_1), "vec4(0.0)") + mask; } - - if (d3.dst != 0x1f || (is_sca ? d3.sca_dst_tmp != 0x3f : d0.dst_tmp != 0x3f)) + else if (d3.dst != 0x1f || (is_sca ? d3.sca_dst_tmp != 0x3f : d0.dst_tmp != 0x3f)) { - dest += GetDST(is_sca) + mask + " = "; + dest = GetDST(is_sca) + mask; } - std::string code; + //std::string code; + //if (d0.cond_test_enable) + // code += "$ifcond "; + //code += dest + value; + //AddCode(code + ";"); - if (d0.cond_test_enable) - code += "$ifcond "; - - code += dest + value; - - AddCode(code + ";"); + AddCodeCond(Format(dest), value); } std::string GLVertexDecompilerThread::GetFunc() @@ -188,6 +186,11 @@ std::string GLVertexDecompilerThread::GetFunc() return name + "()"; } +std::string GLVertexDecompilerThread::GetTex() +{ + return m_parr.AddParam(PARAM_UNIFORM, "sampler2D", std::string("vtex") + std::to_string(/*?.tex_num*/0)); +} + std::string GLVertexDecompilerThread::Format(const std::string& code) { const std::pair> repl_list[] = @@ -200,14 +203,16 @@ std::string GLVertexDecompilerThread::Format(const std::string& code) { "$am", std::bind(std::mem_fn(&GLVertexDecompilerThread::AddAddrMask), this) }, { "$a", std::bind(std::mem_fn(&GLVertexDecompilerThread::AddAddrReg), this) }, - { "$fa", [this]()->std::string {return std::to_string(GetAddr()); } }, + { "$t", std::bind(std::mem_fn(&GLVertexDecompilerThread::GetTex), this) }, + + { "$fa", [this]()->std::string { return std::to_string(GetAddr()); } }, { "$f()", std::bind(std::mem_fn(&GLVertexDecompilerThread::GetFunc), this) }, { "$ifcond ", [this]() -> std::string - { - const std::string& cond = GetCond(); - if (cond == "true") return ""; - return "if(" + cond + ") "; - } + { + const std::string& cond = GetCond(); + if (cond == "true") return ""; + return "if(" + cond + ") "; + } }, { "$cond", std::bind(std::mem_fn(&GLVertexDecompilerThread::GetCond), this) } }; @@ -252,6 +257,70 @@ std::string GLVertexDecompilerThread::GetCond() return fmt::Format("any(%s(cc%d%s, vec4(0.0)%s))", cond_string_table[d0.cond], d0.cond_reg_sel_1, swizzle.c_str(), swizzle.c_str()); } +void GLVertexDecompilerThread::AddCodeCond(const std::string& dst, const std::string& src) +{ + enum + { + lt = 0x1, + eq = 0x2, + gt = 0x4, + }; + + + if (!d0.cond_test_enable || d0.cond == (lt | gt | eq)) + { + AddCode(dst + " = " + src + ";"); + return; + } + + if (d0.cond == 0) + { + AddCode("//" + dst + " = " + src + ";"); + return; + } + + static const char* cond_string_table[(lt | gt | eq) + 1] = + { + "error", + "lessThan", + "equal", + "lessThanEqual", + "greaterThan", + "notEqual", + "greaterThanEqual", + "error" + }; + + static const char f[4] = { 'x', 'y', 'z', 'w' }; + + std::string swizzle; + swizzle += f[d0.mask_x]; + swizzle += f[d0.mask_y]; + swizzle += f[d0.mask_z]; + swizzle += f[d0.mask_w]; + + swizzle = swizzle == "xyzw" ? "" : "." + swizzle; + + std::string cond = fmt::Format("%s(cc%d%s, vec4(0.0))", cond_string_table[d0.cond], d0.cond_reg_sel_1, swizzle.c_str()); + + ShaderVar dst_var(dst); + dst_var.symplify(); + + //const char *c_mask = f; + + if (dst_var.swizzles[0].length() == 1) + { + AddCode("if (" + cond + ".x) " + dst + " = vec4(" + src + ").x;"); + } + else + { + for (int i = 0; i < dst_var.swizzles[0].length(); ++i) + { + AddCode("if (" + cond + "." + f[i] + ") " + dst + "." + f[i] + " = " + src + "." + f[i] + ";"); + } + } +} + std::string GLVertexDecompilerThread::AddAddrMask() { @@ -290,21 +359,21 @@ std::string GLVertexDecompilerThread::BuildFuncBody(const FuncInfo& func) { std::string result; - for(uint i=func.offset; i0; --i) + for (int i = m_funcs.size() - 1; i > 0; --i) { fp += fmt::Format("void %s();\n", m_funcs[i].name.c_str()); } @@ -423,7 +492,7 @@ std::string GLVertexDecompilerThread::BuildCode() f += fmt::Format("\nvoid %s()\n{\n%s}\n", m_funcs[1].name.c_str(), main_body.c_str()); - for(uint i=2; iopen_scopes++; + + AddCode(fmt::Format("if (jump_position <= %u)", jump_position++)); + AddCode("{"); + m_cur_instr->open_scopes++; + } + + for (u32 i = 0; i < m_instr_count; ++i) + { + m_cur_instr = &m_instructions[i]; + + d0.HEX = m_data[i * 4 + 0]; + d1.HEX = m_data[i * 4 + 1]; + d2.HEX = m_data[i * 4 + 2]; + d3.HEX = m_data[i * 4 + 3]; src[0].src0l = d2.src0l; src[0].src0h = d1.src0h; @@ -462,107 +600,168 @@ void GLVertexDecompilerThread::Task() src[2].src2l = d3.src2l; src[2].src2h = d2.src2h; - if(!d1.sca_opcode && !d1.vec_opcode) + if (i && (is_has_BRA || std::find(m_jump_lvls.begin(), m_jump_lvls.end(), i) != m_jump_lvls.end())) { - m_body.push_back("//nop"); + m_cur_instr->close_scopes++; + AddCode("}"); + AddCode(""); + + AddCode(fmt::Format("if (jump_position <= %u)", jump_position++)); + AddCode("{"); + m_cur_instr->open_scopes++; } - switch(d1.sca_opcode) + if (!d1.sca_opcode && !d1.vec_opcode) { - case 0x00: break; // NOP - case 0x01: SetDSTSca("$s"); break; // MOV - case 0x02: SetDSTSca("(1.0 / $s)"); break; // RCP - case 0x03: SetDSTSca("clamp(1.0 / $s, 5.42101e-20, 1.884467e19)"); break; // RCC - case 0x04: SetDSTSca("inversesqrt(abs($s))"); break; // RSQ - case 0x05: SetDSTSca("exp($s)"); break; // EXP - case 0x06: SetDSTSca("log($s)"); break; // LOG - case 0x07: SetDSTSca("vec4(1.0, $s.x, ($s.x > 0 ? exp2($s.w * log2($s.y)) : 0.0), 1.0)"); break; // LIT - //case 0x08: break; // BRA - case 0x09: // BRI : works differently (BRI o[1].x(TR) L0;) - //AddCode("$ifcond { $f(); return; }"); - if (GetAddr() > m_instr_count) + AddCode("//nop"); + } + + switch (d1.sca_opcode) + { + case RSX_SCA_OPCODE_NOP: break; + case RSX_SCA_OPCODE_MOV: SetDSTSca("$s"); break; + case RSX_SCA_OPCODE_RCP: SetDSTSca("(1.0 / $s)"); break; + case RSX_SCA_OPCODE_RCC: SetDSTSca("clamp(1.0 / $s, 5.42101e-20, 1.884467e19)"); break; + case RSX_SCA_OPCODE_RSQ: SetDSTSca("inversesqrt(abs($s))"); break; + case RSX_SCA_OPCODE_EXP: SetDSTSca("exp($s)"); break; + case RSX_SCA_OPCODE_LOG: SetDSTSca("log($s)"); break; + case RSX_SCA_OPCODE_LIT: SetDSTSca("vec4(1.0, $s.x, ($s.x > 0.0 ? exp($s.w * log2($s.y)) : 0.0), 1.0)"); break; + case RSX_SCA_OPCODE_BRA: + { + AddCode("$if ($cond)"); + AddCode("{"); + m_cur_instr->open_scopes++; + AddCode("jump_position = $a$am;"); + AddCode("continue;"); + m_cur_instr->close_scopes++; + AddCode("}"); + } + break; + /* This triggers opengl driver lost connection error code 7 + case RSX_SCA_OPCODE_BRI: // works differently (BRI o[1].x(TR) L0;) + { + uint jump_position; + + if (is_has_BRA) { - AddCode("if(!$cond)"); - AddCode("{"); - m_cur_instr->open_scopes++; - m_instructions[GetAddr()].put_close_scopes++; + jump_position = GetAddr(); } else { - AddCode("} while ($cond);"); - m_cur_instr->close_scopes++; - m_instructions[GetAddr()].do_count++; + int addr = GetAddr(); + + jump_position = 0; + for (auto pos : m_jump_lvls) + { + if (addr == pos) + break; + + ++jump_position; + } } + + AddCode("$ifcond "); + AddCode("{"); + m_cur_instr->open_scopes++; + AddCode(fmt::Format("jump_position = %u;", jump_position)); + AddCode("continue;"); + m_cur_instr->close_scopes++; + AddCode("}"); + } break; - //case 0x0a: AddCode("$ifcond $f(); //CAL"); break; // CAL : works same as BRI - case 0x0b: AddCode("$ifcond $f(); //CLI"); break; // CLI : works same as BRI - case 0x0c: AddCode("$ifcond return;"); break; // RET : works like BRI but shorter (RET o[1].x(TR);) - case 0x0d: SetDSTSca("log2($s)"); break; // LG2 - case 0x0e: SetDSTSca("exp2($s)"); break; // EX2 - case 0x0f: SetDSTSca("sin($s)"); break; // SIN - case 0x10: SetDSTSca("cos($s)"); break; // COS - //case 0x11: break; // BRB : works differently (BRB o[1].x !b0, L0;) - //case 0x12: break; // CLB : works same as BRB - //case 0x13: break; // PSH : works differently (PSH o[1].x A0;) - //case 0x14: break; // POP : works differently (POP o[1].x;) + */ + case RSX_SCA_OPCODE_CAL: + // works same as BRI + AddCode("$ifcond $f(); //CAL"); + break; + case RSX_SCA_OPCODE_CLI: + // works same as BRI + AddCode("$ifcond $f(); //CLI"); + break; + case RSX_SCA_OPCODE_RET: + // works like BRI but shorter (RET o[1].x(TR);) + AddCode("$ifcond return;"); + break; + case RSX_SCA_OPCODE_LG2: SetDSTSca("log2($s)"); break; + case RSX_SCA_OPCODE_EX2: SetDSTSca("exp2($s)"); break; + case RSX_SCA_OPCODE_SIN: SetDSTSca("sin($s)"); break; + case RSX_SCA_OPCODE_COS: SetDSTSca("cos($s)"); break; + case RSX_SCA_OPCODE_BRB: + // works differently (BRB o[1].x !b0, L0;) + LOG_ERROR(RSX, "Unimplemented sca_opcode BRB"); + break; + case RSX_SCA_OPCODE_CLB: break; + // works same as BRB + LOG_ERROR(RSX, "Unimplemented sca_opcode CLB"); + break; + case RSX_SCA_OPCODE_PSH: break; + // works differently (PSH o[1].x A0;) + LOG_ERROR(RSX, "Unimplemented sca_opcode PSH"); + break; + case RSX_SCA_OPCODE_POP: break; + // works differently (POP o[1].x;) + LOG_ERROR(RSX, "Unimplemented sca_opcode POP"); + break; default: - m_body.push_back(fmt::Format("//Unknown vp sca_opcode 0x%x", fmt::by_value(d1.sca_opcode))); + AddCode(fmt::Format("//Unknown vp sca_opcode 0x%x", fmt::by_value(d1.sca_opcode))); LOG_ERROR(RSX, "Unknown vp sca_opcode 0x%x", fmt::by_value(d1.sca_opcode)); Emu.Pause(); - break; + break; } - switch(d1.vec_opcode) + switch (d1.vec_opcode) { - case 0x00: break; //NOP - case 0x01: SetDSTVec("$0"); break; //MOV - case 0x02: SetDSTVec("($0 * $1)"); break; //MUL - case 0x03: SetDSTVec("($0 + $2)"); break; //ADD - case 0x04: SetDSTVec("($0 * $1 + $2)"); break; //MAD - case 0x05: SetDSTVec("vec4(dot($0.xyz, $1.xyz))"); break; //DP3 - case 0x06: SetDSTVec("vec4(dot(vec4($0.xyz, 1.0), $1))"); break; //DPH - case 0x07: SetDSTVec("vec4(dot($0, $1))"); break; //DP4 - case 0x08: SetDSTVec("vec4(distance($0, $1))"); break; //DST - case 0x09: SetDSTVec("min($0, $1)"); break; //MIN - case 0x0a: SetDSTVec("max($0, $1)"); break; //MAX - case 0x0b: SetDSTVec("vec4(lessThan($0, $1))"); break; //SLT - case 0x0c: SetDSTVec("vec4(greaterThanEqual($0, $1))"); break; //SGE - case 0x0d: AddCode("$ifcond $a = ivec4($0)$am;"); break; //ARL - case 0x0e: SetDSTVec("fract($0)"); break; //FRC - case 0x0f: SetDSTVec("floor($0)"); break; //FLR - case 0x10: SetDSTVec("vec4(equal($0, $1))"); break; //SEQ - case 0x11: SetDSTVec("vec4(equal($0, vec4(0.0)))"); break; //SFL - case 0x12: SetDSTVec("vec4(greaterThan($0, $1))"); break; //SGT - case 0x13: SetDSTVec("vec4(lessThanEqual($0, $1))"); break; //SLE - case 0x14: SetDSTVec("vec4(notEqual($0, $1))"); break; //SNE - case 0x15: SetDSTVec("vec4(equal($0, vec4(1.0)))"); break; //STR - case 0x16: SetDSTVec("sign($0)"); break; //SSG + case RSX_VEC_OPCODE_NOP: break; + case RSX_VEC_OPCODE_MOV: SetDSTVec("$0"); break; + case RSX_VEC_OPCODE_MUL: SetDSTVec("($0 * $1)"); break; + case RSX_VEC_OPCODE_ADD: SetDSTVec("($0 + $2)"); break; + case RSX_VEC_OPCODE_MAD: SetDSTVec("($0 * $1 + $2)"); break; + case RSX_VEC_OPCODE_DP3: SetDSTVec("vec4(dot($0.xyz, $1.xyz))"); break; + case RSX_VEC_OPCODE_DPH: SetDSTVec("vec4(dot(vec4($0.xyz, 1.0), $1))"); break; + case RSX_VEC_OPCODE_DP4: SetDSTVec("vec4(dot($0, $1))"); break; + case RSX_VEC_OPCODE_DST: SetDSTVec("vec4(distance($0, $1))"); break; + case RSX_VEC_OPCODE_MIN: SetDSTVec("min($0, $1)"); break; + case RSX_VEC_OPCODE_MAX: SetDSTVec("max($0, $1)"); break; + case RSX_VEC_OPCODE_SLT: SetDSTVec("vec4(lessThan($0, $1))"); break; + case RSX_VEC_OPCODE_SGE: SetDSTVec("vec4(greaterThanEqual($0, $1))"); break; + case RSX_VEC_OPCODE_ARL: AddCode("$ifcond $a = ivec4($0)$am;"); break; + case RSX_VEC_OPCODE_FRC: SetDSTVec("fract($0)"); break; + case RSX_VEC_OPCODE_FLR: SetDSTVec("floor($0)"); break; + case RSX_VEC_OPCODE_SEQ: SetDSTVec("vec4(equal($0, $1))"); break; + case RSX_VEC_OPCODE_SFL: SetDSTVec("vec4(equal($0, vec4(0.0)))"); break; + case RSX_VEC_OPCODE_SGT: SetDSTVec("vec4(greaterThan($0, $1))"); break; + case RSX_VEC_OPCODE_SLE: SetDSTVec("vec4(lessThanEqual($0, $1))"); break; + case RSX_VEC_OPCODE_SNE: SetDSTVec("vec4(notEqual($0, $1))"); break; + case RSX_VEC_OPCODE_STR: SetDSTVec("vec4(equal($0, vec4(1.0)))"); break; + case RSX_VEC_OPCODE_SSG: SetDSTVec("sign($0)"); break; + case RSX_VEC_OPCODE_TEX: SetDSTVec("texture($t, $0.xy)"); break; default: - m_body.push_back(fmt::Format("//Unknown vp opcode 0x%x", fmt::by_value(d1.vec_opcode))); + AddCode(fmt::Format("//Unknown vp opcode 0x%x", fmt::by_value(d1.vec_opcode))); LOG_ERROR(RSX, "Unknown vp opcode 0x%x", fmt::by_value(d1.vec_opcode)); Emu.Pause(); - break; - } - - if(d3.end) - { - m_instr_count++; - - if(i < m_data.size()) - LOG_ERROR(RSX, "Program end before buffer end."); - break; } } + if (is_has_BRA || !m_jump_lvls.empty()) + { + m_cur_instr = &m_instructions[m_instr_count - 1]; + m_cur_instr->close_scopes++; + AddCode("}"); + AddCode("break;"); + m_cur_instr->close_scopes++; + AddCode("}"); + } + m_shader = BuildCode(); + m_jump_lvls.clear(); m_body.clear(); if (m_funcs.size() > 2) { - m_funcs.erase(m_funcs.begin()+2, m_funcs.end()); + m_funcs.erase(m_funcs.begin() + 2, m_funcs.end()); } } @@ -574,10 +773,10 @@ GLVertexProgram::GLVertexProgram() GLVertexProgram::~GLVertexProgram() { - if(m_decompiler_thread) + if (m_decompiler_thread) { Wait(); - if(m_decompiler_thread->IsAlive()) + if (m_decompiler_thread->IsAlive()) { m_decompiler_thread->Stop(); } @@ -591,7 +790,7 @@ GLVertexProgram::~GLVertexProgram() void GLVertexProgram::Wait() { - if(m_decompiler_thread && m_decompiler_thread->IsAlive()) + if (m_decompiler_thread && m_decompiler_thread->IsAlive()) { m_decompiler_thread->Join(); } @@ -623,7 +822,10 @@ void GLVertexProgram::DecompileAsync(RSXVertexProgram& prog) void GLVertexProgram::Compile() { - if(id) glDeleteShader(id); + if (id) + { + glDeleteShader(id); + } id = glCreateShader(GL_VERTEX_SHADER); @@ -632,16 +834,16 @@ void GLVertexProgram::Compile() glShaderSource(id, 1, &str, &strlen); glCompileShader(id); - + GLint r = GL_FALSE; glGetShaderiv(id, GL_COMPILE_STATUS, &r); - if(r != GL_TRUE) + if (r != GL_TRUE) { glGetShaderiv(id, GL_INFO_LOG_LENGTH, &r); - if(r) + if (r) { - char* buf = new char[r+1](); + char* buf = new char[r + 1](); GLsizei len; glGetShaderInfoLog(id, r, &len, buf); LOG_ERROR(RSX, "Failed to compile vertex shader: %s", buf); @@ -660,7 +862,7 @@ void GLVertexProgram::Delete() parr.params.clear(); shader.clear(); - if(id) + if (id) { if (Emu.IsStopped()) { diff --git a/rpcs3/Emu/RSX/GL/GLVertexProgram.h b/rpcs3/Emu/RSX/GL/GLVertexProgram.h index ef87c4cca7..de4c3d07cd 100644 --- a/rpcs3/Emu/RSX/GL/GLVertexProgram.h +++ b/rpcs3/Emu/RSX/GL/GLVertexProgram.h @@ -2,6 +2,60 @@ #include "GLShaderParam.h" #include "Emu/RSX/RSXVertexProgram.h" #include "Utilities/Thread.h" +#include + +enum sca_opcode +{ + RSX_SCA_OPCODE_NOP = 0x00, + RSX_SCA_OPCODE_MOV = 0x01, + RSX_SCA_OPCODE_RCP = 0x02, + RSX_SCA_OPCODE_RCC = 0x03, + RSX_SCA_OPCODE_RSQ = 0x04, + RSX_SCA_OPCODE_EXP = 0x05, + RSX_SCA_OPCODE_LOG = 0x06, + RSX_SCA_OPCODE_LIT = 0x07, + RSX_SCA_OPCODE_BRA = 0x08, + RSX_SCA_OPCODE_BRI = 0x09, + RSX_SCA_OPCODE_CAL = 0x0a, + RSX_SCA_OPCODE_CLI = 0x0b, + RSX_SCA_OPCODE_RET = 0x0c, + RSX_SCA_OPCODE_LG2 = 0x0d, + RSX_SCA_OPCODE_EX2 = 0x0e, + RSX_SCA_OPCODE_SIN = 0x0f, + RSX_SCA_OPCODE_COS = 0x10, + RSX_SCA_OPCODE_BRB = 0x11, + RSX_SCA_OPCODE_CLB = 0x12, + RSX_SCA_OPCODE_PSH = 0x13, + RSX_SCA_OPCODE_POP = 0x14, +}; + +enum vec_opcode +{ + RSX_VEC_OPCODE_NOP = 0x00, + RSX_VEC_OPCODE_MOV = 0x01, + RSX_VEC_OPCODE_MUL = 0x02, + RSX_VEC_OPCODE_ADD = 0x03, + RSX_VEC_OPCODE_MAD = 0x04, + RSX_VEC_OPCODE_DP3 = 0x05, + RSX_VEC_OPCODE_DPH = 0x06, + RSX_VEC_OPCODE_DP4 = 0x07, + RSX_VEC_OPCODE_DST = 0x08, + RSX_VEC_OPCODE_MIN = 0x09, + RSX_VEC_OPCODE_MAX = 0x0a, + RSX_VEC_OPCODE_SLT = 0x0b, + RSX_VEC_OPCODE_SGE = 0x0c, + RSX_VEC_OPCODE_ARL = 0x0d, + RSX_VEC_OPCODE_FRC = 0x0e, + RSX_VEC_OPCODE_FLR = 0x0f, + RSX_VEC_OPCODE_SEQ = 0x10, + RSX_VEC_OPCODE_SFL = 0x11, + RSX_VEC_OPCODE_SGT = 0x12, + RSX_VEC_OPCODE_SLE = 0x13, + RSX_VEC_OPCODE_SNE = 0x14, + RSX_VEC_OPCODE_STR = 0x15, + RSX_VEC_OPCODE_SSG = 0x16, + RSX_VEC_OPCODE_TEX = 0x19, +}; struct GLVertexDecompilerThread : public ThreadBase { @@ -154,8 +208,8 @@ struct GLVertexDecompilerThread : public ThreadBase Instruction* m_cur_instr; size_t m_instr_count; + std::set m_jump_lvls; std::vector m_body; - std::vector m_funcs; //wxString main; @@ -184,12 +238,14 @@ struct GLVertexDecompilerThread : public ThreadBase std::string GetDST(bool is_sca = false); std::string GetSRC(const u32 n); std::string GetFunc(); + std::string GetTex(); std::string GetCond(); std::string AddAddrMask(); std::string AddAddrReg(); u32 GetAddr(); std::string Format(const std::string& code); + void AddCodeCond(const std::string& dst, const std::string& src); void AddCode(const std::string& code); void SetDST(bool is_sca, std::string value); void SetDSTVec(const std::string& code); diff --git a/rpcs3/Emu/RSX/Null/NullGSRender.h b/rpcs3/Emu/RSX/Null/NullGSRender.h index 1fa7104356..de2167a8b7 100644 --- a/rpcs3/Emu/RSX/Null/NullGSRender.h +++ b/rpcs3/Emu/RSX/Null/NullGSRender.h @@ -6,44 +6,43 @@ class NullGSRender { public: - NullGSRender() - { - } - - virtual ~NullGSRender() - { - } + NullGSRender() {} + virtual ~NullGSRender() {} private: - virtual void OnInit() - { - } - - virtual void OnInitThread() - { - } - - virtual void OnExitThread() - { - } - - virtual void OnReset() - { - } - - virtual void ExecCMD(u32 cmd) - { - } - - virtual void ExecCMD() - { - } - - virtual void Flip() - { - } - - virtual void Close() - { - } + virtual void OnInit() {} + virtual void OnInitThread() {} + virtual void OnExitThread() {} + virtual void OnReset() {} + virtual void Enable(u32 cmd, u32 enable) {} + virtual void ClearColor(u32 a, u32 r, u32 g, u32 b) {} + virtual void ClearStencil(u32 stencil) {} + virtual void ClearDepth(u32 depth) {} + virtual void ClearSurface(u32 mask) {} + virtual void ColorMask(bool a, bool r, bool g, bool b) {} + virtual void ExecCMD() {} + virtual void AlphaFunc(u32 func, float ref) {} + virtual void DepthFunc(u32 func) {} + virtual void DepthMask(u32 flag) {} + virtual void PolygonMode(u32 face, u32 mode) {} + virtual void PointSize(float size) {} + virtual void LogicOp(u32 opcdoe) {} + virtual void LineWidth(float width) {} + virtual void LineStipple(u16 factor, u16 pattern) {} + virtual void PrimitiveRestartIndex(u32 index) {} + virtual void CullFace(u32 mode) {} + virtual void FrontFace(u32 mode) {} + virtual void Fogi(u32 mode) {} + virtual void Fogf(float start, float end) {} + virtual void PolygonOffset(float factor, float bias) {} + virtual void DepthRangef(float min, float max) {} + virtual void BlendEquationSeparate(u16 rgb, u16 a) {} + virtual void BlendFuncSeparate(u16 srcRGB, u16 dstRGB, u16 srcAlpha, u16 dstAlpha) {} + virtual void BlendColor(u8 r, u8 g, u8 b, u8 a) {} + virtual void LightModeli(u32 enable) {} + virtual void ShadeModel(u32 mode) {} + virtual void DepthBoundsEXT(float min, float max) {} + virtual void Scissor(u16 x, u16 y, u16 width, u16 height) {} + virtual void Flip() {} + virtual void Close() {} }; diff --git a/rpcs3/Emu/RSX/RSXFragmentProgram.h b/rpcs3/Emu/RSX/RSXFragmentProgram.h index 970d4a5727..113d3d2aea 100644 --- a/rpcs3/Emu/RSX/RSXFragmentProgram.h +++ b/rpcs3/Emu/RSX/RSXFragmentProgram.h @@ -49,7 +49,7 @@ enum RSX_FP_OPCODE_PKG = 0x2C, // Pack with sRGB transformation RSX_FP_OPCODE_UPG = 0x2D, // Unpack gamma RSX_FP_OPCODE_DP2A = 0x2E, // 2-component dot product with scalar addition - RSX_FP_OPCODE_TXL = 0x2F, // Texture sample with LOD + RSX_FP_OPCODE_TXL = 0x2F, // Texture sample with explicit LOD RSX_FP_OPCODE_TXB = 0x31, // Texture sample with bias RSX_FP_OPCODE_TEXBEM = 0x33, RSX_FP_OPCODE_TXPBEM = 0x34, @@ -71,14 +71,14 @@ enum RSX_FP_OPCODE_RET = 0x45, // Return }; -struct RSXShaderProgram +struct RSXFragmentProgram { u32 size; u32 addr; u32 offset; u32 ctrl; - RSXShaderProgram() + RSXFragmentProgram() : size(0) , addr(0) , offset(0) diff --git a/rpcs3/Emu/RSX/RSXTexture.cpp b/rpcs3/Emu/RSX/RSXTexture.cpp index 6904da2420..7a21e076d3 100644 --- a/rpcs3/Emu/RSX/RSXTexture.cpp +++ b/rpcs3/Emu/RSX/RSXTexture.cpp @@ -210,3 +210,206 @@ void RSXTexture::SetControl3(u16 depth, u32 pitch) m_depth = depth; m_pitch = pitch; } + +RSXVertexTexture::RSXVertexTexture() : RSXTexture() +{ +} + +RSXVertexTexture::RSXVertexTexture(u8 index) : RSXTexture(index) +{ +} + +void RSXVertexTexture::Init() +{ + // Offset + methodRegisters[NV4097_SET_VERTEX_TEXTURE_OFFSET + (m_index * 32)] = 0; + + // Format + methodRegisters[NV4097_SET_VERTEX_TEXTURE_FORMAT + (m_index * 32)] = 0; + + // Address + methodRegisters[NV4097_SET_VERTEX_TEXTURE_ADDRESS + (m_index * 32)] = + ((/*wraps*/1) | ((/*anisoBias*/0) << 4) | ((/*wrapt*/1) << 8) | ((/*unsignedRemap*/0) << 12) | + ((/*wrapr*/3) << 16) | ((/*gamma*/0) << 20) | ((/*signedRemap*/0) << 24) | ((/*zfunc*/0) << 28)); + + // Control0 + methodRegisters[NV4097_SET_VERTEX_TEXTURE_CONTROL0 + (m_index * 32)] = + (((/*alphakill*/0) << 2) | (/*maxaniso*/0) << 4) | ((/*maxlod*/0xc00) << 7) | ((/*minlod*/0) << 19) | ((/*enable*/0) << 31); + + // Control1 + //methodRegisters[NV4097_SET_VERTEX_TEXTURE_CONTROL1 + (m_index * 32)] = 0xE4; + + // Filter + methodRegisters[NV4097_SET_VERTEX_TEXTURE_FILTER + (m_index * 32)] = + ((/*bias*/0) | ((/*conv*/1) << 13) | ((/*min*/5) << 16) | ((/*mag*/2) << 24) + | ((/*as*/0) << 28) | ((/*rs*/0) << 29) | ((/*gs*/0) << 30) | ((/*bs*/0) << 31)); + + // Image Rect + methodRegisters[NV4097_SET_VERTEX_TEXTURE_IMAGE_RECT + (m_index * 32)] = (/*height*/1) | ((/*width*/1) << 16); + + // Border Color + methodRegisters[NV4097_SET_VERTEX_TEXTURE_BORDER_COLOR + (m_index * 32)] = 0; +} + +u32 RSXVertexTexture::GetOffset() const +{ + return methodRegisters[NV4097_SET_VERTEX_TEXTURE_OFFSET + (m_index * 32)]; +} + +u8 RSXVertexTexture::GetLocation() const +{ + return (methodRegisters[NV4097_SET_VERTEX_TEXTURE_FORMAT + (m_index * 32)] & 0x3) - 1; +} + +bool RSXVertexTexture::isCubemap() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FORMAT + (m_index * 32)] >> 2) & 0x1); +} + +u8 RSXVertexTexture::GetBorderType() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FORMAT + (m_index * 32)] >> 3) & 0x1); +} + +u8 RSXVertexTexture::GetDimension() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FORMAT + (m_index * 32)] >> 4) & 0xf); +} + +u8 RSXVertexTexture::GetFormat() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FORMAT + (m_index * 32)] >> 8) & 0xff); +} + +u16 RSXVertexTexture::GetMipmap() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FORMAT + (m_index * 32)] >> 16) & 0xffff); +} + +u8 RSXVertexTexture::GetWrapS() const +{ + return 1; + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_ADDRESS + (m_index * 32)]) & 0xf); +} + +u8 RSXVertexTexture::GetWrapT() const +{ + return 1; + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_ADDRESS + (m_index * 32)] >> 8) & 0xf); +} + +u8 RSXVertexTexture::GetWrapR() const +{ + return 1; + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_ADDRESS + (m_index * 32)] >> 16) & 0xf); +} + +u8 RSXVertexTexture::GetUnsignedRemap() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_ADDRESS + (m_index * 32)] >> 12) & 0xf); +} + +u8 RSXVertexTexture::GetZfunc() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_ADDRESS + (m_index * 32)] >> 28) & 0xf); +} + +u8 RSXVertexTexture::GetGamma() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_ADDRESS + (m_index * 32)] >> 20) & 0xf); +} + +u8 RSXVertexTexture::GetAnisoBias() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_ADDRESS + (m_index * 32)] >> 4) & 0xf); +} + +u8 RSXVertexTexture::GetSignedRemap() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_ADDRESS + (m_index * 32)] >> 24) & 0xf); +} + +bool RSXVertexTexture::IsEnabled() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_CONTROL0 + (m_index * 32)] >> 31) & 0x1); +} + +u16 RSXVertexTexture::GetMinLOD() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_CONTROL0 + (m_index * 32)] >> 19) & 0xfff); +} + +u16 RSXVertexTexture::GetMaxLOD() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_CONTROL0 + (m_index * 32)] >> 7) & 0xfff); +} + +u8 RSXVertexTexture::GetMaxAniso() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_CONTROL0 + (m_index * 32)] >> 4) & 0x7); +} + +bool RSXVertexTexture::IsAlphaKillEnabled() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_CONTROL0 + (m_index * 32)] >> 2) & 0x1); +} + +u32 RSXVertexTexture::GetRemap() const +{ + return 0 | (1 << 2) | (2 << 4) | (3 << 6);//(methodRegisters[NV4097_SET_VERTEX_TEXTURE_CONTROL1 + (m_index * 32)]); +} + +u16 RSXVertexTexture::GetBias() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FILTER + (m_index * 32)]) & 0x1fff); +} + +u8 RSXVertexTexture::GetMinFilter() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FILTER + (m_index * 32)] >> 16) & 0x7); +} + +u8 RSXVertexTexture::GetMagFilter() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FILTER + (m_index * 32)] >> 24) & 0x7); +} + +u8 RSXVertexTexture::GetConvolutionFilter() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FILTER + (m_index * 32)] >> 13) & 0xf); +} + +bool RSXVertexTexture::isASigned() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FILTER + (m_index * 32)] >> 28) & 0x1); +} + +bool RSXVertexTexture::isRSigned() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FILTER + (m_index * 32)] >> 29) & 0x1); +} + +bool RSXVertexTexture::isGSigned() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FILTER + (m_index * 32)] >> 30) & 0x1); +} + +bool RSXVertexTexture::isBSigned() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_FILTER + (m_index * 32)] >> 31) & 0x1); +} + +u16 RSXVertexTexture::GetWidth() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_IMAGE_RECT + (m_index * 32)] >> 16) & 0xffff); +} + +u16 RSXVertexTexture::GetHeight() const +{ + return ((methodRegisters[NV4097_SET_VERTEX_TEXTURE_IMAGE_RECT + (m_index * 32)]) & 0xffff); +} + +u32 RSXVertexTexture::GetBorderColor() const +{ + return methodRegisters[NV4097_SET_VERTEX_TEXTURE_BORDER_COLOR + (m_index * 32)]; +} \ No newline at end of file diff --git a/rpcs3/Emu/RSX/RSXTexture.h b/rpcs3/Emu/RSX/RSXTexture.h index d5db3480fb..c595dba082 100644 --- a/rpcs3/Emu/RSX/RSXTexture.h +++ b/rpcs3/Emu/RSX/RSXTexture.h @@ -2,6 +2,7 @@ class RSXTexture { +protected: u8 m_index; public: @@ -11,6 +12,64 @@ public: public: RSXTexture(); RSXTexture(u8 index); + virtual void Init(); + + // Offset + virtual u32 GetOffset() const; + + // Format + virtual u8 GetLocation() const; + virtual bool isCubemap() const; + virtual u8 GetBorderType() const; + virtual u8 GetDimension() const; + virtual u8 GetFormat() const; + virtual u16 GetMipmap() const; + + // Address + virtual u8 GetWrapS() const; + virtual u8 GetWrapT() const; + virtual u8 GetWrapR() const; + virtual u8 GetUnsignedRemap() const; + virtual u8 GetZfunc() const; + virtual u8 GetGamma() const; + virtual u8 GetAnisoBias() const; + virtual u8 GetSignedRemap() const; + + // Control0 + virtual bool IsEnabled() const; + virtual u16 GetMinLOD() const; + virtual u16 GetMaxLOD() const; + virtual u8 GetMaxAniso() const; + virtual bool IsAlphaKillEnabled() const; + + // Control1 + virtual u32 GetRemap() const; + + // Filter + virtual u16 GetBias() const; + virtual u8 GetMinFilter() const; + virtual u8 GetMagFilter() const; + virtual u8 GetConvolutionFilter() const; + virtual bool isASigned() const; + virtual bool isRSigned() const; + virtual bool isGSigned() const; + virtual bool isBSigned() const; + + // Image Rect + virtual u16 GetWidth() const; + virtual u16 GetHeight() const; + + // Border Color + virtual u32 GetBorderColor() const; + + void SetControl3(u16 depth, u32 pitch); +}; + +class RSXVertexTexture : public RSXTexture +{ +public: + RSXVertexTexture(); + RSXVertexTexture(u8 index); void Init(); // Offset @@ -60,6 +119,4 @@ public: // Border Color u32 GetBorderColor() const; - - void SetControl3(u16 depth, u32 pitch); -}; +}; \ No newline at end of file diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index 311dd3143c..e57931d415 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -11,37 +11,46 @@ #include "Emu/SysCalls/lv2/sys_time.h" #define ARGS(x) (x >= count ? OutOfArgsCount(x, cmd, count, args.addr()) : args[x].ToLE()) +#define CMD_DEBUG 0 u32 methodRegisters[0xffff]; -void RSXThread::nativeRescale(float width, float height) +void RSXThread::NativeRescale(float width, float height) { switch (Ini.GSResolution.GetValue()) { case 1: // 1920x1080 window size + { m_width_scale = 1920 / width * 2.0f; m_height_scale = 1080 / height * 2.0f; m_width = 1920; m_height = 1080; - break; + } + break; case 2: // 1280x720 window size + { m_width_scale = 1280 / width * 2.0f; m_height_scale = 720 / height * 2.0f; m_width = 1280; m_height = 720; - break; + } + break; case 4: // 720x480 window size + { m_width_scale = 720 / width * 2.0f; m_height_scale = 480 / height * 2.0f; m_width = 720; m_height = 480; - break; + } + break; case 5: // 720x576 window size + { m_width_scale = 720 / width * 2.0f; m_height_scale = 576 / height * 2.0f; m_width = 720; m_height = 576; - break; + } + break; } } @@ -95,23 +104,23 @@ RSXVertexData::RSXVertexData() void RSXVertexData::Reset() { - //frequency = 0; - //stride = 0; - //size = 0; - //type = 0; - //addr = 0; + frequency = 0; + stride = 0; + size = 0; + type = 0; + addr = 0; data.clear(); } void RSXVertexData::Load(u32 start, u32 count, u32 baseOffset, u32 baseIndex=0) { - if(!addr) return; + if (!addr) return; const u32 tsize = GetTypeSize(); data.resize((start + count) * tsize * size); - for(u32 i=start; i(addr + baseOffset + stride * (i + baseIndex)); u8* dst = &data[i * tsize * size]; @@ -128,7 +137,7 @@ void RSXVertexData::Load(u32 start, u32 count, u32 baseOffset, u32 baseIndex=0) { const u16* c_src = (const u16*)src; u16* c_dst = (u16*)dst; - for(u32 j=0; j::make(args_addr); std::string debug = GetMethodName(cmd); debug += "("; - for(u32 i=0; i::make(args_addr); #if CMD_DEBUG - std::string debug = GetMethodName(cmd); - debug += "("; - for(u32 i=0; i> 20; + tex.SetControl3(depth, pitch); + } + break; + // Vertex data - case_16(NV4097_SET_VERTEX_DATA4UB_M, 4): + case_range(16, NV4097_SET_VERTEX_DATA4UB_M, 4) { const u32 a0 = ARGS(0); u8 v0 = a0; @@ -401,18 +425,19 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const u8 v2 = a0 >> 16; u8 v3 = a0 >> 24; - //m_vertex_data[index].Reset(); + m_vertex_data[index].Reset(); m_vertex_data[index].size = 4; m_vertex_data[index].type = CELL_GCM_VERTEX_UB; m_vertex_data[index].data.push_back(v0); m_vertex_data[index].data.push_back(v1); m_vertex_data[index].data.push_back(v2); m_vertex_data[index].data.push_back(v3); + //LOG_WARNING(RSX, "NV4097_SET_VERTEX_DATA4UB_M: index = %d, v0 = 0x%x, v1 = 0x%x, v2 = 0x%x, v3 = 0x%x", index, v0, v1, v2, v3); } break; - case_16(NV4097_SET_VERTEX_DATA2F_M, 8): + case_range(16, NV4097_SET_VERTEX_DATA2F_M, 8) { const u32 a0 = ARGS(0); const u32 a1 = ARGS(1); @@ -420,7 +445,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const float v0 = (float&)a0; float v1 = (float&)a1; - //m_vertex_data[index].Reset(); + m_vertex_data[index].Reset(); m_vertex_data[index].type = CELL_GCM_VERTEX_F; m_vertex_data[index].size = 2; u32 pos = m_vertex_data[index].data.size(); @@ -432,7 +457,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const } break; - case_16(NV4097_SET_VERTEX_DATA4F_M, 16): + case_range(16, NV4097_SET_VERTEX_DATA4F_M, 16) { const u32 a0 = ARGS(0); const u32 a1 = ARGS(1); @@ -444,7 +469,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const float v2 = (float&)a2; float v3 = (float&)a3; - //m_vertex_data[index].Reset(); + m_vertex_data[index].Reset(); m_vertex_data[index].type = CELL_GCM_VERTEX_F; m_vertex_data[index].size = 4; u32 pos = m_vertex_data[index].data.size(); @@ -458,10 +483,10 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const } break; - case_16(NV4097_SET_VERTEX_DATA_ARRAY_OFFSET, 4): + case_range(16, NV4097_SET_VERTEX_DATA_ARRAY_OFFSET, 4) { const u32 addr = GetAddress(ARGS(0) & 0x7fffffff, ARGS(0) >> 31); - CMD_LOG("num=%d, addr=0x%x", index, addr); + m_vertex_data[index].addr = addr; m_vertex_data[index].data.clear(); @@ -469,7 +494,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const } break; - case_16(NV4097_SET_VERTEX_DATA_ARRAY_FORMAT, 4): + case_range(16, NV4097_SET_VERTEX_DATA_ARRAY_FORMAT, 4) { const u32 a0 = ARGS(0); u16 frequency = a0 >> 16; @@ -477,8 +502,6 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const u8 size = (a0 >> 4) & 0xf; u8 type = a0 & 0xf; - CMD_LOG("index=%d, frequency=%d, stride=%d, size=%d, type=%d", index, frequency, stride, size, type); - RSXVertexData& cv = m_vertex_data[index]; cv.frequency = frequency; cv.stride = stride; @@ -486,14 +509,17 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const cv.type = type; //LOG_WARNING(RSX, "NV4097_SET_VERTEX_DATA_ARRAY_FORMAT: index=%d, frequency=%d, stride=%d, size=%d, type=%d", index, frequency, stride, size, type); + } break; // Vertex Attribute case NV4097_SET_VERTEX_ATTRIB_INPUT_MASK: { - if (ARGS(0)) - LOG_WARNING(RSX, "NV4097_SET_VERTEX_ATTRIB_INPUT_MASK: 0x%x", ARGS(0)); + if (u32 mask = ARGS(0)) + { + LOG_WARNING(RSX, "TODO: NV4097_SET_VERTEX_ATTRIB_INPUT_MASK: 0x%x", mask); + } //VertexData[0].prog.attributeInputMask = ARGS(0); } @@ -501,8 +527,10 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV4097_SET_VERTEX_ATTRIB_OUTPUT_MASK: { - if (ARGS(0)) - LOG_WARNING(RSX, "NV4097_SET_VERTEX_ATTRIB_OUTPUT_MASK: 0x%x", ARGS(0)); + if (u32 mask = ARGS(0)) + { + LOG_WARNING(RSX, "TODO: NV4097_SET_VERTEX_ATTRIB_OUTPUT_MASK: 0x%x", mask); + } //VertexData[0].prog.attributeOutputMask = ARGS(0); //FragmentData.prog.attributeInputMask = ARGS(0)/* & ~0x20*/; @@ -512,76 +540,82 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const // Color Mask case NV4097_SET_COLOR_MASK: { - const u32 a0 = ARGS(0); - - m_set_color_mask = true; - m_color_mask_a = a0 & 0x1000000 ? true : false; - m_color_mask_r = a0 & 0x0010000 ? true : false; - m_color_mask_g = a0 & 0x0000100 ? true : false; - m_color_mask_b = a0 & 0x0000001 ? true : false; + const u32 mask = ARGS(0); + ColorMask(mask & 0x1000000, mask & 0x1000000, mask & 0x1000000, mask & 0x0000001); } break; case NV4097_SET_COLOR_MASK_MRT: { - if (ARGS(0)) - LOG_WARNING(RSX, "NV4097_SET_COLOR_MASK_MRT: 0x%x", ARGS(0)); + if (u32 mask = ARGS(0)) + { + LOG_WARNING(RSX, "TODO: NV4097_SET_COLOR_MASK_MRT: 0x%x", mask); + } } break; // Alpha testing case NV4097_SET_ALPHA_TEST_ENABLE: { - m_set_alpha_test = ARGS(0) ? true : false; + const u32 value = ARGS(0); + Enable(cmd, value); } break; case NV4097_SET_ALPHA_FUNC: { - m_set_alpha_func = true; - m_alpha_func = ARGS(0); + const u32 value = ARGS(0); + m_alpha_func = value; - if (count == 2) + // Sanity check here for invalid alpha func + if (m_alpha_func) { - m_set_alpha_ref = true; - const u32 a1 = ARGS(1); - m_alpha_ref = (float&)a1; + AlphaFunc(m_alpha_func, m_alpha_ref); } } break; case NV4097_SET_ALPHA_REF: { - m_set_alpha_ref = true; - const u32 a0 = ARGS(0); - m_alpha_ref = (float&)a0; + const u32 value = ARGS(0); + m_alpha_ref = (float&)value; + + // Sanity check here for invalid alpha func + if (m_alpha_func) + { + AlphaFunc(m_alpha_func, m_alpha_ref); + } } break; // Cull face case NV4097_SET_CULL_FACE_ENABLE: { - m_set_cull_face = ARGS(0) ? true : false; + const u32 value = ARGS(0); + Enable(cmd, value); } break; case NV4097_SET_CULL_FACE: { - m_cull_face = ARGS(0); + const u32 value = ARGS(0); + CullFace(value); } break; // Front face case NV4097_SET_FRONT_FACE: { - m_front_face = ARGS(0); + const u32 value = ARGS(0); + //FrontFace(value); } break; // Blending case NV4097_SET_BLEND_ENABLE: { - m_set_blend = ARGS(0) ? true : false; + const u32 value = ARGS(0); + Enable(cmd, value); } break; @@ -595,85 +629,98 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV4097_SET_BLEND_FUNC_SFACTOR: { + const u32 value = ARGS(0); m_set_blend_sfactor = true; - m_blend_sfactor_rgb = ARGS(0) & 0xffff; - m_blend_sfactor_alpha = ARGS(0) >> 16; + m_blend_sfactor_rgb = value & 0xffff; + m_blend_sfactor_alpha = value >> 16; if (count == 2) { - m_set_blend_dfactor = true; - m_blend_dfactor_rgb = ARGS(1) & 0xffff; - m_blend_dfactor_alpha = ARGS(1) >> 16; + const u32 value1 = ARGS(1); + m_blend_dfactor_rgb = value1 & 0xffff; + m_blend_dfactor_alpha = value1 >> 16; + BlendFuncSeparate(m_blend_sfactor_rgb, m_blend_dfactor_rgb, m_blend_sfactor_alpha, m_blend_dfactor_alpha); } } break; case NV4097_SET_BLEND_FUNC_DFACTOR: { - m_set_blend_dfactor = true; - m_blend_dfactor_rgb = ARGS(0) & 0xffff; - m_blend_dfactor_alpha = ARGS(0) >> 16; + const u32 value = ARGS(0); + m_blend_dfactor_rgb = value & 0xffff; + m_blend_dfactor_alpha = value >> 16; + + if (m_set_blend_sfactor) + { + BlendFuncSeparate(m_blend_sfactor_rgb, m_blend_dfactor_rgb, m_blend_sfactor_alpha, m_blend_dfactor_alpha); + } } break; case NV4097_SET_BLEND_COLOR: { - m_set_blend_color = true; - m_blend_color_r = ARGS(0) & 0xff; - m_blend_color_g = (ARGS(0) >> 8) & 0xff; - m_blend_color_b = (ARGS(0) >> 16) & 0xff; - m_blend_color_a = (ARGS(0) >> 24) & 0xff; + const u32 value = ARGS(0); + BlendColor(value & 0xff, (value >> 8) & 0xff, (value >> 16) & 0xff, (value >> 24) & 0xff); } break; case NV4097_SET_BLEND_COLOR2: { - if (ARGS(0)) - LOG_WARNING(RSX, "NV4097_SET_BLEND_COLOR2: 0x % x", ARGS(0)); + if (u32 value = ARGS(0)) + { + LOG_WARNING(RSX, "TODO : NV4097_SET_BLEND_COLOR2: 0x%x", value); + } } break; case NV4097_SET_BLEND_EQUATION: { - m_set_blend_equation = true; - m_blend_equation_rgb = ARGS(0) & 0xffff; - m_blend_equation_alpha = ARGS(0) >> 16; + const u32 value = ARGS(0); + BlendEquationSeparate(value & 0xffff, value >> 16); } break; case NV4097_SET_REDUCE_DST_COLOR: { - if (ARGS(0)) - LOG_WARNING(RSX, "NV4097_SET_REDUCE_DST_COLOR: 0x%x", ARGS(0)); + if (u32 value = ARGS(0)) + { + LOG_WARNING(RSX, "TODO: NV4097_SET_REDUCE_DST_COLOR: 0x%x", value); + } } break; // Depth bound testing case NV4097_SET_DEPTH_BOUNDS_TEST_ENABLE: { - m_set_depth_bounds_test = ARGS(0) ? true : false; + const u32 value = ARGS(0); + Enable(cmd, value); } break; case NV4097_SET_DEPTH_BOUNDS_MIN: { + const u32 value = ARGS(0); m_set_depth_bounds = true; - const u32 a0 = ARGS(0); - m_depth_bounds_min = (float&)a0; + m_depth_bounds_min = (float&)value; if (count == 2) { - const u32 a1 = ARGS(1); - m_depth_bounds_max = (float&)a1; + const u32 value1 = ARGS(1); + m_depth_bounds_max = (float&)value1; + DepthBoundsEXT(m_depth_bounds_min, m_depth_bounds_max); } } break; case NV4097_SET_DEPTH_BOUNDS_MAX: { - m_set_depth_bounds = true; - const u32 a0 = ARGS(0); - m_depth_bounds_max = (float&)a0; + const u32 value = ARGS(0); + m_depth_bounds_max = (float&)value; + + if (m_set_depth_bounds) + { + DepthBoundsEXT(m_depth_bounds_min, m_depth_bounds_max); + } } break; @@ -691,7 +738,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const m_viewport_h = ARGS(1) >> 16; } - CMD_LOG("x=%d, y=%d, w=%d, h=%d", m_viewport_x, m_viewport_y, m_viewport_w, m_viewport_h); + //LOG_NOTICE(RSX, "NV4097_SET_VIEWPORT_HORIZONTAL: x=%d, y=%d, w=%d, h=%d", m_viewport_x, m_viewport_y, m_viewport_w, m_viewport_h); } break; @@ -700,6 +747,8 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const m_set_viewport_vertical = true; m_viewport_y = ARGS(0) & 0xffff; m_viewport_h = ARGS(0) >> 16; + + //LOG_NOTICE(RSX, "NV4097_SET_VIEWPORT_VERTICAL: y=%d, h=%d", m_viewport_y, m_viewport_h); } break; @@ -713,105 +762,118 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const // Clipping case NV4097_SET_CLIP_MIN: { - const u32 a0 = ARGS(0); - const u32 a1 = ARGS(1); - - m_set_clip = true; - m_clip_min = (float&)a0; - m_clip_max = (float&)a1; - - CMD_LOG("clip_min=%.01f, clip_max=%.01f", m_clip_min, m_clip_max); + const u32 value = ARGS(0); + m_clip_min = (float&)value; + DepthRangef(m_clip_min, m_clip_max); } break; case NV4097_SET_CLIP_MAX: { - const u32 a0 = ARGS(0); - - m_set_clip = true; - m_clip_max = (float&)a0; - - CMD_LOG("clip_max=%.01f", m_clip_max); + const u32 value = ARGS(0); + m_clip_max = (float&)value; + DepthRangef(m_clip_min, m_clip_max); } break; // Depth testing case NV4097_SET_DEPTH_TEST_ENABLE: { - m_set_depth_test = ARGS(0) ? true : false; + const u32 value = ARGS(0); + Enable(cmd, value); } break; case NV4097_SET_DEPTH_FUNC: { - m_set_depth_func = true; - m_depth_func = ARGS(0); + const u32 value = ARGS(0); + // Sanity check here for invalid depth func + if (value) + { + DepthFunc(value); + } } break; case NV4097_SET_DEPTH_MASK: { - m_set_depth_mask = true; - m_depth_mask = ARGS(0); + const u32 value = ARGS(0); + DepthMask(value); } break; // Polygon mode/offset case NV4097_SET_FRONT_POLYGON_MODE: { - m_set_front_polygon_mode = true; - m_front_polygon_mode = ARGS(0); + const u32 value = ARGS(0); + PolygonMode(cmd, value); } break; case NV4097_SET_BACK_POLYGON_MODE: { - m_set_back_polygon_mode = true; - m_back_polygon_mode = ARGS(0); + const u32 value = ARGS(0); + PolygonMode(cmd, value); } break; case NV4097_SET_POLY_OFFSET_FILL_ENABLE: { - m_set_poly_offset_fill = ARGS(0) ? true : false; + Enable(cmd, ARGS(0)); } break; case NV4097_SET_POLY_OFFSET_LINE_ENABLE: { - m_set_poly_offset_line = ARGS(0) ? true : false; + const u32 value = ARGS(0); + Enable(cmd, value); } break; case NV4097_SET_POLY_OFFSET_POINT_ENABLE: { - m_set_poly_offset_point = ARGS(0) ? true : false; + const u32 value = ARGS(0); + Enable(cmd, value); } break; case NV4097_SET_POLYGON_OFFSET_SCALE_FACTOR: { - m_set_depth_test = true; + Enable(NV4097_SET_DEPTH_TEST_ENABLE, 1); + + const u32 value = ARGS(0); m_set_poly_offset_mode = true; - - const u32 a0 = ARGS(0); - m_poly_offset_scale_factor = (float&)a0; + m_poly_offset_scale_factor = (float&)value; if (count == 2) { - const u32 a1 = ARGS(1); - m_poly_offset_bias = (float&)a1; + const u32 value1 = ARGS(1); + m_poly_offset_bias = (float&)value1; + PolygonOffset(m_poly_offset_scale_factor, m_poly_offset_bias); } } break; case NV4097_SET_POLYGON_OFFSET_BIAS: { - m_set_depth_test = true; - m_set_poly_offset_mode = true; + Enable(NV4097_SET_DEPTH_TEST_ENABLE, 1); - const u32 a0 = ARGS(0); - m_poly_offset_bias = (float&)a0; + const u32 value = ARGS(0); + m_poly_offset_bias = (float&)value; + + if (m_set_poly_offset_mode) + { + PolygonOffset(m_poly_offset_scale_factor, m_poly_offset_bias); + } + } + break; + + case NV4097_SET_CYLINDRICAL_WRAP: + { + if (ARGS(0)) + { + LOG_WARNING(RSX, "TODO: NV4097_SET_CYLINDRICAL_WRAP: 0x%x", ARGS(0)); + } } break; @@ -820,8 +882,8 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const { u32 a0 = ARGS(0); - if(a0 & 0x01) m_clear_surface_z = m_clear_z; - if(a0 & 0x02) m_clear_surface_s = m_clear_s; + if (a0 & 0x01) m_clear_surface_z = m_clear_z; + if (a0 & 0x02) m_clear_surface_s = m_clear_s; m_clear_surface_mask |= a0 & 0x3; } @@ -829,56 +891,60 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV4097_CLEAR_SURFACE: { - const u32 a0 = ARGS(0); + const u32 mask = ARGS(0); - if(a0 & 0x01) m_clear_surface_z = m_clear_z; - if(a0 & 0x02) m_clear_surface_s = m_clear_s; - if(a0 & 0x10) m_clear_surface_color_r = m_clear_color_r; - if(a0 & 0x20) m_clear_surface_color_g = m_clear_color_g; - if(a0 & 0x40) m_clear_surface_color_b = m_clear_color_b; - if(a0 & 0x80) m_clear_surface_color_a = m_clear_color_a; - - m_clear_surface_mask = a0; - ExecCMD(NV4097_CLEAR_SURFACE); + ClearSurface(mask); } break; case NV4097_SET_ZSTENCIL_CLEAR_VALUE: { - const u32 a0 = ARGS(0); - m_clear_s = a0 & 0xff; - m_clear_z = a0 >> 8; + const u32 value = ARGS(0); + + ClearStencil(value & 0xff); + ClearDepth(value >> 8); } break; case NV4097_SET_COLOR_CLEAR_VALUE: { const u32 color = ARGS(0); - m_clear_color_a = (color >> 24) & 0xff; - m_clear_color_r = (color >> 16) & 0xff; - m_clear_color_g = (color >> 8) & 0xff; - m_clear_color_b = color & 0xff; + + ClearColor((color >> 24) & 0xff, (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff); } break; case NV4097_SET_CLEAR_RECT_HORIZONTAL: { - if (ARGS(0)) - LOG_WARNING(RSX, "NV4097_SET_CLEAR_RECT_HORIZONTAL: 0x%x", ARGS(0)); + if (u32 value = ARGS(0)) + { + LOG_WARNING(RSX, "TODO: NV4097_SET_CLEAR_RECT_HORIZONTAL: 0x%x", value); + } } break; case NV4097_SET_CLEAR_RECT_VERTICAL: { - if (ARGS(0)) - LOG_WARNING(RSX, "NV4097_SET_CLEAR_RECT_VERTICAL: 0x%x", ARGS(0)); + if (u32 value = ARGS(0)) + { + LOG_WARNING(RSX, "TODO: NV4097_SET_CLEAR_RECT_VERTICAL: 0x%x", value); + } } break; // Arrays + case NV4097_INLINE_ARRAY: + { + if (u32 value = ARGS(0)) + { + LOG_WARNING(RSX, "TODO: NNV4097_INLINE_ARRAY: 0x%x", value); + } + } + break; + case NV4097_DRAW_ARRAYS: { - for(u32 c=0; c> 24) + 1; - if(first < m_indexed_array.m_first) m_indexed_array.m_first = first; + if (first < m_indexed_array.m_first) m_indexed_array.m_first = first; - for(u32 i=first; i<_count; ++i) + for (u32 i=first; i<_count; ++i) { u32 index; switch(m_indexed_array.m_type) @@ -940,8 +1006,8 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const break; } - if(index < m_indexed_array.index_min) m_indexed_array.index_min = index; - if(index > m_indexed_array.index_max) m_indexed_array.index_max = index; + if (index < m_indexed_array.index_min) m_indexed_array.index_min = index; + if (index > m_indexed_array.index_max) m_indexed_array.index_max = index; } m_indexed_array.m_count += _count; @@ -952,11 +1018,13 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV4097_SET_VERTEX_DATA_BASE_OFFSET: { m_vertex_data_base_offset = ARGS(0); - if (count >= 2) { + + if (count >= 2) + { m_vertex_data_base_index = ARGS(1); } - //LOG_ERROR(RSX, "NV4097_SET_VERTEX_DATA_BASE_OFFSET: 0x%x", m_vertex_data_base_offset); + //LOG_WARNING(RSX, "NV4097_SET_VERTEX_DATA_BASE_OFFSET: 0x%x", m_vertex_data_base_offset); } break; @@ -972,9 +1040,27 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const //LOG_WARNING(RSX, "NV4097_SET_BEGIN_END: 0x%x", a0); - m_read_buffer = false; + if (!m_indexed_array.m_count && !m_draw_array_count) + { + u32 min_vertex_size = ~0; + for (auto &i : m_vertex_data) + { + if (!i.size) + continue; - if(a0) + u32 vertex_size = i.data.size() / (i.size * i.GetTypeSize()); + + if (min_vertex_size > vertex_size) + min_vertex_size = vertex_size; + } + + m_draw_array_count = min_vertex_size; + m_draw_array_first = 0; + } + + m_read_buffer = Ini.GSReadColorBuffer.GetValue() || (!m_indexed_array.m_count && !m_draw_array_count); + + if (a0) { Begin(a0); } @@ -988,12 +1074,12 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const // Shader case NV4097_SET_SHADER_PROGRAM: { - m_cur_shader_prog = &m_shader_progs[m_cur_shader_prog_num]; - //m_cur_shader_prog_num = (m_cur_shader_prog_num + 1) % 16; + m_cur_fragment_prog = &m_fragment_progs[m_cur_fragment_prog_num]; + const u32 a0 = ARGS(0); - m_cur_shader_prog->offset = a0 & ~0x3; - m_cur_shader_prog->addr = GetAddress(m_cur_shader_prog->offset, (a0 & 0x3) - 1); - m_cur_shader_prog->ctrl = 0x40; + m_cur_fragment_prog->offset = a0 & ~0x3; + m_cur_fragment_prog->addr = GetAddress(m_cur_fragment_prog->offset, (a0 & 0x3) - 1); + m_cur_fragment_prog->ctrl = 0x40; } break; @@ -1005,11 +1091,19 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV4097_SET_SHADE_MODE: { - m_set_shade_mode = true; - m_shade_mode = ARGS(0); + const u32 value = ARGS(0); + ShadeModel(value); } break; + case NV4097_SET_SHADER_PACKER: + { + if (ARGS(0)) + { + LOG_WARNING(RSX, "TODO: NV4097_SET_SHADER_PACKER: 0x%x", ARGS(0)); + } + } + case NV4097_SET_SHADER_WINDOW: { const u32 a0 = ARGS(0); @@ -1048,17 +1142,20 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const } break; - case_32(NV4097_SET_TRANSFORM_PROGRAM, 4): + case_range(32, NV4097_SET_TRANSFORM_PROGRAM, 4) { //LOG_WARNING(RSX, "NV4097_SET_TRANSFORM_PROGRAM[%d](%d)", index, count); - if(!m_cur_vertex_prog) + if (!m_cur_vertex_prog) { - LOG_WARNING(RSX, "NV4097_SET_TRANSFORM_PROGRAM: m_cur_vertex_prog == NULL"); + LOG_ERROR(RSX, "NV4097_SET_TRANSFORM_PROGRAM: m_cur_vertex_prog is null"); break; } - for(u32 i=0; idata.push_back(ARGS(i)); + for (u32 i = 0; i < count; ++i) + { + m_cur_vertex_prog->data.push_back(ARGS(i)); + } } break; @@ -1067,24 +1164,33 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const // TODO: // (cmd)[1] = CELL_GCM_ENDIAN_SWAP((count) | ((registerCount) << 16)); \ - if(!m_cur_vertex_prog) + if (!m_cur_vertex_prog) { - LOG_WARNING(RSX, "NV4097_SET_TRANSFORM_TIMEOUT: m_cur_vertex_prog == NULL"); + LOG_ERROR(RSX, "NV4097_SET_TRANSFORM_TIMEOUT: m_cur_vertex_prog is null"); break; } //m_cur_vertex_prog->Decompile(); break; + case NV4097_SET_TRANSFORM_BRANCH_BITS: + { + if (u32 value = ARGS(0)) + { + LOG_WARNING(RSX, "TODO: NV4097_SET_TRANSFORM_BRANCH_BITS: 0x%x", value); + } + } + break; + case NV4097_SET_TRANSFORM_CONSTANT_LOAD: { - if((count - 1) % 4) + if ((count - 1) % 4) { - CMD_LOG("NV4097_SET_TRANSFORM_CONSTANT_LOAD [%d]", count); + LOG_ERROR(RSX, "NV4097_SET_TRANSFORM_CONSTANT_LOAD: bad count %d", count); break; } - for(u32 id = ARGS(0), i = 1; i= 2) + if (count >= 2) { m_set_stencil_func_ref = true; m_stencil_func_ref = ARGS(1); - if(count >= 3) + if (count >= 3) { m_set_stencil_func_mask = true; m_stencil_func_mask = ARGS(2); @@ -1210,12 +1326,12 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const m_set_stencil_fail = true; m_stencil_fail = ARGS(0); - if(count >= 2) + if (count >= 2) { m_set_stencil_zfail = true; m_stencil_zfail = ARGS(1); - if(count >= 3) + if (count >= 3) { m_set_stencil_zpass = true; m_stencil_zpass = ARGS(2); @@ -1236,12 +1352,12 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const m_set_back_stencil_func = true; m_back_stencil_func = ARGS(0); - if(count >= 2) + if (count >= 2) { m_set_back_stencil_func_ref = true; m_back_stencil_func_ref = ARGS(1); - if(count >= 3) + if (count >= 3) { m_set_back_stencil_func_mask = true; m_back_stencil_func_mask = ARGS(2); @@ -1269,12 +1385,12 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const m_set_stencil_fail = true; m_stencil_fail = ARGS(0); - if(count >= 2) + if (count >= 2) { m_set_back_stencil_zfail = true; m_back_stencil_zfail = ARGS(1); - if(count >= 3) + if (count >= 3) { m_set_back_stencil_zpass = true; m_back_stencil_zpass = ARGS(2); @@ -1285,52 +1401,50 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV4097_SET_SCULL_CONTROL: { - if (ARGS(0)) - LOG_WARNING(RSX, "NV4097_SET_SCULL_CONTROL: 0x%x", ARGS(0)); - - //This is stencil culling , nothing to do with stencil masking on regular color or depth buffer - //const u32 a0 = ARGS(0); - //m_set_stencil_func = m_set_stencil_func_ref = m_set_stencil_func_mask = true; - - //m_stencil_func = a0 & 0xffff; - //m_stencil_func_ref = (a0 >> 16) & 0xff; - //m_stencil_func_mask = (a0 >> 24) & 0xff; + if (u32 value = ARGS(0)) + { + LOG_WARNING(RSX, "TODO: NV4097_SET_SCULL_CONTROL: 0x%x", value); + } } break; // Primitive restart index case NV4097_SET_RESTART_INDEX_ENABLE: { - m_set_restart_index = ARGS(0) ? true : false; + const u32 value = ARGS(0); + Enable(cmd, value); } break; case NV4097_SET_RESTART_INDEX: { - m_restart_index = ARGS(0); + const u32 value = ARGS(0); + PrimitiveRestartIndex(value); } break; // Point size case NV4097_SET_POINT_SIZE: { - m_set_point_size = true; - const u32 a0 = ARGS(0); - m_point_size = (float&)a0; + const u32 value = ARGS(0); + PointSize((float&)value); } break; // Point sprite case NV4097_SET_POINT_PARAMS_ENABLE: { - if (ARGS(0)) - LOG_ERROR(RSX, "NV4097_SET_POINT_PARAMS_ENABLE: 0x%x", ARGS(0)); + if (u32 value = ARGS(0)) + { + LOG_WARNING(RSX, "TODO: NV4097_SET_POINT_PARAMS_ENABLE: 0x%x", value); + } } break; case NV4097_SET_POINT_SPRITE_CONTROL: { - m_set_point_sprite_control = ARGS(0) ? true : false; + const u32 value = ARGS(0); + Enable(cmd, value); // TODO: //(cmd)[1] = CELL_GCM_ENDIAN_SWAP((enable) | ((rmode) << 1) | (texcoordMask)); @@ -1340,31 +1454,39 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const // Lighting case NV4097_SET_SPECULAR_ENABLE: { - m_set_specular = ARGS(0) ? true : false; + const u32 value = ARGS(0); + Enable(cmd, value); } break; // Scissor case NV4097_SET_SCISSOR_HORIZONTAL: { + const u32 value = ARGS(0); m_set_scissor_horizontal = true; - m_scissor_x = ARGS(0) & 0xffff; - m_scissor_w = ARGS(0) >> 16; + m_scissor_x = value & 0xffff; + m_scissor_w = value >> 16; - if(count == 2) + if (count == 2) { - m_set_scissor_vertical = true; - m_scissor_y = ARGS(1) & 0xffff; - m_scissor_h = ARGS(1) >> 16; + const u32 value1 = ARGS(1); + m_scissor_y = value1 & 0xffff; + m_scissor_h = value1 >> 16; + Scissor(m_scissor_x, m_scissor_y, m_scissor_w, m_scissor_h); } } break; case NV4097_SET_SCISSOR_VERTICAL: { - m_set_scissor_vertical = true; - m_scissor_y = ARGS(0) & 0xffff; - m_scissor_h = ARGS(0) >> 16; + const u32 value = ARGS(0); + m_scissor_y = value & 0xffff; + m_scissor_h = value >> 16; + + if (m_set_scissor_horizontal) + { + Scissor(m_scissor_x, m_scissor_y, m_scissor_w, m_scissor_h); + } } break; @@ -1393,8 +1515,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const m_width = buffers[m_gcm_current_buffer].width; m_height = buffers[m_gcm_current_buffer].height; - // Rescale native resolution to fit 1080p/720p/480p/576p window size - nativeRescale((float)m_width, (float)m_height); + NativeRescale((float)m_width, (float)m_height); } break; @@ -1450,7 +1571,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const { if (count != 4) { - LOG_WARNING(RSX, "NV4097_SET_SURFACE_PITCH_C: Bad count (%d)", count); + LOG_ERROR(RSX, "NV4097_SET_SURFACE_PITCH_C: Bad count (%d)", count); break; } @@ -1467,7 +1588,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const if (count != 1) { - LOG_WARNING(RSX, "NV4097_SET_SURFACE_PITCH_D: Bad count (%d)", count); + LOG_ERROR(RSX, "NV4097_SET_SURFACE_PITCH_D: Bad count (%d)", count); break; } } @@ -1476,9 +1597,10 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV4097_SET_SURFACE_PITCH_Z: { m_surface_pitch_z = ARGS(0); + if (count != 1) { - LOG_WARNING(RSX, "NV4097_SET_SURFACE_PITCH_Z: Bad count (%d)", count); + LOG_ERROR(RSX, "NV4097_SET_SURFACE_PITCH_Z: Bad count (%d)", count); break; } } @@ -1491,7 +1613,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const if (count != 1) { - LOG_WARNING(RSX, "NV4097_SET_CONTEXT_DMA_COLOR_A: Bad count (%d)", count); + LOG_ERROR(RSX, "NV4097_SET_CONTEXT_DMA_COLOR_A: Bad count (%d)", count); break; } } @@ -1509,7 +1631,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const m_set_context_dma_color_c = true; m_context_dma_color_c = ARGS(0); - if(count > 1) + if (count > 1) { m_set_context_dma_color_d = true; m_context_dma_color_d = ARGS(1); @@ -1520,7 +1642,9 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV4097_SET_CONTEXT_DMA_COLOR_D: { if (ARGS(0)) - LOG_WARNING(RSX, "NV4097_SET_CONTEXT_DMA_COLOR_D: 0x%x", ARGS(0)); + { + LOG_WARNING(RSX, "TODO: NV4097_SET_CONTEXT_DMA_COLOR_D: 0x%x", ARGS(0)); + } } break; @@ -1533,15 +1657,19 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV4097_SET_CONTEXT_DMA_SEMAPHORE: { - if (ARGS(0)) - LOG_WARNING(RSX, "NV4097_SET_CONTEXT_DMA_SEMAPHORE: 0x%x", ARGS(0)); + if (u32 value = ARGS(0)) + { + LOG_WARNING(RSX, "TODO: NV4097_SET_CONTEXT_DMA_SEMAPHORE: 0x%x", value); + } } break; case NV4097_SET_CONTEXT_DMA_NOTIFIES: { - if (ARGS(0)) - LOG_WARNING(RSX, "NV4097_SET_CONTEXT_DMA_NOTIFIES: 0x%x", ARGS(0)); + if (u32 value = ARGS(0)) + { + LOG_WARNING(RSX, "TODO: NV4097_SET_CONTEXT_DMA_NOTIFIES: 0x%x", value); + } } break; @@ -1553,7 +1681,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const m_surface_clip_x = a0; m_surface_clip_w = a0 >> 16; - if(count == 2) + if (count == 2) { const u32 a1 = ARGS(1); m_set_surface_clip_vertical = true; @@ -1582,51 +1710,55 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const const u8 alphaToOne = (a0 >> 8) & 0xf; const u16 sampleMask = a0 >> 16; - LOG_WARNING(RSX, "TODO: NV4097_SET_ANTI_ALIASING_CONTROL: 0x%x", a0); + if (a0) + { + LOG_WARNING(RSX, "TODO: NV4097_SET_ANTI_ALIASING_CONTROL: 0x%x", a0); + } } break; // Line/Polygon smoothing case NV4097_SET_LINE_SMOOTH_ENABLE: { - m_set_line_smooth = ARGS(0) ? true : false; + const u32 value = ARGS(0); + Enable(cmd, value); } break; case NV4097_SET_POLY_SMOOTH_ENABLE: { - m_set_poly_smooth = ARGS(0) ? true : false; + const u32 value = ARGS(0); + Enable(cmd, value); } break; // Line width case NV4097_SET_LINE_WIDTH: { - m_set_line_width = true; - const u32 a0 = ARGS(0); - m_line_width = (float)a0 / 8.0f; + const u32 value = ARGS(0); + LineWidth((float)value / 8.0f); } break; // Line/Polygon stipple case NV4097_SET_LINE_STIPPLE: { - m_set_line_stipple = ARGS(0) ? true : false; + const u32 value = ARGS(0); + Enable(cmd, value); } break; case NV4097_SET_LINE_STIPPLE_PATTERN: { - m_set_line_stipple = true; - const u32 a0 = ARGS(0); - m_line_stipple_factor = a0 & 0xffff; - m_line_stipple_pattern = a0 >> 16; + const u32 value = ARGS(0); + LineStipple(value & 0xffff, value >> 16); } break; case NV4097_SET_POLYGON_STIPPLE: { - m_set_polygon_stipple = ARGS(0) ? true : false; + const u32 value = ARGS(0); + Enable(cmd, value); } break; @@ -1642,44 +1774,45 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const // Zcull case NV4097_SET_ZCULL_EN: { - const u32 a0 = ARGS(0); - - m_set_depth_test = a0 & 0x1 ? true : false; - m_set_stencil_test = a0 & 0x2 ? true : false; + const u32 value = ARGS(0); + Enable(NV4097_SET_DEPTH_TEST_ENABLE, value & 0x1); + Enable(NV4097_SET_STENCIL_TEST_ENABLE, value & 0x2); } break; case NV4097_SET_ZCULL_CONTROL0: { - if (ARGS(0)) - LOG_WARNING(RSX, "NV4097_SET_ZCULL_CONTROL0: 0x%x", ARGS(0)); - - //m_set_depth_func = true; - //m_depth_func = ARGS(0) >> 4; + if (u32 value = ARGS(0)) + { + LOG_WARNING(RSX, "TODO: NV4097_SET_ZCULL_CONTROL0: 0x%x", value); + } } break; case NV4097_SET_ZCULL_CONTROL1: { - if (ARGS(0)) - LOG_WARNING(RSX, "NV4097_SET_ZCULL_CONTROL1: 0x%x", ARGS(0)); - - //m_set_depth_func = true; - //m_depth_func = ARGS(0) >> 4; + if (u32 value = ARGS(0)) + { + LOG_WARNING(RSX, "TODO: NV4097_SET_ZCULL_CONTROL1: 0x%x", value); + } } break; case NV4097_SET_ZCULL_STATS_ENABLE: { - if (ARGS(0)) - LOG_WARNING(RSX, "NV4097_SET_ZCULL_STATS_ENABLE: 0x%x", ARGS(0)); + if (u32 value = ARGS(0)) + { + LOG_WARNING(RSX, "TODO: NV4097_SET_ZCULL_STATS_ENABLE: 0x%x", value); + } } break; case NV4097_ZCULL_SYNC: { - if (ARGS(0)) - LOG_WARNING(RSX, "NV4097_ZCULL_SYNC: 0x%x", ARGS(0)); + if (u32 value = ARGS(0)) + { + LOG_WARNING(RSX, "TODO: NV4097_ZCULL_SYNC: 0x%x", value); + } } break; @@ -1704,7 +1837,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const default: value = 0; - LOG_WARNING(RSX, "NV4097_GET_REPORT: Bad type %d", type); + LOG_ERROR(RSX, "NV4097_GET_REPORT: Bad type %d", type); break; } @@ -1732,6 +1865,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const break; default: LOG_ERROR(RSX, "NV4097_CLEAR_REPORT_VALUE: Bad type: %d", type); + break; } } break; @@ -1739,32 +1873,24 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const // Clip Plane case NV4097_SET_USER_CLIP_PLANE_CONTROL: { - const u32 a0 = ARGS(0); - m_set_clip_plane = true; - m_clip_plane_0 = (a0 & 0xf) ? true : false; - m_clip_plane_1 = ((a0 >> 4)) & 0xf ? true : false; - m_clip_plane_2 = ((a0 >> 8)) & 0xf ? true : false; - m_clip_plane_3 = ((a0 >> 12)) & 0xf ? true : false; - m_clip_plane_4 = ((a0 >> 16)) & 0xf ? true : false; - m_clip_plane_5 = (a0 >> 20) ? true : false; + const u32 value = ARGS(0); + Enable(cmd, value); } break; // Fog case NV4097_SET_FOG_MODE: { - m_set_fog_mode = true; - m_fog_mode = ARGS(0); + const u32 value = ARGS(0); + Fogi(value); } break; case NV4097_SET_FOG_PARAMS: { - m_set_fog_params = true; - const u32 a0 = ARGS(0); - const u32 a1 = ARGS(1); - m_fog_param0 = (float&)a0; - m_fog_param1 = (float&)a1; + const u32 start = ARGS(0); + const u32 end = ARGS(1); + Fogf((float&)start, (float&)end); } break; @@ -1774,16 +1900,16 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const const u8 cullNearFarEnable = ARGS(0) & 0xf; const u8 zclampEnable = (ARGS(0) >> 4) & 0xf; const u8 cullIgnoreW = (ARGS(0) >> 8) & 0xf; - LOG_WARNING(RSX, "TODO: NV4097_SET_ZMIN_MAX_CONTROL: cullNearFarEnable=%d, zclampEnable=%d, cullIgnoreW=%d", - cullNearFarEnable, zclampEnable, cullIgnoreW); + + LOG_WARNING(RSX, "TODO: NV4097_SET_ZMIN_MAX_CONTROL: cullNearFarEnable=%d, zclampEnable=%d, cullIgnoreW=%d", cullNearFarEnable, zclampEnable, cullIgnoreW); } break; - // Windows Clipping case NV4097_SET_WINDOW_OFFSET: { const u16 x = ARGS(0); const u16 y = ARGS(0) >> 16; + LOG_WARNING(RSX, "TODO: NV4097_SET_WINDOW_OFFSET: x=%d, y=%d", x, y); } break; @@ -1791,6 +1917,8 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV4097_SET_FREQUENCY_DIVIDER_OPERATION: { m_set_frequency_divider_operation = ARGS(0); + + LOG_WARNING(RSX, "TODO: NV4097_SET_FREQUENCY_DIVIDER_OPERATION: %d", m_set_frequency_divider_operation); } break; @@ -1798,13 +1926,15 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const { const u32 offset = ARGS(0) & 0xffffff; const u8 mode = ARGS(0) >> 24; - LOG_WARNING(RSX, "NV4097_SET_RENDER_ENABLE: Offset=0x%06x, Mode=0x%x", offset, mode); + + LOG_WARNING(RSX, "TODO: NV4097_SET_RENDER_ENABLE: Offset=0x%06x, Mode=0x%x", offset, mode); } break; case NV4097_SET_ZPASS_PIXEL_COUNT_ENABLE: { - const u32 enable = ARGS(0); + const u32 enable = ARGS(0); + LOG_WARNING(RSX, "TODO: NV4097_SET_ZPASS_PIXEL_COUNT_ENABLE: %d", enable); } break; @@ -1832,7 +1962,8 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const const u32 notify = ARGS(7); // The existing GCM commands use only the value 0x1 for inFormat and outFormat - if (inFormat != 0x01 || outFormat != 0x01) { + if (inFormat != 0x01 || outFormat != 0x01) + { LOG_ERROR(RSX, "NV0039_OFFSET_IN: Unsupported format: inFormat=%d, outFormat=%d", inFormat, outFormat); } @@ -1842,7 +1973,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const } else { - LOG_ERROR(RSX, "NV0039_OFFSET_IN: TODO: offset(in=0x%x, out=0x%x), pitch(in=0x%x, out=0x%x), line(len=0x%x, cnt=0x%x), fmt(in=0x%x, out=0x%x), notify=0x%x", + LOG_ERROR(RSX, "NV0039_OFFSET_IN: bad offset(in=0x%x, out=0x%x), pitch(in=0x%x, out=0x%x), line(len=0x%x, cnt=0x%x), fmt(in=0x%x, out=0x%x), notify=0x%x", inOffset, outOffset, inPitch, outPitch, lineLength, lineCount, inFormat, outFormat, notify); } } @@ -1857,22 +1988,26 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const } else { - LOG_ERROR(RSX, "NV0039_OFFSET_OUT: TODO: offset=0x%x", offset); + LOG_ERROR(RSX, "TODO: NV0039_OFFSET_OUT: offset=0x%x", offset); } } break; case NV0039_PITCH_IN: { - if (ARGS(0)) - LOG_WARNING(RSX, "NV0039_PITCH_IN: 0x%x", ARGS(0)); + if (u32 value = ARGS(0)) + { + LOG_WARNING(RSX, "TODO: NV0039_PITCH_IN: 0x%x", value); + } } break; case NV0039_BUFFER_NOTIFY: { - if (ARGS(0)) - LOG_WARNING(RSX, "NV0039_BUFFER_NOTIFY: 0x%x", ARGS(0)); + if (u32 value = ARGS(0)) + { + LOG_WARNING(RSX, "TODO: NV0039_BUFFER_NOTIFY: 0x%x", value); + } } break; @@ -1900,8 +2035,10 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const // NV309E case NV309E_SET_CONTEXT_DMA_IMAGE: { - if (ARGS(0)) - LOG_WARNING(RSX, "NV309E_SET_CONTEXT_DMA_IMAGE: 0x%x", ARGS(0)); + if (u32 value = ARGS(0)) + { + LOG_WARNING(RSX, "TODO: NV309E_SET_CONTEXT_DMA_IMAGE: 0x%x", value); + } } break; @@ -1911,7 +2048,8 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const const u8 width = ARGS(0) >> 16; const u8 format = ARGS(0); const u32 offset = ARGS(1); - LOG_WARNING(RSX, "NV309E_SET_FORMAT: Format:0x%x, Width:%d, Height:%d, Offset:0x%x", format, width, height, offset); + + LOG_WARNING(RSX, "TODO: NV309E_SET_FORMAT: Format:0x%x, Width:%d, Height:%d, Offset:0x%x", format, width, height, offset); } break; @@ -1943,27 +2081,28 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const c.y = (float&)a; } - if(count >= 3) + if (count >= 3) { u32 a = ARGS(2); a = a << 16 | a >> 16; c.z = (float&)a; } - if(count >= 4) + if (count >= 4) { u32 a = ARGS(3); a = a << 16 | a >> 16; c.w = (float&)a; } - if(count >= 5) + if (count >= 5) { LOG_WARNING(RSX, "NV308A_COLOR: count = %d", count); } - //LOG_WARNING(RSX, "NV308A_COLOR: [%d]: %f, %f, %f, %f", c.id, c.x, c.y, c.z, c.w); m_fragment_constants.push_back(c); + + //LOG_WARNING(RSX, "NV308A_COLOR: [%d]: %f, %f, %f, %f", c.id, c.x, c.y, c.z, c.w); } break; @@ -1978,7 +2117,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const { if (ARGS(0) != CELL_GCM_CONTEXT_SURFACE2D) { - LOG_WARNING(RSX, "NV3089_SET_CONTEXT_SURFACE: Unsupported surface (0x%x)", ARGS(0)); + LOG_ERROR(RSX, "NV3089_SET_CONTEXT_SURFACE: Unsupported surface (0x%x)", ARGS(0)); } } break; @@ -2001,12 +2140,12 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const u8* pixels_dst = vm::get_ptr(GetAddress(m_dst_offset, m_context_dma_img_dst - 0xfeed0000)); LOG_WARNING(RSX, "NV3089_IMAGE_IN_SIZE: width=%d, height=%d, pitch=%d, origin=%d, inter=%d, offset=0x%x, u=%d, v=%d", width, height, pitch, origin, inter, offset, u, v); - LOG_WARNING(RSX, "*** m_dst_offset=0x%x, m_color: conv_in_h=0x%x, format_src_pitch=0x%x, conv_in_x=0x%x, conv_in_y=0x%x, conv_out_x=0x%x, conv_out_y=0x%x", + LOG_WARNING(RSX, "NV3089_IMAGE_IN_SIZE: m_dst_offset=0x%x, m_color: conv_in_h=0x%x, format_src_pitch=0x%x, conv_in_x=0x%x, conv_in_y=0x%x, conv_out_x=0x%x, conv_out_y=0x%x", m_dst_offset, m_color_conv_in_h, m_color_format_src_pitch, m_color_conv_in_x, m_color_conv_in_y, m_color_conv_out_x, m_color_conv_out_y); - for(u16 y=0; y> 16; m_color_conv_dsdx = ARGS(7); m_color_conv_dtdy = ARGS(8); + + LOG_WARNING(RSX, "TODO: NV3089_SET_COLOR_CONVERSION"); } break; @@ -2131,7 +2272,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const case NV3089_IMAGE_IN_OFFSET: case NV3089_IMAGE_IN: { - LOG_WARNING(RSX, "Unused NV3089 method 0x%x detected!", cmd); + LOG_WARNING(RSX, "Unused NV3089 methods 0x%x detected!", cmd); } break; @@ -2162,18 +2303,18 @@ void RSXThread::End() ExecCMD(); for (auto &vdata : m_vertex_data) + { vdata.data.clear(); + } m_indexed_array.Reset(); m_fragment_constants.clear(); m_transform_constants.clear(); - m_cur_shader_prog_num = 0; - //m_cur_shader_prog = nullptr; + m_cur_fragment_prog_num = 0; m_clear_surface_mask = 0; m_begin_end = 0; - //Reset(); OnReset(); } @@ -2215,14 +2356,14 @@ void RSXThread::Task() continue; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for (std::chrono::milliseconds(1)); // hack } is_vblank_stopped = true; }); vblank.detach(); - while(!TestDestroy()) try + while (!TestDestroy()) try { if (Emu.IsStopped()) { @@ -2236,66 +2377,61 @@ void RSXThread::Task() u32 get = m_ctrl->get.read_sync(); u32 put = m_ctrl->put.read_sync(); - if(put == get || !Emu.IsRunning()) + if (put == get || !Emu.IsRunning()) { - if(put == get) + if (put == get) { - if(m_flip_status == 0) + if (m_flip_status == 0) m_sem_flip.post_and_wait(); m_sem_flush.post_and_wait(); } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for (std::chrono::milliseconds(1)); // hack continue; } - //ConLog.Write("addr = 0x%x", m_ioAddress + get); const u32 cmd = ReadIO32(get); const u32 count = (cmd >> 18) & 0x7ff; - //if(cmd == 0) continue; - + if (Ini.RSXLogging.GetValue()) + { LOG_NOTICE(Log::RSX, "%s (cmd=0x%x)", GetMethodName(cmd & 0xffff).c_str(), cmd); + } - //LOG_NOTICE(Log::RSX, "put=0x%x, get=0x%x, cmd=0x%x (%s)", put, get, cmd, GetMethodName(cmd & 0xffff).c_str()); - - if(cmd & CELL_GCM_METHOD_FLAG_JUMP) + if (cmd & CELL_GCM_METHOD_FLAG_JUMP) { u32 offs = cmd & 0x1fffffff; //LOG_WARNING(RSX, "rsx jump(0x%x) #addr=0x%x, cmd=0x%x, get=0x%x, put=0x%x", offs, m_ioAddress + get, cmd, get, put); m_ctrl->get.exchange(be_t::make(offs)); continue; } - if(cmd & CELL_GCM_METHOD_FLAG_CALL) + + if (cmd & CELL_GCM_METHOD_FLAG_CALL) { m_call_stack.push(get + 4); u32 offs = cmd & ~3; - //u32 addr = offs; //LOG_WARNING(RSX, "rsx call(0x%x) #0x%x - 0x%x", offs, cmd, get); m_ctrl->get.exchange(be_t::make(offs)); continue; } - if(cmd == CELL_GCM_METHOD_FLAG_RETURN) + + if (cmd == CELL_GCM_METHOD_FLAG_RETURN) { - //LOG_WARNING(RSX, "rsx return!"); u32 get = m_call_stack.top(); m_call_stack.pop(); //LOG_WARNING(RSX, "rsx return(0x%x)", get); m_ctrl->get.exchange(be_t::make(get)); continue; } - if(cmd & CELL_GCM_METHOD_FLAG_NON_INCREMENT) + + if (cmd & CELL_GCM_METHOD_FLAG_NON_INCREMENT) { - //LOG_WARNING(RSX, "non increment cmd! 0x%x", cmd); + //LOG_WARNING(RSX, "rsx non increment cmd! 0x%x", cmd); inc = 0; } - else - { - //LOG_WARNING(RSX, "increment cmd! 0x%x", cmd); - } - if(cmd == 0) //nop + if (cmd == 0) //nop { m_ctrl->get.atomic_op([](be_t& value) { @@ -2306,7 +2442,7 @@ void RSXThread::Task() auto args = vm::ptr::make((u32)Memory.RSXIOMem.RealAddr(get + 4)); - for(u32 i=0; i #include "Utilities/SSemaphore.h" #include "Utilities/Thread.h" +#include "Utilities/Timer.h" enum Method { @@ -101,19 +102,22 @@ public: protected: std::stack m_call_stack; CellGcmControl* m_ctrl; + Timer m_timer_sync; + double m_fps_limit = 59.94; public: GcmTileInfo m_tiles[m_tiles_count]; GcmZcullInfo m_zculls[m_zculls_count]; RSXTexture m_textures[m_textures_count]; + RSXVertexTexture m_vertex_textures[m_textures_count]; RSXVertexData m_vertex_data[m_vertex_count]; RSXIndexArrayData m_indexed_array; std::vector m_fragment_constants; std::vector m_transform_constants; - u32 m_shader_ctrl, m_cur_shader_prog_num; - RSXShaderProgram m_shader_progs[m_fragment_count]; - RSXShaderProgram* m_cur_shader_prog; + u32 m_shader_ctrl, m_cur_fragment_prog_num; + RSXFragmentProgram m_fragment_progs[m_fragment_count]; + RSXFragmentProgram* m_cur_fragment_prog; RSXVertexProgram m_vertex_progs[m_vertex_count]; RSXVertexProgram* m_cur_vertex_prog; @@ -492,7 +496,7 @@ protected: m_front_face = 0x0901; // GL_CCW m_cull_face = 0x0405; // GL_BACK m_alpha_func = 0x0207; // GL_ALWAYS - m_alpha_ref = 0; + m_alpha_ref = 0.0; m_logic_op = 0x1503; // GL_COPY m_shade_mode = 0x1D01; // GL_SMOOTH m_depth_mask = 1; @@ -515,12 +519,15 @@ protected: m_line_stipple_factor = 1; m_vertex_data_base_offset = 0; m_vertex_data_base_index = 0; - for (size_t i = 0; i < 32; i++) { + + // Construct Stipple Pattern + for (size_t i = 0; i < 32; i++) + { m_polygon_stipple_pattern[i] = 0xFFFFFFFF; } // Construct Textures - for(int i=0; i<16; i++) + for (int i = 0; i < 16; i++) { m_textures[i] = RSXTexture(i); } @@ -607,7 +614,7 @@ protected: m_clear_surface_mask = 0; m_begin_end = 0; - for(uint i=0; i __noinline void Notice(const char* fmt, Targs... args) const { - LogOutput(LogNotice, " : ", fmt::Format(fmt, args...)); + LogOutput(LogNotice, ": ", fmt::Format(fmt, args...)); } template __forceinline void Log(const char* fmt, Targs... args) const @@ -62,7 +62,7 @@ public: template __noinline void Success(const char* fmt, Targs... args) const { - LogOutput(LogSuccess, " : ", fmt::Format(fmt, args...)); + LogOutput(LogSuccess, ": ", fmt::Format(fmt, args...)); } template __noinline void Warning(const u32 id, const char* fmt, Targs... args) const diff --git a/rpcs3/Emu/SysCalls/ModuleManager.cpp b/rpcs3/Emu/SysCalls/ModuleManager.cpp index bb5609cbc7..17cdd88a60 100644 --- a/rpcs3/Emu/SysCalls/ModuleManager.cpp +++ b/rpcs3/Emu/SysCalls/ModuleManager.cpp @@ -38,6 +38,7 @@ extern void cellRtc_init(Module *pxThis); extern void cellSail_init(Module *pxThis); extern void cellSpurs_init(Module *pxThis); extern void cellSpursJq_init(Module *pxThis); +extern void cellSubdisplay_init(Module *pxThis); extern void cellSync_init(Module *pxThis); extern void cellSync2_init(Module *pxThis); extern void cellSysutil_init(Module *pxThis); @@ -125,7 +126,7 @@ static const g_modules_list[] = { 0x0031, "cellAvconfExt", cellAvconfExt_init, nullptr, nullptr }, { 0x0032, "cellUserInfo", cellUserInfo_init, nullptr, nullptr }, { 0x0033, "cellSysutilSavedata", nullptr, nullptr, nullptr }, - { 0x0034, "cellSubdisplay", nullptr, nullptr, nullptr }, + { 0x0034, "cellSubdisplay", cellSubdisplay_init, nullptr, nullptr }, { 0x0035, "cellSysutilRec", nullptr, nullptr, nullptr }, { 0x0036, "cellVideoExport", nullptr, nullptr, nullptr }, { 0x0037, "cellGameExec", nullptr, nullptr, nullptr }, diff --git a/rpcs3/Emu/SysCalls/Modules.cpp b/rpcs3/Emu/SysCalls/Modules.cpp index 26b6931544..3de1be5414 100644 --- a/rpcs3/Emu/SysCalls/Modules.cpp +++ b/rpcs3/Emu/SysCalls/Modules.cpp @@ -188,7 +188,7 @@ void fix_import(Module* module, u32 func, u32 addr) *ptr++ = ORI(11, 11, func & 0xffff); *ptr++ = NOP(); ++ptr; - *ptr++ = SC(2); + *ptr++ = SC(0); *ptr++ = BLR(); *ptr++ = NOP(); *ptr++ = NOP(); diff --git a/rpcs3/Emu/SysCalls/Modules.h b/rpcs3/Emu/SysCalls/Modules.h index 0ee2ddd9f4..5874dc6fc5 100644 --- a/rpcs3/Emu/SysCalls/Modules.h +++ b/rpcs3/Emu/SysCalls/Modules.h @@ -95,7 +95,8 @@ public: public: bool CheckID(u32 id) const; - template bool CheckId(u32 id, T*& data) + + template bool CheckId(u32 id, std::shared_ptr& data) { ID* id_data; @@ -106,7 +107,7 @@ public: return true; } - template bool CheckId(u32 id, T*& data, IDType& type) + template bool CheckId(u32 id, std::shared_ptr& data, IDType& type) { ID* id_data; @@ -117,10 +118,11 @@ public: return true; } + bool CheckID(u32 id, ID*& _id) const; template - u32 GetNewId(T* data, IDType type = TYPE_OTHER) + u32 GetNewId(std::shared_ptr& data, IDType type = TYPE_OTHER) { return GetIdManager().GetNewID(GetName(), data, type); } diff --git a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp index 9ae92e6dc6..139ab029f0 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAdec.cpp @@ -19,6 +19,8 @@ extern "C" Module *cellAdec = nullptr; +#define ADEC_ERROR(...) { cellAdec->Error(__VA_ARGS__); Emu.Pause(); return; } // only for decoder thread + AudioDecoder::AudioDecoder(AudioCodecType type, u32 addr, u32 size, vm::ptr func, u32 arg) : type(type) , memAddr(addr) @@ -31,33 +33,55 @@ AudioDecoder::AudioDecoder(AudioCodecType type, u32 addr, u32 size, vm::ptrError("AudioDecoder(): avcodec_find_decoder(ATRAC3P) failed"); - Emu.Pause(); - return; + ADEC_ERROR("AudioDecoder(): avcodec_find_decoder() failed"); + } + if (!input_format) + { + ADEC_ERROR("AudioDecoder(): av_find_input_format() failed"); } fmt = avformat_alloc_context(); if (!fmt) { - cellAdec->Error("AudioDecoder(): avformat_alloc_context failed"); - Emu.Pause(); - return; + ADEC_ERROR("AudioDecoder(): avformat_alloc_context() failed"); } io_buf = (u8*)av_malloc(4096); fmt->pb = avio_alloc_context(io_buf, 256, 0, this, adecRead, NULL, NULL); if (!fmt->pb) { - cellAdec->Error("AudioDecoder(): avio_alloc_context failed"); - Emu.Pause(); - return; + ADEC_ERROR("AudioDecoder(): avio_alloc_context() failed"); } } @@ -65,7 +89,7 @@ AudioDecoder::~AudioDecoder() { // TODO: check finalization AdecFrame af; - while (frames.Pop(af, &sq_no_wait)) + while (frames.try_pop(af)) { av_frame_unref(af.data); av_frame_free(&af.data); @@ -93,11 +117,11 @@ int adecRead(void* opaque, u8* buf, int buf_size) int res = 0; next: - if (adec.reader.has_ats) + if (adecIsAtracX(adec.type) && adec.reader.has_ats) { u8 code1 = vm::read8(adec.reader.addr + 2); u8 code2 = vm::read8(adec.reader.addr + 3); - adec.channels = (code1 >> 2) & 0x7; + adec.ch_cfg = (code1 >> 2) & 0x7; adec.frame_size = ((((u32)code1 & 0x3) << 8) | (u32)code2) * 8 + 8; adec.sample_rate = at3freq[code1 >> 5]; @@ -106,9 +130,9 @@ next: adec.reader.has_ats = false; } - if (!adec.reader.init) + if (adecIsAtracX(adec.type) && !adec.reader.init) { - OMAHeader oma(1 /* atrac3p id */, adec.sample_rate, adec.channels, adec.frame_size); + OMAHeader oma(1 /* atrac3p id */, adec.sample_rate, adec.ch_cfg, adec.frame_size); if (buf_size < sizeof(oma)) { cellAdec->Error("adecRead(): OMAHeader writing failed"); @@ -127,7 +151,7 @@ next: if (adec.reader.size < (u32)buf_size /*&& !adec.just_started*/) { AdecTask task; - if (!adec.job.Peek(task, &adec.is_closed)) + if (!adec.job.peek(task, 0, &adec.is_closed)) { if (Emu.IsStopped()) cellAdec->Warning("adecRawRead() aborted"); return 0; @@ -152,7 +176,7 @@ next: adec.cbFunc.call(*adec.adecCb, adec.id, CELL_ADEC_MSG_TYPE_AUDONE, adec.task.au.auInfo_addr, adec.cbArg); - adec.job.Pop(adec.task, nullptr); + adec.job.pop(adec.task); adec.reader.addr = adec.task.au.addr; adec.reader.size = adec.task.au.size; @@ -190,11 +214,12 @@ next: } } -u32 adecOpen(AudioDecoder* data) +u32 adecOpen(AudioDecoder* adec_ptr) { - AudioDecoder& adec = *data; + std::shared_ptr sptr(adec_ptr); + AudioDecoder& adec = *adec_ptr; - u32 adec_id = cellAdec->GetNewId(data); + u32 adec_id = cellAdec->GetNewId(sptr); adec.id = adec_id; @@ -207,8 +232,9 @@ u32 adecOpen(AudioDecoder* data) adec.adecCb->InitRegs(); adec.adecCb->DoRun(); - thread t("Audio Decoder[" + std::to_string(adec_id) + "] Thread", [&]() + thread t("Audio Decoder[" + std::to_string(adec_id) + "] Thread", [adec_ptr, sptr]() { + AudioDecoder& adec = *adec_ptr; cellAdec->Notice("Audio Decoder thread started"); AdecTask& task = adec.task; @@ -220,13 +246,7 @@ u32 adecOpen(AudioDecoder* data) break; } - //if (!adec.job.GetCountUnsafe() && adec.is_running) - //{ - // std::this_thread::sleep_for(std::chrono::milliseconds(1)); - // continue; - //} - - if (!adec.job.Pop(task, &adec.is_closed)) + if (!adec.job.pop(task, &adec.is_closed)) { break; } @@ -244,12 +264,16 @@ u32 adecOpen(AudioDecoder* data) adec.reader.has_ats = false; adec.just_started = true; - adec.channels = task.at3p.channels; - adec.frame_size = task.at3p.frame_size; - adec.sample_rate = task.at3p.sample_rate; - adec.use_ats_headers = task.at3p.ats_header == 1; + if (adecIsAtracX(adec.type)) + { + adec.ch_cfg = task.at3p.channel_config; + adec.ch_out = task.at3p.channels; + adec.frame_size = task.at3p.frame_size; + adec.sample_rate = task.at3p.sample_rate; + adec.use_ats_headers = task.at3p.ats_header == 1; + } + break; } - break; case adecEndSeq: { @@ -258,8 +282,8 @@ u32 adecOpen(AudioDecoder* data) adec.cbFunc.call(*adec.adecCb, adec.id, CELL_ADEC_MSG_TYPE_SEQDONE, CELL_OK, adec.cbArg); adec.just_finished = true; + break; } - break; case adecDecodeAu: { @@ -273,7 +297,8 @@ u32 adecOpen(AudioDecoder* data) if (adec.just_started) { adec.first_pts = task.au.pts; - adec.last_pts = task.au.pts - 0x10000; // hack? + adec.last_pts = task.au.pts; + if (adecIsAtracX(adec.type)) adec.last_pts -= 0x10000; // hack } struct AVPacketHolder : AVPacket @@ -313,39 +338,19 @@ u32 adecOpen(AudioDecoder* data) { AVDictionary* opts = nullptr; av_dict_set(&opts, "probesize", "96", 0); - err = avformat_open_input(&adec.fmt, NULL, av_find_input_format("oma"), &opts); + err = avformat_open_input(&adec.fmt, NULL, adec.input_format, &opts); if (err || opts) { - cellAdec->Error("adecDecodeAu: avformat_open_input() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0); - Emu.Pause(); - break; - } - - AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_ATRAC3P); // ??? - if (!codec) - { - cellAdec->Error("adecDecodeAu: avcodec_find_decoder() failed"); - Emu.Pause(); - break; + ADEC_ERROR("adecDecodeAu: avformat_open_input() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0); } //err = avformat_find_stream_info(adec.fmt, NULL); - //if (err) + //if (err || !adec.fmt->nb_streams) //{ - // cellAdec->Error("adecDecodeAu: avformat_find_stream_info() failed"); - // Emu.Pause(); - // break; + // ADEC_ERROR("adecDecodeAu: avformat_find_stream_info() failed (err=0x%x, nb_streams=%d)", err, adec.fmt->nb_streams); //} - //if (!adec.fmt->nb_streams) - //{ - // cellAdec->Error("adecDecodeAu: no stream found"); - // Emu.Pause(); - // break; - //} - if (!avformat_new_stream(adec.fmt, codec)) + if (!avformat_new_stream(adec.fmt, adec.codec)) { - cellAdec->Error("adecDecodeAu: avformat_new_stream() failed"); - Emu.Pause(); - break; + ADEC_ERROR("adecDecodeAu: avformat_new_stream() failed"); } adec.ctx = adec.fmt->streams[0]->codec; // TODO: check data @@ -354,13 +359,11 @@ u32 adecOpen(AudioDecoder* data) { std::lock_guard lock(g_mutex_avcodec_open2); // not multithread-safe (???) - err = avcodec_open2(adec.ctx, codec, &opts); + err = avcodec_open2(adec.ctx, adec.codec, &opts); } if (err || opts) { - cellAdec->Error("adecDecodeAu: avcodec_open2() failed"); - Emu.Pause(); - break; + ADEC_ERROR("adecDecodeAu: avcodec_open2() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0); } adec.just_started = false; } @@ -404,9 +407,7 @@ u32 adecOpen(AudioDecoder* data) if (!frame.data) { - cellAdec->Error("adecDecodeAu: av_frame_alloc() failed"); - Emu.Pause(); - break; + ADEC_ERROR("adecDecodeAu: av_frame_alloc() failed"); } int got_frame = 0; @@ -415,7 +416,7 @@ u32 adecOpen(AudioDecoder* data) if (decode <= 0) { - if (!last_frame && decode < 0) + if (decode < 0) { cellAdec->Error("adecDecodeAu: AU decoding error(0x%x)", decode); } @@ -424,36 +425,34 @@ u32 adecOpen(AudioDecoder* data) if (got_frame) { - u64 ts = av_frame_get_best_effort_timestamp(frame.data); - if (ts != AV_NOPTS_VALUE) + //u64 ts = av_frame_get_best_effort_timestamp(frame.data); + //if (ts != AV_NOPTS_VALUE) + //{ + // frame.pts = ts/* - adec.first_pts*/; + // adec.last_pts = frame.pts; + //} + adec.last_pts += ((u64)frame.data->nb_samples) * 90000 / frame.data->sample_rate; + frame.pts = adec.last_pts; + + s32 nbps = av_get_bytes_per_sample((AVSampleFormat)frame.data->format); + switch (frame.data->format) { - frame.pts = ts/* - adec.first_pts*/; - adec.last_pts = frame.pts; - } - else + case AV_SAMPLE_FMT_FLTP: break; + case AV_SAMPLE_FMT_S16P: break; + default: { - adec.last_pts += ((u64)frame.data->nb_samples) * 90000 / frame.data->sample_rate; - frame.pts = adec.last_pts; + ADEC_ERROR("adecDecodeAu: unsupported frame format(%d)", frame.data->format); + } } - //frame.pts = adec.last_pts; - //adec.last_pts += ((u64)frame.data->nb_samples) * 90000 / 48000; // ??? frame.auAddr = task.au.addr; frame.auSize = task.au.size; frame.userdata = task.au.userdata; - frame.size = frame.data->nb_samples * frame.data->channels * sizeof(float); - - if (frame.data->format != AV_SAMPLE_FMT_FLTP) - { - cellAdec->Error("adecDecodeaAu: unsupported frame format(%d)", frame.data->format); - Emu.Pause(); - break; - } + frame.size = frame.data->nb_samples * frame.data->channels * nbps; //LOG_NOTICE(HLE, "got audio frame (pts=0x%llx, nb_samples=%d, ch=%d, sample_rate=%d, nbps=%d)", - //frame.pts, frame.data->nb_samples, frame.data->channels, frame.data->sample_rate, - //av_get_bytes_per_sample((AVSampleFormat)frame.data->format)); + //frame.pts, frame.data->nb_samples, frame.data->channels, frame.data->sample_rate, nbps); - if (adec.frames.Push(frame, &adec.is_closed)) + if (adec.frames.push(frame, &adec.is_closed)) { frame.data = nullptr; // to prevent destruction adec.cbFunc.call(*adec.adecCb, adec.id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, adec.cbArg); @@ -462,16 +461,17 @@ u32 adecOpen(AudioDecoder* data) } adec.cbFunc.call(*adec.adecCb, adec.id, CELL_ADEC_MSG_TYPE_AUDONE, task.au.auInfo_addr, adec.cbArg); + break; } - break; - case adecClose: break; + case adecClose: + { + break; + } default: { - cellAdec->Error("Audio Decoder thread error: unknown task(%d)", task.type); - Emu.Pause(); - return; + ADEC_ERROR("Audio Decoder thread error: unknown task(%d)", task.type); } } } @@ -490,23 +490,25 @@ bool adecCheckType(AudioCodecType type) { switch (type) { - case CELL_ADEC_TYPE_ATRACX: cellAdec->Notice("adecCheckType: ATRAC3plus"); break; - case CELL_ADEC_TYPE_ATRACX_2CH: cellAdec->Notice("adecCheckType: ATRAC3plus 2ch"); break; + case CELL_ADEC_TYPE_ATRACX: cellAdec->Notice("adecCheckType(): ATRAC3plus"); break; + case CELL_ADEC_TYPE_ATRACX_2CH: cellAdec->Notice("adecCheckType(): ATRAC3plus 2ch"); break; + case CELL_ADEC_TYPE_ATRACX_6CH: cellAdec->Notice("adecCheckType(): ATRAC3plus 6ch"); break; + case CELL_ADEC_TYPE_ATRACX_8CH: cellAdec->Notice("adecCheckType(): ATRAC3plus 8ch"); break; + case CELL_ADEC_TYPE_MP3: cellAdec->Notice("adecCheckType(): MP3"); break; - case CELL_ADEC_TYPE_ATRACX_6CH: - case CELL_ADEC_TYPE_ATRACX_8CH: case CELL_ADEC_TYPE_LPCM_PAMF: case CELL_ADEC_TYPE_AC3: - case CELL_ADEC_TYPE_MP3: case CELL_ADEC_TYPE_ATRAC3: case CELL_ADEC_TYPE_MPEG_L2: case CELL_ADEC_TYPE_CELP: case CELL_ADEC_TYPE_M4AAC: case CELL_ADEC_TYPE_CELP8: + { cellAdec->Todo("Unimplemented audio codec type (%d)", type); + Emu.Pause(); break; - default: - return false; + } + default: return false; } return true; @@ -554,14 +556,14 @@ int cellAdecClose(u32 handle) { cellAdec->Warning("cellAdecClose(handle=%d)", handle); - AudioDecoder* adec; + std::shared_ptr adec; if (!Emu.GetIdManager().GetIDData(handle, adec)) { return CELL_ADEC_ERROR_ARG; } adec->is_closed = true; - adec->job.Push(AdecTask(adecClose), &sq_no_wait); + adec->job.try_push(AdecTask(adecClose)); while (!adec->is_finished) { @@ -570,7 +572,7 @@ int cellAdecClose(u32 handle) cellAdec->Warning("cellAdecClose(%d) aborted", handle); break; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } if (adec->adecCb) Emu.GetCPU().RemoveThread(adec->adecCb->GetId()); @@ -582,7 +584,7 @@ int cellAdecStartSeq(u32 handle, u32 param_addr) { cellAdec->Warning("cellAdecStartSeq(handle=%d, param_addr=0x%x)", handle, param_addr); - AudioDecoder* adec; + std::shared_ptr adec; if (!Emu.GetIdManager().GetIDData(handle, adec)) { return CELL_ADEC_ERROR_ARG; @@ -592,7 +594,10 @@ int cellAdecStartSeq(u32 handle, u32 param_addr) switch (adec->type) { + case CELL_ADEC_TYPE_ATRACX: case CELL_ADEC_TYPE_ATRACX_2CH: + case CELL_ADEC_TYPE_ATRACX_6CH: + case CELL_ADEC_TYPE_ATRACX_8CH: { auto param = vm::ptr::make(param_addr); @@ -608,6 +613,13 @@ int cellAdecStartSeq(u32 handle, u32 param_addr) task.at3p.sample_rate, task.at3p.channel_config, task.at3p.channels, task.at3p.frame_size, (u32&)task.at3p.extra_config, task.at3p.output, task.at3p.downmix, task.at3p.ats_header); break; } + case CELL_ADEC_TYPE_MP3: + { + auto param = vm::ptr::make(param_addr); + + cellAdec->Todo("*** CellAdecParamMP3: bw_pcm=%d", param->bw_pcm.ToLE()); + break; + } default: { cellAdec->Todo("cellAdecStartSeq(): Unimplemented audio codec type(%d)", adec->type); @@ -616,7 +628,7 @@ int cellAdecStartSeq(u32 handle, u32 param_addr) } } - adec->job.Push(task, &adec->is_closed); + adec->job.push(task, &adec->is_closed); return CELL_OK; } @@ -624,13 +636,13 @@ int cellAdecEndSeq(u32 handle) { cellAdec->Warning("cellAdecEndSeq(handle=%d)", handle); - AudioDecoder* adec; + std::shared_ptr adec; if (!Emu.GetIdManager().GetIDData(handle, adec)) { return CELL_ADEC_ERROR_ARG; } - adec->job.Push(AdecTask(adecEndSeq), &adec->is_closed); + adec->job.push(AdecTask(adecEndSeq), &adec->is_closed); return CELL_OK; } @@ -638,7 +650,7 @@ int cellAdecDecodeAu(u32 handle, vm::ptr auInfo) { cellAdec->Log("cellAdecDecodeAu(handle=%d, auInfo_addr=0x%x)", handle, auInfo.addr()); - AudioDecoder* adec; + std::shared_ptr adec; if (!Emu.GetIdManager().GetIDData(handle, adec)) { return CELL_ADEC_ERROR_ARG; @@ -652,7 +664,7 @@ int cellAdecDecodeAu(u32 handle, vm::ptr auInfo) task.au.userdata = auInfo->userData; //cellAdec->Notice("cellAdecDecodeAu(): addr=0x%x, size=0x%x, pts=0x%llx", task.au.addr, task.au.size, task.au.pts); - adec->job.Push(task, &adec->is_closed); + adec->job.push(task, &adec->is_closed); return CELL_OK; } @@ -660,14 +672,14 @@ int cellAdecGetPcm(u32 handle, vm::ptr outBuffer) { cellAdec->Log("cellAdecGetPcm(handle=%d, outBuffer_addr=0x%x)", handle, outBuffer.addr()); - AudioDecoder* adec; + std::shared_ptr adec; if (!Emu.GetIdManager().GetIDData(handle, adec)) { return CELL_ADEC_ERROR_ARG; } AdecFrame af; - if (!adec->frames.Pop(af, &sq_no_wait)) + if (!adec->frames.try_pop(af)) { //std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack return CELL_ADEC_ERROR_EMPTY; @@ -678,7 +690,7 @@ int cellAdecGetPcm(u32 handle, vm::ptr outBuffer) if (outBuffer) { // reverse byte order: - if (frame->channels == 1) + if (frame->format == AV_SAMPLE_FMT_FLTP && frame->channels == 1) { float* in_f = (float*)frame->extended_data[0]; for (u32 i = 0; i < af.size / 4; i++) @@ -686,7 +698,7 @@ int cellAdecGetPcm(u32 handle, vm::ptr outBuffer) outBuffer[i] = in_f[i]; } } - else if (frame->channels == 2) + else if (frame->format == AV_SAMPLE_FMT_FLTP && frame->channels == 2) { float* in_f[2]; in_f[0] = (float*)frame->extended_data[0]; @@ -697,9 +709,70 @@ int cellAdecGetPcm(u32 handle, vm::ptr outBuffer) outBuffer[i * 2 + 1] = in_f[1][i]; } } + else if (frame->format == AV_SAMPLE_FMT_FLTP && frame->channels == 6) + { + float* in_f[6]; + in_f[0] = (float*)frame->extended_data[0]; + in_f[1] = (float*)frame->extended_data[1]; + in_f[2] = (float*)frame->extended_data[2]; + in_f[3] = (float*)frame->extended_data[3]; + in_f[4] = (float*)frame->extended_data[4]; + in_f[5] = (float*)frame->extended_data[5]; + for (u32 i = 0; i < af.size / 24; i++) + { + outBuffer[i * 6 + 0] = in_f[0][i]; + outBuffer[i * 6 + 1] = in_f[1][i]; + outBuffer[i * 6 + 2] = in_f[2][i]; + outBuffer[i * 6 + 3] = in_f[3][i]; + outBuffer[i * 6 + 4] = in_f[4][i]; + outBuffer[i * 6 + 5] = in_f[5][i]; + } + } + else if (frame->format == AV_SAMPLE_FMT_FLTP && frame->channels == 8) + { + float* in_f[8]; + in_f[0] = (float*)frame->extended_data[0]; + in_f[1] = (float*)frame->extended_data[1]; + in_f[2] = (float*)frame->extended_data[2]; + in_f[3] = (float*)frame->extended_data[3]; + in_f[4] = (float*)frame->extended_data[4]; + in_f[5] = (float*)frame->extended_data[5]; + in_f[6] = (float*)frame->extended_data[6]; + in_f[7] = (float*)frame->extended_data[7]; + for (u32 i = 0; i < af.size / 24; i++) + { + outBuffer[i * 8 + 0] = in_f[0][i]; + outBuffer[i * 8 + 1] = in_f[1][i]; + outBuffer[i * 8 + 2] = in_f[2][i]; + outBuffer[i * 8 + 3] = in_f[3][i]; + outBuffer[i * 8 + 4] = in_f[4][i]; + outBuffer[i * 8 + 5] = in_f[5][i]; + outBuffer[i * 8 + 6] = in_f[6][i]; + outBuffer[i * 8 + 7] = in_f[7][i]; + } + } + else if (frame->format == AV_SAMPLE_FMT_S16P && frame->channels == 1) + { + s16* in_i = (s16*)frame->extended_data[0]; + for (u32 i = 0; i < af.size / 2; i++) + { + outBuffer[i] = (float)in_i[i] / 0x8000; + } + } + else if (frame->format == AV_SAMPLE_FMT_S16P && frame->channels == 2) + { + s16* in_i[2]; + in_i[0] = (s16*)frame->extended_data[0]; + in_i[1] = (s16*)frame->extended_data[1]; + for (u32 i = 0; i < af.size / 4; i++) + { + outBuffer[i * 2 + 0] = (float)in_i[0][i] / 0x8000; + outBuffer[i * 2 + 1] = (float)in_i[1][i] / 0x8000; + } + } else { - cellAdec->Error("cellAdecGetPcm(): unsupported channel count (%d)", frame->channels); + cellAdec->Error("cellAdecGetPcm(): unsupported frame format (channels=%d, format=%d)", frame->channels, frame->format); Emu.Pause(); } } @@ -713,14 +786,14 @@ int cellAdecGetPcmItem(u32 handle, vm::ptr pcmItem_ptr) { cellAdec->Log("cellAdecGetPcmItem(handle=%d, pcmItem_ptr_addr=0x%x)", handle, pcmItem_ptr.addr()); - AudioDecoder* adec; + std::shared_ptr adec; if (!Emu.GetIdManager().GetIDData(handle, adec)) { return CELL_ADEC_ERROR_ARG; } AdecFrame af; - if (!adec->frames.Peek(af, &sq_no_wait)) + if (!adec->frames.try_peek(af)) { //std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack return CELL_ADEC_ERROR_EMPTY; @@ -747,21 +820,40 @@ int cellAdecGetPcmItem(u32 handle, vm::ptr pcmItem_ptr) pcm->auInfo.startAddr = af.auAddr; pcm->auInfo.userData = af.userdata; - auto atx = vm::ptr::make(pcm.addr() + sizeof(CellAdecPcmItem)); - atx->samplingFreq = frame->sample_rate; - atx->nbytes = frame->nb_samples * sizeof(float); - if (frame->channels == 1) + if (adecIsAtracX(adec->type)) { - atx->channelConfigIndex = 1; + auto atx = vm::ptr::make(pcm.addr() + sizeof(CellAdecPcmItem)); + + atx->samplingFreq = frame->sample_rate; + atx->nbytes = frame->nb_samples * sizeof(float); + if (frame->channels == 1) + { + atx->channelConfigIndex = 1; + } + else if (frame->channels == 2) + { + atx->channelConfigIndex = 2; + } + else if (frame->channels == 6) + { + atx->channelConfigIndex = 6; + } + else if (frame->channels == 8) + { + atx->channelConfigIndex = 7; + } + else + { + cellAdec->Error("cellAdecGetPcmItem(): unsupported channel count (%d)", frame->channels); + Emu.Pause(); + } } - else if (frame->channels == 2) + else if (adec->type == CELL_ADEC_TYPE_MP3) { - atx->channelConfigIndex = 2; - } - else - { - cellAdec->Error("cellAdecGetPcmItem(): unsupported channel count (%d)", frame->channels); - Emu.Pause(); + auto mp3 = vm::ptr::make(pcm.addr() + sizeof(CellAdecPcmItem)); + + // TODO + memset(mp3.get_ptr(), 0, sizeof(CellAdecMP3Info)); } *pcmItem_ptr = pcm.addr(); diff --git a/rpcs3/Emu/SysCalls/Modules/cellAdec.h b/rpcs3/Emu/SysCalls/Modules/cellAdec.h index 414d986dee..a0a3fb2a8e 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAdec.h +++ b/rpcs3/Emu/SysCalls/Modules/cellAdec.h @@ -1,7 +1,5 @@ #pragma once -#include "Utilities/SQueue.h" - // Error Codes enum { @@ -284,6 +282,14 @@ enum AudioCodecType CELL_ADEC_TYPE_RESERVED25, }; +static bool adecIsAtracX(const AudioCodecType type) +{ + return type == CELL_ADEC_TYPE_ATRACX + || type == CELL_ADEC_TYPE_ATRACX_2CH + || type == CELL_ADEC_TYPE_ATRACX_6CH + || type == CELL_ADEC_TYPE_ATRACX_8CH; +} + // Output Channel Number enum CellAdecChannel { @@ -1093,13 +1099,15 @@ static_assert(sizeof(OMAHeader) == 96, "Wrong OMAHeader size"); class AudioDecoder { public: - SQueue job; + squeue_t job; u32 id; volatile bool is_closed; volatile bool is_finished; bool just_started; bool just_finished; + AVCodec* codec; + AVInputFormat* input_format; AVCodecContext* ctx; AVFormatContext* fmt; u8* io_buf; @@ -1118,7 +1126,7 @@ public: } reader; - SQueue frames; + squeue_t frames; const AudioCodecType type; const u32 memAddr; @@ -1130,7 +1138,8 @@ public: AdecTask task; u64 last_pts, first_pts; - u32 channels; + u32 ch_out; + u32 ch_cfg; u32 frame_size; u32 sample_rate; bool use_ats_headers; diff --git a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp index f302a9fc2f..69b95612cd 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAudio.cpp @@ -2,11 +2,13 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/SysCalls/Modules.h" +#include "Emu/Memory/atomic_type.h" #include "rpcs3/Ini.h" -#include "Utilities/SQueue.h" -#include "Emu/Event.h" +#include "Emu/SysCalls/lv2/sleep_queue_type.h" #include "Emu/SysCalls/lv2/sys_time.h" +#include "Emu/SysCalls/lv2/sys_event.h" +#include "Emu/Event.h" #include "Emu/Audio/AudioManager.h" #include "Emu/Audio/AudioDumper.h" #include "Emu/Audio/cellAudio.h" @@ -74,11 +76,8 @@ int cellAudioInit() oal_buffer_float[i] = std::unique_ptr(new float[oal_buffer_size] {} ); } - SQueue queue; - queue.Clear(); - - SQueue queue_float; - queue_float.Clear(); + squeue_t queue; + squeue_t queue_float; std::vector keys; @@ -105,9 +104,9 @@ int cellAudioInit() float* oal_buffer_float = nullptr; if (g_is_u16) - queue.Pop(oal_buffer, nullptr); + queue.pop(oal_buffer); else - queue_float.Pop(oal_buffer_float, nullptr); + queue_float.pop(oal_buffer_float); if (g_is_u16) { @@ -370,9 +369,9 @@ int cellAudioInit() if(m_audio_out) { if (g_is_u16) - queue.Push(&oal_buffer[oal_pos][0], nullptr); + queue.push(&oal_buffer[oal_pos][0]); - queue_float.Push(&oal_buffer_float[oal_pos][0], nullptr); + queue_float.push(&oal_buffer_float[oal_pos][0]); } oal_buffer_offset = 0; @@ -438,8 +437,8 @@ int cellAudioInit() } cellAudio->Notice("Audio thread ended"); abort: - queue.Push(nullptr, nullptr); - queue_float.Push(nullptr, nullptr); + queue.push(nullptr); + queue_float.push(nullptr); if(do_dump) m_dump.Finalize(); @@ -457,7 +456,7 @@ abort: while (!internal_finished) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } m_config.m_is_audio_finalized = true; @@ -471,7 +470,7 @@ abort: cellAudio->Warning("cellAudioInit() aborted"); return CELL_OK; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } return CELL_OK; @@ -490,7 +489,7 @@ int cellAudioQuit() while (!m_config.m_is_audio_finalized) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack if (Emu.IsStopped()) { cellAudio->Warning("cellAudioQuit(): aborted"); @@ -527,6 +526,9 @@ int cellAudioPortOpen(vm::ptr audioParam, vm::ptr portN port.channel = (u8)audioParam->nChannel; port.block = (u8)audioParam->nBlock; port.attr = audioParam->attr; + port.addr = m_config.m_buffer + (128 * 1024 * i); + port.read_index_addr = m_config.m_indexes + (sizeof(u64) * i); + port.size = port.channel * port.block * 256 * sizeof(float); if (port.attr & CELL_AUDIO_PORTATTR_INITLEVEL) { port.level = audioParam->level; @@ -578,9 +580,9 @@ int cellAudioGetPortConfig(u32 portNum, vm::ptr portConfig) portConfig->nChannel = port.channel; portConfig->nBlock = port.block; - portConfig->portSize = port.channel * port.block * 256 * sizeof(float); - portConfig->portAddr = m_config.m_buffer + (128 * 1024 * portNum); // 0x20020000 - portConfig->readIndexAddr = m_config.m_indexes + (sizeof(u64) * portNum); // 0x20010010 on ps3 + portConfig->portSize = port.size; + portConfig->portAddr = port.addr; // 0x20020000 + portConfig->readIndexAddr = port.read_index_addr; // 0x20010010 on ps3 cellAudio->Log("*** port config: nChannel=%d, nBlock=%d, portSize=0x%x, portAddr=0x%x, readIndexAddr=0x%x", (u32)portConfig->nChannel, (u32)portConfig->nBlock, (u32)portConfig->portSize, (u32)portConfig->portAddr, (u32)portConfig->readIndexAddr); @@ -731,6 +733,28 @@ int cellAudioGetPortBlockTag(u32 portNum, u64 blockNo, vm::ptr tag) int cellAudioSetPortLevel(u32 portNum, float level) { cellAudio->Todo("cellAudioSetPortLevel(portNum=0x%x, level=%f)", portNum, level); + + AudioPortConfig& port = m_config.m_ports[portNum]; + + if (portNum >= m_config.AUDIO_PORT_COUNT) + { + return CELL_AUDIO_ERROR_PARAM; + } + + if (!port.m_is_audio_port_opened) + { + return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + } + + if (!port.m_is_audio_port_started) + { + return CELL_AUDIO_ERROR_PORT_NOT_RUN; + } + + std::lock_guard lock(audioMutex); + + port.level = level; // TODO + return CELL_OK; } @@ -749,11 +773,10 @@ int cellAudioCreateNotifyEventQueue(vm::ptr id, vm::ptr key) } event_key = (event_key << 48) | 0x80004d494f323221; // left part: 0x8000, 0x8001, 0x8002 ... - EventQueue* eq = new EventQueue(SYS_SYNC_FIFO, SYS_PPU_QUEUE, event_key, event_key, 32); + std::shared_ptr eq(new EventQueue(SYS_SYNC_FIFO, SYS_PPU_QUEUE, event_key, event_key, 32)); if (!Emu.GetEventManager().RegisterKey(eq, event_key)) { - delete eq; return CELL_AUDIO_ERROR_EVENT_QUEUE; } @@ -841,21 +864,117 @@ int cellAudioRemoveNotifyEventQueueEx(u64 key, u32 iFlags) return CELL_OK; } -int cellAudioAddData(u32 portNum, vm::ptr> src, u32 samples, float volume) +int cellAudioAddData(u32 portNum, vm::ptr src, u32 samples, float volume) { - cellAudio->Todo("cellAudioAddData(portNum=0x%x, src_addr=0x%x, samples=%d, volume=%f)", portNum, src.addr(), samples, volume); + cellAudio->Warning("cellAudioAddData(portNum=0x%x, src_addr=0x%x, samples=%d, volume=%f)", portNum, src.addr(), samples, volume); + + if (src.addr() % 16) + return CELL_AUDIO_ERROR_PARAM; + + AudioPortConfig& port = m_config.m_ports[portNum]; + + if (portNum >= m_config.AUDIO_PORT_COUNT) + { + return CELL_AUDIO_ERROR_PARAM; + } + + if (!port.m_is_audio_port_opened) + { + return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + } + + if (!port.m_is_audio_port_started) + { + return CELL_AUDIO_ERROR_PORT_NOT_RUN; + } + + std::lock_guard lock(audioMutex); + + u32 addr = port.addr; + u32 src_addr = src.addr(); + + for (u32 i = 0; i < samples; i++) + { + // vm::write32(addr, (u32)((float)vm::read32(src_addr) * volume)); // TODO: use volume? + vm::write32(addr, vm::read32(src_addr)); + src_addr += (port.size / samples); + addr += (port.size / samples); + } + return CELL_OK; } -int cellAudioAdd2chData(u32 portNum, vm::ptr> src, u32 samples, float volume) +int cellAudioAdd2chData(u32 portNum, vm::ptr src, u32 samples, float volume) { - cellAudio->Todo("cellAudioAdd2chData(portNum=0x%x, src_addr=0x%x, samples=%d, volume=%f)", portNum, src.addr(), samples, volume); + cellAudio->Warning("cellAudioAdd2chData(portNum=0x%x, src_addr=0x%x, samples=%d, volume=%f)", portNum, src.addr(), samples, volume); + + AudioPortConfig& port = m_config.m_ports[portNum]; + + if (portNum >= m_config.AUDIO_PORT_COUNT) + { + return CELL_AUDIO_ERROR_PARAM; + } + + if (!port.m_is_audio_port_opened) + { + return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + } + + if (!port.m_is_audio_port_started) + { + return CELL_AUDIO_ERROR_PORT_NOT_RUN; + } + + std::lock_guard lock(audioMutex); + + u32 addr = port.addr; + u32 src_addr = src.addr(); + + for (u32 i = 0; i < samples; i++) + { + // vm::write32(addr, (u32)((float)vm::read32(src_addr) * volume)); // TODO: use volume? + vm::write32(addr, vm::read32(src_addr)); + src_addr += (2 * port.block * 256 * sizeof(float) / samples); + addr += (2 * port.block * 256 * sizeof(float) / samples); + } + return CELL_OK; } -int cellAudioAdd6chData(u32 portNum, vm::ptr> src, float volume) +int cellAudioAdd6chData(u32 portNum, vm::ptr src, float volume) { - cellAudio->Todo("cellAudioAdd6chData(portNum=0x%x, src_addr=0x%x, volume=%f)", portNum, src.addr(), volume); + cellAudio->Warning("cellAudioAdd6chData(portNum=0x%x, src_addr=0x%x, volume=%f)", portNum, src.addr(), volume); + + AudioPortConfig& port = m_config.m_ports[portNum]; + + if (portNum >= m_config.AUDIO_PORT_COUNT) + { + return CELL_AUDIO_ERROR_PARAM; + } + + if (!port.m_is_audio_port_opened) + { + return CELL_AUDIO_ERROR_PORT_NOT_OPEN; + } + + if (!port.m_is_audio_port_started) + { + return CELL_AUDIO_ERROR_PORT_NOT_RUN; + } + + std::lock_guard lock(audioMutex); + + u32 addr = port.addr; + u32 src_addr = src.addr(); + + for (u32 i = 0; i < 256; i++) + { + // vm::write32(addr, (u32)((float)vm::read32(src_addr) * volume)); // TODO: use volume? + vm::write32(addr, vm::read32(src_addr)); + src_addr += (6 * port.block * sizeof(float)); + addr += (6 * port.block * sizeof(float)); + } + return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellAvconfExt.cpp b/rpcs3/Emu/SysCalls/Modules/cellAvconfExt.cpp index 260c8eb9bb..9014f472f0 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellAvconfExt.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellAvconfExt.cpp @@ -16,16 +16,18 @@ int cellVideoOutGetScreenSize(u32 videoOut, vm::ptr screenSize) { cellAvconfExt->Warning("cellVideoOutGetScreenSize(videoOut=%d, screenSize_addr=0x%x)", videoOut, screenSize.addr()); - if (!videoOut == CELL_VIDEO_OUT_PRIMARY) + if (videoOut != CELL_VIDEO_OUT_PRIMARY) + { return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT; + } //TODO: Use virtual screen size #ifdef _WIN32 HDC screen = GetDC(NULL); - float diagonal = round(sqrt((pow(GetDeviceCaps(screen, HORZSIZE), 2) + pow(GetDeviceCaps(screen, VERTSIZE), 2))) * 0.0393); + float diagonal = roundf(sqrtf((powf(float(GetDeviceCaps(screen, HORZSIZE)), 2) + powf(float(GetDeviceCaps(screen, VERTSIZE)), 2))) * 0.0393f); #else // TODO: Linux implementation, without using wx - // float diagonal = round(sqrt((pow(wxGetDisplaySizeMM().GetWidth(), 2) + pow(wxGetDisplaySizeMM().GetHeight(), 2))) * 0.0393); + // float diagonal = roundf(sqrtf((powf(wxGetDisplaySizeMM().GetWidth(), 2) + powf(wxGetDisplaySizeMM().GetHeight(), 2))) * 0.0393f); #endif if (Ini.GS3DTV.GetValue()) @@ -55,7 +57,8 @@ void cellAvconfExt_init(Module *pxThis) { cellAvconfExt = pxThis; - cellAvconfExt->AddFunc(0x4ec8c141, cellVideoOutConvertCursorColor); - cellAvconfExt->AddFunc(0xfaa275a4, cellVideoOutGetScreenSize); - cellAvconfExt->AddFunc(0xc7020f62, cellVideoOutSetGamma); + REG_FUNC(cellAvconfExt, cellVideoOutConvertCursorColor); + REG_FUNC(cellAvconfExt, cellVideoOutGetScreenSize); + REG_FUNC(cellAvconfExt, cellVideoOutGetGamma); + REG_FUNC(cellAvconfExt, cellVideoOutSetGamma); } \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp index 57ee842309..5c17b81125 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.cpp @@ -10,67 +10,112 @@ Module *cellDmux = nullptr; +#define DMUX_ERROR(...) { cellDmux->Error(__VA_ARGS__); Emu.Pause(); return; } // only for demuxer thread + PesHeader::PesHeader(DemuxerStream& stream) - : pts(0xffffffffffffffffull) - , dts(0xffffffffffffffffull) + : pts(CODEC_TS_INVALID) + , dts(CODEC_TS_INVALID) , size(0) , has_ts(false) + , is_ok(false) { u16 header; - stream.get(header); - stream.get(size); - if (size) + if (!stream.get(header)) + { + DMUX_ERROR("PesHeader(): end of stream (header)"); + } + if (!stream.get(size)) + { + DMUX_ERROR("PesHeader(): end of stream (size)"); + } + if (!stream.check(size)) + { + DMUX_ERROR("PesHeader(): end of stream (size=%d)", size); + } + + u8 pos = 0; + while (pos++ < size) { - u8 empty = 0; u8 v; - while (true) + if (!stream.get(v)) { - stream.get(v); - if (v != 0xFF) break; // skip padding bytes - empty++; - if (empty == size) return; - }; + return; // should never occur + } - if ((v & 0xF0) == 0x20 && (size - empty) >= 5) // pts only + if (v == 0xff) // skip padding bytes { - has_ts = true; + continue; + } + + if ((v & 0xf0) == 0x20 && (size - pos) >= 4) // pts only + { + pos += 4; pts = stream.get_ts(v); - stream.skip(size - empty - 5); + has_ts = true; + } + else if ((v & 0xf0) == 0x30 && (size - pos) >= 9) // pts and dts + { + pos += 5; + pts = stream.get_ts(v); + stream.get(v); + has_ts = true; + + if ((v & 0xf0) != 0x10) + { + cellDmux->Error("PesHeader(): dts not found (v=0x%x, size=%d, pos=%d)", v, size, pos - 1); + stream.skip(size - pos); + return; + } + pos += 4; + dts = stream.get_ts(v); } else { - has_ts = true; - if ((v & 0xF0) != 0x30 || (size - empty) < 10) - { - cellDmux->Error("PesHeader(): pts not found"); - Emu.Pause(); - } - pts = stream.get_ts(v); - stream.get(v); - if ((v & 0xF0) != 0x10) - { - cellDmux->Error("PesHeader(): dts not found"); - Emu.Pause(); - } - dts = stream.get_ts(v); - stream.skip(size - empty - 10); + cellDmux->Warning("PesHeader(): unknown code (v=0x%x, size=%d, pos=%d)", v, size, pos - 1); + stream.skip(size - pos); + pos = size; + break; } } + + is_ok = true; +} + +ElementaryStream::ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr cbFunc, u32 cbArg, u32 spec) + : dmux(dmux) + , memAddr(a128(addr)) + , memSize(size - (addr - memAddr)) + , fidMajor(fidMajor) + , fidMinor(fidMinor) + , sup1(sup1) + , sup2(sup2) + , cbFunc(cbFunc) + , cbArg(cbArg) + , spec(spec) + , put(a128(addr)) + , put_count(0) + , got_count(0) + , released(0) + , raw_pos(0) + , last_dts(CODEC_TS_INVALID) + , last_pts(CODEC_TS_INVALID) +{ } bool ElementaryStream::is_full(u32 space) { if (released < put_count) { - if (entries.IsFull()) + if (entries.is_full()) { return true; } u32 first = 0; - if (!entries.Peek(first, &dmux->is_closed) || !first) + if (!entries.peek(first, 0, &dmux->is_closed) || !first) { - throw "es::is_full() error: entries.Peek() failed"; + assert(!"es::is_full() error: entries.Peek() failed"); + return false; } else if (first >= put) { @@ -103,10 +148,7 @@ void ElementaryStream::push_au(u32 size, u64 dts, u64 pts, u64 userdata, bool ra { std::lock_guard lock(m_mutex); - if (is_full(size)) - { - throw "es::push_au() error: buffer is full"; - } + assert(!is_full(size)); if (put + size + 128 > memAddr + memSize) { @@ -146,9 +188,9 @@ void ElementaryStream::push_au(u32 size, u64 dts, u64 pts, u64 userdata, bool ra put_count++; } - if (!entries.Push(addr, &dmux->is_closed)) + if (!entries.push(addr, &dmux->is_closed)) { - throw "es::push_au() error: entries.Push() failed"; + assert(!"es::push_au() error: entries.Push() failed"); } } @@ -180,7 +222,7 @@ bool ElementaryStream::release() } u32 addr = 0; - if (!entries.Pop(addr, &dmux->is_closed) || !addr) + if (!entries.pop(addr, &dmux->is_closed) || !addr) { cellDmux->Error("es::release() error: entries.Pop() failed"); Emu.Pause(); @@ -206,7 +248,7 @@ bool ElementaryStream::peek(u32& out_data, bool no_ex, u32& out_spec, bool updat } u32 addr = 0; - if (!entries.Peek(addr, &dmux->is_closed, got_count - released) || !addr) + if (!entries.peek(addr, got_count - released, &dmux->is_closed) || !addr) { cellDmux->Error("es::peek() error: entries.Peek() failed"); Emu.Pause(); @@ -227,7 +269,7 @@ void ElementaryStream::reset() { std::lock_guard lock(m_mutex); put = memAddr; - entries.Clear(); + entries.clear(); put_count = 0; got_count = 0; released = 0; @@ -248,17 +290,18 @@ void dmuxQueryEsAttr(u32 info_addr /* may be 0 */, vm::ptrfilterIdMajor >= 0xe0) attr->memSize = 0x500000; // 0x45fa49 from ps3 else - attr->memSize = 0x8000; // 0x73d9 from ps3 + attr->memSize = 0x7000; // 0x73d9 from ps3 cellDmux->Warning("*** filter(0x%x, 0x%x, 0x%x, 0x%x)", (u32)esFilterId->filterIdMajor, (u32)esFilterId->filterIdMinor, (u32)esFilterId->supplementalInfo1, (u32)esFilterId->supplementalInfo2); } -u32 dmuxOpen(Demuxer* data) +u32 dmuxOpen(Demuxer* dmux_ptr) { - Demuxer& dmux = *data; + std::shared_ptr sptr(dmux_ptr); + Demuxer& dmux = *dmux_ptr; - u32 dmux_id = cellDmux->GetNewId(data); + u32 dmux_id = cellDmux->GetNewId(sptr); dmux.id = dmux_id; @@ -271,19 +314,20 @@ u32 dmuxOpen(Demuxer* data) dmux.dmuxCb->InitRegs(); dmux.dmuxCb->DoRun(); - thread t("Demuxer[" + std::to_string(dmux_id) + "] Thread", [&]() + thread t("Demuxer[" + std::to_string(dmux_id) + "] Thread", [dmux_ptr, sptr]() { + Demuxer& dmux = *dmux_ptr; cellDmux->Notice("Demuxer thread started (mem=0x%x, size=0x%x, cb=0x%x, arg=0x%x)", dmux.memAddr, dmux.memSize, dmux.cbFunc, dmux.cbArg); DemuxerTask task; DemuxerStream stream = {}; - ElementaryStream* esALL[192]; memset(esALL, 0, sizeof(esALL)); - ElementaryStream** esAVC = &esALL[0]; // AVC (max 16) - ElementaryStream** esM2V = &esALL[16]; // MPEG-2 (max 16) + ElementaryStream* esALL[96]; memset(esALL, 0, sizeof(esALL)); + ElementaryStream** esAVC = &esALL[0]; // AVC (max 16 minus M2V count) + ElementaryStream** esM2V = &esALL[16]; // M2V (max 16 minus AVC count) ElementaryStream** esDATA = &esALL[32]; // user data (max 16) - ElementaryStream** esATX = &esALL[48]; // ATRAC3+ (max 48) - ElementaryStream** esAC3 = &esALL[96]; // AC3 (max 48) - ElementaryStream** esPCM = &esALL[144]; // LPCM (max 48) + ElementaryStream** esATX = &esALL[48]; // ATRAC3+ (max 16) + ElementaryStream** esAC3 = &esALL[64]; // AC3 (max 16) + ElementaryStream** esPCM = &esALL[80]; // LPCM (max 16) u32 cb_add = 0; @@ -294,12 +338,11 @@ u32 dmuxOpen(Demuxer* data) break; } - if (!dmux.job.Peek(task, &sq_no_wait) && dmux.is_running && stream.addr) + if (!dmux.job.try_peek(task) && dmux.is_running && stream.addr) { // default task (demuxing) (if there is no other work) be_t code; be_t len; - u8 ch; if (!stream.peek(code)) { @@ -310,64 +353,119 @@ u32 dmuxOpen(Demuxer* data) dmux.cbFunc.call(*dmux.dmuxCb, dmux.id, dmuxMsg, dmux.cbArg); dmux.is_running = false; + continue; } - else switch (code.ToLE()) + + switch (code.ToLE()) { case PACK_START_CODE: { + if (!stream.check(14)) + { + DMUX_ERROR("End of stream (PACK_START_CODE)"); + } stream.skip(14); + break; } - break; case SYSTEM_HEADER_START_CODE: { + if (!stream.check(18)) + { + DMUX_ERROR("End of stream (SYSTEM_HEADER_START_CODE)"); + } stream.skip(18); + break; } - break; case PADDING_STREAM: { + if (!stream.check(6)) + { + DMUX_ERROR("End of stream (PADDING_STREAM)"); + } stream.skip(4); stream.get(len); + + if (!stream.check(len.ToLE())) + { + DMUX_ERROR("End of stream (PADDING_STREAM, len=%d)", len.ToLE()); + } stream.skip(len); + break; } - break; case PRIVATE_STREAM_2: { + if (!stream.check(6)) + { + DMUX_ERROR("End of stream (PRIVATE_STREAM_2)"); + } stream.skip(4); stream.get(len); + + cellDmux->Notice("PRIVATE_STREAM_2 (%d)", len.ToLE()); + + if (!stream.check(len.ToLE())) + { + DMUX_ERROR("End of stream (PRIVATE_STREAM_2, len=%d)", len.ToLE()); + } stream.skip(len); + break; } - break; case PRIVATE_STREAM_1: { + // audio and user data stream DemuxerStream backup = stream; - // audio AT3+ (and probably LPCM or user data) + if (!stream.check(6)) + { + DMUX_ERROR("End of stream (PRIVATE_STREAM_1)"); + } stream.skip(4); stream.get(len); - PesHeader pes(stream); + if (!stream.check(len.ToLE())) + { + DMUX_ERROR("End of stream (PRIVATE_STREAM_1, len=%d)", len.ToLE()); + } - // read additional header: - stream.peek(ch); // ??? - //stream.skip(4); - //pes.size += 4; + const PesHeader pes(stream); + if (!pes.is_ok) + { + DMUX_ERROR("PesHeader error (PRIVATE_STREAM_1, len=%d)", len.ToLE()); + } - if (esATX[ch]) + if (len < pes.size + 4) + { + DMUX_ERROR("End of block (PRIVATE_STREAM_1, PesHeader + fid_minor, len=%d)", len.ToLE()); + } + len -= pes.size + 4; + + u8 fid_minor; + if (!stream.get(fid_minor)) + { + DMUX_ERROR("End of stream (PRIVATE_STREAM1, fid_minor)"); + } + + const u32 ch = fid_minor % 16; + if ((fid_minor & -0x10) == 0 && esATX[ch]) { ElementaryStream& es = *esATX[ch]; if (es.raw_data.size() > 1024 * 1024) { stream = backup; - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack continue; } - stream.skip(4); - len -= 4; + if (len < 3 || !stream.check(3)) + { + DMUX_ERROR("End of block (ATX, unknown header, len=%d)", len.ToLE()); + } + len -= 3; + stream.skip(3); if (pes.has_ts) { @@ -375,7 +473,7 @@ u32 dmuxOpen(Demuxer* data) es.last_pts = pes.pts; } - es.push(stream, len - pes.size - 3); + es.push(stream, len); while (true) { @@ -386,9 +484,7 @@ u32 dmuxOpen(Demuxer* data) if (data[0] != 0x0f || data[1] != 0xd0) { - cellDmux->Error("ATX: 0x0fd0 header not found (ats=0x%llx)", ((be_t*)data)->ToLE()); - Emu.Pause(); - return; + DMUX_ERROR("ATX: 0x0fd0 header not found (ats=0x%llx)", ((be_t*)data)->ToLE()); } u32 frame_size = ((((u32)data[2] & 0x3) << 8) | (u32)data[3]) * 8 + 8; @@ -399,6 +495,8 @@ u32 dmuxOpen(Demuxer* data) es.push_au(frame_size + 8, es.last_dts, es.last_pts, stream.userdata, false /* TODO: set correct value */, 0); + //cellDmux->Notice("ATX AU pushed (ats=0x%llx, frame_size=%d)", ((be_t*)data)->ToLE(), frame_size); + auto esMsg = vm::ptr::make(a128(dmux.memAddr) + (cb_add ^= 16)); esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_AU_FOUND; esMsg->supplementalInfo = stream.userdata; @@ -407,38 +505,60 @@ u32 dmuxOpen(Demuxer* data) } else { - stream.skip(len - pes.size - 3); + cellDmux->Notice("PRIVATE_STREAM_1 (len=%d, fid_minor=0x%x)", len.ToLE(), fid_minor); + stream.skip(len); } + break; } - break; case 0x1e0: case 0x1e1: case 0x1e2: case 0x1e3: case 0x1e4: case 0x1e5: case 0x1e6: case 0x1e7: case 0x1e8: case 0x1e9: case 0x1ea: case 0x1eb: case 0x1ec: case 0x1ed: case 0x1ee: case 0x1ef: { - // video AVC - ch = code - 0x1e0; + // video stream (AVC or M2V) + DemuxerStream backup = stream; + + if (!stream.check(6)) + { + DMUX_ERROR("End of stream (video, code=0x%x)", code.ToLE()); + } + stream.skip(4); + stream.get(len); + + if (!stream.check(len.ToLE())) + { + DMUX_ERROR("End of stream (video, code=0x%x, len=%d)", code.ToLE(), len.ToLE()); + } + + const PesHeader pes(stream); + if (!pes.is_ok) + { + DMUX_ERROR("PesHeader error (video, code=0x%x, len=%d)", code.ToLE(), len.ToLE()); + } + + if (len < pes.size + 3) + { + DMUX_ERROR("End of block (video, code=0x%x, PesHeader)", code.ToLE()); + } + len -= pes.size + 3; + + const u32 ch = code.ToLE() % 16; if (esAVC[ch]) { ElementaryStream& es = *esAVC[ch]; - DemuxerStream backup = stream; - - stream.skip(4); - stream.get(len); - PesHeader pes(stream); const u32 old_size = (u32)es.raw_data.size(); if (es.isfull(old_size)) { stream = backup; - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack continue; } - if ((pes.has_ts && old_size) || old_size >= 0x70000) + if ((pes.has_ts && old_size) || old_size >= 0x69800) { - // push AU if it becomes too big or the next packet contains ts data + // push AU if it becomes too big or the next packet contains PTS/DTS es.push_au(old_size, es.last_dts, es.last_pts, stream.userdata, false /* TODO: set correct value */, 0); // callback @@ -456,54 +576,35 @@ u32 dmuxOpen(Demuxer* data) } // reconstruction of MPEG2-PS stream for vdec module - const u32 size = len + 6 /*- pes.size - 3*/; + const u32 size = (u32)len.ToLE() + pes.size + 9; stream = backup; es.push(stream, size); } else { - stream.skip(4); - stream.get(len); + cellDmux->Notice("Video stream (code=0x%x, len=%d)", code.ToLE(), len.ToLE()); stream.skip(len); } - } - break; - - case 0x1c0: case 0x1c1: case 0x1c2: case 0x1c3: - case 0x1c4: case 0x1c5: case 0x1c6: case 0x1c7: - case 0x1c8: case 0x1c9: case 0x1ca: case 0x1cb: - case 0x1cc: case 0x1cd: case 0x1ce: case 0x1cf: - case 0x1d0: case 0x1d1: case 0x1d2: case 0x1d3: - case 0x1d4: case 0x1d5: case 0x1d6: case 0x1d7: - case 0x1d8: case 0x1d9: case 0x1da: case 0x1db: - case 0x1dc: case 0x1dd: case 0x1de: case 0x1df: - { - // unknown - cellDmux->Warning("Unknown MPEG stream found"); - stream.skip(4); - stream.get(len); - stream.skip(len); - } - break; - - case USER_DATA_START_CODE: - { - cellDmux->Error("USER_DATA_START_CODE found"); - Emu.Pause(); - return; + break; } default: { + if ((code.ToLE() & PACKET_START_CODE_MASK) == PACKET_START_CODE_PREFIX) + { + DMUX_ERROR("Unknown code found (0x%x)", code.ToLE()); + } + // search stream.skip(1); } } + continue; } - // wait for task with yielding (if no default work) - if (!dmux.job.Pop(task, &dmux.is_closed)) + // wait for task if no work + if (!dmux.job.pop(task, &dmux.is_closed)) { break; // Emu is stopped } @@ -515,7 +616,7 @@ u32 dmuxOpen(Demuxer* data) if (task.stream.discontinuity) { cellDmux->Warning("dmuxSetStream (beginning)"); - for (u32 i = 0; i < 192; i++) + for (u32 i = 0; i < sizeof(esALL) / sizeof(esALL[0]); i++) { if (esALL[i]) { @@ -527,8 +628,8 @@ u32 dmuxOpen(Demuxer* data) stream = task.stream; //LOG_NOTICE(HLE, "*** stream updated(addr=0x%x, size=0x%x, discont=%d, userdata=0x%llx)", //stream.addr, stream.size, stream.discontinuity, stream.userdata); + break; } - break; case dmuxResetStream: case dmuxResetStreamAndWaitDone: @@ -543,44 +644,55 @@ u32 dmuxOpen(Demuxer* data) //if (task.type == dmuxResetStreamAndWaitDone) //{ //} + break; } - break; case dmuxEnableEs: { ElementaryStream& es = *task.es.es_ptr; - if (es.fidMajor >= 0xe0 && - es.fidMajor <= 0xef && - es.fidMinor == 0 && - es.sup1 == 1 && - es.sup2 == 0) + + // TODO: uncomment when ready to use + if ((es.fidMajor & -0x10) == 0xe0 && es.fidMinor == 0 && es.sup1 == 1 && !es.sup2) { - esAVC[es.fidMajor - 0xe0] = task.es.es_ptr; + esAVC[es.fidMajor % 16] = task.es.es_ptr; } - else if (es.fidMajor == 0xbd && - es.fidMinor == 0 && - es.sup1 == 0 && - es.sup2 == 0) + //else if ((es.fidMajor & -0x10) == 0xe0 && es.fidMinor == 0 && !es.sup1 && !es.sup2) + //{ + // esM2V[es.fidMajor % 16] = task.es.es_ptr; + //} + else if (es.fidMajor == 0xbd && (es.fidMinor & -0x10) == 0 && !es.sup1 && !es.sup2) { - esATX[0] = task.es.es_ptr; + esATX[es.fidMinor % 16] = task.es.es_ptr; } + //else if (es.fidMajor == 0xbd && (es.fidMinor & -0x10) == 0x20 && !es.sup1 && !es.sup2) + //{ + // esDATA[es.fidMinor % 16] = task.es.es_ptr; + //} + //else if (es.fidMajor == 0xbd && (es.fidMinor & -0x10) == 0x30 && !es.sup1 && !es.sup2) + //{ + // esAC3[es.fidMinor % 16] = task.es.es_ptr; + //} + //else if (es.fidMajor == 0xbd && (es.fidMinor & -0x10) == 0x40 && !es.sup1 && !es.sup2) + //{ + // esPCM[es.fidMinor % 16] = task.es.es_ptr; + //} else { - cellDmux->Warning("dmuxEnableEs: (TODO) unsupported filter (0x%x, 0x%x, 0x%x, 0x%x)", es.fidMajor, es.fidMinor, es.sup1, es.sup2); + DMUX_ERROR("dmuxEnableEs: unknown filter (0x%x, 0x%x, 0x%x, 0x%x)", es.fidMajor, es.fidMinor, es.sup1, es.sup2); } es.dmux = &dmux; + break; } - break; case dmuxDisableEs: { ElementaryStream& es = *task.es.es_ptr; if (es.dmux != &dmux) { - cellDmux->Warning("dmuxDisableEs: invalid elementary stream"); - break; + DMUX_ERROR("dmuxDisableEs: invalid elementary stream"); } - for (u32 i = 0; i < 192; i++) + + for (u32 i = 0; i < sizeof(esALL) / sizeof(esALL[0]); i++) { if (esALL[i] == &es) { @@ -589,22 +701,22 @@ u32 dmuxOpen(Demuxer* data) } es.dmux = nullptr; Emu.GetIdManager().RemoveID(task.es.es); + break; } - break; case dmuxFlushEs: { ElementaryStream& es = *task.es.es_ptr; const u32 old_size = (u32)es.raw_data.size(); - if (old_size && (es.fidMajor & 0xf0) == 0xe0) + if (old_size && (es.fidMajor & -0x10) == 0xe0) { // TODO (it's only for AVC, some ATX data may be lost) while (es.isfull(old_size)) { if (Emu.IsStopped() || dmux.is_closed) break; - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } es.push_au(old_size, es.last_dts, es.last_pts, stream.userdata, false, 0); @@ -626,22 +738,23 @@ u32 dmuxOpen(Demuxer* data) esMsg->msgType = CELL_DMUX_ES_MSG_TYPE_FLUSH_DONE; esMsg->supplementalInfo = stream.userdata; es.cbFunc.call(*dmux.dmuxCb, dmux.id, es.id, esMsg, es.cbArg); + break; } - break; case dmuxResetEs: { task.es.es_ptr->reset(); + break; + } + + case dmuxClose: + { + break; } - break; - - case dmuxClose: break; default: { - cellDmux->Error("Demuxer thread error: unknown task(%d)", task.type); - Emu.Pause(); - return; + DMUX_ERROR("Demuxer thread error: unknown task (0x%x)", task.type); } } } @@ -740,14 +853,14 @@ int cellDmuxClose(u32 demuxerHandle) { cellDmux->Warning("cellDmuxClose(demuxerHandle=%d)", demuxerHandle); - Demuxer* dmux; + std::shared_ptr dmux; if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux)) { return CELL_DMUX_ERROR_ARG; } dmux->is_closed = true; - dmux->job.Push(DemuxerTask(dmuxClose), &sq_no_wait); + dmux->job.try_push(DemuxerTask(dmuxClose)); while (!dmux->is_finished) { @@ -757,7 +870,7 @@ int cellDmuxClose(u32 demuxerHandle) return CELL_OK; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } if (dmux->dmuxCb) Emu.GetCPU().RemoveThread(dmux->dmuxCb->GetId()); @@ -770,7 +883,7 @@ int cellDmuxSetStream(u32 demuxerHandle, const u32 streamAddress, u32 streamSize cellDmux->Log("cellDmuxSetStream(demuxerHandle=%d, streamAddress=0x%x, streamSize=%d, discontinuity=%d, userData=0x%llx", demuxerHandle, streamAddress, streamSize, discontinuity, userData); - Demuxer* dmux; + std::shared_ptr dmux; if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux)) { return CELL_DMUX_ERROR_ARG; @@ -789,7 +902,7 @@ int cellDmuxSetStream(u32 demuxerHandle, const u32 streamAddress, u32 streamSize info.discontinuity = discontinuity; info.userdata = userData; - dmux->job.Push(task, &dmux->is_closed); + dmux->job.push(task, &dmux->is_closed); return CELL_OK; } @@ -797,13 +910,13 @@ int cellDmuxResetStream(u32 demuxerHandle) { cellDmux->Warning("cellDmuxResetStream(demuxerHandle=%d)", demuxerHandle); - Demuxer* dmux; + std::shared_ptr dmux; if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux)) { return CELL_DMUX_ERROR_ARG; } - dmux->job.Push(DemuxerTask(dmuxResetStream), &dmux->is_closed); + dmux->job.push(DemuxerTask(dmuxResetStream), &dmux->is_closed); return CELL_OK; } @@ -811,13 +924,13 @@ int cellDmuxResetStreamAndWaitDone(u32 demuxerHandle) { cellDmux->Warning("cellDmuxResetStreamAndWaitDone(demuxerHandle=%d)", demuxerHandle); - Demuxer* dmux; + std::shared_ptr dmux; if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux)) { return CELL_DMUX_ERROR_ARG; } - dmux->job.Push(DemuxerTask(dmuxResetStreamAndWaitDone), &dmux->is_closed); + dmux->job.push(DemuxerTask(dmuxResetStreamAndWaitDone), &dmux->is_closed); while (dmux->is_running && !dmux->is_closed) // TODO: ensure that it is safe { if (Emu.IsStopped()) @@ -825,7 +938,7 @@ int cellDmuxResetStreamAndWaitDone(u32 demuxerHandle) cellDmux->Warning("cellDmuxResetStreamAndWaitDone(%d) aborted", demuxerHandle); return CELL_OK; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } return CELL_OK; } @@ -870,7 +983,7 @@ int cellDmuxEnableEs(u32 demuxerHandle, vm::ptr esFil "esSpecificInfo_addr=0x%x, esHandle_addr=0x%x)", demuxerHandle, esFilterId.addr(), esResourceInfo.addr(), esCb.addr(), esSpecificInfo_addr, esHandle.addr()); - Demuxer* dmux; + std::shared_ptr dmux; if (!Emu.GetIdManager().GetIDData(demuxerHandle, dmux)) { return CELL_DMUX_ERROR_ARG; @@ -878,9 +991,9 @@ int cellDmuxEnableEs(u32 demuxerHandle, vm::ptr esFil // TODO: check esFilterId, esResourceInfo, esCb and esSpecificInfo correctly - ElementaryStream* es = new ElementaryStream(dmux, esResourceInfo->memAddr, esResourceInfo->memSize, + std::shared_ptr es(new ElementaryStream(dmux.get(), esResourceInfo->memAddr, esResourceInfo->memSize, esFilterId->filterIdMajor, esFilterId->filterIdMinor, esFilterId->supplementalInfo1, esFilterId->supplementalInfo2, - vm::ptr::make(esCb->cbEsMsgFunc.addr()), esCb->cbArg, esSpecificInfo_addr); + vm::ptr::make(esCb->cbEsMsgFunc.addr()), esCb->cbArg, esSpecificInfo_addr)); u32 id = cellDmux->GetNewId(es); es->id = id; @@ -891,9 +1004,9 @@ int cellDmuxEnableEs(u32 demuxerHandle, vm::ptr esFil DemuxerTask task(dmuxEnableEs); task.es.es = id; - task.es.es_ptr = es; + task.es.es_ptr = es.get(); - dmux->job.Push(task, &dmux->is_closed); + dmux->job.push(task, &dmux->is_closed); return CELL_OK; } @@ -901,7 +1014,7 @@ int cellDmuxDisableEs(u32 esHandle) { cellDmux->Warning("cellDmuxDisableEs(esHandle=0x%x)", esHandle); - ElementaryStream* es; + std::shared_ptr es; if (!Emu.GetIdManager().GetIDData(esHandle, es)) { return CELL_DMUX_ERROR_ARG; @@ -909,9 +1022,9 @@ int cellDmuxDisableEs(u32 esHandle) DemuxerTask task(dmuxDisableEs); task.es.es = esHandle; - task.es.es_ptr = es; + task.es.es_ptr = es.get(); - es->dmux->job.Push(task, &es->dmux->is_closed); + es->dmux->job.push(task, &es->dmux->is_closed); return CELL_OK; } @@ -919,7 +1032,7 @@ int cellDmuxResetEs(u32 esHandle) { cellDmux->Log("cellDmuxResetEs(esHandle=0x%x)", esHandle); - ElementaryStream* es; + std::shared_ptr es; if (!Emu.GetIdManager().GetIDData(esHandle, es)) { return CELL_DMUX_ERROR_ARG; @@ -927,9 +1040,9 @@ int cellDmuxResetEs(u32 esHandle) DemuxerTask task(dmuxResetEs); task.es.es = esHandle; - task.es.es_ptr = es; + task.es.es_ptr = es.get(); - es->dmux->job.Push(task, &es->dmux->is_closed); + es->dmux->job.push(task, &es->dmux->is_closed); return CELL_OK; } @@ -938,7 +1051,7 @@ int cellDmuxGetAu(u32 esHandle, vm::ptr auInfo_ptr, vm::ptr auSpecific cellDmux->Log("cellDmuxGetAu(esHandle=0x%x, auInfo_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)", esHandle, auInfo_ptr.addr(), auSpecificInfo_ptr.addr()); - ElementaryStream* es; + std::shared_ptr es; if (!Emu.GetIdManager().GetIDData(esHandle, es)) { return CELL_DMUX_ERROR_ARG; @@ -961,7 +1074,7 @@ int cellDmuxPeekAu(u32 esHandle, vm::ptr auInfo_ptr, vm::ptr auSpecifi cellDmux->Log("cellDmuxPeekAu(esHandle=0x%x, auInfo_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)", esHandle, auInfo_ptr.addr(), auSpecificInfo_ptr.addr()); - ElementaryStream* es; + std::shared_ptr es; if (!Emu.GetIdManager().GetIDData(esHandle, es)) { return CELL_DMUX_ERROR_ARG; @@ -984,7 +1097,7 @@ int cellDmuxGetAuEx(u32 esHandle, vm::ptr auInfoEx_ptr, vm::ptr auSpec cellDmux->Log("cellDmuxGetAuEx(esHandle=0x%x, auInfoEx_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)", esHandle, auInfoEx_ptr.addr(), auSpecificInfo_ptr.addr()); - ElementaryStream* es; + std::shared_ptr es; if (!Emu.GetIdManager().GetIDData(esHandle, es)) { return CELL_DMUX_ERROR_ARG; @@ -1007,7 +1120,7 @@ int cellDmuxPeekAuEx(u32 esHandle, vm::ptr auInfoEx_ptr, vm::ptr auSpe cellDmux->Log("cellDmuxPeekAuEx(esHandle=0x%x, auInfoEx_ptr_addr=0x%x, auSpecificInfo_ptr_addr=0x%x)", esHandle, auInfoEx_ptr.addr(), auSpecificInfo_ptr.addr()); - ElementaryStream* es; + std::shared_ptr es; if (!Emu.GetIdManager().GetIDData(esHandle, es)) { return CELL_DMUX_ERROR_ARG; @@ -1029,7 +1142,7 @@ int cellDmuxReleaseAu(u32 esHandle) { cellDmux->Log("cellDmuxReleaseAu(esHandle=0x%x)", esHandle); - ElementaryStream* es; + std::shared_ptr es; if (!Emu.GetIdManager().GetIDData(esHandle, es)) { return CELL_DMUX_ERROR_ARG; @@ -1046,7 +1159,7 @@ int cellDmuxFlushEs(u32 esHandle) { cellDmux->Warning("cellDmuxFlushEs(esHandle=0x%x)", esHandle); - ElementaryStream* es; + std::shared_ptr es; if (!Emu.GetIdManager().GetIDData(esHandle, es)) { return CELL_DMUX_ERROR_ARG; @@ -1054,9 +1167,9 @@ int cellDmuxFlushEs(u32 esHandle) DemuxerTask task(dmuxFlushEs); task.es.es = esHandle; - task.es.es_ptr = es; + task.es.es_ptr = es.get(); - es->dmux->job.Push(task, &es->dmux->is_closed); + es->dmux->job.push(task, &es->dmux->is_closed); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellDmux.h b/rpcs3/Emu/SysCalls/Modules/cellDmux.h index 5da9258bb0..6f0ed352b3 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellDmux.h +++ b/rpcs3/Emu/SysCalls/Modules/cellDmux.h @@ -1,7 +1,5 @@ #pragma once -#include "Utilities/SQueue.h" - // align size or address to 128 #define a128(x) ((x + 127) & (~127)) @@ -288,15 +286,8 @@ enum PACKET_START_CODE_MASK = 0xffffff00, PACKET_START_CODE_PREFIX = 0x00000100, - USER_DATA_START_CODE = 0x000001b2, - SEQUENCE_START_CODE = 0x000001b3, - EXT_START_CODE = 0x000001b5, - SEQUENCE_END_CODE = 0x000001b7, - GOP_START_CODE = 0x000001b8, - ISO_11172_END_CODE = 0x000001b9, PACK_START_CODE = 0x000001ba, SYSTEM_HEADER_START_CODE = 0x000001bb, - PROGRAM_STREAM_MAP = 0x000001bc, PRIVATE_STREAM_1 = 0x000001bd, PADDING_STREAM = 0x000001be, PRIVATE_STREAM_2 = 0x000001bf, @@ -336,6 +327,11 @@ struct DemuxerStream size = size > count ? size - count : 0; } + bool check(u32 count) const + { + return count <= size; + } + u64 get_ts(u8 c) { u8 v[4]; get((u32&)v); @@ -345,12 +341,6 @@ struct DemuxerStream (((u64)v[1] & 0x7e) << 15) | (((u64)v[2]) << 7) | ((u64)v[3] >> 1); } - - u64 get_ts() - { - u8 v; get(v); - return get_ts(v); - } }; struct PesHeader @@ -359,6 +349,7 @@ struct PesHeader u64 dts; u8 size; bool has_ts; + bool is_ok; PesHeader(DemuxerStream& stream); }; @@ -407,7 +398,7 @@ struct DemuxerTask class Demuxer { public: - SQueue job; + squeue_t job; const u32 memAddr; const u32 memSize; const vm::ptr cbFunc; @@ -436,7 +427,7 @@ class ElementaryStream { std::mutex m_mutex; - SQueue entries; // AU starting addresses + squeue_t entries; // AU starting addresses u32 put_count; // number of AU written u32 got_count; // number of AU obtained by GetAu(Ex) u32 released; // number of AU released @@ -446,6 +437,8 @@ class ElementaryStream bool is_full(u32 space); public: + ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr cbFunc, u32 cbArg, u32 spec); + Demuxer* dmux; u32 id; const u32 memAddr; @@ -465,27 +458,6 @@ public: void push(DemuxerStream& stream, u32 size); // called by demuxer thread (not multithread-safe) - ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr cbFunc, u32 cbArg, u32 spec) - : dmux(dmux) - , memAddr(a128(addr)) - , memSize(size - (addr - memAddr)) - , fidMajor(fidMajor) - , fidMinor(fidMinor) - , sup1(sup1) - , sup2(sup2) - , cbFunc(cbFunc) - , cbArg(cbArg) - , spec(spec) - , put(memAddr) - , put_count(0) - , got_count(0) - , released(0) - , raw_pos(0) - , last_dts(0xffffffffffffffffull) - , last_pts(0xffffffffffffffffull) - { - } - bool isfull(u32 space); void push_au(u32 size, u64 dts, u64 pts, u64 userdata, bool rap, u32 specific); diff --git a/rpcs3/Emu/SysCalls/Modules/cellFont.cpp b/rpcs3/Emu/SysCalls/Modules/cellFont.cpp index 59130605eb..0d709d6d39 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellFont.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellFont.cpp @@ -385,8 +385,7 @@ int cellFontGetEffectSlant(vm::ptr font, vm::ptr> slantPar int cellFontGetFontIdCode(vm::ptr font, u32 code, vm::ptr fontId, vm::ptr fontCode) { - cellFont->Todo("cellFontGetFontIdCode(font_addr=0x%x, code=0x%x, fontId_addr=0x%x, fontCode_addr=0x%x", - font.addr(), code, fontId.addr(), fontCode.addr()); + cellFont->Todo("cellFontGetFontIdCode(font_addr=0x%x, code=0x%x, fontId_addr=0x%x, fontCode_addr=0x%x)", font.addr(), code, fontId.addr(), fontCode.addr()); // TODO: ? return CELL_FONT_OK; @@ -406,8 +405,7 @@ int cellFontCloseFont(vm::ptr font) int cellFontGetCharGlyphMetrics(vm::ptr font, u32 code, vm::ptr metrics) { - cellFont->Log("cellFontGetCharGlyphMetrics(font_addr=0x%x, code=0x%x, metrics_addr=0x%x", - font.addr(), code, metrics.addr()); + cellFont->Log("cellFontGetCharGlyphMetrics(font_addr=0x%x, code=0x%x, metrics_addr=0x%x)", font.addr(), code, metrics.addr()); int x0, y0, x1, y1; int advanceWidth, leftSideBearing; diff --git a/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp b/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp index 2f6b5a5bd0..f91f4cb1c6 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp @@ -92,7 +92,7 @@ vm::ptr cellGcmGetReportDataAddressLocation(u32 index, u32 lo } if (location == CELL_GCM_LOCATION_MAIN) { - if (index >= 1024*1024) { + if (index >= 1024 * 1024) { cellGcmSys->Error("cellGcmGetReportDataAddressLocation: Wrong main index (%d)", index); return vm::ptr::make(0); } @@ -195,7 +195,7 @@ u64 cellGcmGetTimeStampLocation(u32 index, u32 location) } if (location == CELL_GCM_LOCATION_MAIN) { - if (index >= 1024*1024) { + if (index >= 1024 * 1024) { cellGcmSys->Error("cellGcmGetTimeStampLocation: Wrong main index (%d)", index); return 0; } @@ -300,7 +300,7 @@ u32 cellGcmGetTiledPitchSize(u32 size) { cellGcmSys->Log("cellGcmGetTiledPitchSize(size=%d)", size); - for (size_t i=0; i < sizeof(tiled_pitches)/sizeof(tiled_pitches[0]) - 1; i++) { + for (size_t i=0; i < sizeof(tiled_pitches) / sizeof(tiled_pitches[0]) - 1; i++) { if (tiled_pitches[i] < size && size <= tiled_pitches[i+1]) { return tiled_pitches[i+1]; } @@ -369,7 +369,7 @@ s32 _cellGcmInitBody(vm::ptr context, u32 cmdSize, u32 ioSiz u32 ctx_begin = ioAddress/* + 0x1000*/; u32 ctx_size = 0x6ffc; current_context.begin = ctx_begin; - current_context.end = ctx_begin + ctx_size; + current_context.end = ctx_begin + ctx_size - 4; current_context.current = current_context.begin; current_context.callback.set(be_t::make(Emu.GetRSXCallback() - 4)); @@ -805,8 +805,7 @@ s32 cellGcmAddressToOffset(u64 address, vm::ptr> offset) cellGcmSys->Log("cellGcmAddressToOffset(address=0x%x,offset_addr=0x%x)", address, offset.addr()); // Address not on main memory or local memory - if (!address || address >= 0xD0000000) { - cellGcmSys->Error("cellGcmAddressToOffset(address=0x%x,offset_addr=0x%x)", address, offset.addr()); + if (address >= 0xD0000000) { return CELL_GCM_ERROR_FAILURE; } @@ -1170,12 +1169,16 @@ s32 cellGcmCallback(vm::ptr context, u32 count) { cellGcmSys->Log("cellGcmCallback(context_addr=0x%x, count=0x%x)", context.addr(), count); - GSLockCurrent gslock(GS_LOCK_WAIT_FLUSH); - if (1) { auto& ctrl = vm::get_ref(gcm_info.control_addr); be_t res = be_t::make(context->current - context->begin - ctrl.put.read_relaxed()); + + if (res != 0) + { + GSLockCurrent gslock(GS_LOCK_WAIT_FLUSH); + } + memmove(vm::get_ptr(context->begin), vm::get_ptr(context->current - res), res); context->current = context->begin + res; diff --git a/rpcs3/Emu/SysCalls/Modules/cellGifDec.cpp b/rpcs3/Emu/SysCalls/Modules/cellGifDec.cpp index db9da02789..48f52fa422 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellGifDec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellGifDec.cpp @@ -4,7 +4,7 @@ #include "stblib/stb_image.h" #include "stblib/stb_image.c" // (TODO: Should we put this elsewhere?) -#include "Emu/SysCalls/lv2/lv2Fs.h" +#include "Emu/SysCalls/lv2/cellFs.h" #include "cellGifDec.h" Module *cellGifDec = nullptr; @@ -26,7 +26,7 @@ int cellGifDecOpen(u32 mainHandle, vm::ptr subHandle, vm::ptrWarning("cellGifDecOpen(mainHandle=0x%x, subHandle_addr=0x%x, src_addr=0x%x, openInfo_addr=0x%x)", mainHandle, subHandle.addr(), src.addr(), openInfo.addr()); - CellGifDecSubHandle *current_subHandle = new CellGifDecSubHandle; + std::shared_ptr current_subHandle(new CellGifDecSubHandle); current_subHandle->fd = 0; current_subHandle->src = *src; @@ -62,7 +62,7 @@ int cellGifDecReadHeader(u32 mainHandle, u32 subHandle, vm::ptr cellGifDec->Warning("cellGifDecReadHeader(mainHandle=0x%x, subHandle=0x%x, info_addr=0x%x)", mainHandle, subHandle, info.addr()); - CellGifDecSubHandle* subHandle_data; + std::shared_ptr subHandle_data; if(!cellGifDec->CheckId(subHandle, subHandle_data)) return CELL_GIFDEC_ERROR_FATAL; @@ -112,7 +112,7 @@ int cellGifDecSetParameter(u32 mainHandle, u32 subHandle, vm::ptrWarning("cellGifDecSetParameter(mainHandle=0x%x, subHandle=0x%x, inParam_addr=0x%x, outParam_addr=0x%x)", mainHandle, subHandle, inParam.addr(), outParam.addr()); - CellGifDecSubHandle* subHandle_data; + std::shared_ptr subHandle_data; if(!cellGifDec->CheckId(subHandle, subHandle_data)) return CELL_GIFDEC_ERROR_FATAL; @@ -144,7 +144,7 @@ int cellGifDecDecodeData(u32 mainHandle, u32 subHandle, vm::ptr data, vm::pt dataOutInfo->status = CELL_GIFDEC_DEC_STATUS_STOP; - CellGifDecSubHandle* subHandle_data; + std::shared_ptr subHandle_data; if(!cellGifDec->CheckId(subHandle, subHandle_data)) return CELL_GIFDEC_ERROR_FATAL; @@ -259,7 +259,7 @@ int cellGifDecClose(u32 mainHandle, u32 subHandle) cellGifDec->Warning("cellGifDecClose(mainHandle=0x%x, subHandle=0x%x)", mainHandle, subHandle); - CellGifDecSubHandle* subHandle_data; + std::shared_ptr subHandle_data; if(!cellGifDec->CheckId(subHandle, subHandle_data)) return CELL_GIFDEC_ERROR_FATAL; diff --git a/rpcs3/Emu/SysCalls/Modules/cellJpgDec.cpp b/rpcs3/Emu/SysCalls/Modules/cellJpgDec.cpp index 9ac73c1584..e907298dc8 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellJpgDec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellJpgDec.cpp @@ -3,7 +3,7 @@ #include "Emu/SysCalls/Modules.h" #include "stblib/stb_image.h" -#include "Emu/SysCalls/lv2/lv2Fs.h" +#include "Emu/SysCalls/lv2/cellFs.h" #include "cellJpgDec.h" Module *cellJpgDec = nullptr; @@ -31,7 +31,7 @@ int cellJpgDecOpen(u32 mainHandle, vm::ptr subHandle, vm::ptrWarning("cellJpgDecOpen(mainHandle=0x%x, subHandle_addr=0x%x, src_addr=0x%x, openInfo_addr=0x%x)", mainHandle, subHandle.addr(), src.addr(), openInfo.addr()); - CellJpgDecSubHandle *current_subHandle = new CellJpgDecSubHandle; + std::shared_ptr current_subHandle(new CellJpgDecSubHandle); current_subHandle->fd = 0; current_subHandle->src = *src; @@ -68,7 +68,7 @@ int cellJpgDecClose(u32 mainHandle, u32 subHandle) cellJpgDec->Warning("cellJpgDecOpen(mainHandle=0x%x, subHandle=0x%x)", mainHandle, subHandle); - CellJpgDecSubHandle* subHandle_data; + std::shared_ptr subHandle_data; if(!cellJpgDec->CheckId(subHandle, subHandle_data)) return CELL_JPGDEC_ERROR_FATAL; @@ -82,7 +82,7 @@ int cellJpgDecReadHeader(u32 mainHandle, u32 subHandle, vm::ptr { cellJpgDec->Log("cellJpgDecReadHeader(mainHandle=0x%x, subHandle=0x%x, info_addr=0x%x)", mainHandle, subHandle, info.addr()); - CellJpgDecSubHandle* subHandle_data; + std::shared_ptr subHandle_data; if(!cellJpgDec->CheckId(subHandle, subHandle_data)) return CELL_JPGDEC_ERROR_FATAL; @@ -151,7 +151,7 @@ int cellJpgDecDecodeData(u32 mainHandle, u32 subHandle, vm::ptr data, vm::pt mainHandle, subHandle, data.addr(), dataCtrlParam.addr(), dataOutInfo.addr()); dataOutInfo->status = CELL_JPGDEC_DEC_STATUS_STOP; - CellJpgDecSubHandle* subHandle_data; + std::shared_ptr subHandle_data; if(!cellJpgDec->CheckId(subHandle, subHandle_data)) return CELL_JPGDEC_ERROR_FATAL; @@ -281,7 +281,7 @@ int cellJpgDecSetParameter(u32 mainHandle, u32 subHandle, vm::ptrLog("cellJpgDecSetParameter(mainHandle=0x%x, subHandle=0x%x, inParam_addr=0x%x, outParam_addr=0x%x)", mainHandle, subHandle, inParam.addr(), outParam.addr()); - CellJpgDecSubHandle* subHandle_data; + std::shared_ptr subHandle_data; if(!cellJpgDec->CheckId(subHandle, subHandle_data)) return CELL_JPGDEC_ERROR_FATAL; diff --git a/rpcs3/cellMic.h b/rpcs3/Emu/SysCalls/Modules/cellMic.h similarity index 100% rename from rpcs3/cellMic.h rename to rpcs3/Emu/SysCalls/Modules/cellMic.h diff --git a/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.cpp b/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.cpp index bbda084de9..f6f7fefbbe 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.cpp @@ -32,29 +32,13 @@ MsgDialogProgressBarSetMsgCb MsgDialogProgressBarSetMsg = nullptr; MsgDialogProgressBarResetCb MsgDialogProgressBarReset = nullptr; MsgDialogProgressBarIncCb MsgDialogProgressBarInc = nullptr; -void SetMsgDialogCreateCallback(MsgDialogCreateCb cb) +void SetMsgDialogCallbacks(MsgDialogCreateCb ccb, MsgDialogDestroyCb dcb, MsgDialogProgressBarSetMsgCb pbscb, MsgDialogProgressBarResetCb pbrcb, MsgDialogProgressBarIncCb pbicb) { - MsgDialogCreate = cb; -} - -void SetMsgDialogDestroyCallback(MsgDialogDestroyCb cb) -{ - MsgDialogDestroy = cb; -} - -void SetMsgDialogProgressBarSetMsgCallback(MsgDialogProgressBarSetMsgCb cb) -{ - MsgDialogProgressBarSetMsg = cb; -} - -void SetMsgDialogProgressBarResetCallback(MsgDialogProgressBarResetCb cb) -{ - MsgDialogProgressBarReset = cb; -} - -void SetMsgDialogProgressBarIncCallback(MsgDialogProgressBarIncCb cb) -{ - MsgDialogProgressBarInc = cb; + MsgDialogCreate = ccb; + MsgDialogDestroy = dcb; + MsgDialogProgressBarSetMsg = pbscb; + MsgDialogProgressBarReset = pbrcb; + MsgDialogProgressBarInc = pbicb; } void MsgDialogClose() @@ -63,13 +47,64 @@ void MsgDialogClose() g_msg_dialog_wait_until = get_system_time(); } -int cellMsgDialogOpen2(u32 type, vm::ptr msgString, vm::ptr callback, u32 userData, u32 extParam) +s32 cellMsgDialogOpen2(u32 type, vm::ptr msgString, vm::ptr callback, u32 userData, u32 extParam) { cellSysutil->Warning("cellMsgDialogOpen2(type=0x%x, msgString_addr=0x%x, callback_addr=0x%x, userData=0x%x, extParam=0x%x)", type, msgString.addr(), callback.addr(), userData, extParam); - - //type |= CELL_MSGDIALOG_TYPE_PROGRESSBAR_SINGLE | CELL_MSGDIALOG_TYPE_BG_INVISIBLE; - //type |= CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO | CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR_NO; + + if (!msgString || strlen(msgString.get_ptr()) >= 0x200 || type & -0x33f8) + { + return CELL_MSGDIALOG_ERROR_PARAM; + } + + switch (type & CELL_MSGDIALOG_TYPE_BUTTON_TYPE) + { + case CELL_MSGDIALOG_TYPE_BUTTON_TYPE_NONE: + { + if (type & CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR) + { + return CELL_MSGDIALOG_ERROR_PARAM; + } + switch (type & CELL_MSGDIALOG_TYPE_PROGRESSBAR) + { + case CELL_MSGDIALOG_TYPE_PROGRESSBAR_NONE: break; + case CELL_MSGDIALOG_TYPE_PROGRESSBAR_SINGLE: break; + case CELL_MSGDIALOG_TYPE_PROGRESSBAR_DOUBLE: break; + default: return CELL_MSGDIALOG_ERROR_PARAM; + } + break; + } + + case CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO: + { + switch (type & CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR) + { + case CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR_YES: break; + case CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR_NO: break; + default: return CELL_MSGDIALOG_ERROR_PARAM; + } + if (type & CELL_MSGDIALOG_TYPE_PROGRESSBAR) + { + return CELL_MSGDIALOG_ERROR_PARAM; + } + break; + } + + case CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK: + { + if (type & CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR) + { + return CELL_MSGDIALOG_ERROR_PARAM; + } + if (type & CELL_MSGDIALOG_TYPE_PROGRESSBAR) + { + return CELL_MSGDIALOG_ERROR_PARAM; + } + break; + } + + default: return CELL_MSGDIALOG_ERROR_PARAM; + } MsgDialogState old = msgDialogNone; if (!g_msg_dialog_state.compare_exchange_strong(old, msgDialogOpen)) @@ -83,7 +118,7 @@ int cellMsgDialogOpen2(u32 type, vm::ptr msgString, vm::ptr msgString, vm::ptrWarning("MsgDialog thread aborted"); return; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } while (g_msg_dialog_state == msgDialogOpen || (s64)(get_system_time() - g_msg_dialog_wait_until) < 0) @@ -131,7 +166,7 @@ int cellMsgDialogOpen2(u32 type, vm::ptr msgString, vm::ptr msgString, vm::ptr callback, u32 userData, u32 extParam) +s32 cellMsgDialogOpenErrorCode(u32 errorCode, vm::ptr callback, u32 userData, u32 extParam) { cellSysutil->Warning("cellMsgDialogOpenErrorCode(errorCode=0x%x, callback_addr=0x%x, userData=0x%x, extParam=%d)", errorCode, callback.addr(), userData, extParam); @@ -174,15 +209,15 @@ int cellMsgDialogOpenErrorCode(u32 errorCode, vm::ptr cal case 0x80010007: errorMessage = "The file is in unrecognized format / The file is not a valid ELF file."; break; case 0x80010008: errorMessage = "Resource deadlock is avoided."; break; case 0x80010009: errorMessage = "Operation not permitted."; break; - case 0x8001000A: errorMessage = "The device or resource is bus."; break; - case 0x8001000B: errorMessage = "The operation is timed ou."; break; - case 0x8001000C: errorMessage = "The operation is aborte."; break; + case 0x8001000A: errorMessage = "The device or resource is busy."; break; + case 0x8001000B: errorMessage = "The operation is timed out."; break; + case 0x8001000C: errorMessage = "The operation is aborted."; break; case 0x8001000D: errorMessage = "Invalid memory access."; break; case 0x8001000F: errorMessage = "State of the target thread is invalid."; break; case 0x80010010: errorMessage = "Alignment is invalid."; break; case 0x80010011: errorMessage = "Shortage of the kernel resources."; break; case 0x80010012: errorMessage = "The file is a directory."; break; - case 0x80010013: errorMessage = "Operation canceled."; break; + case 0x80010013: errorMessage = "Operation cancelled."; break; case 0x80010014: errorMessage = "Entry already exists."; break; case 0x80010015: errorMessage = "Port is already connected."; break; case 0x80010016: errorMessage = "Port is not connected."; break; @@ -255,7 +290,7 @@ int cellMsgDialogOpenErrorCode(u32 errorCode, vm::ptr cal return CELL_OK; } -int cellMsgDialogClose(float delay) +s32 cellMsgDialogClose(float delay) { cellSysutil->Warning("cellMsgDialogClose(delay=%f)", delay); @@ -277,7 +312,7 @@ int cellMsgDialogClose(float delay) return CELL_OK; } -int cellMsgDialogAbort() +s32 cellMsgDialogAbort() { cellSysutil->Warning("cellMsgDialogAbort()"); @@ -298,7 +333,7 @@ int cellMsgDialogAbort() return CELL_OK; } -int cellMsgDialogProgressBarSetMsg(u32 progressBarIndex, vm::ptr msgString) +s32 cellMsgDialogProgressBarSetMsg(u32 progressBarIndex, vm::ptr msgString) { cellSysutil->Warning("cellMsgDialogProgressBarSetMsg(progressBarIndex=%d, msgString_addr=0x%x ['%s'])", progressBarIndex, msgString.addr(), msgString.get_ptr()); @@ -322,7 +357,7 @@ int cellMsgDialogProgressBarSetMsg(u32 progressBarIndex, vm::ptr msg return CELL_OK; } -int cellMsgDialogProgressBarReset(u32 progressBarIndex) +s32 cellMsgDialogProgressBarReset(u32 progressBarIndex) { cellSysutil->Warning("cellMsgDialogProgressBarReset(progressBarIndex=%d)", progressBarIndex); @@ -343,7 +378,7 @@ int cellMsgDialogProgressBarReset(u32 progressBarIndex) return CELL_OK; } -int cellMsgDialogProgressBarInc(u32 progressBarIndex, u32 delta) +s32 cellMsgDialogProgressBarInc(u32 progressBarIndex, u32 delta) { cellSysutil->Warning("cellMsgDialogProgressBarInc(progressBarIndex=%d, delta=%d)", progressBarIndex, delta); diff --git a/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.h b/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.h index 9c0b2eeb55..4b76eb975c 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.h +++ b/rpcs3/Emu/SysCalls/Modules/cellMsgDialog.h @@ -2,7 +2,7 @@ enum { - CELL_MSGDIALOG_ERROR_PARAM = 0x8002b301, + CELL_MSGDIALOG_ERROR_PARAM = 0x8002b301, CELL_MSGDIALOG_ERROR_DIALOG_NOT_OPENED = 0x8002b302, }; @@ -18,28 +18,28 @@ enum CellMsgDialogType enum { - CELL_MSGDIALOG_TYPE_SE_TYPE = 1 << 0, + CELL_MSGDIALOG_TYPE_SE_TYPE = 0x1, CELL_MSGDIALOG_TYPE_SE_TYPE_ERROR = 0 << 0, CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL = 1 << 0, }; enum { - CELL_MSGDIALOG_TYPE_SE_MUTE = 1 << 1, + CELL_MSGDIALOG_TYPE_SE_MUTE = 0x2, CELL_MSGDIALOG_TYPE_SE_MUTE_OFF = 0 << 1, CELL_MSGDIALOG_TYPE_SE_MUTE_ON = 1 << 1, }; enum { - CELL_MSGDIALOG_TYPE_BG = 1 << 2, + CELL_MSGDIALOG_TYPE_BG = 0x4, CELL_MSGDIALOG_TYPE_BG_VISIBLE = 0 << 2, CELL_MSGDIALOG_TYPE_BG_INVISIBLE = 1 << 2, }; enum { - CELL_MSGDIALOG_TYPE_BUTTON_TYPE = 3 << 4, + CELL_MSGDIALOG_TYPE_BUTTON_TYPE = 0x70, CELL_MSGDIALOG_TYPE_BUTTON_TYPE_NONE = 0 << 4, CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO = 1 << 4, CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK = 2 << 4, @@ -47,14 +47,14 @@ enum enum { - CELL_MSGDIALOG_TYPE_DISABLE_CANCEL = 1 << 7, + CELL_MSGDIALOG_TYPE_DISABLE_CANCEL = 0x80, CELL_MSGDIALOG_TYPE_DISABLE_CANCEL_OFF = 0 << 7, CELL_MSGDIALOG_TYPE_DISABLE_CANCEL_ON = 1 << 7, }; enum { - CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR = 1 << 8, + CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR = 0x300, CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR_NONE = 0 << 8, CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR_YES = 0 << 8, CELL_MSGDIALOG_TYPE_DEFAULT_CURSOR_NO = 1 << 8, @@ -63,7 +63,7 @@ enum enum { - CELL_MSGDIALOG_TYPE_PROGRESSBAR = 3 << 12, + CELL_MSGDIALOG_TYPE_PROGRESSBAR = 0x3000, CELL_MSGDIALOG_TYPE_PROGRESSBAR_NONE = 0 << 12, CELL_MSGDIALOG_TYPE_PROGRESSBAR_SINGLE = 1 << 12, CELL_MSGDIALOG_TYPE_PROGRESSBAR_DOUBLE = 2 << 12, @@ -81,14 +81,14 @@ enum typedef void(*CellMsgDialogCallback)(s32 buttonType, u32 userData); -int cellMsgDialogOpen2(u32 type, vm::ptr msgString, vm::ptr callback, u32 userData, u32 extParam); -int cellMsgDialogOpenErrorCode(u32 errorCode, vm::ptr callback, u32 userData, u32 extParam); +s32 cellMsgDialogOpen2(u32 type, vm::ptr msgString, vm::ptr callback, u32 userData, u32 extParam); +s32 cellMsgDialogOpenErrorCode(u32 errorCode, vm::ptr callback, u32 userData, u32 extParam); -int cellMsgDialogProgressBarSetMsg(u32 progressBarIndex, vm::ptr msgString); -int cellMsgDialogProgressBarReset(u32 progressBarIndex); -int cellMsgDialogProgressBarInc(u32 progressBarIndex, u32 delta); -int cellMsgDialogClose(float delay); -int cellMsgDialogAbort(); +s32 cellMsgDialogProgressBarSetMsg(u32 progressBarIndex, vm::ptr msgString); +s32 cellMsgDialogProgressBarReset(u32 progressBarIndex); +s32 cellMsgDialogProgressBarInc(u32 progressBarIndex, u32 delta); +s32 cellMsgDialogClose(float delay); +s32 cellMsgDialogAbort(); typedef void(*MsgDialogCreateCb)(u32 type, const char* msg, u64& status); typedef void(*MsgDialogDestroyCb)(); @@ -96,10 +96,5 @@ typedef void(*MsgDialogProgressBarSetMsgCb)(u32 progressBarIndex, const char* ms typedef void(*MsgDialogProgressBarResetCb)(u32 progressBarIndex); typedef void(*MsgDialogProgressBarIncCb)(u32 progressBarIndex, u32 delta); -void SetMsgDialogCreateCallback(MsgDialogCreateCb cb); -void SetMsgDialogDestroyCallback(MsgDialogDestroyCb cb); -void SetMsgDialogProgressBarSetMsgCallback(MsgDialogProgressBarSetMsgCb cb); -void SetMsgDialogProgressBarResetCallback(MsgDialogProgressBarResetCb cb); -void SetMsgDialogProgressBarIncCallback(MsgDialogProgressBarIncCb cb); - +void SetMsgDialogCallbacks(MsgDialogCreateCb ccb, MsgDialogDestroyCb dcb, MsgDialogProgressBarSetMsgCb pbscb, MsgDialogProgressBarResetCb pbrcb, MsgDialogProgressBarIncCb pbicb); void MsgDialogClose(); diff --git a/rpcs3/Emu/SysCalls/Modules/cellPad.cpp b/rpcs3/Emu/SysCalls/Modules/cellPad.cpp index 5bdc078089..29671843ef 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPad.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellPad.cpp @@ -54,16 +54,39 @@ int cellPadClearBuf(u32 port_no) return CELL_OK; } +int cellPadPeriphGetInfo(vm::ptr info) +{ + sys_io->Warning("cellPadPeriphGetInfo(info_addr=0x%x)", info.addr()); + + // TODO: Support other types of controllers + for (int i = 0; i < info->now_connect; i++) + { + info->pclass_type[i] = CELL_PAD_PCLASS_TYPE_STANDARD; + } + + return CELL_OK; +} + int cellPadGetData(u32 port_no, vm::ptr data) { sys_io->Log("cellPadGetData(port_no=%d, data_addr=0x%x)", port_no, data.addr()); std::vector& pads = Emu.GetPadManager().GetPads(); - if(!Emu.GetPadManager().IsInited()) return CELL_PAD_ERROR_UNINITIALIZED; + + if (!Emu.GetPadManager().IsInited()) { + return CELL_PAD_ERROR_UNINITIALIZED; + } + const PadInfo& rinfo = Emu.GetPadManager().GetInfo(); - if(port_no >= rinfo.max_connect) return CELL_PAD_ERROR_INVALID_PARAMETER; + + if (port_no >= rinfo.max_connect) { + return CELL_PAD_ERROR_INVALID_PARAMETER; + } + //We have a choice here of NO_DEVICE or READ_FAILED...lets try no device for now - if(port_no >= rinfo.now_connect) return CELL_PAD_ERROR_NO_DEVICE; + if (port_no >= rinfo.now_connect) { + return CELL_PAD_ERROR_NO_DEVICE; + } Pad& pad = pads[port_no]; @@ -409,6 +432,7 @@ void cellPad_init() sys_io->AddFunc(0xf65544ee, cellPadSetActDirect); sys_io->AddFunc(0x3aaad464, cellPadGetInfo); sys_io->AddFunc(0xa703a51d, cellPadGetInfo2); + sys_io->AddFunc(0x4cc9b68d, cellPadPeriphGetInfo); sys_io->AddFunc(0x578e3c98, cellPadSetPortSetting); sys_io->AddFunc(0x0e2dfaad, cellPadInfoPressMode); sys_io->AddFunc(0x78200559, cellPadInfoSensorMode); diff --git a/rpcs3/Emu/SysCalls/Modules/cellPad.h b/rpcs3/Emu/SysCalls/Modules/cellPad.h index 8b9f77ac40..c87a6c8dc5 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPad.h +++ b/rpcs3/Emu/SysCalls/Modules/cellPad.h @@ -14,6 +14,17 @@ enum CELL_PAD_ERROR_CODE CELL_PAD_ERROR_EBUSY = 0x8012110a, }; +// Controller types +enum +{ + CELL_PAD_PCLASS_TYPE_STANDARD = 0x00, + CELL_PAD_PCLASS_TYPE_GUITAR = 0x01, + CELL_PAD_PCLASS_TYPE_DRUM = 0x02, + CELL_PAD_PCLASS_TYPE_DJ = 0x03, + CELL_PAD_PCLASS_TYPE_DANCEMAT = 0x04, + CELL_PAD_PCLASS_TYPE_NAVIGATION = 0x05, +}; + struct CellPadData { be_t len; @@ -41,6 +52,19 @@ struct CellPadInfo2 be_t device_type[CELL_PAD_MAX_PORT_NUM]; }; +struct CellPadPeriphInfo +{ + be_t max_connect; + be_t now_connect; + be_t system_info; + be_t port_status[CELL_PAD_MAX_PORT_NUM]; + be_t port_setting[CELL_PAD_MAX_PORT_NUM]; + be_t device_capability[CELL_PAD_MAX_PORT_NUM]; + be_t device_type[CELL_PAD_MAX_PORT_NUM]; + be_t pclass_type[CELL_PAD_MAX_PORT_NUM]; + be_t pclass_profile[CELL_PAD_MAX_PORT_NUM]; +}; + struct CellCapabilityInfo { be_t info[CELL_PAD_MAX_CAPABILITY_INFO]; diff --git a/rpcs3/Emu/SysCalls/Modules/cellPamf.cpp b/rpcs3/Emu/SysCalls/Modules/cellPamf.cpp index 16a5064293..f768cd7001 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPamf.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellPamf.cpp @@ -1,157 +1,203 @@ #include "stdafx.h" #include "Emu/Memory/Memory.h" +#include "Emu/System.h" #include "Emu/SysCalls/Modules.h" #include "cellPamf.h" Module *cellPamf = nullptr; -int pamfStreamTypeToEsFilterId(u8 type, u8 ch, vm::ptr pEsFilterId) +s32 pamfStreamTypeToEsFilterId(u8 type, u8 ch, CellCodecEsFilterId& pEsFilterId) { - //TODO: convert type and ch to EsFilterId - pEsFilterId->filterIdMajor = 0; - pEsFilterId->filterIdMinor = 0; - pEsFilterId->supplementalInfo1 = 0; - pEsFilterId->supplementalInfo2 = 0; - + // convert type and ch to EsFilterId + assert(ch < 16); + pEsFilterId.supplementalInfo1 = type == CELL_PAMF_STREAM_TYPE_AVC; + pEsFilterId.supplementalInfo2 = 0; + switch (type) { case CELL_PAMF_STREAM_TYPE_AVC: - { - if (ch < 16) - { - pEsFilterId->filterIdMajor = 0xe0 + ch; - pEsFilterId->filterIdMinor = 0; - pEsFilterId->supplementalInfo1 = 0x01; - pEsFilterId->supplementalInfo2 = 0; - } - else - cellPamf->Error("pamfStreamTypeToEsFilterId: invalid CELL_PAMF_STREAM_TYPE_AVC channel (ch=%d)", ch); - } - break; - case CELL_PAMF_STREAM_TYPE_ATRAC3PLUS: - if (ch == 0) - { - pEsFilterId->filterIdMajor = 0xbd; - pEsFilterId->filterIdMinor = 0; - pEsFilterId->supplementalInfo1 = 0; - pEsFilterId->supplementalInfo2 = 0; - } - else - cellPamf->Todo("pamfStreamTypeToEsFilterId: CELL_PAMF_STREAM_TYPE_ATRAC3PLUS (ch=%d)", ch); - break; - case CELL_PAMF_STREAM_TYPE_PAMF_LPCM: - if (ch == 0) - { - pEsFilterId->filterIdMajor = 0xbd; - pEsFilterId->filterIdMinor = 0x40; - pEsFilterId->supplementalInfo1 = 0; - pEsFilterId->supplementalInfo2 = 0; - } - else - cellPamf->Todo("pamfStreamTypeToEsFilterId: CELL_PAMF_STREAM_TYPE_LPCM (ch=%d)", ch); - break; - case CELL_PAMF_STREAM_TYPE_USER_DATA: - if (ch == 0) - { - pEsFilterId->filterIdMajor = 0xbd; - pEsFilterId->filterIdMinor = 0x20; - pEsFilterId->supplementalInfo1 = 0; - pEsFilterId->supplementalInfo2 = 0; - } - else - cellPamf->Todo("pamfStreamTypeToEsFilterId: CELL_PAMF_STREAM_TYPE_USER_DATA (ch=%d)", ch); - break; - case CELL_PAMF_STREAM_TYPE_AC3: - cellPamf->Todo("pamfStreamTypeToEsFilterId: CELL_PAMF_STREAM_TYPE_AC3 (ch=%d)", ch); + { + // code = 0x1b + pEsFilterId.filterIdMajor = 0xe0 | ch; + pEsFilterId.filterIdMinor = 0; break; + } + case CELL_PAMF_STREAM_TYPE_M2V: - cellPamf->Todo("pamfStreamTypeToEsFilterId: CELL_PAMF_STREAM_TYPE_M2V (ch=%d)", ch); + { + // code = 0x02 + pEsFilterId.filterIdMajor = 0xe0 | ch; + pEsFilterId.filterIdMinor = 0; break; + } + + case CELL_PAMF_STREAM_TYPE_ATRAC3PLUS: + { + // code = 0xdc + pEsFilterId.filterIdMajor = 0xbd; + pEsFilterId.filterIdMinor = ch; + break; + } + + case CELL_PAMF_STREAM_TYPE_PAMF_LPCM: + { + // code = 0x80 + pEsFilterId.filterIdMajor = 0xbd; + pEsFilterId.filterIdMinor = 0x40 | ch; + break; + } + + case CELL_PAMF_STREAM_TYPE_AC3: + { + // code = 0x81 + pEsFilterId.filterIdMajor = 0xbd; + pEsFilterId.filterIdMinor = 0x30 | ch; + break; + } + + case CELL_PAMF_STREAM_TYPE_USER_DATA: + { + // code = 0xdd + pEsFilterId.filterIdMajor = 0xbd; + pEsFilterId.filterIdMinor = 0x20 | ch; + break; + } + + case 6: + { + // code = 0xff + pEsFilterId.filterIdMajor = 0xe0 | ch; + pEsFilterId.filterIdMinor = 0; + break; + } + + case 7: + { + // code = 0xff + pEsFilterId.filterIdMajor = 0xbd; + pEsFilterId.filterIdMinor = ch; + break; + } + + case 8: + { + // code = 0xff + pEsFilterId.filterIdMajor = 0xbd; + pEsFilterId.filterIdMinor = 0x10 | ch; + break; + } + + case 9: + { + // code = 0xff + pEsFilterId.filterIdMajor = 0xbd; + pEsFilterId.filterIdMinor = 0x20 | ch; + break; + } + default: + { + cellPamf->Error("pamfStreamTypeToEsFilterId(): unknown type (%d, ch=%d)", type, ch); + Emu.Pause(); return CELL_PAMF_ERROR_INVALID_ARG; } + } + return CELL_OK; } -u8 pamfGetStreamType(vm::ptr pSelf, u8 stream) +u8 pamfGetStreamType(vm::ptr pSelf, u32 stream) { - //TODO: get stream type correctly - switch (pSelf->pAddr->stream_headers[stream].type) + // TODO: get stream type correctly + assert(stream < (u32)pSelf->pAddr->stream_count); + auto& header = pSelf->pAddr->stream_headers[stream]; + + switch (header.type) { case 0x1b: return CELL_PAMF_STREAM_TYPE_AVC; + case 0x02: return CELL_PAMF_STREAM_TYPE_M2V; case 0xdc: return CELL_PAMF_STREAM_TYPE_ATRAC3PLUS; case 0x80: return CELL_PAMF_STREAM_TYPE_PAMF_LPCM; + case 0x81: return CELL_PAMF_STREAM_TYPE_AC3; case 0xdd: return CELL_PAMF_STREAM_TYPE_USER_DATA; - default: - cellPamf->Todo("pamfGetStreamType: unsupported stream type found(0x%x)", pSelf->pAddr->stream_headers[stream].type); - return 0; } + + cellPamf->Todo("pamfGetStreamType(): unsupported stream type found(0x%x)", header.type); + Emu.Pause(); + return 0xff; } -u8 pamfGetStreamChannel(vm::ptr pSelf, u8 stream) +u8 pamfGetStreamChannel(vm::ptr pSelf, u32 stream) { - //TODO: get stream channel correctly + // TODO: get stream channel correctly + assert(stream < (u32)pSelf->pAddr->stream_count); + auto& header = pSelf->pAddr->stream_headers[stream]; - switch (pSelf->pAddr->stream_headers[stream].type) + switch (header.type) { - case 0x1b: - if ((pSelf->pAddr->stream_headers[stream].stream_id >= 0xe0) && (pSelf->pAddr->stream_headers[stream].stream_id <= 0xef)) - { - return pSelf->pAddr->stream_headers[stream].stream_id - 0xe0; - } - else - { - cellPamf->Error("pamfGetStreamChannel: stream type 0x%x got invalid stream id=0x%x", - pSelf->pAddr->stream_headers[stream].type, pSelf->pAddr->stream_headers[stream].stream_id); - return 0; - } - case 0xdc: - cellPamf->Todo("pamfGetStreamChannel: CELL_PAMF_STREAM_TYPE_ATRAC3PLUS"); - return 0; - case 0x80: - cellPamf->Todo("pamfGetStreamChannel: CELL_PAMF_STREAM_TYPE_PAMF_LPCM"); - return 0; + case 0x1b: // AVC + case 0x02: // M2V + { + assert((header.fid_major & 0xf0) == 0xe0 && header.fid_minor == 0); + return header.fid_major % 16; + } + + case 0xdc: // ATRAC3PLUS + { + assert(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0); + return header.fid_minor % 16; + } + + case 0x80: // LPCM + { + assert(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0x40); + return header.fid_minor % 16; + } + case 0x81: // AC3 + { + assert(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0x30); + return header.fid_minor % 16; + } case 0xdd: - cellPamf->Todo("pamfGetStreamChannel: CELL_PAMF_STREAM_TYPE_USER_DATA"); - return 0; - default: - cellPamf->Todo("pamfGetStreamType: unsupported stream type found(0x%x)", pSelf->pAddr->stream_headers[stream].type); - return 0; + { + assert(header.fid_major == 0xbd && (header.fid_minor & 0xf0) == 0x20); + return header.fid_minor % 16; + } } + cellPamf->Todo("pamfGetStreamChannel(): unsupported stream type found(0x%x)", header.type); + Emu.Pause(); + return 0xff; } -int cellPamfGetHeaderSize(vm::ptr pAddr, u64 fileSize, vm::ptr pSize) +s32 cellPamfGetHeaderSize(vm::ptr pAddr, u64 fileSize, vm::ptr pSize) { cellPamf->Warning("cellPamfGetHeaderSize(pAddr=0x%x, fileSize=%d, pSize_addr=0x%x)", pAddr.addr(), fileSize, pSize.addr()); - //if ((u32)pAddr->magic != 0x464d4150) - //return CELL_PAMF_ERROR_UNKNOWN_TYPE; + //if ((u32)pAddr->magic != 0x464d4150) return CELL_PAMF_ERROR_UNKNOWN_TYPE; const u64 offset = (u64)pAddr->data_offset << 11; *pSize = offset; return CELL_OK; } -int cellPamfGetHeaderSize2(vm::ptr pAddr, u64 fileSize, u32 attribute, vm::ptr pSize) +s32 cellPamfGetHeaderSize2(vm::ptr pAddr, u64 fileSize, u32 attribute, vm::ptr pSize) { cellPamf->Warning("cellPamfGetHeaderSize2(pAddr=0x%x, fileSize=%d, attribute=0x%x, pSize_addr=0x%x)", pAddr.addr(), fileSize, attribute, pSize.addr()); - //if ((u32)pAddr->magic != 0x464d4150) - //return CELL_PAMF_ERROR_UNKNOWN_TYPE; + //if ((u32)pAddr->magic != 0x464d4150) return CELL_PAMF_ERROR_UNKNOWN_TYPE; const u64 offset = (u64)pAddr->data_offset << 11; *pSize = offset; return CELL_OK; } -int cellPamfGetStreamOffsetAndSize(vm::ptr pAddr, u64 fileSize, vm::ptr pOffset, vm::ptr pSize) +s32 cellPamfGetStreamOffsetAndSize(vm::ptr pAddr, u64 fileSize, vm::ptr pOffset, vm::ptr pSize) { cellPamf->Warning("cellPamfGetStreamOffsetAndSize(pAddr=0x%x, fileSize=%d, pOffset_addr=0x%x, pSize_addr=0x%x)", pAddr.addr(), fileSize, pOffset.addr(), pSize.addr()); - //if ((u32)pAddr->magic != 0x464d4150) - //return CELL_PAMF_ERROR_UNKNOWN_TYPE; + //if ((u32)pAddr->magic != 0x464d4150) return CELL_PAMF_ERROR_UNKNOWN_TYPE; const u64 offset = (u64)pAddr->data_offset << 11; *pOffset = offset; @@ -160,14 +206,15 @@ int cellPamfGetStreamOffsetAndSize(vm::ptr pAddr, u64 fileSize, vm:: return CELL_OK; } -int cellPamfVerify(vm::ptr pAddr, u64 fileSize) +s32 cellPamfVerify(vm::ptr pAddr, u64 fileSize) { - cellPamf->Warning("cellPamfVerify(pAddr=0x%x, fileSize=%d)", pAddr.addr(), fileSize); + cellPamf->Todo("cellPamfVerify(pAddr=0x%x, fileSize=%d)", pAddr.addr(), fileSize); + // TODO return CELL_OK; } -int cellPamfReaderInitialize(vm::ptr pSelf, vm::ptr pAddr, u64 fileSize, u32 attribute) +s32 cellPamfReaderInitialize(vm::ptr pSelf, vm::ptr pAddr, u64 fileSize, u32 attribute) { cellPamf->Warning("cellPamfReaderInitialize(pSelf=0x%x, pAddr=0x%x, fileSize=%d, attribute=0x%x)", pSelf.addr(), pAddr.addr(), fileSize, attribute); @@ -175,7 +222,7 @@ int cellPamfReaderInitialize(vm::ptr pSelf, vm::ptrfileSize = fileSize; } - else //if fileSize is unknown + else // if fileSize is unknown { pSelf->fileSize = ((u64)pAddr->data_offset << 11) + ((u64)pAddr->data_size << 11); } @@ -183,70 +230,59 @@ int cellPamfReaderInitialize(vm::ptr pSelf, vm::ptrTodo("cellPamfReaderInitialize(): verification"); } - pSelf->stream = 0; //??? currently set stream + pSelf->stream = 0; // currently set stream return CELL_OK; } -int cellPamfReaderGetPresentationStartTime(vm::ptr pSelf, vm::ptr pTimeStamp) +s32 cellPamfReaderGetPresentationStartTime(vm::ptr pSelf, vm::ptr pTimeStamp) { cellPamf->Warning("cellPamfReaderGetPresentationStartTime(pSelf=0x%x, pTimeStamp_addr=0x%x)", pSelf.addr(), pTimeStamp.addr()); - if (!pSelf->pAddr) { - return CELL_PAMF_ERROR_INVALID_PAMF; - } + // always returns CELL_OK pTimeStamp->upper = (u32)(u16)pSelf->pAddr->start_pts_high; pTimeStamp->lower = pSelf->pAddr->start_pts_low; return CELL_OK; } -int cellPamfReaderGetPresentationEndTime(vm::ptr pSelf, vm::ptr pTimeStamp) +s32 cellPamfReaderGetPresentationEndTime(vm::ptr pSelf, vm::ptr pTimeStamp) { cellPamf->Warning("cellPamfReaderGetPresentationEndTime(pSelf=0x%x, pTimeStamp_addr=0x%x)", pSelf.addr(), pTimeStamp.addr()); - if (!pSelf->pAddr) { - return CELL_PAMF_ERROR_INVALID_PAMF; - } + // always returns CELL_OK pTimeStamp->upper = (u32)(u16)pSelf->pAddr->end_pts_high; pTimeStamp->lower = pSelf->pAddr->end_pts_low; return CELL_OK; } -int cellPamfReaderGetMuxRateBound(vm::ptr pSelf) +u32 cellPamfReaderGetMuxRateBound(vm::ptr pSelf) { cellPamf->Warning("cellPamfReaderGetMuxRateBound(pSelf=0x%x)", pSelf.addr()); - if (!pSelf->pAddr) { - return CELL_PAMF_ERROR_INVALID_PAMF; - } - + // cannot return error code return pSelf->pAddr->mux_rate_max; } -int cellPamfReaderGetNumberOfStreams(vm::ptr pSelf) +u8 cellPamfReaderGetNumberOfStreams(vm::ptr pSelf) { cellPamf->Warning("cellPamfReaderGetNumberOfStreams(pSelf=0x%x)", pSelf.addr()); - if (!pSelf->pAddr) { - return CELL_PAMF_ERROR_INVALID_PAMF; - } - + // cannot return error code return pSelf->pAddr->stream_count; } -int cellPamfReaderGetNumberOfSpecificStreams(vm::ptr pSelf, u8 streamType) +u8 cellPamfReaderGetNumberOfSpecificStreams(vm::ptr pSelf, u8 streamType) { cellPamf->Warning("cellPamfReaderGetNumberOfSpecificStreams(pSelf=0x%x, streamType=%d)", pSelf.addr(), streamType); - if (!pSelf->pAddr) { - return CELL_PAMF_ERROR_INVALID_PAMF; - } + // cannot return error code - int counts[6] = {0, 0, 0, 0, 0, 0}; + u8 counts[256] = {}; for (u8 i = 0; i < pSelf->pAddr->stream_count; i++) { @@ -261,46 +297,48 @@ int cellPamfReaderGetNumberOfSpecificStreams(vm::ptr pSelf, u8 s case CELL_PAMF_STREAM_TYPE_PAMF_LPCM: case CELL_PAMF_STREAM_TYPE_AC3: case CELL_PAMF_STREAM_TYPE_USER_DATA: + { return counts[streamType]; - case CELL_PAMF_STREAM_TYPE_VIDEO: - return counts[CELL_PAMF_STREAM_TYPE_AVC] + counts[CELL_PAMF_STREAM_TYPE_M2V]; - case CELL_PAMF_STREAM_TYPE_AUDIO: - return counts[CELL_PAMF_STREAM_TYPE_ATRAC3PLUS] + counts[CELL_PAMF_STREAM_TYPE_PAMF_LPCM] + counts[CELL_PAMF_STREAM_TYPE_AC3]; - default: - return 0; } + + case CELL_PAMF_STREAM_TYPE_VIDEO: + { + return counts[CELL_PAMF_STREAM_TYPE_AVC] + counts[CELL_PAMF_STREAM_TYPE_M2V]; + } + + case CELL_PAMF_STREAM_TYPE_AUDIO: + { + return counts[CELL_PAMF_STREAM_TYPE_ATRAC3PLUS] + counts[CELL_PAMF_STREAM_TYPE_PAMF_LPCM] + counts[CELL_PAMF_STREAM_TYPE_AC3]; + } + } + + cellPamf->Todo("cellPamfReaderGetNumberOfSpecificStreams(): unsupported stream type (0x%x)", streamType); + Emu.Pause(); + return 0; } -int cellPamfReaderSetStreamWithIndex(vm::ptr pSelf, u8 streamIndex) +s32 cellPamfReaderSetStreamWithIndex(vm::ptr pSelf, u8 streamIndex) { cellPamf->Warning("cellPamfReaderSetStreamWithIndex(pSelf=0x%x, streamIndex=%d)", pSelf.addr(), streamIndex); - if (!pSelf->pAddr) { - return CELL_PAMF_ERROR_INVALID_PAMF; - } - - if (streamIndex < pSelf->pAddr->stream_count) + if (streamIndex >= pSelf->pAddr->stream_count) { - pSelf->stream = streamIndex; - return CELL_OK; + return CELL_PAMF_ERROR_INVALID_ARG; } - cellPamf->Error("cellPamfReaderSetStreamWithIndex: CELL_PAMF_ERROR_INVALID_ARG"); - return CELL_PAMF_ERROR_INVALID_ARG; + pSelf->stream = streamIndex; + return CELL_OK; } -int cellPamfReaderSetStreamWithTypeAndChannel(vm::ptr pSelf, u8 streamType, u8 ch) +s32 cellPamfReaderSetStreamWithTypeAndChannel(vm::ptr pSelf, u8 streamType, u8 ch) { cellPamf->Warning("cellPamfReaderSetStreamWithTypeAndChannel(pSelf=0x%x, streamType=%d, ch=%d)", pSelf.addr(), streamType, ch); - - if (!pSelf->pAddr) { - return CELL_PAMF_ERROR_INVALID_PAMF; - } - if (streamType > 5) + // it probably doesn't support "any audio" or "any video" argument + if (streamType > 5 || ch >= 16) { - cellPamf->Error("cellPamfReaderSetStreamWithTypeAndChannel: invalid stream type(%d)", streamType); - //it probably doesn't support "any audio" or "any video" argument + cellPamf->Error("cellPamfReaderSetStreamWithTypeAndChannel(): invalid arguments (streamType=%d, ch=%d)", streamType, ch); + Emu.Pause(); return CELL_PAMF_ERROR_INVALID_ARG; } @@ -319,14 +357,10 @@ int cellPamfReaderSetStreamWithTypeAndChannel(vm::ptr pSelf, u8 return CELL_PAMF_ERROR_STREAM_NOT_FOUND; } -int cellPamfReaderSetStreamWithTypeAndIndex(vm::ptr pSelf, u8 streamType, u8 streamIndex) +s32 cellPamfReaderSetStreamWithTypeAndIndex(vm::ptr pSelf, u8 streamType, u8 streamIndex) { cellPamf->Warning("cellPamfReaderSetStreamWithTypeAndIndex(pSelf=0x%x, streamType=%d, streamIndex=%d)", pSelf.addr(), streamType, streamIndex); - if (!pSelf->pAddr) { - return CELL_PAMF_ERROR_INVALID_PAMF; - } - u32 found = 0; for (u8 i = 0; i < pSelf->pAddr->stream_count; i++) @@ -340,23 +374,31 @@ int cellPamfReaderSetStreamWithTypeAndIndex(vm::ptr pSelf, u8 st else switch(streamType) { case CELL_PAMF_STREAM_TYPE_VIDEO: - if (type == CELL_PAMF_STREAM_TYPE_AVC || type == CELL_PAMF_STREAM_TYPE_M2V) + { + if (type == CELL_PAMF_STREAM_TYPE_AVC || type == CELL_PAMF_STREAM_TYPE_M2V) { found++; } break; + } + case CELL_PAMF_STREAM_TYPE_AUDIO: + { if (type == CELL_PAMF_STREAM_TYPE_ATRAC3PLUS || type == CELL_PAMF_STREAM_TYPE_AC3 || type == CELL_PAMF_STREAM_TYPE_PAMF_LPCM) { found++; } break; + } + default: + { if (streamType > 5) { return CELL_PAMF_ERROR_INVALID_ARG; } } + } if (found > streamIndex) { @@ -368,199 +410,328 @@ int cellPamfReaderSetStreamWithTypeAndIndex(vm::ptr pSelf, u8 st return CELL_PAMF_ERROR_STREAM_NOT_FOUND; } -int cellPamfStreamTypeToEsFilterId(u8 type, u8 ch, vm::ptr pEsFilterId) +s32 cellPamfStreamTypeToEsFilterId(u8 type, u8 ch, vm::ptr pEsFilterId) { cellPamf->Warning("cellPamfStreamTypeToEsFilterId(type=%d, ch=%d, pEsFilterId_addr=0x%x)", type, ch, pEsFilterId.addr()); + + if (!pEsFilterId) + { + return CELL_PAMF_ERROR_INVALID_ARG; + } - return pamfStreamTypeToEsFilterId(type, ch, pEsFilterId); + return pamfStreamTypeToEsFilterId(type, ch, *pEsFilterId); } -int cellPamfReaderGetStreamIndex(vm::ptr pSelf) +s32 cellPamfReaderGetStreamIndex(vm::ptr pSelf) { cellPamf->Log("cellPamfReaderGetStreamIndex(pSelf=0x%x)", pSelf.addr()); + // seems that CELL_PAMF_ERROR_INVALID_PAMF must be already written in pSelf->stream if it's the case return pSelf->stream; } -int cellPamfReaderGetStreamTypeAndChannel(vm::ptr pSelf, vm::ptr pType, vm::ptr pCh) +s32 cellPamfReaderGetStreamTypeAndChannel(vm::ptr pSelf, vm::ptr pType, vm::ptr pCh) { cellPamf->Warning("cellPamfReaderGetStreamTypeAndChannel(pSelf=0x%x (stream=%d), pType_addr=0x%x, pCh_addr=0x%x", pSelf.addr(), pSelf->stream, pType.addr(), pCh.addr()); + // unclear + *pType = pamfGetStreamType(pSelf, pSelf->stream); *pCh = pamfGetStreamChannel(pSelf, pSelf->stream); return CELL_OK; } -int cellPamfReaderGetEsFilterId(vm::ptr pSelf, vm::ptr pEsFilterId) +s32 cellPamfReaderGetEsFilterId(vm::ptr pSelf, vm::ptr pEsFilterId) { cellPamf->Warning("cellPamfReaderGetEsFilterId(pSelf=0x%x (stream=%d), pEsFilterId_addr=0x%x)", pSelf.addr(), pSelf->stream, pEsFilterId.addr()); - return pamfStreamTypeToEsFilterId(pamfGetStreamType(pSelf, pSelf->stream), - pamfGetStreamChannel(pSelf, pSelf->stream), pEsFilterId); + // always returns CELL_OK + + assert((u32)pSelf->stream < (u32)pSelf->pAddr->stream_count); + auto& header = pSelf->pAddr->stream_headers[pSelf->stream]; + pEsFilterId->filterIdMajor = header.fid_major; + pEsFilterId->filterIdMinor = header.fid_minor; + pEsFilterId->supplementalInfo1 = header.type == 0x1b ? 1 : 0; + pEsFilterId->supplementalInfo2 = 0; + return CELL_OK; } -int cellPamfReaderGetStreamInfo(vm::ptr pSelf, u32 pInfo_addr, u32 size) +s32 cellPamfReaderGetStreamInfo(vm::ptr pSelf, u32 pInfo_addr, u32 size) { cellPamf->Warning("cellPamfReaderGetStreamInfo(pSelf=0x%x, stream=%d, pInfo_addr=0x%x, size=%d)", pSelf.addr(), pSelf->stream, pInfo_addr, size); - if (!pSelf->pAddr) { - return CELL_PAMF_ERROR_INVALID_PAMF; - } + assert((u32)pSelf->stream < (u32)pSelf->pAddr->stream_count); + auto& header = pSelf->pAddr->stream_headers[pSelf->stream]; + const u8 type = pamfGetStreamType(pSelf, pSelf->stream); + const u8 ch = pamfGetStreamChannel(pSelf, pSelf->stream); - memset(vm::get_ptr(pInfo_addr), 0, size); - - switch (pamfGetStreamType(pSelf, pSelf->stream)) + switch (type) { case CELL_PAMF_STREAM_TYPE_AVC: + { + if (size < sizeof(CellPamfAvcInfo)) { - auto pInfo = vm::ptr::make(pInfo_addr); - auto pAVC = vm::ptr::make(pSelf->pAddr.addr() + 0x98 + pSelf->stream * 0x30); - - if (size != sizeof(CellPamfAvcInfo)) - { - cellPamf->Error("cellPamfReaderGetStreamInfo: wrong AVC data size(%d)", size); - return CELL_PAMF_ERROR_INVALID_ARG; - } - - pInfo->profileIdc = pAVC->profileIdc; - pInfo->levelIdc = pAVC->levelIdc; - - pInfo->frameMbsOnlyFlag = 1; //fake - pInfo->frameRateInfo = (pAVC->unk0 & 0x7) - 1; - pInfo->aspectRatioIdc = 1; //fake - - pInfo->horizontalSize = 16 * (u16)pAVC->horizontalSize; - pInfo->verticalSize = 16 * (u16)pAVC->verticalSize; - - pInfo->videoSignalInfoFlag = 1; //fake - pInfo->colourPrimaries = 1; //fake - pInfo->transferCharacteristics = 1; //fake - pInfo->matrixCoefficients = 1; //fake - //pInfo->deblockingFilterFlag = 1; //??? - - cellPamf->Warning("cellPamfReaderGetStreamInfo: CELL_PAMF_STREAM_TYPE_AVC"); - } - break; - case CELL_PAMF_STREAM_TYPE_M2V: - { - //TODO - cellPamf->Error("TODO: cellPamfReaderGetStreamInfo: CELL_PAMF_STREAM_TYPE_M2V"); - } - break; - case CELL_PAMF_STREAM_TYPE_ATRAC3PLUS: - { - auto pInfo = vm::ptr::make(pInfo_addr); - auto pAudio = vm::ptr::make(pSelf->pAddr.addr() + 0x98 + pSelf->stream * 0x30); - - if (size != sizeof(CellPamfAtrac3plusInfo)) - { - cellPamf->Error("cellPamfReaderGetStreamInfo: wrong ATRAC3+ data size(%d)", size); - return CELL_PAMF_ERROR_INVALID_ARG; - } - - pInfo->numberOfChannels = pAudio->channels; - pInfo->samplingFrequency = CELL_PAMF_FS_48kHz; - } - break; - case CELL_PAMF_STREAM_TYPE_AC3: - { - auto pInfo = vm::ptr::make(pInfo_addr); - auto pAudio = vm::ptr::make(pSelf->pAddr.addr() + 0x98 + pSelf->stream * 0x30); - - if (size != sizeof(CellPamfAc3Info)) - { - cellPamf->Error("cellPamfReaderGetStreamInfo: wrong AC3 data size(%d)", size); - return CELL_PAMF_ERROR_INVALID_ARG; - } - - pInfo->numberOfChannels = pAudio->channels; - pInfo->samplingFrequency = CELL_PAMF_FS_48kHz; - } - break; - case CELL_PAMF_STREAM_TYPE_PAMF_LPCM: - { - auto pInfo = vm::ptr::make(pInfo_addr); - auto pAudio = vm::ptr::make(pSelf->pAddr.addr() + 0x98 + pSelf->stream * 0x30); - - if (size != sizeof(CellPamfLpcmInfo)) - { - cellPamf->Error("cellPamfReaderGetStreamInfo: wrong LPCM data size(%d)", size); - return CELL_PAMF_ERROR_INVALID_ARG; - } - - pInfo->numberOfChannels = pAudio->channels; - pInfo->samplingFrequency = CELL_PAMF_FS_48kHz; - - if (pAudio->bps == 0x40) - pInfo->bitsPerSample = CELL_PAMF_BIT_LENGTH_16; - else - //TODO: CELL_PAMF_BIT_LENGTH_24 - cellPamf->Error("cellPamfReaderGetStreamInfo: unknown bps(0x%x)", (u8)pAudio->bps); - } - break; - case CELL_PAMF_STREAM_TYPE_USER_DATA: - { - cellPamf->Error("cellPamfReaderGetStreamInfo: CELL_PAMF_STREAM_TYPE_USER_DATA"); return CELL_PAMF_ERROR_INVALID_ARG; } + + auto info = vm::ptr::make(pInfo_addr); + + info->profileIdc = header.AVC.profileIdc; + info->levelIdc = header.AVC.levelIdc; + info->frameMbsOnlyFlag = (header.AVC.x2 & 0x80) >> 7; + info->videoSignalInfoFlag = (header.AVC.x2 & 0x40) >> 6; + info->frameRateInfo = (header.AVC.x2 & 0x0f) - 1; + info->aspectRatioIdc = header.AVC.aspectRatioIdc; + + if (header.AVC.aspectRatioIdc == 0xff) + { + info->sarWidth = header.AVC.sarWidth; + info->sarHeight = header.AVC.sarHeight; + } + else + { + info->sarWidth = 0; + info->sarHeight = 0; + } + + info->horizontalSize = ((u16)header.AVC.horizontalSize & 0xff) * 16; + info->verticalSize = ((u16)header.AVC.verticalSize & 0xff) * 16; + info->frameCropLeftOffset = header.AVC.frameCropLeftOffset; + info->frameCropRightOffset = header.AVC.frameCropRightOffset; + info->frameCropTopOffset = header.AVC.frameCropTopOffset; + info->frameCropBottomOffset = header.AVC.frameCropBottomOffset; + + if (info->videoSignalInfoFlag) + { + info->videoFormat = header.AVC.x14 >> 5; + info->videoFullRangeFlag = (header.AVC.x14 & 0x10) >> 4; + info->colourPrimaries = header.AVC.colourPrimaries; + info->transferCharacteristics = header.AVC.transferCharacteristics; + info->matrixCoefficients = header.AVC.matrixCoefficients; + } + else + { + info->videoFormat = 0; + info->videoFullRangeFlag = 0; + info->colourPrimaries = 0; + info->transferCharacteristics = 0; + info->matrixCoefficients = 0; + } + + info->entropyCodingModeFlag = (header.AVC.x18 & 0x80) >> 7; + info->deblockingFilterFlag = (header.AVC.x18 & 0x40) >> 6; + info->minNumSlicePerPictureIdc = (header.AVC.x18 & 0x30) >> 4; + info->nfwIdc = header.AVC.x18 & 0x03; + info->maxMeanBitrate = header.AVC.maxMeanBitrate; + + cellPamf->Notice("cellPamfReaderGetStreamInfo(): CELL_PAMF_STREAM_TYPE_AVC"); + break; + } + + case CELL_PAMF_STREAM_TYPE_M2V: + { + if (size < sizeof(CellPamfM2vInfo)) + { + return CELL_PAMF_ERROR_INVALID_ARG; + } + + auto info = vm::ptr::make(pInfo_addr); + + switch (header.M2V.x0) + { + case 0x44: info->profileAndLevelIndication = 3; break; + case 0x48: info->profileAndLevelIndication = 1; break; + default: info->profileAndLevelIndication = CELL_PAMF_M2V_UNKNOWN; + } + + info->progressiveSequence = (header.M2V.x2 & 0x80) >> 7; + info->videoSignalInfoFlag = (header.M2V.x2 & 0x40) >> 6; + info->frameRateInfo = header.M2V.x2 & 0xf; + info->aspectRatioIdc = header.M2V.aspectRatioIdc; + + if (header.M2V.aspectRatioIdc == 0xff) + { + info->sarWidth = header.M2V.sarWidth; + info->sarHeight = header.M2V.sarHeight; + } + else + { + info->sarWidth = 0; + info->sarHeight = 0; + } + + info->horizontalSize = ((u16)header.M2V.horizontalSize & 0xff) * 16; + info->verticalSize = ((u16)header.M2V.verticalSize & 0xff) * 16; + info->horizontalSizeValue = header.M2V.horizontalSizeValue; + info->verticalSizeValue = header.M2V.verticalSizeValue; + + if (info->videoSignalInfoFlag) + { + info->videoFormat = header.M2V.x14 >> 5; + info->videoFullRangeFlag = (header.M2V.x14 & 0x10) >> 4; + info->colourPrimaries = header.M2V.colourPrimaries; + info->transferCharacteristics = header.M2V.transferCharacteristics; + info->matrixCoefficients = header.M2V.matrixCoefficients; + } + else + { + info->videoFormat = 0; + info->videoFullRangeFlag = 0; + info->colourPrimaries = 0; + info->transferCharacteristics = 0; + info->matrixCoefficients = 0; + } + + cellPamf->Notice("cellPamfReaderGetStreamInfo(): CELL_PAMF_STREAM_TYPE_M2V"); + break; + } + + case CELL_PAMF_STREAM_TYPE_ATRAC3PLUS: + { + if (size < sizeof(CellPamfAtrac3plusInfo)) + { + return CELL_PAMF_ERROR_INVALID_ARG; + } + + auto info = vm::ptr::make(pInfo_addr); + + info->samplingFrequency = header.audio.freq & 0xf; + info->numberOfChannels = header.audio.channels & 0xf; + + cellPamf->Notice("cellPamfReaderGetStreamInfo(): CELL_PAMF_STREAM_TYPE_ATRAC3PLUS"); + break; + } + + case CELL_PAMF_STREAM_TYPE_PAMF_LPCM: + { + if (size < sizeof(CellPamfLpcmInfo)) + { + return CELL_PAMF_ERROR_INVALID_ARG; + } + + auto info = vm::ptr::make(pInfo_addr); + + info->samplingFrequency = header.audio.freq & 0xf; + info->numberOfChannels = header.audio.channels & 0xf; + info->bitsPerSample = header.audio.bps >> 6; + + cellPamf->Notice("cellPamfReaderGetStreamInfo(): CELL_PAMF_STREAM_TYPE_PAMF_LPCM"); + break; + } + + case CELL_PAMF_STREAM_TYPE_AC3: + { + if (size < sizeof(CellPamfAc3Info)) + { + return CELL_PAMF_ERROR_INVALID_ARG; + } + + auto info = vm::ptr::make(pInfo_addr); + + info->samplingFrequency = header.audio.freq & 0xf; + info->numberOfChannels = header.audio.channels & 0xf; + + cellPamf->Notice("cellPamfReaderGetStreamInfo(): CELL_PAMF_STREAM_TYPE_AC3"); + break; + } + + case CELL_PAMF_STREAM_TYPE_USER_DATA: + { + cellPamf->Error("cellPamfReaderGetStreamInfo(): invalid type CELL_PAMF_STREAM_TYPE_USER_DATA"); + return CELL_PAMF_ERROR_INVALID_ARG; + } + + case 6: + { + if (size < 4) + { + return CELL_PAMF_ERROR_INVALID_ARG; + } + + cellPamf->Todo("cellPamfReaderGetStreamInfo(): type 6"); + break; + } + + case 7: + { + if (size < 2) + { + return CELL_PAMF_ERROR_INVALID_ARG; + } + + cellPamf->Todo("cellPamfReaderGetStreamInfo(): type 7"); + break; + } + + case 8: + { + if (size < 2) + { + return CELL_PAMF_ERROR_INVALID_ARG; + } + + cellPamf->Todo("cellPamfReaderGetStreamInfo(): type 8"); + break; + } + + case 9: + { + cellPamf->Error("cellPamfReaderGetStreamInfo(): invalid type 9"); + return CELL_PAMF_ERROR_INVALID_ARG; + } + + default: + { + // invalid type or getting type/ch failed + cellPamf->Error("cellPamfReaderGetStreamInfo(): invalid type %d (ch=%d)", type, ch); + return CELL_PAMF_ERROR_INVALID_PAMF; + } } return CELL_OK; } -int cellPamfReaderGetNumberOfEp(vm::ptr pSelf) +u32 cellPamfReaderGetNumberOfEp(vm::ptr pSelf) { - cellPamf->Warning("cellPamfReaderGetNumberOfEp(pSelf=0x%x, stream=%d)", pSelf.addr(), pSelf->stream); + cellPamf->Todo("cellPamfReaderGetNumberOfEp(pSelf=0x%x, stream=%d)", pSelf.addr(), pSelf->stream); - if (!pSelf->pAddr) { - return CELL_PAMF_ERROR_INVALID_PAMF; - } - - return pSelf->pAddr->stream_headers[pSelf->stream].ep_num; + // cannot return error code + return 0; //pSelf->pAddr->stream_headers[pSelf->stream].ep_num; } -int cellPamfReaderGetEpIteratorWithIndex(vm::ptr pSelf, u32 epIndex, vm::ptr pIt) +s32 cellPamfReaderGetEpIteratorWithIndex(vm::ptr pSelf, u32 epIndex, vm::ptr pIt) { cellPamf->Todo("cellPamfReaderGetEpIteratorWithIndex(pSelf=0x%x, stream=%d, epIndex=%d, pIt_addr=0x%x)", pSelf.addr(), pSelf->stream, epIndex, pIt.addr()); - if (!pSelf->pAddr) { - return CELL_PAMF_ERROR_INVALID_PAMF; - } - - //TODO: + // TODO return CELL_OK; } -int cellPamfReaderGetEpIteratorWithTimeStamp(vm::ptr pSelf, vm::ptr pTimeStamp, vm::ptr pIt) +s32 cellPamfReaderGetEpIteratorWithTimeStamp(vm::ptr pSelf, vm::ptr pTimeStamp, vm::ptr pIt) { cellPamf->Todo("cellPamfReaderGetEpIteratorWithTimeStamp(pSelf=0x%x, pTimeStamp_addr=0x%x, pIt_addr=0x%x)", pSelf.addr(), pTimeStamp.addr(), pIt.addr()); - if (!pSelf->pAddr) { - return CELL_PAMF_ERROR_INVALID_PAMF; - } - - //TODO: - + // TODO return CELL_OK; } -int cellPamfEpIteratorGetEp(vm::ptr pIt, vm::ptr pEp) +s32 cellPamfEpIteratorGetEp(vm::ptr pIt, vm::ptr pEp) { cellPamf->Todo("cellPamfEpIteratorGetEp(pIt_addr=0x%x, pEp_addr=0x%x)", pIt.addr(), pEp.addr()); - //TODO: - + // always returns CELL_OK + // TODO return CELL_OK; } -int cellPamfEpIteratorMove(vm::ptr pIt, s32 steps, vm::ptr pEp) +s32 cellPamfEpIteratorMove(vm::ptr pIt, s32 steps, vm::ptr pEp) { cellPamf->Todo("cellPamfEpIteratorMove(pIt_addr=0x%x, steps=%d, pEp_addr=0x%x)", pIt.addr(), steps, pEp.addr()); - //TODO: - - return CELL_OK; + // cannot return error code + // TODO + return 0; } void cellPamf_init(Module *pxThis) diff --git a/rpcs3/Emu/SysCalls/Modules/cellPamf.h b/rpcs3/Emu/SysCalls/Modules/cellPamf.h index 639b02b662..33904beb97 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPamf.h +++ b/rpcs3/Emu/SysCalls/Modules/cellPamf.h @@ -141,6 +141,8 @@ struct CellCodecTimeStamp be_t lower; }; +static const u64 CODEC_TS_INVALID = 0xffffffffffffffffull; + // Entry point information struct CellPamfEp { @@ -168,37 +170,41 @@ struct CellCodecEsFilterId }; // AVC (MPEG4 AVC Video) Specific Information -struct CellPamfAvcInfo { +struct CellPamfAvcInfo +{ u8 profileIdc; u8 levelIdc; u8 frameMbsOnlyFlag; u8 videoSignalInfoFlag; u8 frameRateInfo; u8 aspectRatioIdc; - be_t sarWidth; //reserved - be_t sarHeight; //reserved + be_t sarWidth; + be_t sarHeight; be_t horizontalSize; be_t verticalSize; - be_t frameCropLeftOffset; //reserved - be_t frameCropRightOffset; //reserved - be_t frameCropTopOffset; //reserved - be_t frameCropBottomOffset; //!!!!! - u8 videoFormat; //reserved + be_t frameCropLeftOffset; + be_t frameCropRightOffset; + be_t frameCropTopOffset; + be_t frameCropBottomOffset; + u8 videoFormat; u8 videoFullRangeFlag; u8 colourPrimaries; u8 transferCharacteristics; u8 matrixCoefficients; - u8 entropyCodingModeFlag; //reserved + u8 entropyCodingModeFlag; u8 deblockingFilterFlag; - u8 minNumSlicePerPictureIdc; //reserved - u8 nfwIdc; //reserved - u8 maxMeanBitrate; //reserved + u8 minNumSlicePerPictureIdc; + u8 nfwIdc; + u8 maxMeanBitrate; }; +static_assert(sizeof(CellPamfAvcInfo) == 0x20, "Invalid CellPamfAvcInfo size"); + // M2V (MPEG2 Video) Specific Information -struct CellPamfM2vInfo { +struct CellPamfM2vInfo +{ u8 profileAndLevelIndication; - bool progressiveSequence; + u8 progressiveSequence; u8 videoSignalInfoFlag; u8 frameRateInfo; u8 aspectRatioIdc; @@ -215,76 +221,122 @@ struct CellPamfM2vInfo { u8 matrixCoefficients; }; +static_assert(sizeof(CellPamfM2vInfo) == 0x18, "Invalid CellPamfM2vInfo size"); + +// ATRAC3+ Audio Specific Information +struct CellPamfAtrac3plusInfo +{ + be_t samplingFrequency; + u8 numberOfChannels; +}; + +static_assert(sizeof(CellPamfAtrac3plusInfo) == 8, "Invalid CellPamfAtrac3plusInfo size"); + +// AC3 Audio Specific Information +struct CellPamfAc3Info +{ + be_t samplingFrequency; + u8 numberOfChannels; +}; + +static_assert(sizeof(CellPamfAc3Info) == 8, "Invalid CellPamfAc3Info size"); + // LPCM Audio Specific Information -struct CellPamfLpcmInfo { +struct CellPamfLpcmInfo +{ be_t samplingFrequency; u8 numberOfChannels; be_t bitsPerSample; }; -// ATRAC3+ Audio Specific Information -struct CellPamfAtrac3plusInfo { - be_t samplingFrequency; - u8 numberOfChannels; -}; -// AC3 Audio Specific Information -struct CellPamfAc3Info { - be_t samplingFrequency; - u8 numberOfChannels; -}; -#pragma pack(push, 1) //file data +#pragma pack(push, 1) // file data -struct PamfStreamHeader_AVC { //AVC specific information - u8 profileIdc; - u8 levelIdc; - u8 unk0; - u8 unk1; //1 - u32 unk2; //0 - be_t horizontalSize; //divided by 16 - be_t verticalSize; //divided by 16 - u32 unk3; //0 - u32 unk4; //0 - u8 unk5; //0xA0 - u8 unk6; //1 - u8 unk7; //1 - u8 unk8; //1 - u8 unk9; //0xB0 - u8 unk10; - u16 unk11; //0 - u32 unk12; //0 -}; - -struct PamfStreamHeader_M2V { //M2V specific information - u8 unknown[32]; //no information yet -}; - -struct PamfStreamHeader_Audio { //Audio specific information - u16 unknown; //== 0 - u8 channels; //number of channels (1, 2, 6 or 8) - u8 freq; //== 1 (always 48000) - u8 bps; //(LPCM only, 0x40 for 16 bit, ???? for 24) - u8 reserved[27]; //probably nothing -}; - -struct PamfStreamHeader //48 bytes +struct PamfStreamHeader { - //TODO: look for correct beginning of stream header - u8 type; //0x1B for video (AVC), 0xDC ATRAC3+, 0x80 LPCM, 0xDD userdata - u8 unknown[3]; //0 - //TODO: examine stream_ch encoding - u8 stream_id; - u8 private_stream_id; - u8 unknown1; //????? - u8 unknown2; //????? - //Entry Point Info - be_t ep_offset; //offset of EP section in header - be_t ep_num; //count of EPs - //Specific Info - u8 data[32]; + u8 type; + u8 unknown[3]; + u8 fid_major; + u8 fid_minor; + u8 unknown1; + u8 unknown2; + be_t ep_offset; // offset of EP section in header + be_t ep_num; // count of EPs + + union + { + u8 data[32]; // specific info + + // AVC specific information + struct + { + u8 profileIdc; + u8 levelIdc; + u8 x2; // contains frameMbsOnlyFlag, videoSignalInfoFlag, frameRateInfo + u8 aspectRatioIdc; + u32 x4; // 0 (not used) + be_t horizontalSize; // divided by 16 + be_t verticalSize; // divided by 16 + be_t frameCropLeftOffset; + be_t frameCropRightOffset; + be_t frameCropTopOffset; + be_t frameCropBottomOffset; + union + { + struct + { + be_t sarWidth; + be_t sarHeight; + }; + struct + { + u8 x14; // contains videoFormat and videoFullRangeFlag + u8 colourPrimaries; + u8 transferCharacteristics; + u8 matrixCoefficients; + }; + }; + u8 x18; // contains entropyCodingModeFlag, deblockingFilterFlag, minNumSlicePerPictureIdc, nfwIdc + u8 maxMeanBitrate; + + } AVC; + + // M2V specific information + struct + { + s8 x0; // contains profileAndLevelIndication + u8 x1; // not used + u8 x2; // contains progressiveSequence, videoSignalInfoFlag, frameRateInfo + u8 aspectRatioIdc; + be_t sarWidth; + be_t sarHeight; + be_t horizontalSize; + be_t verticalSize; + be_t horizontalSizeValue; + be_t verticalSizeValue; + u32 x10; // not used + u8 x14; // contains videoFormat and videoFullRangeFlag + u8 colourPrimaries; + u8 transferCharacteristics; + u8 matrixCoefficients; + + } M2V; + + // Audio specific information + struct + { + u16 unknown; // 0 + u8 channels; // number of channels (1, 2, 6, 8) + u8 freq; // 1 (always 48000) + u8 bps; // LPCM only + + } audio; + }; }; +static_assert(sizeof(PamfStreamHeader) == 48, "Invalid PamfStreamHeader size"); + struct PamfHeader { u32 magic; //"PAMF" @@ -317,21 +369,27 @@ struct PamfHeader PamfStreamHeader stream_headers[256]; }; -struct PamfEpHeader { //12 bytes +struct PamfEpHeader +{ be_t value0; //mixed indexN (probably left 2 bits) and nThRefPictureOffset be_t pts_high; be_t pts_low; be_t rpnOffset; }; +static_assert(sizeof(PamfEpHeader) == 12, "Invalid PamfEpHeader size"); + #pragma pack(pop) +// not directly accessed by virtual CPU, fields are unknown struct CellPamfReader { - //this struct can be used in any way, if it is not accessed directly by virtual CPU - //be_t internalData[16]; vm::ptr pAddr; - int stream; + s32 stream; u64 fileSize; u32 internalData[28]; -}; \ No newline at end of file +}; + +static_assert(sizeof(CellPamfReader) == 128, "Invalid CellPamfReader size"); + +s32 cellPamfReaderInitialize(vm::ptr pSelf, vm::ptr pAddr, u64 fileSize, u32 attribute); \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/Modules/cellPngDec.cpp b/rpcs3/Emu/SysCalls/Modules/cellPngDec.cpp index 05e88cd71e..973c1dff2b 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPngDec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellPngDec.cpp @@ -4,12 +4,14 @@ #include "Emu/SysCalls/Modules.h" #include "stblib/stb_image.h" -#include "Emu/SysCalls/lv2/lv2Fs.h" +#include "Emu/SysCalls/lv2/cellFs.h" #include "cellPngDec.h" #include Module *cellPngDec = nullptr; +#undef PRX_DEBUG + #ifdef PRX_DEBUG #include "prx_libpngdec.h" u32 libpngdec; @@ -75,13 +77,13 @@ s64 pngDecOpen( stream->fd = 0; stream->src = *src; - switch (src->srcSelect.ToLE()) + switch ((u32)src->srcSelect.ToBE()) { - case CELL_PNGDEC_BUFFER: + case se32(CELL_PNGDEC_BUFFER): stream->fileSize = src->streamSize.ToLE(); break; - case CELL_PNGDEC_FILE: + case se32(CELL_PNGDEC_FILE): // Get file descriptor vm::var> fd; int ret = cellFsOpen(vm::ptr::make(src->fileName.addr()), 0, fd, vm::ptr::make(0), 0); @@ -143,7 +145,7 @@ s64 pngReadHeader( auto buffer_32 = buffer.To>(); vm::var> pos, nread; - switch (stream->src.srcSelect.ToBE()) + switch ((u32)stream->src.srcSelect.ToBE()) { case se32(CELL_PNGDEC_BUFFER): memmove(buffer.begin(), stream->src.streamPtr.get_ptr(), buffer.size()); @@ -204,17 +206,21 @@ s64 pngDecSetParameter( current_outParam.outputHeight = current_info.imageHeight; current_outParam.outputColorSpace = inParam->outputColorSpace; - switch ((u32)current_outParam.outputColorSpace) + switch ((u32)current_outParam.outputColorSpace.ToBE()) { - case CELL_PNGDEC_PALETTE: - case CELL_PNGDEC_GRAYSCALE: current_outParam.outputComponents = 1; break; + case se32(CELL_PNGDEC_PALETTE): + case se32(CELL_PNGDEC_GRAYSCALE): + current_outParam.outputComponents = 1; break; - case CELL_PNGDEC_GRAYSCALE_ALPHA: current_outParam.outputComponents = 2; break; + case se32(CELL_PNGDEC_GRAYSCALE_ALPHA): + current_outParam.outputComponents = 2; break; - case CELL_PNGDEC_RGB: current_outParam.outputComponents = 3; break; + case se32(CELL_PNGDEC_RGB): + current_outParam.outputComponents = 3; break; - case CELL_PNGDEC_RGBA: - case CELL_PNGDEC_ARGB: current_outParam.outputComponents = 4; break; + case se32(CELL_PNGDEC_RGBA): + case se32(CELL_PNGDEC_ARGB): + current_outParam.outputComponents = 4; break; default: cellPngDec->Error("pngDecSetParameter: Unsupported color space (%d)", current_outParam.outputColorSpace.ToLE()); @@ -248,7 +254,7 @@ s64 pngDecodeData( vm::var png((u32)fileSize); vm::var> pos, nread; - switch (stream->src.srcSelect.ToBE()) + switch ((u32)stream->src.srcSelect.ToBE()) { case se32(CELL_PNGDEC_BUFFER): memmove(png.begin(), stream->src.streamPtr.get_ptr(), png.size()); @@ -277,10 +283,10 @@ s64 pngDecodeData( const int bytesPerLine = (u32)dataCtrlParam->outputBytesPerLine; uint image_size = width * height; - switch ((u32)current_outParam.outputColorSpace) + switch ((u32)current_outParam.outputColorSpace.ToBE()) { - case CELL_PNGDEC_RGB: - case CELL_PNGDEC_RGBA: + case se32(CELL_PNGDEC_RGB): + case se32(CELL_PNGDEC_RGBA): { const char nComponents = current_outParam.outputColorSpace == CELL_PNGDEC_RGBA ? 4 : 3; image_size *= nComponents; @@ -298,10 +304,10 @@ s64 pngDecodeData( { memcpy(data.get_ptr(), image.get(), image_size); } - } break; + } - case CELL_PNGDEC_ARGB: + case se32(CELL_PNGDEC_ARGB): { const int nComponents = 4; image_size *= nComponents; @@ -340,12 +346,12 @@ s64 pngDecodeData( memcpy(data.get_ptr(), img, image_size); delete[] img; } - } break; + } - case CELL_PNGDEC_GRAYSCALE: - case CELL_PNGDEC_PALETTE: - case CELL_PNGDEC_GRAYSCALE_ALPHA: + case se32(CELL_PNGDEC_GRAYSCALE): + case se32(CELL_PNGDEC_PALETTE): + case se32(CELL_PNGDEC_GRAYSCALE_ALPHA): cellPngDec->Error("pngDecodeData: Unsupported color space (%d)", current_outParam.outputColorSpace.ToLE()); break; diff --git a/rpcs3/Emu/SysCalls/Modules/cellSail.cpp b/rpcs3/Emu/SysCalls/Modules/cellSail.cpp index 3e22257a26..9e5ee1fc73 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSail.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSail.cpp @@ -1,8 +1,10 @@ #include "stdafx.h" #include "Emu/Memory/Memory.h" #include "Emu/SysCalls/Modules.h" +#include "Emu/FS/vfsFile.h" #include "cellSail.h" +#include "cellPamf.h" Module *cellSail = nullptr; @@ -11,6 +13,7 @@ int cellSailMemAllocatorInitialize(vm::ptr pSelf, vm::ptr< cellSail->Warning("cellSailMemAllocatorInitialize(pSelf_addr=0x%x, pCallbacks_addr=0x%x)", pSelf.addr(), pCallbacks.addr()); pSelf->callbacks = pCallbacks; + // TODO: Create a cellSail thread return CELL_OK; } @@ -71,7 +74,7 @@ int cellSailDescriptorGetMediaInfo() int cellSailDescriptorSetAutoSelection(vm::ptr pSelf, bool autoSelection) { - cellSail->Todo("cellSailDescriptorSetAutoSelection(pSelf_addr=0x%x, autoSelection=%s)", pSelf.addr(), autoSelection ? "true" : "false"); + cellSail->Warning("cellSailDescriptorSetAutoSelection(pSelf_addr=0x%x, autoSelection=%s)", pSelf.addr(), autoSelection ? "true" : "false"); if (pSelf) { pSelf->autoSelection = autoSelection; @@ -84,16 +87,29 @@ int cellSailDescriptorSetAutoSelection(vm::ptr pSelf, bool a int cellSailDescriptorIsAutoSelection(vm::ptr pSelf) { cellSail->Warning("cellSailDescriptorIsAutoSelection(pSelf_addr=0x%x)", pSelf.addr()); - + if (pSelf) return pSelf->autoSelection; return CELL_OK; } -int cellSailDescriptorCreateDatabase() +int cellSailDescriptorCreateDatabase(vm::ptr pSelf, vm::ptr pDatabase, be_t size, be_t arg) { - UNIMPLEMENTED_FUNC(cellSail); + cellSail->Warning("cellSailDescriptorCreateDatabase(pSelf=0x%x, pDatabase=0x%x, size=0x%x, arg=0x%x", pSelf.addr(), pDatabase.addr(), size, arg); + + switch ((s32)pSelf->streamType) { + case CELL_SAIL_STREAM_PAMF: + { + u32 addr = pSelf->internalData[1]; + auto ptr = vm::ptr::make(addr); + memcpy(pDatabase.get_ptr(), ptr.get_ptr(), sizeof(CellPamfReader)); + break; + } + default: + cellSail->Error("Unhandled stream type: %d", pSelf->streamType); + } + return CELL_OK; } @@ -616,23 +632,52 @@ int cellSailPlayerAddDescriptor(vm::ptr pSelf, vm::ptr pSelf, s32 streamType, vm::ptr pMediaInfo, vm::ptr pUri, vm::ptr ppDesc) +int cellSailPlayerCreateDescriptor(vm::ptr pSelf, s32 streamType, vm::ptr pMediaInfo, vm::ptr pUri, vm::ptr ppDesc) { - cellSail->Todo("cellSailPlayerCreateDescriptor(pSelf_addr=0x%x, streamType=%d, pMediaInfo_addr=0x%x, pUri_addr=0x%x, ppDesc_addr=0x%x)", pSelf.addr(), streamType, + cellSail->Warning("cellSailPlayerCreateDescriptor(pSelf_addr=0x%x, streamType=%d, pMediaInfo_addr=0x%x, pUri_addr=0x%x, ppDesc_addr=0x%x)", pSelf.addr(), streamType, pMediaInfo.addr(), pUri.addr(), ppDesc.addr()); - // TODO: Let the game allocate memory for the descriptor, setup the descriptor and pass it back to the game + u32 descriptorAddress = Memory.Alloc(sizeof(CellSailDescriptor), 1); + auto descriptor = vm::ptr::make(descriptorAddress); + *ppDesc = descriptorAddress; + descriptor->streamType = streamType; + descriptor->registered = false; - //CellSailDescriptor *pDesc = new CellSailDescriptor(); - //u32 descriptorAddress = pSelf->allocator->callbacks->pAlloc(pSelf->allocator->pArg, 4, descriptorAddress); - //cellSail->Error("Address: 0x%x", descriptorAddress); - //vm::ptr descriptor = vm::ptr::make(Memory.RealToVirtualAddr(&descriptorAddress)); - //descriptor->streamType = streamType; - //descriptor->registered = false; - - pSelf->descriptors = 0; + //pSelf->descriptors = 0; pSelf->repeatMode = 0; - //ppDesc = descriptor; + + switch (streamType) + { + case CELL_SAIL_STREAM_PAMF: + { + std::string uri = pUri.get_ptr(); + if (uri.substr(0, 12) == "x-cell-fs://") { + std::string path = uri.substr(12); + vfsFile f; + if (f.Open(path)) { + u64 size = f.GetSize(); + u32 buf_ = Memory.Alloc(size, 1); + auto bufPtr = vm::ptr::make(buf_); + PamfHeader *buf = const_cast(bufPtr.get_ptr()); + assert(f.Read(buf, size) == size); + u32 sp_ = Memory.Alloc(sizeof(CellPamfReader), 1); + auto sp = vm::ptr::make(sp_); + u32 r = cellPamfReaderInitialize(sp, bufPtr, size, 0); + + descriptor->internalData[0] = buf_; + descriptor->internalData[1] = sp_; + } + else + cellSail->Warning("Couldn't open PAMF: %s", uri.c_str()); + + } + else + cellSail->Warning("Unhandled uri: %s", uri.c_str()); + break; + } + default: + cellSail->Error("Unhandled stream type: %d", streamType); + } //cellSail->Todo("pSelf_addr=0x%x, pDesc_addr=0x%x", pSelf.addr(), descriptor.addr()); //cellSailPlayerAddDescriptor(pSelf, ppDesc); @@ -766,16 +811,16 @@ int cellSailPlayerCancel() return CELL_OK; } -int cellSailPlayerSetPaused() +int cellSailPlayerSetPaused(vm::ptr pSelf, bool paused) { - UNIMPLEMENTED_FUNC(cellSail); + cellSail->Todo("cellSailPlayerSetPaused(pSelf_addr=0x%x, paused=)", pSelf.addr(), paused); return CELL_OK; } -int cellSailPlayerIsPaused() +int cellSailPlayerIsPaused(vm::ptr pSelf) { - UNIMPLEMENTED_FUNC(cellSail); - return CELL_OK; + cellSail->Warning("cellSailPlayerIsPaused(pSelf_addr=0x%x)", pSelf.addr()); + return pSelf->paused; } int cellSailPlayerSetRepeatMode(vm::ptr pSelf, s32 repeatMode, vm::ptr pCommand) diff --git a/rpcs3/Emu/SysCalls/Modules/cellSail.h b/rpcs3/Emu/SysCalls/Modules/cellSail.h index 052133beaa..d0244fed6d 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSail.h +++ b/rpcs3/Emu/SysCalls/Modules/cellSail.h @@ -679,8 +679,8 @@ typedef void(*CellSailPlayerFuncNotified)(u32 pArg, vm::ptr event struct CellSailMemAllocatorFuncs { - CellSailMemAllocatorFuncAlloc pAlloc; - CellSailMemAllocatorFuncFree pFree; + vm::ptr pAlloc; + vm::ptr pFree; }; struct CellSailMemAllocator @@ -691,8 +691,8 @@ struct CellSailMemAllocator struct CellSailFuture { - u32 mutex_id; - u32 cond_id; + be_t mutex_id; + be_t cond_id; volatile be_t flags; be_t result; be_t userParam; @@ -1038,9 +1038,11 @@ struct CellSailDescriptor bool autoSelection; bool registered; be_t streamType; - be_t internalData[32]; + be_t internalData[31]; }; +static_assert(sizeof(CellSailDescriptor) == 0x100, "Invalid CellSailDescriptor size"); + struct CellSailStartCommand { be_t startType; @@ -1102,4 +1104,8 @@ struct CellSailPlayer be_t repeatMode; be_t descriptors; vm::ptr registeredDescriptors[2]; -}; \ No newline at end of file + bool paused = true; + be_t internalData[26]; +}; + +static_assert(sizeof(CellSailPlayer) == 0x100, "Invalid CellSailPlayer size"); \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp b/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp index de2d5307a3..58d0df01d0 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSaveData.cpp @@ -10,6 +10,14 @@ #include "Loader/PSF.h" #include "cellSaveData.h" +#ifdef _WIN32 + #include + #undef CreateFile +#else + #include + #include +#endif + extern Module *cellSysutil; // Auxiliary Classes @@ -39,7 +47,6 @@ public: } }; - // Auxiliary Functions u64 getSaveDataSize(const std::string& dirName) { @@ -69,6 +76,26 @@ void addSaveDataEntry(std::vector& saveEntries, const std::string std::string localPath; Emu.GetVFS().GetDevice(saveDir + "/ICON0.PNG", localPath); + u64 atime = 0; + u64 mtime = 0; + u64 ctime = 0; + + cellSysutil->Error("Running _stat in cellSaveData. Please report this to a RPCS3 developer!"); + + std::string real_path; + struct stat buf; + + Emu.GetVFS().GetDevice(f.GetPath(), real_path); + + if (stat(real_path.c_str(), &buf) != 0) + cellSysutil->Error("stat failed! (%s)", real_path.c_str()); + else + { + atime = buf.st_atime; + mtime = buf.st_mtime; + ctime = buf.st_ctime; + } + SaveDataEntry saveEntry; saveEntry.dirName = psf.GetString("SAVEDATA_DIRECTORY"); saveEntry.listParam = psf.GetString("SAVEDATA_LIST_PARAM"); @@ -76,9 +103,9 @@ void addSaveDataEntry(std::vector& saveEntries, const std::string saveEntry.subtitle = psf.GetString("SUB_TITLE"); saveEntry.details = psf.GetString("DETAIL"); saveEntry.sizeKB = (u32)(getSaveDataSize(saveDir) / 1024); - saveEntry.st_atime_ = 0; // TODO - saveEntry.st_mtime_ = 0; // TODO - saveEntry.st_ctime_ = 0; // TODO + saveEntry.st_atime_ = atime; + saveEntry.st_mtime_ = mtime; + saveEntry.st_ctime_ = ctime; saveEntry.iconBuf = NULL; // TODO: Here should be the PNG buffer saveEntry.iconBufSize = 0; // TODO: Size of the PNG file saveEntry.isNew = false; @@ -112,7 +139,7 @@ void setSaveDataList(std::vector& saveEntries, vm::ptrdirName == (char*)fixedList[j].dirName) { @@ -196,10 +223,15 @@ void getSaveDataStat(SaveDataEntry entry, vm::ptr statGet) CellSaveDataFileStat fileEntry; vfsFile file(saveDir + "/" + dirEntry->name); - if (dirEntry->name == "ICON0.PNG") fileEntry.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_ICON0; - if (dirEntry->name == "ICON1.PAM") fileEntry.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_ICON1; - if (dirEntry->name == "PIC1.PNG") fileEntry.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_PIC1; - if (dirEntry->name == "SND0.AT3") fileEntry.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_SND0; + if (dirEntry->name == "ICON0.PNG") + fileEntry.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_ICON0; + else if (dirEntry->name == "ICON1.PAM") + fileEntry.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_ICON1; + else if (dirEntry->name == "PIC1.PNG") + fileEntry.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_PIC1; + else if (dirEntry->name == "SND0.AT3") + fileEntry.fileType = CELL_SAVEDATA_FILETYPE_CONTENT_SND0; + fileEntry.st_size = file.GetSize(); fileEntry.st_atime_ = 0; // TODO ? fileEntry.st_mtime_ = 0; // TODO ? @@ -210,9 +242,11 @@ void getSaveDataStat(SaveDataEntry entry, vm::ptr statGet) } } - statGet->fileList = vm::bptr::make(be_t::make((u32)Memory.Alloc(sizeof(CellSaveDataFileStat) * (u32)fileEntries.size(), sizeof(CellSaveDataFileStat)))); - for (u32 i=0; ifileList[i], &fileEntries[i], sizeof(CellSaveDataFileStat)); + statGet->fileList = vm::ptr::make((u32)Memory.Alloc(sizeof(CellSaveDataFileStat) * fileEntries.size(), 8)); + for (u32 i = 0; i < fileEntries.size(); i++) { + CellSaveDataFileStat *dst = &statGet->fileList[i]; + memcpy(dst, &fileEntries[i], sizeof(CellSaveDataFileStat)); + } } s32 modifySaveDataFiles(vm::ptr funcFile, vm::ptr result, const std::string& saveDataDir) @@ -231,7 +265,7 @@ s32 modifySaveDataFiles(vm::ptr funcFile, vm::ptrError("modifySaveDataFiles: CellSaveDataFileCallback failed."); // TODO: Once we verify that the entire SysCall is working, delete this debug error message. return CELL_SAVEDATA_ERROR_CBRESULT; } - if (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST) { + if (result->result == CELL_SAVEDATA_CBRESULT_OK_LAST || result->result == CELL_SAVEDATA_CBRESULT_OK_LAST_NOCONFIRM) { break; } @@ -637,7 +671,9 @@ int cellSaveDataAutoSave2(u32 version, vm::ptr dirName, u32 errDialo result->userdata = userdata; funcStat(result, statGet, statSet); - Memory.Free(statGet->fileList.addr()); + if (statGet->fileList) + Memory.Free(statGet->fileList.addr()); + if (result->result < 0) { cellSysutil->Error("cellSaveDataAutoSave2: CellSaveDataStatCallback failed."); // TODO: Once we verify that the entire SysCall is working, delete this debug error message. return CELL_SAVEDATA_ERROR_CBRESULT; diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp b/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp index 343ca9ecbb..10c2348d4b 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSpurs.cpp @@ -3,8 +3,13 @@ #include "Emu/System.h" #include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/CB_FUNC.h" +#include "Emu/Memory/atomic_type.h" #include "Emu/Cell/SPUThread.h" +#include "Emu/SysCalls/lv2/sleep_queue_type.h" +#include "Emu/SysCalls/lv2/sys_lwmutex.h" +#include "Emu/SysCalls/lv2/sys_lwcond.h" +#include "Emu/SysCalls/lv2/sys_spu.h" #include "Emu/SysCalls/lv2/sys_ppu_thread.h" #include "Emu/SysCalls/lv2/sys_memory.h" #include "Emu/SysCalls/lv2/sys_process.h" @@ -251,13 +256,13 @@ s64 spursInit( if (spurs->m.flags1 & SF1_EXIT_IF_NO_WORK) { - if (s32 res = sys_lwmutex_lock(spurs->get_lwmutex(), 0)) + if (s32 res = sys_lwmutex_lock(CPU, spurs->get_lwmutex(), 0)) { assert(!"sys_lwmutex_lock() failed"); } if (spurs->m.xD66.read_relaxed()) { - if (s32 res = sys_lwmutex_unlock(spurs->get_lwmutex())) + if (s32 res = sys_lwmutex_unlock(CPU, spurs->get_lwmutex())) { assert(!"sys_lwmutex_unlock() failed"); } @@ -265,6 +270,8 @@ s64 spursInit( } else while (true) { + if (Emu.IsStopped()) break; + spurs->m.xD64.exchange(0); if (spurs->m.exception.ToBE() == 0) { @@ -311,7 +318,7 @@ s64 spursInit( spurs->m.xD65.exchange(1); if (spurs->m.xD64.read_relaxed() == 0) { - if (s32 res = sys_lwcond_wait(spurs->get_lwcond(), 0)) + if (s32 res = sys_lwcond_wait(CPU, spurs->get_lwcond(), 0)) { assert(!"sys_lwcond_wait() failed"); } @@ -319,14 +326,17 @@ s64 spursInit( spurs->m.xD65.exchange(0); if (spurs->m.xD66.read_relaxed()) { - if (s32 res = sys_lwmutex_unlock(spurs->get_lwmutex())) + if (s32 res = sys_lwmutex_unlock(CPU, spurs->get_lwmutex())) { assert(!"sys_lwmutex_unlock() failed"); } return; } } - if (s32 res = sys_lwmutex_unlock(spurs->get_lwmutex())) + + if (Emu.IsStopped()) continue; + + if (s32 res = sys_lwmutex_unlock(CPU, spurs->get_lwmutex())) { assert(!"sys_lwmutex_unlock() failed"); } @@ -393,7 +403,7 @@ s64 spursInit( } else if (flags & SAF_EXIT_IF_NO_WORK) // wakeup { - return spursWakeUp(spurs); + return spursWakeUp(GetCurrentPPUThread(), spurs); } return CELL_OK; @@ -953,7 +963,7 @@ s64 cellSpursGetInfo(vm::ptr spurs, vm::ptr info) #endif } -s64 spursWakeUp(vm::ptr spurs) +s64 spursWakeUp(PPUThread& CPU, vm::ptr spurs) { #ifdef PRX_DEBUG_XXX return cb_call>(GetCurrentPPUThread(), libsre + 0x84D8, libsre_rtoc, spurs); @@ -975,7 +985,7 @@ s64 spursWakeUp(vm::ptr spurs) spurs->m.xD64.exchange(1); if (spurs->m.xD65.read_sync()) { - if (s32 res = sys_lwmutex_lock(spurs->get_lwmutex(), 0)) + if (s32 res = sys_lwmutex_lock(CPU, spurs->get_lwmutex(), 0)) { assert(!"sys_lwmutex_lock() failed"); } @@ -983,7 +993,7 @@ s64 spursWakeUp(vm::ptr spurs) { assert(!"sys_lwcond_signal() failed"); } - if (s32 res = sys_lwmutex_unlock(spurs->get_lwmutex())) + if (s32 res = sys_lwmutex_unlock(CPU, spurs->get_lwmutex())) { assert(!"sys_lwmutex_unlock() failed"); } @@ -991,11 +1001,11 @@ s64 spursWakeUp(vm::ptr spurs) return CELL_OK; } -s64 cellSpursWakeUp(vm::ptr spurs) +s64 cellSpursWakeUp(PPUThread& CPU, vm::ptr spurs) { cellSpurs->Warning("%s(spurs_addr=0x%x)", __FUNCTION__, spurs.addr()); - return spursWakeUp(spurs); + return spursWakeUp(CPU, spurs); } s32 spursAddWorkload( @@ -2509,7 +2519,7 @@ s64 _cellSpursTaskAttribute2Initialize(vm::ptr attribut #else attribute->revision = revision; attribute->sizeContext = 0; - attribute->eaContext = NULL; + attribute->eaContext = 0; for (s32 c = 0; c < 4; c++) { diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpurs.h b/rpcs3/Emu/SysCalls/Modules/cellSpurs.h index 771406b3af..dab014f898 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpurs.h +++ b/rpcs3/Emu/SysCalls/Modules/cellSpurs.h @@ -1,7 +1,4 @@ #pragma once -#include "Emu/SysCalls/lv2/sys_lwmutex.h" -#include "Emu/SysCalls/lv2/sys_lwcond.h" -#include "Emu/SysCalls/lv2/sys_spu.h" // Core return codes. enum @@ -820,4 +817,4 @@ struct SpursKernelMgmtData { }; s64 spursAttachLv2EventQueue(vm::ptr spurs, u32 queue, vm::ptr port, s32 isDynamic, bool wasCreated); -s64 spursWakeUp(vm::ptr spurs); +s64 spursWakeUp(PPUThread& CPU, vm::ptr spurs); diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpursJq.cpp b/rpcs3/Emu/SysCalls/Modules/cellSpursJq.cpp index c1ad643060..e15c8be5f6 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpursJq.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSpursJq.cpp @@ -2,7 +2,12 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/SysCalls/Modules.h" +#include "Emu/Memory/atomic_type.h" +#include "Emu/SysCalls/lv2/sleep_queue_type.h" +#include "Emu/SysCalls/lv2/sys_lwmutex.h" +#include "Emu/SysCalls/lv2/sys_lwcond.h" +#include "Emu/SysCalls/lv2/sys_spu.h" #include "cellSpurs.h" #include "cellSpursJq.h" diff --git a/rpcs3/Emu/SysCalls/Modules/cellSpursSpu.cpp b/rpcs3/Emu/SysCalls/Modules/cellSpursSpu.cpp index 643aed981c..2d696666aa 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSpursSpu.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSpursSpu.cpp @@ -3,6 +3,9 @@ #include "Emu/System.h" #include "Emu/Cell/SPUThread.h" #include "Emu/SysCalls/Modules.h" +#include "Emu/SysCalls/lv2/sys_lwmutex.h" +#include "Emu/SysCalls/lv2/sys_lwcond.h" +#include "Emu/SysCalls/lv2/sys_spu.h" #include "Emu/SysCalls/Modules/cellSpurs.h" // diff --git a/rpcs3/Emu/SysCalls/Modules/cellSubdisplay.cpp b/rpcs3/Emu/SysCalls/Modules/cellSubdisplay.cpp index ff0612316b..98f71097f4 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSubdisplay.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSubdisplay.cpp @@ -1,21 +1,10 @@ #include "stdafx.h" -#if 0 +#include "Emu/Memory/Memory.h" +#include "Emu/SysCalls/Modules.h" -void cellSubdisplay_init(); -Module cellSubdisplay(0x0034, cellSubdisplay_init); +#include "cellSubdisplay.h" -// Return Codes -enum -{ - CELL_SUBDISPLAY_ERROR_OUT_OF_MEMORY = 0x80029851, - CELL_SUBDISPLAY_ERROR_FATAL = 0x80029852, - CELL_SUBDISPLAY_ERROR_NOT_FOUND = 0x80029853, - CELL_SUBDISPLAY_ERROR_INVALID_VALUE = 0x80029854, - CELL_SUBDISPLAY_ERROR_NOT_INITIALIZED = 0x80029855, - CELL_SUBDISPLAY_ERROR_SET_SAMPLE = 0x80029860, - CELL_SUBDISPLAY_ERROR_AUDIOOUT_IS_BUSY = 0x80029861, - CELL_SUBDISPLAY_ERROR_ZERO_REGISTERED = 0x80029813, -}; +Module *cellSubdisplay = nullptr; int cellSubDisplayInit() { @@ -29,10 +18,18 @@ int cellSubDisplayEnd() return CELL_OK; } -int cellSubDisplayGetRequiredMemory() +int cellSubDisplayGetRequiredMemory(vm::ptr pParam) { - UNIMPLEMENTED_FUNC(cellSubdisplay); - return CELL_OK; + cellSubdisplay->Warning("cellSubDisplayGetRequiredMemory(pParam_addr=0x%x)", pParam.addr()); + + if (pParam->version == CELL_SUBDISPLAY_VERSION_0002) + { + return CELL_SUBDISPLAY_0002_MEMORY_CONTAINER_SIZE; + } + else + { + return CELL_SUBDISPLAY_0001_MEMORY_CONTAINER_SIZE; + } } int cellSubDisplayStart() @@ -77,19 +74,20 @@ int cellSubDisplayGetPeerList() return CELL_OK; } -void cellSubdisplay_init() +void cellSubdisplay_init(Module *pxThis) { - cellSubdisplay.AddFunc(0xf9a7e8a5, cellSubDisplayInit); - cellSubdisplay.AddFunc(0x551d80a5, cellSubDisplayEnd); - cellSubdisplay.AddFunc(0x6595ce22, cellSubDisplayGetRequiredMemory); - cellSubdisplay.AddFunc(0xa5bccb47, cellSubDisplayStart); - cellSubdisplay.AddFunc(0x6d85ddb3, cellSubDisplayStop); + cellSubdisplay = pxThis; - cellSubdisplay.AddFunc(0x938ac642, cellSubDisplayGetVideoBuffer); - cellSubdisplay.AddFunc(0xaee1e0c2, cellSubDisplayAudioOutBlocking); - cellSubdisplay.AddFunc(0x5468d6b0, cellSubDisplayAudioOutNonBlocking); + cellSubdisplay->AddFunc(0xf9a7e8a5, cellSubDisplayInit); + cellSubdisplay->AddFunc(0x551d80a5, cellSubDisplayEnd); + cellSubdisplay->AddFunc(0x6595ce22, cellSubDisplayGetRequiredMemory); + cellSubdisplay->AddFunc(0xa5bccb47, cellSubDisplayStart); + cellSubdisplay->AddFunc(0x6d85ddb3, cellSubDisplayStop); - cellSubdisplay.AddFunc(0x8a264d71, cellSubDisplayGetPeerNum); - cellSubdisplay.AddFunc(0xe2485f79, cellSubDisplayGetPeerList); + cellSubdisplay->AddFunc(0x938ac642, cellSubDisplayGetVideoBuffer); + cellSubdisplay->AddFunc(0xaee1e0c2, cellSubDisplayAudioOutBlocking); + cellSubdisplay->AddFunc(0x5468d6b0, cellSubDisplayAudioOutNonBlocking); + + cellSubdisplay->AddFunc(0x8a264d71, cellSubDisplayGetPeerNum); + cellSubdisplay->AddFunc(0xe2485f79, cellSubDisplayGetPeerList); } -#endif diff --git a/rpcs3/Emu/SysCalls/Modules/cellSubdisplay.h b/rpcs3/Emu/SysCalls/Modules/cellSubdisplay.h new file mode 100644 index 0000000000..8321a606c0 --- /dev/null +++ b/rpcs3/Emu/SysCalls/Modules/cellSubdisplay.h @@ -0,0 +1,83 @@ +#pragma once + +// Return Codes +enum +{ + CELL_SUBDISPLAY_ERROR_OUT_OF_MEMORY = 0x80029851, + CELL_SUBDISPLAY_ERROR_FATAL = 0x80029852, + CELL_SUBDISPLAY_ERROR_NOT_FOUND = 0x80029853, + CELL_SUBDISPLAY_ERROR_INVALID_VALUE = 0x80029854, + CELL_SUBDISPLAY_ERROR_NOT_INITIALIZED = 0x80029855, + CELL_SUBDISPLAY_ERROR_SET_SAMPLE = 0x80029860, + CELL_SUBDISPLAY_ERROR_AUDIOOUT_IS_BUSY = 0x80029861, + CELL_SUBDISPLAY_ERROR_ZERO_REGISTERED = 0x80029813, +}; + +// Different constants +enum +{ + CELL_SUBDISPLAY_STATUS_JOIN = 1, + CELL_SUBDISPLAY_STATUS_LEAVE = 2, + CELL_SUBDISPLAY_STATUS_FATALERROR = 3, + CELL_SUBDISPLAY_VERSION_0001 = 1, + CELL_SUBDISPLAY_VERSION_0002 = 2, + CELL_SUBDISPLAY_MODE_REMOTEPLAY = 1, + CELL_SUBDISPLAY_VIDEO_FORMAT_A8R8G8B8 = 1, + CELL_SUBDISPLAY_VIDEO_FORMAT_R8G8B8A8 = 2, + CELL_SUBDISPLAY_VIDEO_ASPECT_RATIO_16_9 = 0, + CELL_SUBDISPLAY_VIDEO_ASPECT_RATIO_4_3 = 1, + CELL_SUBDISPLAY_VIDEO_MODE_SETDATA = 0, + CELL_SUBDISPLAY_VIDEO_MODE_CAPTURE = 1, + CELL_SUBDISPLAY_AUDIO_MODE_SETDATA = 0, + CELL_SUBDISPLAY_AUDIO_MODE_CAPTURE = 1, + CELL_SUBDISPLAY_0001_MEMORY_CONTAINER_SIZE = 8 * 1024 * 1024, + CELL_SUBDISPLAY_0002_MEMORY_CONTAINER_SIZE = 10 * 1024 * 1024, + CELL_SUBDISPLAY_NICKNAME_LEN = 256, + CELL_SUBDISPLAY_PSPID_LEN = 16, +}; + +struct CellSubDisplayVideoParam +{ + be_t format; + be_t width; + be_t height; + be_t pitch; + be_t aspectRatio; + be_t videoMode; +}; + +struct CellSubDisplayAudioParam +{ + be_t ch; + be_t audioMode; +}; + +struct CellSubDisplayParam +{ + be_t version; + be_t mode; + be_t nGroup; + be_t nPeer; + vm::ptr videoParam; + vm::ptr audioParam; +}; + +struct CellSubDisplayPSPId +{ + char data[CELL_SUBDISPLAY_PSPID_LEN]; +}; + +struct CellSubDisplayNickname +{ + char data[CELL_SUBDISPLAY_NICKNAME_LEN]; +}; + +struct CellSubDisplayPeerInfo +{ + be_t sessionId; + be_t portNo; + CellSubDisplayPSPId pspId; + CellSubDisplayNickname pspNickname; +}; + +typedef void(*CellSubDisplayHandler)(s32 cbMsg, u64 cbParam, u32 *userdata); \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/Modules/cellSync.cpp b/rpcs3/Emu/SysCalls/Modules/cellSync.cpp index afac57e65e..fca2ca40f7 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSync.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSync.cpp @@ -3,7 +3,10 @@ #include "Emu/System.h" #include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/CB_FUNC.h" +#include "Emu/Memory/atomic_type.h" +#include "Emu/SysCalls/lv2/sleep_queue_type.h" +#include "Emu/SysCalls/lv2/sys_event.h" #include "Emu/SysCalls/lv2/sys_process.h" #include "Emu/Event.h" #include "cellSync.h" diff --git a/rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp b/rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp index aa7458e940..5afa9e72dc 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellSysutil.cpp @@ -286,13 +286,13 @@ int cellVideoOutGetNumberOfDevice(u32 videoOut) int cellVideoOutGetResolutionAvailability(u32 videoOut, u32 resolutionId, u32 aspect, u32 option) { - cellSysutil->Warning("cellVideoOutGetResolutionAvailability(videoOut=%d, resolutionId=0x%x, option_addr=0x%x, aspect=0x%x, option=0x%x)", + cellSysutil->Warning("cellVideoOutGetResolutionAvailability(videoOut=%d, resolutionId=0x%x, option_addr=0x%x, aspect=%d, option=%d)", videoOut, resolutionId, aspect, option); - if(!ResolutionIdToNum(resolutionId)) - { - return CELL_EINVAL; - } + if (!Ini.GS3DTV.GetValue() && (resolutionId == CELL_VIDEO_OUT_RESOLUTION_720_3D_FRAME_PACKING || resolutionId == CELL_VIDEO_OUT_RESOLUTION_1024x720_3D_FRAME_PACKING || + resolutionId == CELL_VIDEO_OUT_RESOLUTION_960x720_3D_FRAME_PACKING || resolutionId == CELL_VIDEO_OUT_RESOLUTION_800x720_3D_FRAME_PACKING || + resolutionId == CELL_VIDEO_OUT_RESOLUTION_640x720_3D_FRAME_PACKING)) + return 0; switch(videoOut) { diff --git a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp index 12b28591c8..ddf5726ff4 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellVdec.cpp @@ -19,6 +19,8 @@ extern "C" Module *cellVdec = nullptr; +#define VDEC_ERROR(...) { cellVdec->Error(__VA_ARGS__); Emu.Pause(); return; } // only for decoder thread + VideoDecoder::VideoDecoder(CellVdecCodecType type, u32 profile, u32 addr, u32 size, vm::ptr func, u32 arg) : type(type) , profile(profile) @@ -31,33 +33,59 @@ VideoDecoder::VideoDecoder(CellVdecCodecType type, u32 profile, u32 addr, u32 si , is_closed(false) , just_started(false) , just_finished(false) + , frc_set(0) + , codec(nullptr) + , input_format(nullptr) , ctx(nullptr) , vdecCb(nullptr) { av_register_all(); avcodec_register_all(); - AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_H264); + switch (type) + { + case CELL_VDEC_CODEC_TYPE_MPEG2: + { + codec = avcodec_find_decoder(AV_CODEC_ID_MPEG2VIDEO); + input_format = av_find_input_format("mpeg"); + break; + } + case CELL_VDEC_CODEC_TYPE_AVC: + { + codec = avcodec_find_decoder(AV_CODEC_ID_H264); + input_format = av_find_input_format("mpeg"); + break; + } + case CELL_VDEC_CODEC_TYPE_DIVX: + { + codec = avcodec_find_decoder(AV_CODEC_ID_MPEG4); + input_format = av_find_input_format("mpeg"); + break; + } + default: + { + VDEC_ERROR("VideoDecoder(): unknown type (0x%x)", type); + } + } + if (!codec) { - cellVdec->Error("VideoDecoder(): avcodec_find_decoder(H264) failed"); - Emu.Pause(); - return; + VDEC_ERROR("VideoDecoder(): avcodec_find_decoder() failed"); + } + if (!input_format) + { + VDEC_ERROR("VideoDecoder(): av_find_input_format() failed"); } fmt = avformat_alloc_context(); if (!fmt) { - cellVdec->Error("VideoDecoder(): avformat_alloc_context failed"); - Emu.Pause(); - return; + VDEC_ERROR("VideoDecoder(): avformat_alloc_context() failed"); } io_buf = (u8*)av_malloc(4096); fmt->pb = avio_alloc_context(io_buf, 4096, 0, this, vdecRead, NULL, NULL); if (!fmt->pb) { - cellVdec->Error("VideoDecoder(): avio_alloc_context failed"); - Emu.Pause(); - return; + VDEC_ERROR("VideoDecoder(): avio_alloc_context() failed"); } } @@ -65,7 +93,7 @@ VideoDecoder::~VideoDecoder() { // TODO: check finalization VdecFrame vf; - while (frames.Pop(vf, &sq_no_wait)) + while (frames.try_pop(vf)) { av_frame_unref(vf.data); av_frame_free(&vf.data); @@ -96,7 +124,7 @@ next: if (vdec.reader.size < (u32)buf_size /*&& !vdec.just_started*/) { VdecTask task; - if (!vdec.job.Peek(task, &vdec.is_closed)) + if (!vdec.job.peek(task, 0, &vdec.is_closed)) { if (Emu.IsStopped()) cellVdec->Warning("vdecRead() aborted"); return 0; @@ -121,7 +149,7 @@ next: vdec.cbFunc.call(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_AUDONE, CELL_OK, vdec.cbArg); - vdec.job.Pop(vdec.task, nullptr); + vdec.job.pop(vdec.task); vdec.reader.addr = vdec.task.addr; vdec.reader.size = vdec.task.size; @@ -163,8 +191,8 @@ u32 vdecQueryAttr(CellVdecCodecType type, u32 profile, u32 spec_addr /* may be 0 switch (type) // TODO: check profile levels { case CELL_VDEC_CODEC_TYPE_AVC: cellVdec->Warning("cellVdecQueryAttr: AVC (profile=%d)", profile); break; - case CELL_VDEC_CODEC_TYPE_MPEG2: cellVdec->Todo("MPEG2 not supported"); break; - case CELL_VDEC_CODEC_TYPE_DIVX: cellVdec->Todo("DIVX not supported"); break; + case CELL_VDEC_CODEC_TYPE_MPEG2: cellVdec->Warning("cellVdecQueryAttr: MPEG2 (profile=%d)", profile); break; + case CELL_VDEC_CODEC_TYPE_DIVX: cellVdec->Warning("cellVdecQueryAttr: DivX (profile=%d)", profile); break; default: return CELL_VDEC_ERROR_ARG; } @@ -176,11 +204,12 @@ u32 vdecQueryAttr(CellVdecCodecType type, u32 profile, u32 spec_addr /* may be 0 return CELL_OK; } -u32 vdecOpen(VideoDecoder* data) +u32 vdecOpen(VideoDecoder* vdec_ptr) { - VideoDecoder& vdec = *data; + std::shared_ptr sptr(vdec_ptr); + VideoDecoder& vdec = *vdec_ptr; - u32 vdec_id = cellVdec->GetNewId(data); + u32 vdec_id = cellVdec->GetNewId(sptr); vdec.id = vdec_id; @@ -193,8 +222,9 @@ u32 vdecOpen(VideoDecoder* data) vdec.vdecCb->InitRegs(); vdec.vdecCb->DoRun(); - thread t("Video Decoder[" + std::to_string(vdec_id) + "] Thread", [&]() + thread t("Video Decoder[" + std::to_string(vdec_id) + "] Thread", [vdec_ptr, sptr]() { + VideoDecoder& vdec = *vdec_ptr; cellVdec->Notice("Video Decoder thread started"); VdecTask& task = vdec.task; @@ -206,13 +236,7 @@ u32 vdecOpen(VideoDecoder* data) break; } - //if (!vdec.job.GetCountUnsafe() && vdec.is_running) - //{ - // std::this_thread::sleep_for(std::chrono::milliseconds(1)); - // continue; - //} - - if (!vdec.job.Pop(task, &vdec.is_closed)) + if (!vdec.job.pop(task, &vdec.is_closed)) { break; } @@ -225,9 +249,10 @@ u32 vdecOpen(VideoDecoder* data) cellVdec->Warning("vdecStartSeq:"); vdec.reader = {}; + vdec.frc_set = 0; vdec.just_started = true; + break; } - break; case vdecEndSeq: { @@ -237,8 +262,8 @@ u32 vdecOpen(VideoDecoder* data) vdec.cbFunc.call(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_SEQDONE, CELL_OK, vdec.cbArg); vdec.just_finished = true; + break; } - break; case vdecDecodeAu: { @@ -257,7 +282,7 @@ u32 vdecOpen(VideoDecoder* data) if (vdec.just_started) { vdec.first_pts = task.pts; - vdec.last_pts = task.pts; + vdec.last_pts = -1; vdec.first_dts = task.dts; } @@ -296,54 +321,42 @@ u32 vdecOpen(VideoDecoder* data) } else if (vdec.just_started) // deferred initialization { - err = avformat_open_input(&vdec.fmt, NULL, av_find_input_format("mpeg"), NULL); - if (err) + AVDictionary* opts = nullptr; + av_dict_set(&opts, "probesize", "4096", 0); + err = avformat_open_input(&vdec.fmt, NULL, NULL, &opts); + if (err || opts) { - cellVdec->Error("vdecDecodeAu: avformat_open_input() failed"); - Emu.Pause(); - break; + VDEC_ERROR("vdecDecodeAu: avformat_open_input() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0); } - AVCodec* codec = avcodec_find_decoder(AV_CODEC_ID_H264); // ??? - if (!codec) + if (vdec.type == CELL_VDEC_CODEC_TYPE_DIVX) { - cellVdec->Error("vdecDecodeAu: avcodec_find_decoder() failed"); - Emu.Pause(); - break; + err = avformat_find_stream_info(vdec.fmt, NULL); + if (err || !vdec.fmt->nb_streams) + { + VDEC_ERROR("vdecDecodeAu: avformat_find_stream_info() failed (err=0x%x, nb_streams=%d)", err, vdec.fmt->nb_streams); + } } - /*err = avformat_find_stream_info(vdec.fmt, NULL); - if (err) + else { - LOG_ERROR(HLE, "vdecDecodeAu: avformat_find_stream_info() failed"); - Emu.Pause(); - break; - } - if (!vdec.fmt->nb_streams) - { - LOG_ERROR(HLE, "vdecDecodeAu: no stream found"); - Emu.Pause(); - break; - }*/ - if (!avformat_new_stream(vdec.fmt, codec)) - { - cellVdec->Error("vdecDecodeAu: avformat_new_stream() failed"); - Emu.Pause(); - break; + if (!avformat_new_stream(vdec.fmt, vdec.codec)) + { + VDEC_ERROR("vdecDecodeAu: avformat_new_stream() failed"); + } } vdec.ctx = vdec.fmt->streams[0]->codec; // TODO: check data - AVDictionary* opts = nullptr; + opts = nullptr; av_dict_set(&opts, "refcounted_frames", "1", 0); { std::lock_guard lock(g_mutex_avcodec_open2); // not multithread-safe (???) - err = avcodec_open2(vdec.ctx, codec, &opts); + err = avcodec_open2(vdec.ctx, vdec.codec, &opts); } - if (err) + if (err || opts) { - cellVdec->Error("vdecDecodeAu: avcodec_open2() failed"); - Emu.Pause(); - break; + VDEC_ERROR("vdecDecodeAu: avcodec_open2() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0); } + vdec.just_started = false; } @@ -386,9 +399,7 @@ u32 vdecOpen(VideoDecoder* data) if (!frame.data) { - cellVdec->Error("vdecDecodeAu: av_frame_alloc() failed"); - Emu.Pause(); - break; + VDEC_ERROR("vdecDecodeAu: av_frame_alloc() failed"); } int got_picture = 0; @@ -397,7 +408,7 @@ u32 vdecOpen(VideoDecoder* data) if (decode <= 0) { - if (!last_frame && decode < 0) + if (decode < 0) { cellVdec->Error("vdecDecodeAu: AU decoding error(0x%x)", decode); } @@ -406,25 +417,103 @@ u32 vdecOpen(VideoDecoder* data) if (got_picture) { - u64 ts = av_frame_get_best_effort_timestamp(frame.data); - if (ts != AV_NOPTS_VALUE) + if (frame.data->interlaced_frame) { - frame.pts = ts/* - vdec.first_pts*/; // ??? - vdec.last_pts = frame.pts; + VDEC_ERROR("vdecDecodeAu: interlaced frames not supported (0x%x)", frame.data->interlaced_frame); + } + + if (frame.data->repeat_pict) + { + VDEC_ERROR("vdecDecodeAu: repeated frames not supported (0x%x)", frame.data->repeat_pict); + } + + if (vdec.frc_set) + { + if (vdec.last_pts == -1) + { + vdec.last_pts = 0x8000; //av_frame_get_best_effort_timestamp(frame.data); + } + else switch (vdec.frc_set) + { + case CELL_VDEC_FRC_24000DIV1001: vdec.last_pts += 1001 * 90000 / 24000; break; + case CELL_VDEC_FRC_24: vdec.last_pts += 90000 / 24; break; + case CELL_VDEC_FRC_25: vdec.last_pts += 90000 / 25; break; + case CELL_VDEC_FRC_30000DIV1001: vdec.last_pts += 1001 * 90000 / 30000; break; + case CELL_VDEC_FRC_30: vdec.last_pts += 90000 / 30; break; + case CELL_VDEC_FRC_50: vdec.last_pts += 90000 / 50; break; + case CELL_VDEC_FRC_60000DIV1001: vdec.last_pts += 1001 * 90000 / 60000; break; + case CELL_VDEC_FRC_60: vdec.last_pts += 90000 / 60; break; + default: + { + VDEC_ERROR("vdecDecodeAu: invalid frame rate code set (0x%x)", vdec.frc_set); + } + } + + frame.frc = vdec.frc_set; } else { - vdec.last_pts += vdec.ctx->time_base.num * 90000 / (vdec.ctx->time_base.den / vdec.ctx->ticks_per_frame); - frame.pts = vdec.last_pts; + u64 ts = av_frame_get_best_effort_timestamp(frame.data); + if (ts != AV_NOPTS_VALUE) + { + vdec.last_pts = ts; + } + else if (vdec.last_pts == -1) + { + vdec.last_pts = 0; + } + else + { + vdec.last_pts += vdec.ctx->time_base.num * 90000 * vdec.ctx->ticks_per_frame / vdec.ctx->time_base.den; + } + + if (vdec.ctx->time_base.num == 1) + { + switch ((u64)vdec.ctx->time_base.den + (u64)(vdec.ctx->ticks_per_frame - 1) * 0x100000000ull) + { + case 24: case 0x100000000ull + 48: frame.frc = CELL_VDEC_FRC_24; break; + case 25: case 0x100000000ull + 50: frame.frc = CELL_VDEC_FRC_25; break; + case 30: case 0x100000000ull + 60: frame.frc = CELL_VDEC_FRC_30; break; + case 50: case 0x100000000ull + 100: frame.frc = CELL_VDEC_FRC_50; break; + case 60: case 0x100000000ull + 120: frame.frc = CELL_VDEC_FRC_60; break; + default: + { + VDEC_ERROR("vdecDecodeAu: unsupported time_base.den (%d/1, tpf=%d)", vdec.ctx->time_base.den, vdec.ctx->ticks_per_frame); + } + } + } + else if (vdec.ctx->time_base.num == 1001) + { + if (vdec.ctx->time_base.den / vdec.ctx->ticks_per_frame == 24000) + { + frame.frc = CELL_VDEC_FRC_24000DIV1001; + } + else if (vdec.ctx->time_base.den / vdec.ctx->ticks_per_frame == 30000) + { + frame.frc = CELL_VDEC_FRC_30000DIV1001; + } + else if (vdec.ctx->time_base.den / vdec.ctx->ticks_per_frame == 60000) + { + frame.frc = CELL_VDEC_FRC_60000DIV1001; + } + else + { + VDEC_ERROR("vdecDecodeAu: unsupported time_base.den (%d/1001, tpf=%d)", vdec.ctx->time_base.den, vdec.ctx->ticks_per_frame); + } + } + else + { + VDEC_ERROR("vdecDecodeAu: unsupported time_base.num (%d)", vdec.ctx->time_base.num); + } } - //frame.pts = vdec.last_pts; - //vdec.last_pts += 3754; + + frame.pts = vdec.last_pts; frame.dts = (frame.pts - vdec.first_pts) + vdec.first_dts; frame.userdata = task.userData; //LOG_NOTICE(HLE, "got picture (pts=0x%llx, dts=0x%llx)", frame.pts, frame.dts); - if (vdec.frames.Push(frame, &vdec.is_closed)) + if (vdec.frames.push(frame, &vdec.is_closed)) { frame.data = nullptr; // to prevent destruction vdec.cbFunc.call(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_PICOUT, CELL_OK, vdec.cbArg); @@ -433,23 +522,24 @@ u32 vdecOpen(VideoDecoder* data) } vdec.cbFunc.call(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_AUDONE, CELL_OK, vdec.cbArg); + break; } - break; case vdecSetFrameRate: { - cellVdec->Error("TODO: vdecSetFrameRate(%d)", task.frc); - Emu.Pause(); + cellVdec->Warning("vdecSetFrameRate(0x%x)", task.frc); + vdec.frc_set = task.frc; + break; } - break; - case vdecClose: break; + case vdecClose: + { + break; + } default: { - cellVdec->Error("Video Decoder thread error: unknown task(%d)", task.type); - Emu.Pause(); - return; + VDEC_ERROR("Video Decoder thread error: unknown task(%d)", task.type); } } } @@ -502,14 +592,14 @@ int cellVdecClose(u32 handle) { cellVdec->Warning("cellVdecClose(handle=%d)", handle); - VideoDecoder* vdec; + std::shared_ptr vdec; if (!Emu.GetIdManager().GetIDData(handle, vdec)) { return CELL_VDEC_ERROR_ARG; } vdec->is_closed = true; - vdec->job.Push(VdecTask(vdecClose), &sq_no_wait); + vdec->job.try_push(VdecTask(vdecClose)); while (!vdec->is_finished) { @@ -518,7 +608,7 @@ int cellVdecClose(u32 handle) cellVdec->Warning("cellVdecClose(%d) aborted", handle); break; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } if (vdec->vdecCb) Emu.GetCPU().RemoveThread(vdec->vdecCb->GetId()); @@ -530,13 +620,13 @@ int cellVdecStartSeq(u32 handle) { cellVdec->Log("cellVdecStartSeq(handle=%d)", handle); - VideoDecoder* vdec; + std::shared_ptr vdec; if (!Emu.GetIdManager().GetIDData(handle, vdec)) { return CELL_VDEC_ERROR_ARG; } - vdec->job.Push(VdecTask(vdecStartSeq), &vdec->is_closed); + vdec->job.push(VdecTask(vdecStartSeq), &vdec->is_closed); return CELL_OK; } @@ -544,13 +634,13 @@ int cellVdecEndSeq(u32 handle) { cellVdec->Warning("cellVdecEndSeq(handle=%d)", handle); - VideoDecoder* vdec; + std::shared_ptr vdec; if (!Emu.GetIdManager().GetIDData(handle, vdec)) { return CELL_VDEC_ERROR_ARG; } - vdec->job.Push(VdecTask(vdecEndSeq), &vdec->is_closed); + vdec->job.push(VdecTask(vdecEndSeq), &vdec->is_closed); return CELL_OK; } @@ -558,7 +648,7 @@ int cellVdecDecodeAu(u32 handle, CellVdecDecodeMode mode, vm::ptrLog("cellVdecDecodeAu(handle=%d, mode=0x%x, auInfo_addr=0x%x)", handle, mode, auInfo.addr()); - VideoDecoder* vdec; + std::shared_ptr vdec; if (!Emu.GetIdManager().GetIDData(handle, vdec)) { return CELL_VDEC_ERROR_ARG; @@ -574,7 +664,7 @@ int cellVdecDecodeAu(u32 handle, CellVdecDecodeMode mode, vm::ptruserData; task.specData = auInfo->codecSpecificData; - vdec->job.Push(task, &vdec->is_closed); + vdec->job.push(task, &vdec->is_closed); return CELL_OK; } @@ -582,14 +672,14 @@ int cellVdecGetPicture(u32 handle, vm::ptr format, vm:: { cellVdec->Log("cellVdecGetPicture(handle=%d, format_addr=0x%x, outBuff_addr=0x%x)", handle, format.addr(), outBuff.addr()); - VideoDecoder* vdec; + std::shared_ptr vdec; if (!Emu.GetIdManager().GetIDData(handle, vdec)) { return CELL_VDEC_ERROR_ARG; } VdecFrame vf; - if (!vdec->frames.Pop(vf, &sq_no_wait)) + if (!vdec->frames.try_pop(vf)) { //std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack return CELL_VDEC_ERROR_EMPTY; @@ -624,7 +714,7 @@ int cellVdecGetPicture(u32 handle, vm::ptr format, vm:: int err = av_image_copy_to_buffer(outBuff.get_ptr(), buf_size, frame.data, frame.linesize, vdec->ctx->pix_fmt, frame.width, frame.height, 1); if (err < 0) { - cellVdec->Error("cellVdecGetPicture: av_image_copy_to_buffer failed(%d)", err); + cellVdec->Error("cellVdecGetPicture: av_image_copy_to_buffer failed (err=0x%x)", err); Emu.Pause(); } } @@ -638,14 +728,14 @@ int cellVdecGetPicItem(u32 handle, vm::ptr picItem_ptr) { cellVdec->Log("cellVdecGetPicItem(handle=%d, picItem_ptr_addr=0x%x)", handle, picItem_ptr.addr()); - VideoDecoder* vdec; + std::shared_ptr vdec; if (!Emu.GetIdManager().GetIDData(handle, vdec)) { return CELL_VDEC_ERROR_ARG; } VdecFrame vf; - if (!vdec->frames.Peek(vf, &sq_no_wait)) + if (!vdec->frames.try_peek(vf)) { //std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack return CELL_VDEC_ERROR_EMPTY; @@ -667,79 +757,115 @@ int cellVdecGetPicItem(u32 handle, vm::ptr picItem_ptr) info->auNum = 1; info->auPts[0].lower = (u32)vf.pts; info->auPts[0].upper = vf.pts >> 32; - info->auPts[1].lower = 0xffffffff; - info->auPts[1].upper = 0xffffffff; + info->auPts[1].lower = (u32)CODEC_TS_INVALID; + info->auPts[1].upper = (u32)CODEC_TS_INVALID; info->auDts[0].lower = (u32)vf.dts; info->auDts[0].upper = vf.dts >> 32; - info->auDts[1].lower = 0xffffffff; - info->auDts[1].upper = 0xffffffff; + info->auDts[1].lower = (u32)CODEC_TS_INVALID; + info->auDts[1].upper = (u32)CODEC_TS_INVALID; info->auUserData[0] = vf.userdata; info->auUserData[1] = 0; info->status = CELL_OK; info->attr = CELL_VDEC_PICITEM_ATTR_NORMAL; info->picInfo_addr = info.addr() + sizeof(CellVdecPicItem); - auto avc = vm::ptr::make(info.addr() + sizeof(CellVdecPicItem)); + if (vdec->type == CELL_VDEC_CODEC_TYPE_AVC) + { + auto avc = vm::ptr::make(info.addr() + sizeof(CellVdecPicItem)); - avc->horizontalSize = frame.width; - avc->verticalSize = frame.height; - switch (frame.pict_type) - { - case AV_PICTURE_TYPE_I: avc->pictureType[0] = CELL_VDEC_AVC_PCT_I; break; - case AV_PICTURE_TYPE_P: avc->pictureType[0] = CELL_VDEC_AVC_PCT_P; break; - case AV_PICTURE_TYPE_B: avc->pictureType[0] = CELL_VDEC_AVC_PCT_B; break; - default: avc->pictureType[0] = CELL_VDEC_AVC_PCT_UNKNOWN; break; // ??? + avc->horizontalSize = frame.width; + avc->verticalSize = frame.height; + switch (frame.pict_type) + { + case AV_PICTURE_TYPE_I: avc->pictureType[0] = CELL_VDEC_AVC_PCT_I; break; + case AV_PICTURE_TYPE_P: avc->pictureType[0] = CELL_VDEC_AVC_PCT_P; break; + case AV_PICTURE_TYPE_B: avc->pictureType[0] = CELL_VDEC_AVC_PCT_B; break; + default: cellVdec->Error("cellVdecGetPicItem(AVC): unknown pict_type value (0x%x)", frame.pict_type); + } + avc->pictureType[1] = CELL_VDEC_AVC_PCT_UNKNOWN; // ??? + avc->idrPictureFlag = false; // ??? + avc->aspect_ratio_idc = CELL_VDEC_AVC_ARI_SAR_UNSPECIFIED; // ??? + avc->sar_height = 0; + avc->sar_width = 0; + avc->pic_struct = CELL_VDEC_AVC_PSTR_FRAME; // ??? + avc->picOrderCount[0] = 0; // ??? + avc->picOrderCount[1] = 0; + avc->vui_parameters_present_flag = true; // ??? + avc->frame_mbs_only_flag = true; // ??? progressive + avc->video_signal_type_present_flag = true; // ??? + avc->video_format = CELL_VDEC_AVC_VF_COMPONENT; // ??? + avc->video_full_range_flag = false; // ??? + avc->colour_description_present_flag = true; + avc->colour_primaries = CELL_VDEC_AVC_CP_ITU_R_BT_709_5; // ??? + avc->transfer_characteristics = CELL_VDEC_AVC_TC_ITU_R_BT_709_5; + avc->matrix_coefficients = CELL_VDEC_AVC_MXC_ITU_R_BT_709_5; // important + avc->timing_info_present_flag = true; + + switch (vf.frc) + { + case CELL_VDEC_FRC_24000DIV1001: avc->frameRateCode = CELL_VDEC_AVC_FRC_24000DIV1001; break; + case CELL_VDEC_FRC_24: avc->frameRateCode = CELL_VDEC_AVC_FRC_24; break; + case CELL_VDEC_FRC_25: avc->frameRateCode = CELL_VDEC_AVC_FRC_25; break; + case CELL_VDEC_FRC_30000DIV1001: avc->frameRateCode = CELL_VDEC_AVC_FRC_30000DIV1001; break; + case CELL_VDEC_FRC_30: avc->frameRateCode = CELL_VDEC_AVC_FRC_30; break; + case CELL_VDEC_FRC_50: avc->frameRateCode = CELL_VDEC_AVC_FRC_50; break; + case CELL_VDEC_FRC_60000DIV1001: avc->frameRateCode = CELL_VDEC_AVC_FRC_60000DIV1001; break; + case CELL_VDEC_FRC_60: avc->frameRateCode = CELL_VDEC_AVC_FRC_60; break; + default: cellVdec->Error("cellVdecGetPicItem(AVC): unknown frc value (0x%x)", vf.frc); + } + + avc->fixed_frame_rate_flag = true; + avc->low_delay_hrd_flag = true; // ??? + avc->entropy_coding_mode_flag = true; // ??? + avc->nalUnitPresentFlags = 0; // ??? + avc->ccDataLength[0] = 0; + avc->ccDataLength[1] = 0; + avc->reserved[0] = 0; + avc->reserved[1] = 0; } - avc->pictureType[1] = CELL_VDEC_AVC_PCT_UNKNOWN; // ??? - avc->idrPictureFlag = false; // ??? - avc->aspect_ratio_idc = CELL_VDEC_AVC_ARI_SAR_UNSPECIFIED; // ??? - avc->sar_height = 0; - avc->sar_width = 0; - avc->pic_struct = CELL_VDEC_AVC_PSTR_FRAME; // ??? - avc->picOrderCount[0] = 0; // ??? - avc->picOrderCount[1] = 0; - avc->vui_parameters_present_flag = true; // ??? - avc->frame_mbs_only_flag = true; // ??? progressive - avc->video_signal_type_present_flag = true; // ??? - avc->video_format = CELL_VDEC_AVC_VF_COMPONENT; // ??? - avc->video_full_range_flag = false; // ??? - avc->colour_description_present_flag = true; - avc->colour_primaries = CELL_VDEC_AVC_CP_ITU_R_BT_709_5; // ??? - avc->transfer_characteristics = CELL_VDEC_AVC_TC_ITU_R_BT_709_5; - avc->matrix_coefficients = CELL_VDEC_AVC_MXC_ITU_R_BT_709_5; // important - avc->timing_info_present_flag = true; - if (vdec->ctx->time_base.num == 1001) + else if (vdec->type == CELL_VDEC_CODEC_TYPE_DIVX) { - if (vdec->ctx->time_base.den == 48000 && vdec->ctx->ticks_per_frame == 2) + auto dvx = vm::ptr::make(info.addr() + sizeof(CellVdecPicItem)); + + switch (frame.pict_type) { - avc->frameRateCode = CELL_VDEC_AVC_FRC_24000DIV1001; + case AV_PICTURE_TYPE_I: dvx->pictureType = CELL_VDEC_DIVX_VCT_I; break; + case AV_PICTURE_TYPE_P: dvx->pictureType = CELL_VDEC_DIVX_VCT_P; break; + case AV_PICTURE_TYPE_B: dvx->pictureType = CELL_VDEC_DIVX_VCT_B; break; + default: cellVdec->Error("cellVdecGetPicItem(DivX): unknown pict_type value (0x%x)", frame.pict_type); } - else if (vdec->ctx->time_base.den == 60000 && vdec->ctx->ticks_per_frame == 2) + dvx->horizontalSize = frame.width; + dvx->verticalSize = frame.height; + dvx->pixelAspectRatio = CELL_VDEC_DIVX_ARI_PAR_1_1; // ??? + dvx->parHeight = 0; + dvx->parWidth = 0; + dvx->colourDescription = false; // ??? + dvx->colourPrimaries = CELL_VDEC_DIVX_CP_ITU_R_BT_709; // ??? + dvx->transferCharacteristics = CELL_VDEC_DIVX_TC_ITU_R_BT_709; // ??? + dvx->matrixCoefficients = CELL_VDEC_DIVX_MXC_ITU_R_BT_709; // ??? + dvx->pictureStruct = CELL_VDEC_DIVX_PSTR_FRAME; // ??? + switch (vf.frc) { - avc->frameRateCode = CELL_VDEC_AVC_FRC_30000DIV1001; - } - else - { - cellVdec->Error("cellVdecGetPicItem: unsupported time_base.den (%d)", vdec->ctx->time_base.den); - Emu.Pause(); + case CELL_VDEC_FRC_24000DIV1001: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_24000DIV1001; break; + case CELL_VDEC_FRC_24: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_24; break; + case CELL_VDEC_FRC_25: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_25; break; + case CELL_VDEC_FRC_30000DIV1001: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_30000DIV1001; break; + case CELL_VDEC_FRC_30: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_30; break; + case CELL_VDEC_FRC_50: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_50; break; + case CELL_VDEC_FRC_60000DIV1001: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_60000DIV1001; break; + case CELL_VDEC_FRC_60: dvx->frameRateCode = CELL_VDEC_DIVX_FRC_60; break; + default: cellVdec->Error("cellVdecGetPicItem(DivX): unknown frc value (0x%x)", vf.frc); } } - else + else if (vdec->type == CELL_VDEC_CODEC_TYPE_MPEG2) { - cellVdec->Error("cellVdecGetPicItem: unsupported time_base.num (%d)", vdec->ctx->time_base.num); + auto mp2 = vm::ptr::make(info.addr() + sizeof(CellVdecPicItem)); + + cellVdec->Todo("cellVdecGetPicItem(MPEG2)"); Emu.Pause(); } - avc->fixed_frame_rate_flag = true; - avc->low_delay_hrd_flag = true; // ??? - avc->entropy_coding_mode_flag = true; // ??? - avc->nalUnitPresentFlags = 0; // ??? - avc->ccDataLength[0] = 0; - avc->ccDataLength[1] = 0; - avc->reserved[0] = 0; - avc->reserved[1] = 0; - - *picItem_ptr = info.addr(); + *picItem_ptr = info.addr(); return CELL_OK; } @@ -747,7 +873,7 @@ int cellVdecSetFrameRate(u32 handle, CellVdecFrameRate frc) { cellVdec->Log("cellVdecSetFrameRate(handle=%d, frc=0x%x)", handle, frc); - VideoDecoder* vdec; + std::shared_ptr vdec; if (!Emu.GetIdManager().GetIDData(handle, vdec)) { return CELL_VDEC_ERROR_ARG; @@ -757,7 +883,7 @@ int cellVdecSetFrameRate(u32 handle, CellVdecFrameRate frc) VdecTask task(vdecSetFrameRate); task.frc = frc; - vdec->job.Push(task, &vdec->is_closed); + vdec->job.push(task, &vdec->is_closed); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/Modules/cellVdec.h b/rpcs3/Emu/SysCalls/Modules/cellVdec.h index 144c0766ad..e03cc26f06 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVdec.h +++ b/rpcs3/Emu/SysCalls/Modules/cellVdec.h @@ -1,7 +1,5 @@ #pragma once -#include "Utilities/SQueue.h" - #define a128(x) ((x + 127) & (~127)) // Error Codes @@ -685,6 +683,7 @@ struct VdecFrame u64 dts; u64 pts; u64 userdata; + u32 frc; }; int vdecRead(void* opaque, u8* buf, int buf_size); @@ -692,13 +691,15 @@ int vdecRead(void* opaque, u8* buf, int buf_size); class VideoDecoder { public: - SQueue job; + squeue_t job; u32 id; volatile bool is_closed; volatile bool is_finished; bool just_started; bool just_finished; + AVCodec* codec; + AVInputFormat* input_format; AVCodecContext* ctx; AVFormatContext* fmt; u8* io_buf; @@ -709,7 +710,7 @@ public: u32 size; } reader; - SQueue frames; + squeue_t frames; const CellVdecCodecType type; const u32 profile; @@ -721,6 +722,7 @@ public: VdecTask task; // current task variable u64 last_pts, first_pts, first_dts; + u32 frc_set; // frame rate overwriting AVRational rfr, afr; PPUThread* vdecCb; diff --git a/rpcs3/Emu/SysCalls/Modules/cellVpost.cpp b/rpcs3/Emu/SysCalls/Modules/cellVpost.cpp index d4790ca782..e393ba8d13 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellVpost.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellVpost.cpp @@ -28,7 +28,8 @@ int cellVpostQueryAttr(vm::ptr cfgParam, vm::ptrGetNewId(data); + std::shared_ptr data_ptr(data); + u32 id = cellVpost->GetNewId(data_ptr); cellVpost->Notice("*** Vpost instance created (to_rgba=%d): id = %d", data->to_rgba, id); @@ -59,7 +60,7 @@ int cellVpostClose(u32 handle) { cellVpost->Warning("cellVpostClose(handle=0x%x)", handle); - VpostInstance* vpost; + std::shared_ptr vpost; if (!Emu.GetIdManager().GetIDData(handle, vpost)) { return CELL_VPOST_ERROR_C_ARG_HDL_INVALID; @@ -75,7 +76,7 @@ int cellVpostExec(u32 handle, vm::ptr inPicBuff, vm::ptrLog("cellVpostExec(handle=0x%x, inPicBuff_addr=0x%x, ctrlParam_addr=0x%x, outPicBuff_addr=0x%x, picInfo_addr=0x%x)", handle, inPicBuff.addr(), ctrlParam.addr(), outPicBuff.addr(), picInfo.addr()); - VpostInstance* vpost; + std::shared_ptr vpost; if (!Emu.GetIdManager().GetIDData(handle, vpost)) { return CELL_VPOST_ERROR_E_ARG_HDL_INVALID; diff --git a/rpcs3/Emu/SysCalls/Modules/libmixer.cpp b/rpcs3/Emu/SysCalls/Modules/libmixer.cpp index bd7527c5cf..21646f4d1c 100644 --- a/rpcs3/Emu/SysCalls/Modules/libmixer.cpp +++ b/rpcs3/Emu/SysCalls/Modules/libmixer.cpp @@ -347,7 +347,7 @@ int cellSurMixerCreate(vm::ptr config) if (mixcount > (port.tag + 0)) // adding positive value (1-15): preemptive buffer filling (hack) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack continue; } diff --git a/rpcs3/Emu/SysCalls/Modules/sceNp.cpp b/rpcs3/Emu/SysCalls/Modules/sceNp.cpp index e9d7b4fd0a..a05edc415c 100644 --- a/rpcs3/Emu/SysCalls/Modules/sceNp.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sceNp.cpp @@ -2,6 +2,7 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/SysCalls/Modules.h" +#include "Emu/SysCalls/lv2/sys_process.h" #include "Emu/FS/VFS.h" #include "Utilities/rFile.h" @@ -112,20 +113,19 @@ int npDrmIsAvailable(u32 k_licensee_addr, vm::ptr drm_path) std::string enc_drm_path = drm_path.get_ptr(); std::string dec_drm_path = "/dev_hdd1/cache/" + drm_file_name; std::string pf_str("00000001"); // TODO: Allow multiple profiles. Use default for now. - std::string rap_path("../dev_hdd0/home/" + pf_str + "/exdata/"); + std::string rap_path("/dev_hdd0/home/" + pf_str + "/exdata/"); // Search dev_usb000 for a compatible RAP file. - vfsDir *raps_dir = new vfsDir(rap_path); - if (!raps_dir->IsOpened()) + vfsDir raps_dir(rap_path); + if (!raps_dir.IsOpened()) sceNp->Warning("npDrmIsAvailable: Can't find RAP file for DRM!"); else { - const std::vector &entries = raps_dir->GetEntries(); - for (auto &entry : entries) + for (const DirEntryInfo *entry : raps_dir) { - if (entry.name.find(titleID) != std::string::npos) + if (entry->name.find(titleID) != std::string::npos) { - rap_path += entry.name; + rap_path += entry->name; break; } } @@ -187,15 +187,35 @@ int sceNpDrmGetTimelimit(u32 drm_path_addr, vm::ptr time_remain_usec) return CELL_OK; } -int sceNpDrmProcessExitSpawn() +int sceNpDrmProcessExitSpawn(vm::ptr path, u32 argv_addr, u32 envp_addr, u32 data_addr, u32 data_size, u32 prio, u64 flags) { - UNIMPLEMENTED_FUNC(sceNp); + sceNp->Warning("sceNpDrmProcessExitSpawn()"); + sceNp->Warning("path: %s", path.get_ptr()); + sceNp->Warning("argv: 0x%x", argv_addr); + sceNp->Warning("envp: 0x%x", envp_addr); + sceNp->Warning("data: 0x%x", data_addr); + sceNp->Warning("data_size: 0x%x", data_size); + sceNp->Warning("prio: %d", prio); + sceNp->Warning("flags: %d", flags); + + sys_game_process_exitspawn(path, argv_addr, envp_addr, data_addr, data_size, prio, flags); + return CELL_OK; } -int sceNpDrmProcessExitSpawn2() +int sceNpDrmProcessExitSpawn2(vm::ptr path, u32 argv_addr, u32 envp_addr, u32 data_addr, u32 data_size, u32 prio, u64 flags) { - UNIMPLEMENTED_FUNC(sceNp); + sceNp->Warning("sceNpDrmProcessExitSpawn2()"); + sceNp->Warning("path: %s", path.get_ptr()); + sceNp->Warning("argv: 0x%x", argv_addr); + sceNp->Warning("envp: 0x%x", envp_addr); + sceNp->Warning("data: 0x%x", data_addr); + sceNp->Warning("data_size: 0x%x", data_size); + sceNp->Warning("prio: %d", prio); + sceNp->Warning("flags: %d", flags); + + sys_game_process_exitspawn2(path, argv_addr, envp_addr, data_addr, data_size, prio, flags); + return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp index 987877493f..faf91a529f 100644 --- a/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp +++ b/rpcs3/Emu/SysCalls/Modules/sysPrxForUser.cpp @@ -3,8 +3,10 @@ #include "Emu/System.h" #include "Emu/SysCalls/Modules.h" #include "Emu/SysCalls/CB_FUNC.h" +#include "Emu/Memory/atomic_type.h" #include "Emu/FS/vfsFile.h" +#include "Emu/SysCalls/lv2/sleep_queue_type.h" #include "Emu/SysCalls/lv2/sys_spu.h" #include "Emu/SysCalls/lv2/sys_lwmutex.h" #include "Emu/SysCalls/lv2/sys_spinlock.h" @@ -30,7 +32,8 @@ int _sys_heap_create_heap(const u32 heap_addr, const u32 align, const u32 size) { sysPrxForUser->Warning("_sys_heap_create_heap(heap_addr=0x%x, align=0x%x, size=0x%x)", heap_addr, align, size); - u32 heap_id = sysPrxForUser->GetNewId(new HeapInfo(heap_addr, align, size)); + std::shared_ptr heap(new HeapInfo(heap_addr, align, size)); + u32 heap_id = sysPrxForUser->GetNewId(heap); sysPrxForUser->Warning("*** sys_heap created: id = %d", heap_id); return heap_id; } @@ -39,7 +42,7 @@ u32 _sys_heap_malloc(const u32 heap_id, const u32 size) { sysPrxForUser->Warning("_sys_heap_malloc(heap_id=%d, size=0x%x)", heap_id, size); - HeapInfo* heap; + std::shared_ptr heap; if(!sysPrxForUser->CheckId(heap_id, heap)) return CELL_ESRCH; return (u32)Memory.Alloc(size, 1); @@ -49,7 +52,7 @@ u32 _sys_heap_memalign(u32 heap_id, u32 align, u32 size) { sysPrxForUser->Warning("_sys_heap_memalign(heap_id=%d, align=0x%x, size=0x%x)", heap_id, align, size); - HeapInfo* heap; + std::shared_ptr heap; if(!sysPrxForUser->CheckId(heap_id, heap)) return CELL_ESRCH; return (u32)Memory.Alloc(size, align); diff --git a/rpcs3/Emu/SysCalls/Modules/sys_fs.cpp b/rpcs3/Emu/SysCalls/Modules/sys_fs.cpp deleted file mode 100644 index 46e255925d..0000000000 --- a/rpcs3/Emu/SysCalls/Modules/sys_fs.cpp +++ /dev/null @@ -1,347 +0,0 @@ -#include "stdafx.h" -#include "Emu/Memory/Memory.h" -#include "Emu/System.h" -#include "Emu/SysCalls/Modules.h" -#include "Emu/SysCalls/Callback.h" -#include "Emu/SysCalls/CB_FUNC.h" - -#include "Emu/FS/VFS.h" -#include "Emu/FS/vfsFileBase.h" -#include "Emu/SysCalls/lv2/lv2Fs.h" - -Module *sys_fs = nullptr; - -bool sdata_check(u32 version, u32 flags, u64 filesizeInput, u64 filesizeTmp) -{ - if (version > 4 || flags & 0x7EFFFFC0){ - printf("ERROR: unknown version"); - return false; - } - - if ((version == 1 && (flags & 0x7FFFFFFE)) || - (version == 2 && (flags & 0x7EFFFFC0))){ - printf("ERROR: unknown or unsupported type"); - return false; - } - - if (filesizeTmp > filesizeInput){ - printf("ERROR: input file size is too short."); - return false; - } - - if (!(flags & 0x80000000)){ - printf("ERROR: cannot extract finalized edata."); - return false; - } - - return true; -} - -int sdata_unpack(const std::string& packed_file, const std::string& unpacked_file) -{ - std::shared_ptr packed_stream(Emu.GetVFS().OpenFile(packed_file, vfsRead)); - std::shared_ptr unpacked_stream(Emu.GetVFS().OpenFile(unpacked_file, vfsWrite)); - - if(!packed_stream || !packed_stream->IsOpened()) - { - sys_fs->Error("'%s' not found! flags: 0x%08x", packed_file.c_str(), vfsRead); - return CELL_ENOENT; - } - - if(!unpacked_stream || !unpacked_stream->IsOpened()) - { - sys_fs->Error("'%s' couldn't be created! flags: 0x%08x", unpacked_file.c_str(), vfsWrite); - return CELL_ENOENT; - } - - char buffer [10200]; - packed_stream->Read(buffer, 256); - u32 format = re32(*(u32*)&buffer[0]); - if (format != 0x4E504400) // "NPD\x00" - { - sys_fs->Error("Illegal format. Expected 0x4E504400, but got 0x%08x", format); - return CELL_EFSSPECIFIC; - } - - u32 version = re32(*(u32*)&buffer[0x04]); - u32 flags = re32(*(u32*)&buffer[0x80]); - u32 blockSize = re32(*(u32*)&buffer[0x84]); - u64 filesizeOutput = re64(*(u64*)&buffer[0x88]); - u64 filesizeInput = packed_stream->GetSize(); - u32 blockCount = (u32)((filesizeOutput + blockSize - 1) / blockSize); - - // SDATA file is compressed - if (flags & 0x1) - { - sys_fs->Warning("cellFsSdataOpen: Compressed SDATA files are not supported yet."); - return CELL_EFSSPECIFIC; - } - - // SDATA file is NOT compressed - else - { - u32 t1 = (flags & 0x20) ? 0x20 : 0x10; - u32 startOffset = (blockCount * t1) + 0x100; - u64 filesizeTmp = (filesizeOutput+0xF)&0xFFFFFFF0 + startOffset; - - if (!sdata_check(version, flags, filesizeInput, filesizeTmp)) - { - sys_fs->Error("cellFsSdataOpen: Wrong header information."); - return CELL_EFSSPECIFIC; - } - - if (flags & 0x20) - packed_stream->Seek(0x100); - else - packed_stream->Seek(startOffset); - - for (u32 i = 0; i < blockCount; i++) - { - if (flags & 0x20) - packed_stream->Seek(packed_stream->Tell() + t1); - - if (!(blockCount-i-1)) - blockSize = (u32)(filesizeOutput - i * blockSize); - - packed_stream->Read(buffer+256, blockSize); - unpacked_stream->Write(buffer+256, blockSize); - } - } - - return CELL_OK; -} - - -int cellFsSdataOpen(vm::ptr path, int flags, vm::ptr> fd, vm::ptr arg, u64 size) -{ - sys_fs->Warning("cellFsSdataOpen(path=\"%s\", flags=0x%x, fd_addr=0x%x, arg_addr=0x%x, size=0x%llx) -> cellFsOpen()", - path.get_ptr(), flags, fd.addr(), arg.addr(), size); - - /*if (flags != CELL_O_RDONLY) - return CELL_EINVAL; - - std::string suffix = path.substr(path.length() - 5, 5); - if (suffix != ".sdat" && suffix != ".SDAT") - return CELL_ENOTSDATA; - - std::string::size_type last_slash = path.rfind('/'); //TODO: use a filesystem library to solve this more robustly - last_slash = last_slash == std::string::npos ? 0 : last_slash+1; - std::string unpacked_path = "/dev_hdd1/"+path.substr(last_slash,path.length()-last_slash)+".unpacked"; - int ret = sdata_unpack(path, unpacked_path); - if (ret) return ret; - - fd = sys_fs->GetNewId(Emu.GetVFS().OpenFile(unpacked_path, vfsRead), TYPE_FS_FILE); - - return CELL_OK;*/ - - return cellFsOpen(path, flags, fd, arg, size); -} - -int cellFsSdataOpenByFd(int mself_fd, int flags, vm::ptr sdata_fd, u64 offset, vm::ptr arg, u64 size) -{ - sys_fs->Todo("cellFsSdataOpenByFd(mself_fd=0x%x, flags=0x%x, sdata_fd_addr=0x%x, offset=0x%llx, arg_addr=0x%x, size=0x%llx) -> cellFsOpen()", - mself_fd, flags, sdata_fd.addr(), offset, arg.addr(), size); - - // TODO: - - return CELL_OK; -} - -std::atomic g_FsAioReadID( 0 ); -std::atomic g_FsAioReadCur( 0 ); -bool aio_init = false; - -void fsAioRead(u32 fd, vm::ptr aio, int xid, vm::ptr xaio, int error, int xid, u64 size)> func) -{ - while (g_FsAioReadCur != xid) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - if (Emu.IsStopped()) - { - sys_fs->Warning("fsAioRead() aborted"); - return; - } - } - - u32 error = CELL_OK; - u64 res = 0; - { - LV2_LOCK(0); - - vfsFileBase* orig_file; - if (!sys_fs->CheckId(fd, orig_file)) - { - sys_fs->Error("Wrong fd (%s)", fd); - Emu.Pause(); - return; - } - - u64 nbytes = aio->size; - - vfsStream& file = *(vfsStream*)orig_file; - const u64 old_pos = file.Tell(); - file.Seek((u64)aio->offset); - - // TODO: use code from cellFsRead or something - if (nbytes != (u32)nbytes) - { - error = CELL_ENOMEM; - } - else - { - res = nbytes ? file.Read(aio->buf.get_ptr(), nbytes) : 0; - } - - file.Seek(old_pos); - - sys_fs->Log("*** fsAioRead(fd=%d, offset=0x%llx, buf_addr=0x%x, size=0x%x, error=0x%x, res=0x%x, xid=0x%x [%s])", - fd, (u64)aio->offset, aio->buf.addr(), (u64)aio->size, error, res, xid, orig_file->GetPath().c_str()); - } - - if (func) // start callback thread - { - Emu.GetCallbackManager().Async([func, aio, error, xid, res]() - { - func(aio, error, xid, res); - }); - } - - g_FsAioReadCur++; -} - -int cellFsAioRead(vm::ptr aio, vm::ptr aio_id, vm::ptr xaio, int error, int xid, u64 size)> func) -{ - sys_fs->Warning("cellFsAioRead(aio_addr=0x%x, id_addr=0x%x, func_addr=0x%x)", aio.addr(), aio_id.addr(), func.addr()); - - LV2_LOCK(0); - - if (!aio_init) - { - return CELL_ENXIO; - } - - vfsFileBase* orig_file; - u32 fd = aio->fd; - - if (!sys_fs->CheckId(fd, orig_file)) - { - return CELL_EBADF; - } - - //get a unique id for the callback (may be used by cellFsAioCancel) - const u32 xid = g_FsAioReadID++; - *aio_id = xid; - - { - thread t("fsAioRead", std::bind(fsAioRead, fd, aio, xid, func)); - t.detach(); - } - - return CELL_OK; -} - -int cellFsAioWrite(vm::ptr aio, vm::ptr aio_id, vm::ptr xaio, int error, int xid, u64 size)> func) -{ - sys_fs->Todo("cellFsAioWrite(aio_addr=0x%x, id_addr=0x%x, func_addr=0x%x)", aio.addr(), aio_id.addr(), func.addr()); - - LV2_LOCK(0); - - // TODO: - - return CELL_OK; -} - -int cellFsAioInit(vm::ptr mount_point) -{ - sys_fs->Warning("cellFsAioInit(mount_point_addr=0x%x (%s))", mount_point.addr(), mount_point.get_ptr()); - - LV2_LOCK(0); - - aio_init = true; - return CELL_OK; -} - -int cellFsAioFinish(vm::ptr mount_point) -{ - sys_fs->Warning("cellFsAioFinish(mount_point_addr=0x%x (%s))", mount_point.addr(), mount_point.get_ptr()); - - LV2_LOCK(0); - - aio_init = false; - return CELL_OK; -} - -int cellFsReadWithOffset(u32 fd, u64 offset, vm::ptr buf, u64 buffer_size, vm::ptr> nread) -{ - sys_fs->Warning("cellFsReadWithOffset(fd=%d, offset=0x%llx, buf_addr=0x%x, buffer_size=%lld nread=0x%llx)", - fd, offset, buf.addr(), buffer_size, nread.addr()); - - LV2_LOCK(0); - - int ret; - vm::var> oldPos, newPos; - ret = cellFsLseek(fd, 0, CELL_SEEK_CUR, oldPos); // Save the current position - if (ret) return ret; - ret = cellFsLseek(fd, offset, CELL_SEEK_SET, newPos); // Move to the specified offset - if (ret) return ret; - ret = cellFsRead(fd, buf, buffer_size, nread); // Read the file - if (ret) return ret; - ret = cellFsLseek(fd, oldPos.value(), CELL_SEEK_SET, newPos); // Return to the old position - if (ret) return ret; - - return CELL_OK; -} - -void sys_fs_init(Module *pxThis) -{ - sys_fs = pxThis; - - sys_fs->AddFunc(0x718bf5f8, cellFsOpen); - sys_fs->AddFunc(0xb1840b53, cellFsSdataOpen); - sys_fs->AddFunc(0x6d3bb15b, cellFsSdataOpenByFd); - sys_fs->AddFunc(0x4d5ff8e2, cellFsRead); - sys_fs->AddFunc(0xecdcf2ab, cellFsWrite); - sys_fs->AddFunc(0x2cb51f0d, cellFsClose); - sys_fs->AddFunc(0x3f61245c, cellFsOpendir); - sys_fs->AddFunc(0x5c74903d, cellFsReaddir); - sys_fs->AddFunc(0xff42dcc3, cellFsClosedir); - sys_fs->AddFunc(0x7de6dced, cellFsStat); - sys_fs->AddFunc(0xef3efa34, cellFsFstat); - sys_fs->AddFunc(0xba901fe6, cellFsMkdir); - sys_fs->AddFunc(0xf12eecc8, cellFsRename); - sys_fs->AddFunc(0x99406d0b, cellFsChmod); - sys_fs->AddFunc(0x967a162b, cellFsFsync); - sys_fs->AddFunc(0x2796fdf3, cellFsRmdir); - sys_fs->AddFunc(0x7f4677a8, cellFsUnlink); - sys_fs->AddFunc(0xa397d042, cellFsLseek); - sys_fs->AddFunc(0x0e2939e5, cellFsFtruncate); - sys_fs->AddFunc(0xc9dc3ac5, cellFsTruncate); - sys_fs->AddFunc(0xcb588dba, cellFsFGetBlockSize); - sys_fs->AddFunc(0xc1c507e7, cellFsAioRead); - sys_fs->AddFunc(0x4cef342e, cellFsAioWrite); - sys_fs->AddFunc(0xdb869f20, cellFsAioInit); - sys_fs->AddFunc(0x9f951810, cellFsAioFinish); - sys_fs->AddFunc(0x1a108ab7, cellFsGetBlockSize); - sys_fs->AddFunc(0xaa3b4bcd, cellFsGetFreeSize); - sys_fs->AddFunc(0x0d5b4a14, cellFsReadWithOffset); - sys_fs->AddFunc(0x9b882495, cellFsGetDirectoryEntries); - sys_fs->AddFunc(0x2664c8ae, cellFsStReadInit); - sys_fs->AddFunc(0xd73938df, cellFsStReadFinish); - sys_fs->AddFunc(0xb3afee8b, cellFsStReadGetRingBuf); - sys_fs->AddFunc(0xcf34969c, cellFsStReadGetStatus); - sys_fs->AddFunc(0xbd273a88, cellFsStReadGetRegid); - sys_fs->AddFunc(0x8df28ff9, cellFsStReadStart); - sys_fs->AddFunc(0xf8e5d9a0, cellFsStReadStop); - sys_fs->AddFunc(0x27800c6b, cellFsStRead); - sys_fs->AddFunc(0x190912f6, cellFsStReadGetCurrentAddr); - sys_fs->AddFunc(0x81f33783, cellFsStReadPutCurrentAddr); - sys_fs->AddFunc(0x8f71c5b2, cellFsStReadWait); - sys_fs->AddFunc(0x866f6aec, cellFsStReadWaitCallback); -} - -void sys_fs_load() -{ - g_FsAioReadID = 0; - g_FsAioReadCur = 0; - aio_init = false; -} diff --git a/rpcs3/Emu/SysCalls/Static.cpp b/rpcs3/Emu/SysCalls/Static.cpp index 9ea47550cb..677b32c970 100644 --- a/rpcs3/Emu/SysCalls/Static.cpp +++ b/rpcs3/Emu/SysCalls/Static.cpp @@ -85,7 +85,7 @@ void StaticFuncManager::StaticAnalyse(void* ptr, u32 size, u32 base) LOG_NOTICE(LOADER, "Function '%s' hooked (addr=0x%x)", m_static_funcs_list[j]->name, i * 4 + base); m_static_funcs_list[j]->found++; data[i+0] = re32(0x39600000 | j); // li r11, j - data[i+1] = se32(0x44000003); // sc 3 + data[i+1] = se32(0x44000042); // sc 2 data[i+2] = se32(0x4e800020); // blr i += 2; // skip modified code } diff --git a/rpcs3/Emu/SysCalls/SyncPrimitivesManager.cpp b/rpcs3/Emu/SysCalls/SyncPrimitivesManager.cpp new file mode 100644 index 0000000000..349e9782fe --- /dev/null +++ b/rpcs3/Emu/SysCalls/SyncPrimitivesManager.cpp @@ -0,0 +1,75 @@ +#include "stdafx.h" +#include "Utilities/Log.h" +#include "Emu/System.h" +#include "Emu/IdManager.h" +#include "Utilities/Thread.h" + +#include "lv2/sleep_queue_type.h" +#include "lv2/sys_lwmutex.h" +#include "lv2/sys_lwcond.h" +#include "lv2/sys_mutex.h" +#include "lv2/sys_cond.h" +#include "lv2/sys_semaphore.h" +#include "SyncPrimitivesManager.h" + +SemaphoreAttributes SyncPrimManager::GetSemaphoreData(u32 id) +{ + std::shared_ptr sem; + if (!Emu.GetIdManager().GetIDData(id, sem)) + { + return{}; + } + + return{ std::string((const char*)&sem->name, 8), sem->value.read_sync(), sem->max }; +} + +LwMutexAttributes SyncPrimManager::GetLwMutexData(u32 id) +{ + std::shared_ptr sq; + if (!Emu.GetIdManager().GetIDData(id, sq)) + { + return{}; + } + + return{ std::string((const char*)&sq->name, 8) }; +} + +std::string SyncPrimManager::GetSyncPrimName(u32 id, IDType type) +{ + switch (type) + { + case TYPE_LWCOND: + { + std::shared_ptr lw; + if (Emu.GetIdManager().GetIDData(id, lw)) + { + return std::string((const char*)&lw->queue.name, 8); + } + break; + } + + case TYPE_MUTEX: + { + std::shared_ptr mutex; + if (Emu.GetIdManager().GetIDData(id, mutex)) + { + return std::string((const char*)&mutex->queue.name, 8); + } + break; + } + + case TYPE_COND: + { + std::shared_ptr cond; + if (Emu.GetIdManager().GetIDData(id, cond)) + { + return std::string((const char*)&cond->queue.name, 8); + } + break; + } + default: break; + } + + LOG_ERROR(GENERAL, "SyncPrimManager::GetSyncPrimName(id=%d, type=%d) failed", id, type); + return "NOT_FOUND"; +} diff --git a/rpcs3/Emu/SysCalls/SyncPrimitivesManager.h b/rpcs3/Emu/SysCalls/SyncPrimitivesManager.h index 97110e2a50..34f20c05f8 100644 --- a/rpcs3/Emu/SysCalls/SyncPrimitivesManager.h +++ b/rpcs3/Emu/SysCalls/SyncPrimitivesManager.h @@ -1,119 +1,27 @@ #pragma once -#include -#include "Emu/System.h" -#include "Emu/IdManager.h" -#include "Utilities/Log.h" - struct SemaphoreAttributes { std::string name; - u32 count; - u32 max_count; - - SemaphoreAttributes() {} - SemaphoreAttributes(const std::string& _name, u32 _count, u32 _max_count) : name(_name), count(_count), max_count(_max_count) {} + s32 count; + s32 max_count; }; struct LwMutexAttributes { std::string name; - u32 owner_id; - std::string status; // TODO: check status? - - LwMutexAttributes() {} - LwMutexAttributes(const std::string& _name, u32 _owner_id, std::string _status = "INITIALIZED") - : name(_name), owner_id(_owner_id), status(_status) {} }; class SyncPrimManager { private: - std::map m_cond_name; - std::map m_mutex_name; - std::map m_lw_cond_name; - std::map m_lw_mutex_attr; - std::map m_semaph_attr; public: - - // semaphores - void AddSemaphoreData(const u32 id, const std::string& name, const u32 count, const u32 max_count) - { - m_semaph_attr[id] = *(new SemaphoreAttributes(name, count, max_count)); - } - - void EraseSemaphoreData(const u32 id) - { - m_semaph_attr.erase(id); - } - - SemaphoreAttributes& GetSemaphoreData(const u32 id) - { - return m_semaph_attr[id]; - } - - // lw_mutexes - void AddLwMutexData(const u32 id, const std::string& name, const u32 owner_id) - { - m_lw_mutex_attr[id] = *(new LwMutexAttributes(name, owner_id)); - } - - void EraseLwMutexData(const u32 id) - { - m_lw_mutex_attr.erase(id); - } - - LwMutexAttributes& GetLwMutexData(const u32 id) - { - return m_lw_mutex_attr[id]; - } - - // lw_conditions, mutexes, conditions - void AddSyncPrimData(const IDType type, const u32 id, const std::string& name) - { - switch (type) - { - case TYPE_LWCOND: m_lw_cond_name[id] = name; break; - case TYPE_MUTEX: m_mutex_name[id] = name; break; - case TYPE_COND: m_cond_name[id] = name; break; - - default: LOG_ERROR(GENERAL, "Unknown IDType = %d", type); - } - } - - void EraseSyncPrimData(const IDType type, const u32 id) - { - switch (type) - { - case TYPE_LWCOND: m_lw_cond_name.erase(id); break; - case TYPE_MUTEX: m_mutex_name.erase(id); break; - case TYPE_COND: m_cond_name.erase(id); break; - - default: LOG_ERROR(GENERAL, "Unknown IDType = %d", type); - } - } - - const std::string& GetSyncPrimName(const IDType type, const u32 id) - { - static const std::string empty = ""; - - switch (type) - { - case TYPE_LWCOND: return m_lw_cond_name[id]; - case TYPE_MUTEX: return m_mutex_name[id]; - case TYPE_COND: return m_cond_name[id]; - - default: LOG_ERROR(GENERAL, "Unknown IDType = %d", type); return empty; - } - } + SemaphoreAttributes GetSemaphoreData(u32 id); + LwMutexAttributes GetLwMutexData(u32 id); + std::string GetSyncPrimName(u32 id, IDType type); void Close() { - m_cond_name.clear(); - m_mutex_name.clear(); - m_lw_cond_name.clear(); - m_lw_mutex_attr.clear(); - m_semaph_attr.clear(); } }; \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/SysCalls.cpp b/rpcs3/Emu/SysCalls/SysCalls.cpp index af6777ecff..3a76026cf7 100644 --- a/rpcs3/Emu/SysCalls/SysCalls.cpp +++ b/rpcs3/Emu/SysCalls/SysCalls.cpp @@ -5,8 +5,12 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "ModuleManager.h" +#include "Emu/Memory/atomic_type.h" -#include "lv2/lv2Fs.h" +#include "lv2/cellFs.h" +#include "lv2/sleep_queue_type.h" +#include "lv2/sys_lwmutex.h" +#include "lv2/sys_mutex.h" #include "lv2/sys_cond.h" #include "lv2/sys_event.h" #include "lv2/sys_event_flag.h" @@ -30,8 +34,9 @@ #include "SysCalls.h" -namespace detail{ - template<> bool CheckId(u32 id, ID*& _id,const std::string &name) +namespace detail +{ + bool CheckIdID(u32 id, ID*& _id, const std::string &name) { return Emu.GetIdManager().CheckID(id) && (_id = &Emu.GetIdManager().GetID(id))->GetName() == name; } @@ -135,11 +140,11 @@ static func_caller* sc_table[kSyscallTableLength] = bind_func(sys_semaphore_wait), //92 (0x05C) bind_func(sys_semaphore_trywait), //93 (0x05D) bind_func(sys_semaphore_post), //94 (0x05E) - null_func,//bind_func(sys_lwmutex_create), //95 (0x05F) // internal, used by sys_lwmutex_create - null_func,//bind_func(sys_lwmutex_destroy), //96 (0x060) // internal, used by sys_lwmutex_destroy - null_func,//bind_func(sys_lwmutex_lock), //97 (0x061) // internal, used by sys_lwmutex_lock - null_func,//bind_func(sys_lwmutex_trylock), //98 (0x062) // internal, used by sys_lwmutex_unlock - null_func,//bind_func(sys_lwmutex_unlock), //99 (0x063) // internal, used by sys_lwmutex_trylock + null_func,//bind_func(_sys_lwmutex_create), //95 (0x05F) // internal, used by sys_lwmutex_create + null_func,//bind_func(_sys_lwmutex_destroy), //96 (0x060) // internal, used by sys_lwmutex_destroy + null_func,//bind_func(_sys_lwmutex_lock), //97 (0x061) // internal, used by sys_lwmutex_lock + null_func,//bind_func(_sys_lwmutex_???lock), //98 (0x062) // internal, used by sys_lwmutex_unlock + null_func,//bind_func(_sys_lwmutex_???lock), //99 (0x063) // internal, used by sys_lwmutex_trylock bind_func(sys_mutex_create), //100 (0x064) bind_func(sys_mutex_destroy), //101 (0x065) bind_func(sys_mutex_lock), //102 (0x066) @@ -151,9 +156,9 @@ static func_caller* sc_table[kSyscallTableLength] = bind_func(sys_cond_signal), //108 (0x06C) bind_func(sys_cond_signal_all), //109 (0x06D) bind_func(sys_cond_signal_to), //110 (0x06E) - null_func,//bind_func(sys_lwcond_create) //111 (0x06F) // internal, used by sys_lwcond_create - null_func,//bind_func(sys_lwcond_destroy) //112 (0x070) // internal, used by sys_lwcond_destroy - null_func,//bind_func(sys_lwcond_queue_wait) //113 (0x071) // internal, used by sys_lwcond_wait + null_func,//bind_func(_sys_lwcond_create) //111 (0x06F) // internal, used by sys_lwcond_create + null_func,//bind_func(_sys_lwcond_destroy) //112 (0x070) // internal, used by sys_lwcond_destroy + null_func,//bind_func(_sys_lwcond_queue_wait) //113 (0x071) // internal, used by sys_lwcond_wait bind_func(sys_semaphore_get_value), //114 (0x072) null_func,//bind_func(sys_semaphore_...) //115 (0x073) // internal, used by sys_lwcond_signal, sys_lwcond_signal_to null_func,//bind_func(sys_semaphore_...) //116 (0x074) // internal, used by sys_lwcond_signal_all diff --git a/rpcs3/Emu/SysCalls/SysCalls.h b/rpcs3/Emu/SysCalls/SysCalls.h index f01e33ed14..5cf99e50cd 100644 --- a/rpcs3/Emu/SysCalls/SysCalls.h +++ b/rpcs3/Emu/SysCalls/SysCalls.h @@ -7,16 +7,17 @@ class SysCallBase; -namespace detail{ - template bool CheckId(u32 id, T*& data,const std::string &name) +namespace detail +{ + bool CheckIdID(u32 id, ID*& _id, const std::string& name); + + template bool CheckId(u32 id, std::shared_ptr& data, const std::string& name) { ID* id_data; - if(!CheckId(id, id_data,name)) return false; + if(!CheckIdID(id, id_data, name)) return false; data = id_data->GetData()->get(); return true; } - - template<> bool CheckId(u32 id, ID*& _id,const std::string &name); } class SysCallBase : public LogBase @@ -44,13 +45,13 @@ public: } template - bool CheckId(u32 id, T*& data) const + bool CheckId(u32 id, std::shared_ptr& data) const { - return detail::CheckId(id,data,GetName()); + return detail::CheckId(id, data, GetName()); } template - u32 GetNewId(T* data, IDType type = TYPE_OTHER) + u32 GetNewId(std::shared_ptr& data, IDType type = TYPE_OTHER) { return GetIdManager().GetNewID(GetName(), data, type); } diff --git a/rpcs3/Emu/SysCalls/lv2/lv2Fs.cpp b/rpcs3/Emu/SysCalls/lv2/cellFs.cpp similarity index 57% rename from rpcs3/Emu/SysCalls/lv2/lv2Fs.cpp rename to rpcs3/Emu/SysCalls/lv2/cellFs.cpp index 6a67a2c334..60e09c82fc 100644 --- a/rpcs3/Emu/SysCalls/lv2/lv2Fs.cpp +++ b/rpcs3/Emu/SysCalls/lv2/cellFs.cpp @@ -1,15 +1,24 @@ #include "stdafx.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" -//#include "Emu/SysCalls/SysCalls.h" - #include "Emu/SysCalls/Modules.h" +#include "Emu/SysCalls/Callback.h" +#include "Emu/SysCalls/CB_FUNC.h" + +#ifdef _WIN32 + #include + #undef CreateFile +#else + #include + #include +#endif + #include "Emu/FS/VFS.h" #include "Emu/FS/vfsFile.h" #include "Emu/FS/vfsDir.h" -#include "lv2Fs.h" +#include "cellFs.h" -extern Module *sys_fs; +Module *sys_fs = nullptr; struct FsRingBufferConfig { @@ -37,8 +46,6 @@ s32 cellFsOpen(vm::ptr path, s32 flags, vm::ptr> fd, vm::p const std::string _path = path.get_ptr(); - LV2_LOCK(0); - s32 _oflags = flags; if (flags & CELL_O_CREAT) { @@ -100,11 +107,10 @@ s32 cellFsOpen(vm::ptr path, s32 flags, vm::ptr> fd, vm::p return CELL_ENOENT; } - vfsFileBase* stream = Emu.GetVFS().OpenFile(_path, o_mode); + std::shared_ptr stream((vfsStream*)Emu.GetVFS().OpenFile(_path, o_mode)); if (!stream || !stream->IsOpened()) { - delete stream; sys_fs->Error("\"%s\" not found! flags: 0x%08x", path.get_ptr(), flags); return CELL_ENOENT; } @@ -121,9 +127,7 @@ s32 cellFsRead(u32 fd, vm::ptr buf, u64 nbytes, vm::ptr> nread) sys_fs->Log("cellFsRead(fd=%d, buf_addr=0x%x, nbytes=0x%llx, nread_addr=0x%x)", fd, buf.addr(), nbytes, nread.addr()); - LV2_LOCK(0); - - vfsStream* file; + std::shared_ptr file; if (!sys_fs->CheckId(fd, file)) return CELL_ESRCH; @@ -144,9 +148,7 @@ s32 cellFsWrite(u32 fd, vm::ptr buf, u64 nbytes, vm::ptr nwrite sys_fs->Log("cellFsWrite(fd=%d, buf_addr=0x%x, nbytes=0x%llx, nwrite_addr=0x%x)", fd, buf.addr(), nbytes, nwrite.addr()); - LV2_LOCK(0); - - vfsStream* file; + std::shared_ptr file; if (!sys_fs->CheckId(fd, file)) return CELL_ESRCH; if (nbytes != (u32)nbytes) return CELL_ENOMEM; @@ -164,8 +166,6 @@ s32 cellFsClose(u32 fd) { sys_fs->Warning("cellFsClose(fd=%d)", fd); - LV2_LOCK(0); - if (!Emu.GetIdManager().RemoveID(fd)) return CELL_ESRCH; @@ -175,13 +175,10 @@ s32 cellFsClose(u32 fd) s32 cellFsOpendir(vm::ptr path, vm::ptr fd) { sys_fs->Warning("cellFsOpendir(path=\"%s\", fd_addr=0x%x)", path.get_ptr(), fd.addr()); - - LV2_LOCK(0); - vfsDirBase* dir = Emu.GetVFS().OpenDir(path.get_ptr()); + std::shared_ptr dir(Emu.GetVFS().OpenDir(path.get_ptr())); if (!dir || !dir->IsOpened()) { - delete dir; return CELL_ENOENT; } @@ -193,9 +190,7 @@ s32 cellFsReaddir(u32 fd, vm::ptr dir, vm::ptr nread) { sys_fs->Warning("cellFsReaddir(fd=%d, dir_addr=0x%x, nread_addr=0x%x)", fd, dir.addr(), nread.addr()); - LV2_LOCK(0); - - vfsDirBase* directory; + std::shared_ptr directory; if (!sys_fs->CheckId(fd, directory)) return CELL_ESRCH; @@ -219,8 +214,6 @@ s32 cellFsClosedir(u32 fd) { sys_fs->Warning("cellFsClosedir(fd=%d)", fd); - LV2_LOCK(0); - if (!Emu.GetIdManager().RemoveID(fd)) return CELL_ESRCH; @@ -231,20 +224,50 @@ s32 cellFsStat(vm::ptr path, vm::ptr sb) { sys_fs->Warning("cellFsStat(path=\"%s\", sb_addr=0x%x)", path.get_ptr(), sb.addr()); - LV2_LOCK(0); - const std::string _path = path.get_ptr(); + u32 mode = 0; + s32 uid = 0; + s32 gid = 0; + u64 atime = 0; + u64 mtime = 0; + u64 ctime = 0; + u64 size = 0; + + std::string real_path; + + Emu.GetVFS().GetDevice(_path, real_path); + + struct stat buf; + + if (int result = stat(real_path.c_str(), &buf)) + { + sys_fs->Error("stat('%s') failed -> 0x%x", real_path.c_str(), result); + } + else + { + mode = buf.st_mode; + uid = buf.st_uid; + gid = buf.st_gid; + atime = buf.st_atime; + mtime = buf.st_mtime; + ctime = buf.st_ctime; + size = buf.st_size; + } + sb->st_mode = CELL_FS_S_IRUSR | CELL_FS_S_IWUSR | CELL_FS_S_IXUSR | CELL_FS_S_IRGRP | CELL_FS_S_IWGRP | CELL_FS_S_IXGRP | CELL_FS_S_IROTH | CELL_FS_S_IWOTH | CELL_FS_S_IXOTH; - sb->st_uid = 0; - sb->st_gid = 0; - sb->st_atime_ = 0; //TODO - sb->st_mtime_ = 0; //TODO - sb->st_ctime_ = 0; //TODO + if (sb->st_mode == mode) + sys_fs->Error("Mode is the same. Report this to a RPCS3 developer! (%d)", mode); + + sb->st_uid = uid; + sb->st_gid = gid; + sb->st_atime_ = atime; + sb->st_mtime_ = mtime; + sb->st_ctime_ = ctime; sb->st_blksize = 4096; { @@ -266,6 +289,9 @@ s32 cellFsStat(vm::ptr path, vm::ptr sb) } } + if (sb->st_size == size && size != 0) + sys_fs->Error("Size is the same. Report this to a RPCS3 developer! (%d)", size); + sys_fs->Warning("cellFsStat: \"%s\" not found.", path.get_ptr()); return CELL_ENOENT; } @@ -274,10 +300,8 @@ s32 cellFsFstat(u32 fd, vm::ptr sb) { sys_fs->Warning("cellFsFstat(fd=%d, sb_addr=0x%x)", fd, sb.addr()); - LV2_LOCK(0); - IDType type; - vfsStream* file; + std::shared_ptr file; if (!sys_fs->CheckId(fd, file, type) || type != TYPE_FS_FILE) return CELL_ESRCH; @@ -302,8 +326,6 @@ s32 cellFsMkdir(vm::ptr path, u32 mode) { sys_fs->Warning("cellFsMkdir(path=\"%s\", mode=0x%x)", path.get_ptr(), mode); - LV2_LOCK(0); - const std::string _path = path.get_ptr(); if (vfsDir().IsExists(_path)) @@ -319,8 +341,6 @@ s32 cellFsRename(vm::ptr from, vm::ptr to) { sys_fs->Warning("cellFsRename(from='%s', to='%s')", from.get_ptr(), to.get_ptr()); - LV2_LOCK(0); - std::string _from = from.get_ptr(); std::string _to = to.get_ptr(); @@ -353,8 +373,6 @@ s32 cellFsChmod(vm::ptr path, u32 mode) { sys_fs->Todo("cellFsChmod(path=\"%s\", mode=0x%x)", path.get_ptr(), mode); - LV2_LOCK(0); - // TODO: return CELL_OK; @@ -364,8 +382,6 @@ s32 cellFsFsync(u32 fd) { sys_fs->Todo("cellFsFsync(fd=0x%x)", fd); - LV2_LOCK(0); - // TODO: return CELL_OK; @@ -375,8 +391,6 @@ s32 cellFsRmdir(vm::ptr path) { sys_fs->Warning("cellFsRmdir(path=\"%s\")", path.get_ptr()); - LV2_LOCK(0); - std::string _path = path.get_ptr(); vfsDir d; @@ -393,8 +407,6 @@ s32 cellFsUnlink(vm::ptr path) { sys_fs->Warning("cellFsUnlink(path=\"%s\")", path.get_ptr()); - LV2_LOCK(0); - std::string _path = path.get_ptr(); if (vfsDir().IsExists(_path)) @@ -413,8 +425,6 @@ s32 cellFsLseek(u32 fd, s64 offset, u32 whence, vm::ptr> pos) { sys_fs->Log("cellFsLseek(fd=%d, offset=0x%llx, whence=0x%x, pos_addr=0x%x)", fd, offset, whence, pos.addr()); - LV2_LOCK(0); - vfsSeekMode seek_mode; switch(whence) { @@ -427,7 +437,7 @@ s32 cellFsLseek(u32 fd, s64 offset, u32 whence, vm::ptr> pos) } IDType type; - vfsStream* file; + std::shared_ptr file; if (!sys_fs->CheckId(fd, file, type) || type != TYPE_FS_FILE) return CELL_ESRCH; @@ -438,11 +448,9 @@ s32 cellFsLseek(u32 fd, s64 offset, u32 whence, vm::ptr> pos) s32 cellFsFtruncate(u32 fd, u64 size) { sys_fs->Warning("cellFsFtruncate(fd=%d, size=%lld)", fd, size); - - LV2_LOCK(0); IDType type; - vfsStream* file; + std::shared_ptr file; if (!sys_fs->CheckId(fd, file, type) || type != TYPE_FS_FILE) return CELL_ESRCH; @@ -470,8 +478,6 @@ s32 cellFsTruncate(vm::ptr path, u64 size) { sys_fs->Warning("cellFsTruncate(path=\"%s\", size=%lld)", path.get_ptr(), size); - LV2_LOCK(0); - vfsFile f(path.get_ptr(), vfsReadWrite); if (!f.IsOpened()) { @@ -505,7 +511,7 @@ s32 cellFsFGetBlockSize(u32 fd, vm::ptr sector_size, vm::ptr block_siz LV2_LOCK(0); - vfsStream* file; + std::shared_ptr file; if (!sys_fs->CheckId(fd, file)) return CELL_ESRCH; @@ -520,8 +526,6 @@ s32 cellFsGetBlockSize(vm::ptr path, vm::ptr sector_size, vm::p sys_fs->Warning("cellFsGetBlockSize(file='%s', sector_size_addr=0x%x, block_size_addr=0x%x)", path.get_ptr(), sector_size.addr(), block_size.addr()); - LV2_LOCK(0); - *sector_size = 4096; // ? *block_size = 4096; // ? @@ -533,8 +537,6 @@ s32 cellFsGetFreeSize(vm::ptr path, vm::ptr block_size, vm::ptr sys_fs->Warning("cellFsGetFreeSize(path=\"%s\", block_size_addr=0x%x, block_count_addr=0x%x)", path.get_ptr(), block_size.addr(), block_count.addr()); - LV2_LOCK(0); - // TODO: Get real values. Currently, it always returns 40 GB of free space divided in 4 KB blocks *block_size = 4096; // ? *block_count = 10 * 1024 * 1024; // ? @@ -547,9 +549,7 @@ s32 cellFsGetDirectoryEntries(u32 fd, vm::ptr entries, u32 sys_fs->Warning("cellFsGetDirectoryEntries(fd=%d, entries_addr=0x%x, entries_size=0x%x, data_count_addr=0x%x)", fd, entries.addr(), entries_size, data_count.addr()); - LV2_LOCK(0); - - vfsDirBase* directory; + std::shared_ptr directory; if (!sys_fs->CheckId(fd, directory)) return CELL_ESRCH; @@ -585,9 +585,7 @@ s32 cellFsStReadInit(u32 fd, vm::ptr ringbuf) { sys_fs->Warning("cellFsStReadInit(fd=%d, ringbuf_addr=0x%x)", fd, ringbuf.addr()); - LV2_LOCK(0); - - vfsStream* file; + std::shared_ptr file; if (!sys_fs->CheckId(fd, file)) return CELL_ESRCH; @@ -612,9 +610,7 @@ s32 cellFsStReadFinish(u32 fd) { sys_fs->Warning("cellFsStReadFinish(fd=%d)", fd); - LV2_LOCK(0); - - vfsStream* file; + std::shared_ptr file; if (!sys_fs->CheckId(fd, file)) return CELL_ESRCH; @@ -628,9 +624,7 @@ s32 cellFsStReadGetRingBuf(u32 fd, vm::ptr ringbuf) { sys_fs->Warning("cellFsStReadGetRingBuf(fd=%d, ringbuf_addr=0x%x)", fd, ringbuf.addr()); - LV2_LOCK(0); - - vfsStream* file; + std::shared_ptr file; if (!sys_fs->CheckId(fd, file)) return CELL_ESRCH; @@ -645,9 +639,7 @@ s32 cellFsStReadGetStatus(u32 fd, vm::ptr status) { sys_fs->Warning("cellFsStReadGetRingBuf(fd=%d, status_addr=0x%x)", fd, status.addr()); - LV2_LOCK(0); - - vfsStream* file; + std::shared_ptr file; if (!sys_fs->CheckId(fd, file)) return CELL_ESRCH; @@ -660,9 +652,7 @@ s32 cellFsStReadGetRegid(u32 fd, vm::ptr regid) { sys_fs->Warning("cellFsStReadGetRingBuf(fd=%d, regid_addr=0x%x)", fd, regid.addr()); - LV2_LOCK(0); - - vfsStream* file; + std::shared_ptr file; if (!sys_fs->CheckId(fd, file)) return CELL_ESRCH; @@ -675,9 +665,7 @@ s32 cellFsStReadStart(u32 fd, u64 offset, u64 size) { sys_fs->Todo("cellFsStReadStart(fd=%d, offset=0x%llx, size=0x%llx)", fd, offset, size); - LV2_LOCK(0); - - vfsStream* file; + std::shared_ptr file; if (!sys_fs->CheckId(fd, file)) return CELL_ESRCH; @@ -691,9 +679,7 @@ s32 cellFsStReadStop(u32 fd) { sys_fs->Warning("cellFsStReadStop(fd=%d)", fd); - LV2_LOCK(0); - - vfsStream* file; + std::shared_ptr file; if (!sys_fs->CheckId(fd, file)) return CELL_ESRCH; @@ -705,10 +691,8 @@ s32 cellFsStReadStop(u32 fd) s32 cellFsStRead(u32 fd, u32 buf_addr, u64 size, vm::ptr rsize) { sys_fs->Warning("cellFsStRead(fd=%d, buf_addr=0x%x, size=0x%llx, rsize_addr=0x%x)", fd, buf_addr, size, rsize.addr()); - - LV2_LOCK(0); - vfsStream* file; + std::shared_ptr file; if (!sys_fs->CheckId(fd, file)) return CELL_ESRCH; @@ -727,9 +711,7 @@ s32 cellFsStReadGetCurrentAddr(u32 fd, vm::ptr addr, vm::ptr size) { sys_fs->Todo("cellFsStReadGetCurrentAddr(fd=%d, addr_addr=0x%x, size_addr=0x%x)", fd, addr.addr(), size.addr()); - LV2_LOCK(0); - - vfsStream* file; + std::shared_ptr file; if (!sys_fs->CheckId(fd, file)) return CELL_ESRCH; @@ -739,10 +721,8 @@ s32 cellFsStReadGetCurrentAddr(u32 fd, vm::ptr addr, vm::ptr size) s32 cellFsStReadPutCurrentAddr(u32 fd, u32 addr_addr, u64 size) { sys_fs->Todo("cellFsStReadPutCurrentAddr(fd=%d, addr_addr=0x%x, size=0x%llx)", fd, addr_addr, size); - - LV2_LOCK(0); - vfsStream* file; + std::shared_ptr file; if (!sys_fs->CheckId(fd, file)) return CELL_ESRCH; @@ -752,10 +732,8 @@ s32 cellFsStReadPutCurrentAddr(u32 fd, u32 addr_addr, u64 size) s32 cellFsStReadWait(u32 fd, u64 size) { sys_fs->Todo("cellFsStReadWait(fd=%d, size=0x%llx)", fd, size); - - LV2_LOCK(0); - vfsStream* file; + std::shared_ptr file; if (!sys_fs->CheckId(fd, file)) return CELL_ESRCH; @@ -766,11 +744,331 @@ s32 cellFsStReadWaitCallback(u32 fd, u64 size, vm::ptrTodo("cellFsStReadWaitCallback(fd=%d, size=0x%llx, func_addr=0x%x)", fd, size, func.addr()); - LV2_LOCK(0); - - vfsStream* file; + std::shared_ptr file; if (!sys_fs->CheckId(fd, file)) return CELL_ESRCH; return CELL_OK; } + +bool sdata_check(u32 version, u32 flags, u64 filesizeInput, u64 filesizeTmp) +{ + if (version > 4 || flags & 0x7EFFFFC0){ + printf("ERROR: unknown version"); + return false; + } + + if ((version == 1 && (flags & 0x7FFFFFFE)) || + (version == 2 && (flags & 0x7EFFFFC0))){ + printf("ERROR: unknown or unsupported type"); + return false; + } + + if (filesizeTmp > filesizeInput){ + printf("ERROR: input file size is too short."); + return false; + } + + if (!(flags & 0x80000000)){ + printf("ERROR: cannot extract finalized edata."); + return false; + } + + return true; +} + +int sdata_unpack(const std::string& packed_file, const std::string& unpacked_file) +{ + std::shared_ptr packed_stream(Emu.GetVFS().OpenFile(packed_file, vfsRead)); + std::shared_ptr unpacked_stream(Emu.GetVFS().OpenFile(unpacked_file, vfsWrite)); + + if (!packed_stream || !packed_stream->IsOpened()) + { + sys_fs->Error("'%s' not found! flags: 0x%08x", packed_file.c_str(), vfsRead); + return CELL_ENOENT; + } + + if (!unpacked_stream || !unpacked_stream->IsOpened()) + { + sys_fs->Error("'%s' couldn't be created! flags: 0x%08x", unpacked_file.c_str(), vfsWrite); + return CELL_ENOENT; + } + + char buffer[10200]; + packed_stream->Read(buffer, 256); + u32 format = re32(*(u32*)&buffer[0]); + if (format != 0x4E504400) // "NPD\x00" + { + sys_fs->Error("Illegal format. Expected 0x4E504400, but got 0x%08x", format); + return CELL_EFSSPECIFIC; + } + + u32 version = re32(*(u32*)&buffer[0x04]); + u32 flags = re32(*(u32*)&buffer[0x80]); + u32 blockSize = re32(*(u32*)&buffer[0x84]); + u64 filesizeOutput = re64(*(u64*)&buffer[0x88]); + u64 filesizeInput = packed_stream->GetSize(); + u32 blockCount = (u32)((filesizeOutput + blockSize - 1) / blockSize); + + // SDATA file is compressed + if (flags & 0x1) + { + sys_fs->Warning("cellFsSdataOpen: Compressed SDATA files are not supported yet."); + return CELL_EFSSPECIFIC; + } + + // SDATA file is NOT compressed + else + { + u32 t1 = (flags & 0x20) ? 0x20 : 0x10; + u32 startOffset = (blockCount * t1) + 0x100; + u64 filesizeTmp = (filesizeOutput + 0xF) & 0xFFFFFFF0 + startOffset; + + if (!sdata_check(version, flags, filesizeInput, filesizeTmp)) + { + sys_fs->Error("cellFsSdataOpen: Wrong header information."); + return CELL_EFSSPECIFIC; + } + + if (flags & 0x20) + packed_stream->Seek(0x100); + else + packed_stream->Seek(startOffset); + + for (u32 i = 0; i < blockCount; i++) + { + if (flags & 0x20) + packed_stream->Seek(packed_stream->Tell() + t1); + + if (!(blockCount - i - 1)) + blockSize = (u32)(filesizeOutput - i * blockSize); + + packed_stream->Read(buffer + 256, blockSize); + unpacked_stream->Write(buffer + 256, blockSize); + } + } + + return CELL_OK; +} + +int cellFsSdataOpen(vm::ptr path, int flags, vm::ptr> fd, vm::ptr arg, u64 size) +{ + sys_fs->Warning("cellFsSdataOpen(path=\"%s\", flags=0x%x, fd_addr=0x%x, arg_addr=0x%x, size=0x%llx) -> cellFsOpen()", + path.get_ptr(), flags, fd.addr(), arg.addr(), size); + + /*if (flags != CELL_O_RDONLY) + return CELL_EINVAL; + + std::string suffix = path.substr(path.length() - 5, 5); + if (suffix != ".sdat" && suffix != ".SDAT") + return CELL_ENOTSDATA; + + std::string::size_type last_slash = path.rfind('/'); //TODO: use a filesystem library to solve this more robustly + last_slash = last_slash == std::string::npos ? 0 : last_slash+1; + std::string unpacked_path = "/dev_hdd1/"+path.substr(last_slash,path.length()-last_slash)+".unpacked"; + int ret = sdata_unpack(path, unpacked_path); + if (ret) return ret; + + fd = sys_fs->GetNewId(Emu.GetVFS().OpenFile(unpacked_path, vfsRead), TYPE_FS_FILE); + + return CELL_OK;*/ + + return cellFsOpen(path, flags, fd, arg, size); +} + +int cellFsSdataOpenByFd(int mself_fd, int flags, vm::ptr sdata_fd, u64 offset, vm::ptr arg, u64 size) +{ + sys_fs->Todo("cellFsSdataOpenByFd(mself_fd=0x%x, flags=0x%x, sdata_fd_addr=0x%x, offset=0x%llx, arg_addr=0x%x, size=0x%llx) -> cellFsOpen()", + mself_fd, flags, sdata_fd.addr(), offset, arg.addr(), size); + + // TODO: + + return CELL_OK; +} + +std::atomic g_FsAioReadID(0); +std::atomic g_FsAioReadCur(0); +bool aio_init = false; + +void fsAioRead(u32 fd, vm::ptr aio, int xid, vm::ptr xaio, int error, int xid, u64 size)> func) +{ + while (g_FsAioReadCur != xid) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + if (Emu.IsStopped()) + { + sys_fs->Warning("fsAioRead() aborted"); + return; + } + } + + u32 error = CELL_OK; + u64 res = 0; + { + std::shared_ptr orig_file; + if (!sys_fs->CheckId(fd, orig_file)) + { + sys_fs->Error("Wrong fd (%s)", fd); + Emu.Pause(); + return; + } + + u64 nbytes = aio->size; + + vfsStream& file = *orig_file; + const u64 old_pos = file.Tell(); + file.Seek((u64)aio->offset); + + // TODO: use code from cellFsRead or something + if (nbytes != (u32)nbytes) + { + error = CELL_ENOMEM; + } + else + { + res = nbytes ? file.Read(aio->buf.get_ptr(), nbytes) : 0; + } + + file.Seek(old_pos); + + sys_fs->Log("*** fsAioRead(fd=%d, offset=0x%llx, buf_addr=0x%x, size=0x%x, error=0x%x, res=0x%x, xid=0x%x)", + fd, (u64)aio->offset, aio->buf.addr(), (u64)aio->size, error, res, xid); + } + + if (func) // start callback thread + { + Emu.GetCallbackManager().Async([func, aio, error, xid, res]() + { + func(aio, error, xid, res); + }); + } + + g_FsAioReadCur++; +} + +int cellFsAioRead(vm::ptr aio, vm::ptr aio_id, vm::ptr xaio, int error, int xid, u64 size)> func) +{ + sys_fs->Warning("cellFsAioRead(aio_addr=0x%x, id_addr=0x%x, func_addr=0x%x)", aio.addr(), aio_id.addr(), func.addr()); + + if (!aio_init) + { + return CELL_ENXIO; + } + + std::shared_ptr orig_file; + u32 fd = aio->fd; + + if (!sys_fs->CheckId(fd, orig_file)) + { + return CELL_EBADF; + } + + //get a unique id for the callback (may be used by cellFsAioCancel) + const u32 xid = g_FsAioReadID++; + *aio_id = xid; + + { + thread t("fsAioRead", std::bind(fsAioRead, fd, aio, xid, func)); + t.detach(); + } + + return CELL_OK; +} + +int cellFsAioWrite(vm::ptr aio, vm::ptr aio_id, vm::ptr xaio, int error, int xid, u64 size)> func) +{ + sys_fs->Todo("cellFsAioWrite(aio_addr=0x%x, id_addr=0x%x, func_addr=0x%x)", aio.addr(), aio_id.addr(), func.addr()); + + // TODO: + + return CELL_OK; +} + +int cellFsAioInit(vm::ptr mount_point) +{ + sys_fs->Warning("cellFsAioInit(mount_point_addr=0x%x (%s))", mount_point.addr(), mount_point.get_ptr()); + + aio_init = true; + return CELL_OK; +} + +int cellFsAioFinish(vm::ptr mount_point) +{ + sys_fs->Warning("cellFsAioFinish(mount_point_addr=0x%x (%s))", mount_point.addr(), mount_point.get_ptr()); + + aio_init = false; + return CELL_OK; +} + +int cellFsReadWithOffset(u32 fd, u64 offset, vm::ptr buf, u64 buffer_size, vm::ptr> nread) +{ + sys_fs->Warning("cellFsReadWithOffset(fd=%d, offset=0x%llx, buf_addr=0x%x, buffer_size=%lld nread=0x%llx)", + fd, offset, buf.addr(), buffer_size, nread.addr()); + + int ret; + vm::var> oldPos, newPos; + ret = cellFsLseek(fd, 0, CELL_SEEK_CUR, oldPos); // Save the current position + if (ret) return ret; + ret = cellFsLseek(fd, offset, CELL_SEEK_SET, newPos); // Move to the specified offset + if (ret) return ret; + ret = cellFsRead(fd, buf, buffer_size, nread); // Read the file + if (ret) return ret; + ret = cellFsLseek(fd, oldPos.value(), CELL_SEEK_SET, newPos); // Return to the old position + if (ret) return ret; + + return CELL_OK; +} + +void sys_fs_init(Module *pxThis) +{ + sys_fs = pxThis; + + sys_fs->AddFunc(0x718bf5f8, cellFsOpen); + sys_fs->AddFunc(0xb1840b53, cellFsSdataOpen); + sys_fs->AddFunc(0x6d3bb15b, cellFsSdataOpenByFd); + sys_fs->AddFunc(0x4d5ff8e2, cellFsRead); + sys_fs->AddFunc(0xecdcf2ab, cellFsWrite); + sys_fs->AddFunc(0x2cb51f0d, cellFsClose); + sys_fs->AddFunc(0x3f61245c, cellFsOpendir); + sys_fs->AddFunc(0x5c74903d, cellFsReaddir); + sys_fs->AddFunc(0xff42dcc3, cellFsClosedir); + sys_fs->AddFunc(0x7de6dced, cellFsStat); + sys_fs->AddFunc(0xef3efa34, cellFsFstat); + sys_fs->AddFunc(0xba901fe6, cellFsMkdir); + sys_fs->AddFunc(0xf12eecc8, cellFsRename); + sys_fs->AddFunc(0x99406d0b, cellFsChmod); + sys_fs->AddFunc(0x967a162b, cellFsFsync); + sys_fs->AddFunc(0x2796fdf3, cellFsRmdir); + sys_fs->AddFunc(0x7f4677a8, cellFsUnlink); + sys_fs->AddFunc(0xa397d042, cellFsLseek); + sys_fs->AddFunc(0x0e2939e5, cellFsFtruncate); + sys_fs->AddFunc(0xc9dc3ac5, cellFsTruncate); + sys_fs->AddFunc(0xcb588dba, cellFsFGetBlockSize); + sys_fs->AddFunc(0xc1c507e7, cellFsAioRead); + sys_fs->AddFunc(0x4cef342e, cellFsAioWrite); + sys_fs->AddFunc(0xdb869f20, cellFsAioInit); + sys_fs->AddFunc(0x9f951810, cellFsAioFinish); + sys_fs->AddFunc(0x1a108ab7, cellFsGetBlockSize); + sys_fs->AddFunc(0xaa3b4bcd, cellFsGetFreeSize); + sys_fs->AddFunc(0x0d5b4a14, cellFsReadWithOffset); + sys_fs->AddFunc(0x9b882495, cellFsGetDirectoryEntries); + sys_fs->AddFunc(0x2664c8ae, cellFsStReadInit); + sys_fs->AddFunc(0xd73938df, cellFsStReadFinish); + sys_fs->AddFunc(0xb3afee8b, cellFsStReadGetRingBuf); + sys_fs->AddFunc(0xcf34969c, cellFsStReadGetStatus); + sys_fs->AddFunc(0xbd273a88, cellFsStReadGetRegid); + sys_fs->AddFunc(0x8df28ff9, cellFsStReadStart); + sys_fs->AddFunc(0xf8e5d9a0, cellFsStReadStop); + sys_fs->AddFunc(0x27800c6b, cellFsStRead); + sys_fs->AddFunc(0x190912f6, cellFsStReadGetCurrentAddr); + sys_fs->AddFunc(0x81f33783, cellFsStReadPutCurrentAddr); + sys_fs->AddFunc(0x8f71c5b2, cellFsStReadWait); + sys_fs->AddFunc(0x866f6aec, cellFsStReadWaitCallback); +} + +void sys_fs_load() +{ + g_FsAioReadID = 0; + g_FsAioReadCur = 0; + aio_init = false; +} diff --git a/rpcs3/Emu/SysCalls/lv2/lv2Fs.h b/rpcs3/Emu/SysCalls/lv2/cellFs.h similarity index 100% rename from rpcs3/Emu/SysCalls/lv2/lv2Fs.h rename to rpcs3/Emu/SysCalls/lv2/cellFs.h diff --git a/rpcs3/Emu/SysCalls/lv2/sleep_queue_type.cpp b/rpcs3/Emu/SysCalls/lv2/sleep_queue_type.cpp new file mode 100644 index 0000000000..e2e7da4b6a --- /dev/null +++ b/rpcs3/Emu/SysCalls/lv2/sleep_queue_type.cpp @@ -0,0 +1,259 @@ +#include "stdafx.h" +#include "Utilities/Log.h" +#include "Emu/Memory/Memory.h" +#include "Emu/System.h" +#include "Emu/IdManager.h" +#include "Emu/Memory/atomic_type.h" + +#include "Emu/CPU/CPUThreadManager.h" +#include "Emu/Cell/PPUThread.h" +#include "sleep_queue_type.h" + +sleep_queue_t::~sleep_queue_t() +{ + for (auto& tid : m_waiting) + { + LOG_NOTICE(HLE, "~sleep_queue_t['%s']: m_waiting[%lld]=%d", m_name.c_str(), &tid - m_waiting.data(), tid); + } + for (auto& tid : m_signaled) + { + LOG_NOTICE(HLE, "~sleep_queue_t['%s']: m_signaled[%lld]=%d", m_name.c_str(), &tid - m_signaled.data(), tid); + } +} + +void sleep_queue_t::push(u32 tid, u32 protocol) +{ + assert(tid); + + switch (protocol & SYS_SYNC_ATTR_PROTOCOL_MASK) + { + case SYS_SYNC_FIFO: + case SYS_SYNC_PRIORITY: + { + std::lock_guard lock(m_mutex); + + for (auto& v : m_waiting) + { + if (v == tid) + { + LOG_ERROR(HLE, "sleep_queue_t['%s']::push() failed: thread already waiting (%d)", m_name.c_str(), tid); + Emu.Pause(); + return; + } + } + + for (auto& v : m_signaled) + { + if (v == tid) + { + LOG_ERROR(HLE, "sleep_queue_t['%s']::push() failed: thread already signaled (%d)", m_name.c_str(), tid); + Emu.Pause(); + return; + } + } + + m_waiting.push_back(tid); + return; + } + case SYS_SYNC_RETRY: + { + return; + } + } + + LOG_ERROR(HLE, "sleep_queue_t['%s']::push() failed: unsupported protocol (0x%x)", m_name.c_str(), protocol); + Emu.Pause(); +} + +bool sleep_queue_t::pop(u32 tid, u32 protocol) +{ + assert(tid); + + switch (protocol & SYS_SYNC_ATTR_PROTOCOL_MASK) + { + case SYS_SYNC_FIFO: + case SYS_SYNC_PRIORITY: + { + std::lock_guard lock(m_mutex); + + if (m_signaled.size() && m_signaled[0] == tid) + { + m_signaled.erase(m_signaled.begin()); + return true; + } + + for (auto& v : m_signaled) + { + if (v == tid) + { + return false; + } + } + + for (auto& v : m_waiting) + { + if (v == tid) + { + return false; + } + } + + LOG_ERROR(HLE, "sleep_queue_t['%s']::pop() failed: thread not found (%d)", m_name.c_str(), tid); + Emu.Pause(); + return true; // ??? + } + //case SYS_SYNC_RETRY: // ??? + //{ + // return true; // ??? + //} + } + + LOG_ERROR(HLE, "sleep_queue_t['%s']::pop() failed: unsupported protocol (0x%x)", m_name.c_str(), protocol); + Emu.Pause(); + return false; // ??? +} + +u32 sleep_queue_t::signal(u32 protocol) +{ + u32 res = ~0; + + switch (protocol & SYS_SYNC_ATTR_PROTOCOL_MASK) + { + case SYS_SYNC_FIFO: + { + std::lock_guard lock(m_mutex); + + if (m_waiting.size()) + { + res = m_waiting[0]; + if (!Emu.GetIdManager().CheckID(res)) + { + LOG_ERROR(HLE, "sleep_queue_t['%s']::signal(SYS_SYNC_FIFO) failed: invalid thread (%d)", m_name.c_str(), res); + Emu.Pause(); + } + + m_waiting.erase(m_waiting.begin()); + m_signaled.push_back(res); + } + else + { + res = 0; + } + + return res; + } + case SYS_SYNC_PRIORITY: + { + std::lock_guard lock(m_mutex); + + u64 highest_prio = ~0ull; + u64 sel = ~0ull; + for (auto& v : m_waiting) + { + if (std::shared_ptr t = Emu.GetCPU().GetThread(v)) + { + const u64 prio = t->GetPrio(); + if (prio < highest_prio) + { + highest_prio = prio; + sel = &v - m_waiting.data(); + } + } + else + { + LOG_ERROR(HLE, "sleep_queue_t['%s']::signal(SYS_SYNC_PRIORITY) failed: invalid thread (%d)", m_name.c_str(), v); + Emu.Pause(); + } + } + + if (~sel) + { + res = m_waiting[sel]; + m_waiting.erase(m_waiting.begin() + sel); + m_signaled.push_back(res); + return res; + } + // fallthrough + } + case SYS_SYNC_RETRY: + { + return 0; + } + } + + LOG_ERROR(HLE, "sleep_queue_t['%s']::signal(): unsupported protocol (0x%x)", m_name.c_str(), protocol); + Emu.Pause(); + return 0; +} + +bool sleep_queue_t::invalidate(u32 tid, u32 protocol) +{ + assert(tid); + + switch (protocol & SYS_SYNC_ATTR_PROTOCOL_MASK) + { + case SYS_SYNC_FIFO: + case SYS_SYNC_PRIORITY: + { + std::lock_guard lock(m_mutex); + + for (auto& v : m_waiting) + { + if (v == tid) + { + m_waiting.erase(m_waiting.begin() + (&v - m_waiting.data())); + return true; + } + } + + for (auto& v : m_signaled) + { + if (v == tid) + { + if (&v == m_signaled.data()) + { + return false; // if the thread is signaled, pop() should be used + } + m_signaled.erase(m_signaled.begin() + (&v - m_signaled.data())); + return true; + } + } + + return false; + } + case SYS_SYNC_RETRY: + { + return true; + } + } + + LOG_ERROR(HLE, "sleep_queue_t['%s']::invalidate(): unsupported protocol (0x%x)", m_name.c_str(), protocol); + Emu.Pause(); + return 0; +} + +bool sleep_queue_t::signal_selected(u32 tid) +{ + assert(tid); + + std::lock_guard lock(m_mutex); + + for (auto& v : m_waiting) + { + if (v == tid) + { + m_waiting.erase(m_waiting.begin() + (&v - m_waiting.data())); + m_signaled.push_back(tid); + return true; + } + } + + return false; +} + +u32 sleep_queue_t::count() +{ + std::lock_guard lock(m_mutex); + + return (u32)m_waiting.size() + (u32)m_signaled.size(); +} diff --git a/rpcs3/Emu/SysCalls/lv2/sleep_queue_type.h b/rpcs3/Emu/SysCalls/lv2/sleep_queue_type.h new file mode 100644 index 0000000000..4b3a157888 --- /dev/null +++ b/rpcs3/Emu/SysCalls/lv2/sleep_queue_type.h @@ -0,0 +1,55 @@ +#pragma once + +// attr_protocol (waiting scheduling policy) +enum +{ + // First In, First Out + SYS_SYNC_FIFO = 1, + // Priority Order + SYS_SYNC_PRIORITY = 2, + // Basic Priority Inheritance Protocol (probably not implemented) + SYS_SYNC_PRIORITY_INHERIT = 3, + // Not selected while unlocking + SYS_SYNC_RETRY = 4, + // + SYS_SYNC_ATTR_PROTOCOL_MASK = 0xF, +}; + +// attr_recursive (recursive locks policy) +enum +{ + // Recursive locks are allowed + SYS_SYNC_RECURSIVE = 0x10, + // Recursive locks are NOT allowed + SYS_SYNC_NOT_RECURSIVE = 0x20, + // + SYS_SYNC_ATTR_RECURSIVE_MASK = 0xF0, //??? +}; + +class sleep_queue_t +{ + std::vector m_waiting; + std::vector m_signaled; + std::mutex m_mutex; + std::string m_name; + +public: + const u64 name; + + sleep_queue_t(u64 name = 0) + : name(name) + { + } + + ~sleep_queue_t(); + + void set_full_name(const std::string& name) { m_name = name; } + const std::string& get_full_name() { return m_name; } + + void push(u32 tid, u32 protocol); + bool pop(u32 tid, u32 protocol); + u32 signal(u32 protocol); + bool signal_selected(u32 tid); + bool invalidate(u32 tid, u32 protocol); + u32 count(); +}; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp b/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp index ab53f0699a..67c9e1001c 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_cond.cpp @@ -2,19 +2,20 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/SysCalls/SysCalls.h" +#include "Emu/Memory/atomic_type.h" #include "Emu/CPU/CPUThreadManager.h" #include "Emu/Cell/PPUThread.h" +#include "sleep_queue_type.h" +#include "sys_time.h" +#include "sys_mutex.h" #include "sys_cond.h" SysCallBase sys_cond("sys_cond"); s32 sys_cond_create(vm::ptr cond_id, u32 mutex_id, vm::ptr attr) { - sys_cond.Log("sys_cond_create(cond_id_addr=0x%x, mutex_id=%d, attr_addr=0x%x)", - cond_id.addr(), mutex_id, attr.addr()); - - LV2_LOCK(0); + sys_cond.Log("sys_cond_create(cond_id_addr=0x%x, mutex_id=%d, attr_addr=0x%x)", cond_id.addr(), mutex_id, attr.addr()); if (attr->pshared.ToBE() != se32(0x200)) { @@ -22,24 +23,20 @@ s32 sys_cond_create(vm::ptr cond_id, u32 mutex_id, vm::ptr mutex; if (!Emu.GetIdManager().GetIDData(mutex_id, mutex)) { return CELL_ESRCH; } - if (mutex->is_recursive) - { - sys_cond.Warning("*** condition on recursive mutex(%d)", mutex_id); - } + std::shared_ptr cond(new Cond(mutex, attr->name_u64)); - Cond* cond = new Cond(mutex, attr->name_u64); - u32 id = sys_cond.GetNewId(cond, TYPE_COND); + const u32 id = sys_cond.GetNewId(cond, TYPE_COND); + cond->queue.set_full_name(fmt::Format("Cond(%d, mutex_id=%d)", id, mutex_id)); *cond_id = id; - mutex->cond_count++; - sys_cond.Warning("*** condition created [%s] (mutex_id=%d): id = %d", std::string(attr->name, 8).c_str(), mutex_id, id); - Emu.GetSyncPrimManager().AddSyncPrimData(TYPE_COND, id, std::string(attr->name, 8)); + mutex->cond_count++; // TODO: check safety + sys_cond.Warning("*** cond created [%s] (mutex_id=%d): id = %d", std::string(attr->name, 8).c_str(), mutex_id, id); return CELL_OK; } @@ -47,22 +44,19 @@ s32 sys_cond_destroy(u32 cond_id) { sys_cond.Warning("sys_cond_destroy(cond_id=%d)", cond_id); - LV2_LOCK(0); - - Cond* cond; + std::shared_ptr cond; if (!Emu.GetIdManager().GetIDData(cond_id, cond)) { return CELL_ESRCH; } - if (!cond->m_queue.finalize()) + if (cond->queue.count()) // TODO: safely make object unusable { return CELL_EBUSY; } - cond->mutex->cond_count--; + cond->mutex->cond_count--; // TODO: check safety Emu.GetIdManager().RemoveID(cond_id); - Emu.GetSyncPrimManager().EraseSyncPrimData(TYPE_COND, cond_id); return CELL_OK; } @@ -70,24 +64,13 @@ s32 sys_cond_signal(u32 cond_id) { sys_cond.Log("sys_cond_signal(cond_id=%d)", cond_id); - Cond* cond; + std::shared_ptr cond; if (!Emu.GetIdManager().GetIDData(cond_id, cond)) { return CELL_ESRCH; } - Mutex* mutex = cond->mutex; - - if (u32 target = (mutex->protocol == SYS_SYNC_PRIORITY ? cond->m_queue.pop_prio() : cond->m_queue.pop())) - { - cond->signal.lock(target); - - if (Emu.IsStopped()) - { - sys_cond.Warning("sys_cond_signal(id=%d) aborted", cond_id); - } - } - + u32 target = cond->queue.signal(cond->mutex->protocol); return CELL_OK; } @@ -95,19 +78,16 @@ s32 sys_cond_signal_all(u32 cond_id) { sys_cond.Log("sys_cond_signal_all(cond_id=%d)", cond_id); - Cond* cond; + std::shared_ptr cond; if (!Emu.GetIdManager().GetIDData(cond_id, cond)) { return CELL_ESRCH; } - Mutex* mutex = cond->mutex; + Mutex* mutex = cond->mutex.get(); - while (u32 target = (mutex->protocol == SYS_SYNC_PRIORITY ? cond->m_queue.pop_prio() : cond->m_queue.pop())) + while (u32 target = cond->queue.signal(mutex->protocol)) { - cond->signaler = GetCurrentPPUThread().GetId(); - cond->signal.lock(target); - if (Emu.IsStopped()) { sys_cond.Warning("sys_cond_signal_all(id=%d) aborted", cond_id); @@ -115,7 +95,6 @@ s32 sys_cond_signal_all(u32 cond_id) } } - cond->signaler = 0; return CELL_OK; } @@ -123,7 +102,7 @@ s32 sys_cond_signal_to(u32 cond_id, u32 thread_id) { sys_cond.Log("sys_cond_signal_to(cond_id=%d, thread_id=%d)", cond_id, thread_id); - Cond* cond; + std::shared_ptr cond; if (!Emu.GetIdManager().GetIDData(cond_id, cond)) { return CELL_ESRCH; @@ -134,99 +113,88 @@ s32 sys_cond_signal_to(u32 cond_id, u32 thread_id) return CELL_ESRCH; } - if (!cond->m_queue.invalidate(thread_id)) + if (!cond->queue.signal_selected(thread_id)) { return CELL_EPERM; } - - Mutex* mutex = cond->mutex; - - u32 target = thread_id; - { - cond->signal.lock(target); - } - - if (Emu.IsStopped()) - { - sys_cond.Warning("sys_cond_signal_to(id=%d, to=%d) aborted", cond_id, thread_id); - } - return CELL_OK; } -s32 sys_cond_wait(u32 cond_id, u64 timeout) +s32 sys_cond_wait(PPUThread& CPU, u32 cond_id, u64 timeout) { sys_cond.Log("sys_cond_wait(cond_id=%d, timeout=%lld)", cond_id, timeout); - Cond* cond; + const u64 start_time = get_system_time(); + + std::shared_ptr cond; if (!Emu.GetIdManager().GetIDData(cond_id, cond)) { return CELL_ESRCH; } - Mutex* mutex = cond->mutex; - u32 tid = GetCurrentPPUThread().GetId(); + Mutex* mutex = cond->mutex.get(); - if (mutex->m_mutex.GetOwner() != tid) + const u32 tid = CPU.GetId(); + if (mutex->owner.read_sync() != tid) { - sys_cond.Warning("sys_cond_wait(cond_id=%d) failed (EPERM)", cond_id); return CELL_EPERM; } - cond->m_queue.push(tid); + cond->queue.push(tid, mutex->protocol); - if (mutex->recursive != 1) + auto old_recursive = mutex->recursive_count.load(); + mutex->recursive_count = 0; + if (!mutex->owner.compare_and_swap_test(tid, mutex->queue.signal(mutex->protocol))) { - sys_cond.Warning("sys_cond_wait(cond_id=%d): associated mutex had wrong recursive value (%d)", cond_id, mutex->recursive); + assert(!"sys_cond_wait() failed"); } - mutex->recursive = 0; - mutex->m_mutex.unlock(tid, mutex->protocol == SYS_SYNC_PRIORITY ? mutex->m_queue.pop_prio() : mutex->m_queue.pop()); - - u64 counter = 0; - const u64 max_counter = timeout ? (timeout / 1000) : ~0ull; + bool pushed_in_sleep_queue = false, signaled = false; while (true) { - if (cond->signal.unlock(tid, tid) == SMR_OK) + if ((signaled = signaled || cond->queue.pop(tid, mutex->protocol))) // check if signaled { - if (SMutexResult res = mutex->m_mutex.trylock(tid)) + if (mutex->owner.compare_and_swap_test(0, tid)) // try to lock { - if (res != SMR_FAILED) - { - goto abort; - } - mutex->m_queue.push(tid); - - switch (mutex->m_mutex.lock(tid)) - { - case SMR_OK: - mutex->m_queue.invalidate(tid); - case SMR_SIGNAL: - break; - default: - goto abort; - } + break; + } + + if (!pushed_in_sleep_queue) + { + mutex->queue.push(tid, mutex->protocol); + pushed_in_sleep_queue = true; + } + + auto old_owner = mutex->owner.compare_and_swap(0, tid); + if (!old_owner || old_owner == tid) + { + break; } - mutex->recursive = 1; - cond->signal.unlock(tid); - return CELL_OK; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack - if (counter++ > max_counter) + if (timeout && get_system_time() - start_time > timeout) { - cond->m_queue.invalidate(tid); - GetCurrentPPUThread().owned_mutexes--; // ??? - return CELL_ETIMEDOUT; + if (!cond->queue.invalidate(tid, mutex->protocol)) + { + assert(!"sys_cond_wait() failed (timeout)"); + } + CPU.owned_mutexes--; // ??? + return CELL_ETIMEDOUT; // mutex not locked } + if (Emu.IsStopped()) { - goto abort; + sys_cond.Warning("sys_cond_wait(id=%d) aborted", cond_id); + return CELL_OK; } } -abort: - sys_cond.Warning("sys_cond_wait(id=%d) aborted", cond_id); + if (pushed_in_sleep_queue && !mutex->queue.invalidate(tid, mutex->protocol) && !mutex->queue.pop(tid, mutex->protocol)) + { + assert(!"sys_cond_wait() failed (locking)"); + } + mutex->recursive_count = old_recursive; return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_cond.h b/rpcs3/Emu/SysCalls/lv2/sys_cond.h index f1278a484d..13c8b7f5cd 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_cond.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_cond.h @@ -1,11 +1,10 @@ #pragma once -#include "sys_mutex.h" struct sys_cond_attribute { be_t pshared; be_t ipc_key; - be_t flags; + be_t flags; union { char name[8]; @@ -15,26 +14,22 @@ struct sys_cond_attribute struct Cond { - Mutex* mutex; // associated with mutex - SMutex signal; - u32 signaler; // signaler thread id (for signal_all) - SleepQueue m_queue; + std::shared_ptr mutex; // associated with mutex + sleep_queue_t queue; - u64 signal_stamp; - - Cond(Mutex* mutex, u64 name) + Cond(std::shared_ptr& mutex, u64 name) : mutex(mutex) - , m_queue(name) - , signaler(0) + , queue(name) { - signal.initialize(); } }; +class PPUThread; + // SysCalls s32 sys_cond_create(vm::ptr cond_id, u32 mutex_id, vm::ptr attr); s32 sys_cond_destroy(u32 cond_id); -s32 sys_cond_wait(u32 cond_id, u64 timeout); +s32 sys_cond_wait(PPUThread& CPU, u32 cond_id, u64 timeout); s32 sys_cond_signal(u32 cond_id); s32 sys_cond_signal_all(u32 cond_id); s32 sys_cond_signal_to(u32 cond_id, u32 thread_id); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_event.cpp b/rpcs3/Emu/SysCalls/lv2/sys_event.cpp index 701c827c40..305fccdacb 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_event.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_event.cpp @@ -2,9 +2,12 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/SysCalls/SysCalls.h" +#include "Emu/Memory/atomic_type.h" #include "Emu/Cell/PPUThread.h" #include "Emu/Event.h" +#include "sleep_queue_type.h" +#include "sys_time.h" #include "sys_process.h" #include "sys_event.h" @@ -12,18 +15,17 @@ SysCallBase sys_event("sys_event"); u32 event_queue_create(u32 protocol, s32 type, u64 name_u64, u64 event_queue_key, s32 size) { - EventQueue* eq = new EventQueue(protocol, type, name_u64, event_queue_key, size); + std::shared_ptr eq(new EventQueue(protocol, type, name_u64, event_queue_key, size)); if (event_queue_key && !Emu.GetEventManager().RegisterKey(eq, event_queue_key)) { - delete eq; return 0; } - std::string name((const char*)&name_u64, 8); - u32 id = sys_event.GetNewId(eq, TYPE_EVENT_QUEUE); + const u32 id = sys_event.GetNewId(eq, TYPE_EVENT_QUEUE); + eq->sq.set_full_name(fmt::Format("EventQueue(%d)", id)); sys_event.Warning("*** event_queue created [%s] (protocol=0x%x, type=0x%x, key=0x%llx, size=0x%x): id = %d", - name.c_str(), protocol, type, event_queue_key, size, id); + std::string((const char*)&name_u64, 8).c_str(), protocol, type, event_queue_key, size, id); return id; } @@ -71,7 +73,7 @@ s32 sys_event_queue_destroy(u32 equeue_id, int mode) { sys_event.Todo("sys_event_queue_destroy(equeue_id=%d, mode=0x%x)", equeue_id, mode); - EventQueue* eq; + std::shared_ptr eq; if (!Emu.GetIdManager().GetIDData(equeue_id, eq)) { return CELL_ESRCH; @@ -82,28 +84,27 @@ s32 sys_event_queue_destroy(u32 equeue_id, int mode) return CELL_EINVAL; } - u32 tid = GetCurrentPPUThread().GetId(); - - eq->sq.m_mutex.lock(); - eq->owner.lock(tid); + //u32 tid = GetCurrentPPUThread().GetId(); + //eq->sq.m_mutex.lock(); + //eq->owner.lock(tid); // check if some threads are waiting for an event - if (!mode && eq->sq.list.size()) - { - eq->owner.unlock(tid); - eq->sq.m_mutex.unlock(); - return CELL_EBUSY; - } - eq->owner.unlock(tid, ~0); - eq->sq.m_mutex.unlock(); - while (eq->sq.list.size()) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - if (Emu.IsStopped()) - { - sys_event.Warning("sys_event_queue_destroy(equeue=%d) aborted", equeue_id); - break; - } - } + //if (!mode && eq->sq.list.size()) + //{ + // eq->owner.unlock(tid); + // eq->sq.m_mutex.unlock(); + // return CELL_EBUSY; + //} + //eq->owner.unlock(tid, ~0); + //eq->sq.m_mutex.unlock(); + //while (eq->sq.list.size()) + //{ + // std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + // if (Emu.IsStopped()) + // { + // sys_event.Warning("sys_event_queue_destroy(equeue=%d) aborted", equeue_id); + // break; + // } + //} Emu.GetEventManager().UnregisterKey(eq->key); eq->ports.clear(); @@ -117,7 +118,7 @@ s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr event_arra sys_event.Todo("sys_event_queue_tryreceive(equeue_id=%d, event_array_addr=0x%x, size=%d, number_addr=0x%x)", equeue_id, event_array.addr(), size, number.addr()); - EventQueue* eq; + std::shared_ptr eq; if (!Emu.GetIdManager().GetIDData(equeue_id, eq)) { return CELL_ESRCH; @@ -134,20 +135,19 @@ s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr event_arra return CELL_OK; } - u32 tid = GetCurrentPPUThread().GetId(); - - eq->sq.m_mutex.lock(); - eq->owner.lock(tid); - if (eq->sq.list.size()) - { - *number = 0; - eq->owner.unlock(tid); - eq->sq.m_mutex.unlock(); - return CELL_OK; - } + //u32 tid = GetCurrentPPUThread().GetId(); + //eq->sq.m_mutex.lock(); + //eq->owner.lock(tid); + //if (eq->sq.list.size()) + //{ + // *number = 0; + // eq->owner.unlock(tid); + // eq->sq.m_mutex.unlock(); + // return CELL_OK; + //} *number = eq->events.pop_all(event_array.get_ptr(), size); - eq->owner.unlock(tid); - eq->sq.m_mutex.unlock(); + //eq->owner.unlock(tid); + //eq->sq.m_mutex.unlock(); return CELL_OK; } @@ -157,7 +157,9 @@ s32 sys_event_queue_receive(u32 equeue_id, vm::ptr dummy_event, sys_event.Log("sys_event_queue_receive(equeue_id=%d, dummy_event_addr=0x%x, timeout=%lld)", equeue_id, dummy_event.addr(), timeout); - EventQueue* eq; + const u64 start_time = get_system_time(); + + std::shared_ptr eq; if (!Emu.GetIdManager().GetIDData(equeue_id, eq)) { return CELL_ESRCH; @@ -168,36 +170,38 @@ s32 sys_event_queue_receive(u32 equeue_id, vm::ptr dummy_event, return CELL_EINVAL; } - u32 tid = GetCurrentPPUThread().GetId(); + const u32 tid = GetCurrentPPUThread().GetId(); - eq->sq.push(tid); // add thread to sleep queue + eq->sq.push(tid, eq->protocol); // add thread to sleep queue - timeout = timeout ? (timeout / 1000) : ~0; - u64 counter = 0; while (true) { - switch (eq->owner.trylock(tid)) + const u32 old_owner = eq->owner.compare_and_swap(0, tid); + const s32 res = old_owner ? (old_owner == tid ? 1 : 2) : 0; + + switch (res) { - case SMR_OK: - if (!eq->events.count()) + case 0: + { + const u32 next = eq->events.count() ? eq->sq.signal(eq->protocol) : 0; + if (next != tid) { - eq->owner.unlock(tid); + if (!eq->owner.compare_and_swap_test(tid, next)) + { + assert(!"sys_event_queue_receive() failed (I)"); + } break; } - else - { - u32 next = (eq->protocol == SYS_SYNC_FIFO) ? eq->sq.pop() : eq->sq.pop_prio(); - if (next != tid) - { - eq->owner.unlock(tid, next); - break; - } - } - case SMR_SIGNAL: + // fallthrough + } + case 1: { sys_event_data event; eq->events.pop(event); - eq->owner.unlock(tid); + if (!eq->owner.compare_and_swap_test(tid, 0)) + { + assert(!"sys_event_queue_receive() failed (II)"); + } sys_event.Log(" *** event received: source=0x%llx, d1=0x%llx, d2=0x%llx, d3=0x%llx", (u64)event.source, (u64)event.data1, (u64)event.data2, (u64)event.data3); /* passing event data in registers */ @@ -206,19 +210,39 @@ s32 sys_event_queue_receive(u32 equeue_id, vm::ptr dummy_event, t.GPR[5] = event.data1; t.GPR[6] = event.data2; t.GPR[7] = event.data3; + if (!eq->sq.invalidate(tid, eq->protocol) && !eq->sq.pop(tid, eq->protocol)) + { + assert(!"sys_event_queue_receive() failed (receiving)"); + } return CELL_OK; } - case SMR_FAILED: break; - default: eq->sq.invalidate(tid); return CELL_ECANCELED; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - if (counter++ > timeout || Emu.IsStopped()) + if (!~old_owner) { - if (Emu.IsStopped()) sys_event.Warning("sys_event_queue_receive(equeue=%d) aborted", equeue_id); - eq->sq.invalidate(tid); + if (!eq->sq.invalidate(tid, eq->protocol)) + { + assert(!"sys_event_queue_receive() failed (cancelling)"); + } + return CELL_ECANCELED; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + + if (timeout && get_system_time() - start_time > timeout) + { + if (!eq->sq.invalidate(tid, eq->protocol)) + { + assert(!"sys_event_queue_receive() failed (timeout)"); + } return CELL_ETIMEDOUT; } + + if (Emu.IsStopped()) + { + sys_event.Warning("sys_event_queue_receive(equeue=%d) aborted", equeue_id); + return CELL_OK; + } } } @@ -226,7 +250,7 @@ s32 sys_event_queue_drain(u32 equeue_id) { sys_event.Log("sys_event_queue_drain(equeue_id=%d)", equeue_id); - EventQueue* eq; + std::shared_ptr eq; if (!Emu.GetIdManager().GetIDData(equeue_id, eq)) { return CELL_ESRCH; @@ -239,10 +263,10 @@ s32 sys_event_queue_drain(u32 equeue_id) u32 event_port_create(u64 name) { - EventPort* eport = new EventPort(); + std::shared_ptr eport(new EventPort()); u32 id = sys_event.GetNewId(eport, TYPE_EVENT_PORT); eport->name = name ? name : ((u64)process_getpid() << 32) | (u64)id; - sys_event.Warning("*** sys_event_port created: id = %d", id); + sys_event.Warning("*** sys_event_port created: id = %d, name=0x%llx", id, eport->name); return id; } @@ -265,7 +289,7 @@ s32 sys_event_port_destroy(u32 eport_id) { sys_event.Warning("sys_event_port_destroy(eport_id=%d)", eport_id); - EventPort* eport; + std::shared_ptr eport; if (!Emu.GetIdManager().GetIDData(eport_id, eport)) { return CELL_ESRCH; @@ -291,7 +315,7 @@ s32 sys_event_port_connect_local(u32 eport_id, u32 equeue_id) { sys_event.Warning("sys_event_port_connect_local(eport_id=%d, equeue_id=%d)", eport_id, equeue_id); - EventPort* eport; + std::shared_ptr eport; if (!Emu.GetIdManager().GetIDData(eport_id, eport)) { return CELL_ESRCH; @@ -308,7 +332,7 @@ s32 sys_event_port_connect_local(u32 eport_id, u32 equeue_id) return CELL_EISCONN; } - EventQueue* equeue; + std::shared_ptr equeue; if (!Emu.GetIdManager().GetIDData(equeue_id, equeue)) { sys_event.Error("sys_event_port_connect_local: event_queue(%d) not found!", equeue_id); @@ -329,7 +353,7 @@ s32 sys_event_port_disconnect(u32 eport_id) { sys_event.Warning("sys_event_port_disconnect(eport_id=%d)", eport_id); - EventPort* eport; + std::shared_ptr eport; if (!Emu.GetIdManager().GetIDData(eport_id, eport)) { return CELL_ESRCH; @@ -356,7 +380,7 @@ s32 sys_event_port_send(u32 eport_id, u64 data1, u64 data2, u64 data3) sys_event.Log("sys_event_port_send(eport_id=%d, data1=0x%llx, data2=0x%llx, data3=0x%llx)", eport_id, data1, data2, data3); - EventPort* eport; + std::shared_ptr eport; if (!Emu.GetIdManager().GetIDData(eport_id, eport)) { return CELL_ESRCH; @@ -364,7 +388,7 @@ s32 sys_event_port_send(u32 eport_id, u64 data1, u64 data2, u64 data3) std::lock_guard lock(eport->m_mutex); - EventQueue* eq = eport->eq; + std::shared_ptr eq = eport->eq; if (!eq) { return CELL_ENOTCONN; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_event.h b/rpcs3/Emu/SysCalls/lv2/sys_event.h index 61180f5982..0fdfae8f4a 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_event.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_event.h @@ -1,7 +1,5 @@ #pragma once -#include "sys_lwmutex.h" - #define FIX_SPUQ(x) ((u64)x | 0x5350555100000000ULL) // arbitrary code to prevent "special" zero value in key argument @@ -58,7 +56,7 @@ struct EventQueue; struct EventPort { u64 name; // generated or user-specified code that is passed to sys_event_data struct - EventQueue* eq; // event queue this port has been connected to + std::shared_ptr eq; // event queue this port has been connected to std::mutex m_mutex; // may be locked until the event sending is finished EventPort(u64 name = 0) @@ -152,7 +150,7 @@ public: class EventPortList { - std::vector data; + std::vector> data; std::mutex m_mutex; public: @@ -169,18 +167,18 @@ public: data.clear(); } - void add(EventPort* port) + void add(std::shared_ptr& port) { std::lock_guard lock(m_mutex); data.push_back(port); } - void remove(EventPort* port) + void remove(std::shared_ptr& port) { std::lock_guard lock(m_mutex); for (u32 i = 0; i < data.size(); i++) { - if (data[i] == port) + if (data[i].get() == port.get()) { data.erase(data.begin() + i); return; @@ -191,10 +189,10 @@ public: struct EventQueue { - SleepQueue sq; + sleep_queue_t sq; EventPortList ports; EventRingBuffer events; - SMutex owner; + atomic_le_t owner; const union { @@ -212,7 +210,7 @@ struct EventQueue , key(key) , events(size) // size: max event count this queue can hold { - owner.initialize(); + owner.write_relaxed(0); } }; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_event_flag.cpp b/rpcs3/Emu/SysCalls/lv2/sys_event_flag.cpp index 9a0da23fe6..9c186d6a75 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_event_flag.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_event_flag.cpp @@ -2,43 +2,60 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/SysCalls/SysCalls.h" +#include "Emu/Memory/atomic_type.h" +#include "Emu/CPU/CPUThreadManager.h" #include "Emu/Cell/PPUThread.h" -#include "sys_lwmutex.h" +#include "sleep_queue_type.h" #include "sys_event_flag.h" SysCallBase sys_event_flag("sys_event_flag"); u32 EventFlag::check() { - SleepQueue sq; // TODO: implement without SleepQueue - u32 target = 0; + u64 highest_prio = ~0ull; + const u64 flag_set = flags.read_sync(); for (u32 i = 0; i < waiters.size(); i++) { - if (((waiters[i].mode & SYS_EVENT_FLAG_WAIT_AND) && (flags & waiters[i].bitptn) == waiters[i].bitptn) || - ((waiters[i].mode & SYS_EVENT_FLAG_WAIT_OR) && (flags & waiters[i].bitptn))) + if (((waiters[i].mode & SYS_EVENT_FLAG_WAIT_AND) && (flag_set & waiters[i].bitptn) == waiters[i].bitptn) || + ((waiters[i].mode & SYS_EVENT_FLAG_WAIT_OR) && (flag_set & waiters[i].bitptn))) { - if (m_protocol == SYS_SYNC_FIFO) + if (protocol == SYS_SYNC_FIFO) { target = waiters[i].tid; break; } - sq.list.push_back(waiters[i].tid); + else if (protocol == SYS_SYNC_PRIORITY) + { + if (std::shared_ptr t = Emu.GetCPU().GetThread(waiters[i].tid)) + { + const u64 prio = t->GetPrio(); + if (prio < highest_prio) + { + highest_prio = prio; + target = waiters[i].tid; + } + } + else + { + assert(!"EventFlag::check(): waiter not found"); + } + } + else + { + assert(!"EventFlag::check(): unknown protocol"); + } } } - if (m_protocol == SYS_SYNC_PRIORITY) - target = sq.pop_prio(); - return target; } s32 sys_event_flag_create(vm::ptr eflag_id, vm::ptr attr, u64 init) { - sys_event_flag.Warning("sys_event_flag_create(eflag_id_addr=0x%x, attr_addr=0x%x, init=0x%llx)", - eflag_id.addr(), attr.addr(), init); + sys_event_flag.Warning("sys_event_flag_create(eflag_id_addr=0x%x, attr_addr=0x%x, init=0x%llx)", eflag_id.addr(), attr.addr(), init); if (!eflag_id) { @@ -62,7 +79,9 @@ s32 sys_event_flag_create(vm::ptr eflag_id, vm::ptr at } if (attr->pshared.ToBE() != se32(0x200)) + { return CELL_EINVAL; + } switch (attr->type.ToBE()) { @@ -71,10 +90,11 @@ s32 sys_event_flag_create(vm::ptr eflag_id, vm::ptr at default: return CELL_EINVAL; } - u32 id = sys_event_flag.GetNewId(new EventFlag(init, (u32)attr->protocol, (int)attr->type), TYPE_EVENT_FLAG); + std::shared_ptr ef(new EventFlag(init, (u32)attr->protocol, (s32)attr->type, attr->name_u64)); + u32 id = sys_event_flag.GetNewId(ef, TYPE_EVENT_FLAG); *eflag_id = id; sys_event_flag.Warning("*** event_flag created [%s] (protocol=0x%x, type=0x%x): id = %d", - std::string(attr->name, 8).c_str(), (u32)attr->protocol, (int)attr->type, id); + std::string(attr->name, 8).c_str(), (u32)attr->protocol, (s32)attr->type, id); return CELL_OK; } @@ -83,7 +103,7 @@ s32 sys_event_flag_destroy(u32 eflag_id) { sys_event_flag.Warning("sys_event_flag_destroy(eflag_id=%d)", eflag_id); - EventFlag* ef; + std::shared_ptr ef; if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; if (ef->waiters.size()) // ??? @@ -118,18 +138,19 @@ s32 sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, vm::ptr result, default: return CELL_EINVAL; } - EventFlag* ef; + std::shared_ptr ef; if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; const u32 tid = GetCurrentPPUThread().GetId(); { - ef->m_mutex.lock(tid); - if (ef->m_type == SYS_SYNC_WAITER_SINGLE && ef->waiters.size() > 0) + std::lock_guard lock(ef->mutex); + + if (ef->type == SYS_SYNC_WAITER_SINGLE && ef->waiters.size() > 0) { - ef->m_mutex.unlock(tid); return CELL_EPERM; } + EventFlagWaiter rec; rec.bitptn = bitptn; rec.mode = mode; @@ -138,7 +159,7 @@ s32 sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, vm::ptr result, if (ef->check() == tid) { - u64 flags = ef->flags; + const u64 flag_set = ef->flags.read_sync(); ef->waiters.erase(ef->waiters.end() - 1); @@ -148,15 +169,15 @@ s32 sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, vm::ptr result, } else if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL) { - ef->flags = 0; + ef->flags &= 0; } - if (result) *result = flags; - - ef->m_mutex.unlock(tid); + if (result) + { + *result = flag_set; + } return CELL_OK; } - ef->m_mutex.unlock(tid); } u64 counter = 0; @@ -164,10 +185,14 @@ s32 sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, vm::ptr result, while (true) { - if (ef->signal.unlock(tid, tid) == SMR_OK) + u32 signaled; + if (ef->signal.try_peek(signaled) && signaled == tid) { - ef->m_mutex.lock(tid); - u64 flags = ef->flags; + std::lock_guard lock(ef->mutex); + + const u64 flag_set = ef->flags.read_sync(); + + ef->signal.pop(signaled); for (u32 i = 0; i < ef->waiters.size(); i++) { @@ -181,37 +206,30 @@ s32 sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, vm::ptr result, } else if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL) { - ef->flags = 0; + ef->flags &= 0; } if (u32 target = ef->check()) { - // if signal, leave both mutexes locked... - ef->signal.unlock(tid, target); - ef->m_mutex.unlock(tid, target); + ef->signal.push(target); } - else + + if (result) { - ef->signal.unlock(tid); + *result = flag_set; } - - if (result) *result = flags; - - ef->m_mutex.unlock(tid); return CELL_OK; } } - ef->signal.unlock(tid); - ef->m_mutex.unlock(tid); return CELL_ECANCELED; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack if (counter++ > max_counter) { - ef->m_mutex.lock(tid); + std::lock_guard lock(ef->mutex); for (u32 i = 0; i < ef->waiters.size(); i++) { @@ -221,10 +239,9 @@ s32 sys_event_flag_wait(u32 eflag_id, u64 bitptn, u32 mode, vm::ptr result, break; } } - - ef->m_mutex.unlock(tid); return CELL_ETIMEDOUT; } + if (Emu.IsStopped()) { sys_event_flag.Warning("sys_event_flag_wait(id=%d) aborted", eflag_id); @@ -255,16 +272,15 @@ s32 sys_event_flag_trywait(u32 eflag_id, u64 bitptn, u32 mode, vm::ptr resu default: return CELL_EINVAL; } - EventFlag* ef; + std::shared_ptr ef; if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; + + std::lock_guard lock(ef->mutex); - const u32 tid = GetCurrentPPUThread().GetId(); - ef->m_mutex.lock(tid); + const u64 flag_set = ef->flags.read_sync(); - u64 flags = ef->flags; - - if (((mode & SYS_EVENT_FLAG_WAIT_AND) && (flags & bitptn) == bitptn) || - ((mode & SYS_EVENT_FLAG_WAIT_OR) && (flags & bitptn))) + if (((mode & SYS_EVENT_FLAG_WAIT_AND) && (flag_set & bitptn) == bitptn) || + ((mode & SYS_EVENT_FLAG_WAIT_OR) && (flag_set & bitptn))) { if (mode & SYS_EVENT_FLAG_WAIT_CLEAR) { @@ -272,16 +288,17 @@ s32 sys_event_flag_trywait(u32 eflag_id, u64 bitptn, u32 mode, vm::ptr resu } else if (mode & SYS_EVENT_FLAG_WAIT_CLEAR_ALL) { - ef->flags = 0; + ef->flags &= 0; } - if (result) *result = flags; + if (result) + { + *result = flag_set; + } - ef->m_mutex.unlock(tid); return CELL_OK; } - ef->m_mutex.unlock(tid); return CELL_EBUSY; } @@ -289,24 +306,16 @@ s32 sys_event_flag_set(u32 eflag_id, u64 bitptn) { sys_event_flag.Log("sys_event_flag_set(eflag_id=%d, bitptn=0x%llx)", eflag_id, bitptn); - EventFlag* ef; + std::shared_ptr ef; if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; - u32 tid = GetCurrentPPUThread().GetId(); + std::lock_guard lock(ef->mutex); - ef->m_mutex.lock(tid); ef->flags |= bitptn; if (u32 target = ef->check()) { - // if signal, leave both mutexes locked... - ef->signal.lock(target); - ef->m_mutex.unlock(tid, target); + ef->signal.push(target); } - else - { - ef->m_mutex.unlock(tid); - } - return CELL_OK; } @@ -314,13 +323,11 @@ s32 sys_event_flag_clear(u32 eflag_id, u64 bitptn) { sys_event_flag.Log("sys_event_flag_clear(eflag_id=%d, bitptn=0x%llx)", eflag_id, bitptn); - EventFlag* ef; + std::shared_ptr ef; if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; - const u32 tid = GetCurrentPPUThread().GetId(); - ef->m_mutex.lock(tid); + std::lock_guard lock(ef->mutex); ef->flags &= bitptn; - ef->m_mutex.unlock(tid); return CELL_OK; } @@ -328,27 +335,24 @@ s32 sys_event_flag_cancel(u32 eflag_id, vm::ptr num) { sys_event_flag.Log("sys_event_flag_cancel(eflag_id=%d, num_addr=0x%x)", eflag_id, num.addr()); - EventFlag* ef; + std::shared_ptr ef; if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; std::vector tids; - - const u32 tid = GetCurrentPPUThread().GetId(); - { - ef->m_mutex.lock(tid); + std::lock_guard lock(ef->mutex); + tids.resize(ef->waiters.size()); for (u32 i = 0; i < ef->waiters.size(); i++) { tids[i] = ef->waiters[i].tid; } ef->waiters.clear(); - ef->m_mutex.unlock(tid); } - for (u32 i = 0; i < tids.size(); i++) + for (auto& v : tids) { - ef->signal.lock(tids[i]); + ef->signal.push(v); } if (Emu.IsStopped()) @@ -357,7 +361,10 @@ s32 sys_event_flag_cancel(u32 eflag_id, vm::ptr num) return CELL_OK; } - if (num) *num = (u32)tids.size(); + if (num) + { + *num = (u32)tids.size(); + } return CELL_OK; } @@ -372,12 +379,9 @@ s32 sys_event_flag_get(u32 eflag_id, vm::ptr flags) return CELL_EFAULT; } - EventFlag* ef; + std::shared_ptr ef; if (!sys_event_flag.CheckId(eflag_id, ef)) return CELL_ESRCH; - const u32 tid = GetCurrentPPUThread().GetId(); - ef->m_mutex.lock(tid); - *flags = ef->flags; - ef->m_mutex.unlock(tid); + *flags = ef->flags.read_sync(); return CELL_OK; } \ No newline at end of file diff --git a/rpcs3/Emu/SysCalls/lv2/sys_event_flag.h b/rpcs3/Emu/SysCalls/lv2/sys_event_flag.h index 05309fb748..5f21c5f413 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_event_flag.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_event_flag.h @@ -1,7 +1,5 @@ #pragma once -#include "Utilities/SMutex.h" - enum { SYS_SYNC_WAITER_SINGLE = 0x10000, @@ -19,9 +17,13 @@ struct sys_event_flag_attr be_t protocol; be_t pshared; be_t ipc_key; - be_t flags; - be_t type; - char name[8]; + be_t flags; + be_t type; + union + { + char name[8]; + u64 name_u64; + }; }; struct EventFlagWaiter @@ -33,20 +35,21 @@ struct EventFlagWaiter struct EventFlag { - SMutex m_mutex; - u64 flags; + atomic_le_t flags; + squeue_t signal; + std::mutex mutex; // protects waiters std::vector waiters; - SMutex signal; - const u32 m_protocol; - const int m_type; - EventFlag(u64 pattern, u32 protocol, int type) - : flags(pattern) - , m_protocol(protocol) - , m_type(type) + const u32 protocol; + const int type; + const u64 name; + + EventFlag(u64 pattern, u32 protocol, int type, u64 name) + : protocol(protocol) + , type(type) + , name(name) { - m_mutex.initialize(); - signal.initialize(); + flags.write_relaxed(pattern); } u32 check(); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_interrupt.cpp b/rpcs3/Emu/SysCalls/lv2/sys_interrupt.cpp index cd7f229b71..8ef3829ff5 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_interrupt.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_interrupt.cpp @@ -60,7 +60,7 @@ s32 sys_interrupt_thread_establish(vm::ptr ih, u32 intrtag, u64 intrthread, return CELL_ESTAT; } - CPUThread* it = Emu.GetCPU().GetThread(intrthread); + std::shared_ptr it = Emu.GetCPU().GetThread(intrthread); if (!it) { return CELL_ESRCH; @@ -80,7 +80,7 @@ s32 sys_interrupt_thread_disestablish(u32 ih) { sys_interrupt.Todo("sys_interrupt_thread_disestablish(ih=%d)", ih); - CPUThread* it = Emu.GetCPU().GetThread(ih); + std::shared_ptr it = Emu.GetCPU().GetThread(ih); if (!it) { return CELL_ESRCH; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp index a7d277977b..6670f797e6 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.cpp @@ -2,8 +2,11 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/SysCalls/SysCalls.h" +#include "Emu/Memory/atomic_type.h" #include "Emu/Cell/PPUThread.h" +#include "sleep_queue_type.h" +#include "sys_time.h" #include "sys_lwmutex.h" #include "sys_lwcond.h" @@ -11,20 +14,15 @@ SysCallBase sys_lwcond("sys_lwcond"); s32 lwcond_create(sys_lwcond_t& lwcond, sys_lwmutex_t& lwmutex, u64 name_u64) { - LV2_LOCK(0); + std::shared_ptr lw(new Lwcond(name_u64, Memory.RealToVirtualAddr(&lwcond))); - u32 id = sys_lwcond.GetNewId(new Lwcond(name_u64), TYPE_LWCOND); - u32 addr = Memory.RealToVirtualAddr(&lwmutex); + const u32 id = sys_lwcond.GetNewId(lw, TYPE_LWCOND); + const u32 addr = Memory.RealToVirtualAddr(&lwmutex); + lw->queue.set_full_name(fmt::Format("Lwcond(%d, addr=0x%x)", id, lw->addr)); lwcond.lwmutex.set(addr); lwcond.lwcond_queue = id; - std::string name((const char*)&name_u64, 8); - - sys_lwcond.Warning("*** lwcond created [%s] (lwmutex_addr=0x%x): id = %d", - name.c_str(), addr, id); - - Emu.GetSyncPrimManager().AddSyncPrimData(TYPE_LWCOND, id, name); - + sys_lwcond.Warning("*** lwcond created [%s] (lwmutex_addr=0x%x): id = %d", std::string((const char*)&name_u64, 8).c_str(), addr, id); return CELL_OK; } @@ -40,23 +38,20 @@ s32 sys_lwcond_destroy(vm::ptr lwcond) { sys_lwcond.Warning("sys_lwcond_destroy(lwcond_addr=0x%x)", lwcond.addr()); - LV2_LOCK(0); - u32 id = lwcond->lwcond_queue; - Lwcond* lw; + std::shared_ptr lw; if (!Emu.GetIdManager().GetIDData(id, lw)) { return CELL_ESRCH; } - if (!lw->m_queue.finalize()) + if (lw->queue.count()) // TODO: safely make object unusable { return CELL_EBUSY; } Emu.GetIdManager().RemoveID(id); - Emu.GetSyncPrimManager().EraseSyncPrimData(TYPE_LWCOND, id); return CELL_OK; } @@ -64,7 +59,7 @@ s32 sys_lwcond_signal(vm::ptr lwcond) { sys_lwcond.Log("sys_lwcond_signal(lwcond_addr=0x%x)", lwcond.addr()); - Lwcond* lw; + std::shared_ptr lw; if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, lw)) { return CELL_ESRCH; @@ -72,10 +67,8 @@ s32 sys_lwcond_signal(vm::ptr lwcond) auto mutex = vm::ptr::make(lwcond->lwmutex.addr()); - if (u32 target = (mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? lw->m_queue.pop_prio() : lw->m_queue.pop())) + if (u32 target = lw->queue.signal(mutex->attribute)) { - lw->signal.lock(target); - if (Emu.IsStopped()) { sys_lwcond.Warning("sys_lwcond_signal(id=%d) aborted", (u32)lwcond->lwcond_queue); @@ -90,7 +83,7 @@ s32 sys_lwcond_signal_all(vm::ptr lwcond) { sys_lwcond.Log("sys_lwcond_signal_all(lwcond_addr=0x%x)", lwcond.addr()); - Lwcond* lw; + std::shared_ptr lw; if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, lw)) { return CELL_ESRCH; @@ -98,10 +91,8 @@ s32 sys_lwcond_signal_all(vm::ptr lwcond) auto mutex = vm::ptr::make(lwcond->lwmutex.addr()); - while (u32 target = (mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? lw->m_queue.pop_prio() : lw->m_queue.pop())) + while (u32 target = lw->queue.signal(mutex->attribute)) { - lw->signal.lock(target); - if (Emu.IsStopped()) { sys_lwcond.Warning("sys_lwcond_signal_all(id=%d) aborted", (u32)lwcond->lwcond_queue); @@ -116,7 +107,7 @@ s32 sys_lwcond_signal_to(vm::ptr lwcond, u32 ppu_thread_id) { sys_lwcond.Log("sys_lwcond_signal_to(lwcond_addr=0x%x, ppu_thread_id=%d)", lwcond.addr(), ppu_thread_id); - Lwcond* lw; + std::shared_ptr lw; if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, lw)) { return CELL_ESRCH; @@ -127,107 +118,112 @@ s32 sys_lwcond_signal_to(vm::ptr lwcond, u32 ppu_thread_id) return CELL_ESRCH; } - if (!lw->m_queue.invalidate(ppu_thread_id)) + if (!lw->queue.signal_selected(ppu_thread_id)) { return CELL_EPERM; } - u32 target = ppu_thread_id; - { - lw->signal.lock(target); - - if (Emu.IsStopped()) - { - sys_lwcond.Warning("sys_lwcond_signal_to(id=%d, to=%d) aborted", (u32)lwcond->lwcond_queue, ppu_thread_id); - return CELL_OK; - } - } - return CELL_OK; } -s32 sys_lwcond_wait(vm::ptr lwcond, u64 timeout) +s32 sys_lwcond_wait(PPUThread& CPU, vm::ptr lwcond, u64 timeout) { sys_lwcond.Log("sys_lwcond_wait(lwcond_addr=0x%x, timeout=%lld)", lwcond.addr(), timeout); - Lwcond* lw; + const u64 start_time = get_system_time(); + + std::shared_ptr lw; if (!Emu.GetIdManager().GetIDData((u32)lwcond->lwcond_queue, lw)) { return CELL_ESRCH; } auto mutex = vm::ptr::make(lwcond->lwmutex.addr()); - u32 tid_le = GetCurrentPPUThread().GetId(); + u32 tid_le = CPU.GetId(); be_t tid = be_t::make(tid_le); - SleepQueue* sq = nullptr; - Emu.GetIdManager().GetIDData((u32)mutex->sleep_queue, sq); - - if (mutex->mutex.GetOwner() != tid) - { - sys_lwcond.Warning("sys_lwcond_wait(id=%d) failed (EPERM)", (u32)lwcond->lwcond_queue); - return CELL_EPERM; // caller must own this lwmutex - } - - lw->m_queue.push(tid_le); - - if (mutex->recursive_count.ToBE() != se32(1)) - { - sys_lwcond.Warning("sys_lwcond_wait(id=%d): associated mutex had wrong recursive value (%d)", - (u32)lwcond->lwcond_queue, (u32)mutex->recursive_count); - } - mutex->recursive_count = 0; - - if (sq) - { - mutex->mutex.unlock(tid, be_t::make(mutex->attribute.ToBE() == se32(SYS_SYNC_PRIORITY) ? sq->pop_prio() : sq->pop())); - } - else if (mutex->attribute.ToBE() == se32(SYS_SYNC_RETRY)) - { - mutex->mutex.unlock(tid); // SYS_SYNC_RETRY - } - else + std::shared_ptr sq; + if (!Emu.GetIdManager().GetIDData((u32)mutex->sleep_queue, sq)) { sys_lwcond.Warning("sys_lwcond_wait(id=%d): associated mutex had invalid sleep queue (%d)", (u32)lwcond->lwcond_queue, (u32)mutex->sleep_queue); + return CELL_ESRCH; } - u64 counter = 0; - const u64 max_counter = timeout ? (timeout / 1000) : ~0; + if (mutex->owner.read_sync() != tid) + { + return CELL_EPERM; + } + lw->queue.push(tid_le, mutex->attribute); + + auto old_recursive = mutex->recursive_count.read_relaxed(); + mutex->recursive_count.exchange(be_t::make(0)); + + be_t target = be_t::make(sq->signal(mutex->attribute)); + if (!mutex->owner.compare_and_swap_test(tid, target)) + { + assert(!"sys_lwcond_wait(): mutex unlocking failed"); + } + + bool signaled = false; while (true) { - if (lw->signal.unlock(tid, tid) == SMR_OK) + if ((signaled = signaled || lw->queue.pop(tid, mutex->attribute))) // check signaled threads { - switch (mutex->lock(tid, 0)) + s32 res = mutex->lock(tid, timeout ? get_system_time() - start_time : 0); // this is bad + if (res == CELL_OK) { - case CELL_OK: break; - case static_cast(CELL_EDEADLK): sys_lwcond.Warning("sys_lwcond_wait(id=%d): associated mutex was locked", - (u32)lwcond->lwcond_queue); return CELL_OK; - case static_cast(CELL_ESRCH): sys_lwcond.Warning("sys_lwcond_wait(id=%d): associated mutex not found (%d)", - (u32)lwcond->lwcond_queue, (u32)mutex->sleep_queue); return CELL_ESRCH; - case static_cast(CELL_EINVAL): goto abort; + break; } - mutex->recursive_count = 1; - lw->signal.unlock(tid); - return CELL_OK; + switch (res) + { + case static_cast(CELL_EDEADLK): + { + sys_lwcond.Error("sys_lwcond_wait(id=%d): associated mutex was locked", (u32)lwcond->lwcond_queue); + return CELL_OK; // mutex not locked (but already locked in the incorrect way) + } + case static_cast(CELL_ESRCH): + { + sys_lwcond.Error("sys_lwcond_wait(id=%d): associated mutex not found (%d)", (u32)lwcond->lwcond_queue, (u32)mutex->sleep_queue); + return CELL_ESRCH; // mutex not locked + } + case static_cast(CELL_ETIMEDOUT): + { + return CELL_ETIMEDOUT; // mutex not locked + } + case static_cast(CELL_EINVAL): + { + sys_lwcond.Error("sys_lwcond_wait(id=%d): invalid associated mutex (%d)", (u32)lwcond->lwcond_queue, (u32)mutex->sleep_queue); + return CELL_EINVAL; // mutex not locked + } + default: + { + sys_lwcond.Error("sys_lwcond_wait(id=%d): mutex->lock() returned 0x%x", (u32)lwcond->lwcond_queue, res); + return CELL_EINVAL; // mutex not locked + } + } } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack - if (counter++ > max_counter) + if (timeout && get_system_time() - start_time > timeout) { - lw->m_queue.invalidate(tid_le); - return CELL_ETIMEDOUT; + if (!lw->queue.invalidate(tid_le, mutex->attribute)) + { + assert(!"sys_lwcond_wait() failed (timeout)"); + } + return CELL_ETIMEDOUT; // mutex not locked } + if (Emu.IsStopped()) { - goto abort; + sys_lwcond.Warning("sys_lwcond_wait(id=%d) aborted", (u32)lwcond->lwcond_queue); + return CELL_OK; } } -abort: - sys_lwcond.Warning("sys_lwcond_wait(id=%d) aborted", (u32)lwcond->lwcond_queue); + mutex->recursive_count.exchange(old_recursive); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.h b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.h index 5c34190776..1c519bca42 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwcond.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwcond.h @@ -19,23 +19,26 @@ struct sys_lwcond_t struct Lwcond { - SMutex signal; - SleepQueue m_queue; + sleep_queue_t queue; - Lwcond(u64 name) - : m_queue(name) + const u32 addr; + + Lwcond(u64 name, u32 addr) + : queue(name) + , addr(addr) { - signal.initialize(); } }; // Aux s32 lwcond_create(sys_lwcond_t& lwcond, sys_lwmutex_t& lwmutex, u64 name_u64); +class PPUThread; + // SysCalls s32 sys_lwcond_create(vm::ptr lwcond, vm::ptr lwmutex, vm::ptr attr); s32 sys_lwcond_destroy(vm::ptr lwcond); s32 sys_lwcond_signal(vm::ptr lwcond); s32 sys_lwcond_signal_all(vm::ptr lwcond); s32 sys_lwcond_signal_to(vm::ptr lwcond, u32 ppu_thread_id); -s32 sys_lwcond_wait(vm::ptr lwcond, u64 timeout); +s32 sys_lwcond_wait(PPUThread& CPU, vm::ptr lwcond, u64 timeout); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp index c6a08033bd..0e5eae950c 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.cpp @@ -2,35 +2,33 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/SysCalls/SysCalls.h" +#include "Emu/Memory/atomic_type.h" #include "Emu/CPU/CPUThreadManager.h" #include "Emu/Cell/PPUThread.h" +#include "sleep_queue_type.h" +#include "sys_time.h" #include "sys_lwmutex.h" SysCallBase sys_lwmutex("sys_lwmutex"); -// TODO: move SleepQueue somewhere - s32 lwmutex_create(sys_lwmutex_t& lwmutex, u32 protocol, u32 recursive, u64 name_u64) { - LV2_LOCK(0); + std::shared_ptr sq(new sleep_queue_t(name_u64)); - lwmutex.waiter = ~0; - lwmutex.mutex.initialize(); + lwmutex.owner.write_relaxed(be_t::make(0)); + lwmutex.waiter.write_relaxed(be_t::make(~0)); lwmutex.attribute = protocol | recursive; - lwmutex.recursive_count = 0; - u32 sq_id = sys_lwmutex.GetNewId(new SleepQueue(name_u64), TYPE_LWMUTEX); + lwmutex.recursive_count.write_relaxed(be_t::make(0)); + u32 sq_id = sys_lwmutex.GetNewId(sq, TYPE_LWMUTEX); lwmutex.sleep_queue = sq_id; + sq->set_full_name(fmt::Format("Lwmutex(%d, addr=0x%x)", sq_id, Memory.RealToVirtualAddr(&lwmutex))); - std::string name((const char*)&name_u64, 8); - sys_lwmutex.Notice("*** lwmutex created [%s] (attribute=0x%x): sq_id = %d", name.c_str(), protocol | recursive, sq_id); - - Emu.GetSyncPrimManager().AddLwMutexData(sq_id, name, GetCurrentPPUThread().GetId()); - + sys_lwmutex.Notice("*** lwmutex created [%s] (attribute=0x%x): sq_id = %d", std::string((const char*)&name_u64, 8).c_str(), protocol | recursive, sq_id); return CELL_OK; } -s32 sys_lwmutex_create(vm::ptr lwmutex, vm::ptr attr) +s32 sys_lwmutex_create(PPUThread& CPU, vm::ptr lwmutex, vm::ptr attr) { sys_lwmutex.Warning("sys_lwmutex_create(lwmutex_addr=0x%x, attr_addr=0x%x)", lwmutex.addr(), attr.addr()); @@ -53,7 +51,7 @@ s32 sys_lwmutex_create(vm::ptr lwmutex, vm::ptrprotocol, attr->recursive, attr->name_u64); } -s32 sys_lwmutex_destroy(vm::ptr lwmutex) +s32 sys_lwmutex_destroy(PPUThread& CPU, vm::ptr lwmutex) { sys_lwmutex.Warning("sys_lwmutex_destroy(lwmutex_addr=0x%x)", lwmutex.addr()); @@ -62,207 +60,62 @@ s32 sys_lwmutex_destroy(vm::ptr lwmutex) u32 sq_id = lwmutex->sleep_queue; if (!Emu.GetIdManager().CheckID(sq_id)) return CELL_ESRCH; - // try to make it unable to lock - switch (int res = lwmutex->trylock(lwmutex->mutex.GetDeadValue())) + if (s32 res = lwmutex->trylock(be_t::make(~0))) { - case CELL_OK: - lwmutex->all_info() = 0; - lwmutex->attribute = 0xDEADBEEF; - lwmutex->sleep_queue = 0; - Emu.GetIdManager().RemoveID(sq_id); - Emu.GetSyncPrimManager().EraseLwMutexData(sq_id); - default: return res; + return res; } + + // try to make it unable to lock + lwmutex->all_info() = 0; + lwmutex->attribute = 0xDEADBEEF; + lwmutex->sleep_queue = 0; + Emu.GetIdManager().RemoveID(sq_id); + return CELL_OK; } -s32 sys_lwmutex_lock(vm::ptr lwmutex, u64 timeout) +s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr lwmutex, u64 timeout) { sys_lwmutex.Log("sys_lwmutex_lock(lwmutex_addr=0x%x, timeout=%lld)", lwmutex.addr(), timeout); - //ConLog.Write("*** lock mutex (addr=0x%x, attr=0x%x, Nrec=%d, owner=%d, waiter=%d)", - //lwmutex.addr(), (u32)lwmutex->attribute, (u32)lwmutex->recursive_count, lwmutex->vars.parts.owner.GetOwner(), (u32)lwmutex->waiter); - - return lwmutex->lock(be_t::make(GetCurrentPPUThread().GetId()), timeout ? ((timeout < 1000) ? 1 : (timeout / 1000)) : 0); + return lwmutex->lock(be_t::make(CPU.GetId()), timeout); } -s32 sys_lwmutex_trylock(vm::ptr lwmutex) +s32 sys_lwmutex_trylock(PPUThread& CPU, vm::ptr lwmutex) { sys_lwmutex.Log("sys_lwmutex_trylock(lwmutex_addr=0x%x)", lwmutex.addr()); - return lwmutex->trylock(be_t::make(GetCurrentPPUThread().GetId())); + return lwmutex->trylock(be_t::make(CPU.GetId())); } -s32 sys_lwmutex_unlock(vm::ptr lwmutex) +s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr lwmutex) { sys_lwmutex.Log("sys_lwmutex_unlock(lwmutex_addr=0x%x)", lwmutex.addr()); - //ConLog.Write("*** unlocking mutex (addr=0x%x, attr=0x%x, Nrec=%d, owner=%d, waiter=%d)", - //lwmutex.addr(), (u32)lwmutex->attribute, (u32)lwmutex->recursive_count, (u32)lwmutex->vars.parts.owner.GetOwner(), (u32)lwmutex->waiter); - - return lwmutex->unlock(be_t::make(GetCurrentPPUThread().GetId())); + return lwmutex->unlock(be_t::make(CPU.GetId())); } -void SleepQueue::push(u32 tid) -{ - std::lock_guard lock(m_mutex); - list.push_back(tid); -} - -u32 SleepQueue::pop() // SYS_SYNC_FIFO -{ - std::lock_guard lock(m_mutex); - - while (true) - { - if (list.size()) - { - u32 res = list[0]; - list.erase(list.begin()); - if (res && Emu.GetIdManager().CheckID(res)) - // check thread - { - return res; - } - } - return 0; - }; -} - -u32 SleepQueue::pop_prio() // SYS_SYNC_PRIORITY -{ - std::lock_guard lock(m_mutex); - - while (true) - { - if (list.size()) - { - u64 highest_prio = ~0ull; - u32 sel = 0; - for (u32 i = 0; i < list.size(); i++) - { - CPUThread* t = Emu.GetCPU().GetThread(list[i]); - if (!t) - { - list[i] = 0; - sel = i; - break; - } - u64 prio = t->GetPrio(); - if (prio < highest_prio) - { - highest_prio = prio; - sel = i; - } - } - u32 res = list[sel]; - list.erase(list.begin() + sel); - /* if (Emu.GetIdManager().CheckID(res)) */ - if (res) - // check thread - { - return res; - } - } - return 0; - } -} - -u32 SleepQueue::pop_prio_inherit() // (TODO) -{ - sys_lwmutex.Error("TODO: SleepQueue::pop_prio_inherit()"); - Emu.Pause(); - return 0; -} - -bool SleepQueue::invalidate(u32 tid) -{ - std::lock_guard lock(m_mutex); - - if (tid) for (u32 i = 0; i < list.size(); i++) - { - if (list[i] == tid) - { - list.erase(list.begin() + i); - return true; - } - } - - return false; -} - -u32 SleepQueue::count() -{ - std::lock_guard lock(m_mutex); - - u32 result = 0; - for (u32 i = 0; i < list.size(); i++) - { - if (list[i]) result++; - } - return result; -} - -bool SleepQueue::finalize() -{ - if (!m_mutex.try_lock()) return false; - - for (u32 i = 0; i < list.size(); i++) - { - if (list[i]) - { - m_mutex.unlock(); - return false; - } - } - - m_mutex.unlock(); - return true; -} - -int sys_lwmutex_t::trylock(be_t tid) +s32 sys_lwmutex_t::trylock(be_t tid) { if (attribute.ToBE() == se32(0xDEADBEEF)) return CELL_EINVAL; - be_t owner_tid = mutex.GetFreeValue(); - - if (mutex.unlock(owner_tid, owner_tid) != SMR_OK) // check free value + if (!Emu.GetIdManager().CheckID(sleep_queue)) { - owner_tid = mutex.GetOwner(); - /*if (CPUThread* tt = Emu.GetCPU().GetThread(owner_tid)) - { - if (!tt->IsAlive()) - { - sc_lwmutex.Error("sys_lwmutex_t::(try)lock(%d): deadlock on invalid thread(%d)", (u32)sleep_queue, (u32)owner_tid); - mutex.unlock(owner_tid, tid); - recursive_count = 1; - return CELL_OK; - } - } - else - { - sc_lwmutex.Error("sys_lwmutex_t::(try)lock(%d): deadlock on invalid thread(%d)", (u32)sleep_queue, (u32)owner_tid); - mutex.unlock(owner_tid, tid); - recursive_count = 1; - return CELL_OK; - }*/ + return CELL_ESRCH; } - /*while ((attribute.ToBE() & se32(SYS_SYNC_ATTR_RECURSIVE_MASK)) == 0) - { - if (Emu.IsStopped()) - { - LOG_WARNING(HLE, "(hack) sys_lwmutex_t::(try)lock aborted (waiting for recursive attribute, attr=0x%x)", (u32)attribute); - return CELL_ESRCH; - } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - }*/ + const be_t old_owner = owner.read_sync(); - if (tid == owner_tid) + if (old_owner == tid) { if (attribute.ToBE() & se32(SYS_SYNC_RECURSIVE)) { - recursive_count += 1; - if (!recursive_count.ToBE()) return CELL_EKRESOURCE; + auto rv = recursive_count.read_relaxed(); + if (!~(rv++).ToBE()) + { + return CELL_EKRESOURCE; + } + + recursive_count.exchange(rv); return CELL_OK; } else @@ -271,77 +124,96 @@ int sys_lwmutex_t::trylock(be_t tid) } } - switch (mutex.trylock(tid)) + if (!owner.compare_and_swap_test(be_t::make(0), tid)) { - case SMR_OK: recursive_count = 1; return CELL_OK; - case SMR_FAILED: return CELL_EBUSY; - default: return CELL_EINVAL; + return CELL_EBUSY; } + + recursive_count.exchange(be_t::make(1)); + return CELL_OK; } -int sys_lwmutex_t::unlock(be_t tid) +s32 sys_lwmutex_t::unlock(be_t tid) { - if (mutex.unlock(tid, tid) != SMR_OK) + if (owner.read_sync() != tid) { return CELL_EPERM; } - else + + auto rv = recursive_count.read_relaxed(); + if (!rv.ToBE() || (rv.ToBE() != se32(1) && (attribute.ToBE() & se32(SYS_SYNC_NOT_RECURSIVE)))) { - if (!recursive_count || (recursive_count.ToBE() != se32(1) && (attribute.ToBE() & se32(SYS_SYNC_NOT_RECURSIVE)))) - { - sys_lwmutex.Error("sys_lwmutex_t::unlock(%d): wrong recursive value fixed (%d)", (u32)sleep_queue, (u32)recursive_count); - recursive_count = 1; - } - recursive_count -= 1; - if (!recursive_count.ToBE()) - { - be_t target = be_t::make(0); - switch (attribute.ToBE() & se32(SYS_SYNC_ATTR_PROTOCOL_MASK)) - { - case se32(SYS_SYNC_FIFO): - case se32(SYS_SYNC_PRIORITY): - SleepQueue* sq; - if (!Emu.GetIdManager().GetIDData(sleep_queue, sq)) return CELL_ESRCH; - target = attribute & SYS_SYNC_FIFO ? sq->pop() : sq->pop_prio(); - case se32(SYS_SYNC_RETRY): break; - } - if (target) mutex.unlock(tid, target); - else mutex.unlock(tid); - } - return CELL_OK; + sys_lwmutex.Error("sys_lwmutex_t::unlock(%d): wrong recursive value fixed (%d)", (u32)sleep_queue, (u32)rv); + rv = 1; } + + rv--; + recursive_count.exchange(rv); + if (!rv.ToBE()) + { + std::shared_ptr sq; + if (!Emu.GetIdManager().GetIDData(sleep_queue, sq)) + { + return CELL_ESRCH; + } + + if (!owner.compare_and_swap_test(tid, be_t::make(sq->signal(attribute)))) + { + assert(!"sys_lwmutex_t::unlock() failed"); + } + } + + return CELL_OK; } -int sys_lwmutex_t::lock(be_t tid, u64 timeout) +s32 sys_lwmutex_t::lock(be_t tid, u64 timeout) { - switch (int res = trylock(tid)) + const u64 start_time = get_system_time(); + + switch (s32 res = trylock(tid)) { - case static_cast(CELL_EBUSY): break; + case static_cast(CELL_EBUSY): break; default: return res; } - SleepQueue* sq; - if (!Emu.GetIdManager().GetIDData(sleep_queue, sq)) return CELL_ESRCH; - - switch (attribute.ToBE() & se32(SYS_SYNC_ATTR_PROTOCOL_MASK)) + std::shared_ptr sq; + if (!Emu.GetIdManager().GetIDData(sleep_queue, sq)) { - case se32(SYS_SYNC_PRIORITY): - case se32(SYS_SYNC_FIFO): - sq->push(tid); - default: break; + return CELL_ESRCH; } - switch (mutex.lock(tid, timeout)) + sq->push(tid, attribute); + + while (true) { - case SMR_OK: - sq->invalidate(tid); - case SMR_SIGNAL: - recursive_count = 1; return CELL_OK; - case SMR_TIMEOUT: - sq->invalidate(tid); return CELL_ETIMEDOUT; - case SMR_ABORT: - if (Emu.IsStopped()) sys_lwmutex.Warning("sys_lwmutex_t::lock(sq=%d) aborted", (u32)sleep_queue); - default: - sq->invalidate(tid); return CELL_EINVAL; + auto old_owner = owner.compare_and_swap(be_t::make(0), tid); + if (!old_owner.ToBE() || old_owner == tid) + { + break; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + + if (timeout && get_system_time() - start_time > timeout) + { + if (!sq->invalidate(tid, attribute)) + { + assert(!"sys_lwmutex_t::lock() failed (timeout)"); + } + return CELL_ETIMEDOUT; + } + + if (Emu.IsStopped()) + { + sys_lwmutex.Warning("sys_lwmutex_t::lock(sq=%d) aborted", (u32)sleep_queue); + return CELL_OK; + } } + + if (!sq->invalidate(tid, attribute) && !sq->pop(tid, attribute)) + { + assert(!"sys_lwmutex_t::lock() failed (locking)"); + } + recursive_count.exchange(be_t::make(1)); + return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h index 16a2381f60..ce29524d48 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_lwmutex.h @@ -1,31 +1,4 @@ #pragma once -#include - -// attr_protocol (waiting scheduling policy) -enum -{ - // First In, First Out - SYS_SYNC_FIFO = 1, - // Priority Order - SYS_SYNC_PRIORITY = 2, - // Basic Priority Inheritance Protocol (probably not implemented) - SYS_SYNC_PRIORITY_INHERIT = 3, - // Not selected while unlocking - SYS_SYNC_RETRY = 4, - // - SYS_SYNC_ATTR_PROTOCOL_MASK = 0xF, -}; - -// attr_recursive (recursive locks policy) -enum -{ - // Recursive locks are allowed - SYS_SYNC_RECURSIVE = 0x10, - // Recursive locks are NOT allowed - SYS_SYNC_NOT_RECURSIVE = 0x20, - // - SYS_SYNC_ATTR_RECURSIVE_MASK = 0xF0, //??? -}; struct sys_lwmutex_attribute_t { @@ -38,38 +11,12 @@ struct sys_lwmutex_attribute_t }; }; -struct SleepQueue -{ - /* struct q_rec - { - u32 tid; - u64 prio; - q_rec(u32 tid, u64 prio): tid(tid), prio(prio) {} - }; */ - std::vector list; - std::mutex m_mutex; - u64 m_name; - - SleepQueue(u64 name = 0) - : m_name(name) - { - } - - void push(u32 tid); - u32 pop(); // SYS_SYNC_FIFO - u32 pop_prio(); // SYS_SYNC_PRIORITY - u32 pop_prio_inherit(); // (TODO) - bool invalidate(u32 tid); - u32 count(); - bool finalize(); -}; - struct sys_lwmutex_t { - SMutexBase> mutex; - be_t waiter; // currently not used + atomic_t owner; + atomic_t waiter; // currently not used be_t attribute; - be_t recursive_count; + atomic_t recursive_count; be_t sleep_queue; be_t pad; @@ -78,17 +25,19 @@ struct sys_lwmutex_t return *(reinterpret_cast(this)); } - int trylock(be_t tid); - int unlock(be_t tid); - int lock(be_t tid, u64 timeout); + s32 trylock(be_t tid); + s32 unlock(be_t tid); + s32 lock(be_t tid, u64 timeout); }; // Aux s32 lwmutex_create(sys_lwmutex_t& lwmutex, u32 protocol, u32 recursive, u64 name_u64); +class PPUThread; + // SysCalls -s32 sys_lwmutex_create(vm::ptr lwmutex, vm::ptr attr); -s32 sys_lwmutex_destroy(vm::ptr lwmutex); -s32 sys_lwmutex_lock(vm::ptr lwmutex, u64 timeout); -s32 sys_lwmutex_trylock(vm::ptr lwmutex); -s32 sys_lwmutex_unlock(vm::ptr lwmutex); +s32 sys_lwmutex_create(PPUThread& CPU, vm::ptr lwmutex, vm::ptr attr); +s32 sys_lwmutex_destroy(PPUThread& CPU, vm::ptr lwmutex); +s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr lwmutex, u64 timeout); +s32 sys_lwmutex_trylock(PPUThread& CPU, vm::ptr lwmutex); +s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr lwmutex); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_memory.cpp b/rpcs3/Emu/SysCalls/lv2/sys_memory.cpp index ed68723e9d..b6b5e9ea57 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_memory.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_memory.cpp @@ -43,7 +43,7 @@ s32 sys_memory_allocate_from_container(u32 size, u32 cid, u32 flags, u32 alloc_a sys_memory.Log("sys_memory_allocate_from_container(size=0x%x, cid=0x%x, flags=0x%x)", size, cid, flags); // Check if this container ID is valid. - MemoryContainerInfo* ct; + std::shared_ptr ct; if (!sys_memory.CheckId(cid, ct)) return CELL_ESRCH; @@ -119,7 +119,7 @@ s32 sys_memory_container_create(vm::ptr cid, u32 yield_size) return CELL_ENOMEM; // Wrap the allocated memory in a memory container. - MemoryContainerInfo *ct = new MemoryContainerInfo(addr, yield_size); + std::shared_ptr ct(new MemoryContainerInfo(addr, yield_size)); u32 id = sys_memory.GetNewId(ct, TYPE_MEM); *cid = id; @@ -133,7 +133,7 @@ s32 sys_memory_container_destroy(u32 cid) sys_memory.Warning("sys_memory_container_destroy(cid=%d)", cid); // Check if this container ID is valid. - MemoryContainerInfo* ct; + std::shared_ptr ct; if (!sys_memory.CheckId(cid, ct)) return CELL_ESRCH; @@ -149,7 +149,7 @@ s32 sys_memory_container_get_size(vm::ptr mem_info, u32 cid) sys_memory.Warning("sys_memory_container_get_size(mem_info_addr=0x%x, cid=%d)", mem_info.addr(), cid); // Check if this container ID is valid. - MemoryContainerInfo* ct; + std::shared_ptr ct; if (!sys_memory.CheckId(cid, ct)) return CELL_ESRCH; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_mmapper.cpp b/rpcs3/Emu/SysCalls/lv2/sys_mmapper.cpp index 8dc1c35709..8c7f221160 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_mmapper.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_mmapper.cpp @@ -75,7 +75,8 @@ s32 sys_mmapper_allocate_memory(u32 size, u64 flags, vm::ptr mem_id) } // Generate a new mem ID. - *mem_id = sys_mmapper.GetNewId(new mmapper_info(size, flags)); + std::shared_ptr info(new mmapper_info(size, flags)); + *mem_id = sys_mmapper.GetNewId(info); return CELL_OK; } @@ -86,7 +87,7 @@ s32 sys_mmapper_allocate_memory_from_container(u32 size, u32 cid, u64 flags, vm: size, cid, flags, mem_id.addr()); // Check if this container ID is valid. - MemoryContainerInfo* ct; + std::shared_ptr ct; if(!sys_mmapper.CheckId(cid, ct)) return CELL_ESRCH; @@ -110,7 +111,8 @@ s32 sys_mmapper_allocate_memory_from_container(u32 size, u32 cid, u64 flags, vm: ct->size = size; // Generate a new mem ID. - *mem_id = sys_mmapper.GetNewId(new mmapper_info(ct->size, flags), TYPE_MEM); + std::shared_ptr info(new mmapper_info(ct->size, flags)); + *mem_id = sys_mmapper.GetNewId(info, TYPE_MEM); return CELL_OK; } @@ -138,7 +140,7 @@ s32 sys_mmapper_free_memory(u32 mem_id) sys_mmapper.Warning("sys_mmapper_free_memory(mem_id=0x%x)", mem_id); // Check if this mem ID is valid. - mmapper_info* info; + std::shared_ptr info; if(!sys_mmapper.CheckId(mem_id, info)) return CELL_ESRCH; @@ -153,7 +155,7 @@ s32 sys_mmapper_map_memory(u32 start_addr, u32 mem_id, u64 flags) sys_mmapper.Warning("sys_mmapper_map_memory(start_addr=0x%x, mem_id=0x%x, flags=0x%llx)", start_addr, mem_id, flags); // Check if this mem ID is valid. - mmapper_info* info; + std::shared_ptr info; if(!sys_mmapper.CheckId(mem_id, info)) return CELL_ESRCH; @@ -173,7 +175,7 @@ s32 sys_mmapper_search_and_map(u32 start_addr, u32 mem_id, u64 flags, u32 alloc_ start_addr, mem_id, flags, alloc_addr); // Check if this mem ID is valid. - mmapper_info* info; + std::shared_ptr info; if(!sys_mmapper.CheckId(mem_id, info)) return CELL_ESRCH; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp b/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp index f22dd97d87..07ca016830 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_mutex.cpp @@ -2,36 +2,33 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/SysCalls/SysCalls.h" +#include "Emu/Memory/atomic_type.h" #include "Emu/CPU/CPUThreadManager.h" #include "Emu/Cell/PPUThread.h" +#include "sleep_queue_type.h" +#include "sys_time.h" #include "sys_mutex.h" SysCallBase sys_mutex("sys_mutex"); Mutex::~Mutex() { - if (u32 owner = m_mutex.GetOwner()) + if (u32 tid = owner.read_sync()) { - sys_mutex.Notice("Mutex(%d) was owned by thread %d (recursive=%d)", id, owner, recursive); + sys_mutex.Notice("Mutex(%d) was owned by thread %d (recursive=%d)", id, tid, recursive_count.load()); } - if (!m_queue.m_mutex.try_lock()) return; - - for (u32 i = 0; i < m_queue.list.size(); i++) + if (u32 count = queue.count()) { - if (u32 owner = m_queue.list[i]) sys_mutex.Notice("Mutex(%d) was waited by thread %d", id, owner); + sys_mutex.Notice("Mutex(%d) was waited by %d threads", id, count); } - - m_queue.m_mutex.unlock(); } -s32 sys_mutex_create(vm::ptr mutex_id, vm::ptr attr) +s32 sys_mutex_create(PPUThread& CPU, vm::ptr mutex_id, vm::ptr attr) { sys_mutex.Log("sys_mutex_create(mutex_id_addr=0x%x, attr_addr=0x%x)", mutex_id.addr(), attr.addr()); - LV2_LOCK(0); - switch (attr->protocol.ToBE()) { case se32(SYS_SYNC_FIFO): break; @@ -55,79 +52,72 @@ s32 sys_mutex_create(vm::ptr mutex_id, vm::ptr attr) return CELL_EINVAL; } - u32 tid = GetCurrentPPUThread().GetId(); - Mutex* mutex = new Mutex((u32)attr->protocol, is_recursive, attr->name_u64); - u32 id = sys_mutex.GetNewId(mutex, TYPE_MUTEX); - mutex->m_mutex.lock(tid); - mutex->id = id; + std::shared_ptr mutex(new Mutex((u32)attr->protocol, is_recursive, attr->name_u64)); + + const u32 id = sys_mutex.GetNewId(mutex, TYPE_MUTEX); + mutex->id.exchange(id); *mutex_id = id; - mutex->m_mutex.unlock(tid); + mutex->queue.set_full_name(fmt::Format("Mutex(%d)", id)); + sys_mutex.Warning("*** mutex created [%s] (protocol=0x%x, recursive=%s): id = %d", std::string(attr->name, 8).c_str(), (u32) attr->protocol, (is_recursive ? "true" : "false"), id); - - Emu.GetSyncPrimManager().AddSyncPrimData(TYPE_MUTEX, id, std::string(attr->name, 8)); // TODO: unlock mutex when owner thread does exit - return CELL_OK; } -s32 sys_mutex_destroy(u32 mutex_id) +s32 sys_mutex_destroy(PPUThread& CPU, u32 mutex_id) { sys_mutex.Warning("sys_mutex_destroy(mutex_id=%d)", mutex_id); - LV2_LOCK(0); - - Mutex* mutex; + std::shared_ptr mutex; if (!Emu.GetIdManager().GetIDData(mutex_id, mutex)) { return CELL_ESRCH; } - if (mutex->cond_count) // check if associated condition variable exists + // check if associated condition variable exists + if (mutex->cond_count) // TODO: check safety { return CELL_EPERM; } - u32 tid = GetCurrentPPUThread().GetId(); - - if (mutex->m_mutex.trylock(tid)) // check if locked + if (!mutex->owner.compare_and_swap_test(0, ~0)) // check if locked and make unusable { return CELL_EBUSY; } - if (!mutex->m_queue.finalize()) - { - mutex->m_mutex.unlock(tid); - return CELL_EBUSY; - } - - mutex->m_mutex.unlock(tid, ~0); Emu.GetIdManager().RemoveID(mutex_id); - Emu.GetSyncPrimManager().EraseSyncPrimData(TYPE_MUTEX, mutex_id); return CELL_OK; } -s32 sys_mutex_lock(u32 mutex_id, u64 timeout) +s32 sys_mutex_lock(PPUThread& CPU, u32 mutex_id, u64 timeout) { sys_mutex.Log("sys_mutex_lock(mutex_id=%d, timeout=%lld)", mutex_id, timeout); - Mutex* mutex; + const u64 start_time = get_system_time(); + + std::shared_ptr mutex; if (!Emu.GetIdManager().GetIDData(mutex_id, mutex)) { return CELL_ESRCH; } - PPUThread& t = GetCurrentPPUThread(); - u32 tid = t.GetId(); + const u32 tid = CPU.GetId(); - if (mutex->m_mutex.unlock(tid, tid) == SMR_OK) + const u32 old_owner = mutex->owner.compare_and_swap(0, tid); + if (!~old_owner) + { + return CELL_ESRCH; // mutex is going to be destroyed + } + if (old_owner == tid) { if (mutex->is_recursive) { - if (++mutex->recursive == 0) + if (!~mutex->recursive_count) { return CELL_EKRESOURCE; } + mutex->recursive_count++; return CELL_OK; } else @@ -135,68 +125,76 @@ s32 sys_mutex_lock(u32 mutex_id, u64 timeout) return CELL_EDEADLK; } } - else if (u32 owner = mutex->m_mutex.GetOwner()) + else if (!old_owner) { - if (CPUThread* tt = Emu.GetCPU().GetThread(owner)) - { - } - else - { - sys_mutex.Error("sys_mutex_lock(%d): deadlock on invalid thread(%d)", mutex_id, owner); - } - } - - switch (mutex->m_mutex.trylock(tid)) - { - case SMR_OK: mutex->recursive = 1; t.owned_mutexes++; return CELL_OK; - case SMR_FAILED: break; - default: goto abort; - } - - mutex->m_queue.push(tid); - - switch (mutex->m_mutex.lock(tid, timeout ? ((timeout < 1000) ? 1 : (timeout / 1000)) : 0)) - { - case SMR_OK: - mutex->m_queue.invalidate(tid); - case SMR_SIGNAL: - mutex->recursive = 1; t.owned_mutexes++; return CELL_OK; - case SMR_TIMEOUT: - mutex->m_queue.invalidate(tid); return CELL_ETIMEDOUT; - default: - mutex->m_queue.invalidate(tid); goto abort; - } - -abort: - if (Emu.IsStopped()) - { - sys_mutex.Warning("sys_mutex_lock(id=%d) aborted", mutex_id); + mutex->recursive_count = 1; + CPU.owned_mutexes++; return CELL_OK; } - return CELL_ESRCH; + + mutex->queue.push(tid, mutex->protocol); + + while (true) + { + auto old_owner = mutex->owner.compare_and_swap(0, tid); + if (!old_owner || old_owner == tid) + { + break; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + + if (timeout && get_system_time() - start_time > timeout) + { + if (!mutex->queue.invalidate(tid, mutex->protocol)) + { + assert(!"sys_mutex_lock() failed (timeout)"); + } + return CELL_ETIMEDOUT; + } + + if (Emu.IsStopped()) + { + sys_mutex.Warning("sys_mutex_lock(id=%d) aborted", mutex_id); + return CELL_OK; + } + } + + if (!mutex->queue.invalidate(tid, mutex->protocol) && !mutex->queue.pop(tid, mutex->protocol)) + { + assert(!"sys_mutex_lock() failed (locking)"); + } + mutex->recursive_count = 1; + CPU.owned_mutexes++; + return CELL_OK; } -s32 sys_mutex_trylock(u32 mutex_id) +s32 sys_mutex_trylock(PPUThread& CPU, u32 mutex_id) { sys_mutex.Log("sys_mutex_trylock(mutex_id=%d)", mutex_id); - Mutex* mutex; + std::shared_ptr mutex; if (!Emu.GetIdManager().GetIDData(mutex_id, mutex)) { return CELL_ESRCH; } - PPUThread& t = GetCurrentPPUThread(); - u32 tid = t.GetId(); + const u32 tid = CPU.GetId(); - if (mutex->m_mutex.unlock(tid, tid) == SMR_OK) + const u32 old_owner = mutex->owner.compare_and_swap(0, tid); + if (!~old_owner) + { + return CELL_ESRCH; // mutex is going to be destroyed + } + if (old_owner == tid) { if (mutex->is_recursive) { - if (++mutex->recursive == 0) + if (!~mutex->recursive_count) { return CELL_EKRESOURCE; } + mutex->recursive_count++; return CELL_OK; } else @@ -204,52 +202,51 @@ s32 sys_mutex_trylock(u32 mutex_id) return CELL_EDEADLK; } } - else if (u32 owner = mutex->m_mutex.GetOwner()) + else if (!old_owner) { - if (CPUThread* tt = Emu.GetCPU().GetThread(owner)) - { - } - else - { - sys_mutex.Error("sys_mutex_trylock(%d): deadlock on invalid thread(%d)", mutex_id, owner); - } + mutex->recursive_count = 1; + CPU.owned_mutexes++; + return CELL_OK; } - switch (mutex->m_mutex.trylock(tid)) - { - case SMR_OK: mutex->recursive = 1; t.owned_mutexes++; return CELL_OK; - default: return CELL_EBUSY; - } + return CELL_EBUSY; } -s32 sys_mutex_unlock(u32 mutex_id) +s32 sys_mutex_unlock(PPUThread& CPU, u32 mutex_id) { sys_mutex.Log("sys_mutex_unlock(mutex_id=%d)", mutex_id); - Mutex* mutex; + std::shared_ptr mutex; if (!Emu.GetIdManager().GetIDData(mutex_id, mutex)) { return CELL_ESRCH; } - PPUThread& t = GetCurrentPPUThread(); - u32 tid = t.GetId(); + const u32 tid = CPU.GetId(); - if (mutex->m_mutex.unlock(tid, tid) == SMR_OK) + const u32 owner = mutex->owner.read_sync(); + if (!~owner) { - if (!mutex->recursive || (mutex->recursive != 1 && !mutex->is_recursive)) - { - sys_mutex.Error("sys_mutex_unlock(%d): wrong recursive value fixed (%d)", mutex_id, mutex->recursive); - mutex->recursive = 1; - } - mutex->recursive--; - if (!mutex->recursive) - { - mutex->m_mutex.unlock(tid, mutex->protocol == SYS_SYNC_PRIORITY ? mutex->m_queue.pop_prio() : mutex->m_queue.pop()); - t.owned_mutexes--; - } - return CELL_OK; + return CELL_ESRCH; // mutex is going to be destroyed + } + if (owner != tid) + { + return CELL_EPERM; } - return CELL_EPERM; + if (!mutex->recursive_count || (mutex->recursive_count != 1 && !mutex->is_recursive)) + { + sys_mutex.Error("sys_mutex_unlock(%d): wrong recursive value fixed (%d)", mutex_id, mutex->recursive_count.load()); + mutex->recursive_count = 1; + } + + if (!--mutex->recursive_count) + { + if (!mutex->owner.compare_and_swap_test(tid, mutex->queue.signal(mutex->protocol))) + { + assert(!"sys_mutex_unlock() failed"); + } + CPU.owned_mutexes--; + } + return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_mutex.h b/rpcs3/Emu/SysCalls/lv2/sys_mutex.h index 74a7378e63..2767dbe31c 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_mutex.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_mutex.h @@ -1,5 +1,4 @@ #pragma once -#include "sys_lwmutex.h" struct sys_mutex_attribute { @@ -8,7 +7,7 @@ struct sys_mutex_attribute be_t pshared; // always 0x200 (not shared) be_t adaptive; be_t ipc_key; - be_t flags; + be_t flags; be_t pad; union { @@ -19,11 +18,11 @@ struct sys_mutex_attribute struct Mutex { - u32 id; - SMutex m_mutex; - SleepQueue m_queue; - u32 recursive; // recursive locks count + atomic_le_t id; + atomic_le_t owner; + std::atomic recursive_count; // recursive locks count std::atomic cond_count; // count of condition variables associated + sleep_queue_t queue; const u32 protocol; const bool is_recursive; @@ -31,18 +30,20 @@ struct Mutex Mutex(u32 protocol, bool is_recursive, u64 name) : protocol(protocol) , is_recursive(is_recursive) - , m_queue(name) + , queue(name) , cond_count(0) { - m_mutex.initialize(); + owner.write_relaxed(0); } ~Mutex(); }; +class PPUThread; + // SysCalls -s32 sys_mutex_create(vm::ptr mutex_id, vm::ptr attr); -s32 sys_mutex_destroy(u32 mutex_id); -s32 sys_mutex_lock(u32 mutex_id, u64 timeout); -s32 sys_mutex_trylock(u32 mutex_id); -s32 sys_mutex_unlock(u32 mutex_id); +s32 sys_mutex_create(PPUThread& CPU, vm::ptr mutex_id, vm::ptr attr); +s32 sys_mutex_destroy(PPUThread& CPU, u32 mutex_id); +s32 sys_mutex_lock(PPUThread& CPU, u32 mutex_id, u64 timeout); +s32 sys_mutex_trylock(PPUThread& CPU, u32 mutex_id); +s32 sys_mutex_unlock(PPUThread& CPU, u32 mutex_id); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp b/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp index e60882bc21..bb1b49eead 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_ppu_thread.cpp @@ -43,7 +43,7 @@ s32 sys_ppu_thread_yield() { sys_ppu_thread.Log("sys_ppu_thread_yield()"); // Note: Or do we actually want to yield? - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack return CELL_OK; } @@ -51,7 +51,7 @@ s32 sys_ppu_thread_join(u64 thread_id, vm::ptr vptr) { sys_ppu_thread.Warning("sys_ppu_thread_join(thread_id=%lld, vptr_addr=0x%x)", thread_id, vptr.addr()); - CPUThread* thr = Emu.GetCPU().GetThread(thread_id); + std::shared_ptr thr = Emu.GetCPU().GetThread(thread_id); if(!thr) return CELL_ESRCH; while (thr->IsAlive()) @@ -61,7 +61,7 @@ s32 sys_ppu_thread_join(u64 thread_id, vm::ptr vptr) sys_ppu_thread.Warning("sys_ppu_thread_join(%d) aborted", thread_id); return CELL_OK; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } *vptr = thr->GetExitStatus(); @@ -72,7 +72,7 @@ s32 sys_ppu_thread_detach(u64 thread_id) { sys_ppu_thread.Todo("sys_ppu_thread_detach(thread_id=%lld)", thread_id); - CPUThread* thr = Emu.GetCPU().GetThread(thread_id); + std::shared_ptr thr = Emu.GetCPU().GetThread(thread_id); if(!thr) return CELL_ESRCH; if(!thr->IsJoinable()) @@ -93,7 +93,7 @@ s32 sys_ppu_thread_set_priority(u64 thread_id, s32 prio) { sys_ppu_thread.Log("sys_ppu_thread_set_priority(thread_id=%lld, prio=%d)", thread_id, prio); - CPUThread* thr = Emu.GetCPU().GetThread(thread_id); + std::shared_ptr thr = Emu.GetCPU().GetThread(thread_id); if(!thr) return CELL_ESRCH; thr->SetPrio(prio); @@ -105,7 +105,7 @@ s32 sys_ppu_thread_get_priority(u64 thread_id, u32 prio_addr) { sys_ppu_thread.Log("sys_ppu_thread_get_priority(thread_id=%lld, prio_addr=0x%x)", thread_id, prio_addr); - CPUThread* thr = Emu.GetCPU().GetThread(thread_id); + std::shared_ptr thr = Emu.GetCPU().GetThread(thread_id); if(!thr) return CELL_ESRCH; vm::write32(prio_addr, (s32)thr->GetPrio()); @@ -127,7 +127,7 @@ s32 sys_ppu_thread_stop(u64 thread_id) { sys_ppu_thread.Warning("sys_ppu_thread_stop(thread_id=%lld)", thread_id); - CPUThread* thr = Emu.GetCPU().GetThread(thread_id); + std::shared_ptr thr = Emu.GetCPU().GetThread(thread_id); if(!thr) return CELL_ESRCH; thr->Stop(); @@ -139,7 +139,7 @@ s32 sys_ppu_thread_restart(u64 thread_id) { sys_ppu_thread.Warning("sys_ppu_thread_restart(thread_id=%lld)", thread_id); - CPUThread* thr = Emu.GetCPU().GetThread(thread_id); + std::shared_ptr thr = Emu.GetCPU().GetThread(thread_id); if(!thr) return CELL_ESRCH; thr->Stop(); @@ -233,7 +233,7 @@ s32 sys_ppu_thread_rename(u64 thread_id, vm::ptr name) { sys_ppu_thread.Log("sys_ppu_thread_rename(thread_id=%d, name_addr=0x%x('%s'))", thread_id, name.addr(), name.get_ptr()); - CPUThread* thr = Emu.GetCPU().GetThread(thread_id); + std::shared_ptr thr = Emu.GetCPU().GetThread(thread_id); if (!thr) { return CELL_ESRCH; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_process.cpp b/rpcs3/Emu/SysCalls/lv2/sys_process.cpp index ea419694d4..ccbe619bee 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_process.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_process.cpp @@ -1,4 +1,5 @@ #include "stdafx.h" +#include "Emu/FS/VFS.h" #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/SysCalls/SysCalls.h" @@ -38,17 +39,20 @@ s32 sys_process_exit(s32 errorcode) return CELL_OK; } -void sys_game_process_exitspawn( - vm::ptr path, - u32 argv_addr, - u32 envp_addr, - u32 data_addr, - u32 data_size, - u32 prio, - u64 flags ) +void sys_game_process_exitspawn(vm::ptr path, u32 argv_addr, u32 envp_addr, u32 data_addr, u32 data_size, u32 prio, u64 flags) { + std::string _path = path.get_ptr(); + const std::string& from = "//"; + const std::string& to = "/"; + + size_t start_pos = 0; + while ((start_pos = _path.find(from, start_pos)) != std::string::npos) { + _path.replace(start_pos, from.length(), to); + start_pos += to.length(); + } + sys_process.Todo("sys_game_process_exitspawn()"); - sys_process.Warning("path: %s", path.get_ptr()); + sys_process.Warning("path: %s", _path.c_str()); sys_process.Warning("argv: 0x%x", argv_addr); sys_process.Warning("envp: 0x%x", envp_addr); sys_process.Warning("data: 0x%x", data_addr); @@ -56,29 +60,35 @@ void sys_game_process_exitspawn( sys_process.Warning("prio: %d", prio); sys_process.Warning("flags: %d", flags); - std::string _path = path.get_ptr(); std::vector argv; std::vector env; - auto argvp = vm::ptr>::make(argv_addr); - while (argvp && *argvp) + if (argv_addr) { - argv.push_back(argvp[0].get_ptr()); - argvp++; - } - auto envp = vm::ptr>::make(envp_addr); - while (envp && *envp) - { - env.push_back(envp[0].get_ptr()); - envp++; + auto argvp = vm::ptr>::make(argv_addr); + while (argvp && *argvp) + { + argv.push_back(argvp[0].get_ptr()); + argvp++; + } + + for (auto &arg : argv) { + sys_process.Log("argument: %s", arg.c_str()); + } } - for (auto &arg : argv) { - sys_process.Log("argument: %s", arg.c_str()); - } + if (envp_addr) + { + auto envp = vm::ptr>::make(envp_addr); + while (envp && *envp) + { + env.push_back(envp[0].get_ptr()); + envp++; + } - for (auto &en : env) { - sys_process.Log("env_argument: %s", en.c_str()); + for (auto &en : env) { + sys_process.Log("env_argument: %s", en.c_str()); + } } //TODO: execute the file in with the args in argv @@ -94,20 +104,29 @@ void sys_game_process_exitspawn( Emu.Stop(); }); + std::string real_path; + + Emu.GetVFS().GetDevice(_path.c_str(), real_path); + + Emu.BootGame(real_path, true); + return; } -void sys_game_process_exitspawn2( - vm::ptr path, - u32 argv_addr, - u32 envp_addr, - u32 data_addr, - u32 data_size, - u32 prio, - u64 flags) +void sys_game_process_exitspawn2(vm::ptr path, u32 argv_addr, u32 envp_addr, u32 data_addr, u32 data_size, u32 prio, u64 flags) { - sys_process.Todo("sys_game_process_exitspawn2"); - sys_process.Warning("path: %s", path.get_ptr()); + std::string _path = path.get_ptr(); + const std::string& from = "//"; + const std::string& to = "/"; + + size_t start_pos = 0; + while ((start_pos = _path.find(from, start_pos)) != std::string::npos) { + _path.replace(start_pos, from.length(), to); + start_pos += to.length(); + } + + sys_process.Warning("sys_game_process_exitspawn2()"); + sys_process.Warning("path: %s", _path.c_str()); sys_process.Warning("argv: 0x%x", argv_addr); sys_process.Warning("envp: 0x%x", envp_addr); sys_process.Warning("data: 0x%x", data_addr); @@ -115,29 +134,37 @@ void sys_game_process_exitspawn2( sys_process.Warning("prio: %d", prio); sys_process.Warning("flags: %d", flags); - std::string _path = path.get_ptr(); std::vector argv; std::vector env; - auto argvp = vm::ptr>::make(argv_addr); - while (argvp && *argvp) + if (argv_addr) { - argv.push_back(argvp[0].get_ptr()); - argvp++; - } - auto envp = vm::ptr>::make(envp_addr); - while (envp && *envp) - { - env.push_back(envp[0].get_ptr()); - envp++; + auto argvp = vm::ptr>::make(argv_addr); + while (argvp && *argvp) + { + argv.push_back(argvp[0].get_ptr()); + argvp++; + } + + for (auto &arg : argv) + { + sys_process.Log("argument: %s", arg.c_str()); + } } - for (auto &arg : argv) { - sys_process.Log("argument: %s", arg.c_str()); - } + if (envp_addr) + { + auto envp = vm::ptr>::make(envp_addr); + while (envp && *envp) + { + env.push_back(envp[0].get_ptr()); + envp++; + } - for (auto &en : env) { - sys_process.Log("env_argument: %s", en.c_str()); + for (auto &en : env) + { + sys_process.Log("env_argument: %s", en.c_str()); + } } //TODO: execute the file in with the args in argv @@ -152,13 +179,19 @@ void sys_game_process_exitspawn2( { Emu.Stop(); }); + + std::string real_path; + + Emu.GetVFS().GetDevice(_path.c_str(), real_path); + + Emu.BootGame(real_path, true); return; } s32 sys_process_get_number_of_object(u32 object, vm::ptr nump) { - sys_process.Warning("sys_process_get_number_of_object(object=%d, nump_addr=0x%x)", + sys_process.Todo("sys_process_get_number_of_object(object=%d, nump_addr=0x%x)", object, nump.addr()); switch(object) @@ -201,7 +234,7 @@ s32 sys_process_get_id(u32 object, vm::ptr buffer, u32 size, vm::ptr s #define ADD_OBJECTS(type) { \ u32 i=0; \ - const auto& objects = Emu.GetIdManager().GetTypeIDs(type); \ + const auto objects = Emu.GetIdManager().GetTypeIDs(type); \ for(auto id=objects.begin(); i path, u64 flags, vm::ptr prx(new sys_prx_t()); prx->size = (u32)f.GetSize(); prx->address = (u32)Memory.Alloc(prx->size, 4); prx->path = (const char*)path; @@ -66,7 +66,7 @@ s32 sys_prx_start_module(s32 id, u32 args, u32 argp_addr, vm::ptr modres, u sys_prx.Todo("sys_prx_start_module(id=%d, args=%d, argp_addr=0x%x, modres_addr=0x%x, flags=0x%llx, pOpt=0x%x)", id, args, argp_addr, modres.addr(), flags, pOpt.addr()); - sys_prx_t* prx; + std::shared_ptr prx; if (!Emu.GetIdManager().GetIDData(id, prx)) return CELL_ESRCH; @@ -81,7 +81,7 @@ s32 sys_prx_stop_module(s32 id, u32 args, u32 argp_addr, vm::ptr modres, u6 sys_prx.Todo("sys_prx_stop_module(id=%d, args=%d, argp_addr=0x%x, modres_addr=0x%x, flags=0x%llx, pOpt=0x%x)", id, args, argp_addr, modres.addr(), flags, pOpt.addr()); - sys_prx_t* prx; + std::shared_ptr prx; if (!Emu.GetIdManager().GetIDData(id, prx)) return CELL_ESRCH; @@ -96,7 +96,7 @@ s32 sys_prx_unload_module(s32 id, u64 flags, vm::ptr prx; if (!Emu.GetIdManager().GetIDData(id, prx)) return CELL_ESRCH; Memory.Free(prx->address); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_rwlock.cpp b/rpcs3/Emu/SysCalls/lv2/sys_rwlock.cpp index b35ff563ff..7190e5dfc0 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_rwlock.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_rwlock.cpp @@ -2,9 +2,11 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/SysCalls/SysCalls.h" +#include "Emu/Memory/atomic_type.h" #include "Emu/Cell/PPUThread.h" -#include "sys_lwmutex.h" +#include "sleep_queue_type.h" +#include "sys_time.h" #include "sys_rwlock.h" SysCallBase sys_rwlock("sys_rwlock"); @@ -13,30 +15,27 @@ s32 sys_rwlock_create(vm::ptr rw_lock_id, vm::ptr a { sys_rwlock.Warning("sys_rwlock_create(rw_lock_id_addr=0x%x, attr_addr=0x%x)", rw_lock_id.addr(), attr.addr()); - if (!attr) - return CELL_EFAULT; - - switch (attr->attr_protocol.ToBE()) + switch (attr->protocol.ToBE()) { - case se32(SYS_SYNC_PRIORITY): sys_rwlock.Todo("SYS_SYNC_PRIORITY"); break; + case se32(SYS_SYNC_PRIORITY): break; case se32(SYS_SYNC_RETRY): sys_rwlock.Error("SYS_SYNC_RETRY"); return CELL_EINVAL; case se32(SYS_SYNC_PRIORITY_INHERIT): sys_rwlock.Todo("SYS_SYNC_PRIORITY_INHERIT"); break; case se32(SYS_SYNC_FIFO): break; default: return CELL_EINVAL; } - if (attr->attr_pshared.ToBE() != se32(0x200)) + if (attr->pshared.ToBE() != se32(0x200)) { - sys_rwlock.Error("Invalid attr_pshared(0x%x)", (u32)attr->attr_pshared); + sys_rwlock.Error("Invalid pshared value (0x%x)", (u32)attr->pshared); return CELL_EINVAL; } - u32 id = sys_rwlock.GetNewId(new RWLock((u32)attr->attr_protocol, attr->name_u64), TYPE_RWLOCK); + std::shared_ptr rw(new RWLock((u32)attr->protocol, attr->name_u64)); + const u32 id = sys_rwlock.GetNewId(rw, TYPE_RWLOCK); *rw_lock_id = id; + rw->wqueue.set_full_name(fmt::Format("Rwlock(%d)", id)); - sys_rwlock.Warning("*** rwlock created [%s] (protocol=0x%x): id = %d", - std::string(attr->name, 8).c_str(), (u32)attr->attr_protocol, id); - + sys_rwlock.Warning("*** rwlock created [%s] (protocol=0x%x): id = %d", std::string(attr->name, 8).c_str(), rw->protocol, id); return CELL_OK; } @@ -44,15 +43,18 @@ s32 sys_rwlock_destroy(u32 rw_lock_id) { sys_rwlock.Warning("sys_rwlock_destroy(rw_lock_id=%d)", rw_lock_id); - RWLock* rw; - if (!sys_rwlock.CheckId(rw_lock_id, rw)) return CELL_ESRCH; + std::shared_ptr rw; + if (!sys_rwlock.CheckId(rw_lock_id, rw)) + { + return CELL_ESRCH; + } - std::lock_guard lock(rw->m_lock); - - if (rw->wlock_queue.size() || rw->rlock_list.size() || rw->wlock_thread) return CELL_EBUSY; + if (!rw->sync.compare_and_swap_test({ 0, 0 }, { ~0u, ~0u })) // check if locked and make unusable + { + return CELL_EBUSY; + } Emu.GetIdManager().RemoveID(rw_lock_id); - return CELL_OK; } @@ -60,125 +62,209 @@ s32 sys_rwlock_rlock(u32 rw_lock_id, u64 timeout) { sys_rwlock.Log("sys_rwlock_rlock(rw_lock_id=%d, timeout=%lld)", rw_lock_id, timeout); - RWLock* rw; - if (!sys_rwlock.CheckId(rw_lock_id, rw)) return CELL_ESRCH; - const u32 tid = GetCurrentPPUThread().GetId(); + const u64 start_time = get_system_time(); - if (rw->rlock_trylock(tid)) return CELL_OK; - - u64 counter = 0; - const u64 max_counter = timeout ? (timeout / 1000) : 20000; - do + std::shared_ptr rw; + if (!sys_rwlock.CheckId(rw_lock_id, rw)) { - if (Emu.IsStopped()) + return CELL_ESRCH; + } + + while (true) + { + bool succeeded; + rw->sync.atomic_op_sync([&succeeded](RWLock::sync_var_t& sync) + { + assert(~sync.readers); + if ((succeeded = !sync.writer)) + { + sync.readers++; + } + }); + + if (succeeded) + { + break; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + + if (timeout && get_system_time() - start_time > timeout) { - sys_rwlock.Warning("sys_rwlock_rlock(rw_lock_id=%d, ...) aborted", rw_lock_id); return CELL_ETIMEDOUT; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - if (rw->rlock_trylock(tid)) return CELL_OK; - - if (counter++ > max_counter) + if (Emu.IsStopped()) { - if (!timeout) - { - counter = 0; - } - else - { - return CELL_ETIMEDOUT; - } - } - } while (true); + sys_rwlock.Warning("sys_rwlock_rlock(id=%d) aborted", rw_lock_id); + return CELL_OK; + } + } + + return CELL_OK; } s32 sys_rwlock_tryrlock(u32 rw_lock_id) { sys_rwlock.Log("sys_rwlock_tryrlock(rw_lock_id=%d)", rw_lock_id); - RWLock* rw; - if (!sys_rwlock.CheckId(rw_lock_id, rw)) return CELL_ESRCH; + std::shared_ptr rw; + if (!sys_rwlock.CheckId(rw_lock_id, rw)) + { + return CELL_ESRCH; + } - if (!rw->rlock_trylock(GetCurrentPPUThread().GetId())) return CELL_EBUSY; + bool succeeded; + rw->sync.atomic_op_sync([&succeeded](RWLock::sync_var_t& sync) + { + assert(~sync.readers); + if ((succeeded = !sync.writer)) + { + sync.readers++; + } + }); - return CELL_OK; + if (succeeded) + { + return CELL_OK; + } + + return CELL_EBUSY; } s32 sys_rwlock_runlock(u32 rw_lock_id) { sys_rwlock.Log("sys_rwlock_runlock(rw_lock_id=%d)", rw_lock_id); - RWLock* rw; - if (!sys_rwlock.CheckId(rw_lock_id, rw)) return CELL_ESRCH; + std::shared_ptr rw; + if (!sys_rwlock.CheckId(rw_lock_id, rw)) + { + return CELL_ESRCH; + } - if (!rw->rlock_unlock(GetCurrentPPUThread().GetId())) return CELL_EPERM; + bool succeeded; + rw->sync.atomic_op_sync([&succeeded](RWLock::sync_var_t& sync) + { + if ((succeeded = sync.readers != 0)) + { + assert(!sync.writer); + sync.readers--; + } + }); - return CELL_OK; + if (succeeded) + { + return CELL_OK; + } + + return CELL_EPERM; } -s32 sys_rwlock_wlock(u32 rw_lock_id, u64 timeout) +s32 sys_rwlock_wlock(PPUThread& CPU, u32 rw_lock_id, u64 timeout) { sys_rwlock.Log("sys_rwlock_wlock(rw_lock_id=%d, timeout=%lld)", rw_lock_id, timeout); - RWLock* rw; - if (!sys_rwlock.CheckId(rw_lock_id, rw)) return CELL_ESRCH; - const u32 tid = GetCurrentPPUThread().GetId(); + const u64 start_time = get_system_time(); - if (!rw->wlock_check(tid)) return CELL_EDEADLK; - - if (rw->wlock_trylock(tid, true)) return CELL_OK; - - u64 counter = 0; - const u64 max_counter = timeout ? (timeout / 1000) : 20000; - do + std::shared_ptr rw; + if (!sys_rwlock.CheckId(rw_lock_id, rw)) { - if (Emu.IsStopped()) + return CELL_ESRCH; + } + + const u32 tid = CPU.GetId(); + + if (rw->sync.compare_and_swap_test({ 0, 0 }, { 0, tid })) + { + return CELL_OK; + } + + if (rw->sync.read_relaxed().writer == tid) + { + return CELL_EDEADLK; + } + + rw->wqueue.push(tid, rw->protocol); + + while (true) + { + auto old_sync = rw->sync.compare_and_swap({ 0, 0 }, { 0, tid }); + if (!old_sync.readers && (!old_sync.writer || old_sync.writer == tid)) { - sys_rwlock.Warning("sys_rwlock_wlock(rw_lock_id=%d, ...) aborted", rw_lock_id); + break; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + + if (timeout && get_system_time() - start_time > timeout) + { + if (!rw->wqueue.invalidate(tid, rw->protocol)) + { + assert(!"sys_rwlock_wlock() failed (timeout)"); + } return CELL_ETIMEDOUT; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - if (rw->wlock_trylock(tid, true)) return CELL_OK; - - if (counter++ > max_counter) + if (Emu.IsStopped()) { - if (!timeout) - { - counter = 0; - } - else - { - return CELL_ETIMEDOUT; - } - } - } while (true); + sys_rwlock.Warning("sys_rwlock_wlock(id=%d) aborted", rw_lock_id); + return CELL_OK; + } + } + + if (!rw->wqueue.invalidate(tid, rw->protocol) && !rw->wqueue.pop(tid, rw->protocol)) + { + assert(!"sys_rwlock_wlock() failed (locking)"); + } + return CELL_OK; } -s32 sys_rwlock_trywlock(u32 rw_lock_id) +s32 sys_rwlock_trywlock(PPUThread& CPU, u32 rw_lock_id) { sys_rwlock.Log("sys_rwlock_trywlock(rw_lock_id=%d)", rw_lock_id); - RWLock* rw; - if (!sys_rwlock.CheckId(rw_lock_id, rw)) return CELL_ESRCH; - const u32 tid = GetCurrentPPUThread().GetId(); + std::shared_ptr rw; + if (!sys_rwlock.CheckId(rw_lock_id, rw)) + { + return CELL_ESRCH; + } - if (!rw->wlock_check(tid)) return CELL_EDEADLK; + const u32 tid = CPU.GetId(); - if (!rw->wlock_trylock(tid, false)) return CELL_EBUSY; + if (rw->sync.compare_and_swap_test({ 0, 0 }, { 0, tid })) + { + return CELL_OK; + } - return CELL_OK; + if (rw->sync.read_relaxed().writer == tid) + { + return CELL_EDEADLK; + } + + return CELL_EBUSY; } -s32 sys_rwlock_wunlock(u32 rw_lock_id) +s32 sys_rwlock_wunlock(PPUThread& CPU, u32 rw_lock_id) { sys_rwlock.Log("sys_rwlock_wunlock(rw_lock_id=%d)", rw_lock_id); - RWLock* rw; - if (!sys_rwlock.CheckId(rw_lock_id, rw)) return CELL_ESRCH; + std::shared_ptr rw; + if (!sys_rwlock.CheckId(rw_lock_id, rw)) + { + return CELL_ESRCH; + } - if (!rw->wlock_unlock(GetCurrentPPUThread().GetId())) return CELL_EPERM; + const u32 tid = CPU.GetId(); + const u32 target = rw->wqueue.signal(rw->protocol); - return CELL_OK; + if (rw->sync.compare_and_swap_test({ 0, tid }, { 0, target })) + { + if (!target) + { + // TODO: signal readers + } + return CELL_OK; + } + + return CELL_EPERM; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_rwlock.h b/rpcs3/Emu/SysCalls/lv2/sys_rwlock.h index eab184f21f..27ca2a72b6 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_rwlock.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_rwlock.h @@ -2,11 +2,11 @@ struct sys_rwlock_attribute_t { - be_t attr_protocol; - be_t attr_pshared; // == 0x200 (NOT SHARED) - be_t key; // process-shared key (not used) - be_t flags; // process-shared flags (not used) - be_t pad; // not used + be_t protocol; + be_t pshared; + be_t ipc_key; + be_t flags; + be_t pad; union { char name[8]; @@ -16,136 +16,22 @@ struct sys_rwlock_attribute_t struct RWLock { - std::mutex m_lock; // internal lock - u32 wlock_thread; // write lock owner - std::vector wlock_queue; // write lock queue - std::vector rlock_list; // read lock list - u32 m_protocol; // TODO - - union + struct sync_var_t { - u64 m_name_u64; - char m_name[8]; + u32 readers; // reader count + u32 writer; // writer thread id }; + sleep_queue_t wqueue; + atomic_le_t sync; + + const u32 protocol; + RWLock(u32 protocol, u64 name) - : m_protocol(protocol) - , m_name_u64(name) - , wlock_thread(0) + : protocol(protocol) + , wqueue(name) { - } - - bool rlock_trylock(u32 tid) - { - std::lock_guard lock(m_lock); - - if (!wlock_thread && !wlock_queue.size()) - { - rlock_list.push_back(tid); - return true; - } - return false; - } - - bool rlock_unlock(u32 tid) - { - std::lock_guard lock(m_lock); - - for (u32 i = (u32)rlock_list.size() - 1; ~i; i--) - { - if (rlock_list[i] == tid) - { - rlock_list.erase(rlock_list.begin() + i); - return true; - } - } - return false; - } - - bool wlock_check(u32 tid) - { - std::lock_guard lock(m_lock); - - if (wlock_thread == tid) - { - return false; // deadlock - } - for (u32 i = (u32)rlock_list.size() - 1; ~i; i--) - { - if (rlock_list[i] == tid) - { - return false; // deadlock - } - } - return true; - } - - bool wlock_trylock(u32 tid, bool enqueue) - { - std::lock_guard lock(m_lock); - - if (wlock_thread || rlock_list.size()) // already locked - { - if (!enqueue) - { - return false; // do not enqueue - } - for (u32 i = (u32)wlock_queue.size() - 1; ~i; i--) - { - if (wlock_queue[i] == tid) - { - return false; // already enqueued - } - } - wlock_queue.push_back(tid); // enqueue new thread - return false; - } - else - { - if (wlock_queue.size()) - { - // SYNC_FIFO only yet - if (wlock_queue[0] == tid) - { - wlock_thread = tid; - wlock_queue.erase(wlock_queue.begin()); - return true; - } - else - { - if (!enqueue) - { - return false; // do not enqueue - } - for (u32 i = (u32)wlock_queue.size() - 1; ~i; i--) - { - if (wlock_queue[i] == tid) - { - return false; // already enqueued - } - } - wlock_queue.push_back(tid); // enqueue new thread - return false; - } - } - else - { - wlock_thread = tid; // easy way - return true; - } - } - } - - bool wlock_unlock(u32 tid) - { - std::lock_guard lock(m_lock); - - if (wlock_thread == tid) - { - wlock_thread = 0; - return true; - } - return false; + sync.write_relaxed({ 0, 0 }); } }; @@ -155,6 +41,6 @@ s32 sys_rwlock_destroy(u32 rw_lock_id); s32 sys_rwlock_rlock(u32 rw_lock_id, u64 timeout); s32 sys_rwlock_tryrlock(u32 rw_lock_id); s32 sys_rwlock_runlock(u32 rw_lock_id); -s32 sys_rwlock_wlock(u32 rw_lock_id, u64 timeout); -s32 sys_rwlock_trywlock(u32 rw_lock_id); -s32 sys_rwlock_wunlock(u32 rw_lock_id); +s32 sys_rwlock_wlock(PPUThread& CPU, u32 rw_lock_id, u64 timeout); +s32 sys_rwlock_trywlock(PPUThread& CPU, u32 rw_lock_id); +s32 sys_rwlock_wunlock(PPUThread& CPU, u32 rw_lock_id); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp b/rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp index d194a0b563..a5291cc684 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_semaphore.cpp @@ -2,9 +2,11 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/SysCalls/SysCalls.h" +#include "Emu/Memory/atomic_type.h" #include "Emu/CPU/CPUThreadManager.h" #include "Emu/Cell/PPUThread.h" +#include "sleep_queue_type.h" #include "sys_time.h" #include "sys_semaphore.h" @@ -12,12 +14,12 @@ SysCallBase sys_semaphore("sys_semaphore"); u32 semaphore_create(s32 initial_count, s32 max_count, u32 protocol, u64 name_u64) { - LV2_LOCK(0); + std::shared_ptr sem(new Semaphore(initial_count, max_count, protocol, name_u64)); - const std::string name((const char*)&name_u64, 8); - const u32 id = sys_semaphore.GetNewId(new Semaphore(initial_count, max_count, protocol, name_u64), TYPE_SEMAPHORE); - sys_semaphore.Notice("*** semaphore created [%s] (protocol=0x%x): id = %d", name.c_str(), protocol, id); - Emu.GetSyncPrimManager().AddSemaphoreData(id, name, initial_count, max_count); + const u32 id = sys_semaphore.GetNewId(sem, TYPE_SEMAPHORE); + sem->queue.set_full_name(fmt::Format("Semaphore(%d)", id)); + + sys_semaphore.Notice("*** semaphore created [%s] (protocol=0x%x): id = %d", std::string((const char*)&name_u64, 8).c_str(), protocol, id); return id; } @@ -26,15 +28,17 @@ s32 sys_semaphore_create(vm::ptr sem, vm::ptr attr sys_semaphore.Warning("sys_semaphore_create(sem_addr=0x%x, attr_addr=0x%x, initial_count=%d, max_count=%d)", sem.addr(), attr.addr(), initial_count, max_count); - if (sem.addr() == NULL) { - sys_semaphore.Error("sys_semaphore_create(): invalid memory access (sem_addr=0x%x)", sem.addr()); - return CELL_EFAULT; - } + if (!sem) + { + sys_semaphore.Error("sys_semaphore_create(): invalid memory access (sem_addr=0x%x)", sem.addr()); + return CELL_EFAULT; + } - if (attr.addr() == NULL) { - sys_semaphore.Error("sys_semaphore_create(): An invalid argument value is specified (attr_addr=0x%x)", attr.addr()); - return CELL_EFAULT; - } + if (!attr) + { + sys_semaphore.Error("sys_semaphore_create(): An invalid argument value is specified (attr_addr=0x%x)", attr.addr()); + return CELL_EFAULT; + } if (max_count <= 0 || initial_count > max_count || initial_count < 0) { @@ -65,21 +69,18 @@ s32 sys_semaphore_destroy(u32 sem_id) { sys_semaphore.Warning("sys_semaphore_destroy(sem_id=%d)", sem_id); - LV2_LOCK(0); - - Semaphore* sem; + std::shared_ptr sem; if (!Emu.GetIdManager().GetIDData(sem_id, sem)) { return CELL_ESRCH; } - if (!sem->m_queue.finalize()) + if (sem->queue.count()) // TODO: safely make object unusable { return CELL_EBUSY; } Emu.GetIdManager().RemoveID(sem_id); - Emu.GetSyncPrimManager().EraseSemaphoreData(sem_id); return CELL_OK; } @@ -87,70 +88,92 @@ s32 sys_semaphore_wait(u32 sem_id, u64 timeout) { sys_semaphore.Log("sys_semaphore_wait(sem_id=%d, timeout=%lld)", sem_id, timeout); - Semaphore* sem; + const u64 start_time = get_system_time(); + + std::shared_ptr sem; if (!Emu.GetIdManager().GetIDData(sem_id, sem)) { return CELL_ESRCH; } const u32 tid = GetCurrentPPUThread().GetId(); - const u64 start_time = get_system_time(); + s32 old_value; { - std::lock_guard lock(sem->m_mutex); - if (sem->m_value > 0) + sem->value.atomic_op_sync([&old_value](s32& value) + { + old_value = value; + if (value > 0) + { + value--; + } + }); + + if (old_value > 0) { - sem->m_value--; return CELL_OK; } - sem->m_queue.push(tid); + + sem->queue.push(tid, sem->protocol); } + while (true) { + if (sem->queue.pop(tid, sem->protocol)) + { + break; + } + + assert(!sem->value.read_sync()); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack + + if (timeout && get_system_time() - start_time > timeout) + { + if (!sem->queue.invalidate(tid, sem->protocol)) + { + if (sem->queue.pop(tid, sem->protocol)) + { + return CELL_OK; + } + assert(!"sys_semaphore_wait() failed (timeout)"); + } + return CELL_ETIMEDOUT; + } + if (Emu.IsStopped()) { sys_semaphore.Warning("sys_semaphore_wait(%d) aborted", sem_id); return CELL_OK; } - - if (timeout && get_system_time() - start_time > timeout) - { - sem->m_queue.invalidate(tid); - return CELL_ETIMEDOUT; - } - - if (tid == sem->signal) - { - std::lock_guard lock(sem->m_mutex); - - if (tid != sem->signal) - { - continue; - } - sem->signal = 0; - return CELL_OK; - } - - std::this_thread::sleep_for(std::chrono::milliseconds(1)); } + + return CELL_OK; } s32 sys_semaphore_trywait(u32 sem_id) { sys_semaphore.Log("sys_semaphore_trywait(sem_id=%d)", sem_id); - Semaphore* sem; + std::shared_ptr sem; if (!Emu.GetIdManager().GetIDData(sem_id, sem)) { return CELL_ESRCH; } - std::lock_guard lock(sem->m_mutex); + s32 old_value; - if (sem->m_value > 0) + sem->value.atomic_op_sync([&old_value](s32& value) + { + old_value = value; + if (value > 0) + { + value--; + } + }); + + if (old_value > 0) { - sem->m_value--; return CELL_OK; } else @@ -163,7 +186,7 @@ s32 sys_semaphore_post(u32 sem_id, s32 count) { sys_semaphore.Log("sys_semaphore_post(sem_id=%d, count=%d)", sem_id, count); - Semaphore* sem; + std::shared_ptr sem; if (!Emu.GetIdManager().GetIDData(sem_id, sem)) { return CELL_ESRCH; @@ -174,7 +197,7 @@ s32 sys_semaphore_post(u32 sem_id, s32 count) return CELL_EINVAL; } - if (count + sem->m_value - (s32)sem->m_queue.count() > sem->max) + if (count + sem->value.read_sync() - (s32)sem->queue.count() > sem->max) { return CELL_EBUSY; } @@ -187,22 +210,16 @@ s32 sys_semaphore_post(u32 sem_id, s32 count) return CELL_OK; } - std::lock_guard lock(sem->m_mutex); - - if (sem->signal && sem->m_queue.count()) - { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - continue; - } - - if (u32 target = (sem->protocol == SYS_SYNC_FIFO) ? sem->m_queue.pop() : sem->m_queue.pop_prio()) + if (u32 target = sem->queue.signal(sem->protocol)) { count--; - sem->signal = target; } else { - sem->m_value += count; + sem->value.atomic_op([count](s32& value) + { + value += count; + }); count = 0; } } @@ -214,20 +231,18 @@ s32 sys_semaphore_get_value(u32 sem_id, vm::ptr count) { sys_semaphore.Log("sys_semaphore_get_value(sem_id=%d, count_addr=0x%x)", sem_id, count.addr()); - if (count.addr() == NULL) { - sys_semaphore.Error("sys_semaphore_get_value(): invalid memory access (count=0x%x)", count.addr()); - return CELL_EFAULT; - } + if (!count) + { + sys_semaphore.Error("sys_semaphore_get_value(): invalid memory access (addr=0x%x)", count.addr()); + return CELL_EFAULT; + } - Semaphore* sem; + std::shared_ptr sem; if (!Emu.GetIdManager().GetIDData(sem_id, sem)) { return CELL_ESRCH; } - std::lock_guard lock(sem->m_mutex); - - *count = sem->m_value; - + *count = sem->value.read_sync(); return CELL_OK; } diff --git a/rpcs3/Emu/SysCalls/lv2/sys_semaphore.h b/rpcs3/Emu/SysCalls/lv2/sys_semaphore.h index 19956ad377..7c3ac68c4e 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_semaphore.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_semaphore.h @@ -1,7 +1,5 @@ #pragma once -#include "sys_lwmutex.h" - struct sys_semaphore_attribute { be_t protocol; @@ -18,22 +16,19 @@ struct sys_semaphore_attribute struct Semaphore { - std::mutex m_mutex; - SleepQueue m_queue; - s32 m_value; - u32 signal; + sleep_queue_t queue; + atomic_le_t value; const s32 max; const u32 protocol; const u64 name; Semaphore(s32 initial_count, s32 max_count, u32 protocol, u64 name) - : m_value(initial_count) - , signal(0) - , max(max_count) + : max(max_count) , protocol(protocol) , name(name) { + value.write_relaxed(initial_count); } }; diff --git a/rpcs3/Emu/SysCalls/lv2/sys_spinlock.cpp b/rpcs3/Emu/SysCalls/lv2/sys_spinlock.cpp index 4a24c2b520..519cf44069 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_spinlock.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_spinlock.cpp @@ -59,4 +59,4 @@ void sys_spinlock_unlock(vm::ptr> lock) // prx: sync and set 0 lock->exchange(be_t::make(0)); -} \ No newline at end of file +} diff --git a/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp b/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp index 4a4a1a5523..29cdb9bd39 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_spu.cpp @@ -78,7 +78,7 @@ s32 sys_spu_image_open(vm::ptr img, vm::ptr path) return CELL_OK; } -SPUThread* spu_thread_initialize(SpuGroupInfo* group, u32 spu_num, sys_spu_image& img, const std::string& name, u32 option, u64 a1, u64 a2, u64 a3, u64 a4, std::function task) +SPUThread* spu_thread_initialize(std::shared_ptr& group, u32 spu_num, sys_spu_image& img, const std::string& name, u32 option, u64 a1, u64 a2, u64 a3, u64 a4, std::function task) { if (option) { @@ -117,7 +117,7 @@ s32 sys_spu_thread_initialize(vm::ptr thread, u32 group, u32 spu_num, vm::p sys_spu.Warning("sys_spu_thread_initialize(thread_addr=0x%x, group=0x%x, spu_num=%d, img_addr=0x%x, attr_addr=0x%x, arg_addr=0x%x)", thread.addr(), group, spu_num, img.addr(), attr.addr(), arg.addr()); - SpuGroupInfo* group_info; + std::shared_ptr group_info; if(!Emu.GetIdManager().GetIDData(group, group_info)) { return CELL_ESRCH; @@ -150,14 +150,14 @@ s32 sys_spu_thread_set_argument(u32 id, vm::ptr arg) { sys_spu.Warning("sys_spu_thread_set_argument(id=%d, arg_addr=0x%x)", id, arg.addr()); - CPUThread* thr = Emu.GetCPU().GetThread(id); + std::shared_ptr thr = Emu.GetCPU().GetThread(id); if(!thr || thr->GetType() != CPU_THREAD_SPU) { return CELL_ESRCH; } - SPUThread& spu = *(SPUThread*)thr; + SPUThread& spu = *(SPUThread*)thr.get(); spu.GPR[3] = u128::from64(0, arg->arg1); spu.GPR[4] = u128::from64(0, arg->arg2); @@ -171,7 +171,7 @@ s32 sys_spu_thread_get_exit_status(u32 id, vm::ptr status) { sys_spu.Warning("sys_spu_thread_get_exit_status(id=%d, status_addr=0x%x)", id, status.addr()); - CPUThread* thr = Emu.GetCPU().GetThread(id); + std::shared_ptr thr = Emu.GetCPU().GetThread(id); if(!thr || thr->GetType() != CPU_THREAD_SPU) { @@ -179,7 +179,7 @@ s32 sys_spu_thread_get_exit_status(u32 id, vm::ptr status) } u32 res; - if (!(*(SPUThread*)thr).SPU.Out_MBox.Pop(res) || !thr->IsStopped()) + if (!(*(SPUThread*)thr.get()).SPU.Out_MBox.Pop(res) || !thr->IsStopped()) { return CELL_ESTAT; } @@ -192,7 +192,7 @@ s32 sys_spu_thread_group_destroy(u32 id) { sys_spu.Warning("sys_spu_thread_group_destroy(id=%d)", id); - SpuGroupInfo* group_info; + std::shared_ptr group_info; if(!Emu.GetIdManager().GetIDData(id, group_info)) { return CELL_ESRCH; @@ -215,10 +215,10 @@ s32 sys_spu_thread_group_destroy(u32 id) for (u32 i = 0; i < group_info->list.size(); i++) { // TODO: disconnect all event ports - CPUThread* t = Emu.GetCPU().GetThread(group_info->list[i]); + std::shared_ptr t = Emu.GetCPU().GetThread(group_info->list[i]); if (t) { - Memory.Free(((SPUThread*)t)->GetOffset()); + Memory.Free(((SPUThread*)t.get())->GetOffset()); Emu.GetCPU().RemoveThread(group_info->list[i]); } } @@ -234,7 +234,7 @@ s32 sys_spu_thread_group_start(u32 id) { sys_spu.Warning("sys_spu_thread_group_start(id=%d)", id); - SpuGroupInfo* group_info; + std::shared_ptr group_info; if(!Emu.GetIdManager().GetIDData(id, group_info)) { return CELL_ESRCH; @@ -252,10 +252,10 @@ s32 sys_spu_thread_group_start(u32 id) for (u32 i = 0; i < group_info->list.size(); i++) { - CPUThread* t = Emu.GetCPU().GetThread(group_info->list[i]); + std::shared_ptr t = Emu.GetCPU().GetThread(group_info->list[i]); if (t) { - ((SPUThread*)t)->SPU.Status.SetValue(SPU_STATUS_RUNNING); + ((SPUThread*)t.get())->SPU.Status.SetValue(SPU_STATUS_RUNNING); t->Exec(); } } @@ -270,7 +270,7 @@ s32 sys_spu_thread_group_suspend(u32 id) { sys_spu.Log("sys_spu_thread_group_suspend(id=%d)", id); - SpuGroupInfo* group_info; + std::shared_ptr group_info; if(!Emu.GetIdManager().GetIDData(id, group_info)) { return CELL_ESRCH; @@ -291,7 +291,7 @@ s32 sys_spu_thread_group_suspend(u32 id) for (u32 i = 0; i < group_info->list.size(); i++) { - if (CPUThread* t = Emu.GetCPU().GetThread(group_info->list[i])) + if (std::shared_ptr t = Emu.GetCPU().GetThread(group_info->list[i])) { t->Pause(); } @@ -316,7 +316,7 @@ s32 sys_spu_thread_group_resume(u32 id) { sys_spu.Log("sys_spu_thread_group_resume(id=%d)", id); - SpuGroupInfo* group_info; + std::shared_ptr group_info; if(!Emu.GetIdManager().GetIDData(id, group_info)) { return CELL_ESRCH; @@ -344,7 +344,7 @@ s32 sys_spu_thread_group_resume(u32 id) for (u32 i = 0; i < group_info->list.size(); i++) { - if (CPUThread* t = Emu.GetCPU().GetThread(group_info->list[i])) + if (std::shared_ptr t = Emu.GetCPU().GetThread(group_info->list[i])) { t->Resume(); } @@ -363,7 +363,7 @@ s32 sys_spu_thread_group_yield(u32 id) { sys_spu.Error("sys_spu_thread_group_yield(id=%d)", id); - SpuGroupInfo* group_info; + std::shared_ptr group_info; if (!Emu.GetIdManager().GetIDData(id, group_info)) { return CELL_ESRCH; @@ -405,7 +405,7 @@ s32 sys_spu_thread_group_terminate(u32 id, int value) { sys_spu.Error("sys_spu_thread_group_terminate(id=%d, value=%d)", id, value); - SpuGroupInfo* group_info; + std::shared_ptr group_info; if (!Emu.GetIdManager().GetIDData(id, group_info)) { return CELL_ESRCH; @@ -425,9 +425,9 @@ s32 sys_spu_thread_group_terminate(u32 id, int value) //SET BUSY for (u32 i = 0; i < group_info->list.size(); i++) { - if (CPUThread* t = Emu.GetCPU().GetThread(group_info->list[i])) + if (std::shared_ptr t = Emu.GetCPU().GetThread(group_info->list[i])) { - ((SPUThread*)t)->SPU.Status.SetValue(SPU_STATUS_STOPPED); + ((SPUThread*)t.get())->SPU.Status.SetValue(SPU_STATUS_STOPPED); t->Stop(); } } @@ -440,20 +440,19 @@ s32 sys_spu_thread_group_terminate(u32 id, int value) return CELL_OK; } -SpuGroupInfo* spu_thread_group_create(const std::string& name, u32 num, s32 prio, s32 type, u32 container) +std::shared_ptr spu_thread_group_create(const std::string& name, u32 num, s32 prio, s32 type, u32 container) { - LV2_LOCK(0); - if (type) { sys_spu.Todo("Unsupported SPU Thread Group type (0x%x)", type); } - auto group = new SpuGroupInfo(name, num, prio, type, container); + std::shared_ptr group(new SpuGroupInfo(name, num, prio, type, container)); + const u32 _id = sys_spu.GetNewId(group); group->m_id = _id; - sys_spu.Notice("*** SPU Thread Group created [%s] (num=%d, prio=%d, type=0x%x, container=%d): id=%d", - name.c_str(), num, prio, type, container, _id); + + sys_spu.Notice("*** SPU Thread Group created [%s] (num=%d, prio=%d, type=0x%x, container=%d): id=%d", name.c_str(), num, prio, type, container, _id); return group; } @@ -475,7 +474,7 @@ s32 sys_spu_thread_group_join(u32 id, vm::ptr cause, vm::ptr status) { sys_spu.Warning("sys_spu_thread_group_join(id=%d, cause_addr=0x%x, status_addr=0x%x)", id, cause.addr(), status.addr()); - SpuGroupInfo* group_info; + std::shared_ptr group_info; if(!Emu.GetIdManager().GetIDData(id, group_info)) { return CELL_ESRCH; @@ -489,11 +488,11 @@ s32 sys_spu_thread_group_join(u32 id, vm::ptr cause, vm::ptr status) bool all_threads_exit = true; for (u32 i = 0; i < group_info->list.size(); i++) { - while (CPUThread* t = Emu.GetCPU().GetThread(group_info->list[i])) + while (std::shared_ptr t = Emu.GetCPU().GetThread(group_info->list[i])) { if (!t->IsAlive()) { - if (((SPUThread*)t)->SPU.Status.GetValue() != SPU_STATUS_STOPPED_BY_STOP) + if (((SPUThread*)t.get())->SPU.Status.GetValue() != SPU_STATUS_STOPPED_BY_STOP) { all_threads_exit = false; } @@ -504,7 +503,7 @@ s32 sys_spu_thread_group_join(u32 id, vm::ptr cause, vm::ptr status) sys_spu.Warning("sys_spu_thread_group_join(id=%d) aborted", id); return CELL_OK; } - std::this_thread::sleep_for(std::chrono::milliseconds(1)); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack } } @@ -548,7 +547,7 @@ s32 sys_spu_thread_write_ls(u32 id, u32 address, u64 value, u32 type) sys_spu.Log("sys_spu_thread_write_ls(id=%d, address=0x%x, value=0x%llx, type=0x%x)", id, address, value, type); - CPUThread* thr = Emu.GetCPU().GetThread(id); + std::shared_ptr thr = Emu.GetCPU().GetThread(id); if(!thr || thr->GetType() != CPU_THREAD_SPU) { @@ -567,10 +566,10 @@ s32 sys_spu_thread_write_ls(u32 id, u32 address, u64 value, u32 type) switch (type) { - case 1: (*(SPUThread*)thr).WriteLS8(address, (u8)value); return CELL_OK; - case 2: (*(SPUThread*)thr).WriteLS16(address, (u16)value); return CELL_OK; - case 4: (*(SPUThread*)thr).WriteLS32(address, (u32)value); return CELL_OK; - case 8: (*(SPUThread*)thr).WriteLS64(address, value); return CELL_OK; + case 1: (*(SPUThread*)thr.get()).WriteLS8(address, (u8)value); return CELL_OK; + case 2: (*(SPUThread*)thr.get()).WriteLS16(address, (u16)value); return CELL_OK; + case 4: (*(SPUThread*)thr.get()).WriteLS32(address, (u32)value); return CELL_OK; + case 8: (*(SPUThread*)thr.get()).WriteLS64(address, value); return CELL_OK; default: return CELL_EINVAL; } } @@ -580,7 +579,7 @@ s32 sys_spu_thread_read_ls(u32 id, u32 address, vm::ptr value, u32 type) sys_spu.Log("sys_spu_thread_read_ls(id=%d, address=0x%x, value_addr=0x%x, type=0x%x)", id, address, value.addr(), type); - CPUThread* thr = Emu.GetCPU().GetThread(id); + std::shared_ptr thr = Emu.GetCPU().GetThread(id); if(!thr || thr->GetType() != CPU_THREAD_SPU) { @@ -599,10 +598,10 @@ s32 sys_spu_thread_read_ls(u32 id, u32 address, vm::ptr value, u32 type) switch (type) { - case 1: *value = (*(SPUThread*)thr).ReadLS8(address); return CELL_OK; - case 2: *value = (*(SPUThread*)thr).ReadLS16(address); return CELL_OK; - case 4: *value = (*(SPUThread*)thr).ReadLS32(address); return CELL_OK; - case 8: *value = (*(SPUThread*)thr).ReadLS64(address); return CELL_OK; + case 1: *value = (*(SPUThread*)thr.get()).ReadLS8(address); return CELL_OK; + case 2: *value = (*(SPUThread*)thr.get()).ReadLS16(address); return CELL_OK; + case 4: *value = (*(SPUThread*)thr.get()).ReadLS32(address); return CELL_OK; + case 8: *value = (*(SPUThread*)thr.get()).ReadLS64(address); return CELL_OK; default: return CELL_EINVAL; } } @@ -611,14 +610,14 @@ s32 sys_spu_thread_write_spu_mb(u32 id, u32 value) { sys_spu.Warning("sys_spu_thread_write_spu_mb(id=%d, value=0x%x)", id, value); - CPUThread* thr = Emu.GetCPU().GetThread(id); + std::shared_ptr thr = Emu.GetCPU().GetThread(id); if(!thr || thr->GetType() != CPU_THREAD_SPU) { return CELL_ESRCH; } - (*(SPUThread*)thr).SPU.In_MBox.PushUncond(value); + (*(SPUThread*)thr.get()).SPU.In_MBox.PushUncond(value); return CELL_OK; } @@ -627,7 +626,7 @@ s32 sys_spu_thread_set_spu_cfg(u32 id, u64 value) { sys_spu.Warning("sys_spu_thread_set_spu_cfg(id=%d, value=0x%x)", id, value); - CPUThread* thr = Emu.GetCPU().GetThread(id); + std::shared_ptr thr = Emu.GetCPU().GetThread(id); if(!thr || thr->GetType() != CPU_THREAD_SPU) { @@ -639,7 +638,7 @@ s32 sys_spu_thread_set_spu_cfg(u32 id, u64 value) return CELL_EINVAL; } - (*(SPUThread*)thr).cfg.value = value; + (*(SPUThread*)thr.get()).cfg.value = value; return CELL_OK; } @@ -648,14 +647,14 @@ s32 sys_spu_thread_get_spu_cfg(u32 id, vm::ptr value) { sys_spu.Warning("sys_spu_thread_get_spu_cfg(id=%d, value_addr=0x%x)", id, value.addr()); - CPUThread* thr = Emu.GetCPU().GetThread(id); + std::shared_ptr thr = Emu.GetCPU().GetThread(id); if(!thr || thr->GetType() != CPU_THREAD_SPU) { return CELL_ESRCH; } - *value = (*(SPUThread*)thr).cfg.value; + *value = (*(SPUThread*)thr.get()).cfg.value; return CELL_OK; } @@ -663,7 +662,8 @@ s32 sys_spu_thread_get_spu_cfg(u32 id, vm::ptr value) s32 sys_spu_thread_write_snr(u32 id, u32 number, u32 value) { sys_spu.Log("sys_spu_thread_write_snr(id=%d, number=%d, value=0x%x)", id, number, value); - CPUThread* thr = Emu.GetCPU().GetThread(id); + + std::shared_ptr thr = Emu.GetCPU().GetThread(id); if(!thr || thr->GetType() != CPU_THREAD_SPU) { @@ -675,7 +675,7 @@ s32 sys_spu_thread_write_snr(u32 id, u32 number, u32 value) return CELL_EINVAL; } - (*(SPUThread*)thr).WriteSNR(number ? true : false, value); + (*(SPUThread*)thr.get()).WriteSNR(number ? true : false, value); return CELL_OK; } @@ -706,14 +706,14 @@ s32 sys_spu_thread_connect_event(u32 id, u32 eq_id, u32 et, u8 spup) { sys_spu.Warning("sys_spu_thread_connect_event(id=%d, eq_id=%d, event_type=0x%x, spup=%d)", id, eq_id, et, spup); - CPUThread* thr = Emu.GetCPU().GetThread(id); + std::shared_ptr thr = Emu.GetCPU().GetThread(id); if(!thr || thr->GetType() != CPU_THREAD_SPU) { return CELL_ESRCH; } - EventQueue* eq; + std::shared_ptr eq; if (!Emu.GetIdManager().GetIDData(eq_id, eq)) { return CELL_ESRCH; @@ -733,19 +733,19 @@ s32 sys_spu_thread_connect_event(u32 id, u32 eq_id, u32 et, u8 spup) // TODO: check if can receive these events - SPUThread& spu = *(SPUThread*)thr; + SPUThread& spu = *(SPUThread*)thr.get(); - EventPort& port = spu.SPUPs[spup]; + std::shared_ptr port = spu.SPUPs[spup]; - std::lock_guard lock(port.m_mutex); + std::lock_guard lock(port->m_mutex); - if (port.eq) + if (port->eq) { return CELL_EISCONN; } - eq->ports.add(&port); - port.eq = eq; + eq->ports.add(port); + port->eq = eq; return CELL_OK; } @@ -754,7 +754,7 @@ s32 sys_spu_thread_disconnect_event(u32 id, u32 et, u8 spup) { sys_spu.Warning("sys_spu_thread_disconnect_event(id=%d, event_type=0x%x, spup=%d)", id, et, spup); - CPUThread* thr = Emu.GetCPU().GetThread(id); + std::shared_ptr thr = Emu.GetCPU().GetThread(id); if(!thr || thr->GetType() != CPU_THREAD_SPU) { @@ -773,19 +773,19 @@ s32 sys_spu_thread_disconnect_event(u32 id, u32 et, u8 spup) return CELL_EINVAL; } - SPUThread& spu = *(SPUThread*)thr; + SPUThread& spu = *(SPUThread*)thr.get(); - EventPort& port = spu.SPUPs[spup]; + std::shared_ptr port = spu.SPUPs[spup]; - std::lock_guard lock(port.m_mutex); + std::lock_guard lock(port->m_mutex); - if (!port.eq) + if (!port->eq) { return CELL_ENOTCONN; } - port.eq->ports.remove(&port); - port.eq = nullptr; + port->eq->ports.remove(port); + port->eq = nullptr; return CELL_OK; } @@ -794,7 +794,7 @@ s32 sys_spu_thread_bind_queue(u32 id, u32 eq_id, u32 spuq_num) { sys_spu.Warning("sys_spu_thread_bind_queue(id=%d, equeue_id=%d, spuq_num=0x%x)", id, eq_id, spuq_num); - EventQueue* eq; + std::shared_ptr eq; if (!Emu.GetIdManager().GetIDData(eq_id, eq)) { return CELL_ESRCH; @@ -805,14 +805,14 @@ s32 sys_spu_thread_bind_queue(u32 id, u32 eq_id, u32 spuq_num) return CELL_EINVAL; } - CPUThread* thr = Emu.GetCPU().GetThread(id); + std::shared_ptr thr = Emu.GetCPU().GetThread(id); if(!thr || thr->GetType() != CPU_THREAD_SPU) { return CELL_ESRCH; } - if (!(*(SPUThread*)thr).SPUQs.RegisterKey(eq, FIX_SPUQ(spuq_num))) + if (!(*(SPUThread*)thr.get()).SPUQs.RegisterKey(eq, FIX_SPUQ(spuq_num))) { return CELL_EBUSY; } @@ -824,14 +824,14 @@ s32 sys_spu_thread_unbind_queue(u32 id, u32 spuq_num) { sys_spu.Warning("sys_spu_thread_unbind_queue(id=0x%x, spuq_num=0x%x)", id, spuq_num); - CPUThread* thr = Emu.GetCPU().GetThread(id); + std::shared_ptr thr = Emu.GetCPU().GetThread(id); if(!thr || thr->GetType() != CPU_THREAD_SPU) { return CELL_ESRCH; } - if (!(*(SPUThread*)thr).SPUQs.UnregisterKey(FIX_SPUQ(spuq_num))) + if (!(*(SPUThread*)thr.get()).SPUQs.UnregisterKey(FIX_SPUQ(spuq_num))) { return CELL_ESRCH; // may be CELL_EINVAL } @@ -844,7 +844,7 @@ s32 sys_spu_thread_group_connect_event_all_threads(u32 id, u32 eq_id, u64 req, v sys_spu.Warning("sys_spu_thread_group_connect_event_all_threads(id=%d, eq_id=%d, req=0x%llx, spup_addr=0x%x)", id, eq_id, req, spup.addr()); - EventQueue* eq; + std::shared_ptr eq; if (!Emu.GetIdManager().GetIDData(eq_id, eq)) { return CELL_ESRCH; @@ -855,23 +855,23 @@ s32 sys_spu_thread_group_connect_event_all_threads(u32 id, u32 eq_id, u64 req, v return CELL_EINVAL; } - SpuGroupInfo* group; + std::shared_ptr group; if (!Emu.GetIdManager().GetIDData(id, group)) { return CELL_ESRCH; } - std::vector threads; + std::vector> threads; for (auto& v : group->list) { if (!v) continue; - CPUThread* thr = Emu.GetCPU().GetThread(v); + std::shared_ptr thr = Emu.GetCPU().GetThread(v); if (thr->GetType() != CPU_THREAD_SPU) { sys_spu.Error("sys_spu_thread_group_connect_event_all_threads(): CELL_ESTAT (wrong thread type)"); return CELL_ESTAT; } - threads.push_back((SPUThread*)thr); + threads.push_back(thr); } if (threads.size() != group->m_count) @@ -885,22 +885,22 @@ s32 sys_spu_thread_group_connect_event_all_threads(u32 id, u32 eq_id, u64 req, v bool found = true; if (req & (1ull << i)) { - for (auto& t : threads) t->SPUPs[i].m_mutex.lock(); + for (auto& t : threads) ((SPUThread*)t.get())->SPUPs[i]->m_mutex.lock(); - for (auto& t : threads) if (t->SPUPs[i].eq) found = false; + for (auto& t : threads) if (((SPUThread*)t.get())->SPUPs[i]->eq) found = false; if (found) { for (auto& t : threads) { - eq->ports.add(&(t->SPUPs[i])); - t->SPUPs[i].eq = eq; + eq->ports.add(((SPUThread*)t.get())->SPUPs[i]); + ((SPUThread*)t.get())->SPUPs[i]->eq = eq; } sys_spu.Warning("*** spup -> %d", i); *spup = (u8)i; } - for (auto& t : threads) t->SPUPs[i].m_mutex.unlock(); + for (auto& t : threads) ((SPUThread*)t.get())->SPUPs[i]->m_mutex.unlock(); } else { diff --git a/rpcs3/Emu/SysCalls/lv2/sys_spu.h b/rpcs3/Emu/SysCalls/lv2/sys_spu.h index 6cf66a7bcb..e71c606bf7 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_spu.h +++ b/rpcs3/Emu/SysCalls/lv2/sys_spu.h @@ -161,8 +161,8 @@ u32 LoadSpuImage(vfsStream& stream, u32& spu_ep); // Aux s32 spu_image_import(sys_spu_image& img, u32 src, u32 type); -SpuGroupInfo* spu_thread_group_create(const std::string& name, u32 num, s32 prio, s32 type, u32 container); -SPUThread* spu_thread_initialize(SpuGroupInfo* group, u32 spu_num, sys_spu_image& img, const std::string& name, u32 option, u64 a1, u64 a2, u64 a3, u64 a4, std::function task = nullptr); +std::shared_ptr spu_thread_group_create(const std::string& name, u32 num, s32 prio, s32 type, u32 container); +SPUThread* spu_thread_initialize(std::shared_ptr& group, u32 spu_num, sys_spu_image& img, const std::string& name, u32 option, u64 a1, u64 a2, u64 a3, u64 a4, std::function task = nullptr); // SysCalls s32 sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu); diff --git a/rpcs3/Emu/SysCalls/lv2/sys_timer.cpp b/rpcs3/Emu/SysCalls/lv2/sys_timer.cpp index c2f5d259d7..81af2d8d13 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_timer.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_timer.cpp @@ -2,6 +2,7 @@ #include "Emu/Memory/Memory.h" #include "Emu/System.h" #include "Emu/SysCalls/SysCalls.h" +#include "Emu/Memory/atomic_type.h" #include "Emu/Event.h" #include "sys_timer.h" @@ -12,7 +13,8 @@ s32 sys_timer_create(vm::ptr timer_id) { sys_timer.Warning("sys_timer_create(timer_id_addr=0x%x)", timer_id.addr()); - *timer_id = sys_timer.GetNewId(new timer, TYPE_TIMER); + std::shared_ptr timer_data(new timer); + *timer_id = sys_timer.GetNewId(timer_data, TYPE_TIMER); return CELL_OK; } @@ -30,7 +32,7 @@ s32 sys_timer_get_information(u32 timer_id, vm::ptr inf { sys_timer.Warning("sys_timer_get_information(timer_id=%d, info_addr=0x%x)", timer_id, info.addr()); - timer* timer_data = nullptr; + std::shared_ptr timer_data = nullptr; if(!sys_timer.CheckId(timer_id, timer_data)) return CELL_ESRCH; *info = timer_data->timer_information_t; @@ -41,7 +43,7 @@ s32 sys_timer_start(u32 timer_id, s64 base_time, u64 period) { sys_timer.Warning("sys_timer_start_periodic_absolute(timer_id=%d, basetime=%lld, period=%llu)", timer_id, base_time, period); - timer* timer_data = nullptr; + std::shared_ptr timer_data = nullptr; if(!sys_timer.CheckId(timer_id, timer_data)) return CELL_ESRCH; if(timer_data->timer_information_t.timer_state != SYS_TIMER_STATE_STOP) return CELL_EBUSY; @@ -65,7 +67,7 @@ s32 sys_timer_stop(u32 timer_id) { sys_timer.Todo("sys_timer_stop()"); - timer* timer_data = nullptr; + std::shared_ptr timer_data = nullptr; if(!sys_timer.CheckId(timer_id, timer_data)) return CELL_ESRCH; timer_data->timer_information_t.timer_state = SYS_TIMER_STATE_STOP; @@ -77,8 +79,8 @@ s32 sys_timer_connect_event_queue(u32 timer_id, u32 queue_id, u64 name, u64 data sys_timer.Warning("sys_timer_connect_event_queue(timer_id=%d, queue_id=%d, name=%llu, data1=%llu, data2=%llu)", timer_id, queue_id, name, data1, data2); - timer* timer_data = nullptr; - EventQueue* equeue = nullptr; + std::shared_ptr timer_data = nullptr; + std::shared_ptr equeue = nullptr; if(!sys_timer.CheckId(timer_id, timer_data)) return CELL_ESRCH; if(!sys_timer.CheckId(queue_id, equeue)) return CELL_ESRCH; @@ -91,7 +93,7 @@ s32 sys_timer_disconnect_event_queue(u32 timer_id) { sys_timer.Todo("sys_timer_disconnect_event_queue(timer_id=%d)", timer_id); - timer* timer_data = nullptr; + std::shared_ptr timer_data = nullptr; if(!sys_timer.CheckId(timer_id, timer_data)) return CELL_ESRCH; //TODO: ? diff --git a/rpcs3/Emu/SysCalls/lv2/sys_vm.cpp b/rpcs3/Emu/SysCalls/lv2/sys_vm.cpp index d2557be42d..ed0615c13b 100644 --- a/rpcs3/Emu/SysCalls/lv2/sys_vm.cpp +++ b/rpcs3/Emu/SysCalls/lv2/sys_vm.cpp @@ -7,7 +7,7 @@ #include "sys_vm.h" SysCallBase sys_vm("sys_vm"); -MemoryContainerInfo* current_ct; +std::shared_ptr current_ct; s32 sys_vm_memory_map(u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, u32 addr) { @@ -33,12 +33,12 @@ s32 sys_vm_memory_map(u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, u32 a if(cid == SYS_MEMORY_CONTAINER_ID_INVALID) { // Create a new MemoryContainerInfo to act as default container with vsize. - current_ct = new MemoryContainerInfo(new_addr, vsize); + current_ct.reset(new MemoryContainerInfo(new_addr, vsize)); } else { // Check memory container. - MemoryContainerInfo* ct; + std::shared_ptr ct; if(!sys_vm.CheckId(cid, ct)) return CELL_ESRCH; current_ct = ct; diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index b13e6899df..9e9da63152 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -23,6 +23,7 @@ #include "Emu/RSX/GSManager.h" #include "Emu/Audio/AudioManager.h" #include "Emu/FS/VFS.h" +#include "Emu/SysCalls/SyncPrimitivesManager.h" #include "Loader/PSF.h" @@ -86,8 +87,6 @@ void Emulator::Init() m_modules_init[0]->Init(); m_modules_init.erase(m_modules_init.begin()); } - //if(m_memory_viewer) m_memory_viewer->Close(); - //m_memory_viewer = new MemoryViewerPanel(wxGetApp().m_MainFrame); } void Emulator::SetPath(const std::string& path, const std::string& elf_path) @@ -101,44 +100,51 @@ void Emulator::SetTitleID(const std::string& id) m_title_id = id; } -void Emulator::CheckStatus() +void Emulator::SetTitle(const std::string& title) { - std::vector& threads = GetCPU().GetThreads(); - if(!threads.size()) - { - Stop(); - return; - } - - bool IsAllPaused = true; - for(u32 i=0; iIsPaused()) continue; - IsAllPaused = false; - break; - } - if(IsAllPaused) - { - //ConLog.Warning("all paused!"); - Pause(); - return; - } - - bool IsAllStoped = true; - for(u32 i=0; iIsStopped()) continue; - IsAllStoped = false; - break; - } - if(IsAllStoped) - { - //ConLog.Warning("all stoped!"); - Pause(); //Stop(); - } + m_title = title; } -bool Emulator::BootGame(const std::string& path) +void Emulator::CheckStatus() +{ + //auto& threads = GetCPU().GetThreads(); + //if (!threads.size()) + //{ + // Stop(); + // return; + //} + + //bool IsAllPaused = true; + //for (u32 i = 0; i < threads.size(); ++i) + //{ + // if (threads[i]->IsPaused()) continue; + // IsAllPaused = false; + // break; + //} + + //if(IsAllPaused) + //{ + // //ConLog.Warning("all paused!"); + // Pause(); + // return; + //} + + //bool IsAllStoped = true; + //for (u32 i = 0; i < threads.size(); ++i) + //{ + // if (threads[i]->IsStopped()) continue; + // IsAllStoped = false; + // break; + //} + + //if (IsAllStoped) + //{ + // //LOG_WARNING(GENERAL, "all stoped!"); + // Pause(); //Stop(); + //} +} + +bool Emulator::BootGame(const std::string& path, bool direct) { static const char* elf_path[6] = { @@ -147,14 +153,26 @@ bool Emulator::BootGame(const std::string& path) "/BOOT.BIN", "/PS3_GAME/USRDIR/EBOOT.BIN", "/USRDIR/EBOOT.BIN", - "/EBOOT.BIN", + "/EBOOT.BIN" }; + auto curpath = path; - for(int i=0; i %s", GetVFS().m_devices[i]->GetPs3Path().c_str(), GetVFS().m_devices[i]->GetLocalPath().c_str()); } - LOG_NOTICE(LOADER, " ");//used to be skip_line + LOG_NOTICE(LOADER, " "); //used to be skip_line vfsFile sfo("/app_home/../PARAM.SFO"); PSFLoader psf(sfo); psf.Load(false); @@ -211,6 +229,9 @@ void Emulator::Load() LOG_NOTICE(LOADER, "Title: %s", title.c_str()); LOG_NOTICE(LOADER, "Serial: %s", title_id.c_str()); + title.length() ? SetTitle(title) : SetTitle(m_path); + SetTitleID(title_id); + // bdvd inserting imitation vfsFile f1("/app_home/../dev_bdvd.path"); if (f1.IsOpened()) @@ -223,16 +244,16 @@ void Emulator::Load() Emu.GetVFS().Mount("/dev_bdvd/", bdvd, new vfsDeviceLocalFile()); LOG_NOTICE(LOADER, "/dev_bdvd/ remounted into %s", bdvd.c_str()); } - LOG_NOTICE(LOADER, " ");//used to be skip_line + LOG_NOTICE(LOADER, " "); //used to be skip_line - if(m_elf_path.empty()) + if (m_elf_path.empty()) { GetVFS().GetDeviceLocal(m_path, m_elf_path); } vfsFile f(m_elf_path); - if(!f.IsOpened()) + if (!f.IsOpened()) { LOG_ERROR(LOADER, "Elf not found! (%s - %s)", m_path.c_str(), m_elf_path.c_str()); return; @@ -276,37 +297,31 @@ void Emulator::Load() void Emulator::Run() { - if(!IsReady()) + if (!IsReady()) { Load(); if(!IsReady()) return; } - if(IsRunning()) Stop(); - if(IsPaused()) + if (IsRunning()) Stop(); + + if (IsPaused()) { Resume(); return; } + SendDbgCommand(DID_START_EMU); - //ConLog.Write("run..."); m_status = Running; - //if(m_memory_viewer && m_memory_viewer->exit) safe_delete(m_memory_viewer); - - //m_memory_viewer->SetPC(loader.GetEntry()); - //m_memory_viewer->Show(); - //m_memory_viewer->ShowPC(); - GetCPU().Exec(); SendDbgCommand(DID_STARTED_EMU); } void Emulator::Pause() { - if(!IsRunning()) return; - //ConLog.Write("pause..."); + if (!IsRunning()) return; SendDbgCommand(DID_PAUSE_EMU); if (InterlockedCompareExchange((volatile u32*)&m_status, Paused, Running) == Running) @@ -317,27 +332,24 @@ void Emulator::Pause() void Emulator::Resume() { - if(!IsPaused()) return; - //ConLog.Write("resume..."); + if (!IsPaused()) return; SendDbgCommand(DID_RESUME_EMU); m_status = Running; CheckStatus(); - //if(IsRunning() && Ini.CPUDecoderMode.GetValue() != 1) GetCPU().Exec(); + SendDbgCommand(DID_RESUMED_EMU); } void Emulator::Stop() { if(IsStopped()) return; - //ConLog.Write("shutdown..."); SendDbgCommand(DID_STOP_EMU); m_status = Stopped; u32 uncounted = 0; - u32 counter = 0; while (true) { if (g_thread_count <= uncounted) @@ -374,7 +386,6 @@ void Emulator::Stop() CurGameInfo.Reset(); Memory.Close(); - //if(m_memory_viewer && m_memory_viewer->IsShown()) m_memory_viewer->Hide(); SendDbgCommand(DID_STOPPED_EMU); } @@ -387,12 +398,12 @@ void Emulator::SavePoints(const std::string& path) f << bpdb_version << break_count << marked_count; - if(break_count) + if (break_count) { f.write(reinterpret_cast(&m_break_points[0]), sizeof(u64) * break_count); } - if(marked_count) + if (marked_count) { f.write(reinterpret_cast(&m_marked_points[0]), sizeof(u64) * marked_count); } @@ -413,20 +424,19 @@ void Emulator::LoadPoints(const std::string& path) u16 version; f >> version >> break_count >> marked_count; - if(version != bpdb_version || - (sizeof(u16) + break_count * sizeof(u64) + sizeof(u32) + marked_count * sizeof(u64) + sizeof(u32)) != length) + if (version != bpdb_version || (sizeof(u16) + break_count * sizeof(u64) + sizeof(u32) + marked_count * sizeof(u64) + sizeof(u32)) != length) { LOG_ERROR(LOADER, "'%s' is broken", path.c_str()); return; } - if(break_count > 0) + if (break_count > 0) { m_break_points.resize(break_count); f.read(reinterpret_cast(&m_break_points[0]), sizeof(u64) * break_count); } - if(marked_count > 0) + if (marked_count > 0) { m_marked_points.resize(marked_count); f.read(reinterpret_cast(&m_marked_points[0]), sizeof(u64) * marked_count); @@ -445,4 +455,4 @@ void CallAfter(std::function func) void SetCallAfterCallback(CallAfterCbType cb) { CallAfterCallback = cb; -} \ No newline at end of file +} diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index dd5409cc71..a4901089b3 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -1,7 +1,6 @@ #pragma once #include "Loader/Loader.h" -#include "Emu/SysCalls/SyncPrimitivesManager.h" enum Status { @@ -115,6 +114,7 @@ public: std::string m_elf_path; std::string m_emu_path; std::string m_title_id; + std::string m_title; s32 m_sdk_version; Emulator(); @@ -123,6 +123,7 @@ public: void Init(); void SetPath(const std::string& path, const std::string& elf_path = ""); void SetTitleID(const std::string& id); + void SetTitle(const std::string& title); std::string GetPath() const { @@ -134,6 +135,16 @@ public: return m_emu_path; } + std::string GetTitleID() const + { + return m_title_id; + } + + std::string GetTitle() const + { + return m_title; + } + void SetEmulatorPath(const std::string& path) { m_emu_path = path; @@ -195,7 +206,7 @@ public: u32 GetCPUThreadStop() const { return m_cpu_thr_stop; } void CheckStatus(); - bool BootGame(const std::string& path); + bool BootGame(const std::string& path, bool direct = false); void Load(); void Run(); diff --git a/rpcs3/Gui/ConLogFrame.cpp b/rpcs3/Gui/ConLogFrame.cpp index 9e9d0209fc..879da2e003 100644 --- a/rpcs3/Gui/ConLogFrame.cpp +++ b/rpcs3/Gui/ConLogFrame.cpp @@ -97,7 +97,7 @@ struct wxWriter : Log::LogListener } //put message into the log buffer - void log(Log::LogMessage msg) + void log(const Log::LogMessage &msg) { u8 logLevel = Ini.HLELogLvl.GetValue(); if (msg.mType != Log::TTY && logLevel != 0) diff --git a/rpcs3/Gui/GLGSFrame.cpp b/rpcs3/Gui/GLGSFrame.cpp index 8a0fc1aab7..0051364a08 100644 --- a/rpcs3/Gui/GLGSFrame.cpp +++ b/rpcs3/Gui/GLGSFrame.cpp @@ -1,5 +1,6 @@ #include "stdafx_gui.h" #include "Emu/Memory/Memory.h" +#include "Emu/System.h" #include "GLGSFrame.h" #include "Utilities/Timer.h" @@ -61,10 +62,12 @@ void GLGSFrame::Flip(void* context) canvas->SwapBuffers(); m_frames++; + const std::string sub_title = Emu.GetTitle() += Emu.GetTitleID().length() ? " [" + Emu.GetTitleID() + "] | " : " | "; + if (fps_t.GetElapsedTimeInSec() >= 0.5) { // can freeze on exit - SetTitle(wxString::Format("FPS: %.2f", (double)m_frames / fps_t.GetElapsedTimeInSec())); + SetTitle(wxString(sub_title.c_str(), wxConvUTF8) + wxString::Format("FPS: %.2f", (double)m_frames / fps_t.GetElapsedTimeInSec())); m_frames = 0; fps_t.Start(); } diff --git a/rpcs3/Gui/GameViewer.cpp b/rpcs3/Gui/GameViewer.cpp index 6d18ba349b..6a2d9a8fe0 100644 --- a/rpcs3/Gui/GameViewer.cpp +++ b/rpcs3/Gui/GameViewer.cpp @@ -24,7 +24,7 @@ public: bool operator()(const GameInfo& game1, const GameInfo& game2) const { // Note that the column index has to match the appropriate GameInfo member - switch (sortColumn) + switch (sortColumn - 1) // skip *icon* column { case 0: return sortAscending ? (game1.name < game2.name) : (game1.name > game2.name); case 1: return sortAscending ? (game1.serial < game2.serial) : (game1.serial > game2.serial); @@ -67,7 +67,7 @@ GameViewer::GameViewer(wxWindow* parent) : wxListView(parent) LoadSettings(); m_columns.Show(this); - m_sortColumn = 0; + m_sortColumn = 1; m_sortAscending = true; m_path = "/dev_hdd0/game/"; m_popup = new wxMenu(); @@ -148,6 +148,10 @@ void GameViewer::LoadPSF() if(!psf.Load(false)) continue; + // get local path from VFS... + std::string local_path; + Emu.GetVFS().GetDevice(m_path, local_path); + GameInfo game; game.root = m_games[i]; game.serial = psf.GetString("TITLE_ID"); @@ -159,13 +163,21 @@ void GameViewer::LoadPSF() game.resolution = psf.GetInteger("RESOLUTION"); game.sound_format = psf.GetInteger("SOUND_FORMAT"); - if(game.serial.length() == 9) + if (game.serial.length() == 9) + { game.serial = game.serial.substr(0, 4) + "-" + game.serial.substr(4, 5); + } if (game.category.substr(0, 2) == "HG") + { game.category = "HDD Game"; + game.icon_path = local_path + "/" + m_games[i] + "/ICON0.PNG"; + } else if (game.category.substr(0, 2) == "DG") + { game.category = "Disc Game"; + game.icon_path = local_path + "/" + m_games[i] + "/PS3_GAME/ICON0.PNG"; + } m_game_data.push_back(game); } @@ -233,26 +245,20 @@ void GameViewer::RightClick(wxListEvent& event) void GameViewer::RemoveGame(wxCommandEvent& event) { - wxString GameName = this->GetItemText(event.GetId(), 5); + Emu.GetVFS().Init("/"); - // TODO: VFS is only available at emulation time, this is a temporary solution to locate the game - Emu.GetVFS().Init(m_path); - - vfsDir dir(m_path); - if (!dir.IsOpened()) - return; - const std::string sPath = dir.GetPath().erase(0, 1); - const std::string sGameFolder = GameName.mb_str().data(); - const std::string localPath = sPath + sGameFolder; + // get local path from VFS + std::string local_path; + Emu.GetVFS().GetDevice(m_path, local_path); + std::string del_path = local_path + "/" + this->GetItemText(event.GetId(), 6).ToStdString(); Emu.GetVFS().UnMountAll(); - if (!rExists(localPath)) - return; //TODO: Replace wxWidgetsSpecific filesystem stuff? WxDirDeleteTraverser deleter; - wxDir localDir(localPath); + wxDir localDir(del_path); localDir.Traverse(deleter); + wxRmdir(del_path); // delete empty directory Refresh(); } diff --git a/rpcs3/Gui/GameViewer.h b/rpcs3/Gui/GameViewer.h index 80c007fff0..b0b968b7e9 100644 --- a/rpcs3/Gui/GameViewer.h +++ b/rpcs3/Gui/GameViewer.h @@ -1,5 +1,7 @@ #pragma once #include +#include +#include #include "rpcs3/Ini.h" #include "Emu/GameInfo.h" @@ -69,6 +71,7 @@ struct ColumnsArr } public: + Column* m_col_icon; Column* m_col_name; Column* m_col_serial; Column* m_col_fw; @@ -76,36 +79,46 @@ public: Column* m_col_category; Column* m_col_path; + wxImageList* m_img_list; + std::vector m_icon_indexes; + void Init() { + m_img_list = new wxImageList(58, 32); + m_columns.clear(); + m_columns.emplace_back(m_columns.size(), 75, "Icon"); m_columns.emplace_back(m_columns.size(), 160, "Name"); m_columns.emplace_back(m_columns.size(), 85, "Serial"); m_columns.emplace_back(m_columns.size(), 55, "FW"); m_columns.emplace_back(m_columns.size(), 55, "App version"); - m_columns.emplace_back(m_columns.size(), 55, "Category"); + m_columns.emplace_back(m_columns.size(), 75, "Category"); m_columns.emplace_back(m_columns.size(), 160, "Path"); - m_col_name = &m_columns[0]; - m_col_serial = &m_columns[1]; - m_col_fw = &m_columns[2]; - m_col_app_ver = &m_columns[3]; - m_col_category = &m_columns[4]; - m_col_path = &m_columns[5]; + m_col_icon = &m_columns[0]; + m_col_name = &m_columns[1]; + m_col_serial = &m_columns[2]; + m_col_fw = &m_columns[3]; + m_col_app_ver = &m_columns[4]; + m_col_category = &m_columns[5]; + m_col_path = &m_columns[6]; } void Update(const std::vector& game_data) { + m_col_icon->data.clear(); m_col_name->data.clear(); m_col_serial->data.clear(); m_col_fw->data.clear(); m_col_app_ver->data.clear(); m_col_category->data.clear(); m_col_path->data.clear(); + m_icon_indexes.clear(); if(m_columns.size() == 0) return; for(const auto& game : game_data) { + m_col_icon->data.push_back(game.icon_path); m_col_name->data.push_back(game.name); m_col_serial->data.push_back(game.serial); m_col_fw->data.push_back(game.fw); @@ -113,11 +126,25 @@ public: m_col_category->data.push_back(game.category); m_col_path->data.push_back(game.root); } + + // load icons + for (const auto& path : m_col_icon->data) + { + wxImage game_icon(58, 32); + { + wxLogNull logNo; // temporary disable wx warnings ("iCCP: known incorrect sRGB profile" spamming) + if (game_icon.LoadFile(fmt::FromUTF8(path), wxBITMAP_TYPE_PNG)) + game_icon.Rescale(58, 32, wxIMAGE_QUALITY_HIGH); + } + + m_icon_indexes.push_back(m_img_list->Add(game_icon)); + } } void Show(wxListView* list) { list->DeleteAllColumns(); + list->SetImageList(m_img_list, wxIMAGE_LIST_SMALL); std::vector c_col = GetSortedColumnsByPos(); for(u32 i=0, c=0; iDeleteAllItems(); - for(int c=0; cGetColumnCount(); ++c) + list->SetImageList(m_img_list, wxIMAGE_LIST_SMALL); + for(int c=1; cGetColumnCount(); ++c) { Column* col = GetColumnByPos(c); @@ -147,20 +175,22 @@ public: list->SetItemData(i, i); } list->SetItem(i, c, fmt::FromUTF8(col->data[i])); - + list->SetItemColumnImage(i, 0, m_icon_indexes[i]); } } } void LoadSave(bool isLoad, const std::string& path, wxListView* list = NULL) { - if(isLoad) Init(); - else if(list) + if (isLoad) + Init(); + else if (list) { - for(int c=0; cGetColumnCount(); ++c) + for (int c = 0; c < list->GetColumnCount(); ++c) { Column* col = GetColumnByPos(c); - if(col) col->width = list->GetColumnWidth(c); + if (col) + col->width = list->GetColumnWidth(c); } } @@ -176,21 +206,21 @@ public: } \ } - for(u32 i=0; iFreeze(); m_choice_units->Clear(); - auto& thrs = Emu.GetCPU().GetThreads(); + //auto& thrs = Emu.GetCPU().GetThreads(); - for(uint i=0; iAppend(thrs[i]->GetFName(), thrs[i]); - } + //for (auto& t : thrs) + //{ + // m_choice_units->Append(t->GetFName(), t.get()); + //} m_choice_units->Thaw(); } @@ -150,9 +150,9 @@ void InterpreterDisAsmFrame::OnSelectUnit(wxCommandEvent& event) case CPU_THREAD_ARMv7: { - ARMv7DisAsm& dis_asm = *new ARMv7DisAsm(CPUDisAsm_InterpreterMode); - decoder = new ARMv7Decoder(dis_asm); - disasm = &dis_asm; + //ARMv7DisAsm& dis_asm = *new ARMv7DisAsm(CPUDisAsm_InterpreterMode); + //decoder = new ARMv7Decoder(dis_asm); + //disasm = &dis_asm; } break; } diff --git a/rpcs3/Gui/KernelExplorer.cpp b/rpcs3/Gui/KernelExplorer.cpp index 9e551f27de..c29eceee25 100644 --- a/rpcs3/Gui/KernelExplorer.cpp +++ b/rpcs3/Gui/KernelExplorer.cpp @@ -4,9 +4,10 @@ #include "Emu/System.h" #include "Emu/IdManager.h" -#include "KernelExplorer.h" #include "Emu/CPU/CPUThreadManager.h" #include "Emu/CPU/CPUThread.h" +#include "Emu/SysCalls/SyncPrimitivesManager.h" +#include "KernelExplorer.h" KernelExplorer::KernelExplorer(wxWindow* parent) : wxFrame(parent, wxID_ANY, "Kernel Explorer", wxDefaultPosition, wxSize(700, 450)) @@ -58,11 +59,10 @@ void KernelExplorer::Update() { sprintf(name, "Semaphores (%d)", count); const auto& node = m_tree->AppendItem(root, name); - const auto& objects = Emu.GetIdManager().GetTypeIDs(TYPE_SEMAPHORE); - for (const auto& id : objects) + for (const auto& id : Emu.GetIdManager().GetTypeIDs(TYPE_SEMAPHORE)) { - sprintf(name, "Semaphore: ID = 0x%08x '%s', Count = %d, Max Count = %d", id, Emu.GetSyncPrimManager().GetSemaphoreData(id).name.c_str(), - Emu.GetSyncPrimManager().GetSemaphoreData(id).count, Emu.GetSyncPrimManager().GetSemaphoreData(id).max_count); + auto sem = Emu.GetSyncPrimManager().GetSemaphoreData(id); + sprintf(name, "Semaphore: ID = 0x%08x '%s', Count = %d, Max Count = %d", id, sem.name.c_str(), sem.count, sem.max_count); m_tree->AppendItem(node, name); } } @@ -73,10 +73,9 @@ void KernelExplorer::Update() { sprintf(name, "Mutexes (%d)", count); const auto& node = m_tree->AppendItem(root, name); - const auto& objects = Emu.GetIdManager().GetTypeIDs(TYPE_MUTEX); - for (const auto& id : objects) + for (const auto& id : Emu.GetIdManager().GetTypeIDs(TYPE_MUTEX)) { - sprintf(name, "Mutex: ID = 0x%08x '%s'", id, Emu.GetSyncPrimManager().GetSyncPrimName(TYPE_MUTEX, id).c_str()); + sprintf(name, "Mutex: ID = 0x%08x '%s'", id, Emu.GetSyncPrimManager().GetSyncPrimName(id, TYPE_MUTEX).c_str()); m_tree->AppendItem(node, name); } } @@ -87,11 +86,10 @@ void KernelExplorer::Update() { sprintf(name, "Light Weight Mutexes (%d)", count); const auto& node = m_tree->AppendItem(root, name); - const auto& objects = Emu.GetIdManager().GetTypeIDs(TYPE_LWMUTEX); - for (const auto& id : objects) + for (const auto& id : Emu.GetIdManager().GetTypeIDs(TYPE_LWMUTEX)) { - sprintf(name, "LW Mutex: ID = 0x%08x '%s', Owner Thread ID = 0x%08x - %s", id, Emu.GetSyncPrimManager().GetLwMutexData(id).name.c_str(), - Emu.GetSyncPrimManager().GetLwMutexData(id).owner_id, Emu.GetSyncPrimManager().GetLwMutexData(id).status.c_str()); + auto lwm = Emu.GetSyncPrimManager().GetLwMutexData(id); + sprintf(name, "LW Mutex: ID = 0x%08x '%s'", id, lwm.name.c_str()); m_tree->AppendItem(node, name); } } @@ -102,10 +100,9 @@ void KernelExplorer::Update() { sprintf(name, "Condition Variables (%d)", count); const auto& node = m_tree->AppendItem(root, name); - const auto& objects = Emu.GetIdManager().GetTypeIDs(TYPE_COND); - for (const auto& id : objects) + for (const auto& id : Emu.GetIdManager().GetTypeIDs(TYPE_COND)) { - sprintf(name, "Condition Variable: ID = 0x%08x '%s'", id, Emu.GetSyncPrimManager().GetSyncPrimName(TYPE_COND, id).c_str()); + sprintf(name, "Condition Variable: ID = 0x%08x '%s'", id, Emu.GetSyncPrimManager().GetSyncPrimName(id, TYPE_COND).c_str()); m_tree->AppendItem(node, name); } } @@ -116,12 +113,9 @@ void KernelExplorer::Update() { sprintf(name, "Light Weight Condition Variables (%d)", count); const auto& node = m_tree->AppendItem(root, name); - const auto& objects = Emu.GetIdManager().GetTypeIDs(TYPE_LWCOND); - - u32 index = 0; - for (const auto& id : objects) + for (const auto& id : Emu.GetIdManager().GetTypeIDs(TYPE_LWCOND)) { - sprintf(name, "LW Condition Variable: ID = 0x%08x '%s'", id, Emu.GetSyncPrimManager().GetSyncPrimName(TYPE_LWCOND, id).c_str()); + sprintf(name, "LW Condition Variable: ID = 0x%08x '%s'", id, Emu.GetSyncPrimManager().GetSyncPrimName(id, TYPE_LWCOND).c_str()); m_tree->AppendItem(node, name); } } @@ -132,8 +126,7 @@ void KernelExplorer::Update() { sprintf(name, "Event Queues (%d)", count); const auto& node = m_tree->AppendItem(root, name); - const auto& objects = Emu.GetIdManager().GetTypeIDs(TYPE_EVENT_QUEUE); - for (const auto& id : objects) + for (const auto& id : Emu.GetIdManager().GetTypeIDs(TYPE_EVENT_QUEUE)) { sprintf(name, "Event Queue: ID = 0x%08x", id); m_tree->AppendItem(node, name); @@ -146,10 +139,9 @@ void KernelExplorer::Update() { sprintf(name, "Modules (%d)", count); const auto& node = m_tree->AppendItem(root, name); - const auto& objects = Emu.GetIdManager().GetTypeIDs(TYPE_PRX); - sprintf(name, "Segment List (%l)", 2 * objects.size()); // TODO: Assuming 2 segments per PRX file is not good - m_tree->AppendItem(node, name); - for (const auto& id : objects) + //sprintf(name, "Segment List (%l)", 2 * objects.size()); // TODO: Assuming 2 segments per PRX file is not good + //m_tree->AppendItem(node, name); + for (const auto& id : Emu.GetIdManager().GetTypeIDs(TYPE_PRX)) { sprintf(name, "PRX: ID = 0x%08x", id); m_tree->AppendItem(node, name); @@ -162,8 +154,7 @@ void KernelExplorer::Update() { sprintf(name, "Memory Containers (%d)", count); const auto& node = m_tree->AppendItem(root, name); - const auto& objects = Emu.GetIdManager().GetTypeIDs(TYPE_MEM); - for (const auto& id : objects) + for (const auto& id : Emu.GetIdManager().GetTypeIDs(TYPE_MEM)) { sprintf(name, "Memory Container: ID = 0x%08x", id); m_tree->AppendItem(node, name); @@ -176,8 +167,7 @@ void KernelExplorer::Update() { sprintf(name, "Event Flags (%d)", count); const auto& node = m_tree->AppendItem(root, name); - const auto& objects = Emu.GetIdManager().GetTypeIDs(TYPE_EVENT_FLAG); - for (const auto& id : objects) + for (const auto& id : Emu.GetIdManager().GetTypeIDs(TYPE_EVENT_FLAG)) { sprintf(name, "Event Flag: ID = 0x%08x", id); m_tree->AppendItem(node, name); @@ -188,66 +178,66 @@ void KernelExplorer::Update() { // TODO: add mutexes owners - const auto& objects = Emu.GetCPU().GetThreads(); + //const auto& objects = Emu.GetCPU().GetThreads(); u32 ppu_threads_count = 0; u32 spu_threads_count = 0; u32 raw_spu_threads_count = 0; - for (const auto& thread : objects) - { - if (thread->GetType() == CPU_THREAD_PPU) - ppu_threads_count++; + //for (const auto& thread : objects) + //{ + // if (thread->GetType() == CPU_THREAD_PPU) + // ppu_threads_count++; - if (thread->GetType() == CPU_THREAD_SPU) - spu_threads_count++; + // if (thread->GetType() == CPU_THREAD_SPU) + // spu_threads_count++; - if (thread->GetType() == CPU_THREAD_RAW_SPU) - raw_spu_threads_count++; - } + // if (thread->GetType() == CPU_THREAD_RAW_SPU) + // raw_spu_threads_count++; + //} - if (ppu_threads_count) - { - sprintf(name, "PPU Threads (%d)", ppu_threads_count); - const auto& node = m_tree->AppendItem(root, name); + //if (ppu_threads_count) + //{ + // sprintf(name, "PPU Threads (%d)", ppu_threads_count); + // const auto& node = m_tree->AppendItem(root, name); - for (const auto& thread : objects) - { - if (thread->GetType() == CPU_THREAD_PPU) - { - sprintf(name, "Thread: ID = 0x%08x '%s', - %s", thread->GetId(), thread->GetName().c_str(), thread->ThreadStatusToString().c_str()); - m_tree->AppendItem(node, name); - } - } - } + // for (const auto& thread : objects) + // { + // if (thread->GetType() == CPU_THREAD_PPU) + // { + // sprintf(name, "Thread: ID = 0x%08x '%s', - %s", thread->GetId(), thread->GetName().c_str(), thread->ThreadStatusToString().c_str()); + // m_tree->AppendItem(node, name); + // } + // } + //} - if (spu_threads_count) - { - sprintf(name, "SPU Threads (%d)", spu_threads_count); - const auto& node = m_tree->AppendItem(root, name); + //if (spu_threads_count) + //{ + // sprintf(name, "SPU Threads (%d)", spu_threads_count); + // const auto& node = m_tree->AppendItem(root, name); - for (const auto& thread : objects) - { - if (thread->GetType() == CPU_THREAD_SPU) - { - sprintf(name, "Thread: ID = 0x%08x '%s', - %s", thread->GetId(), thread->GetName().c_str(), thread->ThreadStatusToString().c_str()); - m_tree->AppendItem(node, name); - } - } - } + // for (const auto& thread : objects) + // { + // if (thread->GetType() == CPU_THREAD_SPU) + // { + // sprintf(name, "Thread: ID = 0x%08x '%s', - %s", thread->GetId(), thread->GetName().c_str(), thread->ThreadStatusToString().c_str()); + // m_tree->AppendItem(node, name); + // } + // } + //} - if (raw_spu_threads_count) - { - sprintf(name, "RawSPU Threads (%d)", raw_spu_threads_count); - const auto& node = m_tree->AppendItem(root, name); + //if (raw_spu_threads_count) + //{ + // sprintf(name, "RawSPU Threads (%d)", raw_spu_threads_count); + // const auto& node = m_tree->AppendItem(root, name); - for (const auto& thread : objects) - { - if (thread->GetType() == CPU_THREAD_RAW_SPU) - { - sprintf(name, "Thread: ID = 0x%08x '%s', - %s", thread->GetId(), thread->GetName().c_str(), thread->ThreadStatusToString().c_str()); - m_tree->AppendItem(node, name); - } - } - } + // for (const auto& thread : objects) + // { + // if (thread->GetType() == CPU_THREAD_RAW_SPU) + // { + // sprintf(name, "Thread: ID = 0x%08x '%s', - %s", thread->GetId(), thread->GetName().c_str(), thread->ThreadStatusToString().c_str()); + // m_tree->AppendItem(node, name); + // } + // } + //} } diff --git a/rpcs3/Gui/LLEModulesManager.cpp b/rpcs3/Gui/LLEModulesManager.cpp index f6ccd60b0b..5505e3877e 100644 --- a/rpcs3/Gui/LLEModulesManager.cpp +++ b/rpcs3/Gui/LLEModulesManager.cpp @@ -13,14 +13,26 @@ LLEModulesManagerFrame::LLEModulesManagerFrame(wxWindow* parent) : FrameBase(par wxBoxSizer *s_p_panel = new wxBoxSizer(wxVERTICAL); wxPanel *p_main = new wxPanel(this); m_check_list = new wxCheckListBox(p_main, wxID_ANY); + + // select / unselect + wxStaticBoxSizer* s_selection = new wxStaticBoxSizer(wxHORIZONTAL, p_main); + wxButton* b_select = new wxButton(p_main, wxID_ANY, "Select All", wxDefaultPosition, wxSize(80, -1)); + wxButton* b_unselect = new wxButton(p_main, wxID_ANY, "Unselect All", wxDefaultPosition, wxSize(80, -1)); + s_selection->Add(b_select); + s_selection->Add(b_unselect); + + s_p_panel->Add(s_selection); s_p_panel->Add(m_check_list, 1, wxEXPAND | wxALL, 5); p_main->SetSizerAndFit(s_p_panel); + s_panel->Add(p_main, 1, wxEXPAND | wxALL, 5); SetSizerAndFit(s_panel); - Refresh(); + + b_select->Bind(wxEVT_BUTTON, [this](wxCommandEvent& event) { OnSelectAll(event, true); event.Skip(); }); + b_unselect->Bind(wxEVT_BUTTON, [this](wxCommandEvent& event) { OnSelectAll(event, false); event.Skip(); }); Bind(wxEVT_CHECKLISTBOX, [this](wxCommandEvent& event) { UpdateSelection(event.GetInt()); event.Skip(); }); - Bind(wxEVT_SIZE, [p_main, this](wxSizeEvent& event) { p_main->SetSize(GetClientSize()); m_check_list->SetSize(p_main->GetClientSize() - wxSize(10, 10)); event.Skip(); }); + Bind(wxEVT_SIZE, [p_main, this](wxSizeEvent& event) { p_main->SetSize(GetClientSize()); m_check_list->SetSize(p_main->GetClientSize() - wxSize(10, 50)); event.Skip(); }); } void LLEModulesManagerFrame::Refresh() @@ -91,4 +103,13 @@ void LLEModulesManagerFrame::UpdateSelection(int index) IniEntry load_lib; load_lib.Init(m_funcs[index], "LLE"); load_lib.SaveValue(m_check_list->IsChecked(index)); +} + +void LLEModulesManagerFrame::OnSelectAll(wxCommandEvent& WXUNUSED(event), bool is_checked) +{ + for (uint i = 0; i < m_check_list->GetCount(); i++) + { + m_check_list->Check(i, is_checked); + UpdateSelection(i); + } } \ No newline at end of file diff --git a/rpcs3/Gui/LLEModulesManager.h b/rpcs3/Gui/LLEModulesManager.h index f73fa02910..c4025b5675 100644 --- a/rpcs3/Gui/LLEModulesManager.h +++ b/rpcs3/Gui/LLEModulesManager.h @@ -11,4 +11,5 @@ public: LLEModulesManagerFrame(wxWindow *parent); void Refresh(); void UpdateSelection(int index); + void OnSelectAll(wxCommandEvent& WXUNUSED(event), bool is_checked); }; \ No newline at end of file diff --git a/rpcs3/Gui/MainFrame.cpp b/rpcs3/Gui/MainFrame.cpp index b42fd4be6f..595d207423 100644 --- a/rpcs3/Gui/MainFrame.cpp +++ b/rpcs3/Gui/MainFrame.cpp @@ -20,6 +20,7 @@ #include "Gui/KernelExplorer.h" #include "Gui/MemoryViewer.h" #include "Gui/RSXDebugger.h" +#include "Gui/MemoryStringSearcher.h" #include "Gui/LLEModulesManager.h" #include @@ -51,6 +52,7 @@ enum IDs id_tools_kernel_explorer, id_tools_memory_viewer, id_tools_rsx_debugger, + id_tools_string_search, id_help_about, id_update_dbg, }; @@ -63,7 +65,7 @@ wxString GetPaneName() } MainFrame::MainFrame() - : FrameBase(nullptr, wxID_ANY, "", "MainFrame", wxSize(800, 600)) + : FrameBase(nullptr, wxID_ANY, "", "MainFrame", wxSize(900, 600)) , m_aui_mgr(this) , m_sys_menu_opened(false) { @@ -112,6 +114,7 @@ MainFrame::MainFrame() menu_tools->Append(id_tools_kernel_explorer, "&Kernel Explorer")->Enable(false); menu_tools->Append(id_tools_memory_viewer, "&Memory Viewer")->Enable(false); menu_tools->Append(id_tools_rsx_debugger, "&RSX Debugger")->Enable(false); + menu_tools->Append(id_tools_string_search, "&String Search")->Enable(false); wxMenu* menu_help = new wxMenu(); menubar->Append(menu_help, "&Help"); @@ -151,6 +154,7 @@ MainFrame::MainFrame() Bind(wxEVT_MENU, &MainFrame::OpenKernelExplorer, this, id_tools_kernel_explorer); Bind(wxEVT_MENU, &MainFrame::OpenMemoryViewer, this, id_tools_memory_viewer); Bind(wxEVT_MENU, &MainFrame::OpenRSXDebugger, this, id_tools_rsx_debugger); + Bind(wxEVT_MENU, &MainFrame::OpenStringSearch, this, id_tools_string_search); Bind(wxEVT_MENU, &MainFrame::AboutDialogHandler, this, id_help_about); @@ -342,7 +346,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) wxDialog diag(this, wxID_ANY, "Settings", wxDefaultPosition); static const u32 width = 425; - static const u32 height = 400; + static const u32 height = 460; // Settings panels wxNotebook* nb_config = new wxNotebook(&diag, wxID_ANY, wxPoint(6,6), wxSize(width, height)); @@ -378,6 +382,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) wxStaticBoxSizer* s_round_gs_render = new wxStaticBoxSizer(wxVERTICAL, p_graphics, _("Render")); wxStaticBoxSizer* s_round_gs_res = new wxStaticBoxSizer(wxVERTICAL, p_graphics, _("Default resolution")); wxStaticBoxSizer* s_round_gs_aspect = new wxStaticBoxSizer(wxVERTICAL, p_graphics, _("Default aspect ratio")); + wxStaticBoxSizer* s_round_gs_frame_limit = new wxStaticBoxSizer(wxVERTICAL, p_graphics, _("Frame limit")); // Input / Output wxStaticBoxSizer* s_round_io_pad_handler = new wxStaticBoxSizer(wxVERTICAL, p_io, _("Pad Handler")); @@ -402,6 +407,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) wxComboBox* cbox_gs_render = new wxComboBox(p_graphics, wxID_ANY); wxComboBox* cbox_gs_resolution = new wxComboBox(p_graphics, wxID_ANY); wxComboBox* cbox_gs_aspect = new wxComboBox(p_graphics, wxID_ANY); + wxComboBox* cbox_gs_frame_limit = new wxComboBox(p_graphics, wxID_ANY); wxComboBox* cbox_pad_handler = new wxComboBox(p_io, wxID_ANY); wxComboBox* cbox_keyboard_handler = new wxComboBox(p_io, wxID_ANY); wxComboBox* cbox_mouse_handler = new wxComboBox(p_io, wxID_ANY); @@ -414,6 +420,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) wxCheckBox* chbox_gs_log_prog = new wxCheckBox(p_graphics, wxID_ANY, "Log vertex/fragment programs"); wxCheckBox* chbox_gs_dump_depth = new wxCheckBox(p_graphics, wxID_ANY, "Write Depth Buffer"); wxCheckBox* chbox_gs_dump_color = new wxCheckBox(p_graphics, wxID_ANY, "Write Color Buffers"); + wxCheckBox* chbox_gs_read_color = new wxCheckBox(p_graphics, wxID_ANY, "Read Color Buffer"); wxCheckBox* chbox_gs_vsync = new wxCheckBox(p_graphics, wxID_ANY, "VSync"); wxCheckBox* chbox_gs_3dmonitor = new wxCheckBox(p_graphics, wxID_ANY, "3D Monitor"); wxCheckBox* chbox_audio_dump = new wxCheckBox(p_audio, wxID_ANY, "Dump to file"); @@ -447,6 +454,9 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) cbox_gs_aspect->Append("4:3"); cbox_gs_aspect->Append("16:9"); + for (auto item : { "Off", "50", "59.94", "30", "60", "Auto" }) + cbox_gs_frame_limit->Append(item); + cbox_pad_handler->Append("Null"); cbox_pad_handler->Append("Windows"); #if defined (_WIN32) @@ -501,6 +511,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) chbox_gs_log_prog ->SetValue(Ini.GSLogPrograms.GetValue()); chbox_gs_dump_depth ->SetValue(Ini.GSDumpDepthBuffer.GetValue()); chbox_gs_dump_color ->SetValue(Ini.GSDumpColorBuffers.GetValue()); + chbox_gs_read_color ->SetValue(Ini.GSReadColorBuffer.GetValue()); chbox_gs_vsync ->SetValue(Ini.GSVSyncEnable.GetValue()); chbox_gs_3dmonitor ->SetValue(Ini.GS3DTV.GetValue()); chbox_audio_dump ->SetValue(Ini.AudioDumpToFile.GetValue()); @@ -521,6 +532,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) cbox_gs_render ->SetSelection(Ini.GSRenderMode.GetValue()); cbox_gs_resolution ->SetSelection(ResolutionIdToNum(Ini.GSResolution.GetValue()) - 1); cbox_gs_aspect ->SetSelection(Ini.GSAspectRatio.GetValue() - 1); + cbox_gs_frame_limit ->SetSelection(Ini.GSFrameLimit.GetValue()); cbox_pad_handler ->SetSelection(Ini.PadHandlerMode.GetValue()); cbox_keyboard_handler->SetSelection(Ini.KeyboardHandlerMode.GetValue()); cbox_mouse_handler ->SetSelection(Ini.MouseHandlerMode.GetValue()); @@ -543,6 +555,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) s_round_gs_render->Add(cbox_gs_render, wxSizerFlags().Border(wxALL, 5).Expand()); s_round_gs_res->Add(cbox_gs_resolution, wxSizerFlags().Border(wxALL, 5).Expand()); s_round_gs_aspect->Add(cbox_gs_aspect, wxSizerFlags().Border(wxALL, 5).Expand()); + s_round_gs_frame_limit->Add(cbox_gs_frame_limit, wxSizerFlags().Border(wxALL, 5).Expand()); s_round_io_pad_handler->Add(cbox_pad_handler, wxSizerFlags().Border(wxALL, 5).Expand()); s_round_io_keyboard_handler->Add(cbox_keyboard_handler, wxSizerFlags().Border(wxALL, 5).Expand()); @@ -565,9 +578,11 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) s_subpanel_graphics->Add(s_round_gs_render, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics->Add(s_round_gs_res, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics->Add(s_round_gs_aspect, wxSizerFlags().Border(wxALL, 5).Expand()); + s_subpanel_graphics->Add(s_round_gs_frame_limit, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics->Add(chbox_gs_log_prog, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics->Add(chbox_gs_dump_depth, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics->Add(chbox_gs_dump_color, wxSizerFlags().Border(wxALL, 5).Expand()); + s_subpanel_graphics->Add(chbox_gs_read_color, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics->Add(chbox_gs_vsync, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics->Add(chbox_gs_3dmonitor, wxSizerFlags().Border(wxALL, 5).Expand()); @@ -625,9 +640,11 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) Ini.GSRenderMode.SetValue(cbox_gs_render->GetSelection()); Ini.GSResolution.SetValue(ResolutionNumToId(cbox_gs_resolution->GetSelection() + 1)); Ini.GSAspectRatio.SetValue(cbox_gs_aspect->GetSelection() + 1); + Ini.GSFrameLimit.SetValue(cbox_gs_frame_limit->GetSelection()); Ini.GSLogPrograms.SetValue(chbox_gs_log_prog->GetValue()); Ini.GSDumpDepthBuffer.SetValue(chbox_gs_dump_depth->GetValue()); Ini.GSDumpColorBuffers.SetValue(chbox_gs_dump_color->GetValue()); + Ini.GSReadColorBuffer.SetValue(chbox_gs_read_color->GetValue()); Ini.GSVSyncEnable.SetValue(chbox_gs_vsync->GetValue()); Ini.GS3DTV.SetValue(chbox_gs_3dmonitor->GetValue()); Ini.PadHandlerMode.SetValue(cbox_pad_handler->GetSelection()); @@ -707,6 +724,10 @@ void MainFrame::OpenRSXDebugger(wxCommandEvent& WXUNUSED(event)) (new RSXDebugger(this)) -> Show(); } +void MainFrame::OpenStringSearch(wxCommandEvent& WXUNUSED(event)) +{ + (new MemoryStringSearcher(this)) -> Show(); +} void MainFrame::AboutDialogHandler(wxCommandEvent& WXUNUSED(event)) { @@ -805,9 +826,12 @@ void MainFrame::UpdateUI(wxCommandEvent& event) wxMenuItem& kernel_explorer = *menubar.FindItem(id_tools_kernel_explorer); wxMenuItem& memory_viewer = *menubar.FindItem(id_tools_memory_viewer); wxMenuItem& rsx_debugger = *menubar.FindItem(id_tools_rsx_debugger); + wxMenuItem& string_search = *menubar.FindItem(id_tools_string_search); kernel_explorer.Enable(!is_stopped); memory_viewer.Enable(!is_stopped); rsx_debugger.Enable(!is_stopped); + string_search.Enable(!is_stopped); + //m_aui_mgr.Update(); diff --git a/rpcs3/Gui/MainFrame.h b/rpcs3/Gui/MainFrame.h index 359e932c6a..3de2d38e6a 100644 --- a/rpcs3/Gui/MainFrame.h +++ b/rpcs3/Gui/MainFrame.h @@ -45,6 +45,7 @@ private: void OpenKernelExplorer(wxCommandEvent& evt); void OpenMemoryViewer(wxCommandEvent& evt); void OpenRSXDebugger(wxCommandEvent& evt); + void OpenStringSearch(wxCommandEvent& evt); void OpenFnIdGenerator(wxCommandEvent& evt); void AboutDialogHandler(wxCommandEvent& event); void UpdateUI(wxCommandEvent& event); diff --git a/rpcs3/Gui/MemoryStringSearcher.cpp b/rpcs3/Gui/MemoryStringSearcher.cpp new file mode 100644 index 0000000000..8676d57371 --- /dev/null +++ b/rpcs3/Gui/MemoryStringSearcher.cpp @@ -0,0 +1,74 @@ +#include "stdafx_gui.h" +#include "rpcs3/Ini.h" +#include "Utilities/rPlatform.h" +#include "Utilities/Log.h" +#include "Emu/Memory/Memory.h" +#include "Emu/System.h" + +#include "MemoryStringSearcher.h" +#include "Emu/RSX/sysutil_video.h" +#include "Emu/RSX/GSManager.h" +//#include "Emu/RSX/GCM.h" + +#include + +MemoryStringSearcher::MemoryStringSearcher(wxWindow* parent) + : wxFrame(parent, wxID_ANY, "String Searcher", wxDefaultPosition, wxSize(545, 64)) + , exit(false) +{ + this->SetBackgroundColour(wxColour(240,240,240)); + //wxBoxSizer* s_panel = new wxBoxSizer(wxHORIZONTAL); + + //Tools + //wxBoxSizer* s_tools = new wxBoxSizer(wxVERTICAL); + + //Tabs + //wxNotebook* nb_rsx = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxSize(482,475)); + + s_panel = new wxBoxSizer(wxHORIZONTAL); + t_addr = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(482, -1)); + b_search = new wxButton(this, wxID_ANY, "Search", wxPoint(482, 0), wxSize(40, -1)); + b_search->Bind(wxEVT_BUTTON, &MemoryStringSearcher::Search, this); + s_panel->Add(t_addr); + s_panel->Add(b_search); +}; + +void MemoryStringSearcher::Search(wxCommandEvent& event) +{ + const wxString wstr = t_addr->GetValue(); + const char *str = wstr.c_str(); + const u32 len = wstr.length(); + + LOG_NOTICE(GENERAL, "Searching for string %s", str); + + // Search the address space for the string + u32 strIndex = 0; + u32 numFound = 0; + for (u32 addr = Memory.MainMem.GetStartAddr(); addr < Memory.MainMem.GetEndAddr(); addr++) { + if (!Memory.IsGoodAddr(addr)) { + strIndex = 0; + continue; + } + + u8 byte = vm::read8(addr); + if (byte == str[strIndex]) { + if (strIndex == len) { + // Found it + LOG_NOTICE(GENERAL, "Found @ %04x", addr - len); + numFound++; + strIndex = 0; + continue; + } + + strIndex++; + } + else + strIndex = 0; + + if (addr % (1024 * 1024 * 64) == 0) { // Log every 64mb + LOG_NOTICE(GENERAL, "Searching %04x ...", addr); + } + } + + LOG_NOTICE(GENERAL, "Search completed (found %d matches)", numFound); +} \ No newline at end of file diff --git a/rpcs3/Gui/MemoryStringSearcher.h b/rpcs3/Gui/MemoryStringSearcher.h new file mode 100644 index 0000000000..f0928afe2d --- /dev/null +++ b/rpcs3/Gui/MemoryStringSearcher.h @@ -0,0 +1,19 @@ +#pragma once +#include + +class MemoryStringSearcher : public wxFrame +{ + wxTextCtrl* t_addr; + wxBoxSizer* s_panel; + wxButton* b_search; + +public: + bool exit; + MemoryStringSearcher(wxWindow* parent); + ~MemoryStringSearcher() + { + exit = true; + } + + void Search(wxCommandEvent& event); +}; diff --git a/rpcs3/Gui/MemoryViewer.cpp b/rpcs3/Gui/MemoryViewer.cpp index 73b57c835e..59f3917713 100644 --- a/rpcs3/Gui/MemoryViewer.cpp +++ b/rpcs3/Gui/MemoryViewer.cpp @@ -22,12 +22,12 @@ MemoryViewerPanel::MemoryViewerPanel(wxWindow* parent) wxStaticBoxSizer* s_tools_mem = new wxStaticBoxSizer(wxHORIZONTAL, this, "Memory Viewer Options"); wxStaticBoxSizer* s_tools_mem_addr = new wxStaticBoxSizer(wxHORIZONTAL, this, "Address"); - t_addr = new wxTextCtrl(this, wxID_ANY, "00000000", wxDefaultPosition, wxSize(60,-1)); + t_addr = new wxTextCtrl(this, wxID_ANY, "00000000", wxDefaultPosition, wxSize(60, -1)); t_addr->SetMaxLength(8); s_tools_mem_addr->Add(t_addr); wxStaticBoxSizer* s_tools_mem_bytes = new wxStaticBoxSizer(wxHORIZONTAL, this, "Bytes"); - sc_bytes = new wxSpinCtrl(this, wxID_ANY, "16", wxDefaultPosition, wxSize(44,-1)); + sc_bytes = new wxSpinCtrl(this, wxID_ANY, "16", wxDefaultPosition, wxSize(44, -1)); sc_bytes->SetRange(1, 16); s_tools_mem_bytes->Add(sc_bytes); @@ -49,8 +49,8 @@ MemoryViewerPanel::MemoryViewerPanel(wxWindow* parent) wxStaticBoxSizer* s_tools_img = new wxStaticBoxSizer(wxHORIZONTAL, this, "Raw Image Preview"); wxStaticBoxSizer* s_tools_img_size = new wxStaticBoxSizer(wxHORIZONTAL, this, "Size"); - sc_img_size_x = new wxSpinCtrl(this, wxID_ANY, "256", wxDefaultPosition, wxSize(60,-1)); - sc_img_size_y = new wxSpinCtrl(this, wxID_ANY, "256", wxDefaultPosition, wxSize(60,-1)); + sc_img_size_x = new wxSpinCtrl(this, wxID_ANY, "256", wxDefaultPosition, wxSize(60, -1)); + sc_img_size_y = new wxSpinCtrl(this, wxID_ANY, "256", wxDefaultPosition, wxSize(60, -1)); s_tools_img_size->Add(sc_img_size_x); s_tools_img_size->Add(new wxStaticText(this, wxID_ANY, " x ")); s_tools_img_size->Add(sc_img_size_y); @@ -72,7 +72,7 @@ MemoryViewerPanel::MemoryViewerPanel(wxWindow* parent) //Tools: Run tools wxStaticBoxSizer* s_tools_buttons = new wxStaticBoxSizer(wxVERTICAL, this, "Tools"); - wxButton* b_img = new wxButton(this, wxID_ANY, "View\nimage", wxDefaultPosition, wxSize(52,-1)); + wxButton* b_img = new wxButton(this, wxID_ANY, "View\nimage", wxDefaultPosition, wxSize(52, -1)); s_tools_buttons->Add(b_img); //Tools: Tools = Memory Viewer Options + Raw Image Preview Options + Buttons @@ -108,8 +108,8 @@ MemoryViewerPanel::MemoryViewerPanel(wxWindow* parent) //Memory Panel: Set size of the wxTextCtrl's int x, y; t_mem_hex->GetTextExtent(wxT("T"), &x, &y); - t_mem_hex->SetMinSize(wxSize(x * 3*m_colcount + 6, 228)); - t_mem_hex->SetMaxSize(wxSize(x * 3*m_colcount + 6, 228)); + t_mem_hex->SetMinSize(wxSize(x * 3 * m_colcount + 6, 228)); + t_mem_hex->SetMaxSize(wxSize(x * 3 * m_colcount + 6, 228)); t_mem_ascii->SetMinSize(wxSize(x * m_colcount + 6, 228)); t_mem_ascii->SetMaxSize(wxSize(x * m_colcount + 6, 228)); @@ -156,8 +156,8 @@ void MemoryViewerPanel::OnChangeToolsBytes(wxCommandEvent& event) int x, y; t_mem_hex->GetTextExtent(wxT("T"), &x, &y); - t_mem_hex->SetMinSize(wxSize(x * 3*m_colcount + 6, 228)); - t_mem_hex->SetMaxSize(wxSize(x * 3*m_colcount + 6, 228)); + t_mem_hex->SetMinSize(wxSize(x * 3 * m_colcount + 6, 228)); + t_mem_hex->SetMaxSize(wxSize(x * 3 * m_colcount + 6, 228)); t_mem_ascii->SetMinSize(wxSize(x * m_colcount + 6, 228)); t_mem_ascii->SetMaxSize(wxSize(x * m_colcount + 6, 228)); this->Layout(); @@ -242,43 +242,43 @@ void MemoryViewerPanel::ShowImage(wxWindow* parent, u32 addr, int mode, u32 widt break; case(1): // ARGB - for (u32 y=0; ySetAutoLayout(true); + // fallthrough case CELL_MSGDIALOG_TYPE_PROGRESSBAR_SINGLE: m_gauge1 = new wxGauge(m_dialog, wxID_ANY, 100, wxDefaultPosition, wxSize(300, -1), wxGA_HORIZONTAL | wxGA_SMOOTH); m_text1 = new wxStaticText(m_dialog, wxID_ANY, ""); m_text1->SetAutoLayout(true); - - default: // ??? - break; } if (m_gauge1) @@ -66,9 +64,6 @@ void MsgDialogCreate(u32 type, const char* msg, u64& status) switch (type & CELL_MSGDIALOG_TYPE_BUTTON_TYPE) { - case CELL_MSGDIALOG_TYPE_BUTTON_TYPE_NONE: - break; - case CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO: m_button_yes = new wxButton(m_dialog, wxID_YES); buttons->Add(m_button_yes, 0, wxALIGN_CENTER_HORIZONTAL | wxRIGHT, 8); diff --git a/rpcs3/Ini.h b/rpcs3/Ini.h index cbfc6d9fe4..6b3b9b1e02 100644 --- a/rpcs3/Ini.h +++ b/rpcs3/Ini.h @@ -104,9 +104,11 @@ public: IniEntry GSRenderMode; IniEntry GSResolution; IniEntry GSAspectRatio; + IniEntry GSFrameLimit; IniEntry GSLogPrograms; IniEntry GSDumpColorBuffers; IniEntry GSDumpDepthBuffer; + IniEntry GSReadColorBuffer; IniEntry GSVSyncEnable; IniEntry GS3DTV; @@ -179,9 +181,11 @@ public: GSRenderMode.Init("GS_RenderMode", path); GSResolution.Init("GS_Resolution", path); GSAspectRatio.Init("GS_AspectRatio", path); + GSFrameLimit.Init("GS_FrameLimit", path); GSLogPrograms.Init("GS_LogPrograms", path); GSDumpColorBuffers.Init("GS_DumpColorBuffers", path); GSDumpDepthBuffer.Init("GS_DumpDepthBuffer", path); + GSReadColorBuffer.Init("GS_GSReadColorBuffer", path); GSVSyncEnable.Init("GS_VSyncEnable", path); GS3DTV.Init("GS_3DTV", path); @@ -250,9 +254,11 @@ public: GSRenderMode.Load(1); GSResolution.Load(4); GSAspectRatio.Load(2); + GSFrameLimit.Load(0); GSLogPrograms.Load(false); GSDumpColorBuffers.Load(false); GSDumpDepthBuffer.Load(false); + GSReadColorBuffer.Load(false); GSVSyncEnable.Load(false); GS3DTV.Load(false); @@ -322,9 +328,11 @@ public: GSRenderMode.Save(); GSResolution.Save(); GSAspectRatio.Save(); + GSFrameLimit.Save(); GSLogPrograms.Save(); GSDumpColorBuffers.Save(); GSDumpDepthBuffer.Save(); + GSReadColorBuffer.Save(); GSVSyncEnable.Save(); GS3DTV.Save(); diff --git a/rpcs3/Loader/ELF32.cpp b/rpcs3/Loader/ELF32.cpp index cbfb8a0317..31925d4b57 100644 --- a/rpcs3/Loader/ELF32.cpp +++ b/rpcs3/Loader/ELF32.cpp @@ -55,7 +55,7 @@ namespace loader { m_shdrs.resize(m_ehdr.is_le() ? m_ehdr.data_le.e_shnum : m_ehdr.data_be.e_shnum); m_stream->Seek(handler::get_stream_offset() + (m_ehdr.is_le() ? m_ehdr.data_le.e_shoff : m_ehdr.data_be.e_shoff)); - size_t size = (m_ehdr.is_le() ? m_ehdr.data_le.e_shnum : m_ehdr.data_be.e_shnum) * sizeof(phdr); + size_t size = (m_ehdr.is_le() ? m_ehdr.data_le.e_shnum : m_ehdr.data_be.e_shnum) * sizeof(shdr); if (m_stream->Read(m_shdrs.data(), size) != size) return broken_file; @@ -284,4 +284,4 @@ namespace loader return ok; } } -} \ No newline at end of file +} diff --git a/rpcs3/Loader/ELF64.cpp b/rpcs3/Loader/ELF64.cpp index 09607fc407..0357e5bcfa 100644 --- a/rpcs3/Loader/ELF64.cpp +++ b/rpcs3/Loader/ELF64.cpp @@ -133,7 +133,6 @@ namespace loader if (import_count) { LOG_ERROR(LOADER, "**** Lib '%s'has %d imports!", module_info.name, import_count); - break; } sys_prx_library_info_t lib; @@ -343,17 +342,17 @@ namespace loader Emu.SetRSXCallback(rsx_callback_data.addr()); rsx_callback_data[0] = ADDI(r11, 0, 0x3ff); - rsx_callback_data[1] = SC(2); + rsx_callback_data[1] = SC(0); rsx_callback_data[2] = BLR(); auto ppu_thr_exit_data = vm::ptr::make(Memory.MainMem.AllocAlign(3 * 4)); ppu_thr_exit_data[0] = ADDI(r11, 0, 41); - ppu_thr_exit_data[1] = SC(2); + ppu_thr_exit_data[1] = SC(0); ppu_thr_exit_data[2] = BLR(); Emu.SetCPUThreadExit(ppu_thr_exit_data.addr()); auto ppu_thr_stop_data = vm::ptr::make(Memory.MainMem.AllocAlign(2 * 4)); - ppu_thr_stop_data[0] = SC(4); + ppu_thr_stop_data[0] = SC(3); ppu_thr_stop_data[1] = BLR(); Emu.SetCPUThreadStop(ppu_thr_stop_data.addr()); @@ -493,7 +492,7 @@ namespace loader static const stub_data = { be_t::make(MR(11, 2)), - be_t::make(SC(2)), + be_t::make(SC(0)), be_t::make(BLR()) }; diff --git a/rpcs3/Loader/Loader.cpp b/rpcs3/Loader/Loader.cpp index e2567a60f0..e86b1d58e3 100644 --- a/rpcs3/Loader/Loader.cpp +++ b/rpcs3/Loader/Loader.cpp @@ -10,14 +10,19 @@ namespace loader { for (auto i : m_handlers) { - if (i->init(stream) == handler::ok) + i->set_status(i->init(stream)); + if (i->get_status() == handler::ok) { - if (i->load() == handler::ok) + i->set_status(i->load()); + if (i->get_status() == handler::ok) { return true; } + + LOG_ERROR(LOADER, "loader::load() failed: %s", i->get_error_code().c_str()); } + LOG_ERROR(LOADER, "loader::init() failed: %s", i->get_error_code().c_str()); stream.Seek(i->get_stream_offset()); } diff --git a/rpcs3/Loader/Loader.h b/rpcs3/Loader/Loader.h index 3e6fbf925a..9ff96b0dc5 100644 --- a/rpcs3/Loader/Loader.h +++ b/rpcs3/Loader/Loader.h @@ -15,7 +15,7 @@ enum Elf_Machine MACHINE_MIPS = 0x08, MACHINE_PPC64 = 0x15, MACHINE_SPU = 0x17, - MACHINE_ARM = 0x28, + MACHINE_ARM = 0x28 }; enum ShdrType @@ -31,7 +31,7 @@ enum ShdrType SHT_NOBITS, SHT_REL, SHT_SHLIB, - SHT_DYNSYM, + SHT_DYNSYM }; enum ShdrFlag @@ -39,7 +39,7 @@ enum ShdrFlag SHF_WRITE = 0x1, SHF_ALLOC = 0x2, SHF_EXECINSTR = 0x4, - SHF_MASKPROC = 0xf0000000, + SHF_MASKPROC = 0xf0000000 }; const std::string Ehdr_DataToString(const u8 data); @@ -117,7 +117,7 @@ namespace loader broken_file = -3, loading_error = -4, bad_relocation_type = -5, - ok = 0, + ok = 0 }; virtual ~handler() = default; @@ -128,6 +128,34 @@ namespace loader { return m_stream_offset; } + + void set_status(const error_code& code) + { + m_status = code; + } + + error_code get_status() const + { + return m_status; + } + + const std::string get_error_code() const + { + switch (m_status) + { + case bad_version: return "Bad version"; + case bad_file: return "Bad file"; + case broken_file: return "Broken file"; + case loading_error: return "Loading error"; + case bad_relocation_type: return "Bad relocation type"; + case ok: return "Ok"; + + default: return "Unknown error code"; + } + } + + protected: + error_code m_status; }; class loader diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index dbac3af5be..cf88536f65 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -50,7 +50,6 @@ - @@ -134,7 +133,8 @@ - + + @@ -195,10 +195,10 @@ - + @@ -232,11 +232,11 @@ - + @@ -278,13 +278,10 @@ - - - @@ -383,7 +380,8 @@ - + + @@ -421,17 +419,19 @@ - + + - + + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 3166265186..ef7327a0bd 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -69,16 +69,16 @@ {1d9e6fc4-9a79-4329-a8b5-081e24822aaa} - + {6674e2ab-90cd-47de-a852-d21643ab18c2} - + {fadb4b36-57af-4583-891d-d22ff369e266} - + {4adca4fa-b90f-4662-9eb0-1d29cf3cd2eb} - + {6f1da5b2-52c5-416b-9b5c-b9897bc1b300} @@ -209,6 +209,9 @@ Emu\SysCalls\Modules + + Emu\SysCalls\Modules + Emu\SysCalls\Modules @@ -257,9 +260,6 @@ Emu\SysCalls\Modules - - Emu\SysCalls\Modules - Emu\SysCalls\Modules @@ -383,15 +383,9 @@ Source Files - - Utilities - Utilities - - Utilities - Emu\SysCalls @@ -461,9 +455,6 @@ Emu\SysCalls\currently_unused - - Emu\SysCalls\currently_unused - Emu\SysCalls\currently_unused @@ -548,9 +539,6 @@ Emu\SysCalls\lv2 - - Emu\SysCalls\lv2 - Utilities @@ -558,37 +546,37 @@ Emu\SysCalls\Modules - GPU\RSX\GL + Emu\GPU\RSX\GL - GPU\RSX\GL + Emu\GPU\RSX\GL - GPU\RSX\GL + Emu\GPU\RSX\GL - GPU\RSX\GL + Emu\GPU\RSX\GL - GPU\RSX\GL + Emu\GPU\RSX\GL - GPU\RSX\GL + Emu\GPU\RSX\GL - GPU\RSX\GL + Emu\GPU\RSX\GL - GPU\RSX + Emu\GPU\RSX - GPU\RSX + Emu\GPU\RSX - GPU\RSX + Emu\GPU\RSX - GPU\RSX + Emu\GPU\RSX Emu\SysCalls\lv2 @@ -653,6 +641,18 @@ Emu\CPU\ARMv7\Modules + + Emu\SysCalls\lv2 + + + Emu\SysCalls + + + Emu\SysCalls\lv2 + + + Utilities + Emu\SysCalls\Modules @@ -745,6 +745,9 @@ Emu\SysCalls\Modules + + Emu\SysCalls\Modules + Emu\SysCalls\Modules @@ -784,6 +787,9 @@ Emu\SysCalls\Modules + + Emu\SysCalls\Modules + Emu\SysCalls\Modules @@ -1012,18 +1018,9 @@ Utilities - - Utilities - - - Utilities - Utilities - - Utilities - Utilities @@ -1117,9 +1114,6 @@ Emu\SysCalls\lv2 - - Emu\SysCalls\lv2 - Utilities @@ -1127,58 +1121,58 @@ Emu\SysCalls - GPU\RSX\Null + Emu\GPU\RSX\Null - GPU\RSX\GL + Emu\GPU\RSX\GL - GPU\RSX\GL + Emu\GPU\RSX\GL - GPU\RSX\GL + Emu\GPU\RSX\GL - GPU\RSX\GL + Emu\GPU\RSX\GL - GPU\RSX\GL + Emu\GPU\RSX\GL - GPU\RSX\GL + Emu\GPU\RSX\GL - GPU\RSX\GL + Emu\GPU\RSX\GL - GPU\RSX\GL + Emu\GPU\RSX\GL - GPU\RSX\GL + Emu\GPU\RSX\GL - GPU\RSX + Emu\GPU\RSX - GPU\RSX + Emu\GPU\RSX - GPU\RSX + Emu\GPU\RSX - GPU\RSX + Emu\GPU\RSX - GPU\RSX + Emu\GPU\RSX - GPU\RSX + Emu\GPU\RSX - GPU\RSX + Emu\GPU\RSX - GPU\RSX + Emu\GPU\RSX Emu\SysCalls\lv2 @@ -1255,14 +1249,20 @@ Crypto - - Emu\SysCalls\Modules - Emu\CPU\Cell Emu\CPU\ARMv7 + + Emu\SysCalls\lv2 + + + Emu\SysCalls\lv2 + + + Utilities + \ No newline at end of file diff --git a/rpcs3/rpcs3.cpp b/rpcs3/rpcs3.cpp index 2ec10d0ce1..6eb8cbc46b 100644 --- a/rpcs3/rpcs3.cpp +++ b/rpcs3/rpcs3.cpp @@ -3,6 +3,7 @@ #include "Emu/System.h" #include "rpcs3.h" #include "Ini.h" +#include "Utilities/Log.h" #include "Gui/ConLogFrame.h" #include "Emu/GameInfo.h" @@ -42,52 +43,209 @@ Rpcs3App* TheApp; std::string simplify_path(const std::string& path, bool is_dir); +typedef be_t CGprofile; +typedef int CGbool; +typedef be_t CGresource; +typedef be_t CGenum; +typedef be_t CGtype; + +typedef be_t CgBinaryOffset; +typedef CgBinaryOffset CgBinaryEmbeddedConstantOffset; +typedef CgBinaryOffset CgBinaryFloatOffset; +typedef CgBinaryOffset CgBinaryStringOffset; +typedef CgBinaryOffset CgBinaryParameterOffset; + +// a few typedefs +typedef struct CgBinaryParameter CgBinaryParameter; +typedef struct CgBinaryEmbeddedConstant CgBinaryEmbeddedConstant; +typedef struct CgBinaryVertexProgram CgBinaryVertexProgram; +typedef struct CgBinaryFragmentProgram CgBinaryFragmentProgram; +typedef struct CgBinaryProgram CgBinaryProgram; + +// fragment programs have their constants embedded in the microcode +struct CgBinaryEmbeddedConstant +{ + be_t ucodeCount; // occurances + be_t ucodeOffset[1]; // offsets that need to be patched follow +}; + +// describe a binary program parameter (CgParameter is opaque) +struct CgBinaryParameter +{ + CGtype type; // cgGetParameterType() + CGresource res; // cgGetParameterResource() + CGenum var; // cgGetParameterVariability() + be_t resIndex; // cgGetParameterResourceIndex() + CgBinaryStringOffset name; // cgGetParameterName() + CgBinaryFloatOffset defaultValue; // default constant value + CgBinaryEmbeddedConstantOffset embeddedConst; // embedded constant information + CgBinaryStringOffset semantic; // cgGetParameterSemantic() + CGenum direction; // cgGetParameterDirection() + be_t paramno; // 0..n: cgGetParameterIndex() -1: globals + CGbool isReferenced; // cgIsParameterReferenced() + CGbool isShared; // cgIsParameterShared() +}; + +// attributes needed for vshaders +struct CgBinaryVertexProgram +{ + be_t instructionCount; // #instructions + be_t instructionSlot; // load address (indexed reads!) + be_t registerCount; // R registers count + be_t attributeInputMask; // attributes vs reads from + be_t attributeOutputMask; // attributes vs writes (uses SET_VERTEX_ATTRIB_OUTPUT_MASK bits) + be_t userClipMask; // user clip plane enables (for SET_USER_CLIP_PLANE_CONTROL) +}; + +typedef enum { + CgBinaryPTTNone = 0, + CgBinaryPTT2x16 = 1, + CgBinaryPTT1x32 = 2, +} CgBinaryPartialTexType; + +// attributes needed for pshaders +struct CgBinaryFragmentProgram +{ + be_t instructionCount; // #instructions + be_t attributeInputMask; // attributes fp reads (uses SET_VERTEX_ATTRIB_OUTPUT_MASK bits) + be_t partialTexType; // texid 0..15 use two bits each marking whether the texture format requires partial load: see CgBinaryPartialTexType + be_t texCoordsInputMask; // tex coords used by frag prog. (tex is bit n) + be_t texCoords2D; // tex coords that are 2d (tex is bit n) + be_t texCoordsCentroid; // tex coords that are centroid (tex is bit n) + unsigned char registerCount; // R registers count + unsigned char outputFromH0; // final color from R0 or H0 + unsigned char depthReplace; // fp generated z epth value + unsigned char pixelKill; // fp uses kill operations +}; + +#include "Emu/RSX/GL/GLFragmentProgram.h" +#include "Emu/RSX/GL/GLVertexProgram.h" +// defines a binary program -- *all* address/offsets are relative to the begining of CgBinaryProgram +struct CgBinaryProgram +{ + // vertex/pixel shader identification (BE/LE as well) + CGprofile profile; + + // binary revision (used to verify binary and driver structs match) + be_t binaryFormatRevision; + + // total size of this struct including profile and totalSize field! + be_t totalSize; + + // parameter usually queried using cgGet[First/Next]LeafParameter + be_t parameterCount; + CgBinaryParameterOffset parameterArray; + + // depending on profile points to a CgBinaryVertexProgram or CgBinaryFragmentProgram struct + CgBinaryOffset program; + + // raw ucode data + be_t ucodeSize; + CgBinaryOffset ucode; + + // variable length data follows + unsigned char data[1]; +}; + +void compile_shader(std::string path) +{ + ShaderVar var("r0.yz.x"); + var.symplify(); + LOG_ERROR(GENERAL, var.get().c_str()); + + u32 ptr; + { + wxFile f(path); + + if (!f.IsOpened()) + return; + + size_t size = f.Length(); + vm::ps3::init(); + ptr = vm::alloc(size); + f.Read(vm::get_ptr(ptr), size); + f.Close(); + } + + CgBinaryProgram& prog = vm::get_ref(ptr); + LOG_ERROR(GENERAL, "%d - %x", (u32)prog.profile, (u32)prog.binaryFormatRevision); + + std::string shader; + GLParamArray param_array; + u32 size; + + if (prog.profile == 7004) + { + CgBinaryFragmentProgram& fprog = vm::get_ref(ptr + prog.program); + + u32 ctrl = (fprog.outputFromH0 ? 0 : 0x40) | (fprog.depthReplace ? 0xe : 0); + + GLFragmentDecompilerThread(shader, param_array, ptr + prog.ucode, size, ctrl).Task(); + } + else + { + CgBinaryVertexProgram& vprog = vm::get_ref(ptr + prog.program); + + std::vector data; + be_t* vdata = vm::get_ptr>(ptr + prog.ucode); + for (u32 i = 0; i < prog.ucodeSize; ++i, ++vdata) + { + data.push_back(vdata[i]); + } + + GLVertexDecompilerThread(data, shader, param_array).Task(); + } + + LOG_ERROR(GENERAL, shader.c_str()); + vm::close(); +} + bool Rpcs3App::OnInit() { SetSendDbgCommandCallback([](DbgCommand id, CPUThread* t) { wxGetApp().SendDbgCommand(id, t); }); + SetCallAfterCallback([](std::function func) { wxGetApp().CallAfter(func); }); + SetGetKeyboardHandlerCountCallback([]() { return 2; }); + SetGetKeyboardHandlerCallback([](int i) -> KeyboardHandlerBase* { switch (i) { - case 0: - return new NullKeyboardHandler(); - break; - case 1: - return new WindowsKeyboardHandler(); - break; - default: - return new NullKeyboardHandler(); + case 0: return new NullKeyboardHandler(); + case 1: return new WindowsKeyboardHandler(); } + + assert(!"Invalid keyboard handler number"); + return new NullKeyboardHandler(); }); + SetGetMouseHandlerCountCallback([]() { return 2; }); + SetGetMouseHandlerCallback([](int i) -> MouseHandlerBase* { switch (i) { - case 0: - return new NullMouseHandler(); - break; - case 1: - return new WindowsMouseHandler(); - break; - default: - return new NullMouseHandler(); + case 0: return new NullMouseHandler(); + case 1: return new WindowsMouseHandler(); } + + assert(!"Invalid mouse handler number"); + return new NullMouseHandler(); }); + SetGetPadHandlerCountCallback([]() { #if defined(_WIN32) @@ -96,34 +254,28 @@ bool Rpcs3App::OnInit() return 2; #endif }); + SetGetPadHandlerCallback([](int i) -> PadHandlerBase* { switch (i) { - case 0: - return new NullPadHandler(); - break; - case 1: - return new WindowsPadHandler(); - break; + case 0: return new NullPadHandler(); + case 1: return new WindowsPadHandler(); #if defined(_WIN32) - case 2: - return new XInputPadHandler(); - break; + case 2: return new XInputPadHandler(); #endif - default: - return new NullPadHandler(); } + + assert(!"Invalid pad handler number"); + return new NullPadHandler(); }); + SetGetGSFrameCallback([]() -> GSFrameBase* { return new GLGSFrame(); }); - SetMsgDialogCreateCallback(MsgDialogCreate); - SetMsgDialogDestroyCallback(MsgDialogDestroy); - SetMsgDialogProgressBarSetMsgCallback(MsgDialogProgressBarSetMsg); - SetMsgDialogProgressBarResetCallback(MsgDialogProgressBarReset); - SetMsgDialogProgressBarIncCallback(MsgDialogProgressBarInc); + + SetMsgDialogCallbacks(MsgDialogCreate, MsgDialogDestroy, MsgDialogProgressBarSetMsg, MsgDialogProgressBarReset, MsgDialogProgressBarInc); TheApp = this; SetAppName(_PRGNAME_); @@ -146,6 +298,9 @@ bool Rpcs3App::OnInit() OnArguments(); + //compile_shader("compile_shader0.spo"); + //compile_shader("compile_shader1.spo"); + return true; } @@ -187,9 +342,9 @@ Rpcs3App::Rpcs3App() timeBeginPeriod(1); #endif - #if defined(__unix__) && !defined(__APPLE__) +#if defined(__unix__) && !defined(__APPLE__) XInitThreads(); - #endif +#endif } GameInfo CurGameInfo; diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index 946b6cb66e..44c219a587 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -175,6 +175,7 @@ + diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters index 5fce1aa362..71062a8296 100644 --- a/rpcs3/rpcs3.vcxproj.filters +++ b/rpcs3/rpcs3.vcxproj.filters @@ -93,6 +93,9 @@ Gui + + Gui +