mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-22 02:32:36 +01:00
PPUThread refactoring
`CallbackManager` removed, added _gcm_intr_thread for cellGcmSys `PPUThread` renamed to `ppu_thread`, inheritance allowed Added lightweight command queue for `ppu_thread` Implemented call stack dump for PPU `get_current_thread_mutex` removed `thread_ctrl::spawn`: minor initialization fix `thread_ctrl::wait_for` added `named_thread`: some methods added `cpu_thread::run` added Some bugs fixes, including SPU channels
This commit is contained in:
parent
33c59fa51b
commit
f8719c1230
@ -143,22 +143,34 @@ struct atomic_storage
|
||||
return atomic_storage<T>::sub_fetch(dest, 1);
|
||||
}
|
||||
|
||||
static inline bool test_and_set(T& dest, T mask)
|
||||
{
|
||||
return (atomic_storage<T>::fetch_or(dest, mask) & mask) != 0;
|
||||
}
|
||||
|
||||
static inline bool test_and_reset(T& dest, T mask)
|
||||
{
|
||||
return (atomic_storage<T>::fetch_and(dest, ~mask) & mask) != 0;
|
||||
}
|
||||
|
||||
static inline bool test_and_complement(T& dest, T mask)
|
||||
{
|
||||
return (atomic_storage<T>::fetch_xor(dest, mask) & mask) != 0;
|
||||
}
|
||||
|
||||
static inline bool bts(T& dest, uint bit)
|
||||
{
|
||||
const T mask = static_cast<T>(1) << bit;
|
||||
return (atomic_storage<T>::fetch_or(dest, mask) & mask) != 0;
|
||||
return atomic_storage<T>::test_and_set(dest, static_cast<T>(1) << bit);
|
||||
}
|
||||
|
||||
static inline bool btr(T& dest, uint bit)
|
||||
{
|
||||
const T mask = static_cast<T>(1) << bit;
|
||||
return (atomic_storage<T>::fetch_and(dest, ~mask) & mask) != 0;
|
||||
return atomic_storage<T>::test_and_reset(dest, static_cast<T>(1) << bit);
|
||||
}
|
||||
|
||||
static inline bool btc(T& dest, uint bit)
|
||||
{
|
||||
const T mask = static_cast<T>(1) << bit;
|
||||
return (atomic_storage<T>::fetch_xor(dest, mask) & mask) != 0;
|
||||
return atomic_storage<T>::test_and_complement(dest, static_cast<T>(1) << bit);
|
||||
}
|
||||
};
|
||||
|
||||
@ -637,14 +649,9 @@ struct atomic_test_and_set
|
||||
template<typename T1, typename T2>
|
||||
struct atomic_test_and_set<T1, T2, std::enable_if_t<std::is_integral<T1>::value && std::is_convertible<T2, T1>::value>>
|
||||
{
|
||||
static inline bool op(T1& lhs, const T2& rhs)
|
||||
{
|
||||
return (atomic_storage<T1>::fetch_or(lhs, rhs) & rhs) != 0;
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &op;
|
||||
static constexpr auto op_fetch = &op;
|
||||
static constexpr auto atomic_op = &op;
|
||||
static constexpr auto fetch_op = &atomic_storage<T1>::test_and_set;
|
||||
static constexpr auto op_fetch = &atomic_storage<T1>::test_and_set;
|
||||
static constexpr auto atomic_op = &atomic_storage<T1>::test_and_set;
|
||||
};
|
||||
|
||||
template<typename T1, typename T2, typename>
|
||||
@ -659,14 +666,9 @@ struct atomic_test_and_reset
|
||||
template<typename T1, typename T2>
|
||||
struct atomic_test_and_reset<T1, T2, std::enable_if_t<std::is_integral<T1>::value && std::is_convertible<T2, T1>::value>>
|
||||
{
|
||||
static inline bool op(T1& lhs, const T2& rhs)
|
||||
{
|
||||
return (atomic_storage<T1>::fetch_and(lhs, ~rhs) & rhs) != 0;
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &op;
|
||||
static constexpr auto op_fetch = &op;
|
||||
static constexpr auto atomic_op = &op;
|
||||
static constexpr auto fetch_op = &atomic_storage<T1>::test_and_reset;
|
||||
static constexpr auto op_fetch = &atomic_storage<T1>::test_and_reset;
|
||||
static constexpr auto atomic_op = &atomic_storage<T1>::test_and_reset;
|
||||
};
|
||||
|
||||
template<typename T1, typename T2, typename>
|
||||
@ -681,14 +683,9 @@ struct atomic_test_and_complement
|
||||
template<typename T1, typename T2>
|
||||
struct atomic_test_and_complement<T1, T2, std::enable_if_t<std::is_integral<T1>::value && std::is_convertible<T2, T1>::value>>
|
||||
{
|
||||
static inline bool op(T1& lhs, const T2& rhs)
|
||||
{
|
||||
return (atomic_storage<T1>::fetch_xor(lhs, rhs) & rhs) != 0;
|
||||
}
|
||||
|
||||
static constexpr auto fetch_op = &op;
|
||||
static constexpr auto op_fetch = &op;
|
||||
static constexpr auto atomic_op = &op;
|
||||
static constexpr auto fetch_op = &atomic_storage<T1>::test_and_complement;
|
||||
static constexpr auto op_fetch = &atomic_storage<T1>::test_and_complement;
|
||||
static constexpr auto atomic_op = &atomic_storage<T1>::test_and_complement;
|
||||
};
|
||||
|
||||
// Atomic type with lock-free and standard layout guarantees (and appropriate limitations)
|
||||
|
@ -12,7 +12,7 @@ template<typename T> using sleep_queue = std::deque<T*>;
|
||||
// Sleep is called in the constructor (if not null)
|
||||
// Awake is called in the destructor (if not null)
|
||||
// Sleep queue is actually std::deque with pointers, be careful about the lifetime
|
||||
template<typename T, void(T::*Sleep)() = &T::sleep, void(T::*Awake)() = &T::awake>
|
||||
template<typename T, void(T::*Sleep)() = nullptr, void(T::*Awake)() = nullptr>
|
||||
class sleep_entry final
|
||||
{
|
||||
sleep_queue<T>& m_queue;
|
||||
|
@ -1830,11 +1830,6 @@ struct thread_ctrl::internal
|
||||
|
||||
thread_local thread_ctrl::internal* g_tls_internal = nullptr;
|
||||
|
||||
extern std::mutex& get_current_thread_mutex()
|
||||
{
|
||||
return g_tls_internal->mutex;
|
||||
}
|
||||
|
||||
extern std::condition_variable& get_current_thread_cv()
|
||||
{
|
||||
return g_tls_internal->cond;
|
||||
@ -2244,7 +2239,7 @@ void named_thread::start_thread(const std::shared_ptr<void>& _this)
|
||||
ENSURES(_this.get() == this);
|
||||
|
||||
// Run thread
|
||||
m_thread = thread_ctrl::spawn(get_name(), [this, _this]()
|
||||
thread_ctrl::spawn(m_thread, get_name(), [this, _this]()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -233,9 +233,12 @@ public:
|
||||
// Wait until pred(). Abortable, may throw. Thread must be locked.
|
||||
// Timeout in microseconds (zero means infinite).
|
||||
template<typename F>
|
||||
static inline auto wait(u64 useconds, F&& pred)
|
||||
static inline auto wait_for(u64 useconds, F&& pred)
|
||||
{
|
||||
g_tls_this_thread->wait_start(useconds);
|
||||
if (useconds)
|
||||
{
|
||||
g_tls_this_thread->wait_start(useconds);
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
@ -252,6 +255,26 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// Wait once. Abortable, may throw. Thread must be locked.
|
||||
// Timeout in microseconds (zero means infinite).
|
||||
static inline bool wait_for(u64 useconds = 0)
|
||||
{
|
||||
if (useconds)
|
||||
{
|
||||
g_tls_this_thread->wait_start(useconds);
|
||||
}
|
||||
|
||||
g_tls_this_thread->test();
|
||||
|
||||
if (!g_tls_this_thread->wait_wait(useconds) && useconds)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
g_tls_this_thread->test();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Wait until pred(). Abortable, may throw. Thread must be locked.
|
||||
template<typename F>
|
||||
static inline auto wait(F&& pred)
|
||||
@ -269,7 +292,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// Wait once. Thread must be locked.
|
||||
// Wait once. Abortable, may throw. Thread must be locked.
|
||||
static inline void wait()
|
||||
{
|
||||
g_tls_this_thread->test();
|
||||
@ -277,7 +300,7 @@ public:
|
||||
g_tls_this_thread->test();
|
||||
}
|
||||
|
||||
// Wait unconditionally until aborted. Thread must be locked.
|
||||
// Wait eternally. Abortable, may throw. Thread must be locked.
|
||||
[[noreturn]] static inline void eternalize()
|
||||
{
|
||||
while (true)
|
||||
@ -302,13 +325,20 @@ public:
|
||||
|
||||
// Named thread factory
|
||||
template<typename N, typename F>
|
||||
static inline std::shared_ptr<thread_ctrl> spawn(N&& name, F&& func)
|
||||
static inline void spawn(N&& name, F&& func)
|
||||
{
|
||||
auto ctrl = std::make_shared<thread_ctrl>(std::forward<N>(name));
|
||||
auto&& out = std::make_shared<thread_ctrl>(std::forward<N>(name));
|
||||
|
||||
thread_ctrl::start(ctrl, std::forward<F>(func));
|
||||
thread_ctrl::start(out, std::forward<F>(func));
|
||||
}
|
||||
|
||||
return ctrl;
|
||||
// Named thread factory
|
||||
template<typename N, typename F>
|
||||
static inline void spawn(std::shared_ptr<thread_ctrl>& out, N&& name, F&& func)
|
||||
{
|
||||
out = std::make_shared<thread_ctrl>(std::forward<N>(name));
|
||||
|
||||
thread_ctrl::start(out, std::forward<F>(func));
|
||||
}
|
||||
};
|
||||
|
||||
@ -356,6 +386,31 @@ public:
|
||||
{
|
||||
return m_thread.get();
|
||||
}
|
||||
|
||||
void join() const
|
||||
{
|
||||
return m_thread->join();
|
||||
}
|
||||
|
||||
void lock() const
|
||||
{
|
||||
return m_thread->lock();
|
||||
}
|
||||
|
||||
void unlock() const
|
||||
{
|
||||
return m_thread->unlock();
|
||||
}
|
||||
|
||||
void lock_notify() const
|
||||
{
|
||||
return m_thread->lock_notify();
|
||||
}
|
||||
|
||||
void notify() const
|
||||
{
|
||||
return m_thread->notify();
|
||||
}
|
||||
};
|
||||
|
||||
// Simple thread mutex locker
|
||||
@ -429,8 +484,8 @@ class scope_thread final
|
||||
public:
|
||||
template<typename N, typename F>
|
||||
scope_thread(N&& name, F&& func)
|
||||
: m_thread(thread_ctrl::spawn(std::forward<N>(name), std::forward<F>(func)))
|
||||
{
|
||||
thread_ctrl::spawn(m_thread, std::forward<N>(name), std::forward<F>(func));
|
||||
}
|
||||
|
||||
// Deleted copy/move constructors + copy/move operators
|
||||
@ -441,4 +496,10 @@ public:
|
||||
{
|
||||
m_thread->join();
|
||||
}
|
||||
|
||||
// Access thread_ctrl
|
||||
thread_ctrl* operator->() const
|
||||
{
|
||||
return m_thread.get();
|
||||
}
|
||||
};
|
||||
|
@ -3,13 +3,9 @@
|
||||
#include "CPUThread.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
thread_local cpu_thread* g_tls_current_cpu_thread = nullptr;
|
||||
|
||||
extern std::mutex& get_current_thread_mutex();
|
||||
extern std::condition_variable& get_current_thread_cv();
|
||||
|
||||
void cpu_thread::on_task()
|
||||
{
|
||||
state -= cpu_state::exit;
|
||||
@ -18,7 +14,7 @@ void cpu_thread::on_task()
|
||||
|
||||
Emu.SendDbgCommand(DID_CREATE_THREAD, this);
|
||||
|
||||
std::unique_lock<std::mutex> lock(get_current_thread_mutex());
|
||||
std::unique_lock<named_thread> lock(*this);
|
||||
|
||||
// Check thread status
|
||||
while (!(state & cpu_state::exit))
|
||||
@ -54,14 +50,14 @@ void cpu_thread::on_task()
|
||||
continue;
|
||||
}
|
||||
|
||||
get_current_thread_cv().wait(lock);
|
||||
thread_ctrl::wait();
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_thread::on_stop()
|
||||
{
|
||||
state += cpu_state::exit;
|
||||
(*this)->lock_notify();
|
||||
lock_notify();
|
||||
}
|
||||
|
||||
cpu_thread::~cpu_thread()
|
||||
@ -73,9 +69,9 @@ cpu_thread::cpu_thread(cpu_type type)
|
||||
{
|
||||
}
|
||||
|
||||
bool cpu_thread::check_status()
|
||||
bool cpu_thread::check_state()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(get_current_thread_mutex(), std::defer_lock);
|
||||
std::unique_lock<named_thread> lock(*this, std::defer_lock);
|
||||
|
||||
while (true)
|
||||
{
|
||||
@ -86,7 +82,7 @@ bool cpu_thread::check_status()
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!state.test(cpu_state_pause) && !state.test(cpu_state::interrupt))
|
||||
if (!state.test(cpu_state_pause))
|
||||
{
|
||||
break;
|
||||
}
|
||||
@ -97,12 +93,7 @@ bool cpu_thread::check_status()
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!state.test(cpu_state_pause) && state & cpu_state::interrupt && handle_interrupt())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
get_current_thread_cv().wait(lock);
|
||||
thread_ctrl::wait();
|
||||
}
|
||||
|
||||
const auto state_ = state.load();
|
||||
@ -120,3 +111,9 @@ bool cpu_thread::check_status()
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void cpu_thread::run()
|
||||
{
|
||||
state -= cpu_state::stop;
|
||||
lock_notify();
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include "../Utilities/Thread.h"
|
||||
#include "../Utilities/BitSet.h"
|
||||
|
||||
// CPU Thread Type
|
||||
// CPU Thread Type (TODO: probably remove, use id and idm to classify threads)
|
||||
enum class cpu_type : u8
|
||||
{
|
||||
ppu, // PPU Thread
|
||||
@ -11,7 +11,7 @@ enum class cpu_type : u8
|
||||
arm, // ARMv7 Thread
|
||||
};
|
||||
|
||||
// CPU Thread State flags
|
||||
// CPU Thread State flags (TODO: use u32 once cpu_type is removed)
|
||||
enum struct cpu_state : u16
|
||||
{
|
||||
stop, // Thread not running (HLE, initial state)
|
||||
@ -19,7 +19,6 @@ enum struct cpu_state : u16
|
||||
suspend, // Thread paused
|
||||
ret, // Callback return requested
|
||||
signal, // Thread received a signal (HLE)
|
||||
interrupt, // Thread interrupted
|
||||
|
||||
dbg_global_pause, // Emulation paused
|
||||
dbg_global_stop, // Emulation stopped
|
||||
@ -43,9 +42,6 @@ public:
|
||||
|
||||
cpu_thread(cpu_type type);
|
||||
|
||||
// Public recursive sleep state counter
|
||||
atomic_t<u8> sleep_counter{};
|
||||
|
||||
// Public thread state
|
||||
atomic_t<bitset_t<cpu_state>> state{ cpu_state::stop };
|
||||
|
||||
@ -53,25 +49,14 @@ public:
|
||||
atomic_t<void*> owner{};
|
||||
|
||||
// Process thread state, return true if the checker must return
|
||||
bool check_status();
|
||||
bool check_state();
|
||||
|
||||
// Increse sleep counter
|
||||
void sleep()
|
||||
{
|
||||
if (!sleep_counter++) return; //handle_interrupt();
|
||||
}
|
||||
// Run thread
|
||||
void run();
|
||||
|
||||
// Decrese sleep counter
|
||||
void awake()
|
||||
{
|
||||
if (!--sleep_counter) owner = nullptr;
|
||||
}
|
||||
|
||||
// Print CPU state
|
||||
virtual std::string dump() const = 0;
|
||||
virtual void cpu_init() {}
|
||||
virtual std::string dump() const = 0; // Print CPU state
|
||||
virtual void cpu_init() {} // Obsolete, must be removed
|
||||
virtual void cpu_task() = 0;
|
||||
virtual bool handle_interrupt() { return false; }
|
||||
};
|
||||
|
||||
inline cpu_thread* get_current_cpu_thread() noexcept
|
||||
@ -80,27 +65,3 @@ inline cpu_thread* get_current_cpu_thread() noexcept
|
||||
|
||||
return g_tls_current_cpu_thread;
|
||||
}
|
||||
|
||||
// Helper for cpu_thread.
|
||||
// 1) Calls sleep() and locks the thread in the constructor.
|
||||
// 2) Calls awake() and unlocks the thread in the destructor.
|
||||
class cpu_thread_lock final
|
||||
{
|
||||
cpu_thread& m_thread;
|
||||
|
||||
public:
|
||||
cpu_thread_lock(const cpu_thread_lock&) = delete;
|
||||
|
||||
cpu_thread_lock(cpu_thread& thread)
|
||||
: m_thread(thread)
|
||||
{
|
||||
m_thread.sleep();
|
||||
m_thread->lock();
|
||||
}
|
||||
|
||||
~cpu_thread_lock()
|
||||
{
|
||||
m_thread.awake();
|
||||
m_thread->unlock();
|
||||
}
|
||||
};
|
||||
|
@ -3,8 +3,6 @@
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
|
||||
extern std::mutex g_mutex_avcodec_open2;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "libavcodec/avcodec.h"
|
||||
@ -15,97 +13,391 @@ extern "C"
|
||||
#include "cellPamf.h"
|
||||
#include "cellAdec.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
extern std::mutex g_mutex_avcodec_open2;
|
||||
|
||||
logs::channel cellAdec("cellAdec", logs::level::notice);
|
||||
|
||||
AudioDecoder::AudioDecoder(s32 type, u32 addr, u32 size, vm::ptr<CellAdecCbMsg> func, u32 arg)
|
||||
: type(type)
|
||||
, memAddr(addr)
|
||||
, memSize(size)
|
||||
, memBias(0)
|
||||
, cbFunc(func)
|
||||
, cbArg(arg)
|
||||
, is_closed(false)
|
||||
, is_finished(false)
|
||||
, just_started(false)
|
||||
, just_finished(false)
|
||||
, codec(nullptr)
|
||||
, input_format(nullptr)
|
||||
, ctx(nullptr)
|
||||
, fmt(nullptr)
|
||||
class AudioDecoder : public ppu_thread
|
||||
{
|
||||
av_register_all();
|
||||
avcodec_register_all();
|
||||
public:
|
||||
squeue_t<AdecTask> job;
|
||||
volatile bool is_closed;
|
||||
volatile bool is_finished;
|
||||
bool just_started;
|
||||
bool just_finished;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case CELL_ADEC_TYPE_ATRACX:
|
||||
case CELL_ADEC_TYPE_ATRACX_2CH:
|
||||
case CELL_ADEC_TYPE_ATRACX_6CH:
|
||||
case CELL_ADEC_TYPE_ATRACX_8CH:
|
||||
{
|
||||
codec = avcodec_find_decoder(AV_CODEC_ID_ATRAC3P);
|
||||
input_format = av_find_input_format("oma");
|
||||
break;
|
||||
}
|
||||
case CELL_ADEC_TYPE_MP3:
|
||||
{
|
||||
codec = avcodec_find_decoder(AV_CODEC_ID_MP3);
|
||||
input_format = av_find_input_format("mp3");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw EXCEPTION("Unknown type (0x%x)", type);
|
||||
}
|
||||
}
|
||||
AVCodec* codec;
|
||||
AVInputFormat* input_format;
|
||||
AVCodecContext* ctx;
|
||||
AVFormatContext* fmt;
|
||||
u8* io_buf;
|
||||
|
||||
if (!codec)
|
||||
struct AudioReader
|
||||
{
|
||||
throw EXCEPTION("avcodec_find_decoder() failed");
|
||||
}
|
||||
if (!input_format)
|
||||
{
|
||||
throw EXCEPTION("av_find_input_format() failed");
|
||||
}
|
||||
fmt = avformat_alloc_context();
|
||||
if (!fmt)
|
||||
{
|
||||
throw EXCEPTION("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)
|
||||
{
|
||||
throw EXCEPTION("avio_alloc_context() failed");
|
||||
}
|
||||
}
|
||||
u32 addr;
|
||||
u32 size;
|
||||
bool init;
|
||||
bool has_ats;
|
||||
|
||||
AudioDecoder::~AudioDecoder()
|
||||
{
|
||||
// TODO: check finalization
|
||||
AdecFrame af;
|
||||
while (frames.try_pop(af))
|
||||
{
|
||||
av_frame_unref(af.data);
|
||||
av_frame_free(&af.data);
|
||||
}
|
||||
if (ctx)
|
||||
{
|
||||
avcodec_close(ctx);
|
||||
avformat_close_input(&fmt);
|
||||
}
|
||||
if (fmt)
|
||||
{
|
||||
if (io_buf)
|
||||
AudioReader()
|
||||
: init(false)
|
||||
{
|
||||
av_free(io_buf);
|
||||
}
|
||||
if (fmt->pb) av_free(fmt->pb);
|
||||
avformat_free_context(fmt);
|
||||
|
||||
} reader;
|
||||
|
||||
squeue_t<AdecFrame> frames;
|
||||
|
||||
const s32 type;
|
||||
const u32 memAddr;
|
||||
const u32 memSize;
|
||||
const vm::ptr<CellAdecCbMsg> cbFunc;
|
||||
const u32 cbArg;
|
||||
u32 memBias;
|
||||
|
||||
AdecTask task;
|
||||
u64 last_pts, first_pts;
|
||||
|
||||
u32 ch_out;
|
||||
u32 ch_cfg;
|
||||
u32 frame_size;
|
||||
u32 sample_rate;
|
||||
bool use_ats_headers;
|
||||
|
||||
AudioDecoder(s32 type, u32 addr, u32 size, vm::ptr<CellAdecCbMsg> func, u32 arg)
|
||||
: ppu_thread("HLE Audio Decoder")
|
||||
, type(type)
|
||||
, memAddr(addr)
|
||||
, memSize(size)
|
||||
, memBias(0)
|
||||
, cbFunc(func)
|
||||
, cbArg(arg)
|
||||
, is_closed(false)
|
||||
, is_finished(false)
|
||||
, just_started(false)
|
||||
, just_finished(false)
|
||||
, codec(nullptr)
|
||||
, input_format(nullptr)
|
||||
, ctx(nullptr)
|
||||
, fmt(nullptr)
|
||||
{
|
||||
av_register_all();
|
||||
avcodec_register_all();
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case CELL_ADEC_TYPE_ATRACX:
|
||||
case CELL_ADEC_TYPE_ATRACX_2CH:
|
||||
case CELL_ADEC_TYPE_ATRACX_6CH:
|
||||
case CELL_ADEC_TYPE_ATRACX_8CH:
|
||||
{
|
||||
codec = avcodec_find_decoder(AV_CODEC_ID_ATRAC3P);
|
||||
input_format = av_find_input_format("oma");
|
||||
break;
|
||||
}
|
||||
case CELL_ADEC_TYPE_MP3:
|
||||
{
|
||||
codec = avcodec_find_decoder(AV_CODEC_ID_MP3);
|
||||
input_format = av_find_input_format("mp3");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw EXCEPTION("Unknown type (0x%x)", type);
|
||||
}
|
||||
}
|
||||
|
||||
if (!codec)
|
||||
{
|
||||
throw EXCEPTION("avcodec_find_decoder() failed");
|
||||
}
|
||||
if (!input_format)
|
||||
{
|
||||
throw EXCEPTION("av_find_input_format() failed");
|
||||
}
|
||||
fmt = avformat_alloc_context();
|
||||
if (!fmt)
|
||||
{
|
||||
throw EXCEPTION("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)
|
||||
{
|
||||
throw EXCEPTION("avio_alloc_context() failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~AudioDecoder()
|
||||
{
|
||||
// TODO: check finalization
|
||||
AdecFrame af;
|
||||
while (frames.try_pop(af))
|
||||
{
|
||||
av_frame_unref(af.data);
|
||||
av_frame_free(&af.data);
|
||||
}
|
||||
if (ctx)
|
||||
{
|
||||
avcodec_close(ctx);
|
||||
avformat_close_input(&fmt);
|
||||
}
|
||||
if (fmt)
|
||||
{
|
||||
if (io_buf)
|
||||
{
|
||||
av_free(io_buf);
|
||||
}
|
||||
if (fmt->pb) av_free(fmt->pb);
|
||||
avformat_free_context(fmt);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void cpu_task() override
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (Emu.IsStopped() || is_closed)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (!job.pop(task, &is_closed))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
switch (task.type)
|
||||
{
|
||||
case adecStartSeq:
|
||||
{
|
||||
// TODO: reset data
|
||||
cellAdec.warning("adecStartSeq:");
|
||||
|
||||
reader.addr = 0;
|
||||
reader.size = 0;
|
||||
reader.init = false;
|
||||
reader.has_ats = false;
|
||||
just_started = true;
|
||||
|
||||
if (adecIsAtracX(type))
|
||||
{
|
||||
ch_cfg = task.at3p.channel_config;
|
||||
ch_out = task.at3p.channels;
|
||||
frame_size = task.at3p.frame_size;
|
||||
sample_rate = task.at3p.sample_rate;
|
||||
use_ats_headers = task.at3p.ats_header == 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case adecEndSeq:
|
||||
{
|
||||
// TODO: finalize
|
||||
cellAdec.warning("adecEndSeq:");
|
||||
cbFunc(*this, id, CELL_ADEC_MSG_TYPE_SEQDONE, CELL_OK, cbArg);
|
||||
|
||||
just_finished = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case adecDecodeAu:
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
reader.addr = task.au.addr;
|
||||
reader.size = task.au.size;
|
||||
reader.has_ats = use_ats_headers;
|
||||
//LOG_NOTICE(HLE, "Audio AU: size = 0x%x, pts = 0x%llx", task.au.size, task.au.pts);
|
||||
|
||||
if (just_started)
|
||||
{
|
||||
first_pts = task.au.pts;
|
||||
last_pts = task.au.pts;
|
||||
if (adecIsAtracX(type)) last_pts -= 0x10000; // hack
|
||||
}
|
||||
|
||||
struct AVPacketHolder : AVPacket
|
||||
{
|
||||
AVPacketHolder(u32 size)
|
||||
{
|
||||
av_init_packet(this);
|
||||
|
||||
if (size)
|
||||
{
|
||||
data = (u8*)av_calloc(1, size + FF_INPUT_BUFFER_PADDING_SIZE);
|
||||
this->size = size + FF_INPUT_BUFFER_PADDING_SIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
data = NULL;
|
||||
size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
~AVPacketHolder()
|
||||
{
|
||||
av_free(data);
|
||||
}
|
||||
|
||||
} au(0);
|
||||
|
||||
if (just_started && just_finished)
|
||||
{
|
||||
avcodec_flush_buffers(ctx);
|
||||
|
||||
reader.init = true; // wrong
|
||||
just_finished = false;
|
||||
just_started = false;
|
||||
}
|
||||
else if (just_started) // deferred initialization
|
||||
{
|
||||
AVDictionary* opts = nullptr;
|
||||
av_dict_set(&opts, "probesize", "96", 0);
|
||||
err = avformat_open_input(&fmt, NULL, input_format, &opts);
|
||||
if (err || opts)
|
||||
{
|
||||
throw EXCEPTION("avformat_open_input() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0);
|
||||
}
|
||||
//err = avformat_find_stream_info(fmt, NULL);
|
||||
//if (err || !fmt->nb_streams)
|
||||
//{
|
||||
// ADEC_ERROR("adecDecodeAu: avformat_find_stream_info() failed (err=0x%x, nb_streams=%d)", err, fmt->nb_streams);
|
||||
//}
|
||||
if (!avformat_new_stream(fmt, codec))
|
||||
{
|
||||
throw EXCEPTION("avformat_new_stream() failed");
|
||||
}
|
||||
ctx = fmt->streams[0]->codec; // TODO: check data
|
||||
|
||||
opts = nullptr;
|
||||
av_dict_set(&opts, "refcounted_frames", "1", 0);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_mutex_avcodec_open2);
|
||||
// not multithread-safe (???)
|
||||
err = avcodec_open2(ctx, codec, &opts);
|
||||
}
|
||||
if (err || opts)
|
||||
{
|
||||
throw EXCEPTION("avcodec_open2() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0);
|
||||
}
|
||||
just_started = false;
|
||||
}
|
||||
|
||||
bool last_frame = false;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (Emu.IsStopped() || is_closed)
|
||||
{
|
||||
if (Emu.IsStopped()) cellAdec.warning("adecDecodeAu: aborted");
|
||||
break;
|
||||
}
|
||||
|
||||
last_frame = av_read_frame(fmt, &au) < 0;
|
||||
if (last_frame)
|
||||
{
|
||||
//break;
|
||||
av_free(au.data);
|
||||
au.data = NULL;
|
||||
au.size = 0;
|
||||
}
|
||||
|
||||
struct AdecFrameHolder : AdecFrame
|
||||
{
|
||||
AdecFrameHolder()
|
||||
{
|
||||
data = av_frame_alloc();
|
||||
}
|
||||
|
||||
~AdecFrameHolder()
|
||||
{
|
||||
if (data)
|
||||
{
|
||||
av_frame_unref(data);
|
||||
av_frame_free(&data);
|
||||
}
|
||||
}
|
||||
|
||||
} frame;
|
||||
|
||||
if (!frame.data)
|
||||
{
|
||||
throw EXCEPTION("av_frame_alloc() failed");
|
||||
}
|
||||
|
||||
int got_frame = 0;
|
||||
|
||||
int decode = avcodec_decode_audio4(ctx, frame.data, &got_frame, &au);
|
||||
|
||||
if (decode <= 0)
|
||||
{
|
||||
if (decode < 0)
|
||||
{
|
||||
cellAdec.error("adecDecodeAu: AU decoding error(0x%x)", decode);
|
||||
}
|
||||
if (!got_frame && reader.size == 0) break;
|
||||
}
|
||||
|
||||
if (got_frame)
|
||||
{
|
||||
//u64 ts = av_frame_get_best_effort_timestamp(frame.data);
|
||||
//if (ts != AV_NOPTS_VALUE)
|
||||
//{
|
||||
// frame.pts = ts/* - first_pts*/;
|
||||
// last_pts = frame.pts;
|
||||
//}
|
||||
last_pts += ((u64)frame.data->nb_samples) * 90000 / frame.data->sample_rate;
|
||||
frame.pts = last_pts;
|
||||
|
||||
s32 nbps = av_get_bytes_per_sample((AVSampleFormat)frame.data->format);
|
||||
switch (frame.data->format)
|
||||
{
|
||||
case AV_SAMPLE_FMT_FLTP: break;
|
||||
case AV_SAMPLE_FMT_S16P: break;
|
||||
default:
|
||||
{
|
||||
throw EXCEPTION("Unsupported frame format(%d)", frame.data->format);
|
||||
}
|
||||
}
|
||||
frame.auAddr = task.au.addr;
|
||||
frame.auSize = task.au.size;
|
||||
frame.userdata = task.au.userdata;
|
||||
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, nbps);
|
||||
|
||||
if (frames.push(frame, &is_closed))
|
||||
{
|
||||
frame.data = nullptr; // to prevent destruction
|
||||
cbFunc(*this, id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, cbArg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cbFunc(*this, id, CELL_ADEC_MSG_TYPE_AUDONE, task.au.auInfo_addr, cbArg);
|
||||
break;
|
||||
}
|
||||
|
||||
case adecClose:
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
throw EXCEPTION("Unknown task(%d)", task.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
is_finished = true;
|
||||
}
|
||||
};
|
||||
|
||||
int adecRead(void* opaque, u8* buf, int buf_size)
|
||||
{
|
||||
@ -171,7 +463,7 @@ next:
|
||||
buf_size -= adec.reader.size;
|
||||
res += adec.reader.size;
|
||||
|
||||
adec.cbFunc(*adec.adecCb, adec.id, CELL_ADEC_MSG_TYPE_AUDONE, adec.task.au.auInfo_addr, adec.cbArg);
|
||||
adec.cbFunc(adec, adec.id, CELL_ADEC_MSG_TYPE_AUDONE, adec.task.au.auInfo_addr, adec.cbArg);
|
||||
|
||||
adec.job.pop(adec.task);
|
||||
|
||||
@ -212,267 +504,6 @@ next:
|
||||
}
|
||||
}
|
||||
|
||||
void adecOpen(u32 adec_id) // TODO: call from the constructor
|
||||
{
|
||||
const auto sptr = idm::get<AudioDecoder>(adec_id);
|
||||
AudioDecoder& adec = *sptr;
|
||||
|
||||
adec.id = adec_id;
|
||||
|
||||
adec.adecCb = idm::make_ptr<PPUThread>(fmt::format("Demuxer[0x%x] Thread", adec_id));
|
||||
adec.adecCb->prio = 1001;
|
||||
adec.adecCb->stack_size = 0x10000;
|
||||
adec.adecCb->custom_task = [sptr](PPUThread& CPU)
|
||||
{
|
||||
AudioDecoder& adec = *sptr;
|
||||
AdecTask& task = adec.task;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (Emu.IsStopped() || adec.is_closed)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (!adec.job.pop(task, &adec.is_closed))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
switch (task.type)
|
||||
{
|
||||
case adecStartSeq:
|
||||
{
|
||||
// TODO: reset data
|
||||
cellAdec.warning("adecStartSeq:");
|
||||
|
||||
adec.reader.addr = 0;
|
||||
adec.reader.size = 0;
|
||||
adec.reader.init = false;
|
||||
adec.reader.has_ats = false;
|
||||
adec.just_started = true;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
case adecEndSeq:
|
||||
{
|
||||
// TODO: finalize
|
||||
cellAdec.warning("adecEndSeq:");
|
||||
adec.cbFunc(CPU, adec.id, CELL_ADEC_MSG_TYPE_SEQDONE, CELL_OK, adec.cbArg);
|
||||
|
||||
adec.just_finished = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case adecDecodeAu:
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
adec.reader.addr = task.au.addr;
|
||||
adec.reader.size = task.au.size;
|
||||
adec.reader.has_ats = adec.use_ats_headers;
|
||||
//LOG_NOTICE(HLE, "Audio AU: size = 0x%x, pts = 0x%llx", task.au.size, task.au.pts);
|
||||
|
||||
if (adec.just_started)
|
||||
{
|
||||
adec.first_pts = task.au.pts;
|
||||
adec.last_pts = task.au.pts;
|
||||
if (adecIsAtracX(adec.type)) adec.last_pts -= 0x10000; // hack
|
||||
}
|
||||
|
||||
struct AVPacketHolder : AVPacket
|
||||
{
|
||||
AVPacketHolder(u32 size)
|
||||
{
|
||||
av_init_packet(this);
|
||||
|
||||
if (size)
|
||||
{
|
||||
data = (u8*)av_calloc(1, size + FF_INPUT_BUFFER_PADDING_SIZE);
|
||||
this->size = size + FF_INPUT_BUFFER_PADDING_SIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
data = NULL;
|
||||
size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
~AVPacketHolder()
|
||||
{
|
||||
av_free(data);
|
||||
}
|
||||
|
||||
} au(0);
|
||||
|
||||
if (adec.just_started && adec.just_finished)
|
||||
{
|
||||
avcodec_flush_buffers(adec.ctx);
|
||||
|
||||
adec.reader.init = true; // wrong
|
||||
adec.just_finished = false;
|
||||
adec.just_started = false;
|
||||
}
|
||||
else if (adec.just_started) // deferred initialization
|
||||
{
|
||||
AVDictionary* opts = nullptr;
|
||||
av_dict_set(&opts, "probesize", "96", 0);
|
||||
err = avformat_open_input(&adec.fmt, NULL, adec.input_format, &opts);
|
||||
if (err || opts)
|
||||
{
|
||||
throw EXCEPTION("avformat_open_input() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0);
|
||||
}
|
||||
//err = avformat_find_stream_info(adec.fmt, NULL);
|
||||
//if (err || !adec.fmt->nb_streams)
|
||||
//{
|
||||
// ADEC_ERROR("adecDecodeAu: avformat_find_stream_info() failed (err=0x%x, nb_streams=%d)", err, adec.fmt->nb_streams);
|
||||
//}
|
||||
if (!avformat_new_stream(adec.fmt, adec.codec))
|
||||
{
|
||||
throw EXCEPTION("avformat_new_stream() failed");
|
||||
}
|
||||
adec.ctx = adec.fmt->streams[0]->codec; // TODO: check data
|
||||
|
||||
opts = nullptr;
|
||||
av_dict_set(&opts, "refcounted_frames", "1", 0);
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_mutex_avcodec_open2);
|
||||
// not multithread-safe (???)
|
||||
err = avcodec_open2(adec.ctx, adec.codec, &opts);
|
||||
}
|
||||
if (err || opts)
|
||||
{
|
||||
throw EXCEPTION("avcodec_open2() failed (err=0x%x, opts=%d)", err, opts ? 1 : 0);
|
||||
}
|
||||
adec.just_started = false;
|
||||
}
|
||||
|
||||
bool last_frame = false;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (Emu.IsStopped() || adec.is_closed)
|
||||
{
|
||||
if (Emu.IsStopped()) cellAdec.warning("adecDecodeAu: aborted");
|
||||
break;
|
||||
}
|
||||
|
||||
last_frame = av_read_frame(adec.fmt, &au) < 0;
|
||||
if (last_frame)
|
||||
{
|
||||
//break;
|
||||
av_free(au.data);
|
||||
au.data = NULL;
|
||||
au.size = 0;
|
||||
}
|
||||
|
||||
struct AdecFrameHolder : AdecFrame
|
||||
{
|
||||
AdecFrameHolder()
|
||||
{
|
||||
data = av_frame_alloc();
|
||||
}
|
||||
|
||||
~AdecFrameHolder()
|
||||
{
|
||||
if (data)
|
||||
{
|
||||
av_frame_unref(data);
|
||||
av_frame_free(&data);
|
||||
}
|
||||
}
|
||||
|
||||
} frame;
|
||||
|
||||
if (!frame.data)
|
||||
{
|
||||
throw EXCEPTION("av_frame_alloc() failed");
|
||||
}
|
||||
|
||||
int got_frame = 0;
|
||||
|
||||
int decode = avcodec_decode_audio4(adec.ctx, frame.data, &got_frame, &au);
|
||||
|
||||
if (decode <= 0)
|
||||
{
|
||||
if (decode < 0)
|
||||
{
|
||||
cellAdec.error("adecDecodeAu: AU decoding error(0x%x)", decode);
|
||||
}
|
||||
if (!got_frame && adec.reader.size == 0) break;
|
||||
}
|
||||
|
||||
if (got_frame)
|
||||
{
|
||||
//u64 ts = av_frame_get_best_effort_timestamp(frame.data);
|
||||
//if (ts != AV_NOPTS_VALUE)
|
||||
//{
|
||||
// frame.pts = ts/* - adec.first_pts*/;
|
||||
// adec.last_pts = frame.pts;
|
||||
//}
|
||||
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)
|
||||
{
|
||||
case AV_SAMPLE_FMT_FLTP: break;
|
||||
case AV_SAMPLE_FMT_S16P: break;
|
||||
default:
|
||||
{
|
||||
throw EXCEPTION("Unsupported frame format(%d)", frame.data->format);
|
||||
}
|
||||
}
|
||||
frame.auAddr = task.au.addr;
|
||||
frame.auSize = task.au.size;
|
||||
frame.userdata = task.au.userdata;
|
||||
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, nbps);
|
||||
|
||||
if (adec.frames.push(frame, &adec.is_closed))
|
||||
{
|
||||
frame.data = nullptr; // to prevent destruction
|
||||
adec.cbFunc(CPU, adec.id, CELL_ADEC_MSG_TYPE_PCMOUT, CELL_OK, adec.cbArg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
adec.cbFunc(CPU, adec.id, CELL_ADEC_MSG_TYPE_AUDONE, task.au.auInfo_addr, adec.cbArg);
|
||||
break;
|
||||
}
|
||||
|
||||
case adecClose:
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
throw EXCEPTION("Unknown task(%d)", task.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
adec.is_finished = true;
|
||||
|
||||
};
|
||||
|
||||
adec.adecCb->cpu_init();
|
||||
adec.adecCb->state -= cpu_state::stop;
|
||||
(*adec.adecCb)->lock_notify();
|
||||
}
|
||||
|
||||
bool adecCheckType(s32 type)
|
||||
{
|
||||
switch (type)
|
||||
@ -527,7 +558,11 @@ s32 cellAdecOpen(vm::ptr<CellAdecType> type, vm::ptr<CellAdecResource> res, vm::
|
||||
return CELL_ADEC_ERROR_ARG;
|
||||
}
|
||||
|
||||
adecOpen(*handle = idm::make<AudioDecoder>(type->audioCodecType, res->startAddr, res->totalMemSize, cb->cbFunc, cb->cbArg));
|
||||
auto&& adec = std::make_shared<AudioDecoder>(type->audioCodecType, res->startAddr, res->totalMemSize, cb->cbFunc, cb->cbArg);
|
||||
|
||||
*handle = idm::import_existing<ppu_thread>(adec);
|
||||
|
||||
adec->run();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -541,7 +576,11 @@ s32 cellAdecOpenEx(vm::ptr<CellAdecType> type, vm::ptr<CellAdecResourceEx> res,
|
||||
return CELL_ADEC_ERROR_ARG;
|
||||
}
|
||||
|
||||
adecOpen(*handle = idm::make<AudioDecoder>(type->audioCodecType, res->startAddr, res->totalMemSize, cb->cbFunc, cb->cbArg));
|
||||
auto&& adec = std::make_shared<AudioDecoder>(type->audioCodecType, res->startAddr, res->totalMemSize, cb->cbFunc, cb->cbArg);
|
||||
|
||||
*handle = idm::import_existing<ppu_thread>(adec);
|
||||
|
||||
adec->run();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -574,8 +613,7 @@ s32 cellAdecClose(u32 handle)
|
||||
std::this_thread::sleep_for(1ms); // hack
|
||||
}
|
||||
|
||||
idm::remove<PPUThread>(adec->adecCb->id);
|
||||
idm::remove<AudioDecoder>(handle);
|
||||
idm::remove<ppu_thread>(handle);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
@ -1043,7 +1043,7 @@ struct AdecTask
|
||||
|
||||
struct AdecFrame
|
||||
{
|
||||
AVFrame* data;
|
||||
struct AVFrame* data;
|
||||
u64 pts;
|
||||
u64 userdata;
|
||||
u32 auAddr;
|
||||
@ -1096,58 +1096,3 @@ struct OMAHeader // OMA Header
|
||||
};
|
||||
|
||||
CHECK_SIZE(OMAHeader, 96);
|
||||
|
||||
class AudioDecoder
|
||||
{
|
||||
public:
|
||||
squeue_t<AdecTask> 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;
|
||||
|
||||
struct AudioReader
|
||||
{
|
||||
u32 addr;
|
||||
u32 size;
|
||||
bool init;
|
||||
bool has_ats;
|
||||
|
||||
AudioReader()
|
||||
: init(false)
|
||||
{
|
||||
}
|
||||
|
||||
} reader;
|
||||
|
||||
squeue_t<AdecFrame> frames;
|
||||
|
||||
const s32 type;
|
||||
const u32 memAddr;
|
||||
const u32 memSize;
|
||||
const vm::ptr<CellAdecCbMsg> cbFunc;
|
||||
const u32 cbArg;
|
||||
u32 memBias;
|
||||
|
||||
AdecTask task;
|
||||
u64 last_pts, first_pts;
|
||||
|
||||
u32 ch_out;
|
||||
u32 ch_cfg;
|
||||
u32 frame_size;
|
||||
u32 sample_rate;
|
||||
bool use_ats_headers;
|
||||
|
||||
std::shared_ptr<PPUThread> adecCb;
|
||||
|
||||
AudioDecoder(s32 type, u32 addr, u32 size, vm::ptr<CellAdecCbMsg> func, u32 arg);
|
||||
|
||||
~AudioDecoder();
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -275,196 +275,3 @@ struct CellDmuxAuInfoEx
|
||||
CellCodecTimeStamp pts;
|
||||
CellCodecTimeStamp dts;
|
||||
};
|
||||
|
||||
/* Demuxer Thread Classes */
|
||||
|
||||
enum
|
||||
{
|
||||
/* http://dvd.sourceforge.net/dvdinfo/mpeghdrs.html */
|
||||
|
||||
PACKET_START_CODE_MASK = 0xffffff00,
|
||||
PACKET_START_CODE_PREFIX = 0x00000100,
|
||||
|
||||
PACK_START_CODE = 0x000001ba,
|
||||
SYSTEM_HEADER_START_CODE = 0x000001bb,
|
||||
PRIVATE_STREAM_1 = 0x000001bd,
|
||||
PADDING_STREAM = 0x000001be,
|
||||
PRIVATE_STREAM_2 = 0x000001bf,
|
||||
};
|
||||
|
||||
struct DemuxerStream
|
||||
{
|
||||
u32 addr;
|
||||
u32 size;
|
||||
u64 userdata;
|
||||
bool discontinuity;
|
||||
|
||||
template<typename T>
|
||||
bool get(T& out)
|
||||
{
|
||||
if (sizeof(T) > size) return false;
|
||||
|
||||
out = vm::_ref<T>(addr);
|
||||
addr += sizeof(T);
|
||||
size -= sizeof(T);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool peek(T& out, u32 shift = 0)
|
||||
{
|
||||
if (sizeof(T) + shift > size) return false;
|
||||
|
||||
out = vm::_ref<T>(addr + shift);
|
||||
return true;
|
||||
}
|
||||
|
||||
void skip(u32 count)
|
||||
{
|
||||
addr += count;
|
||||
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);
|
||||
return
|
||||
(((u64)c & 0x0e) << 29) |
|
||||
(((u64)v[0]) << 21) |
|
||||
(((u64)v[1] & 0x7e) << 15) |
|
||||
(((u64)v[2]) << 7) | ((u64)v[3] >> 1);
|
||||
}
|
||||
};
|
||||
|
||||
struct PesHeader
|
||||
{
|
||||
u64 pts;
|
||||
u64 dts;
|
||||
u8 size;
|
||||
bool has_ts;
|
||||
bool is_ok;
|
||||
|
||||
PesHeader(DemuxerStream& stream);
|
||||
};
|
||||
|
||||
class ElementaryStream;
|
||||
|
||||
enum DemuxerJobType
|
||||
{
|
||||
dmuxSetStream,
|
||||
dmuxResetStream,
|
||||
dmuxResetStreamAndWaitDone,
|
||||
dmuxEnableEs,
|
||||
dmuxDisableEs,
|
||||
dmuxResetEs,
|
||||
dmuxFlushEs,
|
||||
dmuxClose,
|
||||
};
|
||||
|
||||
struct DemuxerTask
|
||||
{
|
||||
DemuxerJobType type;
|
||||
|
||||
union
|
||||
{
|
||||
DemuxerStream stream;
|
||||
|
||||
struct
|
||||
{
|
||||
u32 es;
|
||||
u32 auInfo_ptr_addr;
|
||||
u32 auSpec_ptr_addr;
|
||||
ElementaryStream* es_ptr;
|
||||
} es;
|
||||
};
|
||||
|
||||
DemuxerTask()
|
||||
{
|
||||
}
|
||||
|
||||
DemuxerTask(DemuxerJobType type)
|
||||
: type(type)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class Demuxer
|
||||
{
|
||||
public:
|
||||
squeue_t<DemuxerTask, 32> job;
|
||||
const u32 memAddr;
|
||||
const u32 memSize;
|
||||
const vm::ptr<CellDmuxCbMsg> cbFunc;
|
||||
const u32 cbArg;
|
||||
u32 id;
|
||||
volatile bool is_finished;
|
||||
volatile bool is_closed;
|
||||
atomic_t<bool> is_running;
|
||||
atomic_t<bool> is_working;
|
||||
|
||||
std::shared_ptr<PPUThread> dmuxCb;
|
||||
|
||||
Demuxer(u32 addr, u32 size, vm::ptr<CellDmuxCbMsg> func, u32 arg)
|
||||
: is_finished(false)
|
||||
, is_closed(false)
|
||||
, is_running(false)
|
||||
, is_working(false)
|
||||
, memAddr(addr)
|
||||
, memSize(size)
|
||||
, cbFunc(func)
|
||||
, cbArg(arg)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class ElementaryStream
|
||||
{
|
||||
std::mutex m_mutex;
|
||||
|
||||
squeue_t<u32> 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
|
||||
|
||||
u32 put; // AU that is being written now
|
||||
|
||||
bool is_full(u32 space);
|
||||
|
||||
public:
|
||||
ElementaryStream(Demuxer* dmux, u32 addr, u32 size, u32 fidMajor, u32 fidMinor, u32 sup1, u32 sup2, vm::ptr<CellDmuxCbEsMsg> cbFunc, u32 cbArg, u32 spec);
|
||||
|
||||
Demuxer* dmux;
|
||||
const id_value<> id{};
|
||||
const u32 memAddr;
|
||||
const u32 memSize;
|
||||
const u32 fidMajor;
|
||||
const u32 fidMinor;
|
||||
const u32 sup1;
|
||||
const u32 sup2;
|
||||
const vm::ptr<CellDmuxCbEsMsg> cbFunc;
|
||||
const u32 cbArg;
|
||||
const u32 spec; //addr
|
||||
|
||||
std::vector<u8> raw_data; // demultiplexed data stream (managed by demuxer thread)
|
||||
size_t raw_pos; // should be <= raw_data.size()
|
||||
u64 last_dts;
|
||||
u64 last_pts;
|
||||
|
||||
void push(DemuxerStream& stream, u32 size); // called by demuxer thread (not multithread-safe)
|
||||
|
||||
bool isfull(u32 space);
|
||||
|
||||
void push_au(u32 size, u64 dts, u64 pts, u64 userdata, bool rap, u32 specific);
|
||||
|
||||
bool release();
|
||||
|
||||
bool peek(u32& out_data, bool no_ex, u32& out_spec, bool update_index);
|
||||
|
||||
void reset();
|
||||
};
|
||||
|
@ -82,7 +82,7 @@ s32 cellFontOpenFontFile(vm::ptr<CellFontLibrary> library, vm::cptr<char> fontPa
|
||||
return ret;
|
||||
}
|
||||
|
||||
s32 cellFontOpenFontset(PPUThread& ppu, vm::ptr<CellFontLibrary> library, vm::ptr<CellFontType> fontType, vm::ptr<CellFont> font)
|
||||
s32 cellFontOpenFontset(ppu_thread& ppu, vm::ptr<CellFontLibrary> library, vm::ptr<CellFontType> fontType, vm::ptr<CellFont> font)
|
||||
{
|
||||
cellFont.warning("cellFontOpenFontset(library=*0x%x, fontType=*0x%x, font=*0x%x)", library, fontType, font);
|
||||
|
||||
@ -423,7 +423,7 @@ s32 cellFontGraphicsSetFontRGBA()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontOpenFontsetOnMemory(PPUThread& ppu, vm::ptr<CellFontLibrary> library, vm::ptr<CellFontType> fontType, vm::ptr<CellFont> font)
|
||||
s32 cellFontOpenFontsetOnMemory(ppu_thread& ppu, vm::ptr<CellFontLibrary> library, vm::ptr<CellFontType> fontType, vm::ptr<CellFont> font)
|
||||
{
|
||||
cellFont.todo("cellFontOpenFontsetOnMemory(library=*0x%x, fontType=*0x%x, font=*0x%x)", library, fontType, font);
|
||||
|
||||
|
@ -8,6 +8,8 @@
|
||||
|
||||
#include "Utilities/StrUtil.h"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
logs::channel cellFs("cellFs", logs::level::notice);
|
||||
|
||||
s32 cellFsOpen(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, vm::cptr<void> arg, u64 size)
|
||||
@ -691,38 +693,58 @@ struct lv2_fs_mount_point
|
||||
std::mutex mutex;
|
||||
};
|
||||
|
||||
void fsAio(vm::ptr<CellFsAio> aio, bool write, s32 xid, fs_aio_cb_t func)
|
||||
struct fs_aio_thread : ppu_thread
|
||||
{
|
||||
cellFs.notice("FS AIO Request(%d): fd=%d, offset=0x%llx, buf=*0x%x, size=0x%llx, user_data=0x%llx", xid, aio->fd, aio->offset, aio->buf, aio->size, aio->user_data);
|
||||
using ppu_thread::ppu_thread;
|
||||
|
||||
s32 error = CELL_OK;
|
||||
u64 result = 0;
|
||||
|
||||
const auto file = idm::get<lv2_file>(aio->fd);
|
||||
|
||||
if (!file || (!write && file->flags & CELL_FS_O_WRONLY) || (write && !(file->flags & CELL_FS_O_ACCMODE)))
|
||||
virtual void cpu_task() override
|
||||
{
|
||||
error = CELL_EBADF;
|
||||
while (ppu_cmd cmd = cmd_wait())
|
||||
{
|
||||
const u32 type = cmd.arg1<u32>();
|
||||
const s32 xid = cmd.arg2<s32>();
|
||||
const ppu_cmd cmd2 = cmd_queue[cmd_queue.peek() + 1];
|
||||
const auto aio = cmd2.arg1<vm::ptr<CellFsAio>>();
|
||||
const auto func = cmd2.arg2<fs_aio_cb_t>();
|
||||
cmd_pop(1);
|
||||
|
||||
s32 error = CELL_OK;
|
||||
u64 result = 0;
|
||||
|
||||
const auto file = idm::get<lv2_file>(aio->fd);
|
||||
|
||||
if (!file || (type == 1 && file->flags & CELL_FS_O_WRONLY) || (type == 2 && !(file->flags & CELL_FS_O_ACCMODE)))
|
||||
{
|
||||
error = CELL_EBADF;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(file->mp->mutex);
|
||||
|
||||
const auto old_pos = file->file.pos(); file->file.seek(aio->offset);
|
||||
|
||||
result = type == 2
|
||||
? file->op_write(aio->buf, aio->size)
|
||||
: file->op_read(aio->buf, aio->size);
|
||||
|
||||
file->file.seek(old_pos);
|
||||
}
|
||||
|
||||
func(*this, aio, error, xid, result);
|
||||
}
|
||||
}
|
||||
else
|
||||
};
|
||||
|
||||
struct fs_aio_manager
|
||||
{
|
||||
std::shared_ptr<fs_aio_thread> t = std::make_shared<fs_aio_thread>("FS AIO Thread", 500);
|
||||
|
||||
fs_aio_manager()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(file->mp->mutex);
|
||||
|
||||
const auto old_pos = file->file.pos(); file->file.seek(aio->offset);
|
||||
|
||||
result = write
|
||||
? file->op_write(aio->buf, aio->size)
|
||||
: file->op_read(aio->buf, aio->size);
|
||||
|
||||
file->file.seek(old_pos);
|
||||
idm::import_existing<ppu_thread>(t);
|
||||
t->run();
|
||||
}
|
||||
|
||||
// should be executed directly by FS AIO thread
|
||||
Emu.GetCallbackManager().Async([=](PPUThread& ppu)
|
||||
{
|
||||
func(ppu, aio, error, xid, result);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
s32 cellFsAioInit(vm::cptr<char> mount_point)
|
||||
{
|
||||
@ -730,6 +752,7 @@ s32 cellFsAioInit(vm::cptr<char> mount_point)
|
||||
cellFs.warning("*** mount_point = '%s'", mount_point.get_ptr());
|
||||
|
||||
// TODO: create AIO thread (if not exists) for specified mount point
|
||||
fxm::get_always<fs_aio_manager>();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -754,7 +777,15 @@ s32 cellFsAioRead(vm::ptr<CellFsAio> aio, vm::ptr<s32> id, fs_aio_cb_t func)
|
||||
|
||||
const s32 xid = (*id = ++g_fs_aio_id);
|
||||
|
||||
thread_ctrl::spawn("FS AIO Read Thread", COPY_EXPR(fsAio(aio, false, xid, func)));
|
||||
const auto m = fxm::get_always<fs_aio_manager>();
|
||||
|
||||
m->t->cmd_list
|
||||
({
|
||||
{ 1, xid },
|
||||
{ aio, func },
|
||||
});
|
||||
|
||||
m->t->lock_notify();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -767,14 +798,22 @@ s32 cellFsAioWrite(vm::ptr<CellFsAio> aio, vm::ptr<s32> id, fs_aio_cb_t func)
|
||||
|
||||
const s32 xid = (*id = ++g_fs_aio_id);
|
||||
|
||||
thread_ctrl::spawn("FS AIO Write Thread", COPY_EXPR(fsAio(aio, true, xid, func)));
|
||||
const auto m = fxm::get_always<fs_aio_manager>();
|
||||
|
||||
m->t->cmd_list
|
||||
({
|
||||
{ 2, xid },
|
||||
{ aio, func },
|
||||
});
|
||||
|
||||
m->t->lock_notify();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFsAioCancel(s32 id)
|
||||
{
|
||||
cellFs.warning("cellFsAioCancel(id=%d) -> CELL_EINVAL", id);
|
||||
cellFs.todo("cellFsAioCancel(id=%d) -> CELL_EINVAL", id);
|
||||
|
||||
// TODO: cancelled requests return CELL_ECANCELED through their own callbacks
|
||||
|
||||
|
@ -50,7 +50,7 @@ struct content_permission final
|
||||
}
|
||||
};
|
||||
|
||||
s32 cellHddGameCheck(PPUThread& ppu, u32 version, vm::cptr<char> dirName, u32 errDialog, vm::ptr<CellHddGameStatCallback> funcStat, u32 container)
|
||||
s32 cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr<char> dirName, u32 errDialog, vm::ptr<CellHddGameStatCallback> funcStat, u32 container)
|
||||
{
|
||||
cellGame.error("cellHddGameCheck(version=%d, dirName=*0x%x, errDialog=%d, funcStat=*0x%x, container=%d)", version, dirName, errDialog, funcStat, container);
|
||||
|
||||
@ -332,7 +332,7 @@ ppu_error_code cellGameContentPermit(vm::ptr<char[CELL_GAME_PATH_MAX]> contentIn
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
ppu_error_code cellGameDataCheckCreate2(PPUThread& ppu, u32 version, vm::cptr<char> dirName, u32 errDialog, vm::ptr<CellGameDataStatCallback> funcStat, u32 container)
|
||||
ppu_error_code cellGameDataCheckCreate2(ppu_thread& ppu, u32 version, vm::cptr<char> dirName, u32 errDialog, vm::ptr<CellGameDataStatCallback> funcStat, u32 container)
|
||||
{
|
||||
cellGame.error("cellGameDataCheckCreate2(version=0x%x, dirName=*0x%x, errDialog=0x%x, funcStat=*0x%x, container=%d)", version, dirName, errDialog, funcStat, container);
|
||||
|
||||
@ -420,7 +420,7 @@ ppu_error_code cellGameDataCheckCreate2(PPUThread& ppu, u32 version, vm::cptr<ch
|
||||
}
|
||||
}
|
||||
|
||||
s32 cellGameDataCheckCreate(PPUThread& ppu, u32 version, vm::cptr<char> dirName, u32 errDialog, vm::ptr<CellGameDataStatCallback> funcStat, u32 container)
|
||||
s32 cellGameDataCheckCreate(ppu_thread& ppu, u32 version, vm::cptr<char> dirName, u32 errDialog, vm::ptr<CellGameDataStatCallback> funcStat, u32 container)
|
||||
{
|
||||
cellGame.warning("cellGameDataCheckCreate(version=0x%x, dirName=*0x%x, errDialog=0x%x, funcStat=*0x%x, container=%d)", version, dirName, errDialog, funcStat, container);
|
||||
|
||||
|
@ -396,6 +396,8 @@ s32 _cellGcmInitBody(vm::pptr<CellGcmContextData> context, u32 cmdSize, u32 ioSi
|
||||
ctrl.ref = -1;
|
||||
|
||||
const auto render = fxm::get<GSRender>();
|
||||
render->intr_thread = idm::make_ptr<ppu_thread>("_gcm_intr_thread", 1, 0x4000);
|
||||
render->intr_thread->run();
|
||||
render->ctxt_addr = context.addr();
|
||||
render->gcm_buffers.set(vm::alloc(sizeof(CellGcmDisplayInfo) * 8, vm::main));
|
||||
render->zculls_addr = vm::alloc(sizeof(CellGcmZcullInfo) * 8, vm::main);
|
||||
@ -496,7 +498,7 @@ void cellGcmSetFlipStatus()
|
||||
fxm::get<GSRender>()->flip_status = 0;
|
||||
}
|
||||
|
||||
s32 cellGcmSetPrepareFlip(PPUThread& ppu, vm::ptr<CellGcmContextData> ctxt, u32 id)
|
||||
s32 cellGcmSetPrepareFlip(ppu_thread& ppu, vm::ptr<CellGcmContextData> ctxt, u32 id)
|
||||
{
|
||||
cellGcmSys.trace("cellGcmSetPrepareFlip(ctx=*0x%x, id=0x%x)", ctxt, id);
|
||||
|
||||
@ -525,7 +527,7 @@ s32 cellGcmSetPrepareFlip(PPUThread& ppu, vm::ptr<CellGcmContextData> ctxt, u32
|
||||
return id;
|
||||
}
|
||||
|
||||
s32 cellGcmSetFlip(PPUThread& ppu, vm::ptr<CellGcmContextData> ctxt, u32 id)
|
||||
s32 cellGcmSetFlip(ppu_thread& ppu, vm::ptr<CellGcmContextData> ctxt, u32 id)
|
||||
{
|
||||
cellGcmSys.trace("cellGcmSetFlip(ctxt=*0x%x, id=0x%x)", ctxt, id);
|
||||
|
||||
@ -1141,14 +1143,14 @@ s32 cellGcmSetDefaultCommandBufferAndSegmentWordSize()
|
||||
// Other
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
s32 _cellGcmSetFlipCommand(PPUThread& ppu, vm::ptr<CellGcmContextData> ctx, u32 id)
|
||||
s32 _cellGcmSetFlipCommand(ppu_thread& ppu, vm::ptr<CellGcmContextData> ctx, u32 id)
|
||||
{
|
||||
cellGcmSys.trace("cellGcmSetFlipCommand(ctx=*0x%x, id=0x%x)", ctx, id);
|
||||
|
||||
return cellGcmSetPrepareFlip(ppu, ctx, id);
|
||||
}
|
||||
|
||||
s32 _cellGcmSetFlipCommandWithWaitLabel(PPUThread& ppu, vm::ptr<CellGcmContextData> ctx, u32 id, u32 label_index, u32 label_value)
|
||||
s32 _cellGcmSetFlipCommandWithWaitLabel(ppu_thread& ppu, vm::ptr<CellGcmContextData> ctx, u32 id, u32 label_index, u32 label_value)
|
||||
{
|
||||
cellGcmSys.trace("cellGcmSetFlipCommandWithWaitLabel(ctx=*0x%x, id=0x%x, label_index=0x%x, label_value=0x%x)", ctx, id, label_index, label_value);
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
typedef int HostCode;
|
||||
#else
|
||||
#include <iconv.h>
|
||||
#include <errno.h>
|
||||
typedef const char *HostCode;
|
||||
#endif
|
||||
|
||||
|
@ -92,7 +92,7 @@ s32 cellMsgDialogOpen2(u32 type, vm::cptr<char> msgString, vm::ptr<CellMsgDialog
|
||||
{
|
||||
if (callback)
|
||||
{
|
||||
Emu.GetCallbackManager().Register([=](PPUThread& ppu) -> s32
|
||||
sysutil_register_cb([=](ppu_thread& ppu) -> s32
|
||||
{
|
||||
callback(ppu, status, userData);
|
||||
return CELL_OK;
|
||||
@ -121,7 +121,7 @@ s32 cellMsgDialogOpen2(u32 type, vm::cptr<char> msgString, vm::ptr<CellMsgDialog
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellMsgDialogOpenErrorCode(PPUThread& ppu, u32 errorCode, vm::ptr<CellMsgDialogCallback> callback, vm::ptr<void> userData, vm::ptr<void> extParam)
|
||||
s32 cellMsgDialogOpenErrorCode(ppu_thread& ppu, u32 errorCode, vm::ptr<CellMsgDialogCallback> callback, vm::ptr<void> userData, vm::ptr<void> extParam)
|
||||
{
|
||||
cellSysutil.warning("cellMsgDialogOpenErrorCode(errorCode=0x%x, callback=*0x%x, userData=*0x%x, extParam=*0x%x)", errorCode, callback, userData, extParam);
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
|
||||
#include "cellMusic.h"
|
||||
#include "cellSysutil.h"
|
||||
|
||||
logs::channel cellMusic("cellMusic", logs::level::notice);
|
||||
|
||||
@ -122,7 +123,7 @@ s32 cellMusicInitialize2(s32 mode, s32 spuPriority, vm::ptr<CellMusic2Callback>
|
||||
music->func = func;
|
||||
music->userData = userData;
|
||||
|
||||
Emu.GetCallbackManager().Register([=](PPUThread& ppu) -> s32
|
||||
sysutil_register_cb([=](ppu_thread& ppu) -> s32
|
||||
{
|
||||
func(ppu, CELL_MUSIC2_EVENT_INITIALIZE_RESULT, vm::make_var<s32>(CELL_OK), userData);
|
||||
return CELL_OK;
|
||||
|
@ -101,8 +101,8 @@ s32 cellNetCtlNetStartDialogLoadAsync(vm::ptr<CellNetCtlNetStartDialogParam> par
|
||||
|
||||
// TODO: Actually sign into PSN or an emulated network similar to PSN (ESN)
|
||||
// TODO: Properly open the dialog prompt for sign in
|
||||
sysutilSendSystemCommand(CELL_SYSUTIL_NET_CTL_NETSTART_LOADED, 0);
|
||||
sysutilSendSystemCommand(CELL_SYSUTIL_NET_CTL_NETSTART_FINISHED, 0);
|
||||
sysutil_send_system_cmd(CELL_SYSUTIL_NET_CTL_NETSTART_LOADED, 0);
|
||||
sysutil_send_system_cmd(CELL_SYSUTIL_NET_CTL_NETSTART_FINISHED, 0);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -119,7 +119,7 @@ s32 cellNetCtlNetStartDialogUnloadAsync(vm::ptr<CellNetCtlNetStartDialogResult>
|
||||
cellNetCtl.warning("cellNetCtlNetStartDialogUnloadAsync(result=*0x%x)", result);
|
||||
|
||||
result->result = CELL_NET_CTL_ERROR_DIALOG_CANCELED;
|
||||
sysutilSendSystemCommand(CELL_SYSUTIL_NET_CTL_NETSTART_UNLOADED, 0);
|
||||
sysutil_send_system_cmd(CELL_SYSUTIL_NET_CTL_NETSTART_UNLOADED, 0);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
@ -244,7 +244,7 @@ be_t<u32> pngDecGetChunkInformation(PStream stream, bool IDAT = false)
|
||||
return chunk_information;
|
||||
}
|
||||
|
||||
s32 pngDecCreate(PPUThread& ppu, PPHandle png_handle, PThreadInParam thread_in_param, PThreadOutParam thread_out_param, PExtThreadInParam extra_thread_in_param = vm::null, PExtThreadOutParam extra_thread_out_param = vm::null)
|
||||
s32 pngDecCreate(ppu_thread& ppu, PPHandle png_handle, PThreadInParam thread_in_param, PThreadOutParam thread_out_param, PExtThreadInParam extra_thread_in_param = vm::null, PExtThreadOutParam extra_thread_out_param = vm::null)
|
||||
{
|
||||
// Check if partial image decoding is used
|
||||
if (extra_thread_out_param)
|
||||
@ -277,7 +277,7 @@ s32 pngDecCreate(PPUThread& ppu, PPHandle png_handle, PThreadInParam thread_in_p
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 pngDecDestroy(PPUThread& ppu, PHandle handle)
|
||||
s32 pngDecDestroy(ppu_thread& ppu, PHandle handle)
|
||||
{
|
||||
// Deallocate the decoder handle memory
|
||||
if (handle->free(ppu, handle, handle->free_arg) != 0)
|
||||
@ -289,7 +289,7 @@ s32 pngDecDestroy(PPUThread& ppu, PHandle handle)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 pngDecOpen(PPUThread& ppu, PHandle handle, PPStream png_stream, PSrc source, POpenInfo open_info, PCbControlStream control_stream = vm::null, POpenParam open_param = vm::null)
|
||||
s32 pngDecOpen(ppu_thread& ppu, PHandle handle, PPStream png_stream, PSrc source, POpenInfo open_info, PCbControlStream control_stream = vm::null, POpenParam open_param = vm::null)
|
||||
{
|
||||
// Check if partial image decoding is used
|
||||
if (control_stream || open_param)
|
||||
@ -442,7 +442,7 @@ s32 pngDecOpen(PPUThread& ppu, PHandle handle, PPStream png_stream, PSrc source,
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 pngDecClose(PPUThread& ppu, PHandle handle, PStream stream)
|
||||
s32 pngDecClose(ppu_thread& ppu, PHandle handle, PStream stream)
|
||||
{
|
||||
// Remove the file descriptor, if a file descriptor was used for decoding
|
||||
if (stream->buffer->file)
|
||||
@ -555,7 +555,7 @@ s32 pngDecSetParameter(PStream stream, PInParam in_param, POutParam out_param, P
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 pngDecodeData(PPUThread& ppu, PHandle handle, PStream stream, vm::ptr<u8> data, PDataControlParam data_control_param, PDataOutInfo data_out_info, PCbControlDisp cb_control_disp = vm::null, PDispParam disp_param = vm::null)
|
||||
s32 pngDecodeData(ppu_thread& ppu, PHandle handle, PStream stream, vm::ptr<u8> data, PDataControlParam data_control_param, PDataOutInfo data_out_info, PCbControlDisp cb_control_disp = vm::null, PDispParam disp_param = vm::null)
|
||||
{
|
||||
if (cb_control_disp || disp_param)
|
||||
{
|
||||
@ -703,37 +703,37 @@ s32 pngDecodeData(PPUThread& ppu, PHandle handle, PStream stream, vm::ptr<u8> da
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellPngDecCreate(PPUThread& ppu, PPHandle handle, PThreadInParam threadInParam, PThreadOutParam threadOutParam)
|
||||
s32 cellPngDecCreate(ppu_thread& ppu, PPHandle handle, PThreadInParam threadInParam, PThreadOutParam threadOutParam)
|
||||
{
|
||||
cellPngDec.warning("cellPngDecCreate(handle=**0x%x, threadInParam=*0x%x, threadOutParam=*0x%x)", handle, threadInParam, threadOutParam);
|
||||
return pngDecCreate(ppu, handle, threadInParam, threadOutParam);
|
||||
}
|
||||
|
||||
s32 cellPngDecExtCreate(PPUThread& ppu, PPHandle handle, PThreadInParam threadInParam, PThreadOutParam threadOutParam, PExtThreadInParam extThreadInParam, PExtThreadOutParam extThreadOutParam)
|
||||
s32 cellPngDecExtCreate(ppu_thread& ppu, PPHandle handle, PThreadInParam threadInParam, PThreadOutParam threadOutParam, PExtThreadInParam extThreadInParam, PExtThreadOutParam extThreadOutParam)
|
||||
{
|
||||
cellPngDec.warning("cellPngDecCreate(mainHandle=**0x%x, threadInParam=*0x%x, threadOutParam=*0x%x, extThreadInParam=*0x%x, extThreadOutParam=*0x%x)", handle, threadInParam, threadOutParam, extThreadInParam, extThreadOutParam);
|
||||
return pngDecCreate(ppu, handle, threadInParam, threadOutParam, extThreadInParam, extThreadOutParam);
|
||||
}
|
||||
|
||||
s32 cellPngDecDestroy(PPUThread& ppu, PHandle handle)
|
||||
s32 cellPngDecDestroy(ppu_thread& ppu, PHandle handle)
|
||||
{
|
||||
cellPngDec.warning("cellPngDecDestroy(mainHandle=*0x%x)", handle);
|
||||
return pngDecDestroy(ppu, handle);
|
||||
}
|
||||
|
||||
s32 cellPngDecOpen(PPUThread& ppu, PHandle handle, PPStream stream, PSrc src, POpenInfo openInfo)
|
||||
s32 cellPngDecOpen(ppu_thread& ppu, PHandle handle, PPStream stream, PSrc src, POpenInfo openInfo)
|
||||
{
|
||||
cellPngDec.warning("cellPngDecOpen(handle=*0x%x, stream=**0x%x, src=*0x%x, openInfo=*0x%x)", handle, stream, src, openInfo);
|
||||
return pngDecOpen(ppu, handle, stream, src, openInfo);
|
||||
}
|
||||
|
||||
s32 cellPngDecExtOpen(PPUThread& ppu, PHandle handle, PPStream stream, PSrc src, POpenInfo openInfo, PCbControlStream cbCtrlStrm, POpenParam opnParam)
|
||||
s32 cellPngDecExtOpen(ppu_thread& ppu, PHandle handle, PPStream stream, PSrc src, POpenInfo openInfo, PCbControlStream cbCtrlStrm, POpenParam opnParam)
|
||||
{
|
||||
cellPngDec.warning("cellPngDecExtOpen(handle=*0x%x, stream=**0x%x, src=*0x%x, openInfo=*0x%x, cbCtrlStrm=*0x%x, opnParam=*0x%x)", handle, stream, src, openInfo, cbCtrlStrm, opnParam);
|
||||
return pngDecOpen(ppu, handle, stream, src, openInfo, cbCtrlStrm, opnParam);
|
||||
}
|
||||
|
||||
s32 cellPngDecClose(PPUThread& ppu, PHandle handle, PStream stream)
|
||||
s32 cellPngDecClose(ppu_thread& ppu, PHandle handle, PStream stream)
|
||||
{
|
||||
cellPngDec.warning("cellPngDecClose(handle=*0x%x, stream=*0x%x)", handle, stream);
|
||||
return pngDecClose(ppu, handle, stream);
|
||||
@ -763,13 +763,13 @@ s32 cellPngDecExtSetParameter(PHandle handle, PStream stream, PInParam inParam,
|
||||
return pngDecSetParameter(stream, inParam, outParam, extInParam, extOutParam);
|
||||
}
|
||||
|
||||
s32 cellPngDecDecodeData(PPUThread& ppu, PHandle handle, PStream stream, vm::ptr<u8> data, PDataControlParam dataCtrlParam, PDataOutInfo dataOutInfo)
|
||||
s32 cellPngDecDecodeData(ppu_thread& ppu, PHandle handle, PStream stream, vm::ptr<u8> data, PDataControlParam dataCtrlParam, PDataOutInfo dataOutInfo)
|
||||
{
|
||||
cellPngDec.warning("cellPngDecDecodeData(handle=*0x%x, stream=*0x%x, data=*0x%x, dataCtrlParam=*0x%x, dataOutInfo=*0x%x)", handle, stream, data, dataCtrlParam, dataOutInfo);
|
||||
return pngDecodeData(ppu, handle, stream, data, dataCtrlParam, dataOutInfo);
|
||||
}
|
||||
|
||||
s32 cellPngDecExtDecodeData(PPUThread& ppu, PHandle handle, PStream stream, vm::ptr<u8> data, PDataControlParam dataCtrlParam, PDataOutInfo dataOutInfo, PCbControlDisp cbCtrlDisp, PDispParam dispParam)
|
||||
s32 cellPngDecExtDecodeData(ppu_thread& ppu, PHandle handle, PStream stream, vm::ptr<u8> data, PDataControlParam dataCtrlParam, PDataOutInfo dataOutInfo, PCbControlDisp cbCtrlDisp, PDispParam dispParam)
|
||||
{
|
||||
cellPngDec.warning("cellPngDecExtDecodeData(handle=*0x%x, stream=*0x%x, data=*0x%x, dataCtrlParam=*0x%x, dataOutInfo=*0x%x, cbCtrlDisp=*0x%x, dispParam=*0x%x)", handle, stream, data, dataCtrlParam, dataOutInfo, cbCtrlDisp, dispParam);
|
||||
return pngDecodeData(ppu, handle, stream, data, dataCtrlParam, dataOutInfo, cbCtrlDisp, dispParam);
|
||||
|
@ -83,7 +83,7 @@ s32 cellRescSetSrc(s32 idx, vm::ptr<CellRescSrc> src)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellRescSetConvertAndFlip(PPUThread& ppu, vm::ptr<CellGcmContextData> cntxt, s32 idx)
|
||||
s32 cellRescSetConvertAndFlip(ppu_thread& ppu, vm::ptr<CellGcmContextData> cntxt, s32 idx)
|
||||
{
|
||||
cellResc.todo("cellRescSetConvertAndFlip(cntxt=*0x%x, idx=0x%x)", cntxt, idx);
|
||||
|
||||
|
@ -10,8 +10,8 @@ logs::channel cellRudp("cellRudp", logs::level::notice);
|
||||
struct rudp_t
|
||||
{
|
||||
// allocator functions
|
||||
std::function<vm::ptr<void>(PPUThread& ppu, u32 size)> malloc;
|
||||
std::function<void(PPUThread& ppu, vm::ptr<void> ptr)> free;
|
||||
std::function<vm::ptr<void>(ppu_thread& ppu, u32 size)> malloc;
|
||||
std::function<void(ppu_thread& ppu, vm::ptr<void> ptr)> free;
|
||||
|
||||
// event handler function
|
||||
vm::ptr<CellRudpEventHandler> handler = vm::null;
|
||||
@ -36,12 +36,12 @@ s32 cellRudpInit(vm::ptr<CellRudpAllocator> allocator)
|
||||
}
|
||||
else
|
||||
{
|
||||
rudp->malloc = [](PPUThread& ppu, u32 size)
|
||||
rudp->malloc = [](ppu_thread& ppu, u32 size)
|
||||
{
|
||||
return vm::ptr<void>::make(vm::alloc(size, vm::main));
|
||||
};
|
||||
|
||||
rudp->free = [](PPUThread& ppu, vm::ptr<void> ptr)
|
||||
rudp->free = [](ppu_thread& ppu, vm::ptr<void> ptr)
|
||||
{
|
||||
if (!vm::dealloc(ptr.addr(), vm::main))
|
||||
{
|
||||
|
@ -7,28 +7,6 @@
|
||||
|
||||
logs::channel cellSail("cellSail", logs::level::notice);
|
||||
|
||||
void playerBoot(vm::ptr<CellSailPlayer> pSelf, u64 userParam)
|
||||
{
|
||||
Emu.GetCallbackManager().Async([=](PPUThread& ppu)
|
||||
{
|
||||
CellSailEvent event;
|
||||
event.u32x2.major = CELL_SAIL_EVENT_PLAYER_STATE_CHANGED;
|
||||
event.u32x2.minor = 0;
|
||||
pSelf->callback(ppu, pSelf->callbackArg, event, CELL_SAIL_PLAYER_STATE_BOOT_TRANSITION, 0);
|
||||
});
|
||||
|
||||
// TODO: Do stuff here
|
||||
pSelf->booted = true;
|
||||
|
||||
Emu.GetCallbackManager().Async([=](PPUThread& ppu)
|
||||
{
|
||||
CellSailEvent event;
|
||||
event.u32x2.major = CELL_SAIL_EVENT_PLAYER_CALL_COMPLETED;
|
||||
event.u32x2.minor = CELL_SAIL_PLAYER_CALL_BOOT;
|
||||
pSelf->callback(ppu, pSelf->callbackArg, event, 0, 0);
|
||||
});
|
||||
}
|
||||
|
||||
s32 cellSailMemAllocatorInitialize(vm::ptr<CellSailMemAllocator> pSelf, vm::ptr<CellSailMemAllocatorFuncs> pCallbacks)
|
||||
{
|
||||
cellSail.warning("cellSailMemAllocatorInitialize(pSelf=*0x%x, pCallbacks=*0x%x)", pSelf, pCallbacks);
|
||||
@ -611,7 +589,7 @@ s32 cellSailPlayerInitialize()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSailPlayerInitialize2(
|
||||
s32 cellSailPlayerInitialize2(ppu_thread& ppu,
|
||||
vm::ptr<CellSailPlayer> pSelf,
|
||||
vm::ptr<CellSailMemAllocator> pAllocator,
|
||||
vm::ptr<CellSailPlayerFuncNotified> pCallback,
|
||||
@ -630,13 +608,12 @@ s32 cellSailPlayerInitialize2(
|
||||
pSelf->booted = false;
|
||||
pSelf->paused = true;
|
||||
|
||||
Emu.GetCallbackManager().Async([=](PPUThread& ppu)
|
||||
{
|
||||
CellSailEvent event;
|
||||
event.u32x2.major = CELL_SAIL_EVENT_PLAYER_STATE_CHANGED;
|
||||
event.u32x2.minor = 0;
|
||||
pSelf->callback(ppu, pSelf->callbackArg, event, CELL_SAIL_PLAYER_STATE_INITIALIZED, 0);
|
||||
});
|
||||
};
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -765,11 +742,26 @@ s32 cellSailPlayerReplaceEventHandler()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSailPlayerBoot(PPUThread& ppu, vm::ptr<CellSailPlayer> pSelf, u64 userParam)
|
||||
s32 cellSailPlayerBoot(ppu_thread& ppu, vm::ptr<CellSailPlayer> pSelf, u64 userParam)
|
||||
{
|
||||
cellSail.warning("cellSailPlayerBoot(pSelf=*0x%x, userParam=%d)", pSelf, userParam);
|
||||
|
||||
playerBoot(pSelf, userParam);
|
||||
{
|
||||
CellSailEvent event;
|
||||
event.u32x2.major = CELL_SAIL_EVENT_PLAYER_STATE_CHANGED;
|
||||
event.u32x2.minor = 0;
|
||||
pSelf->callback(ppu, pSelf->callbackArg, event, CELL_SAIL_PLAYER_STATE_BOOT_TRANSITION, 0);
|
||||
};
|
||||
|
||||
// TODO: Do stuff here
|
||||
pSelf->booted = true;
|
||||
|
||||
{
|
||||
CellSailEvent event;
|
||||
event.u32x2.major = CELL_SAIL_EVENT_PLAYER_CALL_COMPLETED;
|
||||
event.u32x2.minor = CELL_SAIL_PLAYER_CALL_BOOT;
|
||||
pSelf->callback(ppu, pSelf->callbackArg, event, 0, 0);
|
||||
};
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "Loader/PSF.h"
|
||||
#include "Utilities/StrUtil.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <algorithm>
|
||||
|
||||
logs::channel cellSaveData("cellSaveData", logs::level::notice);
|
||||
@ -36,7 +37,7 @@ enum : u32
|
||||
|
||||
std::mutex g_savedata_mutex;
|
||||
|
||||
static never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version, vm::cptr<char> dirName,
|
||||
static never_inline s32 savedata_op(ppu_thread& ppu, u32 operation, u32 version, vm::cptr<char> dirName,
|
||||
u32 errDialog, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncFixed funcFixed, PFuncStat funcStat,
|
||||
PFuncFile funcFile, u32 container, u32 unknown, vm::ptr<void> userdata, u32 userId, PFuncDone funcDone)
|
||||
{
|
||||
@ -618,7 +619,7 @@ static never_inline s32 savedata_op(PPUThread& ppu, u32 operation, u32 version,
|
||||
}
|
||||
|
||||
// Functions
|
||||
s32 cellSaveDataListSave2(PPUThread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncList funcList,
|
||||
s32 cellSaveDataListSave2(ppu_thread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncList funcList,
|
||||
PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr<void> userdata)
|
||||
{
|
||||
cellSaveData.warning("cellSaveDataListSave2(version=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)",
|
||||
@ -627,7 +628,7 @@ s32 cellSaveDataListSave2(PPUThread& ppu, u32 version, PSetList setList, PSetBuf
|
||||
return savedata_op(ppu, SAVEDATA_OP_LIST_SAVE, version, vm::null, 1, setList, setBuf, funcList, vm::null, funcStat, funcFile, container, 2, userdata, 0, vm::null);
|
||||
}
|
||||
|
||||
s32 cellSaveDataListLoad2(PPUThread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncList funcList,
|
||||
s32 cellSaveDataListLoad2(ppu_thread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncList funcList,
|
||||
PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr<void> userdata)
|
||||
{
|
||||
cellSaveData.warning("cellSaveDataListLoad2(version=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)",
|
||||
@ -636,7 +637,7 @@ s32 cellSaveDataListLoad2(PPUThread& ppu, u32 version, PSetList setList, PSetBuf
|
||||
return savedata_op(ppu, SAVEDATA_OP_LIST_LOAD, version, vm::null, 1, setList, setBuf, funcList, vm::null, funcStat, funcFile, container, 2, userdata, 0, vm::null);
|
||||
}
|
||||
|
||||
s32 cellSaveDataListSave(PPUThread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncList funcList,
|
||||
s32 cellSaveDataListSave(ppu_thread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncList funcList,
|
||||
PFuncStat funcStat, PFuncFile funcFile, u32 container)
|
||||
{
|
||||
cellSaveData.warning("cellSaveDataListSave(version=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)",
|
||||
@ -645,7 +646,7 @@ s32 cellSaveDataListSave(PPUThread& ppu, u32 version, PSetList setList, PSetBuf
|
||||
return savedata_op(ppu, SAVEDATA_OP_LIST_SAVE, version, vm::null, 1, setList, setBuf, funcList, vm::null, funcStat, funcFile, container, 2, vm::null, 0, vm::null);
|
||||
}
|
||||
|
||||
s32 cellSaveDataListLoad(PPUThread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncList funcList,
|
||||
s32 cellSaveDataListLoad(ppu_thread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncList funcList,
|
||||
PFuncStat funcStat, PFuncFile funcFile, u32 container)
|
||||
{
|
||||
cellSaveData.warning("cellSaveDataListLoad(version=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)",
|
||||
@ -655,7 +656,7 @@ s32 cellSaveDataListLoad(PPUThread& ppu, u32 version, PSetList setList, PSetBuf
|
||||
|
||||
}
|
||||
|
||||
s32 cellSaveDataFixedSave2(PPUThread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed,
|
||||
s32 cellSaveDataFixedSave2(ppu_thread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed,
|
||||
PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr<void> userdata)
|
||||
{
|
||||
cellSaveData.warning("cellSaveDataFixedSave2(version=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)",
|
||||
@ -664,7 +665,7 @@ s32 cellSaveDataFixedSave2(PPUThread& ppu, u32 version, PSetList setList, PSetBu
|
||||
return savedata_op(ppu, SAVEDATA_OP_FIXED_SAVE, version, vm::null, 1, setList, setBuf, vm::null, funcFixed, funcStat, funcFile, container, 2, userdata, 0, vm::null);
|
||||
}
|
||||
|
||||
s32 cellSaveDataFixedLoad2(PPUThread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed,
|
||||
s32 cellSaveDataFixedLoad2(ppu_thread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed,
|
||||
PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr<void> userdata)
|
||||
{
|
||||
cellSaveData.warning("cellSaveDataFixedLoad2(version=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)",
|
||||
@ -673,7 +674,7 @@ s32 cellSaveDataFixedLoad2(PPUThread& ppu, u32 version, PSetList setList, PSetBu
|
||||
return savedata_op(ppu, SAVEDATA_OP_FIXED_LOAD, version, vm::null, 1, setList, setBuf, vm::null, funcFixed, funcStat, funcFile, container, 2, userdata, 0, vm::null);
|
||||
}
|
||||
|
||||
s32 cellSaveDataFixedSave(PPUThread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed,
|
||||
s32 cellSaveDataFixedSave(ppu_thread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed,
|
||||
PFuncStat funcStat, PFuncFile funcFile, u32 container)
|
||||
{
|
||||
cellSaveData.warning("cellSaveDataFixedSave(version=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)",
|
||||
@ -683,7 +684,7 @@ s32 cellSaveDataFixedSave(PPUThread& ppu, u32 version, PSetList setList, PSetBuf
|
||||
|
||||
}
|
||||
|
||||
s32 cellSaveDataFixedLoad(PPUThread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed,
|
||||
s32 cellSaveDataFixedLoad(ppu_thread& ppu, u32 version, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed,
|
||||
PFuncStat funcStat, PFuncFile funcFile, u32 container)
|
||||
{
|
||||
cellSaveData.warning("cellSaveDataFixedLoad(version=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)",
|
||||
@ -692,7 +693,7 @@ s32 cellSaveDataFixedLoad(PPUThread& ppu, u32 version, PSetList setList, PSetBuf
|
||||
return savedata_op(ppu, SAVEDATA_OP_FIXED_LOAD, version, vm::null, 1, setList, setBuf, vm::null, funcFixed, funcStat, funcFile, container, 2, vm::null, 0, vm::null);
|
||||
}
|
||||
|
||||
s32 cellSaveDataAutoSave2(PPUThread& ppu, u32 version, vm::cptr<char> dirName, u32 errDialog, PSetBuf setBuf,
|
||||
s32 cellSaveDataAutoSave2(ppu_thread& ppu, u32 version, vm::cptr<char> dirName, u32 errDialog, PSetBuf setBuf,
|
||||
PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr<void> userdata)
|
||||
{
|
||||
cellSaveData.warning("cellSaveDataAutoSave2(version=%d, dirName=*0x%x, errDialog=%d, setBuf=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)",
|
||||
@ -701,7 +702,7 @@ s32 cellSaveDataAutoSave2(PPUThread& ppu, u32 version, vm::cptr<char> dirName, u
|
||||
return savedata_op(ppu, SAVEDATA_OP_AUTO_SAVE, version, dirName, errDialog, vm::null, setBuf, vm::null, vm::null, funcStat, funcFile, container, 2, userdata, 0, vm::null);
|
||||
}
|
||||
|
||||
s32 cellSaveDataAutoLoad2(PPUThread& ppu, u32 version, vm::cptr<char> dirName, u32 errDialog, PSetBuf setBuf,
|
||||
s32 cellSaveDataAutoLoad2(ppu_thread& ppu, u32 version, vm::cptr<char> dirName, u32 errDialog, PSetBuf setBuf,
|
||||
PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr<void> userdata)
|
||||
{
|
||||
cellSaveData.warning("cellSaveDataAutoLoad2(version=%d, dirName=*0x%x, errDialog=%d, setBuf=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)",
|
||||
@ -710,7 +711,7 @@ s32 cellSaveDataAutoLoad2(PPUThread& ppu, u32 version, vm::cptr<char> dirName, u
|
||||
return savedata_op(ppu, SAVEDATA_OP_AUTO_LOAD, version, dirName, errDialog, vm::null, setBuf, vm::null, vm::null, funcStat, funcFile, container, 2, userdata, 0, vm::null);
|
||||
}
|
||||
|
||||
s32 cellSaveDataAutoSave(PPUThread& ppu, u32 version, vm::cptr<char> dirName, u32 errDialog, PSetBuf setBuf,
|
||||
s32 cellSaveDataAutoSave(ppu_thread& ppu, u32 version, vm::cptr<char> dirName, u32 errDialog, PSetBuf setBuf,
|
||||
PFuncStat funcStat, PFuncFile funcFile, u32 container)
|
||||
{
|
||||
cellSaveData.warning("cellSaveDataAutoSave(version=%d, dirName=*0x%x, errDialog=%d, setBuf=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)",
|
||||
@ -719,7 +720,7 @@ s32 cellSaveDataAutoSave(PPUThread& ppu, u32 version, vm::cptr<char> dirName, u3
|
||||
return savedata_op(ppu, SAVEDATA_OP_AUTO_SAVE, version, dirName, errDialog, vm::null, setBuf, vm::null, vm::null, funcStat, funcFile, container, 2, vm::null, 0, vm::null);
|
||||
}
|
||||
|
||||
s32 cellSaveDataAutoLoad(PPUThread& ppu, u32 version, vm::cptr<char> dirName, u32 errDialog, PSetBuf setBuf,
|
||||
s32 cellSaveDataAutoLoad(ppu_thread& ppu, u32 version, vm::cptr<char> dirName, u32 errDialog, PSetBuf setBuf,
|
||||
PFuncStat funcStat, PFuncFile funcFile, u32 container)
|
||||
{
|
||||
cellSaveData.warning("cellSaveDataAutoLoad(version=%d, dirName=*0x%x, errDialog=%d, setBuf=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x)",
|
||||
@ -728,7 +729,7 @@ s32 cellSaveDataAutoLoad(PPUThread& ppu, u32 version, vm::cptr<char> dirName, u3
|
||||
return savedata_op(ppu, SAVEDATA_OP_AUTO_LOAD, version, dirName, errDialog, vm::null, setBuf, vm::null, vm::null, funcStat, funcFile, container, 2, vm::null, 0, vm::null);
|
||||
}
|
||||
|
||||
s32 cellSaveDataListAutoSave(PPUThread& ppu, u32 version, u32 errDialog, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr<void> userdata)
|
||||
s32 cellSaveDataListAutoSave(ppu_thread& ppu, u32 version, u32 errDialog, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr<void> userdata)
|
||||
{
|
||||
cellSaveData.warning("cellSaveDataListAutoSave(version=%d, errDialog=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)",
|
||||
version, errDialog, setList, setBuf, funcFixed, funcStat, funcFile, container, userdata);
|
||||
@ -736,7 +737,7 @@ s32 cellSaveDataListAutoSave(PPUThread& ppu, u32 version, u32 errDialog, PSetLis
|
||||
return savedata_op(ppu, SAVEDATA_OP_LIST_AUTO_SAVE, version, vm::null, errDialog, setList, setBuf, vm::null, funcFixed, funcStat, funcFile, container, 0, userdata, 0, vm::null);
|
||||
}
|
||||
|
||||
s32 cellSaveDataListAutoLoad(PPUThread& ppu, u32 version, u32 errDialog, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr<void> userdata)
|
||||
s32 cellSaveDataListAutoLoad(ppu_thread& ppu, u32 version, u32 errDialog, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr<void> userdata)
|
||||
{
|
||||
cellSaveData.warning("cellSaveDataListAutoLoad(version=%d, errDialog=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)",
|
||||
version, errDialog, setList, setBuf, funcFixed, funcStat, funcFile, container, userdata);
|
||||
@ -758,7 +759,7 @@ s32 cellSaveDataDelete(u32 container)
|
||||
return CELL_SAVEDATA_RET_CANCEL;
|
||||
}
|
||||
|
||||
s32 cellSaveDataFixedDelete(PPUThread& ppu, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
|
||||
s32 cellSaveDataFixedDelete(ppu_thread& ppu, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
|
||||
{
|
||||
cellSaveData.todo("cellSaveDataFixedDelete(setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcDone=*0x%x, container=0x%x, userdata=*0x%x)",
|
||||
setList, setBuf, funcFixed, funcDone, container, userdata);
|
||||
@ -766,7 +767,7 @@ s32 cellSaveDataFixedDelete(PPUThread& ppu, PSetList setList, PSetBuf setBuf, PF
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSaveDataUserListSave(PPUThread& ppu, u32 version, u32 userId, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr<void> userdata)
|
||||
s32 cellSaveDataUserListSave(ppu_thread& ppu, u32 version, u32 userId, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr<void> userdata)
|
||||
{
|
||||
cellSaveData.error("cellSaveDataUserListSave(version=%d, userId=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)",
|
||||
version, userId, setList, setBuf, funcList, funcStat, funcFile, container, userdata);
|
||||
@ -774,7 +775,7 @@ s32 cellSaveDataUserListSave(PPUThread& ppu, u32 version, u32 userId, PSetList s
|
||||
return savedata_op(ppu, SAVEDATA_OP_LIST_SAVE, version, vm::null, 0, setList, setBuf, funcList, vm::null, funcStat, funcFile, container, 6, userdata, userId, vm::null);
|
||||
}
|
||||
|
||||
s32 cellSaveDataUserListLoad(PPUThread& ppu, u32 version, u32 userId, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr<void> userdata)
|
||||
s32 cellSaveDataUserListLoad(ppu_thread& ppu, u32 version, u32 userId, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr<void> userdata)
|
||||
{
|
||||
cellSaveData.error("cellSaveDataUserListLoad(version=%d, userId=%d, setList=*0x%x, setBuf=*0x%x, funcList=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)",
|
||||
version, userId, setList, setBuf, funcList, funcStat, funcFile, container, userdata);
|
||||
@ -782,7 +783,7 @@ s32 cellSaveDataUserListLoad(PPUThread& ppu, u32 version, u32 userId, PSetList s
|
||||
return savedata_op(ppu, SAVEDATA_OP_LIST_LOAD, version, vm::null, 0, setList, setBuf, funcList, vm::null, funcStat, funcFile, container, 6, userdata, userId, vm::null);
|
||||
}
|
||||
|
||||
s32 cellSaveDataUserFixedSave(PPUThread& ppu, u32 version, u32 userId, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr<void> userdata)
|
||||
s32 cellSaveDataUserFixedSave(ppu_thread& ppu, u32 version, u32 userId, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr<void> userdata)
|
||||
{
|
||||
cellSaveData.error("cellSaveDataUserFixedSave(version=%d, userId=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)",
|
||||
version, userId, setList, setBuf, funcFixed, funcStat, funcFile, container, userdata);
|
||||
@ -790,7 +791,7 @@ s32 cellSaveDataUserFixedSave(PPUThread& ppu, u32 version, u32 userId, PSetList
|
||||
return savedata_op(ppu, SAVEDATA_OP_FIXED_SAVE, version, vm::null, 0, setList, setBuf, vm::null, funcFixed, funcStat, funcFile, container, 6, userdata, userId, vm::null);
|
||||
}
|
||||
|
||||
s32 cellSaveDataUserFixedLoad(PPUThread& ppu, u32 version, u32 userId, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr<void> userdata)
|
||||
s32 cellSaveDataUserFixedLoad(ppu_thread& ppu, u32 version, u32 userId, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr<void> userdata)
|
||||
{
|
||||
cellSaveData.error("cellSaveDataUserFixedLoad(version=%d, userId=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)",
|
||||
version, userId, setList, setBuf, funcFixed, funcStat, funcFile, container, userdata);
|
||||
@ -798,7 +799,7 @@ s32 cellSaveDataUserFixedLoad(PPUThread& ppu, u32 version, u32 userId, PSetList
|
||||
return savedata_op(ppu, SAVEDATA_OP_FIXED_LOAD, version, vm::null, 0, setList, setBuf, vm::null, funcFixed, funcStat, funcFile, container, 6, userdata, userId, vm::null);
|
||||
}
|
||||
|
||||
s32 cellSaveDataUserAutoSave(PPUThread& ppu, u32 version, u32 userId, vm::cptr<char> dirName, u32 errDialog, PSetBuf setBuf, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr<void> userdata)
|
||||
s32 cellSaveDataUserAutoSave(ppu_thread& ppu, u32 version, u32 userId, vm::cptr<char> dirName, u32 errDialog, PSetBuf setBuf, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr<void> userdata)
|
||||
{
|
||||
cellSaveData.error("cellSaveDataUserAutoSave(version=%d, userId=%d, dirName=*0x%x, errDialog=%d, setBuf=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)",
|
||||
version, userId, dirName, errDialog, setBuf, funcStat, funcFile, container, userdata);
|
||||
@ -806,7 +807,7 @@ s32 cellSaveDataUserAutoSave(PPUThread& ppu, u32 version, u32 userId, vm::cptr<c
|
||||
return savedata_op(ppu, SAVEDATA_OP_AUTO_SAVE, version, dirName, errDialog, vm::null, setBuf, vm::null, vm::null, funcStat, funcFile, container, 6, userdata, userId, vm::null);
|
||||
}
|
||||
|
||||
s32 cellSaveDataUserAutoLoad(PPUThread& ppu, u32 version, u32 userId, vm::cptr<char> dirName, u32 errDialog, PSetBuf setBuf, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr<void> userdata)
|
||||
s32 cellSaveDataUserAutoLoad(ppu_thread& ppu, u32 version, u32 userId, vm::cptr<char> dirName, u32 errDialog, PSetBuf setBuf, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr<void> userdata)
|
||||
{
|
||||
cellSaveData.error("cellSaveDataUserAutoLoad(version=%d, userId=%d, dirName=*0x%x, errDialog=%d, setBuf=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)",
|
||||
version, userId, dirName, errDialog, setBuf, funcStat, funcFile, container, userdata);
|
||||
@ -814,7 +815,7 @@ s32 cellSaveDataUserAutoLoad(PPUThread& ppu, u32 version, u32 userId, vm::cptr<c
|
||||
return savedata_op(ppu, SAVEDATA_OP_AUTO_LOAD, version, dirName, errDialog, vm::null, setBuf, vm::null, vm::null, funcStat, funcFile, container, 6, userdata, userId, vm::null);
|
||||
}
|
||||
|
||||
s32 cellSaveDataUserListAutoSave(PPUThread& ppu, u32 version, u32 userId, u32 errDialog, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr<void> userdata)
|
||||
s32 cellSaveDataUserListAutoSave(ppu_thread& ppu, u32 version, u32 userId, u32 errDialog, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr<void> userdata)
|
||||
{
|
||||
cellSaveData.error("cellSaveDataUserListAutoSave(version=%d, userId=%d, errDialog=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)",
|
||||
version, userId, errDialog, setList, setBuf, funcFixed, funcStat, funcFile, container, userdata);
|
||||
@ -822,7 +823,7 @@ s32 cellSaveDataUserListAutoSave(PPUThread& ppu, u32 version, u32 userId, u32 er
|
||||
return savedata_op(ppu, SAVEDATA_OP_LIST_AUTO_SAVE, version, vm::null, errDialog, setList, setBuf, vm::null, funcFixed, funcStat, funcFile, container, 6, userdata, userId, vm::null);
|
||||
}
|
||||
|
||||
s32 cellSaveDataUserListAutoLoad(PPUThread& ppu, u32 version, u32 userId, u32 errDialog, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr<void> userdata)
|
||||
s32 cellSaveDataUserListAutoLoad(ppu_thread& ppu, u32 version, u32 userId, u32 errDialog, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncStat funcStat, PFuncFile funcFile, u32 container, vm::ptr<void> userdata)
|
||||
{
|
||||
cellSaveData.error("cellSaveDataUserListAutoLoad(version=%d, userId=%d, errDialog=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcStat=*0x%x, funcFile=*0x%x, container=0x%x, userdata=*0x%x)",
|
||||
version, userId, errDialog, setList, setBuf, funcFixed, funcStat, funcFile, container, userdata);
|
||||
@ -830,7 +831,7 @@ s32 cellSaveDataUserListAutoLoad(PPUThread& ppu, u32 version, u32 userId, u32 er
|
||||
return savedata_op(ppu, SAVEDATA_OP_LIST_AUTO_LOAD, version, vm::null, errDialog, setList, setBuf, vm::null, funcFixed, funcStat, funcFile, container, 6, userdata, userId, vm::null);
|
||||
}
|
||||
|
||||
s32 cellSaveDataUserFixedDelete(PPUThread& ppu, u32 userId, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
|
||||
s32 cellSaveDataUserFixedDelete(ppu_thread& ppu, u32 userId, PSetList setList, PSetBuf setBuf, PFuncFixed funcFixed, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
|
||||
{
|
||||
cellSaveData.todo("cellSaveDataUserFixedDelete(userId=%d, setList=*0x%x, setBuf=*0x%x, funcFixed=*0x%x, funcDone=*0x%x, container=0x%x, userdata=*0x%x)",
|
||||
userId, setList, setBuf, funcFixed, funcDone, container, userdata);
|
||||
@ -847,35 +848,35 @@ void cellSaveDataEnableOverlay(s32 enable)
|
||||
|
||||
|
||||
// Functions (Extensions)
|
||||
s32 cellSaveDataListDelete(PPUThread& ppu, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
|
||||
s32 cellSaveDataListDelete(ppu_thread& ppu, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSaveData);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSaveDataListImport(PPUThread& ppu, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
|
||||
s32 cellSaveDataListImport(ppu_thread& ppu, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSaveData);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSaveDataListExport(PPUThread& ppu, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
|
||||
s32 cellSaveDataListExport(ppu_thread& ppu, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSaveData);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSaveDataFixedImport(PPUThread& ppu, vm::cptr<char> dirName, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
|
||||
s32 cellSaveDataFixedImport(ppu_thread& ppu, vm::cptr<char> dirName, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSaveData);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSaveDataFixedExport(PPUThread& ppu, vm::cptr<char> dirName, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
|
||||
s32 cellSaveDataFixedExport(ppu_thread& ppu, vm::cptr<char> dirName, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSaveData);
|
||||
|
||||
@ -889,35 +890,35 @@ s32 cellSaveDataGetListItem(vm::cptr<char> dirName, vm::ptr<CellSaveDataDirStat>
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSaveDataUserListDelete(PPUThread& ppu, u32 userId, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
|
||||
s32 cellSaveDataUserListDelete(ppu_thread& ppu, u32 userId, PSetList setList, PSetBuf setBuf, PFuncList funcList, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSaveData);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSaveDataUserListImport(PPUThread& ppu, u32 userId, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
|
||||
s32 cellSaveDataUserListImport(ppu_thread& ppu, u32 userId, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSaveData);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSaveDataUserListExport(PPUThread& ppu, u32 userId, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
|
||||
s32 cellSaveDataUserListExport(ppu_thread& ppu, u32 userId, PSetList setList, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSaveData);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSaveDataUserFixedImport(PPUThread& ppu, u32 userId, vm::cptr<char> dirName, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
|
||||
s32 cellSaveDataUserFixedImport(ppu_thread& ppu, u32 userId, vm::cptr<char> dirName, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSaveData);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSaveDataUserFixedExport(PPUThread& ppu, u32 userId, vm::cptr<char> dirName, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
|
||||
s32 cellSaveDataUserFixedExport(ppu_thread& ppu, u32 userId, vm::cptr<char> dirName, u32 maxSizeKB, PFuncDone funcDone, u32 container, vm::ptr<void> userdata)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSaveData);
|
||||
|
||||
|
@ -30,28 +30,6 @@ struct cell_error_t
|
||||
|
||||
#define CHECK_SUCCESS(expr) if (cell_error_t error{expr}) throw fmt::exception("Failure: %s -> 0x%x" HERE, #expr, error.value)
|
||||
|
||||
static u32 ppu_thread_create(u32 entry, u64 arg, s32 prio, u32 stacksize, const std::string& name, std::function<void(PPUThread&)> task)
|
||||
{
|
||||
const auto ppu = idm::make_ptr<PPUThread>(name);
|
||||
|
||||
ppu->prio = prio;
|
||||
ppu->stack_size = stacksize;
|
||||
ppu->custom_task = std::move(task);
|
||||
ppu->cpu_init();
|
||||
|
||||
if (entry)
|
||||
{
|
||||
ppu->pc = vm::read32(entry);
|
||||
ppu->GPR[2] = vm::read32(entry + 4); // rtoc
|
||||
}
|
||||
|
||||
ppu->GPR[3] = arg;
|
||||
ppu->state -= cpu_state::stop;
|
||||
(*ppu)->lock_notify();
|
||||
|
||||
return ppu->id;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Function prototypes
|
||||
//----------------------------------------------------------------------------
|
||||
@ -68,34 +46,34 @@ namespace _spurs
|
||||
bool is_libprof_loaded();
|
||||
|
||||
// Create an LV2 event queue and attach it to the SPURS instance
|
||||
s32 create_lv2_eq(PPUThread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<u32> queueId, vm::ptr<u8> port, s32 size, const sys_event_queue_attribute_t& name);
|
||||
s32 create_lv2_eq(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<u32> queueId, vm::ptr<u8> port, s32 size, const sys_event_queue_attribute_t& name);
|
||||
|
||||
// Attach an LV2 event queue to the SPURS instance
|
||||
s32 attach_lv2_eq(PPUThread& ppu, vm::ptr<CellSpurs> spurs, u32 queue, vm::ptr<u8> port, s32 isDynamic, bool spursCreated);
|
||||
s32 attach_lv2_eq(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 queue, vm::ptr<u8> port, s32 isDynamic, bool spursCreated);
|
||||
|
||||
// Detach an LV2 event queue from the SPURS instance
|
||||
s32 detach_lv2_eq(vm::ptr<CellSpurs> spurs, u8 spuPort, bool spursCreated);
|
||||
|
||||
// Wait until a workload in the SPURS instance becomes ready
|
||||
void handler_wait_ready(PPUThread& ppu, vm::ptr<CellSpurs> spurs);
|
||||
void handler_wait_ready(ppu_thread& ppu, vm::ptr<CellSpurs> spurs);
|
||||
|
||||
// Entry point of the SPURS handler thread. This thread is responsible for starting the SPURS SPU thread group.
|
||||
void handler_entry(PPUThread& ppu, vm::ptr<CellSpurs> spurs);
|
||||
void handler_entry(ppu_thread& ppu, vm::ptr<CellSpurs> spurs);
|
||||
|
||||
// Create the SPURS handler thread
|
||||
s32 create_handler(vm::ptr<CellSpurs> spurs, u32 ppuPriority);
|
||||
|
||||
// Invoke event handlers
|
||||
s32 invoke_event_handlers(PPUThread& ppu, vm::ptr<CellSpurs::EventPortMux> eventPortMux);
|
||||
s32 invoke_event_handlers(ppu_thread& ppu, vm::ptr<CellSpurs::EventPortMux> eventPortMux);
|
||||
|
||||
// Invoke workload shutdown completion callbacks
|
||||
s32 wakeup_shutdown_completion_waiter(PPUThread& ppu, vm::ptr<CellSpurs> spurs, u32 wid);
|
||||
s32 wakeup_shutdown_completion_waiter(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 wid);
|
||||
|
||||
// Entry point of the SPURS event helper thread
|
||||
void event_helper_entry(PPUThread& ppu, vm::ptr<CellSpurs> spurs);
|
||||
void event_helper_entry(ppu_thread& ppu, vm::ptr<CellSpurs> spurs);
|
||||
|
||||
// Create the SPURS event helper thread
|
||||
s32 create_event_helper(PPUThread& ppu, vm::ptr<CellSpurs> spurs, u32 ppuPriority);
|
||||
s32 create_event_helper(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 ppuPriority);
|
||||
|
||||
// Initialise the event port multiplexor structure
|
||||
void init_event_port_mux(vm::ptr<CellSpurs::EventPortMux> eventPortMux, u8 spuPort, u32 eventPort, u32 unknown);
|
||||
@ -107,25 +85,25 @@ namespace _spurs
|
||||
s32 finalize_spu(vm::ptr<CellSpurs> spurs);
|
||||
|
||||
// Stop the event helper thread
|
||||
s32 stop_event_helper(PPUThread& ppu, vm::ptr<CellSpurs> spurs);
|
||||
s32 stop_event_helper(ppu_thread& ppu, vm::ptr<CellSpurs> spurs);
|
||||
|
||||
// Signal to the SPURS handler thread
|
||||
s32 signal_to_handler_thread(PPUThread& ppu, vm::ptr<CellSpurs> spurs);
|
||||
s32 signal_to_handler_thread(ppu_thread& ppu, vm::ptr<CellSpurs> spurs);
|
||||
|
||||
// Join the SPURS handler thread
|
||||
s32 join_handler_thread(PPUThread& ppu, vm::ptr<CellSpurs> spurs);
|
||||
s32 join_handler_thread(ppu_thread& ppu, vm::ptr<CellSpurs> spurs);
|
||||
|
||||
// Initialise SPURS
|
||||
s32 initialize(PPUThread& ppu, vm::ptr<CellSpurs> spurs, u32 revision, u32 sdkVersion, s32 nSpus, s32 spuPriority, s32 ppuPriority, u32 flags, vm::cptr<char> prefix, u32 prefixSize, u32 container, vm::cptr<u8> swlPriority, u32 swlMaxSpu, u32 swlIsPreem);
|
||||
s32 initialize(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 revision, u32 sdkVersion, s32 nSpus, s32 spuPriority, s32 ppuPriority, u32 flags, vm::cptr<char> prefix, u32 prefixSize, u32 container, vm::cptr<u8> swlPriority, u32 swlMaxSpu, u32 swlIsPreem);
|
||||
}
|
||||
|
||||
//
|
||||
// SPURS Core Functions
|
||||
//
|
||||
|
||||
//s32 cellSpursInitialize(PPUThread& ppu, vm::ptr<CellSpurs> spurs, s32 nSpus, s32 spuPriority, s32 ppuPriority, b8 exitIfNoWork);
|
||||
//s32 cellSpursInitializeWithAttribute(PPUThread& ppu, vm::ptr<CellSpurs> spurs, vm::cptr<CellSpursAttribute> attr);
|
||||
//s32 cellSpursInitializeWithAttribute2(PPUThread& ppu, vm::ptr<CellSpurs> spurs, vm::cptr<CellSpursAttribute> attr);
|
||||
//s32 cellSpursInitialize(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, s32 nSpus, s32 spuPriority, s32 ppuPriority, b8 exitIfNoWork);
|
||||
//s32 cellSpursInitializeWithAttribute(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, vm::cptr<CellSpursAttribute> attr);
|
||||
//s32 cellSpursInitializeWithAttribute2(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, vm::cptr<CellSpursAttribute> attr);
|
||||
//s32 _cellSpursAttributeInitialize(vm::ptr<CellSpursAttribute> attr, u32 revision, u32 sdkVersion, u32 nSpus, s32 spuPriority, s32 ppuPriority, b8 exitIfNoWork);
|
||||
//s32 cellSpursAttributeSetMemoryContainerForSpuThread(vm::ptr<CellSpursAttribute> attr, u32 container);
|
||||
//s32 cellSpursAttributeSetNamePrefix(vm::ptr<CellSpursAttribute> attr, vm::cptr<char> prefix, u32 size);
|
||||
@ -139,7 +117,7 @@ namespace _spurs
|
||||
//s32 cellSpursSetMaxContention(vm::ptr<CellSpurs> spurs, u32 wid, u32 maxContention);
|
||||
//s32 cellSpursSetPriorities(vm::ptr<CellSpurs> spurs, u32 wid, vm::cptr<u8> priorities);
|
||||
//s32 cellSpursSetPreemptionVictimHints(vm::ptr<CellSpurs> spurs, vm::cptr<b8> isPreemptible);
|
||||
//s32 cellSpursAttachLv2EventQueue(PPUThread& ppu, vm::ptr<CellSpurs> spurs, u32 queue, vm::ptr<u8> port, s32 isDynamic);
|
||||
//s32 cellSpursAttachLv2EventQueue(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 queue, vm::ptr<u8> port, s32 isDynamic);
|
||||
//s32 cellSpursDetachLv2EventQueue(vm::ptr<CellSpurs> spurs, u8 port);
|
||||
|
||||
// Enable the SPU exception event handler
|
||||
@ -162,22 +140,22 @@ s32 cellSpursEnableExceptionEventHandler(vm::ptr<CellSpurs> spurs, b8 flag);
|
||||
namespace _spurs
|
||||
{
|
||||
// Signal SPUs to update trace status
|
||||
void trace_status_update(PPUThread& ppu, vm::ptr<CellSpurs> spurs);
|
||||
void trace_status_update(ppu_thread& ppu, vm::ptr<CellSpurs> spurs);
|
||||
|
||||
// Initialize SPURS trace
|
||||
s32 trace_initialize(PPUThread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursTraceInfo> buffer, u32 size, u32 mode, u32 updateStatus);
|
||||
s32 trace_initialize(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursTraceInfo> buffer, u32 size, u32 mode, u32 updateStatus);
|
||||
|
||||
// Start SPURS trace
|
||||
s32 trace_start(PPUThread& ppu, vm::ptr<CellSpurs> spurs, u32 updateStatus);
|
||||
s32 trace_start(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 updateStatus);
|
||||
|
||||
// Stop SPURS trace
|
||||
s32 trace_stop(PPUThread& ppu, vm::ptr<CellSpurs> spurs, u32 updateStatus);
|
||||
s32 trace_stop(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 updateStatus);
|
||||
}
|
||||
|
||||
//s32 cellSpursTraceInitialize(PPUThread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursTraceInfo> buffer, u32 size, u32 mode);
|
||||
//s32 cellSpursTraceFinalize(PPUThread& ppu, vm::ptr<CellSpurs> spurs);
|
||||
//s32 cellSpursTraceStart(PPUThread& ppu, vm::ptr<CellSpurs> spurs);
|
||||
//s32 cellSpursTraceStop(PPUThread& ppu, vm::ptr<CellSpurs> spurs);
|
||||
//s32 cellSpursTraceInitialize(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursTraceInfo> buffer, u32 size, u32 mode);
|
||||
//s32 cellSpursTraceFinalize(ppu_thread& ppu, vm::ptr<CellSpurs> spurs);
|
||||
//s32 cellSpursTraceStart(ppu_thread& ppu, vm::ptr<CellSpurs> spurs);
|
||||
//s32 cellSpursTraceStop(ppu_thread& ppu, vm::ptr<CellSpurs> spurs);
|
||||
|
||||
//
|
||||
// SPURS policy module functions
|
||||
@ -199,7 +177,7 @@ namespace _spurs
|
||||
//s32 cellSpursRemoveWorkload();
|
||||
|
||||
// Activate the SPURS kernel
|
||||
s32 cellSpursWakeUp(PPUThread& ppu, vm::ptr<CellSpurs> spurs);
|
||||
s32 cellSpursWakeUp(ppu_thread& ppu, vm::ptr<CellSpurs> spurs);
|
||||
|
||||
//s32 cellSpursSendWorkloadSignal(vm::ptr<CellSpurs> spurs, u32 wid);
|
||||
//s32 cellSpursGetWorkloadFlag(vm::ptr<CellSpurs> spurs, vm::pptr<CellSpursWorkloadFlag> flag);
|
||||
@ -222,11 +200,11 @@ s32 cellSpursWakeUp(PPUThread& ppu, vm::ptr<CellSpurs> spurs);
|
||||
namespace _spurs
|
||||
{
|
||||
// Create taskset
|
||||
s32 create_taskset(PPUThread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursTaskset> taskset, u64 args, vm::cptr<u8[8]> priority, u32 max_contention, vm::cptr<char> name, u32 size, s32 enable_clear_ls);
|
||||
s32 create_taskset(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursTaskset> taskset, u64 args, vm::cptr<u8[8]> priority, u32 max_contention, vm::cptr<char> name, u32 size, s32 enable_clear_ls);
|
||||
}
|
||||
|
||||
//s32 cellSpursCreateTasksetWithAttribute(PPUThread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursTaskset> taskset, vm::ptr<CellSpursTasksetAttribute> attr);
|
||||
//s32 cellSpursCreateTaskset(PPUThread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursTaskset> taskset, u64 args, vm::cptr<u8[8]> priority, u32 maxContention);
|
||||
//s32 cellSpursCreateTasksetWithAttribute(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursTaskset> taskset, vm::ptr<CellSpursTasksetAttribute> attr);
|
||||
//s32 cellSpursCreateTaskset(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursTaskset> taskset, u64 args, vm::cptr<u8[8]> priority, u32 maxContention);
|
||||
//s32 cellSpursJoinTaskset(vm::ptr<CellSpursTaskset> taskset);
|
||||
//s32 cellSpursGetTasksetId(vm::ptr<CellSpursTaskset> taskset, vm::ptr<u32> wid);
|
||||
//s32 cellSpursShutdownTaskset(vm::ptr<CellSpursTaskset> taskset);
|
||||
@ -234,13 +212,13 @@ namespace _spurs
|
||||
//s32 cellSpursTasksetAttributeSetTasksetSize(vm::ptr<CellSpursTasksetAttribute> attr, u32 size);
|
||||
//s32 cellSpursTasksetAttributeEnableClearLS(vm::ptr<CellSpursTasksetAttribute> attr, s32 enable);
|
||||
//s32 _cellSpursTasksetAttribute2Initialize(vm::ptr<CellSpursTasksetAttribute2> attribute, u32 revision);
|
||||
//s32 cellSpursCreateTaskset2(PPUThread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursTaskset> taskset, vm::ptr<CellSpursTasksetAttribute2> attr);
|
||||
//s32 cellSpursCreateTaskset2(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursTaskset> taskset, vm::ptr<CellSpursTasksetAttribute2> attr);
|
||||
//s32 cellSpursDestroyTaskset2();
|
||||
//s32 cellSpursTasksetSetExceptionEventHandler(vm::ptr<CellSpursTaskset> taskset, vm::ptr<CellSpursTasksetExceptionEventHandler> handler, vm::ptr<u64> arg);
|
||||
//s32 cellSpursTasksetUnsetExceptionEventHandler(vm::ptr<CellSpursTaskset> taskset);
|
||||
|
||||
// Get taskset instance from the workload ID
|
||||
s32 cellSpursLookUpTasksetAddress(PPUThread& ppu, vm::ptr<CellSpurs> spurs, vm::pptr<CellSpursTaskset> taskset, u32 id);
|
||||
s32 cellSpursLookUpTasksetAddress(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, vm::pptr<CellSpursTaskset> taskset, u32 id);
|
||||
|
||||
//s32 cellSpursTasksetGetSpursAddress(vm::cptr<CellSpursTaskset> taskset, vm::ptr<u32> spurs);
|
||||
//s32 cellSpursGetTasksetInfo();
|
||||
@ -256,13 +234,13 @@ namespace _spurs
|
||||
s32 create_task(vm::ptr<CellSpursTaskset> taskset, vm::ptr<u32> task_id, vm::cptr<void> elf, vm::cptr<void> context, u32 size, vm::ptr<CellSpursTaskLsPattern> ls_pattern, vm::ptr<CellSpursTaskArgument> arg);
|
||||
|
||||
// Start task
|
||||
s32 task_start(PPUThread& ppu, vm::ptr<CellSpursTaskset> taskset, u32 taskId);
|
||||
s32 task_start(ppu_thread& ppu, vm::ptr<CellSpursTaskset> taskset, u32 taskId);
|
||||
}
|
||||
|
||||
//s32 cellSpursCreateTask(PPUThread& ppu, vm::ptr<CellSpursTaskset> taskset, vm::ptr<u32> taskId, vm::cptr<void> elf, vm::cptr<void> context, u32 size, vm::ptr<CellSpursTaskLsPattern> lsPattern, vm::ptr<CellSpursTaskArgument> argument);
|
||||
//s32 cellSpursCreateTask(ppu_thread& ppu, vm::ptr<CellSpursTaskset> taskset, vm::ptr<u32> taskId, vm::cptr<void> elf, vm::cptr<void> context, u32 size, vm::ptr<CellSpursTaskLsPattern> lsPattern, vm::ptr<CellSpursTaskArgument> argument);
|
||||
|
||||
// Sends a signal to the task
|
||||
s32 _cellSpursSendSignal(PPUThread& ppu, vm::ptr<CellSpursTaskset> taskset, u32 taskId);
|
||||
s32 _cellSpursSendSignal(ppu_thread& ppu, vm::ptr<CellSpursTaskset> taskset, u32 taskId);
|
||||
|
||||
//s32 cellSpursCreateTaskWithAttribute();
|
||||
//s32 cellSpursTaskExitCodeGet();
|
||||
@ -287,15 +265,15 @@ s32 _cellSpursSendSignal(PPUThread& ppu, vm::ptr<CellSpursTaskset> taskset, u32
|
||||
namespace _spurs
|
||||
{
|
||||
// Wait for SPURS event flag
|
||||
s32 event_flag_wait(PPUThread& ppu, vm::ptr<CellSpursEventFlag> eventFlag, vm::ptr<u16> mask, u32 mode, u32 block);
|
||||
s32 event_flag_wait(ppu_thread& ppu, vm::ptr<CellSpursEventFlag> eventFlag, vm::ptr<u16> mask, u32 mode, u32 block);
|
||||
}
|
||||
|
||||
//s32 _cellSpursEventFlagInitialize(vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursTaskset> taskset, vm::ptr<CellSpursEventFlag> eventFlag, u32 flagClearMode, u32 flagDirection);
|
||||
//s32 cellSpursEventFlagClear(vm::ptr<CellSpursEventFlag> eventFlag, u16 bits);
|
||||
//s32 cellSpursEventFlagSet(PPUThread& ppu, vm::ptr<CellSpursEventFlag> eventFlag, u16 bits);
|
||||
//s32 cellSpursEventFlagWait(PPUThread& ppu, vm::ptr<CellSpursEventFlag> eventFlag, vm::ptr<u16> mask, u32 mode);
|
||||
//s32 cellSpursEventFlagTryWait(PPUThread& ppu, vm::ptr<CellSpursEventFlag> eventFlag, vm::ptr<u16> mask, u32 mode);
|
||||
//s32 cellSpursEventFlagAttachLv2EventQueue(PPUThread& ppu, vm::ptr<CellSpursEventFlag> eventFlag);
|
||||
//s32 cellSpursEventFlagSet(ppu_thread& ppu, vm::ptr<CellSpursEventFlag> eventFlag, u16 bits);
|
||||
//s32 cellSpursEventFlagWait(ppu_thread& ppu, vm::ptr<CellSpursEventFlag> eventFlag, vm::ptr<u16> mask, u32 mode);
|
||||
//s32 cellSpursEventFlagTryWait(ppu_thread& ppu, vm::ptr<CellSpursEventFlag> eventFlag, vm::ptr<u16> mask, u32 mode);
|
||||
//s32 cellSpursEventFlagAttachLv2EventQueue(ppu_thread& ppu, vm::ptr<CellSpursEventFlag> eventFlag);
|
||||
//s32 cellSpursEventFlagDetachLv2EventQueue(vm::ptr<CellSpursEventFlag> eventFlag);
|
||||
//s32 cellSpursEventFlagGetDirection(vm::ptr<CellSpursEventFlag> eventFlag, vm::ptr<u32> direction);
|
||||
//s32 cellSpursEventFlagGetClearMode(vm::ptr<CellSpursEventFlag> eventFlag, vm::ptr<u32> clear_mode);
|
||||
@ -391,7 +369,7 @@ bool _spurs::is_libprof_loaded()
|
||||
// SPURS core functions
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
s32 _spurs::create_lv2_eq(PPUThread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<u32> queueId, vm::ptr<u8> port, s32 size, const sys_event_queue_attribute_t& attr)
|
||||
s32 _spurs::create_lv2_eq(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<u32> queueId, vm::ptr<u8> port, s32 size, const sys_event_queue_attribute_t& attr)
|
||||
{
|
||||
if (s32 rc = sys_event_queue_create(queueId, vm::make_var(attr), SYS_EVENT_QUEUE_LOCAL, size))
|
||||
{
|
||||
@ -406,7 +384,7 @@ s32 _spurs::create_lv2_eq(PPUThread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<u32>
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _spurs::attach_lv2_eq(PPUThread& ppu, vm::ptr<CellSpurs> spurs, u32 queue, vm::ptr<u8> port, s32 isDynamic, bool spursCreated)
|
||||
s32 _spurs::attach_lv2_eq(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 queue, vm::ptr<u8> port, s32 isDynamic, bool spursCreated)
|
||||
{
|
||||
if (!spurs || !port)
|
||||
{
|
||||
@ -503,7 +481,7 @@ s32 _spurs::detach_lv2_eq(vm::ptr<CellSpurs> spurs, u8 spuPort, bool spursCreate
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
void _spurs::handler_wait_ready(PPUThread& ppu, vm::ptr<CellSpurs> spurs)
|
||||
void _spurs::handler_wait_ready(ppu_thread& ppu, vm::ptr<CellSpurs> spurs)
|
||||
{
|
||||
CHECK_SUCCESS(sys_lwmutex_lock(ppu, spurs.ptr(&CellSpurs::mutex), 0));
|
||||
|
||||
@ -580,7 +558,7 @@ void _spurs::handler_wait_ready(PPUThread& ppu, vm::ptr<CellSpurs> spurs)
|
||||
CHECK_SUCCESS(sys_lwmutex_unlock(ppu, spurs.ptr(&CellSpurs::mutex)));
|
||||
}
|
||||
|
||||
void _spurs::handler_entry(PPUThread& ppu, vm::ptr<CellSpurs> spurs)
|
||||
void _spurs::handler_entry(ppu_thread& ppu, vm::ptr<CellSpurs> spurs)
|
||||
{
|
||||
if (spurs->flags & SAF_UNKNOWN_FLAG_30)
|
||||
{
|
||||
@ -619,12 +597,27 @@ void _spurs::handler_entry(PPUThread& ppu, vm::ptr<CellSpurs> spurs)
|
||||
|
||||
s32 _spurs::create_handler(vm::ptr<CellSpurs> spurs, u32 ppuPriority)
|
||||
{
|
||||
spurs->ppu0 = ppu_thread_create(0, spurs.addr(), ppuPriority, 0x4000, std::string(spurs->prefix, spurs->prefixSize) + "SpursHdlr0", BIND_FUNC(_spurs::handler_entry));
|
||||
struct handler_thread : ppu_thread
|
||||
{
|
||||
using ppu_thread::ppu_thread;
|
||||
|
||||
virtual void cpu_task() override
|
||||
{
|
||||
BIND_FUNC(_spurs::handler_entry)(*this);
|
||||
}
|
||||
};
|
||||
|
||||
auto&& eht = std::make_shared<handler_thread>(std::string(spurs->prefix, spurs->prefixSize) + "SpursHdlr0", ppuPriority, 0x4000);
|
||||
|
||||
spurs->ppu0 = idm::import_existing<ppu_thread>(eht);
|
||||
|
||||
eht->gpr[3] = spurs.addr();
|
||||
eht->run();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _spurs::invoke_event_handlers(PPUThread& ppu, vm::ptr<CellSpurs::EventPortMux> eventPortMux)
|
||||
s32 _spurs::invoke_event_handlers(ppu_thread& ppu, vm::ptr<CellSpurs::EventPortMux> eventPortMux)
|
||||
{
|
||||
if (eventPortMux->reqPending.exchange(0))
|
||||
{
|
||||
@ -637,7 +630,7 @@ s32 _spurs::invoke_event_handlers(PPUThread& ppu, vm::ptr<CellSpurs::EventPortMu
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _spurs::wakeup_shutdown_completion_waiter(PPUThread& ppu, vm::ptr<CellSpurs> spurs, u32 wid)
|
||||
s32 _spurs::wakeup_shutdown_completion_waiter(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 wid)
|
||||
{
|
||||
if (!spurs)
|
||||
{
|
||||
@ -689,21 +682,19 @@ s32 _spurs::wakeup_shutdown_completion_waiter(PPUThread& ppu, vm::ptr<CellSpurs>
|
||||
return rc;
|
||||
}
|
||||
|
||||
void _spurs::event_helper_entry(PPUThread& ppu, vm::ptr<CellSpurs> spurs)
|
||||
void _spurs::event_helper_entry(ppu_thread& ppu, vm::ptr<CellSpurs> spurs)
|
||||
{
|
||||
bool terminate = false;
|
||||
|
||||
vm::var<sys_event_t[]> events(8);
|
||||
vm::var<u32> count;
|
||||
|
||||
while (!terminate)
|
||||
while (true)
|
||||
{
|
||||
CHECK_SUCCESS(sys_event_queue_receive(ppu, spurs->eventQueue, vm::null, 0));
|
||||
|
||||
const u64 event_src = ppu.GPR[4];
|
||||
const u64 event_data1 = ppu.GPR[5];
|
||||
const u64 event_data2 = ppu.GPR[6];
|
||||
const u64 event_data3 = ppu.GPR[7];
|
||||
const u64 event_src = ppu.gpr[4];
|
||||
const u64 event_data1 = ppu.gpr[5];
|
||||
const u64 event_data2 = ppu.gpr[6];
|
||||
const u64 event_data3 = ppu.gpr[7];
|
||||
|
||||
if (event_src == SYS_SPU_THREAD_EVENT_EXCEPTION_KEY)
|
||||
{
|
||||
@ -737,7 +728,7 @@ void _spurs::event_helper_entry(PPUThread& ppu, vm::ptr<CellSpurs> spurs)
|
||||
|
||||
if (data0 == 1)
|
||||
{
|
||||
terminate = true;
|
||||
return;
|
||||
}
|
||||
else if (data0 < 1)
|
||||
{
|
||||
@ -772,7 +763,7 @@ void _spurs::event_helper_entry(PPUThread& ppu, vm::ptr<CellSpurs> spurs)
|
||||
}
|
||||
}
|
||||
|
||||
s32 _spurs::create_event_helper(PPUThread& ppu, vm::ptr<CellSpurs> spurs, u32 ppuPriority)
|
||||
s32 _spurs::create_event_helper(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 ppuPriority)
|
||||
{
|
||||
if (s32 rc = _spurs::create_lv2_eq(ppu, spurs, spurs.ptr(&CellSpurs::eventQueue), spurs.ptr(&CellSpurs::spuPort), 0x2A, sys_event_queue_attribute_t{ SYS_SYNC_PRIORITY, SYS_PPU_QUEUE, "_spuPrv" }))
|
||||
{
|
||||
@ -803,7 +794,19 @@ s32 _spurs::create_event_helper(PPUThread& ppu, vm::ptr<CellSpurs> spurs, u32 pp
|
||||
return CELL_SPURS_CORE_ERROR_STAT;
|
||||
}
|
||||
|
||||
const u32 tid = ppu_thread_create(0, spurs.addr(), ppuPriority, 0x8000, std::string(spurs->prefix, spurs->prefixSize) + "SpursHdlr1", BIND_FUNC(_spurs::event_helper_entry));
|
||||
struct event_helper_thread : ppu_thread
|
||||
{
|
||||
using ppu_thread::ppu_thread;
|
||||
|
||||
virtual void cpu_task() override
|
||||
{
|
||||
BIND_FUNC(_spurs::event_helper_entry)(*this);
|
||||
}
|
||||
};
|
||||
|
||||
auto&& eht = std::make_shared<event_helper_thread>(std::string(spurs->prefix, spurs->prefixSize) + "SpursHdlr1", ppuPriority, 0x8000);
|
||||
|
||||
const u32 tid = idm::import_existing<ppu_thread>(eht);
|
||||
|
||||
if (tid == 0)
|
||||
{
|
||||
@ -819,6 +822,9 @@ s32 _spurs::create_event_helper(PPUThread& ppu, vm::ptr<CellSpurs> spurs, u32 pp
|
||||
return CELL_SPURS_CORE_ERROR_STAT;
|
||||
}
|
||||
|
||||
eht->gpr[3] = spurs.addr();
|
||||
eht->run();
|
||||
|
||||
spurs->ppu1 = tid;
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -871,7 +877,7 @@ s32 _spurs::finalize_spu(vm::ptr<CellSpurs> spurs)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _spurs::stop_event_helper(PPUThread& ppu, vm::ptr<CellSpurs> spurs)
|
||||
s32 _spurs::stop_event_helper(ppu_thread& ppu, vm::ptr<CellSpurs> spurs)
|
||||
{
|
||||
if (spurs->ppu1 == 0xFFFFFFFF)
|
||||
{
|
||||
@ -898,7 +904,7 @@ s32 _spurs::stop_event_helper(PPUThread& ppu, vm::ptr<CellSpurs> spurs)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _spurs::signal_to_handler_thread(PPUThread& ppu, vm::ptr<CellSpurs> spurs)
|
||||
s32 _spurs::signal_to_handler_thread(ppu_thread& ppu, vm::ptr<CellSpurs> spurs)
|
||||
{
|
||||
CHECK_SUCCESS(sys_lwmutex_lock(ppu, spurs.ptr(&CellSpurs::mutex), 0));
|
||||
CHECK_SUCCESS(sys_lwcond_signal(ppu, spurs.ptr(&CellSpurs::cond)));
|
||||
@ -907,7 +913,7 @@ s32 _spurs::signal_to_handler_thread(PPUThread& ppu, vm::ptr<CellSpurs> spurs)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _spurs::join_handler_thread(PPUThread& ppu, vm::ptr<CellSpurs> spurs)
|
||||
s32 _spurs::join_handler_thread(ppu_thread& ppu, vm::ptr<CellSpurs> spurs)
|
||||
{
|
||||
if (spurs->ppu0 == 0xFFFFFFFF)
|
||||
{
|
||||
@ -920,7 +926,7 @@ s32 _spurs::join_handler_thread(PPUThread& ppu, vm::ptr<CellSpurs> spurs)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _spurs::initialize(PPUThread& ppu, vm::ptr<CellSpurs> spurs, u32 revision, u32 sdkVersion, s32 nSpus, s32 spuPriority, s32 ppuPriority, u32 flags, vm::cptr<char> prefix, u32 prefixSize, u32 container, vm::cptr<u8> swlPriority, u32 swlMaxSpu, u32 swlIsPreem)
|
||||
s32 _spurs::initialize(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 revision, u32 sdkVersion, s32 nSpus, s32 spuPriority, s32 ppuPriority, u32 flags, vm::cptr<char> prefix, u32 prefixSize, u32 container, vm::cptr<u8> swlPriority, u32 swlMaxSpu, u32 swlIsPreem)
|
||||
{
|
||||
vm::var<u32> sem;
|
||||
vm::var<sys_semaphore_attribute_t> semAttr;
|
||||
@ -1211,7 +1217,7 @@ s32 _spurs::initialize(PPUThread& ppu, vm::ptr<CellSpurs> spurs, u32 revision, u
|
||||
}
|
||||
|
||||
/// Initialize SPURS
|
||||
s32 cellSpursInitialize(PPUThread& ppu, vm::ptr<CellSpurs> spurs, s32 nSpus, s32 spuPriority, s32 ppuPriority, b8 exitIfNoWork)
|
||||
s32 cellSpursInitialize(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, s32 nSpus, s32 spuPriority, s32 ppuPriority, b8 exitIfNoWork)
|
||||
{
|
||||
cellSpurs.warning("cellSpursInitialize(spurs=*0x%x, nSpus=%d, spuPriority=%d, ppuPriority=%d, exitIfNoWork=%d)", spurs, nSpus, spuPriority, ppuPriority, exitIfNoWork);
|
||||
|
||||
@ -1219,7 +1225,7 @@ s32 cellSpursInitialize(PPUThread& ppu, vm::ptr<CellSpurs> spurs, s32 nSpus, s32
|
||||
}
|
||||
|
||||
/// Initialise SPURS
|
||||
s32 cellSpursInitializeWithAttribute(PPUThread& ppu, vm::ptr<CellSpurs> spurs, vm::cptr<CellSpursAttribute> attr)
|
||||
s32 cellSpursInitializeWithAttribute(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, vm::cptr<CellSpursAttribute> attr)
|
||||
{
|
||||
cellSpurs.warning("cellSpursInitializeWithAttribute(spurs=*0x%x, attr=*0x%x)", spurs, attr);
|
||||
|
||||
@ -1256,7 +1262,7 @@ s32 cellSpursInitializeWithAttribute(PPUThread& ppu, vm::ptr<CellSpurs> spurs, v
|
||||
}
|
||||
|
||||
/// Initialise SPURS
|
||||
s32 cellSpursInitializeWithAttribute2(PPUThread& ppu, vm::ptr<CellSpurs> spurs, vm::cptr<CellSpursAttribute> attr)
|
||||
s32 cellSpursInitializeWithAttribute2(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, vm::cptr<CellSpursAttribute> attr)
|
||||
{
|
||||
cellSpurs.warning("cellSpursInitializeWithAttribute2(spurs=*0x%x, attr=*0x%x)", spurs, attr);
|
||||
|
||||
@ -1697,7 +1703,7 @@ s32 cellSpursSetPreemptionVictimHints(vm::ptr<CellSpurs> spurs, vm::cptr<b8> isP
|
||||
}
|
||||
|
||||
/// Attach an LV2 event queue to a SPURS instance
|
||||
s32 cellSpursAttachLv2EventQueue(PPUThread& ppu, vm::ptr<CellSpurs> spurs, u32 queue, vm::ptr<u8> port, s32 isDynamic)
|
||||
s32 cellSpursAttachLv2EventQueue(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 queue, vm::ptr<u8> port, s32 isDynamic)
|
||||
{
|
||||
cellSpurs.warning("cellSpursAttachLv2EventQueue(spurs=*0x%x, queue=0x%x, port=*0x%x, isDynamic=%d)", spurs, queue, port, isDynamic);
|
||||
|
||||
@ -1810,7 +1816,7 @@ s32 cellSpursGetSpuGuid()
|
||||
// SPURS trace functions
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void _spurs::trace_status_update(PPUThread& ppu, vm::ptr<CellSpurs> spurs)
|
||||
void _spurs::trace_status_update(ppu_thread& ppu, vm::ptr<CellSpurs> spurs)
|
||||
{
|
||||
u8 init;
|
||||
|
||||
@ -1830,7 +1836,7 @@ void _spurs::trace_status_update(PPUThread& ppu, vm::ptr<CellSpurs> spurs)
|
||||
}
|
||||
}
|
||||
|
||||
s32 _spurs::trace_initialize(PPUThread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursTraceInfo> buffer, u32 size, u32 mode, u32 updateStatus)
|
||||
s32 _spurs::trace_initialize(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursTraceInfo> buffer, u32 size, u32 mode, u32 updateStatus)
|
||||
{
|
||||
if (!spurs || !buffer)
|
||||
{
|
||||
@ -1881,7 +1887,7 @@ s32 _spurs::trace_initialize(PPUThread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<C
|
||||
}
|
||||
|
||||
/// Initialize SPURS trace
|
||||
s32 cellSpursTraceInitialize(PPUThread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursTraceInfo> buffer, u32 size, u32 mode)
|
||||
s32 cellSpursTraceInitialize(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursTraceInfo> buffer, u32 size, u32 mode)
|
||||
{
|
||||
cellSpurs.warning("cellSpursTraceInitialize(spurs=*0x%x, buffer=*0x%x, size=0x%x, mode=0x%x)", spurs, buffer, size, mode);
|
||||
|
||||
@ -1894,7 +1900,7 @@ s32 cellSpursTraceInitialize(PPUThread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<C
|
||||
}
|
||||
|
||||
/// Finalize SPURS trace
|
||||
s32 cellSpursTraceFinalize(PPUThread& ppu, vm::ptr<CellSpurs> spurs)
|
||||
s32 cellSpursTraceFinalize(ppu_thread& ppu, vm::ptr<CellSpurs> spurs)
|
||||
{
|
||||
cellSpurs.warning("cellSpursTraceFinalize(spurs=*0x%x)", spurs);
|
||||
|
||||
@ -1922,7 +1928,7 @@ s32 cellSpursTraceFinalize(PPUThread& ppu, vm::ptr<CellSpurs> spurs)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _spurs::trace_start(PPUThread& ppu, vm::ptr<CellSpurs> spurs, u32 updateStatus)
|
||||
s32 _spurs::trace_start(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 updateStatus)
|
||||
{
|
||||
if (!spurs)
|
||||
{
|
||||
@ -1949,7 +1955,7 @@ s32 _spurs::trace_start(PPUThread& ppu, vm::ptr<CellSpurs> spurs, u32 updateStat
|
||||
}
|
||||
|
||||
/// Start SPURS trace
|
||||
s32 cellSpursTraceStart(PPUThread& ppu, vm::ptr<CellSpurs> spurs)
|
||||
s32 cellSpursTraceStart(ppu_thread& ppu, vm::ptr<CellSpurs> spurs)
|
||||
{
|
||||
cellSpurs.warning("cellSpursTraceStart(spurs=*0x%x)", spurs);
|
||||
|
||||
@ -1966,7 +1972,7 @@ s32 cellSpursTraceStart(PPUThread& ppu, vm::ptr<CellSpurs> spurs)
|
||||
return _spurs::trace_start(ppu, spurs, spurs->traceMode & CELL_SPURS_TRACE_MODE_FLAG_SYNCHRONOUS_START_STOP);
|
||||
}
|
||||
|
||||
s32 _spurs::trace_stop(PPUThread& ppu, vm::ptr<CellSpurs> spurs, u32 updateStatus)
|
||||
s32 _spurs::trace_stop(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 updateStatus)
|
||||
{
|
||||
if (!spurs)
|
||||
{
|
||||
@ -1993,7 +1999,7 @@ s32 _spurs::trace_stop(PPUThread& ppu, vm::ptr<CellSpurs> spurs, u32 updateStatu
|
||||
}
|
||||
|
||||
/// Stop SPURS trace
|
||||
s32 cellSpursTraceStop(PPUThread& ppu, vm::ptr<CellSpurs> spurs)
|
||||
s32 cellSpursTraceStop(ppu_thread& ppu, vm::ptr<CellSpurs> spurs)
|
||||
{
|
||||
cellSpurs.warning("cellSpursTraceStop(spurs=*0x%x)", spurs);
|
||||
|
||||
@ -2315,7 +2321,7 @@ s32 cellSpursRemoveWorkload()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSpursWakeUp(PPUThread& ppu, vm::ptr<CellSpurs> spurs)
|
||||
s32 cellSpursWakeUp(ppu_thread& ppu, vm::ptr<CellSpurs> spurs)
|
||||
{
|
||||
cellSpurs.warning("cellSpursWakeUp(spurs=*0x%x)", spurs);
|
||||
|
||||
@ -2692,7 +2698,7 @@ s32 cellSpursEventFlagClear(vm::ptr<CellSpursEventFlag> eventFlag, u16 bits)
|
||||
}
|
||||
|
||||
/// Set a SPURS event flag
|
||||
s32 cellSpursEventFlagSet(PPUThread& ppu, vm::ptr<CellSpursEventFlag> eventFlag, u16 bits)
|
||||
s32 cellSpursEventFlagSet(ppu_thread& ppu, vm::ptr<CellSpursEventFlag> eventFlag, u16 bits)
|
||||
{
|
||||
cellSpurs.warning("cellSpursEventFlagSet(eventFlag=*0x%x, bits=0x%x)", eventFlag, bits);
|
||||
|
||||
@ -2820,7 +2826,7 @@ s32 cellSpursEventFlagSet(PPUThread& ppu, vm::ptr<CellSpursEventFlag> eventFlag,
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _spurs::event_flag_wait(PPUThread& ppu, vm::ptr<CellSpursEventFlag> eventFlag, vm::ptr<u16> mask, u32 mode, u32 block)
|
||||
s32 _spurs::event_flag_wait(ppu_thread& ppu, vm::ptr<CellSpursEventFlag> eventFlag, vm::ptr<u16> mask, u32 mode, u32 block)
|
||||
{
|
||||
if (!eventFlag || !mask)
|
||||
{
|
||||
@ -2975,7 +2981,7 @@ s32 _spurs::event_flag_wait(PPUThread& ppu, vm::ptr<CellSpursEventFlag> eventFla
|
||||
}
|
||||
|
||||
/// Wait for SPURS event flag
|
||||
s32 cellSpursEventFlagWait(PPUThread& ppu, vm::ptr<CellSpursEventFlag> eventFlag, vm::ptr<u16> mask, u32 mode)
|
||||
s32 cellSpursEventFlagWait(ppu_thread& ppu, vm::ptr<CellSpursEventFlag> eventFlag, vm::ptr<u16> mask, u32 mode)
|
||||
{
|
||||
cellSpurs.warning("cellSpursEventFlagWait(eventFlag=*0x%x, mask=*0x%x, mode=%d)", eventFlag, mask, mode);
|
||||
|
||||
@ -2983,7 +2989,7 @@ s32 cellSpursEventFlagWait(PPUThread& ppu, vm::ptr<CellSpursEventFlag> eventFlag
|
||||
}
|
||||
|
||||
/// Check SPURS event flag
|
||||
s32 cellSpursEventFlagTryWait(PPUThread& ppu, vm::ptr<CellSpursEventFlag> eventFlag, vm::ptr<u16> mask, u32 mode)
|
||||
s32 cellSpursEventFlagTryWait(ppu_thread& ppu, vm::ptr<CellSpursEventFlag> eventFlag, vm::ptr<u16> mask, u32 mode)
|
||||
{
|
||||
cellSpurs.warning("cellSpursEventFlagTryWait(eventFlag=*0x%x, mask=*0x%x, mode=0x%x)", eventFlag, mask, mode);
|
||||
|
||||
@ -2991,7 +2997,7 @@ s32 cellSpursEventFlagTryWait(PPUThread& ppu, vm::ptr<CellSpursEventFlag> eventF
|
||||
}
|
||||
|
||||
/// Attach an LV2 event queue to a SPURS event flag
|
||||
s32 cellSpursEventFlagAttachLv2EventQueue(PPUThread& ppu, vm::ptr<CellSpursEventFlag> eventFlag)
|
||||
s32 cellSpursEventFlagAttachLv2EventQueue(ppu_thread& ppu, vm::ptr<CellSpursEventFlag> eventFlag)
|
||||
{
|
||||
cellSpurs.warning("cellSpursEventFlagAttachLv2EventQueue(eventFlag=*0x%x)", eventFlag);
|
||||
|
||||
@ -3300,7 +3306,7 @@ s32 cellSpursQueueGetDirection()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _spurs::create_taskset(PPUThread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursTaskset> taskset, u64 args, vm::cptr<u8[8]> priority, u32 max_contention, vm::cptr<char> name, u32 size, s32 enable_clear_ls)
|
||||
s32 _spurs::create_taskset(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursTaskset> taskset, u64 args, vm::cptr<u8[8]> priority, u32 max_contention, vm::cptr<char> name, u32 size, s32 enable_clear_ls)
|
||||
{
|
||||
if (!spurs || !taskset)
|
||||
{
|
||||
@ -3342,7 +3348,7 @@ s32 _spurs::create_taskset(PPUThread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<Cel
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSpursCreateTasksetWithAttribute(PPUThread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursTaskset> taskset, vm::ptr<CellSpursTasksetAttribute> attr)
|
||||
s32 cellSpursCreateTasksetWithAttribute(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursTaskset> taskset, vm::ptr<CellSpursTasksetAttribute> attr)
|
||||
{
|
||||
cellSpurs.warning("cellSpursCreateTasksetWithAttribute(spurs=*0x%x, taskset=*0x%x, attr=*0x%x)", spurs, taskset, attr);
|
||||
|
||||
@ -3371,7 +3377,7 @@ s32 cellSpursCreateTasksetWithAttribute(PPUThread& ppu, vm::ptr<CellSpurs> spurs
|
||||
return rc;
|
||||
}
|
||||
|
||||
s32 cellSpursCreateTaskset(PPUThread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursTaskset> taskset, u64 args, vm::cptr<u8[8]> priority, u32 maxContention)
|
||||
s32 cellSpursCreateTaskset(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursTaskset> taskset, u64 args, vm::cptr<u8[8]> priority, u32 maxContention)
|
||||
{
|
||||
cellSpurs.warning("cellSpursCreateTaskset(spurs=*0x%x, taskset=*0x%x, args=0x%llx, priority=*0x%x, maxContention=%d)", spurs, taskset, args, priority, maxContention);
|
||||
|
||||
@ -3513,7 +3519,7 @@ s32 _spurs::create_task(vm::ptr<CellSpursTaskset> taskset, vm::ptr<u32> task_id,
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _spurs::task_start(PPUThread& ppu, vm::ptr<CellSpursTaskset> taskset, u32 taskId)
|
||||
s32 _spurs::task_start(ppu_thread& ppu, vm::ptr<CellSpursTaskset> taskset, u32 taskId)
|
||||
{
|
||||
auto pendingReady = taskset->pending_ready.value();
|
||||
pendingReady._bit[taskId] = true;
|
||||
@ -3536,7 +3542,7 @@ s32 _spurs::task_start(PPUThread& ppu, vm::ptr<CellSpursTaskset> taskset, u32 ta
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSpursCreateTask(PPUThread& ppu, vm::ptr<CellSpursTaskset> taskset, vm::ptr<u32> taskId, vm::cptr<void> elf, vm::cptr<void> context, u32 size, vm::ptr<CellSpursTaskLsPattern> lsPattern, vm::ptr<CellSpursTaskArgument> argument)
|
||||
s32 cellSpursCreateTask(ppu_thread& ppu, vm::ptr<CellSpursTaskset> taskset, vm::ptr<u32> taskId, vm::cptr<void> elf, vm::cptr<void> context, u32 size, vm::ptr<CellSpursTaskLsPattern> lsPattern, vm::ptr<CellSpursTaskArgument> argument)
|
||||
{
|
||||
cellSpurs.warning("cellSpursCreateTask(taskset=*0x%x, taskID=*0x%x, elf=*0x%x, context=*0x%x, size=0x%x, lsPattern=*0x%x, argument=*0x%x)", taskset, taskId, elf, context, size, lsPattern, argument);
|
||||
|
||||
@ -3565,7 +3571,7 @@ s32 cellSpursCreateTask(PPUThread& ppu, vm::ptr<CellSpursTaskset> taskset, vm::p
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _cellSpursSendSignal(PPUThread& ppu, vm::ptr<CellSpursTaskset> taskset, u32 taskId)
|
||||
s32 _cellSpursSendSignal(ppu_thread& ppu, vm::ptr<CellSpursTaskset> taskset, u32 taskId)
|
||||
{
|
||||
if (!taskset)
|
||||
{
|
||||
@ -3768,7 +3774,7 @@ s32 cellSpursTaskGetContextSaveAreaSize()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSpursCreateTaskset2(PPUThread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursTaskset> taskset, vm::ptr<CellSpursTasksetAttribute2> attr)
|
||||
s32 cellSpursCreateTaskset2(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, vm::ptr<CellSpursTaskset> taskset, vm::ptr<CellSpursTasksetAttribute2> attr)
|
||||
{
|
||||
cellSpurs.warning("cellSpursCreateTaskset2(spurs=*0x%x, taskset=*0x%x, attr=*0x%x)", spurs, taskset, attr);
|
||||
|
||||
@ -3877,7 +3883,7 @@ s32 cellSpursTasksetUnsetExceptionEventHandler(vm::ptr<CellSpursTaskset> taskset
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSpursLookUpTasksetAddress(PPUThread& ppu, vm::ptr<CellSpurs> spurs, vm::pptr<CellSpursTaskset> taskset, u32 id)
|
||||
s32 cellSpursLookUpTasksetAddress(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, vm::pptr<CellSpursTaskset> taskset, u32 id)
|
||||
{
|
||||
cellSpurs.warning("cellSpursLookUpTasksetAddress(spurs=*0x%x, taskset=**0x%x, id=0x%x)", spurs, taskset, id);
|
||||
|
||||
|
@ -17,8 +17,6 @@
|
||||
|
||||
extern logs::channel cellSpurs;
|
||||
|
||||
extern std::mutex& get_current_thread_mutex();
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Function prototypes
|
||||
//----------------------------------------------------------------------------
|
||||
@ -774,7 +772,7 @@ void spursSysServiceIdleHandler(SPUThread& spu, SpursKernelContext* ctxt)
|
||||
{
|
||||
bool shouldExit;
|
||||
|
||||
std::unique_lock<std::mutex> lock(get_current_thread_mutex(), std::defer_lock);
|
||||
std::unique_lock<named_thread> lock(spu, std::defer_lock);
|
||||
|
||||
while (true)
|
||||
{
|
||||
@ -864,8 +862,8 @@ void spursSysServiceIdleHandler(SPUThread& spu, SpursKernelContext* ctxt)
|
||||
{
|
||||
// The system service blocks by making a reservation and waiting on the lock line reservation lost event.
|
||||
CHECK_EMU_STATUS;
|
||||
if (!lock) lock.lock();
|
||||
get_current_thread_cv().wait_for(lock, 1ms);
|
||||
if (!lock) { lock.lock(); continue; }
|
||||
thread_ctrl::wait_for(1000);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -820,7 +820,7 @@ ppu_error_code cellSyncLFQueueInitialize(vm::ptr<CellSyncLFQueue> queue, vm::cpt
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
ppu_error_code _cellSyncLFQueueGetPushPointer(PPUThread& ppu, vm::ptr<CellSyncLFQueue> queue, vm::ptr<s32> pointer, u32 isBlocking, u32 useEventQueue)
|
||||
ppu_error_code _cellSyncLFQueueGetPushPointer(ppu_thread& ppu, vm::ptr<CellSyncLFQueue> queue, vm::ptr<s32> pointer, u32 isBlocking, u32 useEventQueue)
|
||||
{
|
||||
cellSync.warning("_cellSyncLFQueueGetPushPointer(queue=*0x%x, pointer=*0x%x, isBlocking=%d, useEventQueue=%d)", queue, pointer, isBlocking, useEventQueue);
|
||||
|
||||
@ -913,7 +913,7 @@ ppu_error_code _cellSyncLFQueueGetPushPointer(PPUThread& ppu, vm::ptr<CellSyncLF
|
||||
}
|
||||
}
|
||||
|
||||
ppu_error_code _cellSyncLFQueueGetPushPointer2(PPUThread& ppu, vm::ptr<CellSyncLFQueue> queue, vm::ptr<s32> pointer, u32 isBlocking, u32 useEventQueue)
|
||||
ppu_error_code _cellSyncLFQueueGetPushPointer2(ppu_thread& ppu, vm::ptr<CellSyncLFQueue> queue, vm::ptr<s32> pointer, u32 isBlocking, u32 useEventQueue)
|
||||
{
|
||||
// arguments copied from _cellSyncLFQueueGetPushPointer
|
||||
cellSync.todo("_cellSyncLFQueueGetPushPointer2(queue=*0x%x, pointer=*0x%x, isBlocking=%d, useEventQueue=%d)", queue, pointer, isBlocking, useEventQueue);
|
||||
@ -921,7 +921,7 @@ ppu_error_code _cellSyncLFQueueGetPushPointer2(PPUThread& ppu, vm::ptr<CellSyncL
|
||||
throw EXCEPTION("");
|
||||
}
|
||||
|
||||
ppu_error_code _cellSyncLFQueueCompletePushPointer(PPUThread& ppu, vm::ptr<CellSyncLFQueue> queue, s32 pointer, vm::ptr<s32(u32 addr, u32 arg)> fpSendSignal)
|
||||
ppu_error_code _cellSyncLFQueueCompletePushPointer(ppu_thread& ppu, vm::ptr<CellSyncLFQueue> queue, s32 pointer, vm::ptr<s32(u32 addr, u32 arg)> fpSendSignal)
|
||||
{
|
||||
cellSync.warning("_cellSyncLFQueueCompletePushPointer(queue=*0x%x, pointer=%d, fpSendSignal=*0x%x)", queue, pointer, fpSendSignal);
|
||||
|
||||
@ -1053,7 +1053,7 @@ ppu_error_code _cellSyncLFQueueCompletePushPointer(PPUThread& ppu, vm::ptr<CellS
|
||||
}
|
||||
}
|
||||
|
||||
ppu_error_code _cellSyncLFQueueCompletePushPointer2(PPUThread& ppu, vm::ptr<CellSyncLFQueue> queue, s32 pointer, vm::ptr<s32(u32 addr, u32 arg)> fpSendSignal)
|
||||
ppu_error_code _cellSyncLFQueueCompletePushPointer2(ppu_thread& ppu, vm::ptr<CellSyncLFQueue> queue, s32 pointer, vm::ptr<s32(u32 addr, u32 arg)> fpSendSignal)
|
||||
{
|
||||
// arguments copied from _cellSyncLFQueueCompletePushPointer
|
||||
cellSync.todo("_cellSyncLFQueueCompletePushPointer2(queue=*0x%x, pointer=%d, fpSendSignal=*0x%x)", queue, pointer, fpSendSignal);
|
||||
@ -1061,7 +1061,7 @@ ppu_error_code _cellSyncLFQueueCompletePushPointer2(PPUThread& ppu, vm::ptr<Cell
|
||||
throw EXCEPTION("");
|
||||
}
|
||||
|
||||
ppu_error_code _cellSyncLFQueuePushBody(PPUThread& ppu, vm::ptr<CellSyncLFQueue> queue, vm::cptr<void> buffer, u32 isBlocking)
|
||||
ppu_error_code _cellSyncLFQueuePushBody(ppu_thread& ppu, vm::ptr<CellSyncLFQueue> queue, vm::cptr<void> buffer, u32 isBlocking)
|
||||
{
|
||||
// cellSyncLFQueuePush has 1 in isBlocking param, cellSyncLFQueueTryPush has 0
|
||||
cellSync.warning("_cellSyncLFQueuePushBody(queue=*0x%x, buffer=*0x%x, isBlocking=%d)", queue, buffer, isBlocking);
|
||||
@ -1119,7 +1119,7 @@ ppu_error_code _cellSyncLFQueuePushBody(PPUThread& ppu, vm::ptr<CellSyncLFQueue>
|
||||
}
|
||||
}
|
||||
|
||||
ppu_error_code _cellSyncLFQueueGetPopPointer(PPUThread& ppu, vm::ptr<CellSyncLFQueue> queue, vm::ptr<s32> pointer, u32 isBlocking, u32 arg4, u32 useEventQueue)
|
||||
ppu_error_code _cellSyncLFQueueGetPopPointer(ppu_thread& ppu, vm::ptr<CellSyncLFQueue> queue, vm::ptr<s32> pointer, u32 isBlocking, u32 arg4, u32 useEventQueue)
|
||||
{
|
||||
cellSync.warning("_cellSyncLFQueueGetPopPointer(queue=*0x%x, pointer=*0x%x, isBlocking=%d, arg4=%d, useEventQueue=%d)", queue, pointer, isBlocking, arg4, useEventQueue);
|
||||
|
||||
@ -1212,7 +1212,7 @@ ppu_error_code _cellSyncLFQueueGetPopPointer(PPUThread& ppu, vm::ptr<CellSyncLFQ
|
||||
}
|
||||
}
|
||||
|
||||
ppu_error_code _cellSyncLFQueueGetPopPointer2(PPUThread& ppu, vm::ptr<CellSyncLFQueue> queue, vm::ptr<s32> pointer, u32 isBlocking, u32 useEventQueue)
|
||||
ppu_error_code _cellSyncLFQueueGetPopPointer2(ppu_thread& ppu, vm::ptr<CellSyncLFQueue> queue, vm::ptr<s32> pointer, u32 isBlocking, u32 useEventQueue)
|
||||
{
|
||||
// arguments copied from _cellSyncLFQueueGetPopPointer
|
||||
cellSync.todo("_cellSyncLFQueueGetPopPointer2(queue=*0x%x, pointer=*0x%x, isBlocking=%d, useEventQueue=%d)", queue, pointer, isBlocking, useEventQueue);
|
||||
@ -1220,7 +1220,7 @@ ppu_error_code _cellSyncLFQueueGetPopPointer2(PPUThread& ppu, vm::ptr<CellSyncLF
|
||||
throw EXCEPTION("");
|
||||
}
|
||||
|
||||
ppu_error_code _cellSyncLFQueueCompletePopPointer(PPUThread& ppu, vm::ptr<CellSyncLFQueue> queue, s32 pointer, vm::ptr<s32(u32 addr, u32 arg)> fpSendSignal, u32 noQueueFull)
|
||||
ppu_error_code _cellSyncLFQueueCompletePopPointer(ppu_thread& ppu, vm::ptr<CellSyncLFQueue> queue, s32 pointer, vm::ptr<s32(u32 addr, u32 arg)> fpSendSignal, u32 noQueueFull)
|
||||
{
|
||||
// arguments copied from _cellSyncLFQueueCompletePushPointer + unknown argument (noQueueFull taken from LFQueue2CompletePopPointer)
|
||||
cellSync.warning("_cellSyncLFQueueCompletePopPointer(queue=*0x%x, pointer=%d, fpSendSignal=*0x%x, noQueueFull=%d)", queue, pointer, fpSendSignal, noQueueFull);
|
||||
@ -1352,7 +1352,7 @@ ppu_error_code _cellSyncLFQueueCompletePopPointer(PPUThread& ppu, vm::ptr<CellSy
|
||||
}
|
||||
}
|
||||
|
||||
ppu_error_code _cellSyncLFQueueCompletePopPointer2(PPUThread& ppu, vm::ptr<CellSyncLFQueue> queue, s32 pointer, vm::ptr<s32(u32 addr, u32 arg)> fpSendSignal, u32 noQueueFull)
|
||||
ppu_error_code _cellSyncLFQueueCompletePopPointer2(ppu_thread& ppu, vm::ptr<CellSyncLFQueue> queue, s32 pointer, vm::ptr<s32(u32 addr, u32 arg)> fpSendSignal, u32 noQueueFull)
|
||||
{
|
||||
// arguments copied from _cellSyncLFQueueCompletePopPointer
|
||||
cellSync.todo("_cellSyncLFQueueCompletePopPointer2(queue=*0x%x, pointer=%d, fpSendSignal=*0x%x, noQueueFull=%d)", queue, pointer, fpSendSignal, noQueueFull);
|
||||
@ -1360,7 +1360,7 @@ ppu_error_code _cellSyncLFQueueCompletePopPointer2(PPUThread& ppu, vm::ptr<CellS
|
||||
throw EXCEPTION("");
|
||||
}
|
||||
|
||||
ppu_error_code _cellSyncLFQueuePopBody(PPUThread& ppu, vm::ptr<CellSyncLFQueue> queue, vm::ptr<void> buffer, u32 isBlocking)
|
||||
ppu_error_code _cellSyncLFQueuePopBody(ppu_thread& ppu, vm::ptr<CellSyncLFQueue> queue, vm::ptr<void> buffer, u32 isBlocking)
|
||||
{
|
||||
// cellSyncLFQueuePop has 1 in isBlocking param, cellSyncLFQueueTryPop has 0
|
||||
cellSync.warning("_cellSyncLFQueuePopBody(queue=*0x%x, buffer=*0x%x, isBlocking=%d)", queue, buffer, isBlocking);
|
||||
|
@ -8,20 +8,40 @@
|
||||
|
||||
#include "Utilities/StrUtil.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
|
||||
logs::channel cellSysutil("cellSysutil", logs::level::notice);
|
||||
|
||||
// Temporarily
|
||||
using sys_callbacks_t = std::array<std::pair<vm::ptr<CellSysutilCallback>, vm::ptr<void>>, 4>;
|
||||
|
||||
void sysutilSendSystemCommand(u64 status, u64 param)
|
||||
struct sysutil_cb_manager
|
||||
{
|
||||
if (const auto g_sys_callback = fxm::get<sys_callbacks_t>())
|
||||
std::mutex mutex;
|
||||
|
||||
std::array<std::pair<vm::ptr<CellSysutilCallback>, vm::ptr<void>>, 4> callbacks;
|
||||
|
||||
std::queue<std::function<s32(ppu_thread&)>> registered;
|
||||
};
|
||||
|
||||
extern void sysutil_register_cb(std::function<s32(ppu_thread&)>&& cb)
|
||||
{
|
||||
const auto cbm = fxm::get_always<sysutil_cb_manager>();
|
||||
|
||||
std::lock_guard<std::mutex> lock(cbm->mutex);
|
||||
|
||||
cbm->registered.push(std::move(cb));
|
||||
}
|
||||
|
||||
extern void sysutil_send_system_cmd(u64 status, u64 param)
|
||||
{
|
||||
if (const auto cbm = fxm::get<sysutil_cb_manager>())
|
||||
{
|
||||
for (auto& cb : *g_sys_callback)
|
||||
for (auto& cb : cbm->callbacks)
|
||||
{
|
||||
if (cb.first)
|
||||
{
|
||||
Emu.GetCallbackManager().Register([=](PPUThread& ppu) -> s32
|
||||
std::lock_guard<std::mutex> lock(cbm->mutex);
|
||||
|
||||
cbm->registered.push([=](ppu_thread& ppu) -> s32
|
||||
{
|
||||
// TODO: check it and find the source of the return value (void isn't equal to CELL_OK)
|
||||
cb.first(ppu, status, param, cb.second);
|
||||
@ -196,15 +216,26 @@ s32 cellSysutilGetSystemParamString(s32 id, vm::ptr<char> buf, u32 bufsize)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSysutilCheckCallback(PPUThread& CPU)
|
||||
s32 cellSysutilCheckCallback(ppu_thread& ppu)
|
||||
{
|
||||
cellSysutil.trace("cellSysutilCheckCallback()");
|
||||
|
||||
while (auto func = Emu.GetCallbackManager().Check())
|
||||
{
|
||||
CHECK_EMU_STATUS;
|
||||
const auto cbm = fxm::get_always<sysutil_cb_manager>();
|
||||
|
||||
if (s32 res = func(CPU))
|
||||
while (true)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(cbm->mutex);
|
||||
|
||||
if (cbm->registered.empty())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
const auto func = std::move(cbm->registered.front());
|
||||
|
||||
cbm->registered.pop();
|
||||
|
||||
if (s32 res = func(ppu))
|
||||
{
|
||||
return res;
|
||||
}
|
||||
@ -217,12 +248,15 @@ s32 cellSysutilRegisterCallback(s32 slot, vm::ptr<CellSysutilCallback> func, vm:
|
||||
{
|
||||
cellSysutil.warning("cellSysutilRegisterCallback(slot=%d, func=*0x%x, userdata=*0x%x)", slot, func, userdata);
|
||||
|
||||
if (slot >= sys_callbacks_t{}.size())
|
||||
if (slot >= 4)
|
||||
{
|
||||
return CELL_SYSUTIL_ERROR_VALUE;
|
||||
}
|
||||
|
||||
fxm::get_always<sys_callbacks_t>()->at(slot) = std::make_pair(func, userdata);
|
||||
const auto cbm = fxm::get_always<sysutil_cb_manager>();
|
||||
|
||||
cbm->callbacks[slot] = std::make_pair(func, userdata);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -230,12 +264,15 @@ s32 cellSysutilUnregisterCallback(u32 slot)
|
||||
{
|
||||
cellSysutil.warning("cellSysutilUnregisterCallback(slot=%d)", slot);
|
||||
|
||||
if (slot >= sys_callbacks_t{}.size())
|
||||
if (slot >= 4)
|
||||
{
|
||||
return CELL_SYSUTIL_ERROR_VALUE;
|
||||
}
|
||||
|
||||
fxm::get_always<sys_callbacks_t>()->at(slot) = std::make_pair(vm::null, vm::null);
|
||||
const auto cbm = fxm::get_always<sysutil_cb_manager>();
|
||||
|
||||
cbm->callbacks[slot] = std::make_pair(vm::null, vm::null);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
@ -195,4 +195,5 @@ struct CellSysCacheParam
|
||||
vm::ptr<void> reserved;
|
||||
};
|
||||
|
||||
extern void sysutilSendSystemCommand(u64 status, u64 param);
|
||||
extern void sysutil_register_cb(std::function<s32(ppu_thread&)>&&);
|
||||
extern void sysutil_send_system_cmd(u64 status, u64 param);
|
||||
|
@ -3,8 +3,6 @@
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
|
||||
std::mutex g_mutex_avcodec_open2;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "libavcodec/avcodec.h"
|
||||
@ -15,200 +13,213 @@ extern "C"
|
||||
#include "cellPamf.h"
|
||||
#include "cellVdec.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <queue>
|
||||
|
||||
std::mutex g_mutex_avcodec_open2;
|
||||
|
||||
logs::channel cellVdec("cellVdec", logs::level::notice);
|
||||
|
||||
vm::gvar<s32> _cell_vdec_prx_ver; // ???
|
||||
|
||||
VideoDecoder::VideoDecoder(s32 type, u32 profile, u32 addr, u32 size, vm::ptr<CellVdecCbMsg> func, u32 arg)
|
||||
: type(type)
|
||||
, profile(profile)
|
||||
, memAddr(addr)
|
||||
, memSize(size)
|
||||
, memBias(0)
|
||||
, cbFunc(func)
|
||||
, cbArg(arg)
|
||||
, is_finished(false)
|
||||
, is_closed(false)
|
||||
, frc_set(0)
|
||||
, codec(nullptr)
|
||||
, ctx(nullptr)
|
||||
enum class vdec_cmd : u32
|
||||
{
|
||||
avcodec_register_all();
|
||||
none = 0,
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case CELL_VDEC_CODEC_TYPE_MPEG2:
|
||||
{
|
||||
codec = avcodec_find_decoder(AV_CODEC_ID_MPEG2VIDEO);
|
||||
break;
|
||||
}
|
||||
case CELL_VDEC_CODEC_TYPE_AVC:
|
||||
{
|
||||
codec = avcodec_find_decoder(AV_CODEC_ID_H264);
|
||||
break;
|
||||
}
|
||||
case CELL_VDEC_CODEC_TYPE_DIVX:
|
||||
{
|
||||
codec = avcodec_find_decoder(AV_CODEC_ID_MPEG4);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw fmt::exception("Unknown video decoder type (0x%x)" HERE, type);
|
||||
}
|
||||
}
|
||||
start_seq,
|
||||
end_seq,
|
||||
decode,
|
||||
set_frc,
|
||||
close,
|
||||
};
|
||||
|
||||
if (!codec)
|
||||
{
|
||||
throw fmt::exception("avcodec_find_decoder() failed (type=0x%x)" HERE, type);
|
||||
}
|
||||
|
||||
ctx = avcodec_alloc_context3(codec);
|
||||
|
||||
if (!ctx)
|
||||
{
|
||||
throw fmt::exception("avcodec_alloc_context3() failed (type=0x%x)" HERE, type);
|
||||
}
|
||||
|
||||
AVDictionary* opts{};
|
||||
av_dict_set(&opts, "refcounted_frames", "1", 0);
|
||||
|
||||
std::lock_guard<std::mutex> lock(g_mutex_avcodec_open2);
|
||||
|
||||
int err = avcodec_open2(ctx, codec, &opts);
|
||||
if (err || opts)
|
||||
{
|
||||
throw fmt::exception("avcodec_open2() failed (err=0x%x, opts=%d)" HERE, err, opts ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
VideoDecoder::~VideoDecoder()
|
||||
struct vdec_frame
|
||||
{
|
||||
VdecFrame vf;
|
||||
while (frames.try_pop(vf))
|
||||
struct frame_dtor
|
||||
{
|
||||
av_frame_unref(vf.data);
|
||||
av_frame_free(&vf.data);
|
||||
void operator()(AVFrame* data) const
|
||||
{
|
||||
av_frame_unref(data);
|
||||
av_frame_free(&data);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<AVFrame, frame_dtor> avf;
|
||||
u64 dts;
|
||||
u64 pts;
|
||||
u64 userdata;
|
||||
u32 frc;
|
||||
|
||||
AVFrame* operator ->() const
|
||||
{
|
||||
return avf.get();
|
||||
}
|
||||
};
|
||||
|
||||
struct vdec_thread : ppu_thread
|
||||
{
|
||||
AVCodec* codec{};
|
||||
AVCodecContext* ctx{};
|
||||
|
||||
const s32 type;
|
||||
const u32 profile;
|
||||
const u32 mem_addr;
|
||||
const u32 mem_size;
|
||||
const vm::ptr<CellVdecCbMsg> cb_func;
|
||||
const u32 cb_arg;
|
||||
u32 mem_bias{};
|
||||
|
||||
u32 frc_set{}; // Frame Rate Override
|
||||
u64 last_pts{};
|
||||
u64 last_dts{};
|
||||
|
||||
std::queue<vdec_frame> out;
|
||||
std::queue<u64> user_data; // TODO
|
||||
|
||||
vdec_thread(s32 type, u32 profile, u32 addr, u32 size, vm::ptr<CellVdecCbMsg> func, u32 arg)
|
||||
: ppu_thread("HLE Video Decoder")
|
||||
, type(type)
|
||||
, profile(profile)
|
||||
, mem_addr(addr)
|
||||
, mem_size(size)
|
||||
, cb_func(func)
|
||||
, cb_arg(arg)
|
||||
{
|
||||
avcodec_register_all();
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case CELL_VDEC_CODEC_TYPE_MPEG2:
|
||||
{
|
||||
codec = avcodec_find_decoder(AV_CODEC_ID_MPEG2VIDEO);
|
||||
break;
|
||||
}
|
||||
case CELL_VDEC_CODEC_TYPE_AVC:
|
||||
{
|
||||
codec = avcodec_find_decoder(AV_CODEC_ID_H264);
|
||||
break;
|
||||
}
|
||||
case CELL_VDEC_CODEC_TYPE_DIVX:
|
||||
{
|
||||
codec = avcodec_find_decoder(AV_CODEC_ID_MPEG4);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw fmt::exception("Unknown video decoder type (0x%x)" HERE, type);
|
||||
}
|
||||
}
|
||||
|
||||
if (!codec)
|
||||
{
|
||||
throw fmt::exception("avcodec_find_decoder() failed (type=0x%x)" HERE, type);
|
||||
}
|
||||
|
||||
ctx = avcodec_alloc_context3(codec);
|
||||
|
||||
if (!ctx)
|
||||
{
|
||||
throw fmt::exception("avcodec_alloc_context3() failed (type=0x%x)" HERE, type);
|
||||
}
|
||||
|
||||
AVDictionary* opts{};
|
||||
av_dict_set(&opts, "refcounted_frames", "1", 0);
|
||||
|
||||
std::lock_guard<std::mutex> lock(g_mutex_avcodec_open2);
|
||||
|
||||
int err = avcodec_open2(ctx, codec, &opts);
|
||||
if (err || opts)
|
||||
{
|
||||
avcodec_free_context(&ctx);
|
||||
throw fmt::exception("avcodec_open2() failed (err=0x%x, opts=%d)" HERE, err, opts ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx)
|
||||
virtual ~vdec_thread() override
|
||||
{
|
||||
avcodec_close(ctx);
|
||||
avcodec_free_context(&ctx);
|
||||
}
|
||||
}
|
||||
|
||||
u32 vdecQueryAttr(s32 type, u32 profile, u32 spec_addr /* may be 0 */, vm::ptr<CellVdecAttr> attr)
|
||||
{
|
||||
switch (type) // TODO: check profile levels
|
||||
virtual std::string dump() const override
|
||||
{
|
||||
case CELL_VDEC_CODEC_TYPE_AVC: cellVdec.warning("cellVdecQueryAttr: AVC (profile=%d)", profile); 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;
|
||||
// TODO
|
||||
return ppu_thread::dump();
|
||||
}
|
||||
|
||||
// TODO: check values
|
||||
attr->decoderVerLower = 0x280000; // from dmux
|
||||
attr->decoderVerUpper = 0x260000;
|
||||
attr->memSize = 4 * 1024 * 1024; // 4 MB
|
||||
attr->cmdDepth = 16;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
void vdecOpen(u32 vdec_id) // TODO: call from the constructor
|
||||
{
|
||||
const auto sptr = idm::get<VideoDecoder>(vdec_id);
|
||||
|
||||
VideoDecoder& vdec = *sptr;
|
||||
|
||||
vdec.id = vdec_id;
|
||||
|
||||
vdec.vdecCb = idm::make_ptr<PPUThread>(fmt::format("VideoDecoder[0x%x] Thread", vdec_id));
|
||||
vdec.vdecCb->prio = 1001;
|
||||
vdec.vdecCb->stack_size = 0x10000;
|
||||
vdec.vdecCb->custom_task = [sptr](PPUThread& ppu)
|
||||
virtual void cpu_task() override
|
||||
{
|
||||
VideoDecoder& vdec = *sptr;
|
||||
VdecTask& task = vdec.task;
|
||||
|
||||
while (true)
|
||||
while (ppu_cmd cmd = cmd_wait())
|
||||
{
|
||||
if (Emu.IsStopped() || vdec.is_closed)
|
||||
switch (vdec_cmd vcmd = cmd.arg1<vdec_cmd>())
|
||||
{
|
||||
case vdec_cmd::start_seq:
|
||||
{
|
||||
cmd_pop();
|
||||
avcodec_flush_buffers(ctx);
|
||||
|
||||
frc_set = 0; // TODO: ???
|
||||
last_pts = 0;
|
||||
last_dts = 0;
|
||||
cellVdec.trace("Start sequence...");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!vdec.job.pop(task, &vdec.is_closed))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
switch (task.type)
|
||||
{
|
||||
case vdecStartSeq:
|
||||
{
|
||||
cellVdec.warning("vdecStartSeq:");
|
||||
avcodec_flush_buffers(vdec.ctx);
|
||||
|
||||
vdec.frc_set = 0; // TODO: ???
|
||||
vdec.last_pts = 0;
|
||||
vdec.last_dts = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case vdecDecodeAu:
|
||||
case vdecEndSeq:
|
||||
case vdec_cmd::decode:
|
||||
case vdec_cmd::end_seq:
|
||||
{
|
||||
AVPacket packet{};
|
||||
packet.pos = -1;
|
||||
|
||||
if (task.type == vdecDecodeAu)
|
||||
u32 au_type{};
|
||||
u32 au_addr{};
|
||||
u32 au_size{};
|
||||
u64 au_pts{};
|
||||
u64 au_dts{};
|
||||
u64 au_usrd{};
|
||||
u64 au_spec{};
|
||||
|
||||
if (vcmd == vdec_cmd::decode)
|
||||
{
|
||||
packet.pts = vdec.task.pts != -1 ? vdec.task.pts : AV_NOPTS_VALUE;
|
||||
packet.dts = vdec.task.dts != -1 ? vdec.task.dts : AV_NOPTS_VALUE;
|
||||
packet.data = vm::_ptr<u8>(vdec.task.addr);
|
||||
packet.size = vdec.task.size;
|
||||
cellVdec.trace("vdecDecodeAu: size = 0x%x, pts = 0x%llx, dts = 0x%llx", task.size, task.pts, task.dts);
|
||||
const u32 pos = cmd_queue.peek();
|
||||
au_type = cmd.arg2<u32>(); // TODO
|
||||
au_addr = cmd_queue[pos + 1].load().arg1<u32>();
|
||||
au_size = cmd_queue[pos + 1].load().arg2<u32>();
|
||||
au_pts = cmd_queue[pos + 2].load().as<u64>();
|
||||
au_dts = cmd_queue[pos + 3].load().as<u64>();
|
||||
au_usrd = cmd_queue[pos + 4].load().as<u64>(); // TODO
|
||||
au_spec = cmd_queue[pos + 5].load().as<u64>(); // TODO
|
||||
cmd_pop(5);
|
||||
|
||||
packet.data = vm::_ptr<u8>(au_addr);
|
||||
packet.size = au_size;
|
||||
packet.pts = au_pts != -1 ? au_pts : AV_NOPTS_VALUE;
|
||||
packet.dts = au_dts != -1 ? au_dts : AV_NOPTS_VALUE;
|
||||
cellVdec.trace("AU decoding: size=0x%x, pts=0x%llx, dts=0x%llx, userdata=0x%llx", au_size, au_pts, au_dts, au_usrd);
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd_pop();
|
||||
|
||||
packet.pts = AV_NOPTS_VALUE;
|
||||
packet.dts = AV_NOPTS_VALUE;
|
||||
packet.data = nullptr;
|
||||
packet.size = 0;
|
||||
cellVdec.warning("vdecEndSeq");
|
||||
cellVdec.trace("End sequence...");
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
struct VdecFrameHolder : VdecFrame
|
||||
{
|
||||
VdecFrameHolder()
|
||||
{
|
||||
data = av_frame_alloc();
|
||||
}
|
||||
vdec_frame frame;
|
||||
frame.avf.reset(av_frame_alloc());
|
||||
|
||||
~VdecFrameHolder()
|
||||
{
|
||||
if (data)
|
||||
{
|
||||
av_frame_unref(data);
|
||||
av_frame_free(&data);
|
||||
}
|
||||
}
|
||||
|
||||
} frame;
|
||||
|
||||
if (!frame.data)
|
||||
if (!frame.avf)
|
||||
{
|
||||
throw fmt::exception("av_frame_alloc() failed" HERE);
|
||||
}
|
||||
|
||||
int got_picture = 0;
|
||||
|
||||
int decode = avcodec_decode_video2(vdec.ctx, frame.data, &got_picture, &packet);
|
||||
int decode = avcodec_decode_video2(ctx, frame.avf.get(), &got_picture, &packet);
|
||||
|
||||
if (decode < 0)
|
||||
{
|
||||
@ -227,21 +238,21 @@ void vdecOpen(u32 vdec_id) // TODO: call from the constructor
|
||||
|
||||
if (got_picture)
|
||||
{
|
||||
if (frame.data->interlaced_frame)
|
||||
if (frame->interlaced_frame)
|
||||
{
|
||||
throw EXCEPTION("Interlaced frames not supported (0x%x)", frame.data->interlaced_frame);
|
||||
throw fmt::exception("Interlaced frames not supported (0x%x)", frame->interlaced_frame);
|
||||
}
|
||||
|
||||
if (frame.data->repeat_pict)
|
||||
if (frame->repeat_pict)
|
||||
{
|
||||
throw EXCEPTION("Repeated frames not supported (0x%x)", frame.data->repeat_pict);
|
||||
throw fmt::exception("Repeated frames not supported (0x%x)", frame->repeat_pict);
|
||||
}
|
||||
|
||||
if (vdec.frc_set)
|
||||
if (frc_set)
|
||||
{
|
||||
u64 amend = 0;
|
||||
|
||||
switch (vdec.frc_set)
|
||||
switch (frc_set)
|
||||
{
|
||||
case CELL_VDEC_FRC_24000DIV1001: amend = 1001 * 90000 / 24000; break;
|
||||
case CELL_VDEC_FRC_24: amend = 90000 / 24; break;
|
||||
@ -253,23 +264,23 @@ void vdecOpen(u32 vdec_id) // TODO: call from the constructor
|
||||
case CELL_VDEC_FRC_60: amend = 90000 / 60; break;
|
||||
default:
|
||||
{
|
||||
throw EXCEPTION("Invalid frame rate code set (0x%x)", vdec.frc_set);
|
||||
throw EXCEPTION("Invalid frame rate code set (0x%x)", frc_set);
|
||||
}
|
||||
}
|
||||
|
||||
vdec.last_pts += amend;
|
||||
vdec.last_dts += amend;
|
||||
frame.frc = vdec.frc_set;
|
||||
last_pts += amend;
|
||||
last_dts += amend;
|
||||
frame.frc = frc_set;
|
||||
}
|
||||
else
|
||||
{
|
||||
const u64 amend = vdec.ctx->time_base.num * 90000 * vdec.ctx->ticks_per_frame / vdec.ctx->time_base.den;
|
||||
vdec.last_pts += amend;
|
||||
vdec.last_dts += amend;
|
||||
const u64 amend = ctx->time_base.num * 90000 * ctx->ticks_per_frame / ctx->time_base.den;
|
||||
last_pts += amend;
|
||||
last_dts += amend;
|
||||
|
||||
if (vdec.ctx->time_base.num == 1)
|
||||
if (ctx->time_base.num == 1)
|
||||
{
|
||||
switch ((u64)vdec.ctx->time_base.den + (u64)(vdec.ctx->ticks_per_frame - 1) * 0x100000000ull)
|
||||
switch ((u64)ctx->time_base.den + (u64)(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;
|
||||
@ -278,91 +289,95 @@ void vdecOpen(u32 vdec_id) // TODO: call from the constructor
|
||||
case 60: case 0x100000000ull + 120: frame.frc = CELL_VDEC_FRC_60; break;
|
||||
default:
|
||||
{
|
||||
throw EXCEPTION("Unsupported time_base.den (%d/1, tpf=%d)", vdec.ctx->time_base.den, vdec.ctx->ticks_per_frame);
|
||||
throw EXCEPTION("Unsupported time_base.den (%d/1, tpf=%d)", ctx->time_base.den, ctx->ticks_per_frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (vdec.ctx->time_base.num == 1001)
|
||||
else if (ctx->time_base.num == 1001)
|
||||
{
|
||||
if (vdec.ctx->time_base.den / vdec.ctx->ticks_per_frame == 24000)
|
||||
if (ctx->time_base.den / ctx->ticks_per_frame == 24000)
|
||||
{
|
||||
frame.frc = CELL_VDEC_FRC_24000DIV1001;
|
||||
}
|
||||
else if (vdec.ctx->time_base.den / vdec.ctx->ticks_per_frame == 30000)
|
||||
else if (ctx->time_base.den / ctx->ticks_per_frame == 30000)
|
||||
{
|
||||
frame.frc = CELL_VDEC_FRC_30000DIV1001;
|
||||
}
|
||||
else if (vdec.ctx->time_base.den / vdec.ctx->ticks_per_frame == 60000)
|
||||
else if (ctx->time_base.den / ctx->ticks_per_frame == 60000)
|
||||
{
|
||||
frame.frc = CELL_VDEC_FRC_60000DIV1001;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw EXCEPTION("Unsupported time_base.den (%d/1001, tpf=%d)", vdec.ctx->time_base.den, vdec.ctx->ticks_per_frame);
|
||||
throw EXCEPTION("Unsupported time_base.den (%d/1001, tpf=%d)", ctx->time_base.den, ctx->ticks_per_frame);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw EXCEPTION("Unsupported time_base.num (%d)", vdec.ctx->time_base.num);
|
||||
throw EXCEPTION("Unsupported time_base.num (%d)", ctx->time_base.num);
|
||||
}
|
||||
}
|
||||
|
||||
frame.pts = vdec.last_pts = frame.data->pkt_pts != AV_NOPTS_VALUE ? frame.data->pkt_pts : vdec.last_pts;
|
||||
frame.dts = vdec.last_dts = frame.data->pkt_dts != AV_NOPTS_VALUE ? frame.data->pkt_dts : vdec.last_dts;
|
||||
frame.userdata = task.userData;
|
||||
frame.pts = last_pts = frame->pkt_pts != AV_NOPTS_VALUE ? frame->pkt_pts : last_pts;
|
||||
frame.dts = last_dts = frame->pkt_dts != AV_NOPTS_VALUE ? frame->pkt_dts : last_dts;
|
||||
frame.userdata = au_usrd;
|
||||
|
||||
cellVdec.trace("got picture (pts=0x%llx, dts=0x%llx)", frame.pts, frame.dts);
|
||||
|
||||
if (vdec.frames.push(frame, &vdec.is_closed))
|
||||
{
|
||||
frame.data = nullptr; // to prevent destruction
|
||||
vdec.cbFunc(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_PICOUT, CELL_OK, vdec.cbArg);
|
||||
}
|
||||
thread_lock{*this}, out.push(std::move(frame));
|
||||
|
||||
cb_func(*this, id, CELL_VDEC_MSG_TYPE_PICOUT, CELL_OK, cb_arg);
|
||||
}
|
||||
|
||||
if (task.type == vdecDecodeAu)
|
||||
if (vcmd == vdec_cmd::decode)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (task.type == vdecDecodeAu)
|
||||
{
|
||||
vdec.cbFunc(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_AUDONE, CELL_OK, vdec.cbArg);
|
||||
}
|
||||
else
|
||||
{
|
||||
vdec.cbFunc(*vdec.vdecCb, vdec.id, CELL_VDEC_MSG_TYPE_SEQDONE, CELL_OK, vdec.cbArg);
|
||||
}
|
||||
|
||||
cb_func(*this, id, vcmd == vdec_cmd::decode ? CELL_VDEC_MSG_TYPE_AUDONE : CELL_VDEC_MSG_TYPE_SEQDONE, CELL_OK, cb_arg);
|
||||
break;
|
||||
}
|
||||
|
||||
case vdecSetFrameRate:
|
||||
case vdec_cmd::set_frc:
|
||||
{
|
||||
cellVdec.warning("vdecSetFrameRate(0x%x)", task.frc);
|
||||
vdec.frc_set = task.frc;
|
||||
cmd_pop();
|
||||
frc_set = cmd.arg2<u32>();
|
||||
break;
|
||||
}
|
||||
|
||||
case vdecClose:
|
||||
case vdec_cmd::close:
|
||||
{
|
||||
break;
|
||||
cmd_pop();
|
||||
state += cpu_state::exit;
|
||||
return;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
throw fmt::exception("Unknown task(%d)" HERE, task.type);
|
||||
throw fmt::exception("Unknown command (0x%x)" HERE, vcmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
vdec.is_finished = true;
|
||||
};
|
||||
u32 vdecQueryAttr(s32 type, u32 profile, u32 spec_addr /* may be 0 */, vm::ptr<CellVdecAttr> attr)
|
||||
{
|
||||
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.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;
|
||||
}
|
||||
|
||||
vdec.vdecCb->cpu_init();
|
||||
vdec.vdecCb->state -= cpu_state::stop;
|
||||
(*vdec.vdecCb)->lock_notify();
|
||||
// TODO: check values
|
||||
attr->decoderVerLower = 0x280000; // from dmux
|
||||
attr->decoderVerUpper = 0x260000;
|
||||
attr->memSize = 4 * 1024 * 1024; // 4 MB
|
||||
attr->cmdDepth = 16;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellVdecQueryAttr(vm::cptr<CellVdecType> type, vm::ptr<CellVdecAttr> attr)
|
||||
@ -383,7 +398,13 @@ s32 cellVdecOpen(vm::cptr<CellVdecType> type, vm::cptr<CellVdecResource> res, vm
|
||||
{
|
||||
cellVdec.warning("cellVdecOpen(type=*0x%x, res=*0x%x, cb=*0x%x, handle=*0x%x)", type, res, cb, handle);
|
||||
|
||||
vdecOpen(*handle = idm::make<VideoDecoder>(type->codecType, type->profileLevel, res->memAddr, res->memSize, cb->cbFunc, cb->cbArg));
|
||||
// Create decoder thread
|
||||
auto&& vdec = std::make_shared<vdec_thread>(type->codecType, type->profileLevel, res->memAddr, res->memSize, cb->cbFunc, cb->cbArg);
|
||||
|
||||
// Hack: store thread id (normally it should be pointer)
|
||||
*handle = idm::import_existing<ppu_thread>(vdec);
|
||||
|
||||
vdec->run();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -392,7 +413,13 @@ s32 cellVdecOpenEx(vm::cptr<CellVdecTypeEx> type, vm::cptr<CellVdecResourceEx> r
|
||||
{
|
||||
cellVdec.warning("cellVdecOpenEx(type=*0x%x, res=*0x%x, cb=*0x%x, handle=*0x%x)", type, res, cb, handle);
|
||||
|
||||
vdecOpen(*handle = idm::make<VideoDecoder>(type->codecType, type->profileLevel, res->memAddr, res->memSize, cb->cbFunc, cb->cbArg));
|
||||
// Create decoder thread
|
||||
auto&& vdec = std::make_shared<vdec_thread>(type->codecType, type->profileLevel, res->memAddr, res->memSize, cb->cbFunc, cb->cbArg);
|
||||
|
||||
// Hack: store thread id (normally it should be pointer)
|
||||
*handle = idm::import_existing<ppu_thread>(vdec);
|
||||
|
||||
vdec->run();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -401,25 +428,17 @@ s32 cellVdecClose(u32 handle)
|
||||
{
|
||||
cellVdec.warning("cellVdecClose(handle=0x%x)", handle);
|
||||
|
||||
const auto vdec = idm::get<VideoDecoder>(handle);
|
||||
const auto vdec = std::dynamic_pointer_cast<vdec_thread>(idm::get<ppu_thread>(handle)); // TODO: avoid RTTI
|
||||
|
||||
if (!vdec)
|
||||
{
|
||||
return CELL_VDEC_ERROR_ARG;
|
||||
}
|
||||
|
||||
vdec->is_closed = true;
|
||||
vdec->job.try_push(VdecTask(vdecClose));
|
||||
|
||||
while (!vdec->is_finished)
|
||||
{
|
||||
CHECK_EMU_STATUS;
|
||||
|
||||
std::this_thread::sleep_for(1ms); // hack
|
||||
}
|
||||
|
||||
idm::remove<PPUThread>(vdec->vdecCb->id);
|
||||
idm::remove<VideoDecoder>(handle);
|
||||
vdec->cmd_push({vdec_cmd::close, 0});
|
||||
vdec->lock_notify();
|
||||
vdec->join();
|
||||
idm::remove<ppu_thread>(handle);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -427,14 +446,15 @@ s32 cellVdecStartSeq(u32 handle)
|
||||
{
|
||||
cellVdec.trace("cellVdecStartSeq(handle=0x%x)", handle);
|
||||
|
||||
const auto vdec = idm::get<VideoDecoder>(handle);
|
||||
const auto vdec = std::dynamic_pointer_cast<vdec_thread>(idm::get<ppu_thread>(handle)); // TODO: avoid RTTI
|
||||
|
||||
if (!vdec)
|
||||
{
|
||||
return CELL_VDEC_ERROR_ARG;
|
||||
}
|
||||
|
||||
vdec->job.push(VdecTask(vdecStartSeq), &vdec->is_closed);
|
||||
vdec->cmd_push({vdec_cmd::start_seq, 0});
|
||||
vdec->lock_notify();
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -442,14 +462,15 @@ s32 cellVdecEndSeq(u32 handle)
|
||||
{
|
||||
cellVdec.warning("cellVdecEndSeq(handle=0x%x)", handle);
|
||||
|
||||
const auto vdec = idm::get<VideoDecoder>(handle);
|
||||
const auto vdec = std::dynamic_pointer_cast<vdec_thread>(idm::get<ppu_thread>(handle)); // TODO: avoid RTTI
|
||||
|
||||
if (!vdec)
|
||||
{
|
||||
return CELL_VDEC_ERROR_ARG;
|
||||
}
|
||||
|
||||
vdec->job.push(VdecTask(vdecEndSeq), &vdec->is_closed);
|
||||
vdec->cmd_push({vdec_cmd::end_seq, 0});
|
||||
vdec->lock_notify();
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -457,9 +478,9 @@ s32 cellVdecDecodeAu(u32 handle, CellVdecDecodeMode mode, vm::cptr<CellVdecAuInf
|
||||
{
|
||||
cellVdec.trace("cellVdecDecodeAu(handle=0x%x, mode=%d, auInfo=*0x%x)", handle, mode, auInfo);
|
||||
|
||||
const auto vdec = idm::get<VideoDecoder>(handle);
|
||||
const auto vdec = std::dynamic_pointer_cast<vdec_thread>(idm::get<ppu_thread>(handle)); // TODO: avoid RTTI
|
||||
|
||||
if (!vdec || mode > CELL_VDEC_DEC_MODE_PB_SKIP)
|
||||
if (mode > CELL_VDEC_DEC_MODE_PB_SKIP || !vdec)
|
||||
{
|
||||
return CELL_VDEC_ERROR_ARG;
|
||||
}
|
||||
@ -470,16 +491,17 @@ s32 cellVdecDecodeAu(u32 handle, CellVdecDecodeMode mode, vm::cptr<CellVdecAuInf
|
||||
}
|
||||
|
||||
// TODO: check info
|
||||
VdecTask task(vdecDecodeAu);
|
||||
task.mode = mode;
|
||||
task.addr = auInfo->startAddr;
|
||||
task.size = auInfo->size;
|
||||
task.dts = (u64)auInfo->dts.lower | ((u64)auInfo->dts.upper << 32);
|
||||
task.pts = (u64)auInfo->pts.lower | ((u64)auInfo->pts.upper << 32);
|
||||
task.userData = auInfo->userData;
|
||||
task.specData = auInfo->codecSpecificData;
|
||||
vdec->cmd_list
|
||||
({
|
||||
{ vdec_cmd::decode, mode },
|
||||
{ auInfo->startAddr, auInfo->size },
|
||||
u64{auInfo->pts.upper} << 32 | auInfo->pts.lower,
|
||||
u64{auInfo->dts.upper} << 32 | auInfo->dts.lower,
|
||||
auInfo->userData,
|
||||
auInfo->codecSpecificData,
|
||||
});
|
||||
|
||||
vdec->job.push(task, &vdec->is_closed);
|
||||
vdec->lock_notify();
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@ -487,39 +509,35 @@ s32 cellVdecGetPicture(u32 handle, vm::cptr<CellVdecPicFormat> format, vm::ptr<u
|
||||
{
|
||||
cellVdec.trace("cellVdecGetPicture(handle=0x%x, format=*0x%x, outBuff=*0x%x)", handle, format, outBuff);
|
||||
|
||||
const auto vdec = idm::get<VideoDecoder>(handle);
|
||||
const auto vdec = std::dynamic_pointer_cast<vdec_thread>(idm::get<ppu_thread>(handle)); // TODO: avoid RTTI
|
||||
|
||||
if (!vdec || !format)
|
||||
if (!format || !vdec)
|
||||
{
|
||||
return CELL_VDEC_ERROR_ARG;
|
||||
}
|
||||
|
||||
VdecFrame vf;
|
||||
if (!vdec->frames.try_pop(vf))
|
||||
vdec_frame frame;
|
||||
{
|
||||
//std::this_thread::sleep_for(1ms); // hack
|
||||
return CELL_VDEC_ERROR_EMPTY;
|
||||
thread_lock lock(*vdec);
|
||||
|
||||
if (vdec->out.empty())
|
||||
{
|
||||
return CELL_VDEC_ERROR_EMPTY;
|
||||
}
|
||||
|
||||
frame = std::move(vdec->out.front());
|
||||
|
||||
vdec->out.pop();
|
||||
}
|
||||
|
||||
if (!vf.data)
|
||||
{
|
||||
// hack
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
std::unique_ptr<AVFrame, void(*)(AVFrame*)> frame(vf.data, [](AVFrame* frame)
|
||||
{
|
||||
av_frame_unref(frame);
|
||||
av_frame_free(&frame);
|
||||
});
|
||||
vdec->notify();
|
||||
|
||||
if (outBuff)
|
||||
{
|
||||
const auto f = vdec->ctx->pix_fmt;
|
||||
const auto w = vdec->ctx->width;
|
||||
const auto h = vdec->ctx->height;
|
||||
const int w = frame->width;
|
||||
const int h = frame->height;
|
||||
|
||||
auto out_f = AV_PIX_FMT_YUV420P;
|
||||
AVPixelFormat out_f = AV_PIX_FMT_YUV420P;
|
||||
|
||||
std::unique_ptr<u8[]> alpha_plane;
|
||||
|
||||
@ -532,29 +550,29 @@ s32 cellVdecGetPicture(u32 handle, vm::cptr<CellVdecPicFormat> format, vm::ptr<u
|
||||
|
||||
default:
|
||||
{
|
||||
throw EXCEPTION("Unknown formatType(%d)", type);
|
||||
throw fmt::exception("Unknown formatType (%d)" HERE, type);
|
||||
}
|
||||
}
|
||||
|
||||
if (format->colorMatrixType != CELL_VDEC_COLOR_MATRIX_TYPE_BT709)
|
||||
{
|
||||
throw EXCEPTION("Unknown colorMatrixType(%d)", format->colorMatrixType);
|
||||
throw fmt::exception("Unknown colorMatrixType (%d)" HERE, format->colorMatrixType);
|
||||
}
|
||||
|
||||
if (alpha_plane)
|
||||
{
|
||||
memset(alpha_plane.get(), format->alpha, w * h);
|
||||
std::memset(alpha_plane.get(), format->alpha, w * h);
|
||||
}
|
||||
|
||||
auto in_f = AV_PIX_FMT_YUV420P;
|
||||
AVPixelFormat in_f = AV_PIX_FMT_YUV420P;
|
||||
|
||||
switch (f)
|
||||
switch (frame->format)
|
||||
{
|
||||
case AV_PIX_FMT_YUV420P: in_f = alpha_plane ? AV_PIX_FMT_YUVA420P : AV_PIX_FMT_YUV420P; break;
|
||||
|
||||
default:
|
||||
{
|
||||
throw EXCEPTION("Unknown pix_fmt(%d)", f);
|
||||
throw fmt::exception("Unknown format (%d)" HERE, frame->format);
|
||||
}
|
||||
}
|
||||
|
||||
@ -611,43 +629,54 @@ s32 cellVdecGetPicItem(u32 handle, vm::pptr<CellVdecPicItem> picItem)
|
||||
{
|
||||
cellVdec.trace("cellVdecGetPicItem(handle=0x%x, picItem=**0x%x)", handle, picItem);
|
||||
|
||||
const auto vdec = idm::get<VideoDecoder>(handle);
|
||||
const auto vdec = std::dynamic_pointer_cast<vdec_thread>(idm::get<ppu_thread>(handle)); // TODO: avoid RTTI
|
||||
|
||||
if (!vdec)
|
||||
{
|
||||
return CELL_VDEC_ERROR_ARG;
|
||||
}
|
||||
|
||||
VdecFrame vf;
|
||||
if (!vdec->frames.try_peek(vf))
|
||||
AVFrame* frame{};
|
||||
u64 pts;
|
||||
u64 dts;
|
||||
u64 usrd;
|
||||
u32 frc;
|
||||
{
|
||||
//std::this_thread::sleep_for(1ms); // hack
|
||||
return CELL_VDEC_ERROR_EMPTY;
|
||||
thread_lock lock(*vdec);
|
||||
|
||||
if (vdec->out.empty())
|
||||
{
|
||||
return CELL_VDEC_ERROR_EMPTY;
|
||||
}
|
||||
|
||||
frame = vdec->out.front().avf.get();
|
||||
pts = vdec->out.front().pts;
|
||||
dts = vdec->out.front().dts;
|
||||
usrd = vdec->out.front().userdata;
|
||||
frc = vdec->out.front().frc;
|
||||
}
|
||||
|
||||
AVFrame& frame = *vf.data;
|
||||
const vm::ptr<CellVdecPicItem> info = vm::cast(vdec->mem_addr + vdec->mem_bias);
|
||||
|
||||
const vm::ptr<CellVdecPicItem> info = vm::cast(vdec->memAddr + vdec->memBias);
|
||||
|
||||
vdec->memBias += 512;
|
||||
if (vdec->memBias + 512 > vdec->memSize)
|
||||
vdec->mem_bias += 512;
|
||||
if (vdec->mem_bias + 512 > vdec->mem_size)
|
||||
{
|
||||
vdec->memBias = 0;
|
||||
vdec->mem_bias = 0;
|
||||
}
|
||||
|
||||
info->codecType = vdec->type;
|
||||
info->startAddr = 0x00000123; // invalid value (no address for picture)
|
||||
info->size = align(av_image_get_buffer_size(vdec->ctx->pix_fmt, vdec->ctx->width, vdec->ctx->height, 1), 128);
|
||||
info->auNum = 1;
|
||||
info->auPts[0].lower = (u32)(vf.pts);
|
||||
info->auPts[0].upper = (u32)(vf.pts >> 32);
|
||||
info->auPts[0].lower = (u32)(pts);
|
||||
info->auPts[0].upper = (u32)(pts >> 32);
|
||||
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 = (u32)(vf.dts >> 32);
|
||||
info->auDts[0].lower = (u32)(dts);
|
||||
info->auDts[0].upper = (u32)(dts >> 32);
|
||||
info->auDts[1].lower = (u32)CODEC_TS_INVALID;
|
||||
info->auDts[1].upper = (u32)CODEC_TS_INVALID;
|
||||
info->auUserData[0] = vf.userdata;
|
||||
info->auUserData[0] = usrd;
|
||||
info->auUserData[1] = 0;
|
||||
info->status = CELL_OK;
|
||||
info->attr = CELL_VDEC_PICITEM_ATTR_NORMAL;
|
||||
@ -657,15 +686,15 @@ s32 cellVdecGetPicItem(u32 handle, vm::pptr<CellVdecPicItem> picItem)
|
||||
{
|
||||
const vm::ptr<CellVdecAvcInfo> avc = vm::cast(info.addr() + SIZE_32(CellVdecPicItem));
|
||||
|
||||
avc->horizontalSize = frame.width;
|
||||
avc->verticalSize = frame.height;
|
||||
avc->horizontalSize = frame->width;
|
||||
avc->verticalSize = frame->height;
|
||||
|
||||
switch (frame.pict_type)
|
||||
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);
|
||||
default: cellVdec.error("cellVdecGetPicItem(AVC): unknown pict_type value (0x%x)", frame->pict_type);
|
||||
}
|
||||
|
||||
avc->pictureType[1] = CELL_VDEC_AVC_PCT_UNKNOWN; // ???
|
||||
@ -687,7 +716,7 @@ s32 cellVdecGetPicItem(u32 handle, vm::pptr<CellVdecPicItem> picItem)
|
||||
avc->matrix_coefficients = CELL_VDEC_AVC_MXC_ITU_R_BT_709_5; // important
|
||||
avc->timing_info_present_flag = true;
|
||||
|
||||
switch (vf.frc)
|
||||
switch (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;
|
||||
@ -697,7 +726,7 @@ s32 cellVdecGetPicItem(u32 handle, vm::pptr<CellVdecPicItem> picItem)
|
||||
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);
|
||||
default: cellVdec.error("cellVdecGetPicItem(AVC): unknown frc value (0x%x)", frc);
|
||||
}
|
||||
|
||||
avc->fixed_frame_rate_flag = true;
|
||||
@ -713,16 +742,16 @@ s32 cellVdecGetPicItem(u32 handle, vm::pptr<CellVdecPicItem> picItem)
|
||||
{
|
||||
const vm::ptr<CellVdecDivxInfo> dvx = vm::cast(info.addr() + SIZE_32(CellVdecPicItem));
|
||||
|
||||
switch (frame.pict_type)
|
||||
switch (frame->pict_type)
|
||||
{
|
||||
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);
|
||||
default: cellVdec.error("cellVdecGetPicItem(DivX): unknown pict_type value (0x%x)", frame->pict_type);
|
||||
}
|
||||
|
||||
dvx->horizontalSize = frame.width;
|
||||
dvx->verticalSize = frame.height;
|
||||
dvx->horizontalSize = frame->width;
|
||||
dvx->verticalSize = frame->height;
|
||||
dvx->pixelAspectRatio = CELL_VDEC_DIVX_ARI_PAR_1_1; // ???
|
||||
dvx->parHeight = 0;
|
||||
dvx->parWidth = 0;
|
||||
@ -732,7 +761,7 @@ s32 cellVdecGetPicItem(u32 handle, vm::pptr<CellVdecPicItem> picItem)
|
||||
dvx->matrixCoefficients = CELL_VDEC_DIVX_MXC_ITU_R_BT_709; // ???
|
||||
dvx->pictureStruct = CELL_VDEC_DIVX_PSTR_FRAME; // ???
|
||||
|
||||
switch (vf.frc)
|
||||
switch (frc)
|
||||
{
|
||||
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;
|
||||
@ -742,7 +771,7 @@ s32 cellVdecGetPicItem(u32 handle, vm::pptr<CellVdecPicItem> picItem)
|
||||
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);
|
||||
default: cellVdec.error("cellVdecGetPicItem(DivX): unknown frc value (0x%x)", frc);
|
||||
}
|
||||
}
|
||||
else if (vdec->type == CELL_VDEC_CODEC_TYPE_MPEG2)
|
||||
@ -750,11 +779,11 @@ s32 cellVdecGetPicItem(u32 handle, vm::pptr<CellVdecPicItem> picItem)
|
||||
const vm::ptr<CellVdecMpeg2Info> mp2 = vm::cast(info.addr() + SIZE_32(CellVdecPicItem));
|
||||
|
||||
std::memset(mp2.get_ptr(), 0, sizeof(CellVdecMpeg2Info));
|
||||
mp2->horizontal_size = frame.width;
|
||||
mp2->vertical_size = frame.height;
|
||||
mp2->horizontal_size = frame->width;
|
||||
mp2->vertical_size = frame->height;
|
||||
mp2->aspect_ratio_information = CELL_VDEC_MPEG2_ARI_SAR_1_1; // ???
|
||||
|
||||
switch (vf.frc)
|
||||
switch (frc)
|
||||
{
|
||||
case CELL_VDEC_FRC_24000DIV1001: mp2->frame_rate_code = CELL_VDEC_MPEG2_FRC_24000DIV1001; break;
|
||||
case CELL_VDEC_FRC_24: mp2->frame_rate_code = CELL_VDEC_MPEG2_FRC_24; break;
|
||||
@ -764,7 +793,7 @@ s32 cellVdecGetPicItem(u32 handle, vm::pptr<CellVdecPicItem> picItem)
|
||||
case CELL_VDEC_FRC_50: mp2->frame_rate_code = CELL_VDEC_MPEG2_FRC_50; break;
|
||||
case CELL_VDEC_FRC_60000DIV1001: mp2->frame_rate_code = CELL_VDEC_MPEG2_FRC_60000DIV1001; break;
|
||||
case CELL_VDEC_FRC_60: mp2->frame_rate_code = CELL_VDEC_MPEG2_FRC_60; break;
|
||||
default: cellVdec.error("cellVdecGetPicItem(MPEG2): unknown frc value (0x%x)", vf.frc);
|
||||
default: cellVdec.error("cellVdecGetPicItem(MPEG2): unknown frc value (0x%x)", frc);
|
||||
}
|
||||
|
||||
mp2->progressive_sequence = true; // ???
|
||||
@ -772,12 +801,12 @@ s32 cellVdecGetPicItem(u32 handle, vm::pptr<CellVdecPicItem> picItem)
|
||||
mp2->video_format = CELL_VDEC_MPEG2_VF_UNSPECIFIED; // ???
|
||||
mp2->colour_description = false; // ???
|
||||
|
||||
switch (frame.pict_type)
|
||||
switch (frame->pict_type)
|
||||
{
|
||||
case AV_PICTURE_TYPE_I: mp2->picture_coding_type[0] = CELL_VDEC_MPEG2_PCT_I; break;
|
||||
case AV_PICTURE_TYPE_P: mp2->picture_coding_type[0] = CELL_VDEC_MPEG2_PCT_P; break;
|
||||
case AV_PICTURE_TYPE_B: mp2->picture_coding_type[0] = CELL_VDEC_MPEG2_PCT_B; break;
|
||||
default: cellVdec.error("cellVdecGetPicItem(MPEG2): unknown pict_type value (0x%x)", frame.pict_type);
|
||||
default: cellVdec.error("cellVdecGetPicItem(MPEG2): unknown pict_type value (0x%x)", frame->pict_type);
|
||||
}
|
||||
|
||||
mp2->picture_coding_type[1] = CELL_VDEC_MPEG2_PCT_FORBIDDEN; // ???
|
||||
@ -795,18 +824,16 @@ s32 cellVdecSetFrameRate(u32 handle, CellVdecFrameRate frc)
|
||||
{
|
||||
cellVdec.trace("cellVdecSetFrameRate(handle=0x%x, frc=0x%x)", handle, frc);
|
||||
|
||||
const auto vdec = idm::get<VideoDecoder>(handle);
|
||||
const auto vdec = std::dynamic_pointer_cast<vdec_thread>(idm::get<ppu_thread>(handle)); // TODO: avoid RTTI
|
||||
|
||||
if (!vdec)
|
||||
{
|
||||
return CELL_VDEC_ERROR_ARG;
|
||||
}
|
||||
|
||||
// TODO: check frc value and set frame rate
|
||||
VdecTask task(vdecSetFrameRate);
|
||||
task.frc = frc;
|
||||
|
||||
vdec->job.push(task, &vdec->is_closed);
|
||||
// TODO: check frc value
|
||||
vdec->cmd_push({vdec_cmd::set_frc, frc});
|
||||
vdec->lock_notify();
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,7 @@ enum CellVdecPicAttr : s32
|
||||
};
|
||||
|
||||
// Universal Frame Rate Code
|
||||
enum CellVdecFrameRate : u8
|
||||
enum CellVdecFrameRate : s32
|
||||
{
|
||||
CELL_VDEC_FRC_24000DIV1001 = 0x80,
|
||||
CELL_VDEC_FRC_24 = 0x81,
|
||||
@ -644,81 +644,3 @@ struct CellVdecMpeg2Info
|
||||
u8 ccData[2][128];
|
||||
be_t<u64> reserved[2];
|
||||
};
|
||||
|
||||
/* Video Decoder Thread Classes */
|
||||
|
||||
enum VdecJobType : u32
|
||||
{
|
||||
vdecStartSeq,
|
||||
vdecEndSeq,
|
||||
vdecDecodeAu,
|
||||
vdecSetFrameRate,
|
||||
vdecClose,
|
||||
};
|
||||
|
||||
struct VdecTask
|
||||
{
|
||||
VdecJobType type;
|
||||
union
|
||||
{
|
||||
u32 frc;
|
||||
CellVdecDecodeMode mode;
|
||||
};
|
||||
u32 addr;
|
||||
u32 size;
|
||||
u64 pts;
|
||||
u64 dts;
|
||||
u64 userData;
|
||||
u64 specData;
|
||||
|
||||
VdecTask(VdecJobType type)
|
||||
: type(type)
|
||||
{
|
||||
}
|
||||
|
||||
VdecTask()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct VdecFrame
|
||||
{
|
||||
AVFrame* data;
|
||||
u64 dts;
|
||||
u64 pts;
|
||||
u64 userdata;
|
||||
u32 frc;
|
||||
};
|
||||
|
||||
class VideoDecoder
|
||||
{
|
||||
public:
|
||||
squeue_t<VdecTask> job;
|
||||
u32 id;
|
||||
volatile bool is_closed;
|
||||
volatile bool is_finished;
|
||||
|
||||
struct AVCodec* codec;
|
||||
struct AVCodecContext* ctx;
|
||||
|
||||
squeue_t<VdecFrame, 64> frames;
|
||||
|
||||
const s32 type;
|
||||
const u32 profile;
|
||||
const u32 memAddr;
|
||||
const u32 memSize;
|
||||
const vm::ptr<CellVdecCbMsg> cbFunc;
|
||||
const u32 cbArg;
|
||||
u32 memBias;
|
||||
|
||||
VdecTask task; // current task variable
|
||||
u32 frc_set; // frame rate overwriting
|
||||
u64 last_pts;
|
||||
u64 last_dts;
|
||||
|
||||
std::shared_ptr<PPUThread> vdecCb;
|
||||
|
||||
VideoDecoder(s32 type, u32 profile, u32 addr, u32 size, vm::ptr<CellVdecCbMsg> func, u32 arg);
|
||||
|
||||
~VideoDecoder();
|
||||
};
|
||||
|
@ -8,9 +8,46 @@
|
||||
|
||||
#include <cmath>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
|
||||
logs::channel libmixer("libmixer", logs::level::notice);
|
||||
|
||||
struct SurMixerConfig
|
||||
{
|
||||
std::mutex mutex;
|
||||
|
||||
u32 audio_port;
|
||||
s32 priority;
|
||||
u32 ch_strips_1;
|
||||
u32 ch_strips_2;
|
||||
u32 ch_strips_6;
|
||||
u32 ch_strips_8;
|
||||
|
||||
vm::ptr<CellSurMixerNotifyCallbackFunction> cb;
|
||||
vm::ptr<void> cb_arg;
|
||||
|
||||
f32 mixdata[8 * 256];
|
||||
u64 mixcount;
|
||||
};
|
||||
|
||||
struct SSPlayer
|
||||
{
|
||||
bool m_created; // SSPlayerCreate/Remove
|
||||
bool m_connected; // AANConnect/Disconnect
|
||||
bool m_active; // SSPlayerPlay/Stop
|
||||
u32 m_channels; // 1 or 2
|
||||
u32 m_addr;
|
||||
u32 m_samples;
|
||||
u32 m_loop_start;
|
||||
u32 m_loop_mode;
|
||||
u32 m_position;
|
||||
float m_level;
|
||||
float m_speed;
|
||||
float m_x;
|
||||
float m_y;
|
||||
float m_z;
|
||||
};
|
||||
|
||||
// TODO: use fxm
|
||||
SurMixerConfig g_surmx;
|
||||
|
||||
@ -284,48 +321,14 @@ s32 cellSSPlayerGetState(u32 handle)
|
||||
return CELL_SSPLAYER_STATE_OFF;
|
||||
}
|
||||
|
||||
s32 cellSurMixerCreate(vm::cptr<CellSurMixerConfig> config)
|
||||
struct surmixer_thread : ppu_thread
|
||||
{
|
||||
libmixer.warning("cellSurMixerCreate(config=*0x%x)", config);
|
||||
using ppu_thread::ppu_thread;
|
||||
|
||||
const auto g_audio = fxm::get<audio_config>();
|
||||
|
||||
const auto port = g_audio->open_port();
|
||||
|
||||
if (!port)
|
||||
virtual void cpu_task() override
|
||||
{
|
||||
return CELL_LIBMIXER_ERROR_FULL;
|
||||
}
|
||||
const auto g_audio = fxm::get<audio_config>();
|
||||
|
||||
g_surmx.audio_port = port->number;
|
||||
g_surmx.priority = config->priority;
|
||||
g_surmx.ch_strips_1 = config->chStrips1;
|
||||
g_surmx.ch_strips_2 = config->chStrips2;
|
||||
g_surmx.ch_strips_6 = config->chStrips6;
|
||||
g_surmx.ch_strips_8 = config->chStrips8;
|
||||
|
||||
port->channel = 8;
|
||||
port->block = 16;
|
||||
port->attr = 0;
|
||||
port->size = port->channel * port->block * AUDIO_SAMPLES * sizeof(float);
|
||||
port->tag = 0;
|
||||
port->level = 1.0f;
|
||||
port->level_set.store({ 1.0f, 0.0f });
|
||||
|
||||
libmixer.warning("*** audio port opened (port=%d)", g_surmx.audio_port);
|
||||
|
||||
g_surmx.mixcount = 0;
|
||||
g_surmx.cb = vm::null;
|
||||
|
||||
g_ssp.clear();
|
||||
|
||||
libmixer.warning("*** surMixer created (ch1=%d, ch2=%d, ch6=%d, ch8=%d)", config->chStrips1, config->chStrips2, config->chStrips6, config->chStrips8);
|
||||
|
||||
const auto ppu = idm::make_ptr<PPUThread>("Surmixer Thread");
|
||||
ppu->prio = 1001;
|
||||
ppu->stack_size = 0x10000;
|
||||
ppu->custom_task = [g_audio](PPUThread& ppu)
|
||||
{
|
||||
audio_port& port = g_audio->ports[g_surmx.audio_port];
|
||||
|
||||
while (port.state != audio_port_state::closed)
|
||||
@ -345,7 +348,7 @@ s32 cellSurMixerCreate(vm::cptr<CellSurMixerConfig> config)
|
||||
memset(g_surmx.mixdata, 0, sizeof(g_surmx.mixdata));
|
||||
if (g_surmx.cb)
|
||||
{
|
||||
g_surmx.cb(ppu, g_surmx.cb_arg, (u32)g_surmx.mixcount, 256);
|
||||
g_surmx.cb(*this, g_surmx.cb_arg, (u32)g_surmx.mixcount, 256);
|
||||
}
|
||||
|
||||
//u64 stamp1 = get_system_time();
|
||||
@ -445,12 +448,52 @@ s32 cellSurMixerCreate(vm::cptr<CellSurMixerConfig> config)
|
||||
g_surmx.mixcount++;
|
||||
}
|
||||
|
||||
idm::remove<PPUThread>(ppu.id);
|
||||
};
|
||||
idm::remove<ppu_thread>(id);
|
||||
}
|
||||
};
|
||||
|
||||
ppu->cpu_init();
|
||||
ppu->state -= cpu_state::stop;
|
||||
(*ppu)->lock_notify();
|
||||
s32 cellSurMixerCreate(vm::cptr<CellSurMixerConfig> config)
|
||||
{
|
||||
libmixer.warning("cellSurMixerCreate(config=*0x%x)", config);
|
||||
|
||||
const auto g_audio = fxm::get<audio_config>();
|
||||
|
||||
const auto port = g_audio->open_port();
|
||||
|
||||
if (!port)
|
||||
{
|
||||
return CELL_LIBMIXER_ERROR_FULL;
|
||||
}
|
||||
|
||||
g_surmx.audio_port = port->number;
|
||||
g_surmx.priority = config->priority;
|
||||
g_surmx.ch_strips_1 = config->chStrips1;
|
||||
g_surmx.ch_strips_2 = config->chStrips2;
|
||||
g_surmx.ch_strips_6 = config->chStrips6;
|
||||
g_surmx.ch_strips_8 = config->chStrips8;
|
||||
|
||||
port->channel = 8;
|
||||
port->block = 16;
|
||||
port->attr = 0;
|
||||
port->size = port->channel * port->block * AUDIO_SAMPLES * sizeof(float);
|
||||
port->tag = 0;
|
||||
port->level = 1.0f;
|
||||
port->level_set.store({ 1.0f, 0.0f });
|
||||
|
||||
libmixer.warning("*** audio port opened (port=%d)", g_surmx.audio_port);
|
||||
|
||||
g_surmx.mixcount = 0;
|
||||
g_surmx.cb = vm::null;
|
||||
|
||||
g_ssp.clear();
|
||||
|
||||
libmixer.warning("*** surMixer created (ch1=%d, ch2=%d, ch6=%d, ch8=%d)", config->chStrips1, config->chStrips2, config->chStrips6, config->chStrips8);
|
||||
|
||||
auto&& thread = std::make_shared<surmixer_thread>("Surmixer Thread");
|
||||
|
||||
idm::import_existing<ppu_thread>(thread);
|
||||
|
||||
thread->run();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
@ -166,39 +166,3 @@ struct CellSurMixerChStripParam
|
||||
be_t<float> floatVal;
|
||||
be_t<s32> intVal;
|
||||
};
|
||||
|
||||
struct SurMixerConfig
|
||||
{
|
||||
std::mutex mutex;
|
||||
|
||||
u32 audio_port;
|
||||
s32 priority;
|
||||
u32 ch_strips_1;
|
||||
u32 ch_strips_2;
|
||||
u32 ch_strips_6;
|
||||
u32 ch_strips_8;
|
||||
|
||||
vm::ptr<CellSurMixerNotifyCallbackFunction> cb;
|
||||
vm::ptr<void> cb_arg;
|
||||
|
||||
f32 mixdata[8 * 256];
|
||||
u64 mixcount;
|
||||
};
|
||||
|
||||
struct SSPlayer
|
||||
{
|
||||
bool m_created; // SSPlayerCreate/Remove
|
||||
bool m_connected; // AANConnect/Disconnect
|
||||
bool m_active; // SSPlayerPlay/Stop
|
||||
u32 m_channels; // 1 or 2
|
||||
u32 m_addr;
|
||||
u32 m_samples;
|
||||
u32 m_loop_start;
|
||||
u32 m_loop_mode;
|
||||
u32 m_position;
|
||||
float m_level;
|
||||
float m_speed;
|
||||
float m_x;
|
||||
float m_y;
|
||||
float m_z;
|
||||
};
|
||||
|
@ -53,7 +53,7 @@ s32 sceNp2Term()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sceNpMatching2Term(PPUThread& ppu)
|
||||
s32 sceNpMatching2Term(ppu_thread& ppu)
|
||||
{
|
||||
sceNp2.warning("sceNpMatching2Term()");
|
||||
|
||||
|
@ -136,7 +136,7 @@ s32 sceNpTrophyDestroyContext(u32 context)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sceNpTrophyRegisterContext(PPUThread& CPU, u32 context, u32 handle, vm::ptr<SceNpTrophyStatusCallback> statusCb, vm::ptr<u32> arg, u64 options)
|
||||
s32 sceNpTrophyRegisterContext(ppu_thread& CPU, u32 context, u32 handle, vm::ptr<SceNpTrophyStatusCallback> statusCb, vm::ptr<u32> arg, u64 options)
|
||||
{
|
||||
sceNpTrophy.error("sceNpTrophyRegisterContext(context=0x%x, handle=0x%x, statusCb=*0x%x, arg=*0x%x, options=0x%llx)", context, handle, statusCb, arg, options);
|
||||
|
||||
|
@ -58,12 +58,12 @@ void ppu_free_tls(u32 addr)
|
||||
}
|
||||
}
|
||||
|
||||
void sys_initialize_tls(PPUThread& ppu, u64 main_thread_id, u32 tls_seg_addr, u32 tls_seg_size, u32 tls_mem_size)
|
||||
void sys_initialize_tls(ppu_thread& ppu, u64 main_thread_id, u32 tls_seg_addr, u32 tls_seg_size, u32 tls_mem_size)
|
||||
{
|
||||
sysPrxForUser.notice("sys_initialize_tls(thread_id=0x%llx, addr=*0x%x, size=0x%x, mem_size=0x%x)", main_thread_id, tls_seg_addr, tls_seg_size, tls_mem_size);
|
||||
|
||||
// Uninitialized TLS expected.
|
||||
if (ppu.GPR[13] != 0) return;
|
||||
if (ppu.gpr[13] != 0) return;
|
||||
|
||||
// Initialize TLS memory
|
||||
s_tls_addr = tls_seg_addr;
|
||||
@ -75,7 +75,7 @@ void sys_initialize_tls(PPUThread& ppu, u64 main_thread_id, u32 tls_seg_addr, u3
|
||||
s_tls_map = std::make_unique<atomic_t<bool>[]>(s_tls_max);
|
||||
|
||||
// Allocate TLS for main thread
|
||||
ppu.GPR[13] = ppu_alloc_tls() + 0x7000 + 0x30;
|
||||
ppu.gpr[13] = ppu_alloc_tls() + 0x7000 + 0x30;
|
||||
|
||||
sysPrxForUser.notice("TLS initialized (addr=0x%x, size=0x%x, max=0x%x)", s_tls_area - 0x30, s_tls_size, s_tls_max);
|
||||
|
||||
@ -105,7 +105,7 @@ s64 _sys_process_at_Exitspawn()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_interrupt_thread_disestablish(PPUThread& ppu, u32 ih)
|
||||
s32 sys_interrupt_thread_disestablish(ppu_thread& ppu, u32 ih)
|
||||
{
|
||||
sysPrxForUser.notice("sys_interrupt_thread_disestablish(ih=0x%x)", ih);
|
||||
|
||||
|
@ -17,19 +17,19 @@ struct sys_lwmutex_t;
|
||||
struct sys_lwmutex_attribute_t;
|
||||
|
||||
s32 sys_lwmutex_create(vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwmutex_attribute_t> attr);
|
||||
s32 sys_lwmutex_lock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex, u64 timeout);
|
||||
s32 sys_lwmutex_trylock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex);
|
||||
s32 sys_lwmutex_unlock(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex);
|
||||
s32 sys_lwmutex_destroy(PPUThread& CPU, vm::ptr<sys_lwmutex_t> lwmutex);
|
||||
s32 sys_lwmutex_lock(ppu_thread& CPU, vm::ptr<sys_lwmutex_t> lwmutex, u64 timeout);
|
||||
s32 sys_lwmutex_trylock(ppu_thread& CPU, vm::ptr<sys_lwmutex_t> lwmutex);
|
||||
s32 sys_lwmutex_unlock(ppu_thread& CPU, vm::ptr<sys_lwmutex_t> lwmutex);
|
||||
s32 sys_lwmutex_destroy(ppu_thread& CPU, vm::ptr<sys_lwmutex_t> lwmutex);
|
||||
|
||||
struct sys_lwcond_t;
|
||||
struct sys_lwcond_attribute_t;
|
||||
|
||||
s32 sys_lwcond_create(vm::ptr<sys_lwcond_t> lwcond, vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwcond_attribute_t> attr);
|
||||
s32 sys_lwcond_destroy(vm::ptr<sys_lwcond_t> lwcond);
|
||||
s32 sys_lwcond_signal(PPUThread& CPU, vm::ptr<sys_lwcond_t> lwcond);
|
||||
s32 sys_lwcond_signal_all(PPUThread& CPU, vm::ptr<sys_lwcond_t> lwcond);
|
||||
s32 sys_lwcond_signal_to(PPUThread& CPU, vm::ptr<sys_lwcond_t> lwcond, u32 ppu_thread_id);
|
||||
s32 sys_lwcond_wait(PPUThread& CPU, vm::ptr<sys_lwcond_t> lwcond, u64 timeout);
|
||||
s32 sys_lwcond_signal(ppu_thread& CPU, vm::ptr<sys_lwcond_t> lwcond);
|
||||
s32 sys_lwcond_signal_all(ppu_thread& CPU, vm::ptr<sys_lwcond_t> lwcond);
|
||||
s32 sys_lwcond_signal_to(ppu_thread& CPU, vm::ptr<sys_lwcond_t> lwcond, u32 ppu_thread_id);
|
||||
s32 sys_lwcond_wait(ppu_thread& CPU, vm::ptr<sys_lwcond_t> lwcond, u64 timeout);
|
||||
|
||||
void sys_ppu_thread_exit(PPUThread& CPU, u64 val);
|
||||
void sys_ppu_thread_exit(ppu_thread& CPU, u64 val);
|
||||
|
@ -6,7 +6,7 @@ extern logs::channel sysPrxForUser;
|
||||
extern fs::file g_tty;
|
||||
|
||||
// TODO
|
||||
static std::string ps3_fmt(PPUThread& context, vm::cptr<char> fmt, u32 g_count)
|
||||
static std::string ps3_fmt(ppu_thread& context, vm::cptr<char> fmt, u32 g_count)
|
||||
{
|
||||
std::string result;
|
||||
|
||||
@ -312,7 +312,7 @@ s32 _sys_free(u32 addr)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _sys_snprintf(PPUThread& ppu, vm::ptr<char> dst, u32 count, vm::cptr<char> fmt, ppu_va_args_t va_args)
|
||||
s32 _sys_snprintf(ppu_thread& ppu, vm::ptr<char> dst, u32 count, vm::cptr<char> fmt, ppu_va_args_t va_args)
|
||||
{
|
||||
sysPrxForUser.warning("_sys_snprintf(dst=*0x%x, count=%d, fmt=*0x%x, ...)", dst, count, fmt);
|
||||
|
||||
@ -334,7 +334,7 @@ s32 _sys_snprintf(PPUThread& ppu, vm::ptr<char> dst, u32 count, vm::cptr<char> f
|
||||
}
|
||||
}
|
||||
|
||||
s32 _sys_printf(PPUThread& ppu, vm::cptr<char> fmt, ppu_va_args_t va_args)
|
||||
s32 _sys_printf(ppu_thread& ppu, vm::cptr<char> fmt, ppu_va_args_t va_args)
|
||||
{
|
||||
sysPrxForUser.warning("_sys_printf(fmt=*0x%x, ...)", fmt);
|
||||
|
||||
|
@ -33,7 +33,7 @@ s32 sys_lwcond_destroy(vm::ptr<sys_lwcond_t> lwcond)
|
||||
return res;
|
||||
}
|
||||
|
||||
s32 sys_lwcond_signal(PPUThread& ppu, vm::ptr<sys_lwcond_t> lwcond)
|
||||
s32 sys_lwcond_signal(ppu_thread& ppu, vm::ptr<sys_lwcond_t> lwcond)
|
||||
{
|
||||
sysPrxForUser.trace("sys_lwcond_signal(lwcond=*0x%x)", lwcond);
|
||||
|
||||
@ -91,7 +91,7 @@ s32 sys_lwcond_signal(PPUThread& ppu, vm::ptr<sys_lwcond_t> lwcond)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_lwcond_signal_all(PPUThread& ppu, vm::ptr<sys_lwcond_t> lwcond)
|
||||
s32 sys_lwcond_signal_all(ppu_thread& ppu, vm::ptr<sys_lwcond_t> lwcond)
|
||||
{
|
||||
sysPrxForUser.trace("sys_lwcond_signal_all(lwcond=*0x%x)", lwcond);
|
||||
|
||||
@ -148,7 +148,7 @@ s32 sys_lwcond_signal_all(PPUThread& ppu, vm::ptr<sys_lwcond_t> lwcond)
|
||||
return res;
|
||||
}
|
||||
|
||||
s32 sys_lwcond_signal_to(PPUThread& ppu, vm::ptr<sys_lwcond_t> lwcond, u32 ppu_thread_id)
|
||||
s32 sys_lwcond_signal_to(ppu_thread& ppu, vm::ptr<sys_lwcond_t> lwcond, u32 ppu_thread_id)
|
||||
{
|
||||
sysPrxForUser.trace("sys_lwcond_signal_to(lwcond=*0x%x, ppu_thread_id=0x%x)", lwcond, ppu_thread_id);
|
||||
|
||||
@ -206,7 +206,7 @@ s32 sys_lwcond_signal_to(PPUThread& ppu, vm::ptr<sys_lwcond_t> lwcond, u32 ppu_t
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_lwcond_wait(PPUThread& ppu, vm::ptr<sys_lwcond_t> lwcond, u64 timeout)
|
||||
s32 sys_lwcond_wait(ppu_thread& ppu, vm::ptr<sys_lwcond_t> lwcond, u64 timeout)
|
||||
{
|
||||
sysPrxForUser.trace("sys_lwcond_wait(lwcond=*0x%x, timeout=0x%llx)", lwcond, timeout);
|
||||
|
||||
|
@ -39,7 +39,7 @@ s32 sys_lwmutex_create(vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwmutex_attri
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_lwmutex_destroy(PPUThread& ppu, vm::ptr<sys_lwmutex_t> lwmutex)
|
||||
s32 sys_lwmutex_destroy(ppu_thread& ppu, vm::ptr<sys_lwmutex_t> lwmutex)
|
||||
{
|
||||
sysPrxForUser.trace("sys_lwmutex_destroy(lwmutex=*0x%x)", lwmutex);
|
||||
|
||||
@ -70,7 +70,7 @@ s32 sys_lwmutex_destroy(PPUThread& ppu, vm::ptr<sys_lwmutex_t> lwmutex)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_lwmutex_lock(PPUThread& ppu, vm::ptr<sys_lwmutex_t> lwmutex, u64 timeout)
|
||||
s32 sys_lwmutex_lock(ppu_thread& ppu, vm::ptr<sys_lwmutex_t> lwmutex, u64 timeout)
|
||||
{
|
||||
sysPrxForUser.trace("sys_lwmutex_lock(lwmutex=*0x%x, timeout=0x%llx)", lwmutex, timeout);
|
||||
|
||||
@ -164,7 +164,7 @@ s32 sys_lwmutex_lock(PPUThread& ppu, vm::ptr<sys_lwmutex_t> lwmutex, u64 timeout
|
||||
return res;
|
||||
}
|
||||
|
||||
s32 sys_lwmutex_trylock(PPUThread& ppu, vm::ptr<sys_lwmutex_t> lwmutex)
|
||||
s32 sys_lwmutex_trylock(ppu_thread& ppu, vm::ptr<sys_lwmutex_t> lwmutex)
|
||||
{
|
||||
sysPrxForUser.trace("sys_lwmutex_trylock(lwmutex=*0x%x)", lwmutex);
|
||||
|
||||
@ -231,7 +231,7 @@ s32 sys_lwmutex_trylock(PPUThread& ppu, vm::ptr<sys_lwmutex_t> lwmutex)
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
s32 sys_lwmutex_unlock(PPUThread& ppu, vm::ptr<sys_lwmutex_t> lwmutex)
|
||||
s32 sys_lwmutex_unlock(ppu_thread& ppu, vm::ptr<sys_lwmutex_t> lwmutex)
|
||||
{
|
||||
sysPrxForUser.trace("sys_lwmutex_unlock(lwmutex=*0x%x)", lwmutex);
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <winsock2.h>
|
||||
#include <WS2tcpip.h>
|
||||
#else
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
|
@ -57,7 +57,7 @@ s32 sys_ppu_thread_create(vm::ptr<u64> thread_id, u32 entry, u64 arg, s32 prio,
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_ppu_thread_get_id(PPUThread& ppu, vm::ptr<u64> thread_id)
|
||||
s32 sys_ppu_thread_get_id(ppu_thread& ppu, vm::ptr<u64> thread_id)
|
||||
{
|
||||
sysPrxForUser.trace("sys_ppu_thread_get_id(thread_id=*0x%x)", thread_id);
|
||||
|
||||
@ -66,7 +66,7 @@ s32 sys_ppu_thread_get_id(PPUThread& ppu, vm::ptr<u64> thread_id)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
void sys_ppu_thread_exit(PPUThread& ppu, u64 val)
|
||||
void sys_ppu_thread_exit(ppu_thread& ppu, u64 val)
|
||||
{
|
||||
sysPrxForUser.trace("sys_ppu_thread_exit(val=0x%llx)", val);
|
||||
|
||||
@ -74,12 +74,12 @@ void sys_ppu_thread_exit(PPUThread& ppu, u64 val)
|
||||
// ...
|
||||
|
||||
// Deallocate TLS
|
||||
ppu_free_tls(vm::cast(ppu.GPR[13], HERE) - 0x7030);
|
||||
ppu_free_tls(vm::cast(ppu.gpr[13], HERE) - 0x7030);
|
||||
|
||||
if (ppu.GPR[3] == val && !ppu.custom_task)
|
||||
if (ppu.gpr[3] == val)
|
||||
{
|
||||
// Change sys_ppu_thread_exit code to the syscall code (hack)
|
||||
ppu.GPR[11] = 41;
|
||||
ppu.gpr[11] = 41;
|
||||
}
|
||||
|
||||
// Call the syscall
|
||||
@ -88,7 +88,7 @@ void sys_ppu_thread_exit(PPUThread& ppu, u64 val)
|
||||
|
||||
std::mutex g_once_mutex;
|
||||
|
||||
void sys_ppu_thread_once(PPUThread& ppu, vm::ptr<atomic_be_t<u32>> once_ctrl, vm::ptr<void()> init)
|
||||
void sys_ppu_thread_once(ppu_thread& ppu, vm::ptr<atomic_be_t<u32>> once_ctrl, vm::ptr<void()> init)
|
||||
{
|
||||
sysPrxForUser.warning("sys_ppu_thread_once(once_ctrl=*0x%x, init=*0x%x)", once_ctrl, init);
|
||||
|
||||
|
@ -93,7 +93,7 @@ s32 sys_raw_spu_load(s32 id, vm::cptr<char> path, vm::ptr<u32> entry)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_raw_spu_image_load(PPUThread& ppu, s32 id, vm::ptr<sys_spu_image_t> img)
|
||||
s32 sys_raw_spu_image_load(ppu_thread& ppu, s32 id, vm::ptr<sys_spu_image_t> img)
|
||||
{
|
||||
sysPrxForUser.warning("sys_raw_spu_image_load(id=%d, img=*0x%x)", id, img);
|
||||
|
||||
@ -140,7 +140,7 @@ s32 _sys_spu_printf_finalize()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _sys_spu_printf_attach_group(PPUThread& ppu, u32 group)
|
||||
s32 _sys_spu_printf_attach_group(ppu_thread& ppu, u32 group)
|
||||
{
|
||||
sysPrxForUser.warning("_sys_spu_printf_attach_group(group=0x%x)", group);
|
||||
|
||||
@ -152,7 +152,7 @@ s32 _sys_spu_printf_attach_group(PPUThread& ppu, u32 group)
|
||||
return g_spu_printf_agcb(ppu, group);
|
||||
}
|
||||
|
||||
s32 _sys_spu_printf_detach_group(PPUThread& ppu, u32 group)
|
||||
s32 _sys_spu_printf_detach_group(ppu_thread& ppu, u32 group)
|
||||
{
|
||||
sysPrxForUser.warning("_sys_spu_printf_detach_group(group=0x%x)", group);
|
||||
|
||||
@ -164,7 +164,7 @@ s32 _sys_spu_printf_detach_group(PPUThread& ppu, u32 group)
|
||||
return g_spu_printf_dgcb(ppu, group);
|
||||
}
|
||||
|
||||
s32 _sys_spu_printf_attach_thread(PPUThread& ppu, u32 thread)
|
||||
s32 _sys_spu_printf_attach_thread(ppu_thread& ppu, u32 thread)
|
||||
{
|
||||
sysPrxForUser.warning("_sys_spu_printf_attach_thread(thread=0x%x)", thread);
|
||||
|
||||
@ -176,7 +176,7 @@ s32 _sys_spu_printf_attach_thread(PPUThread& ppu, u32 thread)
|
||||
return g_spu_printf_atcb(ppu, thread);
|
||||
}
|
||||
|
||||
s32 _sys_spu_printf_detach_thread(PPUThread& ppu, u32 thread)
|
||||
s32 _sys_spu_printf_detach_thread(ppu_thread& ppu, u32 thread)
|
||||
{
|
||||
sysPrxForUser.warning("_sys_spu_printf_detach_thread(thread=0x%x)", thread);
|
||||
|
||||
|
@ -403,6 +403,10 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
|
||||
const u32 addr = ptr[0];
|
||||
const u32 _toc = ptr[1];
|
||||
|
||||
// Rough Table of Contents borders
|
||||
const u32 _toc_begin = _toc - 0x8000;
|
||||
const u32 _toc_end = _toc + 0x8000;
|
||||
|
||||
// TODO: improve TOC constraints
|
||||
if (_toc % 4 || _toc == 0 || _toc >= 0x40000000 || (_toc >= start && _toc < end))
|
||||
{
|
||||
@ -436,8 +440,8 @@ std::vector<ppu_function> ppu_analyse(const std::vector<std::pair<u32, u32>>& se
|
||||
}
|
||||
}
|
||||
|
||||
// Secondary attempt (TODO)
|
||||
if (secs.empty() && lib_toc)
|
||||
// Secondary attempt (TODO, needs better strategy)
|
||||
if (/*secs.empty() &&*/ lib_toc)
|
||||
{
|
||||
add_toc(lib_toc);
|
||||
}
|
||||
|
@ -1,103 +0,0 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
|
||||
#include "PPUThread.h"
|
||||
#include "PPUCallback.h"
|
||||
|
||||
#include <condition_variable>
|
||||
|
||||
void CallbackManager::Register(check_cb_t func)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
m_check_cb.emplace(std::move(func));
|
||||
}
|
||||
|
||||
void CallbackManager::Async(async_cb_t func)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
if (!m_cb_thread)
|
||||
{
|
||||
throw EXCEPTION("Callback thread not found");
|
||||
}
|
||||
|
||||
m_async_cb.emplace(std::move(func));
|
||||
|
||||
(*m_cb_thread)->notify();
|
||||
}
|
||||
|
||||
extern std::condition_variable& get_current_thread_cv();
|
||||
|
||||
CallbackManager::check_cb_t CallbackManager::Check()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
if (m_check_cb.size())
|
||||
{
|
||||
check_cb_t func = std::move(m_check_cb.front());
|
||||
|
||||
m_check_cb.pop();
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CallbackManager::Init()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
auto task = [this](PPUThread& ppu)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
|
||||
while (true)
|
||||
{
|
||||
CHECK_EMU_STATUS;
|
||||
|
||||
if (!lock)
|
||||
{
|
||||
lock.lock();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_async_cb.size())
|
||||
{
|
||||
async_cb_t func = std::move(m_async_cb.front());
|
||||
|
||||
m_async_cb.pop();
|
||||
|
||||
if (lock) lock.unlock();
|
||||
|
||||
func(ppu);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
get_current_thread_cv().wait(lock);
|
||||
}
|
||||
};
|
||||
|
||||
auto thread = idm::make_ptr<PPUThread>("Callback Thread");
|
||||
|
||||
thread->prio = 1001;
|
||||
thread->stack_size = 0x10000;
|
||||
thread->custom_task = task;
|
||||
thread->cpu_init();
|
||||
|
||||
m_cb_thread = thread;
|
||||
}
|
||||
|
||||
void CallbackManager::Clear()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
m_check_cb = decltype(m_check_cb){};
|
||||
m_async_cb = decltype(m_async_cb){};
|
||||
|
||||
m_cb_thread.reset();
|
||||
}
|
@ -27,9 +27,9 @@ namespace ppu_cb_detail
|
||||
static_assert(!std::is_reference<T>::value, "Invalid callback argument type (reference)");
|
||||
static_assert(sizeof(T) <= 8, "Invalid callback argument type for ARG_GENERAL");
|
||||
|
||||
static inline void set_value(PPUThread& CPU, const T& arg)
|
||||
static inline void set_value(ppu_thread& CPU, const T& arg)
|
||||
{
|
||||
CPU.GPR[g_count + 2] = ppu_gpr_cast(arg);
|
||||
CPU.gpr[g_count + 2] = ppu_gpr_cast(arg);
|
||||
}
|
||||
};
|
||||
|
||||
@ -38,9 +38,9 @@ namespace ppu_cb_detail
|
||||
{
|
||||
static_assert(sizeof(T) <= 8, "Invalid callback argument type for ARG_FLOAT");
|
||||
|
||||
static inline void set_value(PPUThread& CPU, const T& arg)
|
||||
static inline void set_value(ppu_thread& CPU, const T& arg)
|
||||
{
|
||||
CPU.FPR[f_count] = static_cast<T>(arg);
|
||||
CPU.fpr[f_count] = static_cast<T>(arg);
|
||||
}
|
||||
};
|
||||
|
||||
@ -49,9 +49,9 @@ namespace ppu_cb_detail
|
||||
{
|
||||
static_assert(std::is_same<CV T, CV v128>::value, "Invalid callback argument type for ARG_VECTOR");
|
||||
|
||||
static inline void set_value(PPUThread& CPU, const T& arg)
|
||||
static inline void set_value(ppu_thread& CPU, const T& arg)
|
||||
{
|
||||
CPU.VR[v_count + 1] = arg;
|
||||
CPU.vr[v_count + 1] = arg;
|
||||
}
|
||||
};
|
||||
|
||||
@ -60,37 +60,37 @@ namespace ppu_cb_detail
|
||||
{
|
||||
static_assert(alignof(T) <= 16, "Unsupported callback argument type alignment for ARG_STACK");
|
||||
|
||||
static inline void set_value(PPUThread& CPU, const T& arg)
|
||||
static inline void set_value(ppu_thread& CPU, const T& arg)
|
||||
{
|
||||
const s64 stack_pos = (g_count - 1) * 0x8 + 0x30 - FIXED_STACK_FRAME_SIZE;
|
||||
static_assert(stack_pos < 0, "TODO: Increase FIXED_STACK_FRAME_SIZE (arg count limit broken)");
|
||||
vm::ps3::write64(CPU.GPR[1] + stack_pos, ppu_gpr_cast(arg)); // TODO
|
||||
vm::ps3::write64(CPU.gpr[1] + stack_pos, ppu_gpr_cast(arg)); // TODO
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, u32 g_count, u32 f_count, u32 v_count>
|
||||
struct _func_arg<T, ARG_CONTEXT, g_count, f_count, v_count>
|
||||
{
|
||||
static_assert(std::is_same<T, PPUThread&>::value, "Invalid callback argument type for ARG_CONTEXT");
|
||||
static_assert(std::is_same<T, ppu_thread&>::value, "Invalid callback argument type for ARG_CONTEXT");
|
||||
|
||||
force_inline static void set_value(PPUThread& CPU, const T& arg)
|
||||
force_inline static void set_value(ppu_thread& CPU, const T& arg)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template<u32 g_count, u32 f_count, u32 v_count>
|
||||
force_inline static bool _bind_func_args(PPUThread& CPU)
|
||||
force_inline static bool _bind_func_args(ppu_thread& CPU)
|
||||
{
|
||||
// terminator
|
||||
return false;
|
||||
}
|
||||
|
||||
template<u32 g_count, u32 f_count, u32 v_count, typename T1, typename... T>
|
||||
force_inline static bool _bind_func_args(PPUThread& CPU, T1 arg1, T... args)
|
||||
force_inline static bool _bind_func_args(ppu_thread& CPU, T1 arg1, T... args)
|
||||
{
|
||||
const bool is_float = std::is_floating_point<T1>::value;
|
||||
const bool is_vector = std::is_same<CV T1, CV v128>::value;
|
||||
const bool is_context = std::is_same<T1, PPUThread&>::value;
|
||||
const bool is_context = std::is_same<T1, ppu_thread&>::value;
|
||||
const bool is_general = !is_float && !is_vector && !is_context;
|
||||
|
||||
const _func_arg_type t =
|
||||
@ -116,9 +116,9 @@ namespace ppu_cb_detail
|
||||
static_assert(type == ARG_GENERAL, "Unknown callback result type");
|
||||
static_assert(sizeof(T) <= 8, "Invalid callback result type for ARG_GENERAL");
|
||||
|
||||
force_inline static T get_value(const PPUThread& CPU)
|
||||
force_inline static T get_value(const ppu_thread& CPU)
|
||||
{
|
||||
return ppu_gpr_cast<T>(CPU.GPR[3]);
|
||||
return ppu_gpr_cast<T>(CPU.gpr[3]);
|
||||
}
|
||||
};
|
||||
|
||||
@ -127,9 +127,9 @@ namespace ppu_cb_detail
|
||||
{
|
||||
static_assert(sizeof(T) <= 8, "Invalid callback result type for ARG_FLOAT");
|
||||
|
||||
force_inline static T get_value(const PPUThread& CPU)
|
||||
force_inline static T get_value(const ppu_thread& CPU)
|
||||
{
|
||||
return static_cast<T>(CPU.FPR[1]);
|
||||
return static_cast<T>(CPU.fpr[1]);
|
||||
}
|
||||
};
|
||||
|
||||
@ -138,16 +138,16 @@ namespace ppu_cb_detail
|
||||
{
|
||||
static_assert(std::is_same<CV T, CV v128>::value, "Invalid callback result type for ARG_VECTOR");
|
||||
|
||||
force_inline static T get_value(const PPUThread& CPU)
|
||||
force_inline static T get_value(const ppu_thread& CPU)
|
||||
{
|
||||
return CPU.VR[2];
|
||||
return CPU.vr[2];
|
||||
}
|
||||
};
|
||||
|
||||
template<typename RT, typename... T>
|
||||
struct _func_caller
|
||||
{
|
||||
force_inline static RT call(PPUThread& CPU, u32 pc, u32 rtoc, T... args)
|
||||
force_inline static RT call(ppu_thread& CPU, u32 pc, u32 rtoc, T... args)
|
||||
{
|
||||
_func_caller<void, T...>::call(CPU, pc, rtoc, args...);
|
||||
|
||||
@ -164,12 +164,12 @@ namespace ppu_cb_detail
|
||||
template<typename... T>
|
||||
struct _func_caller<void, T...>
|
||||
{
|
||||
force_inline static void call(PPUThread& CPU, u32 pc, u32 rtoc, T... args)
|
||||
force_inline static void call(ppu_thread& CPU, u32 pc, u32 rtoc, T... args)
|
||||
{
|
||||
const bool stack = _bind_func_args<0, 0, 0, T...>(CPU, args...);
|
||||
CPU.GPR[1] -= stack ? FIXED_STACK_FRAME_SIZE : 0x30; // create reserved area
|
||||
CPU.gpr[1] -= stack ? FIXED_STACK_FRAME_SIZE : 0x30; // create reserved area
|
||||
CPU.fast_call(pc, rtoc);
|
||||
CPU.GPR[1] += stack ? FIXED_STACK_FRAME_SIZE : 0x30;
|
||||
CPU.gpr[1] += stack ? FIXED_STACK_FRAME_SIZE : 0x30;
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -177,7 +177,7 @@ namespace ppu_cb_detail
|
||||
namespace vm
|
||||
{
|
||||
template<typename AT, typename RT, typename... T>
|
||||
force_inline RT _ptr_base<RT(T...), AT>::operator()(PPUThread& CPU, T... args) const
|
||||
force_inline RT _ptr_base<RT(T...), AT>::operator()(ppu_thread& CPU, T... args) const
|
||||
{
|
||||
const auto data = vm::ps3::_ptr<u32>(vm::cast(m_addr, HERE));
|
||||
const u32 pc = data[0];
|
||||
@ -187,37 +187,7 @@ namespace vm
|
||||
}
|
||||
}
|
||||
|
||||
template<typename RT, typename... T> inline RT cb_call(PPUThread& CPU, u32 pc, u32 rtoc, T... args)
|
||||
template<typename RT, typename... T> inline RT cb_call(ppu_thread& CPU, u32 pc, u32 rtoc, T... args)
|
||||
{
|
||||
return ppu_cb_detail::_func_caller<RT, T...>::call(CPU, pc, rtoc, args...);
|
||||
}
|
||||
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
|
||||
class CallbackManager
|
||||
{
|
||||
using check_cb_t = std::function<s32(PPUThread&)>;
|
||||
using async_cb_t = std::function<void(PPUThread&)>;
|
||||
|
||||
std::mutex m_mutex;
|
||||
|
||||
std::queue<check_cb_t> m_check_cb;
|
||||
std::queue<async_cb_t> m_async_cb;
|
||||
|
||||
std::shared_ptr<PPUThread> m_cb_thread;
|
||||
|
||||
public:
|
||||
// Register checked callback
|
||||
void Register(check_cb_t func);
|
||||
|
||||
// Register async callback, called in callback thread
|
||||
void Async(async_cb_t func);
|
||||
|
||||
// Get one registered callback
|
||||
check_cb_t Check();
|
||||
|
||||
void Init();
|
||||
|
||||
void Clear();
|
||||
};
|
||||
|
@ -2361,7 +2361,7 @@ s32 ppu_error_code::report(s32 error, const char* text)
|
||||
{
|
||||
if (thread->type == cpu_type::ppu)
|
||||
{
|
||||
if (auto func = static_cast<PPUThread*>(thread)->last_function)
|
||||
if (auto func = static_cast<ppu_thread*>(thread)->last_function)
|
||||
{
|
||||
LOG_ERROR(PPU, "'%s' failed with 0x%08x : %s", func, error, text);
|
||||
}
|
||||
@ -2383,7 +2383,7 @@ std::vector<ppu_function_t>& ppu_function_manager::access()
|
||||
static std::vector<ppu_function_t> list
|
||||
{
|
||||
nullptr,
|
||||
[](PPUThread& ppu) { ppu.state += cpu_state::ret; },
|
||||
[](ppu_thread& ppu) { ppu.state += cpu_state::ret; },
|
||||
};
|
||||
|
||||
return list;
|
||||
|
@ -2,14 +2,14 @@
|
||||
|
||||
#include "PPUThread.h"
|
||||
|
||||
using ppu_function_t = void(*)(PPUThread&);
|
||||
using ppu_function_t = void(*)(ppu_thread&);
|
||||
|
||||
// BIND_FUNC macro "converts" any appropriate HLE function to ppu_function_t, binding it to PPU thread context.
|
||||
// If function already has type ppu_function_t, it's handled specially and classified as "low-level HLE function".
|
||||
// 1) Low-level functions are bound directly so they don't save their name to ppu.last_function variable.
|
||||
// 2) Low-level functions don't install thread_guar, so they are very limited, and may be dangerous.
|
||||
// If you don't need "low-level function", be sure it's either `void()` or `void(PPUThread& ppu, PPUThread&)` for example.
|
||||
#define BIND_FUNC(func) (std::is_same<decltype(func), ppu_function_t>::value ? reinterpret_cast<ppu_function_t>(func) : static_cast<ppu_function_t>([](PPUThread& ppu){\
|
||||
// If you don't need "low-level function", be sure it's either `void()` or `void(ppu_thread& ppu, ppu_thread&)` for example.
|
||||
#define BIND_FUNC(func) (std::is_same<decltype(func), ppu_function_t>::value ? reinterpret_cast<ppu_function_t>(func) : static_cast<ppu_function_t>([](ppu_thread& ppu){\
|
||||
const thread_guard guard(ppu);\
|
||||
const auto old_f = ppu.last_function;\
|
||||
ppu.last_function = #func;\
|
||||
@ -27,11 +27,11 @@ namespace ppu_func_detail
|
||||
// argument type classification
|
||||
enum arg_class : u32
|
||||
{
|
||||
ARG_GENERAL, // argument stored in GPR (from r3 to r10)
|
||||
ARG_FLOAT, // argument stored in FPR (from f1 to f13)
|
||||
ARG_VECTOR, // argument stored in VR (from v2 to v13)
|
||||
ARG_GENERAL, // argument stored in gpr (from r3 to r10)
|
||||
ARG_FLOAT, // argument stored in fpr (from f1 to f13)
|
||||
ARG_VECTOR, // argument stored in vr (from v2 to v13)
|
||||
ARG_STACK, // argument stored on the stack
|
||||
ARG_CONTEXT, // PPUThread& passed, doesn't affect g/f/v_count
|
||||
ARG_CONTEXT, // ppu_thread& passed, doesn't affect g/f/v_count
|
||||
ARG_VARIADIC, // argument count at specific position, doesn't affect g/f/v_count
|
||||
ARG_UNKNOWN,
|
||||
};
|
||||
@ -44,9 +44,9 @@ namespace ppu_func_detail
|
||||
static_assert(!std::is_reference<T>::value, "Invalid function argument type (reference)");
|
||||
static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_GENERAL");
|
||||
|
||||
static inline T get_arg(PPUThread& ppu)
|
||||
static inline T get_arg(ppu_thread& ppu)
|
||||
{
|
||||
return ppu_gpr_cast<T>(ppu.GPR[g_count + 2]);
|
||||
return ppu_gpr_cast<T>(ppu.gpr[g_count + 2]);
|
||||
}
|
||||
};
|
||||
|
||||
@ -55,9 +55,9 @@ namespace ppu_func_detail
|
||||
{
|
||||
static_assert(sizeof(T) <= 8, "Invalid function argument type for ARG_FLOAT");
|
||||
|
||||
static inline T get_arg(PPUThread& ppu)
|
||||
static inline T get_arg(ppu_thread& ppu)
|
||||
{
|
||||
return static_cast<T>(ppu.FPR[f_count]);
|
||||
return static_cast<T>(ppu.fpr[f_count]);
|
||||
}
|
||||
};
|
||||
|
||||
@ -66,9 +66,9 @@ namespace ppu_func_detail
|
||||
{
|
||||
static_assert(std::is_same<CV T, CV v128>::value, "Invalid function argument type for ARG_VECTOR");
|
||||
|
||||
static force_inline T get_arg(PPUThread& ppu)
|
||||
static force_inline T get_arg(ppu_thread& ppu)
|
||||
{
|
||||
return ppu.VR[v_count + 1];
|
||||
return ppu.vr[v_count + 1];
|
||||
}
|
||||
};
|
||||
|
||||
@ -77,7 +77,7 @@ namespace ppu_func_detail
|
||||
{
|
||||
static_assert(alignof(T) <= 16, "Unsupported type alignment for ARG_STACK");
|
||||
|
||||
static force_inline T get_arg(PPUThread& ppu)
|
||||
static force_inline T get_arg(ppu_thread& ppu)
|
||||
{
|
||||
return ppu_gpr_cast<T, u64>(*ppu.get_stack_arg(g_count, alignof(T))); // TODO
|
||||
}
|
||||
@ -86,9 +86,9 @@ namespace ppu_func_detail
|
||||
template<typename T, u32 g_count, u32 f_count, u32 v_count>
|
||||
struct bind_arg<T, ARG_CONTEXT, g_count, f_count, v_count>
|
||||
{
|
||||
static_assert(std::is_same<T, PPUThread&>::value, "Invalid function argument type for ARG_CONTEXT");
|
||||
static_assert(std::is_same<T, ppu_thread&>::value, "Invalid function argument type for ARG_CONTEXT");
|
||||
|
||||
static force_inline PPUThread& get_arg(PPUThread& ppu)
|
||||
static force_inline ppu_thread& get_arg(ppu_thread& ppu)
|
||||
{
|
||||
return ppu;
|
||||
}
|
||||
@ -99,7 +99,7 @@ namespace ppu_func_detail
|
||||
{
|
||||
static_assert(std::is_same<T, ppu_va_args_t>::value, "Invalid function argument type for ARG_VARIADIC");
|
||||
|
||||
static force_inline ppu_va_args_t get_arg(PPUThread& ppu)
|
||||
static force_inline ppu_va_args_t get_arg(ppu_thread& ppu)
|
||||
{
|
||||
return{ g_count };
|
||||
}
|
||||
@ -111,9 +111,9 @@ namespace ppu_func_detail
|
||||
static_assert(type == ARG_GENERAL, "Unknown function result type");
|
||||
static_assert(sizeof(T) <= 8, "Invalid function result type for ARG_GENERAL");
|
||||
|
||||
static force_inline void put_result(PPUThread& ppu, const T& result)
|
||||
static force_inline void put_result(ppu_thread& ppu, const T& result)
|
||||
{
|
||||
ppu.GPR[3] = ppu_gpr_cast(result);
|
||||
ppu.gpr[3] = ppu_gpr_cast(result);
|
||||
}
|
||||
};
|
||||
|
||||
@ -122,9 +122,9 @@ namespace ppu_func_detail
|
||||
{
|
||||
static_assert(sizeof(T) <= 8, "Invalid function result type for ARG_FLOAT");
|
||||
|
||||
static force_inline void put_result(PPUThread& ppu, const T& result)
|
||||
static force_inline void put_result(ppu_thread& ppu, const T& result)
|
||||
{
|
||||
ppu.FPR[1] = static_cast<T>(result);
|
||||
ppu.fpr[1] = static_cast<T>(result);
|
||||
}
|
||||
};
|
||||
|
||||
@ -133,9 +133,9 @@ namespace ppu_func_detail
|
||||
{
|
||||
static_assert(std::is_same<CV T, CV v128>::value, "Invalid function result type for ARG_VECTOR");
|
||||
|
||||
static force_inline void put_result(PPUThread& ppu, const T& result)
|
||||
static force_inline void put_result(ppu_thread& ppu, const T& result)
|
||||
{
|
||||
ppu.VR[2] = result;
|
||||
ppu.vr[2] = result;
|
||||
}
|
||||
};
|
||||
|
||||
@ -160,21 +160,21 @@ namespace ppu_func_detail
|
||||
// argument type + g/f/v_count unpacker
|
||||
template<typename T, u32 type_pack> struct bind_arg_packed
|
||||
{
|
||||
static force_inline T get_arg(PPUThread& ppu)
|
||||
static force_inline T get_arg(ppu_thread& ppu)
|
||||
{
|
||||
return bind_arg<T, static_cast<arg_class>(type_pack & 0xff), (type_pack >> 8) & 0xff, (type_pack >> 16) & 0xff, (type_pack >> 24)>::get_arg(ppu);
|
||||
}
|
||||
};
|
||||
|
||||
template<u32... Info, typename RT, typename... Args>
|
||||
force_inline RT call(PPUThread& ppu, RT(*func)(Args...), arg_info_pack_t<Info...>)
|
||||
force_inline RT call(ppu_thread& ppu, RT(*func)(Args...), arg_info_pack_t<Info...>)
|
||||
{
|
||||
// do the actual function call when all arguments are prepared (simultaneous unpacking of Args... and Info...)
|
||||
return func(bind_arg_packed<Args, Info>::get_arg(ppu)...);
|
||||
}
|
||||
|
||||
template<typename T, typename... Types, u32... Info, typename RT, typename... Args>
|
||||
force_inline RT call(PPUThread& ppu, RT(*func)(Args...), arg_info_pack_t<Info...> info)
|
||||
force_inline RT call(ppu_thread& ppu, RT(*func)(Args...), arg_info_pack_t<Info...> info)
|
||||
{
|
||||
// unpack previous type counts (0/0/0 for the first time)
|
||||
const u32 g_count = (info.last_value >> 8) & 0xff;
|
||||
@ -184,7 +184,7 @@ namespace ppu_func_detail
|
||||
// TODO: check calculations
|
||||
const bool is_float = std::is_floating_point<T>::value;
|
||||
const bool is_vector = std::is_same<CV T, CV v128>::value;
|
||||
const bool is_context = std::is_same<T, PPUThread&>::value;
|
||||
const bool is_context = std::is_same<T, ppu_thread&>::value;
|
||||
const bool is_variadic = std::is_same<CV T, CV ppu_va_args_t>::value;
|
||||
const bool is_general = !is_float && !is_vector && !is_context && !is_variadic;
|
||||
|
||||
@ -220,7 +220,7 @@ namespace ppu_func_detail
|
||||
{
|
||||
using func_t = void(*)(T...);
|
||||
|
||||
static force_inline void do_call(PPUThread& ppu, func_t func)
|
||||
static force_inline void do_call(ppu_thread& ppu, func_t func)
|
||||
{
|
||||
call<T...>(ppu, func, arg_info_pack_t<>{});
|
||||
}
|
||||
@ -231,14 +231,14 @@ namespace ppu_func_detail
|
||||
{
|
||||
using func_t = RT(*)(T...);
|
||||
|
||||
static force_inline void do_call(PPUThread& ppu, func_t func)
|
||||
static force_inline void do_call(ppu_thread& ppu, func_t func)
|
||||
{
|
||||
bind_result<RT, result_type<RT>::value>::put_result(ppu, call<T...>(ppu, func, arg_info_pack_t<>{}));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename RT, typename... T>
|
||||
force_inline void do_call(PPUThread& ppu, RT(*func)(T...))
|
||||
force_inline void do_call(ppu_thread& ppu, RT(*func)(T...))
|
||||
{
|
||||
func_binder<RT, T...>::do_call(ppu, func);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2,392 +2,392 @@
|
||||
|
||||
#include "PPUOpcodes.h"
|
||||
|
||||
class PPUThread;
|
||||
class ppu_thread;
|
||||
|
||||
struct ppu_interpreter
|
||||
{
|
||||
static bool MFVSCR(PPUThread&, ppu_opcode_t);
|
||||
static bool MTVSCR(PPUThread&, ppu_opcode_t);
|
||||
static bool VADDCUW(PPUThread&, ppu_opcode_t);
|
||||
static bool VADDFP(PPUThread&, ppu_opcode_t);
|
||||
static bool VADDSBS(PPUThread&, ppu_opcode_t);
|
||||
static bool VADDSHS(PPUThread&, ppu_opcode_t);
|
||||
static bool VADDSWS(PPUThread&, ppu_opcode_t);
|
||||
static bool VADDUBM(PPUThread&, ppu_opcode_t);
|
||||
static bool VADDUBS(PPUThread&, ppu_opcode_t);
|
||||
static bool VADDUHM(PPUThread&, ppu_opcode_t);
|
||||
static bool VADDUHS(PPUThread&, ppu_opcode_t);
|
||||
static bool VADDUWM(PPUThread&, ppu_opcode_t);
|
||||
static bool VADDUWS(PPUThread&, ppu_opcode_t);
|
||||
static bool VAND(PPUThread&, ppu_opcode_t);
|
||||
static bool VANDC(PPUThread&, ppu_opcode_t);
|
||||
static bool VAVGSB(PPUThread&, ppu_opcode_t);
|
||||
static bool VAVGSH(PPUThread&, ppu_opcode_t);
|
||||
static bool VAVGSW(PPUThread&, ppu_opcode_t);
|
||||
static bool VAVGUB(PPUThread&, ppu_opcode_t);
|
||||
static bool VAVGUH(PPUThread&, ppu_opcode_t);
|
||||
static bool VAVGUW(PPUThread&, ppu_opcode_t);
|
||||
static bool VCFSX(PPUThread&, ppu_opcode_t);
|
||||
static bool VCFUX(PPUThread&, ppu_opcode_t);
|
||||
static bool VCMPBFP(PPUThread&, ppu_opcode_t);
|
||||
static bool VCMPEQFP(PPUThread&, ppu_opcode_t);
|
||||
static bool VCMPEQUB(PPUThread&, ppu_opcode_t);
|
||||
static bool VCMPEQUH(PPUThread&, ppu_opcode_t);
|
||||
static bool VCMPEQUW(PPUThread&, ppu_opcode_t);
|
||||
static bool VCMPGEFP(PPUThread&, ppu_opcode_t);
|
||||
static bool VCMPGTFP(PPUThread&, ppu_opcode_t);
|
||||
static bool VCMPGTSB(PPUThread&, ppu_opcode_t);
|
||||
static bool VCMPGTSH(PPUThread&, ppu_opcode_t);
|
||||
static bool VCMPGTSW(PPUThread&, ppu_opcode_t);
|
||||
static bool VCMPGTUB(PPUThread&, ppu_opcode_t);
|
||||
static bool VCMPGTUH(PPUThread&, ppu_opcode_t);
|
||||
static bool VCMPGTUW(PPUThread&, ppu_opcode_t);
|
||||
static bool VCTSXS(PPUThread&, ppu_opcode_t);
|
||||
static bool VCTUXS(PPUThread&, ppu_opcode_t);
|
||||
static bool VEXPTEFP(PPUThread&, ppu_opcode_t);
|
||||
static bool VLOGEFP(PPUThread&, ppu_opcode_t);
|
||||
static bool VMADDFP(PPUThread&, ppu_opcode_t);
|
||||
static bool VMAXFP(PPUThread&, ppu_opcode_t);
|
||||
static bool VMAXSB(PPUThread&, ppu_opcode_t);
|
||||
static bool VMAXSH(PPUThread&, ppu_opcode_t);
|
||||
static bool VMAXSW(PPUThread&, ppu_opcode_t);
|
||||
static bool VMAXUB(PPUThread&, ppu_opcode_t);
|
||||
static bool VMAXUH(PPUThread&, ppu_opcode_t);
|
||||
static bool VMAXUW(PPUThread&, ppu_opcode_t);
|
||||
static bool VMHADDSHS(PPUThread&, ppu_opcode_t);
|
||||
static bool VMHRADDSHS(PPUThread&, ppu_opcode_t);
|
||||
static bool VMINFP(PPUThread&, ppu_opcode_t);
|
||||
static bool VMINSB(PPUThread&, ppu_opcode_t);
|
||||
static bool VMINSH(PPUThread&, ppu_opcode_t);
|
||||
static bool VMINSW(PPUThread&, ppu_opcode_t);
|
||||
static bool VMINUB(PPUThread&, ppu_opcode_t);
|
||||
static bool VMINUH(PPUThread&, ppu_opcode_t);
|
||||
static bool VMINUW(PPUThread&, ppu_opcode_t);
|
||||
static bool VMLADDUHM(PPUThread&, ppu_opcode_t);
|
||||
static bool VMRGHB(PPUThread&, ppu_opcode_t);
|
||||
static bool VMRGHH(PPUThread&, ppu_opcode_t);
|
||||
static bool VMRGHW(PPUThread&, ppu_opcode_t);
|
||||
static bool VMRGLB(PPUThread&, ppu_opcode_t);
|
||||
static bool VMRGLH(PPUThread&, ppu_opcode_t);
|
||||
static bool VMRGLW(PPUThread&, ppu_opcode_t);
|
||||
static bool VMSUMMBM(PPUThread&, ppu_opcode_t);
|
||||
static bool VMSUMSHM(PPUThread&, ppu_opcode_t);
|
||||
static bool VMSUMSHS(PPUThread&, ppu_opcode_t);
|
||||
static bool VMSUMUBM(PPUThread&, ppu_opcode_t);
|
||||
static bool VMSUMUHM(PPUThread&, ppu_opcode_t);
|
||||
static bool VMSUMUHS(PPUThread&, ppu_opcode_t);
|
||||
static bool VMULESB(PPUThread&, ppu_opcode_t);
|
||||
static bool VMULESH(PPUThread&, ppu_opcode_t);
|
||||
static bool VMULEUB(PPUThread&, ppu_opcode_t);
|
||||
static bool VMULEUH(PPUThread&, ppu_opcode_t);
|
||||
static bool VMULOSB(PPUThread&, ppu_opcode_t);
|
||||
static bool VMULOSH(PPUThread&, ppu_opcode_t);
|
||||
static bool VMULOUB(PPUThread&, ppu_opcode_t);
|
||||
static bool VMULOUH(PPUThread&, ppu_opcode_t);
|
||||
static bool VNMSUBFP(PPUThread&, ppu_opcode_t);
|
||||
static bool VNOR(PPUThread&, ppu_opcode_t);
|
||||
static bool VOR(PPUThread&, ppu_opcode_t);
|
||||
static bool VPERM(PPUThread&, ppu_opcode_t);
|
||||
static bool VPKPX(PPUThread&, ppu_opcode_t);
|
||||
static bool VPKSHSS(PPUThread&, ppu_opcode_t);
|
||||
static bool VPKSHUS(PPUThread&, ppu_opcode_t);
|
||||
static bool VPKSWSS(PPUThread&, ppu_opcode_t);
|
||||
static bool VPKSWUS(PPUThread&, ppu_opcode_t);
|
||||
static bool VPKUHUM(PPUThread&, ppu_opcode_t);
|
||||
static bool VPKUHUS(PPUThread&, ppu_opcode_t);
|
||||
static bool VPKUWUM(PPUThread&, ppu_opcode_t);
|
||||
static bool VPKUWUS(PPUThread&, ppu_opcode_t);
|
||||
static bool VREFP(PPUThread&, ppu_opcode_t);
|
||||
static bool VRFIM(PPUThread&, ppu_opcode_t);
|
||||
static bool VRFIN(PPUThread&, ppu_opcode_t);
|
||||
static bool VRFIP(PPUThread&, ppu_opcode_t);
|
||||
static bool VRFIZ(PPUThread&, ppu_opcode_t);
|
||||
static bool VRLB(PPUThread&, ppu_opcode_t);
|
||||
static bool VRLH(PPUThread&, ppu_opcode_t);
|
||||
static bool VRLW(PPUThread&, ppu_opcode_t);
|
||||
static bool VRSQRTEFP(PPUThread&, ppu_opcode_t);
|
||||
static bool VSEL(PPUThread&, ppu_opcode_t);
|
||||
static bool VSL(PPUThread&, ppu_opcode_t);
|
||||
static bool VSLB(PPUThread&, ppu_opcode_t);
|
||||
static bool VSLDOI(PPUThread&, ppu_opcode_t);
|
||||
static bool VSLH(PPUThread&, ppu_opcode_t);
|
||||
static bool VSLO(PPUThread&, ppu_opcode_t);
|
||||
static bool VSLW(PPUThread&, ppu_opcode_t);
|
||||
static bool VSPLTB(PPUThread&, ppu_opcode_t);
|
||||
static bool VSPLTH(PPUThread&, ppu_opcode_t);
|
||||
static bool VSPLTISB(PPUThread&, ppu_opcode_t);
|
||||
static bool VSPLTISH(PPUThread&, ppu_opcode_t);
|
||||
static bool VSPLTISW(PPUThread&, ppu_opcode_t);
|
||||
static bool VSPLTW(PPUThread&, ppu_opcode_t);
|
||||
static bool VSR(PPUThread&, ppu_opcode_t);
|
||||
static bool VSRAB(PPUThread&, ppu_opcode_t);
|
||||
static bool VSRAH(PPUThread&, ppu_opcode_t);
|
||||
static bool VSRAW(PPUThread&, ppu_opcode_t);
|
||||
static bool VSRB(PPUThread&, ppu_opcode_t);
|
||||
static bool VSRH(PPUThread&, ppu_opcode_t);
|
||||
static bool VSRO(PPUThread&, ppu_opcode_t);
|
||||
static bool VSRW(PPUThread&, ppu_opcode_t);
|
||||
static bool VSUBCUW(PPUThread&, ppu_opcode_t);
|
||||
static bool VSUBFP(PPUThread&, ppu_opcode_t);
|
||||
static bool VSUBSBS(PPUThread&, ppu_opcode_t);
|
||||
static bool VSUBSHS(PPUThread&, ppu_opcode_t);
|
||||
static bool VSUBSWS(PPUThread&, ppu_opcode_t);
|
||||
static bool VSUBUBM(PPUThread&, ppu_opcode_t);
|
||||
static bool VSUBUBS(PPUThread&, ppu_opcode_t);
|
||||
static bool VSUBUHM(PPUThread&, ppu_opcode_t);
|
||||
static bool VSUBUHS(PPUThread&, ppu_opcode_t);
|
||||
static bool VSUBUWM(PPUThread&, ppu_opcode_t);
|
||||
static bool VSUBUWS(PPUThread&, ppu_opcode_t);
|
||||
static bool VSUMSWS(PPUThread&, ppu_opcode_t);
|
||||
static bool VSUM2SWS(PPUThread&, ppu_opcode_t);
|
||||
static bool VSUM4SBS(PPUThread&, ppu_opcode_t);
|
||||
static bool VSUM4SHS(PPUThread&, ppu_opcode_t);
|
||||
static bool VSUM4UBS(PPUThread&, ppu_opcode_t);
|
||||
static bool VUPKHPX(PPUThread&, ppu_opcode_t);
|
||||
static bool VUPKHSB(PPUThread&, ppu_opcode_t);
|
||||
static bool VUPKHSH(PPUThread&, ppu_opcode_t);
|
||||
static bool VUPKLPX(PPUThread&, ppu_opcode_t);
|
||||
static bool VUPKLSB(PPUThread&, ppu_opcode_t);
|
||||
static bool VUPKLSH(PPUThread&, ppu_opcode_t);
|
||||
static bool VXOR(PPUThread&, ppu_opcode_t);
|
||||
static bool TDI(PPUThread&, ppu_opcode_t);
|
||||
static bool TWI(PPUThread&, ppu_opcode_t);
|
||||
static bool MULLI(PPUThread&, ppu_opcode_t);
|
||||
static bool SUBFIC(PPUThread&, ppu_opcode_t);
|
||||
static bool CMPLI(PPUThread&, ppu_opcode_t);
|
||||
static bool CMPI(PPUThread&, ppu_opcode_t);
|
||||
static bool ADDIC(PPUThread&, ppu_opcode_t);
|
||||
static bool ADDI(PPUThread&, ppu_opcode_t);
|
||||
static bool ADDIS(PPUThread&, ppu_opcode_t);
|
||||
static bool BC(PPUThread&, ppu_opcode_t);
|
||||
static bool HACK(PPUThread&, ppu_opcode_t);
|
||||
static bool SC(PPUThread&, ppu_opcode_t);
|
||||
static bool B(PPUThread&, ppu_opcode_t);
|
||||
static bool MCRF(PPUThread&, ppu_opcode_t);
|
||||
static bool BCLR(PPUThread&, ppu_opcode_t);
|
||||
static bool CRNOR(PPUThread&, ppu_opcode_t);
|
||||
static bool CRANDC(PPUThread&, ppu_opcode_t);
|
||||
static bool ISYNC(PPUThread&, ppu_opcode_t);
|
||||
static bool CRXOR(PPUThread&, ppu_opcode_t);
|
||||
static bool CRNAND(PPUThread&, ppu_opcode_t);
|
||||
static bool CRAND(PPUThread&, ppu_opcode_t);
|
||||
static bool CREQV(PPUThread&, ppu_opcode_t);
|
||||
static bool CRORC(PPUThread&, ppu_opcode_t);
|
||||
static bool CROR(PPUThread&, ppu_opcode_t);
|
||||
static bool BCCTR(PPUThread&, ppu_opcode_t);
|
||||
static bool RLWIMI(PPUThread&, ppu_opcode_t);
|
||||
static bool RLWINM(PPUThread&, ppu_opcode_t);
|
||||
static bool RLWNM(PPUThread&, ppu_opcode_t);
|
||||
static bool ORI(PPUThread&, ppu_opcode_t);
|
||||
static bool ORIS(PPUThread&, ppu_opcode_t);
|
||||
static bool XORI(PPUThread&, ppu_opcode_t);
|
||||
static bool XORIS(PPUThread&, ppu_opcode_t);
|
||||
static bool ANDI(PPUThread&, ppu_opcode_t);
|
||||
static bool ANDIS(PPUThread&, ppu_opcode_t);
|
||||
static bool RLDICL(PPUThread&, ppu_opcode_t);
|
||||
static bool RLDICR(PPUThread&, ppu_opcode_t);
|
||||
static bool RLDIC(PPUThread&, ppu_opcode_t);
|
||||
static bool RLDIMI(PPUThread&, ppu_opcode_t);
|
||||
static bool RLDCL(PPUThread&, ppu_opcode_t);
|
||||
static bool RLDCR(PPUThread&, ppu_opcode_t);
|
||||
static bool CMP(PPUThread&, ppu_opcode_t);
|
||||
static bool TW(PPUThread&, ppu_opcode_t);
|
||||
static bool LVSL(PPUThread&, ppu_opcode_t);
|
||||
static bool LVEBX(PPUThread&, ppu_opcode_t);
|
||||
static bool SUBFC(PPUThread&, ppu_opcode_t);
|
||||
static bool MULHDU(PPUThread&, ppu_opcode_t);
|
||||
static bool ADDC(PPUThread&, ppu_opcode_t);
|
||||
static bool MULHWU(PPUThread&, ppu_opcode_t);
|
||||
static bool MFOCRF(PPUThread&, ppu_opcode_t);
|
||||
static bool LWARX(PPUThread&, ppu_opcode_t);
|
||||
static bool LDX(PPUThread&, ppu_opcode_t);
|
||||
static bool LWZX(PPUThread&, ppu_opcode_t);
|
||||
static bool SLW(PPUThread&, ppu_opcode_t);
|
||||
static bool CNTLZW(PPUThread&, ppu_opcode_t);
|
||||
static bool SLD(PPUThread&, ppu_opcode_t);
|
||||
static bool AND(PPUThread&, ppu_opcode_t);
|
||||
static bool CMPL(PPUThread&, ppu_opcode_t);
|
||||
static bool LVSR(PPUThread&, ppu_opcode_t);
|
||||
static bool LVEHX(PPUThread&, ppu_opcode_t);
|
||||
static bool SUBF(PPUThread&, ppu_opcode_t);
|
||||
static bool LDUX(PPUThread&, ppu_opcode_t);
|
||||
static bool DCBST(PPUThread&, ppu_opcode_t);
|
||||
static bool LWZUX(PPUThread&, ppu_opcode_t);
|
||||
static bool CNTLZD(PPUThread&, ppu_opcode_t);
|
||||
static bool ANDC(PPUThread&, ppu_opcode_t);
|
||||
static bool TD(PPUThread&, ppu_opcode_t);
|
||||
static bool LVEWX(PPUThread&, ppu_opcode_t);
|
||||
static bool MULHD(PPUThread&, ppu_opcode_t);
|
||||
static bool MULHW(PPUThread&, ppu_opcode_t);
|
||||
static bool LDARX(PPUThread&, ppu_opcode_t);
|
||||
static bool DCBF(PPUThread&, ppu_opcode_t);
|
||||
static bool LBZX(PPUThread&, ppu_opcode_t);
|
||||
static bool LVX(PPUThread&, ppu_opcode_t);
|
||||
static bool NEG(PPUThread&, ppu_opcode_t);
|
||||
static bool LBZUX(PPUThread&, ppu_opcode_t);
|
||||
static bool NOR(PPUThread&, ppu_opcode_t);
|
||||
static bool STVEBX(PPUThread&, ppu_opcode_t);
|
||||
static bool SUBFE(PPUThread&, ppu_opcode_t);
|
||||
static bool ADDE(PPUThread&, ppu_opcode_t);
|
||||
static bool MTOCRF(PPUThread&, ppu_opcode_t);
|
||||
static bool STDX(PPUThread&, ppu_opcode_t);
|
||||
static bool STWCX(PPUThread&, ppu_opcode_t);
|
||||
static bool STWX(PPUThread&, ppu_opcode_t);
|
||||
static bool STVEHX(PPUThread&, ppu_opcode_t);
|
||||
static bool STDUX(PPUThread&, ppu_opcode_t);
|
||||
static bool STWUX(PPUThread&, ppu_opcode_t);
|
||||
static bool STVEWX(PPUThread&, ppu_opcode_t);
|
||||
static bool SUBFZE(PPUThread&, ppu_opcode_t);
|
||||
static bool ADDZE(PPUThread&, ppu_opcode_t);
|
||||
static bool STDCX(PPUThread&, ppu_opcode_t);
|
||||
static bool STBX(PPUThread&, ppu_opcode_t);
|
||||
static bool STVX(PPUThread&, ppu_opcode_t);
|
||||
static bool MULLD(PPUThread&, ppu_opcode_t);
|
||||
static bool SUBFME(PPUThread&, ppu_opcode_t);
|
||||
static bool ADDME(PPUThread&, ppu_opcode_t);
|
||||
static bool MULLW(PPUThread&, ppu_opcode_t);
|
||||
static bool DCBTST(PPUThread&, ppu_opcode_t);
|
||||
static bool STBUX(PPUThread&, ppu_opcode_t);
|
||||
static bool ADD(PPUThread&, ppu_opcode_t);
|
||||
static bool DCBT(PPUThread&, ppu_opcode_t);
|
||||
static bool LHZX(PPUThread&, ppu_opcode_t);
|
||||
static bool EQV(PPUThread&, ppu_opcode_t);
|
||||
static bool ECIWX(PPUThread&, ppu_opcode_t);
|
||||
static bool LHZUX(PPUThread&, ppu_opcode_t);
|
||||
static bool XOR(PPUThread&, ppu_opcode_t);
|
||||
static bool MFSPR(PPUThread&, ppu_opcode_t);
|
||||
static bool LWAX(PPUThread&, ppu_opcode_t);
|
||||
static bool DST(PPUThread&, ppu_opcode_t);
|
||||
static bool LHAX(PPUThread&, ppu_opcode_t);
|
||||
static bool LVXL(PPUThread&, ppu_opcode_t);
|
||||
static bool MFTB(PPUThread&, ppu_opcode_t);
|
||||
static bool LWAUX(PPUThread&, ppu_opcode_t);
|
||||
static bool DSTST(PPUThread&, ppu_opcode_t);
|
||||
static bool LHAUX(PPUThread&, ppu_opcode_t);
|
||||
static bool STHX(PPUThread&, ppu_opcode_t);
|
||||
static bool ORC(PPUThread&, ppu_opcode_t);
|
||||
static bool ECOWX(PPUThread&, ppu_opcode_t);
|
||||
static bool STHUX(PPUThread&, ppu_opcode_t);
|
||||
static bool OR(PPUThread&, ppu_opcode_t);
|
||||
static bool DIVDU(PPUThread&, ppu_opcode_t);
|
||||
static bool DIVWU(PPUThread&, ppu_opcode_t);
|
||||
static bool MTSPR(PPUThread&, ppu_opcode_t);
|
||||
static bool DCBI(PPUThread&, ppu_opcode_t);
|
||||
static bool NAND(PPUThread&, ppu_opcode_t);
|
||||
static bool STVXL(PPUThread&, ppu_opcode_t);
|
||||
static bool DIVD(PPUThread&, ppu_opcode_t);
|
||||
static bool DIVW(PPUThread&, ppu_opcode_t);
|
||||
static bool LVLX(PPUThread&, ppu_opcode_t);
|
||||
static bool LDBRX(PPUThread&, ppu_opcode_t);
|
||||
static bool LSWX(PPUThread&, ppu_opcode_t);
|
||||
static bool LWBRX(PPUThread&, ppu_opcode_t);
|
||||
static bool LFSX(PPUThread&, ppu_opcode_t);
|
||||
static bool SRW(PPUThread&, ppu_opcode_t);
|
||||
static bool SRD(PPUThread&, ppu_opcode_t);
|
||||
static bool LVRX(PPUThread&, ppu_opcode_t);
|
||||
static bool LSWI(PPUThread&, ppu_opcode_t);
|
||||
static bool LFSUX(PPUThread&, ppu_opcode_t);
|
||||
static bool SYNC(PPUThread&, ppu_opcode_t);
|
||||
static bool LFDX(PPUThread&, ppu_opcode_t);
|
||||
static bool LFDUX(PPUThread&, ppu_opcode_t);
|
||||
static bool STVLX(PPUThread&, ppu_opcode_t);
|
||||
static bool STDBRX(PPUThread&, ppu_opcode_t);
|
||||
static bool STSWX(PPUThread&, ppu_opcode_t);
|
||||
static bool STWBRX(PPUThread&, ppu_opcode_t);
|
||||
static bool STFSX(PPUThread&, ppu_opcode_t);
|
||||
static bool STVRX(PPUThread&, ppu_opcode_t);
|
||||
static bool STFSUX(PPUThread&, ppu_opcode_t);
|
||||
static bool STSWI(PPUThread&, ppu_opcode_t);
|
||||
static bool STFDX(PPUThread&, ppu_opcode_t);
|
||||
static bool STFDUX(PPUThread&, ppu_opcode_t);
|
||||
static bool LVLXL(PPUThread&, ppu_opcode_t);
|
||||
static bool LHBRX(PPUThread&, ppu_opcode_t);
|
||||
static bool SRAW(PPUThread&, ppu_opcode_t);
|
||||
static bool SRAD(PPUThread&, ppu_opcode_t);
|
||||
static bool LVRXL(PPUThread&, ppu_opcode_t);
|
||||
static bool DSS(PPUThread&, ppu_opcode_t);
|
||||
static bool SRAWI(PPUThread&, ppu_opcode_t);
|
||||
static bool SRADI(PPUThread&, ppu_opcode_t);
|
||||
static bool EIEIO(PPUThread&, ppu_opcode_t);
|
||||
static bool STVLXL(PPUThread&, ppu_opcode_t);
|
||||
static bool STHBRX(PPUThread&, ppu_opcode_t);
|
||||
static bool EXTSH(PPUThread&, ppu_opcode_t);
|
||||
static bool STVRXL(PPUThread&, ppu_opcode_t);
|
||||
static bool EXTSB(PPUThread&, ppu_opcode_t);
|
||||
static bool STFIWX(PPUThread&, ppu_opcode_t);
|
||||
static bool EXTSW(PPUThread&, ppu_opcode_t);
|
||||
static bool ICBI(PPUThread&, ppu_opcode_t);
|
||||
static bool DCBZ(PPUThread&, ppu_opcode_t);
|
||||
static bool LWZ(PPUThread&, ppu_opcode_t);
|
||||
static bool LWZU(PPUThread&, ppu_opcode_t);
|
||||
static bool LBZ(PPUThread&, ppu_opcode_t);
|
||||
static bool LBZU(PPUThread&, ppu_opcode_t);
|
||||
static bool STW(PPUThread&, ppu_opcode_t);
|
||||
static bool STWU(PPUThread&, ppu_opcode_t);
|
||||
static bool STB(PPUThread&, ppu_opcode_t);
|
||||
static bool STBU(PPUThread&, ppu_opcode_t);
|
||||
static bool LHZ(PPUThread&, ppu_opcode_t);
|
||||
static bool LHZU(PPUThread&, ppu_opcode_t);
|
||||
static bool LHA(PPUThread&, ppu_opcode_t);
|
||||
static bool LHAU(PPUThread&, ppu_opcode_t);
|
||||
static bool STH(PPUThread&, ppu_opcode_t);
|
||||
static bool STHU(PPUThread&, ppu_opcode_t);
|
||||
static bool LMW(PPUThread&, ppu_opcode_t);
|
||||
static bool STMW(PPUThread&, ppu_opcode_t);
|
||||
static bool LFS(PPUThread&, ppu_opcode_t);
|
||||
static bool LFSU(PPUThread&, ppu_opcode_t);
|
||||
static bool LFD(PPUThread&, ppu_opcode_t);
|
||||
static bool LFDU(PPUThread&, ppu_opcode_t);
|
||||
static bool STFS(PPUThread&, ppu_opcode_t);
|
||||
static bool STFSU(PPUThread&, ppu_opcode_t);
|
||||
static bool STFD(PPUThread&, ppu_opcode_t);
|
||||
static bool STFDU(PPUThread&, ppu_opcode_t);
|
||||
static bool LD(PPUThread&, ppu_opcode_t);
|
||||
static bool LDU(PPUThread&, ppu_opcode_t);
|
||||
static bool LWA(PPUThread&, ppu_opcode_t);
|
||||
static bool STD(PPUThread&, ppu_opcode_t);
|
||||
static bool STDU(PPUThread&, ppu_opcode_t);
|
||||
static bool FDIVS(PPUThread&, ppu_opcode_t);
|
||||
static bool FSUBS(PPUThread&, ppu_opcode_t);
|
||||
static bool FADDS(PPUThread&, ppu_opcode_t);
|
||||
static bool FSQRTS(PPUThread&, ppu_opcode_t);
|
||||
static bool FRES(PPUThread&, ppu_opcode_t);
|
||||
static bool FMULS(PPUThread&, ppu_opcode_t);
|
||||
static bool FMADDS(PPUThread&, ppu_opcode_t);
|
||||
static bool FMSUBS(PPUThread&, ppu_opcode_t);
|
||||
static bool FNMSUBS(PPUThread&, ppu_opcode_t);
|
||||
static bool FNMADDS(PPUThread&, ppu_opcode_t);
|
||||
static bool MTFSB1(PPUThread&, ppu_opcode_t);
|
||||
static bool MCRFS(PPUThread&, ppu_opcode_t);
|
||||
static bool MTFSB0(PPUThread&, ppu_opcode_t);
|
||||
static bool MTFSFI(PPUThread&, ppu_opcode_t);
|
||||
static bool MFFS(PPUThread&, ppu_opcode_t);
|
||||
static bool MTFSF(PPUThread&, ppu_opcode_t);
|
||||
static bool FCMPU(PPUThread&, ppu_opcode_t);
|
||||
static bool FRSP(PPUThread&, ppu_opcode_t);
|
||||
static bool FCTIW(PPUThread&, ppu_opcode_t);
|
||||
static bool FCTIWZ(PPUThread&, ppu_opcode_t);
|
||||
static bool FDIV(PPUThread&, ppu_opcode_t);
|
||||
static bool FSUB(PPUThread&, ppu_opcode_t);
|
||||
static bool FADD(PPUThread&, ppu_opcode_t);
|
||||
static bool FSQRT(PPUThread&, ppu_opcode_t);
|
||||
static bool FSEL(PPUThread&, ppu_opcode_t);
|
||||
static bool FMUL(PPUThread&, ppu_opcode_t);
|
||||
static bool FRSQRTE(PPUThread&, ppu_opcode_t);
|
||||
static bool FMSUB(PPUThread&, ppu_opcode_t);
|
||||
static bool FMADD(PPUThread&, ppu_opcode_t);
|
||||
static bool FNMSUB(PPUThread&, ppu_opcode_t);
|
||||
static bool FNMADD(PPUThread&, ppu_opcode_t);
|
||||
static bool FCMPO(PPUThread&, ppu_opcode_t);
|
||||
static bool FNEG(PPUThread&, ppu_opcode_t);
|
||||
static bool FMR(PPUThread&, ppu_opcode_t);
|
||||
static bool FNABS(PPUThread&, ppu_opcode_t);
|
||||
static bool FABS(PPUThread&, ppu_opcode_t);
|
||||
static bool FCTID(PPUThread&, ppu_opcode_t);
|
||||
static bool FCTIDZ(PPUThread&, ppu_opcode_t);
|
||||
static bool FCFID(PPUThread&, ppu_opcode_t);
|
||||
static bool MFVSCR(ppu_thread&, ppu_opcode_t);
|
||||
static bool MTVSCR(ppu_thread&, ppu_opcode_t);
|
||||
static bool VADDCUW(ppu_thread&, ppu_opcode_t);
|
||||
static bool VADDFP(ppu_thread&, ppu_opcode_t);
|
||||
static bool VADDSBS(ppu_thread&, ppu_opcode_t);
|
||||
static bool VADDSHS(ppu_thread&, ppu_opcode_t);
|
||||
static bool VADDSWS(ppu_thread&, ppu_opcode_t);
|
||||
static bool VADDUBM(ppu_thread&, ppu_opcode_t);
|
||||
static bool VADDUBS(ppu_thread&, ppu_opcode_t);
|
||||
static bool VADDUHM(ppu_thread&, ppu_opcode_t);
|
||||
static bool VADDUHS(ppu_thread&, ppu_opcode_t);
|
||||
static bool VADDUWM(ppu_thread&, ppu_opcode_t);
|
||||
static bool VADDUWS(ppu_thread&, ppu_opcode_t);
|
||||
static bool VAND(ppu_thread&, ppu_opcode_t);
|
||||
static bool VANDC(ppu_thread&, ppu_opcode_t);
|
||||
static bool VAVGSB(ppu_thread&, ppu_opcode_t);
|
||||
static bool VAVGSH(ppu_thread&, ppu_opcode_t);
|
||||
static bool VAVGSW(ppu_thread&, ppu_opcode_t);
|
||||
static bool VAVGUB(ppu_thread&, ppu_opcode_t);
|
||||
static bool VAVGUH(ppu_thread&, ppu_opcode_t);
|
||||
static bool VAVGUW(ppu_thread&, ppu_opcode_t);
|
||||
static bool VCFSX(ppu_thread&, ppu_opcode_t);
|
||||
static bool VCFUX(ppu_thread&, ppu_opcode_t);
|
||||
static bool VCMPBFP(ppu_thread&, ppu_opcode_t);
|
||||
static bool VCMPEQFP(ppu_thread&, ppu_opcode_t);
|
||||
static bool VCMPEQUB(ppu_thread&, ppu_opcode_t);
|
||||
static bool VCMPEQUH(ppu_thread&, ppu_opcode_t);
|
||||
static bool VCMPEQUW(ppu_thread&, ppu_opcode_t);
|
||||
static bool VCMPGEFP(ppu_thread&, ppu_opcode_t);
|
||||
static bool VCMPGTFP(ppu_thread&, ppu_opcode_t);
|
||||
static bool VCMPGTSB(ppu_thread&, ppu_opcode_t);
|
||||
static bool VCMPGTSH(ppu_thread&, ppu_opcode_t);
|
||||
static bool VCMPGTSW(ppu_thread&, ppu_opcode_t);
|
||||
static bool VCMPGTUB(ppu_thread&, ppu_opcode_t);
|
||||
static bool VCMPGTUH(ppu_thread&, ppu_opcode_t);
|
||||
static bool VCMPGTUW(ppu_thread&, ppu_opcode_t);
|
||||
static bool VCTSXS(ppu_thread&, ppu_opcode_t);
|
||||
static bool VCTUXS(ppu_thread&, ppu_opcode_t);
|
||||
static bool VEXPTEFP(ppu_thread&, ppu_opcode_t);
|
||||
static bool VLOGEFP(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMADDFP(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMAXFP(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMAXSB(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMAXSH(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMAXSW(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMAXUB(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMAXUH(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMAXUW(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMHADDSHS(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMHRADDSHS(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMINFP(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMINSB(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMINSH(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMINSW(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMINUB(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMINUH(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMINUW(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMLADDUHM(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMRGHB(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMRGHH(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMRGHW(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMRGLB(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMRGLH(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMRGLW(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMSUMMBM(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMSUMSHM(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMSUMSHS(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMSUMUBM(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMSUMUHM(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMSUMUHS(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMULESB(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMULESH(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMULEUB(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMULEUH(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMULOSB(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMULOSH(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMULOUB(ppu_thread&, ppu_opcode_t);
|
||||
static bool VMULOUH(ppu_thread&, ppu_opcode_t);
|
||||
static bool VNMSUBFP(ppu_thread&, ppu_opcode_t);
|
||||
static bool VNOR(ppu_thread&, ppu_opcode_t);
|
||||
static bool VOR(ppu_thread&, ppu_opcode_t);
|
||||
static bool VPERM(ppu_thread&, ppu_opcode_t);
|
||||
static bool VPKPX(ppu_thread&, ppu_opcode_t);
|
||||
static bool VPKSHSS(ppu_thread&, ppu_opcode_t);
|
||||
static bool VPKSHUS(ppu_thread&, ppu_opcode_t);
|
||||
static bool VPKSWSS(ppu_thread&, ppu_opcode_t);
|
||||
static bool VPKSWUS(ppu_thread&, ppu_opcode_t);
|
||||
static bool VPKUHUM(ppu_thread&, ppu_opcode_t);
|
||||
static bool VPKUHUS(ppu_thread&, ppu_opcode_t);
|
||||
static bool VPKUWUM(ppu_thread&, ppu_opcode_t);
|
||||
static bool VPKUWUS(ppu_thread&, ppu_opcode_t);
|
||||
static bool VREFP(ppu_thread&, ppu_opcode_t);
|
||||
static bool VRFIM(ppu_thread&, ppu_opcode_t);
|
||||
static bool VRFIN(ppu_thread&, ppu_opcode_t);
|
||||
static bool VRFIP(ppu_thread&, ppu_opcode_t);
|
||||
static bool VRFIZ(ppu_thread&, ppu_opcode_t);
|
||||
static bool VRLB(ppu_thread&, ppu_opcode_t);
|
||||
static bool VRLH(ppu_thread&, ppu_opcode_t);
|
||||
static bool VRLW(ppu_thread&, ppu_opcode_t);
|
||||
static bool VRSQRTEFP(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSEL(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSL(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSLB(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSLDOI(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSLH(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSLO(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSLW(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSPLTB(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSPLTH(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSPLTISB(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSPLTISH(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSPLTISW(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSPLTW(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSR(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSRAB(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSRAH(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSRAW(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSRB(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSRH(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSRO(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSRW(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSUBCUW(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSUBFP(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSUBSBS(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSUBSHS(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSUBSWS(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSUBUBM(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSUBUBS(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSUBUHM(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSUBUHS(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSUBUWM(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSUBUWS(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSUMSWS(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSUM2SWS(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSUM4SBS(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSUM4SHS(ppu_thread&, ppu_opcode_t);
|
||||
static bool VSUM4UBS(ppu_thread&, ppu_opcode_t);
|
||||
static bool VUPKHPX(ppu_thread&, ppu_opcode_t);
|
||||
static bool VUPKHSB(ppu_thread&, ppu_opcode_t);
|
||||
static bool VUPKHSH(ppu_thread&, ppu_opcode_t);
|
||||
static bool VUPKLPX(ppu_thread&, ppu_opcode_t);
|
||||
static bool VUPKLSB(ppu_thread&, ppu_opcode_t);
|
||||
static bool VUPKLSH(ppu_thread&, ppu_opcode_t);
|
||||
static bool VXOR(ppu_thread&, ppu_opcode_t);
|
||||
static bool TDI(ppu_thread&, ppu_opcode_t);
|
||||
static bool TWI(ppu_thread&, ppu_opcode_t);
|
||||
static bool MULLI(ppu_thread&, ppu_opcode_t);
|
||||
static bool SUBFIC(ppu_thread&, ppu_opcode_t);
|
||||
static bool CMPLI(ppu_thread&, ppu_opcode_t);
|
||||
static bool CMPI(ppu_thread&, ppu_opcode_t);
|
||||
static bool ADDIC(ppu_thread&, ppu_opcode_t);
|
||||
static bool ADDI(ppu_thread&, ppu_opcode_t);
|
||||
static bool ADDIS(ppu_thread&, ppu_opcode_t);
|
||||
static bool BC(ppu_thread&, ppu_opcode_t);
|
||||
static bool HACK(ppu_thread&, ppu_opcode_t);
|
||||
static bool SC(ppu_thread&, ppu_opcode_t);
|
||||
static bool B(ppu_thread&, ppu_opcode_t);
|
||||
static bool MCRF(ppu_thread&, ppu_opcode_t);
|
||||
static bool BCLR(ppu_thread&, ppu_opcode_t);
|
||||
static bool CRNOR(ppu_thread&, ppu_opcode_t);
|
||||
static bool CRANDC(ppu_thread&, ppu_opcode_t);
|
||||
static bool ISYNC(ppu_thread&, ppu_opcode_t);
|
||||
static bool CRXOR(ppu_thread&, ppu_opcode_t);
|
||||
static bool CRNAND(ppu_thread&, ppu_opcode_t);
|
||||
static bool CRAND(ppu_thread&, ppu_opcode_t);
|
||||
static bool CREQV(ppu_thread&, ppu_opcode_t);
|
||||
static bool CRORC(ppu_thread&, ppu_opcode_t);
|
||||
static bool CROR(ppu_thread&, ppu_opcode_t);
|
||||
static bool BCCTR(ppu_thread&, ppu_opcode_t);
|
||||
static bool RLWIMI(ppu_thread&, ppu_opcode_t);
|
||||
static bool RLWINM(ppu_thread&, ppu_opcode_t);
|
||||
static bool RLWNM(ppu_thread&, ppu_opcode_t);
|
||||
static bool ORI(ppu_thread&, ppu_opcode_t);
|
||||
static bool ORIS(ppu_thread&, ppu_opcode_t);
|
||||
static bool XORI(ppu_thread&, ppu_opcode_t);
|
||||
static bool XORIS(ppu_thread&, ppu_opcode_t);
|
||||
static bool ANDI(ppu_thread&, ppu_opcode_t);
|
||||
static bool ANDIS(ppu_thread&, ppu_opcode_t);
|
||||
static bool RLDICL(ppu_thread&, ppu_opcode_t);
|
||||
static bool RLDICR(ppu_thread&, ppu_opcode_t);
|
||||
static bool RLDIC(ppu_thread&, ppu_opcode_t);
|
||||
static bool RLDIMI(ppu_thread&, ppu_opcode_t);
|
||||
static bool RLDCL(ppu_thread&, ppu_opcode_t);
|
||||
static bool RLDCR(ppu_thread&, ppu_opcode_t);
|
||||
static bool CMP(ppu_thread&, ppu_opcode_t);
|
||||
static bool TW(ppu_thread&, ppu_opcode_t);
|
||||
static bool LVSL(ppu_thread&, ppu_opcode_t);
|
||||
static bool LVEBX(ppu_thread&, ppu_opcode_t);
|
||||
static bool SUBFC(ppu_thread&, ppu_opcode_t);
|
||||
static bool MULHDU(ppu_thread&, ppu_opcode_t);
|
||||
static bool ADDC(ppu_thread&, ppu_opcode_t);
|
||||
static bool MULHWU(ppu_thread&, ppu_opcode_t);
|
||||
static bool MFOCRF(ppu_thread&, ppu_opcode_t);
|
||||
static bool LWARX(ppu_thread&, ppu_opcode_t);
|
||||
static bool LDX(ppu_thread&, ppu_opcode_t);
|
||||
static bool LWZX(ppu_thread&, ppu_opcode_t);
|
||||
static bool SLW(ppu_thread&, ppu_opcode_t);
|
||||
static bool CNTLZW(ppu_thread&, ppu_opcode_t);
|
||||
static bool SLD(ppu_thread&, ppu_opcode_t);
|
||||
static bool AND(ppu_thread&, ppu_opcode_t);
|
||||
static bool CMPL(ppu_thread&, ppu_opcode_t);
|
||||
static bool LVSR(ppu_thread&, ppu_opcode_t);
|
||||
static bool LVEHX(ppu_thread&, ppu_opcode_t);
|
||||
static bool SUBF(ppu_thread&, ppu_opcode_t);
|
||||
static bool LDUX(ppu_thread&, ppu_opcode_t);
|
||||
static bool DCBST(ppu_thread&, ppu_opcode_t);
|
||||
static bool LWZUX(ppu_thread&, ppu_opcode_t);
|
||||
static bool CNTLZD(ppu_thread&, ppu_opcode_t);
|
||||
static bool ANDC(ppu_thread&, ppu_opcode_t);
|
||||
static bool TD(ppu_thread&, ppu_opcode_t);
|
||||
static bool LVEWX(ppu_thread&, ppu_opcode_t);
|
||||
static bool MULHD(ppu_thread&, ppu_opcode_t);
|
||||
static bool MULHW(ppu_thread&, ppu_opcode_t);
|
||||
static bool LDARX(ppu_thread&, ppu_opcode_t);
|
||||
static bool DCBF(ppu_thread&, ppu_opcode_t);
|
||||
static bool LBZX(ppu_thread&, ppu_opcode_t);
|
||||
static bool LVX(ppu_thread&, ppu_opcode_t);
|
||||
static bool NEG(ppu_thread&, ppu_opcode_t);
|
||||
static bool LBZUX(ppu_thread&, ppu_opcode_t);
|
||||
static bool NOR(ppu_thread&, ppu_opcode_t);
|
||||
static bool STVEBX(ppu_thread&, ppu_opcode_t);
|
||||
static bool SUBFE(ppu_thread&, ppu_opcode_t);
|
||||
static bool ADDE(ppu_thread&, ppu_opcode_t);
|
||||
static bool MTOCRF(ppu_thread&, ppu_opcode_t);
|
||||
static bool STDX(ppu_thread&, ppu_opcode_t);
|
||||
static bool STWCX(ppu_thread&, ppu_opcode_t);
|
||||
static bool STWX(ppu_thread&, ppu_opcode_t);
|
||||
static bool STVEHX(ppu_thread&, ppu_opcode_t);
|
||||
static bool STDUX(ppu_thread&, ppu_opcode_t);
|
||||
static bool STWUX(ppu_thread&, ppu_opcode_t);
|
||||
static bool STVEWX(ppu_thread&, ppu_opcode_t);
|
||||
static bool SUBFZE(ppu_thread&, ppu_opcode_t);
|
||||
static bool ADDZE(ppu_thread&, ppu_opcode_t);
|
||||
static bool STDCX(ppu_thread&, ppu_opcode_t);
|
||||
static bool STBX(ppu_thread&, ppu_opcode_t);
|
||||
static bool STVX(ppu_thread&, ppu_opcode_t);
|
||||
static bool MULLD(ppu_thread&, ppu_opcode_t);
|
||||
static bool SUBFME(ppu_thread&, ppu_opcode_t);
|
||||
static bool ADDME(ppu_thread&, ppu_opcode_t);
|
||||
static bool MULLW(ppu_thread&, ppu_opcode_t);
|
||||
static bool DCBTST(ppu_thread&, ppu_opcode_t);
|
||||
static bool STBUX(ppu_thread&, ppu_opcode_t);
|
||||
static bool ADD(ppu_thread&, ppu_opcode_t);
|
||||
static bool DCBT(ppu_thread&, ppu_opcode_t);
|
||||
static bool LHZX(ppu_thread&, ppu_opcode_t);
|
||||
static bool EQV(ppu_thread&, ppu_opcode_t);
|
||||
static bool ECIWX(ppu_thread&, ppu_opcode_t);
|
||||
static bool LHZUX(ppu_thread&, ppu_opcode_t);
|
||||
static bool XOR(ppu_thread&, ppu_opcode_t);
|
||||
static bool MFSPR(ppu_thread&, ppu_opcode_t);
|
||||
static bool LWAX(ppu_thread&, ppu_opcode_t);
|
||||
static bool DST(ppu_thread&, ppu_opcode_t);
|
||||
static bool LHAX(ppu_thread&, ppu_opcode_t);
|
||||
static bool LVXL(ppu_thread&, ppu_opcode_t);
|
||||
static bool MFTB(ppu_thread&, ppu_opcode_t);
|
||||
static bool LWAUX(ppu_thread&, ppu_opcode_t);
|
||||
static bool DSTST(ppu_thread&, ppu_opcode_t);
|
||||
static bool LHAUX(ppu_thread&, ppu_opcode_t);
|
||||
static bool STHX(ppu_thread&, ppu_opcode_t);
|
||||
static bool ORC(ppu_thread&, ppu_opcode_t);
|
||||
static bool ECOWX(ppu_thread&, ppu_opcode_t);
|
||||
static bool STHUX(ppu_thread&, ppu_opcode_t);
|
||||
static bool OR(ppu_thread&, ppu_opcode_t);
|
||||
static bool DIVDU(ppu_thread&, ppu_opcode_t);
|
||||
static bool DIVWU(ppu_thread&, ppu_opcode_t);
|
||||
static bool MTSPR(ppu_thread&, ppu_opcode_t);
|
||||
static bool DCBI(ppu_thread&, ppu_opcode_t);
|
||||
static bool NAND(ppu_thread&, ppu_opcode_t);
|
||||
static bool STVXL(ppu_thread&, ppu_opcode_t);
|
||||
static bool DIVD(ppu_thread&, ppu_opcode_t);
|
||||
static bool DIVW(ppu_thread&, ppu_opcode_t);
|
||||
static bool LVLX(ppu_thread&, ppu_opcode_t);
|
||||
static bool LDBRX(ppu_thread&, ppu_opcode_t);
|
||||
static bool LSWX(ppu_thread&, ppu_opcode_t);
|
||||
static bool LWBRX(ppu_thread&, ppu_opcode_t);
|
||||
static bool LFSX(ppu_thread&, ppu_opcode_t);
|
||||
static bool SRW(ppu_thread&, ppu_opcode_t);
|
||||
static bool SRD(ppu_thread&, ppu_opcode_t);
|
||||
static bool LVRX(ppu_thread&, ppu_opcode_t);
|
||||
static bool LSWI(ppu_thread&, ppu_opcode_t);
|
||||
static bool LFSUX(ppu_thread&, ppu_opcode_t);
|
||||
static bool SYNC(ppu_thread&, ppu_opcode_t);
|
||||
static bool LFDX(ppu_thread&, ppu_opcode_t);
|
||||
static bool LFDUX(ppu_thread&, ppu_opcode_t);
|
||||
static bool STVLX(ppu_thread&, ppu_opcode_t);
|
||||
static bool STDBRX(ppu_thread&, ppu_opcode_t);
|
||||
static bool STSWX(ppu_thread&, ppu_opcode_t);
|
||||
static bool STWBRX(ppu_thread&, ppu_opcode_t);
|
||||
static bool STFSX(ppu_thread&, ppu_opcode_t);
|
||||
static bool STVRX(ppu_thread&, ppu_opcode_t);
|
||||
static bool STFSUX(ppu_thread&, ppu_opcode_t);
|
||||
static bool STSWI(ppu_thread&, ppu_opcode_t);
|
||||
static bool STFDX(ppu_thread&, ppu_opcode_t);
|
||||
static bool STFDUX(ppu_thread&, ppu_opcode_t);
|
||||
static bool LVLXL(ppu_thread&, ppu_opcode_t);
|
||||
static bool LHBRX(ppu_thread&, ppu_opcode_t);
|
||||
static bool SRAW(ppu_thread&, ppu_opcode_t);
|
||||
static bool SRAD(ppu_thread&, ppu_opcode_t);
|
||||
static bool LVRXL(ppu_thread&, ppu_opcode_t);
|
||||
static bool DSS(ppu_thread&, ppu_opcode_t);
|
||||
static bool SRAWI(ppu_thread&, ppu_opcode_t);
|
||||
static bool SRADI(ppu_thread&, ppu_opcode_t);
|
||||
static bool EIEIO(ppu_thread&, ppu_opcode_t);
|
||||
static bool STVLXL(ppu_thread&, ppu_opcode_t);
|
||||
static bool STHBRX(ppu_thread&, ppu_opcode_t);
|
||||
static bool EXTSH(ppu_thread&, ppu_opcode_t);
|
||||
static bool STVRXL(ppu_thread&, ppu_opcode_t);
|
||||
static bool EXTSB(ppu_thread&, ppu_opcode_t);
|
||||
static bool STFIWX(ppu_thread&, ppu_opcode_t);
|
||||
static bool EXTSW(ppu_thread&, ppu_opcode_t);
|
||||
static bool ICBI(ppu_thread&, ppu_opcode_t);
|
||||
static bool DCBZ(ppu_thread&, ppu_opcode_t);
|
||||
static bool LWZ(ppu_thread&, ppu_opcode_t);
|
||||
static bool LWZU(ppu_thread&, ppu_opcode_t);
|
||||
static bool LBZ(ppu_thread&, ppu_opcode_t);
|
||||
static bool LBZU(ppu_thread&, ppu_opcode_t);
|
||||
static bool STW(ppu_thread&, ppu_opcode_t);
|
||||
static bool STWU(ppu_thread&, ppu_opcode_t);
|
||||
static bool STB(ppu_thread&, ppu_opcode_t);
|
||||
static bool STBU(ppu_thread&, ppu_opcode_t);
|
||||
static bool LHZ(ppu_thread&, ppu_opcode_t);
|
||||
static bool LHZU(ppu_thread&, ppu_opcode_t);
|
||||
static bool LHA(ppu_thread&, ppu_opcode_t);
|
||||
static bool LHAU(ppu_thread&, ppu_opcode_t);
|
||||
static bool STH(ppu_thread&, ppu_opcode_t);
|
||||
static bool STHU(ppu_thread&, ppu_opcode_t);
|
||||
static bool LMW(ppu_thread&, ppu_opcode_t);
|
||||
static bool STMW(ppu_thread&, ppu_opcode_t);
|
||||
static bool LFS(ppu_thread&, ppu_opcode_t);
|
||||
static bool LFSU(ppu_thread&, ppu_opcode_t);
|
||||
static bool LFD(ppu_thread&, ppu_opcode_t);
|
||||
static bool LFDU(ppu_thread&, ppu_opcode_t);
|
||||
static bool STFS(ppu_thread&, ppu_opcode_t);
|
||||
static bool STFSU(ppu_thread&, ppu_opcode_t);
|
||||
static bool STFD(ppu_thread&, ppu_opcode_t);
|
||||
static bool STFDU(ppu_thread&, ppu_opcode_t);
|
||||
static bool LD(ppu_thread&, ppu_opcode_t);
|
||||
static bool LDU(ppu_thread&, ppu_opcode_t);
|
||||
static bool LWA(ppu_thread&, ppu_opcode_t);
|
||||
static bool STD(ppu_thread&, ppu_opcode_t);
|
||||
static bool STDU(ppu_thread&, ppu_opcode_t);
|
||||
static bool FDIVS(ppu_thread&, ppu_opcode_t);
|
||||
static bool FSUBS(ppu_thread&, ppu_opcode_t);
|
||||
static bool FADDS(ppu_thread&, ppu_opcode_t);
|
||||
static bool FSQRTS(ppu_thread&, ppu_opcode_t);
|
||||
static bool FRES(ppu_thread&, ppu_opcode_t);
|
||||
static bool FMULS(ppu_thread&, ppu_opcode_t);
|
||||
static bool FMADDS(ppu_thread&, ppu_opcode_t);
|
||||
static bool FMSUBS(ppu_thread&, ppu_opcode_t);
|
||||
static bool FNMSUBS(ppu_thread&, ppu_opcode_t);
|
||||
static bool FNMADDS(ppu_thread&, ppu_opcode_t);
|
||||
static bool MTFSB1(ppu_thread&, ppu_opcode_t);
|
||||
static bool MCRFS(ppu_thread&, ppu_opcode_t);
|
||||
static bool MTFSB0(ppu_thread&, ppu_opcode_t);
|
||||
static bool MTFSFI(ppu_thread&, ppu_opcode_t);
|
||||
static bool MFFS(ppu_thread&, ppu_opcode_t);
|
||||
static bool MTFSF(ppu_thread&, ppu_opcode_t);
|
||||
static bool FCMPU(ppu_thread&, ppu_opcode_t);
|
||||
static bool FRSP(ppu_thread&, ppu_opcode_t);
|
||||
static bool FCTIW(ppu_thread&, ppu_opcode_t);
|
||||
static bool FCTIWZ(ppu_thread&, ppu_opcode_t);
|
||||
static bool FDIV(ppu_thread&, ppu_opcode_t);
|
||||
static bool FSUB(ppu_thread&, ppu_opcode_t);
|
||||
static bool FADD(ppu_thread&, ppu_opcode_t);
|
||||
static bool FSQRT(ppu_thread&, ppu_opcode_t);
|
||||
static bool FSEL(ppu_thread&, ppu_opcode_t);
|
||||
static bool FMUL(ppu_thread&, ppu_opcode_t);
|
||||
static bool FRSQRTE(ppu_thread&, ppu_opcode_t);
|
||||
static bool FMSUB(ppu_thread&, ppu_opcode_t);
|
||||
static bool FMADD(ppu_thread&, ppu_opcode_t);
|
||||
static bool FNMSUB(ppu_thread&, ppu_opcode_t);
|
||||
static bool FNMADD(ppu_thread&, ppu_opcode_t);
|
||||
static bool FCMPO(ppu_thread&, ppu_opcode_t);
|
||||
static bool FNEG(ppu_thread&, ppu_opcode_t);
|
||||
static bool FMR(ppu_thread&, ppu_opcode_t);
|
||||
static bool FNABS(ppu_thread&, ppu_opcode_t);
|
||||
static bool FABS(ppu_thread&, ppu_opcode_t);
|
||||
static bool FCTID(ppu_thread&, ppu_opcode_t);
|
||||
static bool FCTIDZ(ppu_thread&, ppu_opcode_t);
|
||||
static bool FCFID(ppu_thread&, ppu_opcode_t);
|
||||
|
||||
static bool UNK(PPUThread&, ppu_opcode_t);
|
||||
static bool UNK(ppu_thread&, ppu_opcode_t);
|
||||
};
|
||||
|
||||
struct ppu_interpreter_precise final : ppu_interpreter
|
||||
|
@ -114,9 +114,9 @@ cfg::set_entry g_cfg_load_libs(cfg::root.core, "Load libraries");
|
||||
extern std::string ppu_get_function_name(const std::string& module, u32 fnid);
|
||||
extern std::string ppu_get_variable_name(const std::string& module, u32 vnid);
|
||||
|
||||
extern void sys_initialize_tls(PPUThread&, u64, u32, u32, u32);
|
||||
extern void sys_initialize_tls(ppu_thread&, u64, u32, u32, u32);
|
||||
|
||||
extern void ppu_initialize(const std::string& name, const std::vector<ppu_function>& set, u32 entry);
|
||||
extern void ppu_initialize(const std::string& name, const std::vector<ppu_function>& set);
|
||||
|
||||
extern u32 g_ps3_sdk_version;
|
||||
|
||||
@ -139,17 +139,17 @@ extern std::string ppu_get_module_function_name(u32 index)
|
||||
return fmt::format(".%u", index);
|
||||
}
|
||||
|
||||
extern void ppu_execute_function(PPUThread& ppu, u32 index)
|
||||
extern void ppu_execute_function(ppu_thread& ppu, u32 index)
|
||||
{
|
||||
if (index < g_ppu_function_cache.size())
|
||||
{
|
||||
// If autopause occures, check_status() will hold the thread until unpaused.
|
||||
if (debug::autopause::pause_function(g_ppu_fnid_cache[index]) && ppu.check_status()) throw cpu_state::ret;
|
||||
if (debug::autopause::pause_function(g_ppu_fnid_cache[index]) && ppu.check_state()) throw cpu_state::ret;
|
||||
|
||||
if (const auto func = g_ppu_function_cache[index])
|
||||
{
|
||||
func(ppu);
|
||||
LOG_TRACE(HLE, "'%s' finished, r3=0x%llx", ppu_get_module_function_name(index), ppu.GPR[3]);
|
||||
LOG_TRACE(HLE, "'%s' finished, r3=0x%llx", ppu_get_module_function_name(index), ppu.gpr[3]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -783,7 +783,7 @@ std::shared_ptr<lv2_prx_t> ppu_load_prx(const ppu_prx_object& elf)
|
||||
const u32 addr = vm::cast(s.sh_addr);
|
||||
const u32 size = vm::cast(s.sh_size);
|
||||
|
||||
if (s.sh_type == 1 && addr && size)
|
||||
if (s.sh_type == 1 && addr && size) // TODO: some sections with addr=0 are valid
|
||||
{
|
||||
for (auto i = 0; i < segments.size(); i++)
|
||||
{
|
||||
@ -1138,7 +1138,15 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
||||
// Add functions
|
||||
exec_set.insert(exec_set.end(), prx->funcs.begin(), prx->funcs.end());
|
||||
|
||||
ppu_validate(lle_dir + '/' + name, prx->funcs, prx->funcs[0].addr);
|
||||
if (prx->funcs.empty())
|
||||
{
|
||||
LOG_FATAL(LOADER, "Module %s has no functions!", name);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: fix arguments
|
||||
ppu_validate(lle_dir + '/' + name, prx->funcs, prx->funcs[0].addr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1279,100 +1287,19 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
||||
exec_set.emplace_back(pair);
|
||||
}
|
||||
|
||||
// TODO: adjust for liblv2 loading option
|
||||
using namespace ppu_instructions;
|
||||
|
||||
static const int branch_size = 10 * 4;
|
||||
|
||||
auto make_branch = [](vm::ptr<u32>& ptr, u32 addr, bool last)
|
||||
{
|
||||
const u32 stub = vm::read32(addr);
|
||||
const u32 rtoc = vm::read32(addr + 4);
|
||||
|
||||
*ptr++ = LI(r0, 0);
|
||||
*ptr++ = ORI(r0, r0, stub & 0xffff);
|
||||
*ptr++ = ORIS(r0, r0, stub >> 16);
|
||||
*ptr++ = LI(r2, 0);
|
||||
*ptr++ = ORI(r2, r2, rtoc & 0xffff);
|
||||
*ptr++ = ORIS(r2, r2, rtoc >> 16);
|
||||
*ptr++ = MTCTR(r0);
|
||||
*ptr++ = last ? BCTR() : BCTRL();
|
||||
};
|
||||
|
||||
auto entry = vm::ptr<u32>::make(vm::alloc(48 + branch_size * (::size32(start_funcs) + 1), vm::main));
|
||||
|
||||
// Save initialization args
|
||||
*entry++ = MR(r14, r3);
|
||||
*entry++ = MR(r15, r4);
|
||||
*entry++ = MR(r16, r5);
|
||||
*entry++ = MR(r17, r6);
|
||||
*entry++ = MR(r18, r11);
|
||||
*entry++ = MR(r19, r12);
|
||||
|
||||
if (!g_cfg_load_liblv2)
|
||||
{
|
||||
// Call sys_initialize_tls explicitly
|
||||
*entry++ = MR(r3, r7);
|
||||
*entry++ = MR(r4, r8);
|
||||
*entry++ = MR(r5, r9);
|
||||
*entry++ = MR(r6, r10);
|
||||
*entry++ = HACK(FIND_FUNC(sys_initialize_tls));
|
||||
}
|
||||
|
||||
for (auto& f : start_funcs)
|
||||
{
|
||||
// Reset arguments (TODO)
|
||||
*entry++ = LI(r3, 0);
|
||||
*entry++ = LI(r4, 0);
|
||||
make_branch(entry, f, false);
|
||||
}
|
||||
|
||||
// Restore initialization args
|
||||
*entry++ = MR(r3, r14);
|
||||
*entry++ = MR(r4, r15);
|
||||
*entry++ = MR(r5, r16);
|
||||
*entry++ = MR(r6, r17);
|
||||
*entry++ = MR(r11, r18);
|
||||
*entry++ = MR(r12, r19);
|
||||
|
||||
// Branch to initialization
|
||||
make_branch(entry, static_cast<u32>(elf.header.e_entry), false);
|
||||
|
||||
// Register entry function (addr, size)
|
||||
ppu_function entry_func;
|
||||
entry_func.addr = entry.addr() & -0x1000;
|
||||
entry_func.size = entry.addr() & 0xfff;
|
||||
entry_func.attr += ppu_attr::entry_point;
|
||||
exec_set.emplace_back(entry_func);
|
||||
|
||||
// Initialize recompiler
|
||||
ppu_initialize("", exec_set, static_cast<u32>(elf.header.e_entry));
|
||||
// Initialize interpreter/recompiler
|
||||
ppu_initialize("", exec_set);
|
||||
|
||||
// Set SDK version
|
||||
g_ps3_sdk_version = sdk_version;
|
||||
|
||||
auto ppu = idm::make_ptr<PPUThread>("main_thread");
|
||||
|
||||
ppu->pc = entry.addr() & -0x1000;
|
||||
ppu->stack_size = std::max<u32>(primary_stacksize, 0x4000);
|
||||
ppu->prio = primary_prio;
|
||||
ppu->cpu_init();
|
||||
|
||||
ppu->GPR[2] = 0xdeadbeef; // rtoc
|
||||
ppu->GPR[11] = 0xabadcafe; // OPD ???
|
||||
ppu->GPR[12] = malloc_pagesize;
|
||||
|
||||
// Initialize process arguments
|
||||
std::initializer_list<std::string> args = { Emu.GetPath()/*, "-emu"s*/ };
|
||||
|
||||
auto argv = vm::ptr<u64>::make(vm::alloc(SIZE_32(u64) * ::size32(args), vm::main));
|
||||
auto envp = vm::ptr<u64>::make(vm::alloc(::align(SIZE_32(u64), 0x10), vm::main));
|
||||
*envp = 0;
|
||||
|
||||
ppu->GPR[3] = args.size(); // argc
|
||||
ppu->GPR[4] = argv.addr();
|
||||
ppu->GPR[5] = envp.addr();
|
||||
ppu->GPR[6] = 0; // ???
|
||||
|
||||
for (const auto& arg : args)
|
||||
{
|
||||
const u32 arg_size = ::align(::size32(arg) + 1, 0x10);
|
||||
@ -1383,15 +1310,43 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
||||
*argv++ = arg_addr;
|
||||
}
|
||||
|
||||
// Arguments for sys_initialize_tls()
|
||||
ppu->GPR[7] = ppu->id;
|
||||
ppu->GPR[8] = tls_vaddr;
|
||||
ppu->GPR[9] = tls_fsize;
|
||||
ppu->GPR[10] = tls_vsize;
|
||||
argv -= args.size();
|
||||
|
||||
//ppu->state += cpu_state::interrupt;
|
||||
// Initialize main thread
|
||||
auto ppu = idm::make_ptr<ppu_thread>("main_thread", primary_prio, primary_stacksize);
|
||||
|
||||
// Set memory protection
|
||||
// TODO: adjust for liblv2 loading option
|
||||
if (!g_cfg_load_liblv2)
|
||||
{
|
||||
// Set TLS args, call sys_initialize_tls
|
||||
ppu->cmd_list
|
||||
({
|
||||
{ ppu_cmd::set_args, 4 }, u64{ppu->id}, u64{tls_vaddr}, u64{tls_fsize}, u64{tls_vsize},
|
||||
{ ppu_cmd::hle_call, FIND_FUNC(sys_initialize_tls) },
|
||||
});
|
||||
}
|
||||
|
||||
// Run start functions
|
||||
for (u32 func : start_funcs)
|
||||
{
|
||||
// Reset arguments, run module entry point function
|
||||
ppu->cmd_list
|
||||
({
|
||||
{ ppu_cmd::set_args, 2 }, u64{0}, u64{0},
|
||||
{ ppu_cmd::lle_call, func },
|
||||
});
|
||||
}
|
||||
|
||||
// Set command line arguments, run entry function
|
||||
ppu->cmd_list
|
||||
({
|
||||
{ ppu_cmd::set_args, 8 }, u64{args.size()}, u64{argv.addr()}, u64{envp.addr()}, u64{0}, u64{ppu->id}, u64{tls_vaddr}, u64{tls_fsize}, u64{tls_vsize},
|
||||
{ ppu_cmd::set_gpr, 11 }, u64{0xabadcafe},
|
||||
{ ppu_cmd::set_gpr, 12 }, u64{malloc_pagesize},
|
||||
{ ppu_cmd::lle_call, static_cast<u32>(elf.header.e_entry) },
|
||||
});
|
||||
|
||||
// Set actual memory protection (experimental)
|
||||
for (const auto& prog : elf.progs)
|
||||
{
|
||||
const u32 addr = static_cast<u32>(prog.p_vaddr);
|
||||
@ -1399,7 +1354,7 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
||||
|
||||
if (prog.p_type == 0x1 /* LOAD */ && prog.p_memsz && (prog.p_flags & 0x2) == 0 /* W */)
|
||||
{
|
||||
// Set memory protection to read-only where necessary
|
||||
// Set memory protection to read-only when necessary
|
||||
VERIFY(vm::page_protect(addr, ::align(size, 0x1000), 0, 0, vm::page_writable));
|
||||
}
|
||||
}
|
||||
|
@ -197,7 +197,7 @@ public:
|
||||
|
||||
// Call specified function directly if LLE is not available, call LLE equivalent in callback style otherwise
|
||||
template<typename T, T Func, typename... Args, typename RT = std::result_of_t<T(Args...)>>
|
||||
inline RT ppu_execute_function_or_callback(const char* name, PPUThread& ppu, Args&&... args)
|
||||
inline RT ppu_execute_function_or_callback(const char* name, ppu_thread& ppu, Args&&... args)
|
||||
{
|
||||
return Func(std::forward<Args>(args)...);
|
||||
}
|
||||
|
@ -57,6 +57,9 @@ cfg::map_entry<ppu_decoder_type> g_cfg_ppu_decoder(cfg::root.core, "PPU Decoder"
|
||||
const ppu_decoder<ppu_interpreter_precise> s_ppu_interpreter_precise;
|
||||
const ppu_decoder<ppu_interpreter_fast> s_ppu_interpreter_fast;
|
||||
|
||||
extern void ppu_execute_syscall(ppu_thread& ppu, u64 code);
|
||||
extern void ppu_execute_function(ppu_thread& ppu, u32 index);
|
||||
|
||||
const auto s_ppu_compiled = static_cast<u32*>(memory_helper::reserve_memory(0x100000000));
|
||||
|
||||
extern void ppu_register_function_at(u32 addr, ppu_function_t ptr)
|
||||
@ -68,82 +71,117 @@ extern void ppu_register_function_at(u32 addr, ppu_function_t ptr)
|
||||
}
|
||||
}
|
||||
|
||||
std::string PPUThread::get_name() const
|
||||
std::string ppu_thread::get_name() const
|
||||
{
|
||||
return fmt::format("PPU[0x%x] Thread (%s)", id, m_name);
|
||||
}
|
||||
|
||||
std::string PPUThread::dump() const
|
||||
std::string ppu_thread::dump() const
|
||||
{
|
||||
std::string ret = "Registers:\n=========\n";
|
||||
std::string ret;
|
||||
|
||||
for (uint i = 0; i<32; ++i) ret += fmt::format("GPR[%d] = 0x%llx\n", i, GPR[i]);
|
||||
for (uint i = 0; i<32; ++i) ret += fmt::format("FPR[%d] = %.6G\n", i, FPR[i]);
|
||||
for (uint i = 0; i<32; ++i) ret += fmt::format("VR[%d] = 0x%s [%s]\n", i, VR[i].to_hex().c_str(), VR[i].to_xyzw().c_str());
|
||||
ret += fmt::format("CR = 0x%08x\n", GetCR());
|
||||
ret += fmt::format("LR = 0x%llx\n", LR);
|
||||
ret += fmt::format("CTR = 0x%llx\n", CTR);
|
||||
ret += fmt::format("XER = [CA=%u | OV=%u | SO=%u | CNT=%u]\n", u32{ CA }, u32{ OV }, u32{ SO }, u32{ XCNT });
|
||||
//ret += fmt::format("FPSCR = 0x%x "
|
||||
// "[RN=%d | NI=%d | XE=%d | ZE=%d | UE=%d | OE=%d | VE=%d | "
|
||||
// "VXCVI=%d | VXSQRT=%d | VXSOFT=%d | FPRF=%d | "
|
||||
// "FI=%d | FR=%d | VXVC=%d | VXIMZ=%d | "
|
||||
// "VXZDZ=%d | VXIDI=%d | VXISI=%d | VXSNAN=%d | "
|
||||
// "XX=%d | ZX=%d | UX=%d | OX=%d | VX=%d | FEX=%d | FX=%d]\n",
|
||||
// FPSCR.FPSCR,
|
||||
// u32{ FPSCR.RN },
|
||||
// u32{ FPSCR.NI }, u32{ FPSCR.XE }, u32{ FPSCR.ZE }, u32{ FPSCR.UE }, u32{ FPSCR.OE }, u32{ FPSCR.VE },
|
||||
// u32{ FPSCR.VXCVI }, u32{ FPSCR.VXSQRT }, u32{ FPSCR.VXSOFT }, u32{ FPSCR.FPRF },
|
||||
// u32{ FPSCR.FI }, u32{ FPSCR.FR }, u32{ FPSCR.VXVC }, u32{ FPSCR.VXIMZ },
|
||||
// u32{ FPSCR.VXZDZ }, u32{ FPSCR.VXIDI }, u32{ FPSCR.VXISI }, u32{ FPSCR.VXSNAN },
|
||||
// u32{ FPSCR.XX }, u32{ FPSCR.ZX }, u32{ FPSCR.UX }, u32{ FPSCR.OX }, u32{ FPSCR.VX }, u32{ FPSCR.FEX }, u32{ FPSCR.FX });
|
||||
ret += fmt::format("State: 0x%08x\n", state.load());
|
||||
ret += fmt::format("Priority: %d\n", prio);
|
||||
|
||||
ret += "\nRegisters:\n=========\n";
|
||||
for (uint i = 0; i < 32; ++i) ret += fmt::format("GPR[%d] = 0x%llx\n", i, gpr[i]);
|
||||
for (uint i = 0; i < 32; ++i) ret += fmt::format("FPR[%d] = %.6G\n", i, fpr[i]);
|
||||
for (uint i = 0; i < 32; ++i) ret += fmt::format("VR[%d] = 0x%s [%s]\n", i, vr[i].to_hex().c_str(), vr[i].to_xyzw().c_str());
|
||||
|
||||
if (g_cfg_ppu_decoder.get() != ppu_decoder_type::llvm)
|
||||
{
|
||||
ret += fmt::format("CR = 0x%08x\n", cr_pack());
|
||||
ret += fmt::format("LR = 0x%llx\n", lr);
|
||||
ret += fmt::format("CTR = 0x%llx\n", ctr);
|
||||
ret += fmt::format("VRSAVE = 0x%08x\n", vrsave);
|
||||
ret += fmt::format("XER = [CA=%u | OV=%u | SO=%u | CNT=%u]\n", xer.ca, xer.ov, xer.so, xer.cnt);
|
||||
ret += fmt::format("VSCR = [SAT=%u | NJ=%u]\n", sat, nj);
|
||||
ret += fmt::format("FPSCR = [FL=%u | FG=%u | FE=%u | FU=%u]\n", fpscr.fl, fpscr.fg, fpscr.fe, fpscr.fu);
|
||||
|
||||
ret += "\nCall stack:\n=========\n";
|
||||
ret += fmt::format("0x%08x (0x0) called\n", cia);
|
||||
const u32 stack_max = ::align(stack_addr + stack_size, 0x200) - 0x200;
|
||||
for (u64 sp = vm::read64(static_cast<u32>(gpr[1])); sp >= stack_addr && sp < stack_max; sp = vm::read64(static_cast<u32>(sp)))
|
||||
{
|
||||
// TODO: print also function addresses
|
||||
ret += fmt::format("> from 0x%08llx (0x0)\n", vm::read64(static_cast<u32>(sp + 16)));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void PPUThread::cpu_init()
|
||||
{
|
||||
if (!stack_addr)
|
||||
{
|
||||
if (!stack_size)
|
||||
{
|
||||
throw EXCEPTION("Invalid stack size");
|
||||
}
|
||||
|
||||
stack_addr = vm::alloc(stack_size, vm::stack);
|
||||
|
||||
if (!stack_addr)
|
||||
{
|
||||
throw EXCEPTION("Out of stack memory");
|
||||
}
|
||||
}
|
||||
|
||||
GPR[1] = align(stack_addr + stack_size, 0x200) - 0x200;
|
||||
}
|
||||
|
||||
extern thread_local std::string(*g_tls_log_prefix)();
|
||||
|
||||
void PPUThread::cpu_task()
|
||||
void ppu_thread::cpu_task()
|
||||
{
|
||||
//SetHostRoundingMode(FPSCR_RN_NEAR);
|
||||
|
||||
return custom_task ? custom_task(*this) : fast_call(pc, static_cast<u32>(GPR[2]));
|
||||
// Execute cmd_queue
|
||||
while (ppu_cmd cmd = cmd_wait())
|
||||
{
|
||||
const u32 pos = cmd_queue.peek() + 1; // Additional arguments start from [pos]
|
||||
const u32 arg = cmd.arg2<u32>(); // 32-bit arg extracted
|
||||
|
||||
switch (u32 type = cmd.arg1<u32>())
|
||||
{
|
||||
case ppu_cmd::opcode:
|
||||
{
|
||||
cmd_pop(), s_ppu_interpreter_fast.decode(arg)(*this, {arg});
|
||||
break;
|
||||
}
|
||||
case ppu_cmd::set_gpr:
|
||||
{
|
||||
if (arg >= 32)
|
||||
{
|
||||
throw fmt::exception("Invalid ppu_cmd::set_gpr arg (0x%x)" HERE, arg);
|
||||
}
|
||||
|
||||
gpr[arg % 32] = cmd_queue[pos].load().as<u64>();
|
||||
cmd_pop(1);
|
||||
break;
|
||||
}
|
||||
case ppu_cmd::set_args:
|
||||
{
|
||||
if (arg > 8)
|
||||
{
|
||||
throw fmt::exception("Unsupported ppu_cmd::set_args size (0x%x)" HERE, arg);
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < arg; i++)
|
||||
{
|
||||
gpr[i + 3] = cmd_queue[pos + i].load().as<u64>();
|
||||
}
|
||||
|
||||
cmd_pop(arg);
|
||||
break;
|
||||
}
|
||||
case ppu_cmd::lle_call:
|
||||
{
|
||||
const vm::ptr<u32> opd(arg < 32 ? vm::cast(gpr[arg]) : vm::cast(arg));
|
||||
cmd_pop(), fast_call(opd[0], opd[1]);
|
||||
break;
|
||||
}
|
||||
case ppu_cmd::hle_call:
|
||||
{
|
||||
cmd_pop(), ppu_execute_function(*this, arg);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw fmt::exception("Unknown ppu_cmd(0x%x)" HERE, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PPUThread::cpu_task_main()
|
||||
void ppu_thread::exec_task()
|
||||
{
|
||||
if (g_cfg_ppu_decoder.get() == ppu_decoder_type::llvm)
|
||||
{
|
||||
return reinterpret_cast<ppu_function_t>((std::uintptr_t)s_ppu_compiled[pc / 4])(*this);
|
||||
return reinterpret_cast<ppu_function_t>((std::uintptr_t)s_ppu_compiled[cia / 4])(*this);
|
||||
}
|
||||
|
||||
g_tls_log_prefix = []
|
||||
{
|
||||
const auto cpu = static_cast<PPUThread*>(get_current_cpu_thread());
|
||||
|
||||
return fmt::format("%s [0x%08x]", cpu->get_name(), cpu->pc);
|
||||
};
|
||||
|
||||
const auto base = vm::_ptr<const u8>(0);
|
||||
|
||||
// Select opcode table
|
||||
@ -159,12 +197,12 @@ void PPUThread::cpu_task_main()
|
||||
{
|
||||
if (UNLIKELY(state.load()))
|
||||
{
|
||||
if (check_status()) return;
|
||||
if (check_state()) return;
|
||||
}
|
||||
|
||||
// Reinitialize
|
||||
{
|
||||
const auto _ops = _mm_shuffle_epi8(_mm_lddqu_si128(reinterpret_cast<const __m128i*>(base + pc)), _mm_set_epi8(12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3));
|
||||
const auto _ops = _mm_shuffle_epi8(_mm_lddqu_si128(reinterpret_cast<const __m128i*>(base + cia)), _mm_set_epi8(12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3));
|
||||
_op.vi = _ops;
|
||||
const v128 _i = v128::fromV(_mm_and_si128(_mm_or_si128(_mm_slli_epi32(_op.vi, 6), _mm_srli_epi32(_op.vi, 26)), _mm_set1_epi32(0x1ffff)));
|
||||
func0 = table[_i._u32[0]];
|
||||
@ -175,14 +213,14 @@ void PPUThread::cpu_task_main()
|
||||
|
||||
while (LIKELY(func0(*this, { _op._u32[0] })))
|
||||
{
|
||||
if (pc += 4, LIKELY(func1(*this, { _op._u32[1] })))
|
||||
if (cia += 4, LIKELY(func1(*this, { _op._u32[1] })))
|
||||
{
|
||||
if (pc += 4, LIKELY(func2(*this, { _op._u32[2] })))
|
||||
if (cia += 4, LIKELY(func2(*this, { _op._u32[2] })))
|
||||
{
|
||||
pc += 4;
|
||||
cia += 4;
|
||||
func0 = func3;
|
||||
|
||||
const auto _ops = _mm_shuffle_epi8(_mm_lddqu_si128(reinterpret_cast<const __m128i*>(base + pc + 4)), _mm_set_epi8(12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3));
|
||||
const auto _ops = _mm_shuffle_epi8(_mm_lddqu_si128(reinterpret_cast<const __m128i*>(base + cia + 4)), _mm_set_epi8(12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3));
|
||||
_op.vi = _mm_alignr_epi8(_ops, _op.vi, 12);
|
||||
const v128 _i = v128::fromV(_mm_and_si128(_mm_or_si128(_mm_slli_epi32(_op.vi, 6), _mm_srli_epi32(_op.vi, 26)), _mm_set1_epi32(0x1ffff)));
|
||||
func1 = table[_i._u32[1]];
|
||||
@ -204,87 +242,7 @@ void PPUThread::cpu_task_main()
|
||||
|
||||
constexpr auto stop_state = make_bitset(cpu_state::stop, cpu_state::exit, cpu_state::suspend);
|
||||
|
||||
atomic_t<u32> g_ppu_core[2]{};
|
||||
|
||||
bool PPUThread::handle_interrupt()
|
||||
{
|
||||
// Reschedule and wake up a new thread, possibly this one as well.
|
||||
return false;
|
||||
|
||||
// Check virtual core allocation
|
||||
if (g_ppu_core[0] != id && g_ppu_core[1] != id)
|
||||
{
|
||||
auto cpu0 = idm::get<PPUThread>(g_ppu_core[0]);
|
||||
auto cpu1 = idm::get<PPUThread>(g_ppu_core[1]);
|
||||
|
||||
if (cpu0 && cpu1)
|
||||
{
|
||||
if (cpu1->prio > cpu0->prio)
|
||||
{
|
||||
cpu0 = std::move(cpu1);
|
||||
}
|
||||
|
||||
// Preempt thread with the lowest priority
|
||||
if (prio < cpu0->prio)
|
||||
{
|
||||
cpu0->state += cpu_state::interrupt;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try to obtain a virtual core in optimistic way
|
||||
if (g_ppu_core[0].compare_and_swap_test(0, id) || g_ppu_core[1].compare_and_swap_test(0, id))
|
||||
{
|
||||
state -= cpu_state::interrupt;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Select appropriate thread
|
||||
u32 top_prio = -1;
|
||||
u32 selected = -1;
|
||||
|
||||
idm::select<PPUThread>([&](u32 id, PPUThread& ppu)
|
||||
{
|
||||
// Exclude suspended and low-priority threads
|
||||
if (!ppu.state.test(stop_state) && ppu.prio < top_prio /*&& (!ppu.is_sleep() || ppu.state & cpu_state::signal)*/)
|
||||
{
|
||||
top_prio = ppu.prio;
|
||||
selected = id;
|
||||
}
|
||||
});
|
||||
|
||||
// If current thread selected
|
||||
if (selected == id)
|
||||
{
|
||||
state -= cpu_state::interrupt;
|
||||
VERIFY(g_ppu_core[0] == id || g_ppu_core[1] == id);
|
||||
return true;
|
||||
}
|
||||
|
||||
// If another thread selected
|
||||
const auto thread = idm::get<PPUThread>(selected);
|
||||
|
||||
// Lend virtual core to another thread
|
||||
if (thread && thread->state.test_and_reset(cpu_state::interrupt))
|
||||
{
|
||||
g_ppu_core[0].compare_and_swap(id, thread->id);
|
||||
g_ppu_core[1].compare_and_swap(id, thread->id);
|
||||
(*thread)->lock_notify();
|
||||
}
|
||||
else
|
||||
{
|
||||
g_ppu_core[0].compare_and_swap(id, 0);
|
||||
g_ppu_core[1].compare_and_swap(id, 0);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
PPUThread::~PPUThread()
|
||||
ppu_thread::~ppu_thread()
|
||||
{
|
||||
if (stack_addr)
|
||||
{
|
||||
@ -292,40 +250,126 @@ PPUThread::~PPUThread()
|
||||
}
|
||||
}
|
||||
|
||||
PPUThread::PPUThread(const std::string& name)
|
||||
ppu_thread::ppu_thread(const std::string& name, u32 prio, u32 stack)
|
||||
: cpu_thread(cpu_type::ppu)
|
||||
, prio(prio)
|
||||
, stack_size(std::max<u32>(stack, 0x4000))
|
||||
, stack_addr(vm::alloc(stack_size, vm::stack))
|
||||
, m_name(name)
|
||||
{
|
||||
if (!stack_addr)
|
||||
{
|
||||
throw fmt::exception("Out of stack memory (size=0x%x)" HERE, stack_size);
|
||||
}
|
||||
|
||||
gpr[1] = ::align(stack_addr + stack_size, 0x200) - 0x200;
|
||||
}
|
||||
|
||||
be_t<u64>* PPUThread::get_stack_arg(s32 i, u64 align)
|
||||
void ppu_thread::cmd_push(ppu_cmd cmd)
|
||||
{
|
||||
// Reserve queue space
|
||||
const u32 pos = cmd_queue.push_begin();
|
||||
|
||||
// Write single command
|
||||
cmd_queue[pos] = cmd;
|
||||
}
|
||||
|
||||
void ppu_thread::cmd_list(std::initializer_list<ppu_cmd> list)
|
||||
{
|
||||
// Reserve queue space
|
||||
const u32 pos = cmd_queue.push_begin(static_cast<u32>(list.size()));
|
||||
|
||||
// Write command tail in relaxed manner
|
||||
for (u32 i = 1; i < list.size(); i++)
|
||||
{
|
||||
cmd_queue[pos + i].raw() = list.begin()[i];
|
||||
}
|
||||
|
||||
// Write command head after all
|
||||
cmd_queue[pos] = *list.begin();
|
||||
}
|
||||
|
||||
void ppu_thread::cmd_pop(u32 count)
|
||||
{
|
||||
// Get current position
|
||||
const u32 pos = cmd_queue.peek();
|
||||
|
||||
// Clean command buffer for command tail
|
||||
for (u32 i = 1; i <= count; i++)
|
||||
{
|
||||
cmd_queue[pos + i].raw() = ppu_cmd{};
|
||||
}
|
||||
|
||||
// Free
|
||||
cmd_queue.pop_end(count + 1);
|
||||
}
|
||||
|
||||
ppu_cmd ppu_thread::cmd_wait()
|
||||
{
|
||||
std::unique_lock<named_thread> lock(*this, std::defer_lock);
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (UNLIKELY(state.load()))
|
||||
{
|
||||
if (lock) lock.unlock();
|
||||
|
||||
if (check_state()) // check_status() requires unlocked mutex
|
||||
{
|
||||
return ppu_cmd{};
|
||||
}
|
||||
}
|
||||
|
||||
// Lightweight queue doesn't care about mutex state
|
||||
if (ppu_cmd result = cmd_queue[cmd_queue.peek()].exchange(ppu_cmd{}))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!lock)
|
||||
{
|
||||
lock.lock();
|
||||
continue;
|
||||
}
|
||||
|
||||
thread_ctrl::wait(); // Waiting requires locked mutex
|
||||
}
|
||||
}
|
||||
|
||||
be_t<u64>* ppu_thread::get_stack_arg(s32 i, u64 align)
|
||||
{
|
||||
if (align != 1 && align != 2 && align != 4 && align != 8 && align != 16) throw fmt::exception("Unsupported alignment: 0x%llx" HERE, align);
|
||||
return vm::_ptr<u64>(vm::cast((GPR[1] + 0x30 + 0x8 * (i - 1)) & (0 - align), HERE));
|
||||
return vm::_ptr<u64>(vm::cast((gpr[1] + 0x30 + 0x8 * (i - 1)) & (0 - align), HERE));
|
||||
}
|
||||
|
||||
void PPUThread::fast_call(u32 addr, u32 rtoc)
|
||||
void ppu_thread::fast_call(u32 addr, u32 rtoc)
|
||||
{
|
||||
const auto old_PC = pc;
|
||||
const auto old_stack = GPR[1];
|
||||
const auto old_rtoc = GPR[2];
|
||||
const auto old_LR = LR;
|
||||
const auto old_task = std::move(custom_task);
|
||||
const auto old_pc = cia;
|
||||
const auto old_stack = gpr[1];
|
||||
const auto old_rtoc = gpr[2];
|
||||
const auto old_lr = lr;
|
||||
const auto old_func = last_function;
|
||||
const auto old_fmt = g_tls_log_prefix;
|
||||
|
||||
pc = addr;
|
||||
GPR[2] = rtoc;
|
||||
LR = Emu.GetCPUThreadStop();
|
||||
custom_task = nullptr;
|
||||
cia = addr;
|
||||
gpr[2] = rtoc;
|
||||
lr = Emu.GetCPUThreadStop();
|
||||
last_function = nullptr;
|
||||
|
||||
g_tls_log_prefix = []
|
||||
{
|
||||
const auto ppu = static_cast<ppu_thread*>(get_current_cpu_thread());
|
||||
|
||||
return fmt::format("%s [0x%08x]", ppu->get_name(), ppu->cia);
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
cpu_task_main();
|
||||
exec_task();
|
||||
|
||||
if (GPR[1] != old_stack && !state.test(cpu_state::ret) && !state.test(cpu_state::exit)) // GPR[1] shouldn't change
|
||||
if (gpr[1] != old_stack && !state.test(cpu_state::ret) && !state.test(cpu_state::exit)) // gpr[1] shouldn't change
|
||||
{
|
||||
throw fmt::exception("Stack inconsistency (addr=0x%x, rtoc=0x%x, SP=0x%llx, old=0x%llx)", addr, rtoc, GPR[1], old_stack);
|
||||
throw fmt::exception("Stack inconsistency (addr=0x%x, rtoc=0x%x, SP=0x%llx, old=0x%llx)", addr, rtoc, gpr[1], old_stack);
|
||||
}
|
||||
}
|
||||
catch (cpu_state _s)
|
||||
@ -348,25 +392,17 @@ void PPUThread::fast_call(u32 addr, u32 rtoc)
|
||||
|
||||
state -= cpu_state::ret;
|
||||
|
||||
pc = old_PC;
|
||||
GPR[1] = old_stack;
|
||||
GPR[2] = old_rtoc;
|
||||
LR = old_LR;
|
||||
custom_task = std::move(old_task);
|
||||
cia = old_pc;
|
||||
gpr[1] = old_stack;
|
||||
gpr[2] = old_rtoc;
|
||||
lr = old_lr;
|
||||
last_function = old_func;
|
||||
|
||||
//if (custom_task)
|
||||
//{
|
||||
// state += cpu_state::interrupt;
|
||||
// handle_interrupt();
|
||||
//}
|
||||
g_tls_log_prefix = old_fmt;
|
||||
}
|
||||
|
||||
const ppu_decoder<ppu_itype> s_ppu_itype;
|
||||
|
||||
extern u64 get_timebased_time();
|
||||
extern void ppu_execute_syscall(PPUThread& ppu, u64 code);
|
||||
extern void ppu_execute_function(PPUThread& ppu, u32 index);
|
||||
extern ppu_function_t ppu_get_syscall(u64 code);
|
||||
extern std::string ppu_get_syscall_name(u64 code);
|
||||
extern ppu_function_t ppu_get_function(u32 index);
|
||||
@ -434,7 +470,7 @@ static bool adde_carry(u64 a, u64 b, bool c)
|
||||
#endif
|
||||
}
|
||||
|
||||
extern void ppu_initialize(const std::string& name, const std::vector<ppu_function>& funcs, u32 entry)
|
||||
extern void ppu_initialize(const std::string& name, const std::vector<ppu_function>& funcs)
|
||||
{
|
||||
if (g_cfg_ppu_decoder.get() != ppu_decoder_type::llvm || funcs.empty())
|
||||
{
|
||||
@ -485,7 +521,7 @@ extern void ppu_initialize(const std::string& name, const std::vector<ppu_functi
|
||||
module->setTargetTriple(Triple::normalize(sys::getProcessTriple()));
|
||||
|
||||
// Initialize translator
|
||||
std::unique_ptr<PPUTranslator> translator = std::make_unique<PPUTranslator>(g_llvm_ctx, module.get(), 0, entry);
|
||||
std::unique_ptr<PPUTranslator> translator = std::make_unique<PPUTranslator>(g_llvm_ctx, module.get(), 0);
|
||||
|
||||
// Define some types
|
||||
const auto _void = Type::getVoidTy(g_llvm_ctx);
|
||||
|
@ -3,28 +3,123 @@
|
||||
#include "Common.h"
|
||||
#include "../CPU/CPUThread.h"
|
||||
#include "../Memory/vm.h"
|
||||
#include "Utilities/lockless.h"
|
||||
|
||||
class PPUThread final : public cpu_thread
|
||||
// Lightweight PPU command queue element
|
||||
struct ppu_cmd : any64
|
||||
{
|
||||
enum : u32
|
||||
{
|
||||
none = 0,
|
||||
|
||||
opcode, // Execute PPU instruction from arg
|
||||
set_gpr, // Set gpr[arg] (+1 cmd)
|
||||
set_args, // Set general-purpose args (+arg cmd)
|
||||
lle_call, // Load addr and rtoc at *arg or *gpr[arg] and execute
|
||||
hle_call, // Execute function by index (arg)
|
||||
};
|
||||
|
||||
struct pair_t
|
||||
{
|
||||
any32 arg1;
|
||||
any32 arg2;
|
||||
};
|
||||
|
||||
ppu_cmd() = default;
|
||||
|
||||
template<typename T>
|
||||
ppu_cmd(const T& value)
|
||||
: any64(value)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T1, typename T2>
|
||||
ppu_cmd(const T1& arg1, const T2& arg2)
|
||||
: any64(pair_t{arg1, arg2})
|
||||
{
|
||||
}
|
||||
|
||||
explicit operator bool() const
|
||||
{
|
||||
return as<u64>() != 0;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
decltype(auto) arg1()
|
||||
{
|
||||
return as<pair_t>().arg1.as<T>();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
decltype(auto) arg1() const
|
||||
{
|
||||
return as<const pair_t>().arg1.as<const T>();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
decltype(auto) arg2()
|
||||
{
|
||||
return as<pair_t>().arg2.as<T>();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
decltype(auto) arg2() const
|
||||
{
|
||||
return as<const pair_t>().arg2.as<const T>();
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(ppu_cmd) == 8 && std::is_pod<ppu_cmd>::value, "Incorrect ppu_cmd struct");
|
||||
|
||||
class ppu_thread : public cpu_thread
|
||||
{
|
||||
public:
|
||||
virtual std::string get_name() const override;
|
||||
virtual std::string dump() const override;
|
||||
virtual void cpu_init() override;
|
||||
virtual void cpu_init() override final {}
|
||||
virtual void cpu_task() override;
|
||||
virtual void cpu_task_main();
|
||||
virtual bool handle_interrupt() override;
|
||||
virtual ~PPUThread() override;
|
||||
virtual ~ppu_thread() override;
|
||||
|
||||
PPUThread(const std::string& name);
|
||||
ppu_thread(const std::string& name, u32 prio = 0, u32 stack = 0x10000);
|
||||
|
||||
u64 GPR[32]{}; // General-Purpose Registers
|
||||
f64 FPR[32]{}; // Floating Point Registers
|
||||
v128 VR[32]{}; // Vector Registers
|
||||
alignas(16) bool CR[32]{}; // Condition Registers
|
||||
bool SO{}; // XER: Summary overflow
|
||||
bool OV{}; // XER: Overflow
|
||||
bool CA{}; // XER: Carry
|
||||
u8 XCNT{}; // XER: 0..6
|
||||
u64 gpr[32] = {}; // General-Purpose Registers
|
||||
f64 fpr[32] = {}; // Floating Point Registers
|
||||
v128 vr[32] = {}; // Vector Registers
|
||||
|
||||
alignas(16) bool cr[32] = {}; // Condition Registers (abstract representation)
|
||||
|
||||
// Pack CR bits
|
||||
u32 cr_pack() const
|
||||
{
|
||||
u32 result{};
|
||||
|
||||
for (u32 bit : cr)
|
||||
{
|
||||
result = (result << 1) | bit;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Unpack CR bits
|
||||
void cr_unpack(u32 value)
|
||||
{
|
||||
for (bool& b : cr)
|
||||
{
|
||||
b = (value & 0x1) != 0;
|
||||
value >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Fixed-Point Exception Register (abstract representation)
|
||||
struct
|
||||
{
|
||||
bool so{}; // Summary Overflow
|
||||
bool ov{}; // Overflow
|
||||
bool ca{}; // Carry
|
||||
u8 cnt{}; // 0..6
|
||||
}
|
||||
xer;
|
||||
|
||||
/*
|
||||
Saturation. A sticky status bit indicating that some field in a saturating instruction saturated since the last
|
||||
@ -45,7 +140,7 @@ public:
|
||||
Vector Convert to Fixed-Point with Saturation (vctuxs, vctsxs)
|
||||
0 Indicates no saturation occurred; mtvscr can explicitly clear this bit.
|
||||
*/
|
||||
bool SAT{};
|
||||
bool sat{};
|
||||
|
||||
/*
|
||||
Non-Java. A mode control bit that determines whether vector floating-point operations will be performed
|
||||
@ -54,88 +149,47 @@ public:
|
||||
by Java, IEEE, and C9X standard.
|
||||
1 The non-Java/non-IEEE-compliant mode is selected. If an element in a source vector register
|
||||
contains a denormalized value, the value '0' is used instead. If an instruction causes an underflow
|
||||
exception, the corresponding element in the target VR is cleared to '0'. In both cases, the '0'
|
||||
exception, the corresponding element in the target vr is cleared to '0'. In both cases, the '0'
|
||||
has the same sign as the denormalized or underflowing value.
|
||||
*/
|
||||
bool NJ{ true };
|
||||
bool nj = true;
|
||||
|
||||
bool FL{}; // FPSCR.FPCC.FL
|
||||
bool FG{}; // FPSCR.FPCC.FG
|
||||
bool FE{}; // FPSCR.FPCC.FE
|
||||
bool FU{}; // FPSCR.FPCC.FU
|
||||
struct // Floating-Point Status and Control Register (abstract representation)
|
||||
{
|
||||
bool fl{}; // FPCC.FL
|
||||
bool fg{}; // FPCC.FG
|
||||
bool fe{}; // FPCC.FE
|
||||
bool fu{}; // FPCC.FU
|
||||
}
|
||||
fpscr;
|
||||
|
||||
u64 LR{}; // Link Register
|
||||
u64 CTR{}; // Counter Register
|
||||
u32 VRSAVE{};
|
||||
u32 cia{}; // Current Instruction Address
|
||||
u64 lr{}; // Link Register
|
||||
u64 ctr{}; // Counter Register
|
||||
u32 vrsave{0xffffffff}; // VR Save Register (almost unused)
|
||||
|
||||
u32 pc = 0;
|
||||
u32 prio = -1; // Thread priority
|
||||
u32 stack_addr = 0; // Stack address
|
||||
u32 stack_size = 0; // Stack size
|
||||
u32 prio = 0; // Thread priority (0..3071)
|
||||
const u32 stack_size; // Stack size
|
||||
const u32 stack_addr; // Stack address
|
||||
bool is_joinable = true;
|
||||
bool is_joining = false;
|
||||
|
||||
lf_fifo<atomic_t<ppu_cmd>, 255> cmd_queue; // Command queue for asynchronous operations.
|
||||
|
||||
void cmd_push(ppu_cmd);
|
||||
void cmd_list(std::initializer_list<ppu_cmd>);
|
||||
void cmd_pop(u32 = 0);
|
||||
ppu_cmd cmd_wait(); // Empty command means caller must return, like true from cpu_thread::check_status().
|
||||
|
||||
const char* last_function{}; // Last function name for diagnosis, optimized for speed.
|
||||
|
||||
const std::string m_name; // Thread name
|
||||
|
||||
std::function<void(PPUThread&)> custom_task;
|
||||
|
||||
// Function name can be stored here. Used to print the last called function.
|
||||
const char* last_function = nullptr;
|
||||
|
||||
// When a thread has met an exception, this variable is used to retro propagate it through stack call.
|
||||
std::exception_ptr pending_exception;
|
||||
|
||||
// Pack CR bits
|
||||
u32 GetCR() const
|
||||
{
|
||||
u32 result{};
|
||||
|
||||
for (u32 bit : CR)
|
||||
{
|
||||
result = (result << 1) | bit;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Unpack CR bits
|
||||
void SetCR(u32 value)
|
||||
{
|
||||
for (bool& b : CR)
|
||||
{
|
||||
b = (value & 0x1) != 0;
|
||||
value >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Set CR field
|
||||
void SetCR(u32 field, bool le, bool gt, bool eq, bool so)
|
||||
{
|
||||
CR[field * 4 + 0] = le;
|
||||
CR[field * 4 + 1] = gt;
|
||||
CR[field * 4 + 2] = eq;
|
||||
CR[field * 4 + 3] = so;
|
||||
}
|
||||
|
||||
// Set CR field for comparison
|
||||
template<typename T>
|
||||
void SetCR(u32 field, const T& a, const T& b)
|
||||
{
|
||||
SetCR(field, a < b, a > b, a == b, SO);
|
||||
}
|
||||
|
||||
// Set overflow bit
|
||||
void SetOV(const bool set)
|
||||
{
|
||||
OV = set;
|
||||
SO |= set;
|
||||
}
|
||||
|
||||
u64 get_next_arg(u32& g_count)
|
||||
{
|
||||
if (g_count < 8)
|
||||
{
|
||||
return GPR[g_count++ + 3];
|
||||
return gpr[g_count++ + 3];
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -144,6 +198,7 @@ public:
|
||||
}
|
||||
|
||||
be_t<u64>* get_stack_arg(s32 i, u64 align = alignof(u64));
|
||||
void exec_task();
|
||||
void fast_call(u32 addr, u32 rtoc);
|
||||
};
|
||||
|
||||
|
@ -63,7 +63,7 @@ const ppu_decoder<PPUTranslator> s_ppu_decoder;
|
||||
GetGpr(op.ra),\
|
||||
GetGpr(op.rb)))
|
||||
|
||||
PPUTranslator::PPUTranslator(LLVMContext& context, Module* module, u64 base, u64 entry)
|
||||
PPUTranslator::PPUTranslator(LLVMContext& context, Module* module, u64 base)
|
||||
: m_context(context)
|
||||
, m_module(module)
|
||||
, m_base_addr(base)
|
||||
@ -74,12 +74,12 @@ PPUTranslator::PPUTranslator(LLVMContext& context, Module* module, u64 base, u64
|
||||
m_base = new GlobalVariable(*module, ArrayType::get(GetType<char>(), 0x100000000)->getPointerTo(), true, GlobalValue::ExternalLinkage, 0, "__mptr");
|
||||
|
||||
// Thread context struct (TODO: safer member access)
|
||||
std::vector<Type*> thread_struct{ArrayType::get(GetType<char>(), OFFSET_32(PPUThread, GPR))};
|
||||
std::vector<Type*> thread_struct{ArrayType::get(GetType<char>(), OFFSET_32(ppu_thread, gpr))};
|
||||
|
||||
thread_struct.insert(thread_struct.end(), 32, GetType<u64>()); // GPR[0..31]
|
||||
thread_struct.insert(thread_struct.end(), 32, GetType<f64>()); // FPR[0..31]
|
||||
thread_struct.insert(thread_struct.end(), 32, GetType<u32[4]>()); // VR[0..31]
|
||||
thread_struct.insert(thread_struct.end(), 32, GetType<bool>()); // CR[0..31]
|
||||
thread_struct.insert(thread_struct.end(), 32, GetType<u64>()); // gpr[0..31]
|
||||
thread_struct.insert(thread_struct.end(), 32, GetType<f64>()); // fpr[0..31]
|
||||
thread_struct.insert(thread_struct.end(), 32, GetType<u32[4]>()); // vr[0..31]
|
||||
thread_struct.insert(thread_struct.end(), 32, GetType<bool>()); // cr[0..31]
|
||||
|
||||
m_thread_type = StructType::create(m_context, thread_struct, "context_t");
|
||||
|
||||
|
@ -238,16 +238,16 @@ public:
|
||||
// Get the basic block for the specified address
|
||||
llvm::BasicBlock* GetBasicBlock(u64 addr);
|
||||
|
||||
// Load GPR
|
||||
// Load gpr
|
||||
llvm::Value* GetGpr(u32 r, u32 num_bits = 64);
|
||||
|
||||
// Set GPR
|
||||
// Set gpr
|
||||
void SetGpr(u32 r, llvm::Value* value);
|
||||
|
||||
// Get FPR
|
||||
// Get fpr
|
||||
llvm::Value* GetFpr(u32 r, u32 bits = 64, bool as_int = false);
|
||||
|
||||
// Set FPR
|
||||
// Set fpr
|
||||
void SetFpr(u32 r, llvm::Value* val);
|
||||
|
||||
// Vector register type
|
||||
@ -260,7 +260,7 @@ public:
|
||||
i128, // Solid 128-bit integer
|
||||
};
|
||||
|
||||
// Load VR
|
||||
// Load vr
|
||||
llvm::Value* GetVr(u32 vr, VrType);
|
||||
|
||||
// Load VRs
|
||||
@ -271,7 +271,7 @@ public:
|
||||
return{ GetVr(regs, type)... };
|
||||
}
|
||||
|
||||
// Set VR to the specified value
|
||||
// Set vr to the specified value
|
||||
void SetVr(u32 vr, llvm::Value*);
|
||||
|
||||
// Bitcast to scalar integer value
|
||||
@ -431,7 +431,7 @@ public:
|
||||
// Handle compilation errors
|
||||
void CompilationError(const std::string& error);
|
||||
|
||||
PPUTranslator(llvm::LLVMContext& context, llvm::Module* module, u64 base, u64 entry);
|
||||
PPUTranslator(llvm::LLVMContext& context, llvm::Module* module, u64 base);
|
||||
~PPUTranslator();
|
||||
|
||||
// Get thread context struct type
|
||||
|
@ -87,21 +87,9 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value)
|
||||
{
|
||||
auto try_start = [this]()
|
||||
{
|
||||
if (status.atomic_op([](u32& status) -> bool
|
||||
if (!status.test_and_set(SPU_STATUS_RUNNING))
|
||||
{
|
||||
if (status & SPU_STATUS_RUNNING)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = SPU_STATUS_RUNNING;
|
||||
return true;
|
||||
}
|
||||
}))
|
||||
{
|
||||
state -= cpu_state::stop;
|
||||
(*this)->lock_notify();
|
||||
run();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -269,7 +269,7 @@ void spu_recompiler::InterpreterCall(spu_opcode_t op)
|
||||
|
||||
const u32 old_pc = _spu->pc;
|
||||
|
||||
if (_spu->state.load() && _spu->check_status())
|
||||
if (_spu->state.load() && _spu->check_state())
|
||||
{
|
||||
return 0x2000000 | _spu->pc;
|
||||
}
|
||||
@ -340,7 +340,7 @@ void spu_recompiler::FunctionCall()
|
||||
LOG_ERROR(SPU, "Branch-to-self");
|
||||
}
|
||||
|
||||
while (!_spu->state.load() || !_spu->check_status())
|
||||
while (!_spu->state.load() || !_spu->check_state())
|
||||
{
|
||||
// Proceed recursively
|
||||
spu_recompiler_base::enter(*_spu);
|
||||
|
@ -24,8 +24,6 @@
|
||||
|
||||
extern u64 get_timebased_time();
|
||||
|
||||
extern std::mutex& get_current_thread_mutex();
|
||||
|
||||
enum class spu_decoder_type
|
||||
{
|
||||
precise,
|
||||
@ -57,8 +55,7 @@ void spu_int_ctrl_t::set(u64 ints)
|
||||
|
||||
if (tag && tag->handler)
|
||||
{
|
||||
tag->handler->signal++;
|
||||
(*tag->handler->thread)->notify();
|
||||
tag->handler->exec();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -126,7 +123,7 @@ spu_imm_table_t::spu_imm_table_t()
|
||||
|
||||
std::string SPUThread::get_name() const
|
||||
{
|
||||
return fmt::format("%sSPU[0x%x] Thread (%s)", offset > RAW_SPU_BASE_ADDR ? "Raw" : "", id, m_name);
|
||||
return fmt::format("%sSPU[0x%x] Thread (%s)", offset >= RAW_SPU_BASE_ADDR ? "Raw" : "", id, m_name);
|
||||
}
|
||||
|
||||
std::string SPUThread::dump() const
|
||||
@ -187,7 +184,7 @@ void SPUThread::cpu_task()
|
||||
|
||||
if (custom_task)
|
||||
{
|
||||
if (check_status()) return;
|
||||
if (check_state()) return;
|
||||
|
||||
return custom_task(*this);
|
||||
}
|
||||
@ -229,7 +226,7 @@ void SPUThread::cpu_task()
|
||||
continue;
|
||||
}
|
||||
|
||||
if (check_status()) return;
|
||||
if (check_state()) return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -281,7 +278,7 @@ void SPUThread::do_dma_transfer(u32 cmd, spu_mfc_arg_t args)
|
||||
|
||||
u32 eal = vm::cast(args.ea, HERE);
|
||||
|
||||
if (eal >= SYS_SPU_THREAD_BASE_LOW && offset >= RAW_SPU_BASE_ADDR) // SPU Thread Group MMIO (LS and SNR)
|
||||
if (eal >= SYS_SPU_THREAD_BASE_LOW && offset < RAW_SPU_BASE_ADDR) // SPU Thread Group MMIO (LS and SNR)
|
||||
{
|
||||
const u32 index = (eal - SYS_SPU_THREAD_BASE_LOW) / SYS_SPU_THREAD_OFFSET; // thread number in group
|
||||
const u32 offset = (eal - SYS_SPU_THREAD_BASE_LOW) % SYS_SPU_THREAD_OFFSET; // LS offset or MMIO register
|
||||
@ -548,7 +545,7 @@ void SPUThread::set_events(u32 mask)
|
||||
// Notify if some events were set
|
||||
if (~old_stat & mask && old_stat & SPU_EVENT_WAITING && ch_event_stat & SPU_EVENT_WAITING)
|
||||
{
|
||||
(*this)->lock_notify();
|
||||
lock_notify();
|
||||
}
|
||||
}
|
||||
|
||||
@ -602,7 +599,7 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
|
||||
{
|
||||
if (!channel.try_pop(out))
|
||||
{
|
||||
cpu_thread_lock{*this}, thread_ctrl::wait(WRAP_EXPR(state & cpu_state::stop || channel.try_pop(out)));
|
||||
thread_lock{*this}, thread_ctrl::wait(WRAP_EXPR(state & cpu_state::stop || channel.try_pop(out)));
|
||||
|
||||
return !state.test(cpu_state::stop);
|
||||
}
|
||||
@ -617,7 +614,7 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
|
||||
// break;
|
||||
case SPU_RdInMbox:
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(get_current_thread_mutex(), std::defer_lock);
|
||||
std::unique_lock<named_thread> lock(*this, std::defer_lock);
|
||||
|
||||
while (true)
|
||||
{
|
||||
@ -644,7 +641,7 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
|
||||
continue;
|
||||
}
|
||||
|
||||
get_current_thread_cv().wait(lock);
|
||||
thread_ctrl::wait();
|
||||
}
|
||||
}
|
||||
|
||||
@ -693,7 +690,7 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
|
||||
|
||||
case SPU_RdEventStat:
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(get_current_thread_mutex(), std::defer_lock);
|
||||
std::unique_lock<named_thread> lock(*this, std::defer_lock);
|
||||
|
||||
// start waiting or return immediately
|
||||
if (u32 res = get_events(true))
|
||||
@ -716,7 +713,7 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
|
||||
{
|
||||
CHECK_EMU_STATUS;
|
||||
|
||||
get_current_thread_cv().wait(lock);
|
||||
thread_ctrl::wait();
|
||||
}
|
||||
}
|
||||
|
||||
@ -756,7 +753,7 @@ bool SPUThread::set_ch_value(u32 ch, u32 value)
|
||||
{
|
||||
if (offset >= RAW_SPU_BASE_ADDR)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(get_current_thread_mutex(), std::defer_lock);
|
||||
std::unique_lock<named_thread> lock(*this, std::defer_lock);
|
||||
|
||||
while (!ch_out_intr_mbox.try_push(value))
|
||||
{
|
||||
@ -773,7 +770,7 @@ bool SPUThread::set_ch_value(u32 ch, u32 value)
|
||||
continue;
|
||||
}
|
||||
|
||||
get_current_thread_cv().wait(lock);
|
||||
thread_ctrl::wait();
|
||||
}
|
||||
|
||||
int_ctrl[2].set(SPU_INT2_STAT_MAILBOX_INT);
|
||||
@ -963,7 +960,7 @@ bool SPUThread::set_ch_value(u32 ch, u32 value)
|
||||
|
||||
case SPU_WrOutMbox:
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(get_current_thread_mutex(), std::defer_lock);
|
||||
std::unique_lock<named_thread> lock(*this, std::defer_lock);
|
||||
|
||||
while (!ch_out_mbox.try_push(value))
|
||||
{
|
||||
@ -980,7 +977,7 @@ bool SPUThread::set_ch_value(u32 ch, u32 value)
|
||||
continue;
|
||||
}
|
||||
|
||||
get_current_thread_cv().wait(lock);
|
||||
thread_ctrl::wait();
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -1305,7 +1302,7 @@ bool SPUThread::stop_and_signal(u32 code)
|
||||
if (thread && thread.get() != this)
|
||||
{
|
||||
thread->state -= cpu_state::suspend;
|
||||
(*thread)->lock_notify();
|
||||
thread->lock_notify();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1344,7 +1341,7 @@ bool SPUThread::stop_and_signal(u32 code)
|
||||
if (thread && thread.get() != this)
|
||||
{
|
||||
thread->state += cpu_state::stop;
|
||||
(*thread)->lock_notify();
|
||||
thread->lock_notify();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,7 +180,7 @@ public:
|
||||
data.value |= value;
|
||||
});
|
||||
|
||||
if (old.wait) spu->lock_notify();
|
||||
if (old.wait) spu.lock_notify();
|
||||
}
|
||||
|
||||
// push unconditionally (overwriting previous value), may require notification
|
||||
@ -193,7 +193,7 @@ public:
|
||||
data.value = value;
|
||||
});
|
||||
|
||||
if (old.wait) spu->lock_notify();
|
||||
if (old.wait) spu.lock_notify();
|
||||
}
|
||||
|
||||
// returns true on success
|
||||
@ -228,7 +228,7 @@ public:
|
||||
// value is not cleared and may be read again
|
||||
});
|
||||
|
||||
if (old.wait) spu->lock_notify();
|
||||
if (old.wait) spu.lock_notify();
|
||||
|
||||
return old.value;
|
||||
}
|
||||
@ -253,12 +253,8 @@ struct spu_channel_4_t
|
||||
{
|
||||
struct alignas(16) sync_var_t
|
||||
{
|
||||
struct
|
||||
{
|
||||
u32 waiting : 1;
|
||||
u32 count : 3;
|
||||
};
|
||||
|
||||
u8 waiting;
|
||||
u8 count;
|
||||
u32 value0;
|
||||
u32 value1;
|
||||
u32 value2;
|
||||
@ -299,7 +295,7 @@ public:
|
||||
return false;
|
||||
}))
|
||||
{
|
||||
spu->lock_notify();
|
||||
spu.lock_notify();
|
||||
}
|
||||
}
|
||||
|
||||
@ -337,7 +333,7 @@ public:
|
||||
|
||||
void set_values(u32 count, u32 value0, u32 value1 = 0, u32 value2 = 0, u32 value3 = 0)
|
||||
{
|
||||
this->values.raw() = { 0, count, value0, value1, value2 };
|
||||
this->values.raw() = { 0, static_cast<u8>(count), value0, value1, value2 };
|
||||
this->value3 = value3;
|
||||
}
|
||||
};
|
||||
|
@ -908,22 +908,22 @@ std::array<ppu_function_t, 1024> g_ppu_syscall_table
|
||||
null_func, null_func, null_func, null_func, //1023 UNS
|
||||
};
|
||||
|
||||
extern void ppu_execute_syscall(PPUThread& ppu, u64 code)
|
||||
extern void ppu_execute_syscall(ppu_thread& ppu, u64 code)
|
||||
{
|
||||
if (code < g_ppu_syscall_table.size())
|
||||
{
|
||||
// If autopause occures, check_status() will hold the thread till unpaused.
|
||||
if (debug::autopause::pause_syscall(code) && ppu.check_status()) throw cpu_state::ret;
|
||||
if (debug::autopause::pause_syscall(code) && ppu.check_state()) throw cpu_state::ret;
|
||||
|
||||
if (auto func = g_ppu_syscall_table[code])
|
||||
{
|
||||
func(ppu);
|
||||
LOG_TRACE(PPU, "Syscall '%s' (%llu) finished, r3=0x%llx", ppu_get_syscall_name(code), code, ppu.GPR[3]);
|
||||
LOG_TRACE(PPU, "Syscall '%s' (%llu) finished, r3=0x%llx", ppu_get_syscall_name(code), code, ppu.gpr[3]);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_TODO(HLE, "Unimplemented syscall %s -> CELL_OK", ppu_get_syscall_name(code));
|
||||
ppu.GPR[3] = 0;
|
||||
ppu.gpr[3] = 0;
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -23,10 +23,10 @@ void lv2_cond_t::notify(lv2_lock_t, cpu_thread* thread)
|
||||
}
|
||||
else
|
||||
{
|
||||
mutex->owner = idm::get<PPUThread>(thread->id);
|
||||
mutex->owner = idm::get<ppu_thread>(thread->id);
|
||||
|
||||
VERIFY(!thread->state.test_and_set(cpu_state::signal));
|
||||
(*thread)->notify();
|
||||
thread->notify();
|
||||
}
|
||||
}
|
||||
|
||||
@ -165,7 +165,7 @@ s32 sys_cond_signal_to(u32 cond_id, u32 thread_id)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_cond_wait(PPUThread& ppu, u32 cond_id, u64 timeout)
|
||||
s32 sys_cond_wait(ppu_thread& ppu, u32 cond_id, u64 timeout)
|
||||
{
|
||||
sys_cond.trace("sys_cond_wait(cond_id=0x%x, timeout=%lld)", cond_id, timeout);
|
||||
|
||||
@ -212,7 +212,7 @@ s32 sys_cond_wait(PPUThread& ppu, u32 cond_id, u64 timeout)
|
||||
// try to reown mutex and exit if timed out
|
||||
if (!cond->mutex->owner)
|
||||
{
|
||||
cond->mutex->owner = idm::get<PPUThread>(ppu.id);
|
||||
cond->mutex->owner = idm::get<ppu_thread>(ppu.id);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -33,12 +33,12 @@ struct lv2_cond_t
|
||||
void notify(lv2_lock_t, cpu_thread* thread);
|
||||
};
|
||||
|
||||
class PPUThread;
|
||||
class ppu_thread;
|
||||
|
||||
// SysCalls
|
||||
s32 sys_cond_create(vm::ptr<u32> cond_id, u32 mutex_id, vm::ptr<sys_cond_attribute_t> attr);
|
||||
s32 sys_cond_destroy(u32 cond_id);
|
||||
s32 sys_cond_wait(PPUThread& ppu, u32 cond_id, u64 timeout);
|
||||
s32 sys_cond_wait(ppu_thread& ppu, 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);
|
||||
|
@ -64,12 +64,12 @@ void lv2_event_queue_t::push(lv2_lock_t, u64 source, u64 data1, u64 data2, u64 d
|
||||
if (type == SYS_PPU_QUEUE && thread->type == cpu_type::ppu)
|
||||
{
|
||||
// store event data in registers
|
||||
auto& ppu = static_cast<PPUThread&>(*thread);
|
||||
auto& ppu = static_cast<ppu_thread&>(*thread);
|
||||
|
||||
ppu.GPR[4] = source;
|
||||
ppu.GPR[5] = data1;
|
||||
ppu.GPR[6] = data2;
|
||||
ppu.GPR[7] = data3;
|
||||
ppu.gpr[4] = source;
|
||||
ppu.gpr[5] = data1;
|
||||
ppu.gpr[6] = data2;
|
||||
ppu.gpr[7] = data3;
|
||||
}
|
||||
else if (type == SYS_SPU_QUEUE && thread->type == cpu_type::spu)
|
||||
{
|
||||
@ -84,7 +84,7 @@ void lv2_event_queue_t::push(lv2_lock_t, u64 source, u64 data1, u64 data2, u64 d
|
||||
}
|
||||
|
||||
VERIFY(!thread->state.test_and_set(cpu_state::signal));
|
||||
(*thread)->notify();
|
||||
thread->notify();
|
||||
|
||||
return m_sq.pop_front();
|
||||
}
|
||||
@ -165,7 +165,7 @@ s32 sys_event_queue_destroy(u32 equeue_id, s32 mode)
|
||||
{
|
||||
if (queue->type == SYS_PPU_QUEUE && thread->type == cpu_type::ppu)
|
||||
{
|
||||
static_cast<PPUThread&>(*thread).GPR[3] = 1;
|
||||
static_cast<ppu_thread&>(*thread).gpr[3] = 1;
|
||||
}
|
||||
else if (queue->type == SYS_SPU_QUEUE && thread->type == cpu_type::spu)
|
||||
{
|
||||
@ -177,7 +177,7 @@ s32 sys_event_queue_destroy(u32 equeue_id, s32 mode)
|
||||
}
|
||||
|
||||
thread->state += cpu_state::signal;
|
||||
(*thread)->notify();
|
||||
thread->notify();
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
@ -220,7 +220,7 @@ s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr<sys_event_t> event_array,
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_event_queue_receive(PPUThread& ppu, u32 equeue_id, vm::ptr<sys_event_t> dummy_event, u64 timeout)
|
||||
s32 sys_event_queue_receive(ppu_thread& ppu, u32 equeue_id, vm::ptr<sys_event_t> dummy_event, u64 timeout)
|
||||
{
|
||||
sys_event.trace("sys_event_queue_receive(equeue_id=0x%x, *0x%x, timeout=0x%llx)", equeue_id, dummy_event, timeout);
|
||||
|
||||
@ -243,12 +243,12 @@ s32 sys_event_queue_receive(PPUThread& ppu, u32 equeue_id, vm::ptr<sys_event_t>
|
||||
if (queue->events())
|
||||
{
|
||||
// event data is returned in registers (dummy_event is not used)
|
||||
std::tie(ppu.GPR[4], ppu.GPR[5], ppu.GPR[6], ppu.GPR[7]) = queue->pop(lv2_lock);
|
||||
std::tie(ppu.gpr[4], ppu.gpr[5], ppu.gpr[6], ppu.gpr[7]) = queue->pop(lv2_lock);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
// cause (if cancelled) will be returned in r3
|
||||
ppu.GPR[3] = 0;
|
||||
ppu.gpr[3] = 0;
|
||||
|
||||
// add waiter; protocol is ignored in current implementation
|
||||
sleep_entry<cpu_thread> waiter(queue->thread_queue(lv2_lock), ppu);
|
||||
@ -274,7 +274,7 @@ s32 sys_event_queue_receive(PPUThread& ppu, u32 equeue_id, vm::ptr<sys_event_t>
|
||||
}
|
||||
}
|
||||
|
||||
if (ppu.GPR[3])
|
||||
if (ppu.gpr[3])
|
||||
{
|
||||
ENSURES(!idm::check<lv2_event_queue_t>(equeue_id));
|
||||
return CELL_ECANCELED;
|
||||
|
@ -132,12 +132,12 @@ struct lv2_event_port_t
|
||||
}
|
||||
};
|
||||
|
||||
class PPUThread;
|
||||
class ppu_thread;
|
||||
|
||||
// SysCalls
|
||||
s32 sys_event_queue_create(vm::ptr<u32> equeue_id, vm::ptr<sys_event_queue_attribute_t> attr, u64 event_queue_key, s32 size);
|
||||
s32 sys_event_queue_destroy(u32 equeue_id, s32 mode);
|
||||
s32 sys_event_queue_receive(PPUThread& ppu, u32 equeue_id, vm::ptr<sys_event_t> dummy_event, u64 timeout);
|
||||
s32 sys_event_queue_receive(ppu_thread& ppu, u32 equeue_id, vm::ptr<sys_event_t> dummy_event, u64 timeout);
|
||||
s32 sys_event_queue_tryreceive(u32 equeue_id, vm::ptr<sys_event_t> event_array, s32 size, vm::ptr<u32> number);
|
||||
s32 sys_event_queue_drain(u32 event_queue_id);
|
||||
|
||||
|
@ -17,20 +17,20 @@ void lv2_event_flag_t::notify_all(lv2_lock_t)
|
||||
{
|
||||
auto pred = [this](cpu_thread* thread) -> bool
|
||||
{
|
||||
auto& ppu = static_cast<PPUThread&>(*thread);
|
||||
auto& ppu = static_cast<ppu_thread&>(*thread);
|
||||
|
||||
// load pattern and mode from registers
|
||||
const u64 bitptn = ppu.GPR[4];
|
||||
const u32 mode = static_cast<u32>(ppu.GPR[5]);
|
||||
const u64 bitptn = ppu.gpr[4];
|
||||
const u32 mode = static_cast<u32>(ppu.gpr[5]);
|
||||
|
||||
// check specific pattern
|
||||
if (check_pattern(bitptn, mode))
|
||||
{
|
||||
// save pattern
|
||||
ppu.GPR[4] = clear_pattern(bitptn, mode);
|
||||
ppu.gpr[4] = clear_pattern(bitptn, mode);
|
||||
|
||||
VERIFY(!thread->state.test_and_set(cpu_state::signal));
|
||||
(*thread)->notify();
|
||||
thread->notify();
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -101,7 +101,7 @@ s32 sys_event_flag_destroy(u32 id)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_event_flag_wait(PPUThread& ppu, u32 id, u64 bitptn, u32 mode, vm::ptr<u64> result, u64 timeout)
|
||||
s32 sys_event_flag_wait(ppu_thread& ppu, u32 id, u64 bitptn, u32 mode, vm::ptr<u64> result, u64 timeout)
|
||||
{
|
||||
sys_event_flag.trace("sys_event_flag_wait(id=0x%x, bitptn=0x%llx, mode=0x%x, result=*0x%x, timeout=0x%llx)", id, bitptn, mode, result, timeout);
|
||||
|
||||
@ -109,8 +109,8 @@ s32 sys_event_flag_wait(PPUThread& ppu, u32 id, u64 bitptn, u32 mode, vm::ptr<u6
|
||||
|
||||
// If this syscall is called through the SC instruction, these registers must already contain corresponding values.
|
||||
// But let's fixup them (in the case of explicit function call or something) because these values are used externally.
|
||||
ppu.GPR[4] = bitptn;
|
||||
ppu.GPR[5] = mode;
|
||||
ppu.gpr[4] = bitptn;
|
||||
ppu.gpr[5] = mode;
|
||||
|
||||
LV2_LOCK;
|
||||
|
||||
@ -172,11 +172,11 @@ s32 sys_event_flag_wait(PPUThread& ppu, u32 id, u64 bitptn, u32 mode, vm::ptr<u6
|
||||
// load pattern saved upon signaling
|
||||
if (result)
|
||||
{
|
||||
*result = ppu.GPR[4];
|
||||
*result = ppu.gpr[4];
|
||||
}
|
||||
|
||||
// check cause
|
||||
if (ppu.GPR[5] == 0)
|
||||
if (ppu.gpr[5] == 0)
|
||||
{
|
||||
return CELL_ECANCELED;
|
||||
}
|
||||
@ -284,16 +284,16 @@ s32 sys_event_flag_cancel(u32 id, vm::ptr<u32> num)
|
||||
// signal all threads to return CELL_ECANCELED
|
||||
for (auto& thread : eflag->sq)
|
||||
{
|
||||
auto& ppu = static_cast<PPUThread&>(*thread);
|
||||
auto& ppu = static_cast<ppu_thread&>(*thread);
|
||||
|
||||
// save existing pattern
|
||||
ppu.GPR[4] = pattern;
|
||||
ppu.gpr[4] = pattern;
|
||||
|
||||
// clear "mode" as a sign of cancellation
|
||||
ppu.GPR[5] = 0;
|
||||
ppu.gpr[5] = 0;
|
||||
|
||||
VERIFY(!thread->state.test_and_set(cpu_state::signal));
|
||||
(*thread)->notify();
|
||||
thread->notify();
|
||||
}
|
||||
|
||||
eflag->sq.clear();
|
||||
|
@ -107,12 +107,12 @@ struct lv2_event_flag_t
|
||||
};
|
||||
|
||||
// Aux
|
||||
class PPUThread;
|
||||
class ppu_thread;
|
||||
|
||||
// SysCalls
|
||||
s32 sys_event_flag_create(vm::ptr<u32> id, vm::ptr<sys_event_flag_attribute_t> attr, u64 init);
|
||||
s32 sys_event_flag_destroy(u32 id);
|
||||
s32 sys_event_flag_wait(PPUThread& ppu, u32 id, u64 bitptn, u32 mode, vm::ptr<u64> result, u64 timeout);
|
||||
s32 sys_event_flag_wait(ppu_thread& ppu, u32 id, u64 bitptn, u32 mode, vm::ptr<u64> result, u64 timeout);
|
||||
s32 sys_event_flag_trywait(u32 id, u64 bitptn, u32 mode, vm::ptr<u64> result);
|
||||
s32 sys_event_flag_set(u32 id, u64 bitptn);
|
||||
s32 sys_event_flag_clear(u32 id, u64 bitptn);
|
||||
|
@ -5,17 +5,35 @@
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
#include "Emu/Cell/PPUOpcodes.h"
|
||||
#include "sys_interrupt.h"
|
||||
|
||||
logs::channel sys_interrupt("sys_interrupt", logs::level::notice);
|
||||
|
||||
void lv2_int_serv_t::join(PPUThread& ppu, lv2_lock_t lv2_lock)
|
||||
void lv2_int_serv_t::exec()
|
||||
{
|
||||
// Use is_joining to stop interrupt thread and signal
|
||||
thread->is_joining = true;
|
||||
(*thread)->notify();
|
||||
thread->cmd_list
|
||||
({
|
||||
{ ppu_cmd::set_args, 2 }, arg1, arg2,
|
||||
{ ppu_cmd::lle_call, 2 },
|
||||
});
|
||||
|
||||
// Start joining
|
||||
thread->lock_notify();
|
||||
}
|
||||
|
||||
void lv2_int_serv_t::join(ppu_thread& ppu, lv2_lock_t lv2_lock)
|
||||
{
|
||||
// Enqueue _sys_ppu_thread_exit call
|
||||
thread->cmd_list
|
||||
({
|
||||
{ ppu_cmd::set_args, 1 }, u64{0},
|
||||
{ ppu_cmd::set_gpr, 11 }, u64{41},
|
||||
{ ppu_cmd::opcode, ppu_instructions::SC(0) },
|
||||
});
|
||||
|
||||
thread->lock_notify();
|
||||
|
||||
// Join thread (TODO)
|
||||
while (!(thread->state & cpu_state::exit))
|
||||
{
|
||||
CHECK_EMU_STATUS;
|
||||
@ -25,7 +43,6 @@ void lv2_int_serv_t::join(PPUThread& ppu, lv2_lock_t lv2_lock)
|
||||
|
||||
// Cleanup
|
||||
idm::remove<lv2_int_serv_t>(id);
|
||||
idm::remove<PPUThread>(thread->id);
|
||||
}
|
||||
|
||||
s32 sys_interrupt_tag_destroy(u32 intrtag)
|
||||
@ -66,7 +83,7 @@ s32 _sys_interrupt_thread_establish(vm::ptr<u32> ih, u32 intrtag, u32 intrthread
|
||||
}
|
||||
|
||||
// Get interrupt thread
|
||||
const auto it = idm::get<PPUThread>(intrthread);
|
||||
const auto it = idm::get<ppu_thread>(intrthread);
|
||||
|
||||
if (!it)
|
||||
{
|
||||
@ -86,55 +103,16 @@ s32 _sys_interrupt_thread_establish(vm::ptr<u32> ih, u32 intrtag, u32 intrthread
|
||||
return CELL_ESTAT;
|
||||
}
|
||||
|
||||
const auto handler = idm::make_ptr<lv2_int_serv_t>(it);
|
||||
tag->handler = idm::make_ptr<lv2_int_serv_t>(it, arg1, arg2);
|
||||
|
||||
tag->handler = handler;
|
||||
it->run();
|
||||
|
||||
it->custom_task = [handler, arg1, arg2](PPUThread& ppu)
|
||||
{
|
||||
const u32 pc = ppu.pc;
|
||||
const u32 rtoc = ppu.GPR[2];
|
||||
|
||||
LV2_LOCK;
|
||||
|
||||
while (!ppu.is_joining)
|
||||
{
|
||||
CHECK_EMU_STATUS;
|
||||
|
||||
// call interrupt handler until int status is clear
|
||||
if (handler->signal)
|
||||
{
|
||||
if (lv2_lock) lv2_lock.unlock();
|
||||
|
||||
ppu.GPR[3] = arg1;
|
||||
ppu.GPR[4] = arg2;
|
||||
ppu.fast_call(pc, rtoc);
|
||||
|
||||
handler->signal--;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!lv2_lock)
|
||||
{
|
||||
lv2_lock.lock();
|
||||
continue;
|
||||
}
|
||||
|
||||
get_current_thread_cv().wait(lv2_lock);
|
||||
}
|
||||
|
||||
ppu.state += cpu_state::exit;
|
||||
};
|
||||
|
||||
it->state -= cpu_state::stop;
|
||||
(*it)->lock_notify();
|
||||
|
||||
*ih = handler->id;
|
||||
*ih = tag->handler->id;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _sys_interrupt_thread_disestablish(PPUThread& ppu, u32 ih, vm::ptr<u64> r13)
|
||||
s32 _sys_interrupt_thread_disestablish(ppu_thread& ppu, u32 ih, vm::ptr<u64> r13)
|
||||
{
|
||||
sys_interrupt.warning("_sys_interrupt_thread_disestablish(ih=0x%x, r13=*0x%x)", ih, r13);
|
||||
|
||||
@ -151,12 +129,12 @@ s32 _sys_interrupt_thread_disestablish(PPUThread& ppu, u32 ih, vm::ptr<u64> r13)
|
||||
handler->join(ppu, lv2_lock);
|
||||
|
||||
// Save TLS base
|
||||
*r13 = handler->thread->GPR[13];
|
||||
*r13 = handler->thread->gpr[13];
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
void sys_interrupt_thread_eoi(PPUThread& ppu) // Low-level PPU function example
|
||||
void sys_interrupt_thread_eoi(ppu_thread& ppu) // Low-level PPU function example
|
||||
{
|
||||
// Low-level function body must guard all C++-ish calls and all objects with non-trivial destructors
|
||||
thread_guard{ppu}, sys_interrupt.trace("sys_interrupt_thread_eoi()");
|
||||
@ -164,7 +142,7 @@ void sys_interrupt_thread_eoi(PPUThread& ppu) // Low-level PPU function example
|
||||
ppu.state += cpu_state::ret;
|
||||
|
||||
// Throw if this syscall was not called directly by the SC instruction (hack)
|
||||
if (ppu.LR == 0 || ppu.GPR[11] != 88 || ppu.custom_task)
|
||||
if (ppu.lr == 0 || ppu.gpr[11] != 88)
|
||||
{
|
||||
// Low-level function must disable interrupts before throwing (not related to sys_interrupt_*, it's rather coincidence)
|
||||
ppu->interrupt_disable();
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include "sys_sync.h"
|
||||
|
||||
class PPUThread;
|
||||
class ppu_thread;
|
||||
|
||||
struct lv2_int_tag_t
|
||||
{
|
||||
@ -13,22 +13,26 @@ struct lv2_int_tag_t
|
||||
|
||||
struct lv2_int_serv_t
|
||||
{
|
||||
const std::shared_ptr<PPUThread> thread;
|
||||
const std::shared_ptr<ppu_thread> thread;
|
||||
|
||||
const id_value<> id{};
|
||||
|
||||
atomic_t<u32> signal{ 0 }; // signal count
|
||||
const u64 arg1;
|
||||
const u64 arg2;
|
||||
|
||||
lv2_int_serv_t(const std::shared_ptr<PPUThread>& thread)
|
||||
lv2_int_serv_t(const std::shared_ptr<ppu_thread>& thread, u64 arg1, u64 arg2)
|
||||
: thread(thread)
|
||||
, arg1(arg1)
|
||||
, arg2(arg2)
|
||||
{
|
||||
}
|
||||
|
||||
void join(PPUThread& ppu, lv2_lock_t);
|
||||
void exec();
|
||||
void join(ppu_thread& ppu, lv2_lock_t);
|
||||
};
|
||||
|
||||
// SysCalls
|
||||
s32 sys_interrupt_tag_destroy(u32 intrtag);
|
||||
s32 _sys_interrupt_thread_establish(vm::ptr<u32> ih, u32 intrtag, u32 intrthread, u64 arg1, u64 arg2);
|
||||
s32 _sys_interrupt_thread_disestablish(PPUThread& ppu, u32 ih, vm::ptr<u64> r13);
|
||||
void sys_interrupt_thread_eoi(PPUThread& ppu);
|
||||
s32 _sys_interrupt_thread_disestablish(ppu_thread& ppu, u32 ih, vm::ptr<u64> r13);
|
||||
void sys_interrupt_thread_eoi(ppu_thread& ppu);
|
||||
|
@ -16,9 +16,9 @@ extern u64 get_system_time();
|
||||
|
||||
void lv2_lwcond_t::notify(lv2_lock_t, cpu_thread* thread, const std::shared_ptr<lv2_lwmutex_t>& mutex, bool mode2)
|
||||
{
|
||||
auto& ppu = static_cast<PPUThread&>(*thread);
|
||||
auto& ppu = static_cast<ppu_thread&>(*thread);
|
||||
|
||||
ppu.GPR[3] = mode2; // set to return CELL_EBUSY
|
||||
ppu.gpr[3] = mode2; // set to return CELL_EBUSY
|
||||
|
||||
if (!mode2)
|
||||
{
|
||||
@ -31,7 +31,7 @@ void lv2_lwcond_t::notify(lv2_lock_t, cpu_thread* thread, const std::shared_ptr<
|
||||
}
|
||||
|
||||
VERIFY(!thread->state.test_and_set(cpu_state::signal));
|
||||
(*thread)->notify();
|
||||
thread->notify();
|
||||
}
|
||||
|
||||
s32 _sys_lwcond_create(vm::ptr<u32> lwcond_id, u32 lwmutex_id, vm::ptr<sys_lwcond_t> control, u64 name, u32 arg5)
|
||||
@ -155,7 +155,7 @@ s32 _sys_lwcond_signal_all(u32 lwcond_id, u32 lwmutex_id, u32 mode)
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 _sys_lwcond_queue_wait(PPUThread& ppu, u32 lwcond_id, u32 lwmutex_id, u64 timeout)
|
||||
s32 _sys_lwcond_queue_wait(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id, u64 timeout)
|
||||
{
|
||||
sys_lwcond.trace("_sys_lwcond_queue_wait(lwcond_id=0x%x, lwmutex_id=0x%x, timeout=0x%llx)", lwcond_id, lwmutex_id, timeout);
|
||||
|
||||
@ -212,5 +212,5 @@ s32 _sys_lwcond_queue_wait(PPUThread& ppu, u32 lwcond_id, u32 lwmutex_id, u64 ti
|
||||
}
|
||||
|
||||
// return cause
|
||||
return ppu.GPR[3] ? CELL_EBUSY : CELL_OK;
|
||||
return ppu.gpr[3] ? CELL_EBUSY : CELL_OK;
|
||||
}
|
||||
|
@ -32,11 +32,11 @@ struct lv2_lwcond_t
|
||||
};
|
||||
|
||||
// Aux
|
||||
class PPUThread;
|
||||
class ppu_thread;
|
||||
|
||||
// SysCalls
|
||||
s32 _sys_lwcond_create(vm::ptr<u32> lwcond_id, u32 lwmutex_id, vm::ptr<sys_lwcond_t> control, u64 name, u32 arg5);
|
||||
s32 _sys_lwcond_destroy(u32 lwcond_id);
|
||||
s32 _sys_lwcond_signal(u32 lwcond_id, u32 lwmutex_id, u32 ppu_thread_id, u32 mode);
|
||||
s32 _sys_lwcond_signal_all(u32 lwcond_id, u32 lwmutex_id, u32 mode);
|
||||
s32 _sys_lwcond_queue_wait(PPUThread& ppu, u32 lwcond_id, u32 lwmutex_id, u64 timeout);
|
||||
s32 _sys_lwcond_queue_wait(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id, u64 timeout);
|
||||
|
@ -22,7 +22,7 @@ void lv2_lwmutex_t::unlock(lv2_lock_t)
|
||||
{
|
||||
auto& thread = sq.front();
|
||||
VERIFY(!thread->state.test_and_set(cpu_state::signal));
|
||||
(*thread)->notify();
|
||||
thread->notify();
|
||||
|
||||
sq.pop_front();
|
||||
}
|
||||
@ -75,7 +75,7 @@ s32 _sys_lwmutex_destroy(u32 lwmutex_id)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _sys_lwmutex_lock(PPUThread& ppu, u32 lwmutex_id, u64 timeout)
|
||||
s32 _sys_lwmutex_lock(ppu_thread& ppu, u32 lwmutex_id, u64 timeout)
|
||||
{
|
||||
sys_lwmutex.trace("_sys_lwmutex_lock(lwmutex_id=0x%x, timeout=0x%llx)", lwmutex_id, timeout);
|
||||
|
||||
|
@ -64,11 +64,11 @@ struct lv2_lwmutex_t
|
||||
};
|
||||
|
||||
// Aux
|
||||
class PPUThread;
|
||||
class ppu_thread;
|
||||
|
||||
// SysCalls
|
||||
s32 _sys_lwmutex_create(vm::ptr<u32> lwmutex_id, u32 protocol, vm::ptr<sys_lwmutex_t> control, u32 arg4, u64 name, u32 arg6);
|
||||
s32 _sys_lwmutex_destroy(u32 lwmutex_id);
|
||||
s32 _sys_lwmutex_lock(PPUThread& ppu, u32 lwmutex_id, u64 timeout);
|
||||
s32 _sys_lwmutex_lock(ppu_thread& ppu, u32 lwmutex_id, u64 timeout);
|
||||
s32 _sys_lwmutex_trylock(u32 lwmutex_id);
|
||||
s32 _sys_lwmutex_unlock(u32 lwmutex_id);
|
||||
|
@ -18,10 +18,10 @@ void lv2_mutex_t::unlock(lv2_lock_t)
|
||||
if (sq.size())
|
||||
{
|
||||
// pick new owner; protocol is ignored in current implementation
|
||||
owner = idm::get<PPUThread>(sq.front()->id);
|
||||
owner = idm::get<ppu_thread>(sq.front()->id);
|
||||
|
||||
VERIFY(!owner->state.test_and_set(cpu_state::signal));
|
||||
(*owner)->notify();
|
||||
owner->notify();
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,7 +91,7 @@ s32 sys_mutex_destroy(u32 mutex_id)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_mutex_lock(PPUThread& ppu, u32 mutex_id, u64 timeout)
|
||||
s32 sys_mutex_lock(ppu_thread& ppu, u32 mutex_id, u64 timeout)
|
||||
{
|
||||
sys_mutex.trace("sys_mutex_lock(mutex_id=0x%x, timeout=0x%llx)", mutex_id, timeout);
|
||||
|
||||
@ -127,7 +127,7 @@ s32 sys_mutex_lock(PPUThread& ppu, u32 mutex_id, u64 timeout)
|
||||
// lock immediately if not locked
|
||||
if (!mutex->owner)
|
||||
{
|
||||
mutex->owner = idm::get<PPUThread>(ppu.id);
|
||||
mutex->owner = idm::get<ppu_thread>(ppu.id);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -165,7 +165,7 @@ s32 sys_mutex_lock(PPUThread& ppu, u32 mutex_id, u64 timeout)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_mutex_trylock(PPUThread& ppu, u32 mutex_id)
|
||||
s32 sys_mutex_trylock(ppu_thread& ppu, u32 mutex_id)
|
||||
{
|
||||
sys_mutex.trace("sys_mutex_trylock(mutex_id=0x%x)", mutex_id);
|
||||
|
||||
@ -202,12 +202,12 @@ s32 sys_mutex_trylock(PPUThread& ppu, u32 mutex_id)
|
||||
}
|
||||
|
||||
// own the mutex if free
|
||||
mutex->owner = idm::get<PPUThread>(ppu.id);
|
||||
mutex->owner = idm::get<ppu_thread>(ppu.id);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_mutex_unlock(PPUThread& ppu, u32 mutex_id)
|
||||
s32 sys_mutex_unlock(ppu_thread& ppu, u32 mutex_id)
|
||||
{
|
||||
sys_mutex.trace("sys_mutex_unlock(mutex_id=0x%x)", mutex_id);
|
||||
|
||||
|
@ -41,11 +41,11 @@ struct lv2_mutex_t
|
||||
void unlock(lv2_lock_t);
|
||||
};
|
||||
|
||||
class PPUThread;
|
||||
class ppu_thread;
|
||||
|
||||
// SysCalls
|
||||
s32 sys_mutex_create(vm::ptr<u32> mutex_id, vm::ptr<sys_mutex_attribute_t> attr);
|
||||
s32 sys_mutex_destroy(u32 mutex_id);
|
||||
s32 sys_mutex_lock(PPUThread& ppu, u32 mutex_id, u64 timeout);
|
||||
s32 sys_mutex_trylock(PPUThread& ppu, u32 mutex_id);
|
||||
s32 sys_mutex_unlock(PPUThread& ppu, u32 mutex_id);
|
||||
s32 sys_mutex_lock(ppu_thread& ppu, u32 mutex_id, u64 timeout);
|
||||
s32 sys_mutex_trylock(ppu_thread& ppu, u32 mutex_id);
|
||||
s32 sys_mutex_unlock(ppu_thread& ppu, u32 mutex_id);
|
||||
|
@ -11,37 +11,24 @@
|
||||
|
||||
logs::channel sys_ppu_thread("sys_ppu_thread", logs::level::notice);
|
||||
|
||||
void _sys_ppu_thread_exit(PPUThread& ppu, u64 errorcode)
|
||||
void _sys_ppu_thread_exit(ppu_thread& ppu, u64 errorcode)
|
||||
{
|
||||
sys_ppu_thread.warning("_sys_ppu_thread_exit(errorcode=0x%llx)", errorcode);
|
||||
|
||||
// TODO: Should we really unlock mutexes?
|
||||
// TODO: shall sys_mutex objects be unlocked?
|
||||
|
||||
//// get all sys_mutex objects
|
||||
//for (auto& mutex : idm::get_all<lv2_mutex_t>())
|
||||
//{
|
||||
// // unlock mutex if locked by this thread
|
||||
// if (mutex->owner.get() == &ppu)
|
||||
// {
|
||||
// mutex->unlock(lv2_lock);
|
||||
// }
|
||||
//}
|
||||
LV2_LOCK;
|
||||
|
||||
ppu.state += cpu_state::exit;
|
||||
|
||||
// Delete detached thread
|
||||
if (!ppu.is_joinable)
|
||||
{
|
||||
LV2_LOCK;
|
||||
|
||||
ppu.state += cpu_state::exit;
|
||||
//ppu.handle_interrupt();
|
||||
|
||||
// Delete detached thread
|
||||
if (!ppu.is_joinable)
|
||||
{
|
||||
idm::remove<PPUThread>(ppu.id);
|
||||
}
|
||||
idm::remove<ppu_thread>(ppu.id);
|
||||
}
|
||||
|
||||
// Throw if this syscall was not called directly by the SC instruction (hack)
|
||||
if (ppu.LR == 0 || ppu.GPR[11] != 41 || ppu.custom_task)
|
||||
if (ppu.lr == 0 || ppu.gpr[11] != 41)
|
||||
{
|
||||
throw cpu_state::exit;
|
||||
}
|
||||
@ -54,13 +41,13 @@ void sys_ppu_thread_yield()
|
||||
std::this_thread::yield();
|
||||
}
|
||||
|
||||
s32 sys_ppu_thread_join(PPUThread& ppu, u32 thread_id, vm::ptr<u64> vptr)
|
||||
s32 sys_ppu_thread_join(ppu_thread& ppu, u32 thread_id, vm::ptr<u64> vptr)
|
||||
{
|
||||
sys_ppu_thread.warning("sys_ppu_thread_join(thread_id=0x%x, vptr=*0x%x)", thread_id, vptr);
|
||||
|
||||
LV2_LOCK;
|
||||
|
||||
const auto thread = idm::get<PPUThread>(thread_id);
|
||||
const auto thread = idm::get<ppu_thread>(thread_id);
|
||||
|
||||
if (!thread)
|
||||
{
|
||||
@ -77,8 +64,6 @@ s32 sys_ppu_thread_join(PPUThread& ppu, u32 thread_id, vm::ptr<u64> vptr)
|
||||
return CELL_EDEADLK;
|
||||
}
|
||||
|
||||
ppu.sleep();
|
||||
|
||||
// mark joining
|
||||
thread->is_joining = true;
|
||||
|
||||
@ -90,13 +75,11 @@ s32 sys_ppu_thread_join(PPUThread& ppu, u32 thread_id, vm::ptr<u64> vptr)
|
||||
get_current_thread_cv().wait_for(lv2_lock, 1ms);
|
||||
}
|
||||
|
||||
ppu.awake();
|
||||
|
||||
// get exit status from the register
|
||||
if (vptr) *vptr = thread->GPR[3];
|
||||
if (vptr) *vptr = thread->gpr[3];
|
||||
|
||||
// cleanup
|
||||
idm::remove<PPUThread>(thread->id);
|
||||
idm::remove<ppu_thread>(thread->id);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -107,7 +90,7 @@ s32 sys_ppu_thread_detach(u32 thread_id)
|
||||
|
||||
LV2_LOCK;
|
||||
|
||||
const auto thread = idm::get<PPUThread>(thread_id);
|
||||
const auto thread = idm::get<ppu_thread>(thread_id);
|
||||
|
||||
if (!thread)
|
||||
{
|
||||
@ -130,7 +113,7 @@ s32 sys_ppu_thread_detach(u32 thread_id)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
void sys_ppu_thread_get_join_state(PPUThread& ppu, vm::ptr<s32> isjoinable)
|
||||
void sys_ppu_thread_get_join_state(ppu_thread& ppu, vm::ptr<s32> isjoinable)
|
||||
{
|
||||
sys_ppu_thread.warning("sys_ppu_thread_get_join_state(isjoinable=*0x%x)", isjoinable);
|
||||
|
||||
@ -145,7 +128,7 @@ s32 sys_ppu_thread_set_priority(u32 thread_id, s32 prio)
|
||||
|
||||
LV2_LOCK;
|
||||
|
||||
const auto thread = idm::get<PPUThread>(thread_id);
|
||||
const auto thread = idm::get<ppu_thread>(thread_id);
|
||||
|
||||
if (!thread)
|
||||
{
|
||||
@ -168,7 +151,7 @@ s32 sys_ppu_thread_get_priority(u32 thread_id, vm::ptr<s32> priop)
|
||||
|
||||
LV2_LOCK;
|
||||
|
||||
const auto thread = idm::get<PPUThread>(thread_id);
|
||||
const auto thread = idm::get<ppu_thread>(thread_id);
|
||||
|
||||
if (!thread)
|
||||
{
|
||||
@ -180,7 +163,7 @@ s32 sys_ppu_thread_get_priority(u32 thread_id, vm::ptr<s32> priop)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_ppu_thread_get_stack_information(PPUThread& ppu, vm::ptr<sys_ppu_thread_stack_t> sp)
|
||||
s32 sys_ppu_thread_get_stack_information(ppu_thread& ppu, vm::ptr<sys_ppu_thread_stack_t> sp)
|
||||
{
|
||||
sys_ppu_thread.trace("sys_ppu_thread_get_stack_information(sp=*0x%x)", sp);
|
||||
|
||||
@ -196,7 +179,7 @@ s32 sys_ppu_thread_stop(u32 thread_id)
|
||||
|
||||
LV2_LOCK;
|
||||
|
||||
const auto thread = idm::get<PPUThread>(thread_id);
|
||||
const auto thread = idm::get<ppu_thread>(thread_id);
|
||||
|
||||
if (!thread)
|
||||
{
|
||||
@ -214,7 +197,7 @@ s32 sys_ppu_thread_restart(u32 thread_id)
|
||||
|
||||
LV2_LOCK;
|
||||
|
||||
const auto thread = idm::get<PPUThread>(thread_id);
|
||||
const auto thread = idm::get<ppu_thread>(thread_id);
|
||||
|
||||
if (!thread)
|
||||
{
|
||||
@ -239,28 +222,30 @@ s32 _sys_ppu_thread_create(vm::ptr<u64> thread_id, vm::ptr<ppu_thread_param_t> p
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
const bool is_joinable = (flags & SYS_PPU_THREAD_CREATE_JOINABLE) != 0;
|
||||
const bool is_interrupt = (flags & SYS_PPU_THREAD_CREATE_INTERRUPT) != 0;
|
||||
|
||||
if (is_joinable && is_interrupt)
|
||||
if ((flags & 3) == 3) // Check two flags: joinable + interrupt not allowed
|
||||
{
|
||||
return CELL_EPERM;
|
||||
}
|
||||
|
||||
const auto ppu = idm::make_ptr<PPUThread>(threadname ? threadname.get_ptr() : "");
|
||||
const auto ppu = idm::make_ptr<ppu_thread>(threadname ? threadname.get_ptr() : "", prio, stacksize);
|
||||
|
||||
ppu->prio = prio;
|
||||
ppu->stack_size = std::max<u32>(stacksize, 0x4000);
|
||||
ppu->cpu_init();
|
||||
ppu->is_joinable = (flags & SYS_PPU_THREAD_CREATE_JOINABLE) != 0;
|
||||
ppu->gpr[13] = param->tls.value();
|
||||
|
||||
ppu->pc = vm::read32(param->entry);
|
||||
ppu->GPR[2] = vm::read32(param->entry + 4); // rtoc
|
||||
ppu->GPR[3] = arg;
|
||||
ppu->GPR[4] = unk; // actually unknown
|
||||
ppu->GPR[13] = param->tls;
|
||||
|
||||
ppu->is_joinable = is_joinable;
|
||||
//ppu->state += cpu_state::interrupt;
|
||||
if ((flags & SYS_PPU_THREAD_CREATE_INTERRUPT) == 0)
|
||||
{
|
||||
// Initialize thread entry point
|
||||
ppu->cmd_list
|
||||
({
|
||||
{ ppu_cmd::set_args, 2 }, arg, unk, // Actually unknown
|
||||
{ ppu_cmd::lle_call, param->entry.value() },
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// Save entry for further use
|
||||
ppu->gpr[2] = param->entry.value();
|
||||
}
|
||||
|
||||
*thread_id = ppu->id;
|
||||
|
||||
@ -273,15 +258,14 @@ s32 sys_ppu_thread_start(u32 thread_id)
|
||||
|
||||
LV2_LOCK;
|
||||
|
||||
const auto thread = idm::get<PPUThread>(thread_id);
|
||||
const auto thread = idm::get<ppu_thread>(thread_id);
|
||||
|
||||
if (!thread)
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
thread->state -= cpu_state::stop;
|
||||
(*thread)->lock_notify();
|
||||
thread->run();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -292,7 +276,7 @@ s32 sys_ppu_thread_rename(u32 thread_id, vm::cptr<char> name)
|
||||
|
||||
LV2_LOCK;
|
||||
|
||||
const auto thread = idm::get<PPUThread>(thread_id);
|
||||
const auto thread = idm::get<ppu_thread>(thread_id);
|
||||
|
||||
if (!thread)
|
||||
{
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include "sys_sync.h"
|
||||
|
||||
class PPUThread;
|
||||
class ppu_thread;
|
||||
|
||||
enum : u32
|
||||
{
|
||||
@ -42,14 +42,14 @@ enum : u32
|
||||
};
|
||||
|
||||
// SysCalls
|
||||
void _sys_ppu_thread_exit(PPUThread& ppu, u64 errorcode);
|
||||
void _sys_ppu_thread_exit(ppu_thread& ppu, u64 errorcode);
|
||||
void sys_ppu_thread_yield();
|
||||
s32 sys_ppu_thread_join(PPUThread& ppu, u32 thread_id, vm::ptr<u64> vptr);
|
||||
s32 sys_ppu_thread_join(ppu_thread& ppu, u32 thread_id, vm::ptr<u64> vptr);
|
||||
s32 sys_ppu_thread_detach(u32 thread_id);
|
||||
void sys_ppu_thread_get_join_state(PPUThread& ppu, vm::ptr<s32> isjoinable);
|
||||
void sys_ppu_thread_get_join_state(ppu_thread& ppu, vm::ptr<s32> isjoinable);
|
||||
s32 sys_ppu_thread_set_priority(u32 thread_id, s32 prio);
|
||||
s32 sys_ppu_thread_get_priority(u32 thread_id, vm::ptr<s32> priop);
|
||||
s32 sys_ppu_thread_get_stack_information(PPUThread& ppu, vm::ptr<sys_ppu_thread_stack_t> sp);
|
||||
s32 sys_ppu_thread_get_stack_information(ppu_thread& ppu, vm::ptr<sys_ppu_thread_stack_t> sp);
|
||||
s32 sys_ppu_thread_stop(u32 thread_id);
|
||||
s32 sys_ppu_thread_restart(u32 thread_id);
|
||||
s32 _sys_ppu_thread_create(vm::ptr<u64> thread_id, vm::ptr<ppu_thread_param_t> param, u64 arg, u64 arg4, s32 prio, u32 stacksize, u64 flags, vm::cptr<char> threadname);
|
||||
|
@ -241,7 +241,7 @@ s32 sys_process_wait_for_child2(u64 unk1, u64 unk2, u64 unk3, u64 unk4, u64 unk5
|
||||
s32 sys_process_get_status(u64 unk)
|
||||
{
|
||||
sys_process.todo("sys_process_get_status(unk=0x%llx)", unk);
|
||||
//vm::write32(CPU.GPR[4], GetPPUThreadStatus(CPU));
|
||||
//vm::write32(CPU.gpr[4], GetPPUThreadStatus(CPU));
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
@ -16,10 +16,10 @@ void lv2_rwlock_t::notify_all(lv2_lock_t)
|
||||
// pick a new writer if possible; protocol is ignored in current implementation
|
||||
if (!readers && !writer && wsq.size())
|
||||
{
|
||||
writer = idm::get<PPUThread>(wsq.front()->id);
|
||||
writer = idm::get<ppu_thread>(wsq.front()->id);
|
||||
|
||||
VERIFY(!writer->state.test_and_set(cpu_state::signal));
|
||||
(*writer)->notify();
|
||||
writer->notify();
|
||||
|
||||
return wsq.pop_front();
|
||||
}
|
||||
@ -32,7 +32,7 @@ void lv2_rwlock_t::notify_all(lv2_lock_t)
|
||||
for (auto& thread : rsq)
|
||||
{
|
||||
VERIFY(!thread->state.test_and_set(cpu_state::signal));
|
||||
(*thread)->notify();
|
||||
thread->notify();
|
||||
}
|
||||
|
||||
return rsq.clear();
|
||||
@ -90,7 +90,7 @@ s32 sys_rwlock_destroy(u32 rw_lock_id)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_rwlock_rlock(PPUThread& ppu, u32 rw_lock_id, u64 timeout)
|
||||
s32 sys_rwlock_rlock(ppu_thread& ppu, u32 rw_lock_id, u64 timeout)
|
||||
{
|
||||
sys_rwlock.trace("sys_rwlock_rlock(rw_lock_id=0x%x, timeout=0x%llx)", rw_lock_id, timeout);
|
||||
|
||||
@ -199,7 +199,7 @@ s32 sys_rwlock_runlock(u32 rw_lock_id)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_rwlock_wlock(PPUThread& ppu, u32 rw_lock_id, u64 timeout)
|
||||
s32 sys_rwlock_wlock(ppu_thread& ppu, u32 rw_lock_id, u64 timeout)
|
||||
{
|
||||
sys_rwlock.trace("sys_rwlock_wlock(rw_lock_id=0x%x, timeout=0x%llx)", rw_lock_id, timeout);
|
||||
|
||||
@ -221,7 +221,7 @@ s32 sys_rwlock_wlock(PPUThread& ppu, u32 rw_lock_id, u64 timeout)
|
||||
|
||||
if (!rwlock->readers && !rwlock->writer)
|
||||
{
|
||||
rwlock->writer = idm::get<PPUThread>(ppu.id);
|
||||
rwlock->writer = idm::get<ppu_thread>(ppu.id);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@ -270,7 +270,7 @@ s32 sys_rwlock_wlock(PPUThread& ppu, u32 rw_lock_id, u64 timeout)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_rwlock_trywlock(PPUThread& ppu, u32 rw_lock_id)
|
||||
s32 sys_rwlock_trywlock(ppu_thread& ppu, u32 rw_lock_id)
|
||||
{
|
||||
sys_rwlock.trace("sys_rwlock_trywlock(rw_lock_id=0x%x)", rw_lock_id);
|
||||
|
||||
@ -293,12 +293,12 @@ s32 sys_rwlock_trywlock(PPUThread& ppu, u32 rw_lock_id)
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
rwlock->writer = idm::get<PPUThread>(ppu.id);
|
||||
rwlock->writer = idm::get<ppu_thread>(ppu.id);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_rwlock_wunlock(PPUThread& ppu, u32 rw_lock_id)
|
||||
s32 sys_rwlock_wunlock(ppu_thread& ppu, u32 rw_lock_id)
|
||||
{
|
||||
sys_rwlock.trace("sys_rwlock_wunlock(rw_lock_id=0x%x)", rw_lock_id);
|
||||
|
||||
|
@ -38,14 +38,14 @@ struct lv2_rwlock_t
|
||||
};
|
||||
|
||||
// Aux
|
||||
class PPUThread;
|
||||
class ppu_thread;
|
||||
|
||||
// SysCalls
|
||||
s32 sys_rwlock_create(vm::ptr<u32> rw_lock_id, vm::ptr<sys_rwlock_attribute_t> attr);
|
||||
s32 sys_rwlock_destroy(u32 rw_lock_id);
|
||||
s32 sys_rwlock_rlock(PPUThread& ppu, u32 rw_lock_id, u64 timeout);
|
||||
s32 sys_rwlock_rlock(ppu_thread& ppu, 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(PPUThread& ppu, u32 rw_lock_id, u64 timeout);
|
||||
s32 sys_rwlock_trywlock(PPUThread& ppu, u32 rw_lock_id);
|
||||
s32 sys_rwlock_wunlock(PPUThread& ppu, u32 rw_lock_id);
|
||||
s32 sys_rwlock_wlock(ppu_thread& ppu, u32 rw_lock_id, u64 timeout);
|
||||
s32 sys_rwlock_trywlock(ppu_thread& ppu, u32 rw_lock_id);
|
||||
s32 sys_rwlock_wunlock(ppu_thread& ppu, u32 rw_lock_id);
|
||||
|
@ -68,7 +68,7 @@ s32 sys_semaphore_destroy(u32 sem_id)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_semaphore_wait(PPUThread& ppu, u32 sem_id, u64 timeout)
|
||||
s32 sys_semaphore_wait(ppu_thread& ppu, u32 sem_id, u64 timeout)
|
||||
{
|
||||
sys_semaphore.trace("sys_semaphore_wait(sem_id=0x%x, timeout=0x%llx)", sem_id, timeout);
|
||||
|
||||
@ -174,7 +174,7 @@ s32 sys_semaphore_post(u32 sem_id, s32 count)
|
||||
|
||||
auto& thread = sem->sq.front();
|
||||
VERIFY(!thread->state.test_and_set(cpu_state::signal));
|
||||
(*thread)->notify();
|
||||
thread->notify();
|
||||
|
||||
sem->sq.pop_front();
|
||||
}
|
||||
|
@ -37,12 +37,12 @@ struct lv2_sema_t
|
||||
};
|
||||
|
||||
// Aux
|
||||
class PPUThread;
|
||||
class ppu_thread;
|
||||
|
||||
// SysCalls
|
||||
s32 sys_semaphore_create(vm::ptr<u32> sem_id, vm::ptr<sys_semaphore_attribute_t> attr, s32 initial_val, s32 max_val);
|
||||
s32 sys_semaphore_destroy(u32 sem_id);
|
||||
s32 sys_semaphore_wait(PPUThread& ppu, u32 sem_id, u64 timeout);
|
||||
s32 sys_semaphore_wait(ppu_thread& ppu, u32 sem_id, u64 timeout);
|
||||
s32 sys_semaphore_trywait(u32 sem_id);
|
||||
s32 sys_semaphore_post(u32 sem_id, s32 count);
|
||||
s32 sys_semaphore_get_value(u32 sem_id, vm::ptr<s32> count);
|
||||
|
@ -321,8 +321,7 @@ s32 sys_spu_thread_group_start(u32 id)
|
||||
{
|
||||
if (thread)
|
||||
{
|
||||
thread->state -= cpu_state::stop;
|
||||
(*thread)->lock_notify();
|
||||
thread->run();
|
||||
}
|
||||
}
|
||||
|
||||
@ -420,7 +419,7 @@ s32 sys_spu_thread_group_resume(u32 id)
|
||||
if (thread)
|
||||
{
|
||||
thread->state -= cpu_state::suspend;
|
||||
(*thread)->lock_notify();
|
||||
thread->lock_notify();
|
||||
}
|
||||
}
|
||||
|
||||
@ -503,7 +502,7 @@ s32 sys_spu_thread_group_terminate(u32 id, s32 value)
|
||||
if (thread)
|
||||
{
|
||||
thread->state += cpu_state::stop;
|
||||
(*thread)->lock_notify();
|
||||
thread->lock_notify();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1154,7 +1153,7 @@ s32 sys_raw_spu_create(vm::ptr<u32> id, vm::ptr<void> attr)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sys_raw_spu_destroy(PPUThread& ppu, u32 id)
|
||||
s32 sys_raw_spu_destroy(ppu_thread& ppu, u32 id)
|
||||
{
|
||||
sys_spu.warning("sys_raw_spu_destroy(id=%d)", id);
|
||||
|
||||
|
@ -196,7 +196,7 @@ struct lv2_spu_group_t
|
||||
}
|
||||
};
|
||||
|
||||
class PPUThread;
|
||||
class ppu_thread;
|
||||
|
||||
// Aux
|
||||
void LoadSpuImage(const fs::file& stream, u32& spu_ep, u32 addr);
|
||||
@ -233,7 +233,7 @@ s32 sys_spu_thread_unbind_queue(u32 id, u32 spuq_num);
|
||||
s32 sys_spu_thread_get_exit_status(u32 id, vm::ptr<u32> status);
|
||||
|
||||
s32 sys_raw_spu_create(vm::ptr<u32> id, vm::ptr<void> attr);
|
||||
s32 sys_raw_spu_destroy(PPUThread& ppu, u32 id);
|
||||
s32 sys_raw_spu_destroy(ppu_thread& ppu, u32 id);
|
||||
s32 sys_raw_spu_create_interrupt_tag(u32 id, u32 class_id, u32 hwthread, vm::ptr<u32> intrtag);
|
||||
s32 sys_raw_spu_set_int_mask(u32 id, u32 class_id, u64 mask);
|
||||
s32 sys_raw_spu_get_int_mask(u32 id, u32 class_id, vm::ptr<u64> mask);
|
||||
|
@ -8,17 +8,13 @@
|
||||
#include "sys_process.h"
|
||||
#include "sys_timer.h"
|
||||
|
||||
#include <thread>
|
||||
|
||||
logs::channel sys_timer("sys_timer", logs::level::notice);
|
||||
|
||||
extern u64 get_system_time();
|
||||
|
||||
extern std::mutex& get_current_thread_mutex();
|
||||
|
||||
void lv2_timer_t::on_task()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(get_current_thread_mutex());
|
||||
thread_lock lock(*this);
|
||||
|
||||
while (state <= SYS_TIMER_STATE_RUN)
|
||||
{
|
||||
@ -54,7 +50,7 @@ void lv2_timer_t::on_task()
|
||||
continue;
|
||||
}
|
||||
|
||||
get_current_thread_cv().wait_for(lock, 1ms);
|
||||
thread_ctrl::wait_for(100);
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,7 +63,7 @@ void lv2_timer_t::on_stop()
|
||||
{
|
||||
// Signal thread using invalid state and join
|
||||
state = -1;
|
||||
(*this)->lock_notify();
|
||||
this->lock_notify();
|
||||
named_thread::on_stop();
|
||||
}
|
||||
|
||||
@ -172,8 +168,7 @@ s32 _sys_timer_start(u32 timer_id, u64 base_time, u64 period)
|
||||
timer->expire = base_time ? base_time : start_time + period;
|
||||
timer->period = period;
|
||||
timer->state = SYS_TIMER_STATE_RUN;
|
||||
|
||||
(*timer)->lock_notify();
|
||||
timer->lock_notify();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
@ -823,19 +823,19 @@ namespace vm
|
||||
{
|
||||
case cpu_type::ppu:
|
||||
{
|
||||
PPUThread& context = static_cast<PPUThread&>(*cpu);
|
||||
ppu_thread& context = static_cast<ppu_thread&>(*cpu);
|
||||
|
||||
const u32 old_pos = vm::cast(context.GPR[1], HERE);
|
||||
context.GPR[1] -= align(size + 4, 8); // room minimal possible size
|
||||
context.GPR[1] &= ~(align_v - 1); // fix stack alignment
|
||||
const u32 old_pos = vm::cast(context.gpr[1], HERE);
|
||||
context.gpr[1] -= align(size + 4, 8); // room minimal possible size
|
||||
context.gpr[1] &= ~(align_v - 1); // fix stack alignment
|
||||
|
||||
if (context.GPR[1] < context.stack_addr)
|
||||
if (context.gpr[1] < context.stack_addr)
|
||||
{
|
||||
throw EXCEPTION("Stack overflow (size=0x%x, align=0x%x, SP=0x%llx, stack=*0x%x)", size, align_v, old_pos, context.stack_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
const u32 addr = static_cast<u32>(context.GPR[1]);
|
||||
const u32 addr = static_cast<u32>(context.gpr[1]);
|
||||
vm::ps3::_ref<nse_t<u32>>(addr + size) = old_pos;
|
||||
std::memset(vm::base(addr), 0, size);
|
||||
return addr;
|
||||
@ -896,15 +896,15 @@ namespace vm
|
||||
{
|
||||
case cpu_type::ppu:
|
||||
{
|
||||
PPUThread& context = static_cast<PPUThread&>(*cpu);
|
||||
ppu_thread& context = static_cast<ppu_thread&>(*cpu);
|
||||
|
||||
if (context.GPR[1] != addr)
|
||||
if (context.gpr[1] != addr)
|
||||
{
|
||||
LOG_ERROR(MEMORY, "Stack inconsistency (addr=0x%x, SP=0x%llx, size=0x%x)", addr, context.GPR[1], size);
|
||||
LOG_ERROR(MEMORY, "Stack inconsistency (addr=0x%x, SP=0x%llx, size=0x%x)", addr, context.gpr[1], size);
|
||||
return;
|
||||
}
|
||||
|
||||
context.GPR[1] = vm::ps3::_ref<nse_t<u32>>(context.GPR[1] + size);
|
||||
context.gpr[1] = vm::ps3::_ref<nse_t<u32>>(context.gpr[1] + size);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include "vm_ref.h"
|
||||
|
||||
class PPUThread;
|
||||
class ppu_thread;
|
||||
class ARMv7Thread;
|
||||
|
||||
namespace vm
|
||||
@ -264,7 +264,7 @@ namespace vm
|
||||
}
|
||||
|
||||
// Callback; defined in PPUCallback.h, passing context is mandatory
|
||||
RT operator()(PPUThread& ppu, T... args) const;
|
||||
RT operator()(ppu_thread& ppu, T... args) const;
|
||||
|
||||
// Callback; defined in ARMv7Callback.h, passing context is mandatory
|
||||
RT operator()(ARMv7Thread& cpu, T... args) const;
|
||||
|
@ -77,7 +77,7 @@ void ARMv7Thread::cpu_task_main()
|
||||
return fmt::format("%s [0x%08x]", cpu->get_name(), cpu->PC);
|
||||
};
|
||||
|
||||
while (!state.load() || !check_status())
|
||||
while (!state.load() || !check_state())
|
||||
{
|
||||
if (ISET == Thumb)
|
||||
{
|
||||
|
@ -129,9 +129,7 @@ arm_error_code sceKernelStartThread(s32 threadId, u32 argSize, vm::cptr<void> pA
|
||||
// set SceKernelThreadEntry function arguments
|
||||
thread->GPR[0] = argSize;
|
||||
thread->GPR[1] = pos;
|
||||
|
||||
thread->state -= cpu_state::stop;
|
||||
(*thread)->lock_notify();
|
||||
thread->run();
|
||||
return SCE_OK;
|
||||
}
|
||||
|
||||
@ -308,7 +306,7 @@ arm_error_code sceKernelWaitThreadEnd(s32 threadId, vm::ptr<s32> pExitStatus, vm
|
||||
{
|
||||
}
|
||||
|
||||
(*thread)->join();
|
||||
thread->join();
|
||||
|
||||
if (pExitStatus)
|
||||
{
|
||||
@ -480,23 +478,20 @@ struct psp2_event_flag final
|
||||
// Returns true if the command has been completed immediately. Its status is unknown otherwise.
|
||||
bool exec(task type, u32 arg)
|
||||
{
|
||||
// Acquire position in the queue
|
||||
// Allocate position in the queue
|
||||
const u32 push_pos = m_workload.push_begin();
|
||||
|
||||
// Make the command
|
||||
cmd_t cmd{type, arg};
|
||||
|
||||
// Get queue head
|
||||
u32 pos = m_workload.peek();
|
||||
|
||||
// Check optimistic case
|
||||
// Check non-optimistic case
|
||||
if (UNLIKELY(pos != push_pos))
|
||||
{
|
||||
// Write the command
|
||||
m_workload[push_pos] = cmd;
|
||||
pos = m_workload.peek(); // ???
|
||||
|
||||
// Try to acquire a command
|
||||
cmd = m_workload[pos].exchange({task::null});
|
||||
// Try to acquire first command in the queue, *then* write current command
|
||||
m_workload[push_pos] = std::exchange(cmd, m_workload[pos].exchange({task::null}));
|
||||
}
|
||||
|
||||
while (true)
|
||||
@ -523,7 +518,7 @@ struct psp2_event_flag final
|
||||
idm::get<ARMv7Thread>(cmd.arg, [&](u32, ARMv7Thread& cpu)
|
||||
{
|
||||
cpu.state += cpu_state::signal;
|
||||
cpu->lock_notify();
|
||||
cpu.lock_notify();
|
||||
});
|
||||
|
||||
break;
|
||||
@ -869,9 +864,9 @@ arm_error_code sceKernelWaitEventFlag(ARMv7Thread& cpu, s32 evfId, u32 bitPatter
|
||||
return SCE_OK;
|
||||
}
|
||||
|
||||
cpu_thread_lock entry(cpu);
|
||||
thread_lock entry(cpu);
|
||||
|
||||
if (!thread_ctrl::wait(timeout, WRAP_EXPR(cpu.state.test_and_reset(cpu_state::signal))))
|
||||
if (!thread_ctrl::wait_for(timeout, WRAP_EXPR(cpu.state.test_and_reset(cpu_state::signal))))
|
||||
{
|
||||
// Timeout cleanup
|
||||
cpu.owner = nullptr;
|
||||
|
@ -375,7 +375,7 @@ namespace rsx
|
||||
|
||||
last_flip_time = get_system_time() - 1000000;
|
||||
|
||||
m_vblank_thread = thread_ctrl::spawn("VBlank Thread", [this]()
|
||||
thread_ctrl::spawn(m_vblank_thread, "VBlank Thread", [this]()
|
||||
{
|
||||
const u64 start_time = get_system_time();
|
||||
|
||||
@ -390,10 +390,13 @@ namespace rsx
|
||||
|
||||
if (vblank_handler)
|
||||
{
|
||||
Emu.GetCallbackManager().Async([func = vblank_handler](PPUThread& ppu)
|
||||
{
|
||||
func(ppu, 1);
|
||||
intr_thread->cmd_list
|
||||
({
|
||||
{ ppu_cmd::set_args, 1 }, u64{1},
|
||||
{ ppu_cmd::lle_call, vblank_handler },
|
||||
});
|
||||
|
||||
intr_thread->lock_notify();
|
||||
}
|
||||
|
||||
continue;
|
||||
|
@ -196,6 +196,8 @@ namespace rsx
|
||||
void capture_frame(const std::string &name);
|
||||
|
||||
public:
|
||||
std::shared_ptr<class ppu_thread> intr_thread;
|
||||
|
||||
u32 ioAddress, ioSize;
|
||||
int flip_status;
|
||||
int flip_mode;
|
||||
|
@ -746,10 +746,13 @@ namespace rsx
|
||||
|
||||
if (rsx->flip_handler)
|
||||
{
|
||||
Emu.GetCallbackManager().Async([func = rsx->flip_handler](PPUThread& ppu)
|
||||
{
|
||||
func(ppu, 1);
|
||||
rsx->intr_thread->cmd_list
|
||||
({
|
||||
{ ppu_cmd::set_args, 1 }, u64{1},
|
||||
{ ppu_cmd::lle_call, rsx->flip_handler },
|
||||
});
|
||||
|
||||
rsx->intr_thread->lock_notify();
|
||||
}
|
||||
}
|
||||
|
||||
@ -757,10 +760,13 @@ namespace rsx
|
||||
{
|
||||
if (rsx->user_handler)
|
||||
{
|
||||
Emu.GetCallbackManager().Async([func = rsx->user_handler, arg](PPUThread& ppu)
|
||||
{
|
||||
func(ppu, arg);
|
||||
rsx->intr_thread->cmd_list
|
||||
({
|
||||
{ ppu_cmd::set_args, 1 }, u64{arg},
|
||||
{ ppu_cmd::lle_call, rsx->user_handler },
|
||||
});
|
||||
|
||||
rsx->intr_thread->lock_notify();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,8 +42,6 @@ std::string g_cfg_defaults;
|
||||
|
||||
extern atomic_t<u32> g_thread_count;
|
||||
|
||||
extern atomic_t<u32> g_ppu_core[2];
|
||||
|
||||
extern u64 get_system_time();
|
||||
|
||||
extern void ppu_load_exec(const ppu_exec_object&);
|
||||
@ -64,7 +62,6 @@ namespace rpcs3
|
||||
Emulator::Emulator()
|
||||
: m_status(Stopped)
|
||||
, m_cpu_thr_stop(0)
|
||||
, m_callback_manager(new CallbackManager())
|
||||
{
|
||||
}
|
||||
|
||||
@ -78,9 +75,6 @@ void Emulator::Init()
|
||||
idm::init();
|
||||
fxm::init();
|
||||
|
||||
g_ppu_core[0] = 0;
|
||||
g_ppu_core[1] = 0;
|
||||
|
||||
// Reset defaults, cache them
|
||||
cfg::root.from_default();
|
||||
g_cfg_defaults = cfg::root.to_string();
|
||||
@ -277,7 +271,6 @@ void Emulator::Load()
|
||||
|
||||
ppu_load_exec(ppu_exec);
|
||||
|
||||
Emu.GetCallbackManager().Init();
|
||||
fxm::import<GSRender>(PURE_EXPR(Emu.GetCallbacks().get_gs_render())); // TODO: must be created in appropriate sys_rsx syscall
|
||||
}
|
||||
else if (ppu_prx.open(elf_file) == elf_error::ok)
|
||||
@ -286,7 +279,6 @@ void Emulator::Load()
|
||||
m_status = Ready;
|
||||
vm::ps3::init();
|
||||
ppu_load_prx(ppu_prx);
|
||||
GetCallbackManager().Init();
|
||||
}
|
||||
else if (spu_exec.open(elf_file) == elf_error::ok)
|
||||
{
|
||||
@ -348,10 +340,9 @@ void Emulator::Run()
|
||||
m_pause_amend_time = 0;
|
||||
m_status = Running;
|
||||
|
||||
idm::select<PPUThread, SPUThread, RawSPUThread, ARMv7Thread>([](u32, cpu_thread& cpu)
|
||||
idm::select<ppu_thread, SPUThread, RawSPUThread, ARMv7Thread>([](u32, cpu_thread& cpu)
|
||||
{
|
||||
cpu.state -= cpu_state::stop;
|
||||
cpu->lock_notify();
|
||||
cpu.run();
|
||||
});
|
||||
|
||||
SendDbgCommand(DID_STARTED_EMU);
|
||||
@ -377,7 +368,7 @@ bool Emulator::Pause()
|
||||
|
||||
SendDbgCommand(DID_PAUSE_EMU);
|
||||
|
||||
idm::select<PPUThread, SPUThread, RawSPUThread, ARMv7Thread>([](u32, cpu_thread& cpu)
|
||||
idm::select<ppu_thread, SPUThread, RawSPUThread, ARMv7Thread>([](u32, cpu_thread& cpu)
|
||||
{
|
||||
cpu.state += cpu_state::dbg_global_pause;
|
||||
});
|
||||
@ -411,10 +402,10 @@ void Emulator::Resume()
|
||||
|
||||
SendDbgCommand(DID_RESUME_EMU);
|
||||
|
||||
idm::select<PPUThread, SPUThread, RawSPUThread, ARMv7Thread>([](u32, cpu_thread& cpu)
|
||||
idm::select<ppu_thread, SPUThread, RawSPUThread, ARMv7Thread>([](u32, cpu_thread& cpu)
|
||||
{
|
||||
cpu.state -= cpu_state::dbg_global_pause;
|
||||
cpu->lock_notify();
|
||||
cpu.lock_notify();
|
||||
});
|
||||
|
||||
rpcs3::on_resume()();
|
||||
@ -437,7 +428,7 @@ void Emulator::Stop()
|
||||
{
|
||||
LV2_LOCK;
|
||||
|
||||
idm::select<PPUThread, SPUThread, RawSPUThread, ARMv7Thread>([](u32, cpu_thread& cpu)
|
||||
idm::select<ppu_thread, SPUThread, RawSPUThread, ARMv7Thread>([](u32, cpu_thread& cpu)
|
||||
{
|
||||
cpu.state += cpu_state::dbg_global_stop;
|
||||
cpu->lock();
|
||||
@ -463,8 +454,6 @@ void Emulator::Stop()
|
||||
|
||||
LOG_NOTICE(GENERAL, "Objects cleared...");
|
||||
|
||||
GetCallbackManager().Clear();
|
||||
|
||||
RSXIOMem.Clear();
|
||||
vm::close();
|
||||
|
||||
|
@ -32,8 +32,6 @@ enum Status : u32
|
||||
// Emulation Stopped exception event
|
||||
class EmulationStopped {};
|
||||
|
||||
class CallbackManager;
|
||||
|
||||
class Emulator final
|
||||
{
|
||||
atomic_t<u32> m_status;
|
||||
@ -45,8 +43,6 @@ class Emulator final
|
||||
|
||||
u32 m_cpu_thr_stop;
|
||||
|
||||
std::unique_ptr<CallbackManager> m_callback_manager;
|
||||
|
||||
std::string m_path;
|
||||
std::string m_elf_path;
|
||||
std::string m_title_id;
|
||||
@ -107,11 +103,6 @@ public:
|
||||
return m_pause_amend_time;
|
||||
}
|
||||
|
||||
CallbackManager& GetCallbackManager()
|
||||
{
|
||||
return *m_callback_manager;
|
||||
}
|
||||
|
||||
void SetCPUThreadStop(u32 addr)
|
||||
{
|
||||
m_cpu_thr_stop = addr;
|
||||
|
@ -25,7 +25,7 @@ u32 InterpreterDisAsmFrame::GetPc() const
|
||||
{
|
||||
switch (cpu->type)
|
||||
{
|
||||
case cpu_type::ppu: return static_cast<PPUThread*>(cpu)->pc;
|
||||
case cpu_type::ppu: return static_cast<ppu_thread*>(cpu)->cia;
|
||||
case cpu_type::spu: return static_cast<SPUThread*>(cpu)->pc;
|
||||
case cpu_type::arm: return static_cast<ARMv7Thread*>(cpu)->PC;
|
||||
}
|
||||
@ -123,7 +123,7 @@ void InterpreterDisAsmFrame::UpdateUnitList()
|
||||
m_choice_units->Freeze();
|
||||
m_choice_units->Clear();
|
||||
|
||||
idm::select<PPUThread, SPUThread, RawSPUThread, ARMv7Thread>([&](u32, cpu_thread& cpu)
|
||||
idm::select<ppu_thread, SPUThread, RawSPUThread, ARMv7Thread>([&](u32, cpu_thread& cpu)
|
||||
{
|
||||
m_choice_units->Append(cpu.get_name(), &cpu);
|
||||
});
|
||||
|
@ -220,11 +220,11 @@ void KernelExplorer::Update()
|
||||
}
|
||||
|
||||
// PPU Threads
|
||||
if (const u32 count = idm::get_count<PPUThread>())
|
||||
if (const u32 count = idm::get_count<ppu_thread>())
|
||||
{
|
||||
const auto& node = m_tree->AppendItem(root, fmt::format("PPU Threads (%zu)", count));
|
||||
|
||||
idm::select<PPUThread>([&](u32 id, PPUThread& ppu)
|
||||
idm::select<ppu_thread>([&](u32 id, ppu_thread& ppu)
|
||||
{
|
||||
m_tree->AppendItem(node, fmt::format("PPU Thread: ID = 0x%08x '%s'", id, ppu.get_name()));
|
||||
});
|
||||
|
@ -414,16 +414,16 @@ void MainFrame::Stop(wxCommandEvent& WXUNUSED(event))
|
||||
}
|
||||
|
||||
// This is ugly, but PS3 headers shall not be included there.
|
||||
extern void sysutilSendSystemCommand(u64 status, u64 param);
|
||||
extern void sysutil_send_system_cmd(u64 status, u64 param);
|
||||
|
||||
void MainFrame::SendExit(wxCommandEvent& event)
|
||||
{
|
||||
sysutilSendSystemCommand(0x0101 /* CELL_SYSUTIL_REQUEST_EXITGAME */, 0);
|
||||
sysutil_send_system_cmd(0x0101 /* CELL_SYSUTIL_REQUEST_EXITGAME */, 0);
|
||||
}
|
||||
|
||||
void MainFrame::SendOpenCloseSysMenu(wxCommandEvent& event)
|
||||
{
|
||||
sysutilSendSystemCommand(m_sys_menu_opened ? 0x0132 /* CELL_SYSUTIL_SYSTEM_MENU_CLOSE */ : 0x0131 /* CELL_SYSUTIL_SYSTEM_MENU_OPEN */, 0);
|
||||
sysutil_send_system_cmd(m_sys_menu_opened ? 0x0132 /* CELL_SYSUTIL_SYSTEM_MENU_CLOSE */ : 0x0131 /* CELL_SYSUTIL_SYSTEM_MENU_OPEN */, 0);
|
||||
m_sys_menu_opened = !m_sys_menu_opened;
|
||||
wxCommandEvent ce;
|
||||
UpdateUI(ce);
|
||||
|
@ -86,7 +86,7 @@ RegisterEditorDialog::RegisterEditorDialog(wxPanel *parent, u32 _pc, cpu_thread*
|
||||
{
|
||||
case cpu_type::ppu:
|
||||
{
|
||||
auto& ppu = *static_cast<PPUThread*>(cpu);
|
||||
auto& ppu = *static_cast<ppu_thread*>(cpu);
|
||||
|
||||
while (value.length() < 32) value = "0" + value;
|
||||
std::string::size_type first_brk = reg.find('[');
|
||||
@ -99,8 +99,8 @@ RegisterEditorDialog::RegisterEditorDialog(wxPanel *parent, u32 _pc, cpu_thread*
|
||||
{
|
||||
unsigned long long reg_value;
|
||||
reg_value = std::stoull(value.substr(16, 31), 0, 16);
|
||||
if (reg.find("GPR") == 0) ppu.GPR[reg_index] = (u64)reg_value;
|
||||
if (reg.find("FPR") == 0) (u64&)ppu.FPR[reg_index] = (u64)reg_value;
|
||||
if (reg.find("GPR") == 0) ppu.gpr[reg_index] = (u64)reg_value;
|
||||
if (reg.find("FPR") == 0) (u64&)ppu.fpr[reg_index] = (u64)reg_value;
|
||||
return;
|
||||
}
|
||||
if (reg.find("VR") == 0)
|
||||
@ -109,8 +109,8 @@ RegisterEditorDialog::RegisterEditorDialog(wxPanel *parent, u32 _pc, cpu_thread*
|
||||
unsigned long long reg_value1;
|
||||
reg_value0 = std::stoull(value.substr(16, 31), 0, 16);
|
||||
reg_value1 = std::stoull(value.substr(0, 15), 0, 16);
|
||||
ppu.VR[reg_index]._u64[0] = (u64)reg_value0;
|
||||
ppu.VR[reg_index]._u64[1] = (u64)reg_value1;
|
||||
ppu.vr[reg_index]._u64[0] = (u64)reg_value0;
|
||||
ppu.vr[reg_index]._u64[1] = (u64)reg_value1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -118,15 +118,15 @@ RegisterEditorDialog::RegisterEditorDialog(wxPanel *parent, u32 _pc, cpu_thread*
|
||||
{
|
||||
unsigned long long reg_value;
|
||||
reg_value = std::stoull(value.substr(16, 31), 0, 16);
|
||||
if (reg == "LR") ppu.LR = (u64)reg_value;
|
||||
if (reg == "CTR") ppu.CTR = (u64)reg_value;
|
||||
if (reg == "LR") ppu.lr = (u64)reg_value;
|
||||
if (reg == "CTR") ppu.ctr = (u64)reg_value;
|
||||
return;
|
||||
}
|
||||
if (reg == "CR")
|
||||
{
|
||||
unsigned long long reg_value;
|
||||
reg_value = std::stoull(value.substr(24, 31), 0, 16);
|
||||
if (reg == "CR") ppu.SetCR((u32)reg_value);
|
||||
if (reg == "CR") ppu.cr_unpack((u32)reg_value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -183,19 +183,19 @@ void RegisterEditorDialog::updateRegister(wxCommandEvent& event)
|
||||
{
|
||||
case cpu_type::ppu:
|
||||
{
|
||||
auto& ppu = *static_cast<PPUThread*>(cpu);
|
||||
auto& ppu = *static_cast<ppu_thread*>(cpu);
|
||||
|
||||
std::size_t first_brk = reg.find('[');
|
||||
if (first_brk != -1)
|
||||
{
|
||||
long reg_index = std::atol(reg.substr(first_brk + 1, reg.length() - first_brk - 2).c_str());
|
||||
if (reg.find("GPR") == 0) str = fmt::format("%016llx", ppu.GPR[reg_index]);
|
||||
if (reg.find("FPR") == 0) str = fmt::format("%016llx", ppu.FPR[reg_index]);
|
||||
if (reg.find("VR") == 0) str = fmt::format("%016llx%016llx", ppu.VR[reg_index]._u64[1], ppu.VR[reg_index]._u64[0]);
|
||||
if (reg.find("GPR") == 0) str = fmt::format("%016llx", ppu.gpr[reg_index]);
|
||||
if (reg.find("FPR") == 0) str = fmt::format("%016llx", ppu.fpr[reg_index]);
|
||||
if (reg.find("VR") == 0) str = fmt::format("%016llx%016llx", ppu.vr[reg_index]._u64[1], ppu.vr[reg_index]._u64[0]);
|
||||
}
|
||||
if (reg == "CR") str = fmt::format("%08x", ppu.GetCR());
|
||||
if (reg == "LR") str = fmt::format("%016llx", ppu.LR);
|
||||
if (reg == "CTR") str = fmt::format("%016llx", ppu.CTR);
|
||||
if (reg == "CR") str = fmt::format("%08x", ppu.cr_pack());
|
||||
if (reg == "LR") str = fmt::format("%016llx", ppu.lr);
|
||||
if (reg == "CTR") str = fmt::format("%016llx", ppu.ctr);
|
||||
break;
|
||||
}
|
||||
case cpu_type::spu:
|
||||
|
@ -240,7 +240,6 @@
|
||||
<ClCompile Include="Emu\Cell\Modules\sys_prx_.cpp" />
|
||||
<ClCompile Include="Emu\Cell\Modules\sys_spinlock.cpp" />
|
||||
<ClCompile Include="Emu\Cell\Modules\sys_spu_.cpp" />
|
||||
<ClCompile Include="Emu\Cell\PPUCallback.cpp" />
|
||||
<ClCompile Include="Emu\Cell\PPUDisAsm.cpp" />
|
||||
<ClCompile Include="Emu\Cell\PPUFunction.cpp" />
|
||||
<ClCompile Include="Emu\Cell\PPUInterpreter.cpp" />
|
||||
@ -390,6 +389,7 @@
|
||||
<ClInclude Include="..\Utilities\GSL.h" />
|
||||
<ClInclude Include="..\Utilities\JIT.h" />
|
||||
<ClInclude Include="..\Utilities\lockless.h" />
|
||||
<ClInclude Include="..\Utilities\SleepQueue.h" />
|
||||
<ClInclude Include="..\Utilities\sync.h" />
|
||||
<ClInclude Include="..\Utilities\Platform.h" />
|
||||
<ClInclude Include="..\Utilities\Log.h" />
|
||||
|
@ -632,9 +632,6 @@
|
||||
<ClCompile Include="Emu\Cell\Modules\sysPrxForUser.cpp">
|
||||
<Filter>Emu\Cell\Modules</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\Cell\PPUCallback.cpp">
|
||||
<Filter>Emu\Cell</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\Cell\PPUFunction.cpp">
|
||||
<Filter>Emu\Cell</Filter>
|
||||
</ClCompile>
|
||||
@ -1696,5 +1693,8 @@
|
||||
<ClInclude Include="Emu\RSX\rsx_trace.h">
|
||||
<Filter>Emu\GPU\RSX</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Utilities\SleepQueue.h">
|
||||
<Filter>Utilities</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
Loading…
Reference in New Issue
Block a user