2020-12-05 13:08:24 +01:00
|
|
|
#pragma once
|
2015-07-09 02:33:15 +02:00
|
|
|
|
2016-06-07 22:24:20 +02:00
|
|
|
#include "../CPU/CPUThread.h"
|
2018-09-25 22:34:45 +02:00
|
|
|
#include "../Memory/vm_ptr.h"
|
2016-07-27 23:43:22 +02:00
|
|
|
#include "Utilities/lockless.h"
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2020-12-22 09:42:57 +01:00
|
|
|
#include "util/logs.hpp"
|
2020-12-13 14:34:45 +01:00
|
|
|
#include "util/v128.hpp"
|
|
|
|
|
|
2020-02-01 09:31:27 +01:00
|
|
|
LOG_CHANNEL(ppu_log, "PPU");
|
|
|
|
|
|
2016-08-09 16:14:41 +02:00
|
|
|
enum class ppu_cmd : u32
|
2016-07-27 23:43:22 +02:00
|
|
|
{
|
2016-08-09 16:14:41 +02:00
|
|
|
null,
|
2016-07-27 23:43:22 +02:00
|
|
|
|
2016-08-09 16:14:41 +02:00
|
|
|
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)
|
2018-10-11 00:17:19 +02:00
|
|
|
ptr_call, // Execute function by pointer
|
2020-04-08 13:26:31 +02:00
|
|
|
opd_call, // Execute function by provided rtoc and address (unlike lle_call, does not read memory)
|
2022-07-04 15:02:17 +02:00
|
|
|
cia_call, // Execute from current CIA, mo GPR modification applied
|
2017-01-22 20:03:57 +01:00
|
|
|
initialize, // ppu_initialize()
|
2017-02-06 19:36:46 +01:00
|
|
|
sleep,
|
2018-03-06 03:36:33 +01:00
|
|
|
reset_stack, // resets stack address
|
2016-07-27 23:43:22 +02:00
|
|
|
};
|
|
|
|
|
|
2020-03-03 21:39:40 +01:00
|
|
|
enum class ppu_join_status : u32
|
|
|
|
|
{
|
|
|
|
|
joinable = 0,
|
|
|
|
|
detached = 1,
|
|
|
|
|
zombie = 2,
|
|
|
|
|
exited = 3,
|
|
|
|
|
max = 4, // Values above it indicate PPU id of joining thread
|
|
|
|
|
};
|
|
|
|
|
|
2021-05-21 07:48:37 +02:00
|
|
|
enum ppu_thread_status : u32
|
|
|
|
|
{
|
|
|
|
|
PPU_THREAD_STATUS_IDLE,
|
|
|
|
|
PPU_THREAD_STATUS_RUNNABLE,
|
|
|
|
|
PPU_THREAD_STATUS_ONPROC,
|
|
|
|
|
PPU_THREAD_STATUS_SLEEP,
|
|
|
|
|
PPU_THREAD_STATUS_STOP,
|
|
|
|
|
PPU_THREAD_STATUS_ZOMBIE,
|
|
|
|
|
PPU_THREAD_STATUS_DELETED,
|
|
|
|
|
PPU_THREAD_STATUS_UNKNOWN,
|
|
|
|
|
};
|
|
|
|
|
|
2017-06-26 00:44:05 +02:00
|
|
|
// Formatting helper
|
|
|
|
|
enum class ppu_syscall_code : u64
|
|
|
|
|
{
|
|
|
|
|
};
|
|
|
|
|
|
2020-07-03 05:18:14 +02:00
|
|
|
enum : u32
|
|
|
|
|
{
|
|
|
|
|
ppu_stack_start_offset = 0x70,
|
|
|
|
|
};
|
|
|
|
|
|
2020-04-08 13:26:31 +02:00
|
|
|
// ppu function descriptor
|
|
|
|
|
struct ppu_func_opd_t
|
|
|
|
|
{
|
|
|
|
|
be_t<u32> addr;
|
|
|
|
|
be_t<u32> rtoc;
|
|
|
|
|
};
|
|
|
|
|
|
2018-10-11 00:17:19 +02:00
|
|
|
// ppu_thread constructor argument
|
|
|
|
|
struct ppu_thread_params
|
|
|
|
|
{
|
|
|
|
|
vm::addr_t stack_addr;
|
|
|
|
|
u32 stack_size;
|
|
|
|
|
u32 tls_addr;
|
2020-04-08 13:26:31 +02:00
|
|
|
ppu_func_opd_t entry;
|
2018-10-11 00:17:19 +02:00
|
|
|
u64 arg0;
|
|
|
|
|
u64 arg1;
|
|
|
|
|
};
|
|
|
|
|
|
2020-12-12 11:12:39 +01:00
|
|
|
struct cmd64
|
|
|
|
|
{
|
|
|
|
|
u64 m_data = 0;
|
|
|
|
|
|
|
|
|
|
constexpr cmd64() noexcept = default;
|
|
|
|
|
|
|
|
|
|
struct pair_t
|
|
|
|
|
{
|
|
|
|
|
u32 arg1;
|
|
|
|
|
u32 arg2;
|
|
|
|
|
};
|
|
|
|
|
|
2021-04-16 05:40:54 +02:00
|
|
|
template <typename T, typename T2 = std::common_type_t<T>>
|
2020-12-12 11:12:39 +01:00
|
|
|
cmd64(const T& value)
|
|
|
|
|
: m_data(std::bit_cast<u64, T2>(value))
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T1, typename T2>
|
|
|
|
|
cmd64(const T1& arg1, const T2& arg2)
|
|
|
|
|
: cmd64(pair_t{std::bit_cast<u32>(arg1), std::bit_cast<u32>(arg2)})
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
explicit operator bool() const
|
|
|
|
|
{
|
|
|
|
|
return m_data != 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
T as() const
|
|
|
|
|
{
|
|
|
|
|
return std::bit_cast<T>(m_data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
T arg1() const
|
|
|
|
|
{
|
|
|
|
|
return std::bit_cast<T>(std::bit_cast<pair_t>(m_data).arg1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
T arg2() const
|
|
|
|
|
{
|
|
|
|
|
return std::bit_cast<T>(std::bit_cast<pair_t>(m_data).arg2);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2016-07-27 23:43:22 +02:00
|
|
|
class ppu_thread : public cpu_thread
|
2012-11-15 00:39:56 +01:00
|
|
|
{
|
2016-04-14 01:09:41 +02:00
|
|
|
public:
|
2017-01-25 18:50:30 +01:00
|
|
|
static const u32 id_base = 0x01000000; // TODO (used to determine thread type)
|
|
|
|
|
static const u32 id_step = 1;
|
2020-09-30 20:08:09 +02:00
|
|
|
static const u32 id_count = 100;
|
2019-11-28 11:17:16 +01:00
|
|
|
static constexpr std::pair<u32, u32> id_invl_range = {12, 12};
|
2016-08-09 16:14:41 +02:00
|
|
|
|
2022-06-22 11:00:06 +02:00
|
|
|
virtual void dump_regs(std::string&) const override;
|
2020-03-31 02:11:37 +02:00
|
|
|
virtual std::string dump_callstack() const override;
|
2020-07-03 06:56:55 +02:00
|
|
|
virtual std::vector<std::pair<u32, u32>> dump_callstack_list() const override;
|
2020-03-31 02:11:37 +02:00
|
|
|
virtual std::string dump_misc() const override;
|
2022-06-22 11:00:06 +02:00
|
|
|
virtual void dump_all(std::string&) const override;
|
2018-10-11 00:17:19 +02:00
|
|
|
virtual void cpu_task() override final;
|
2017-02-06 19:36:46 +01:00
|
|
|
virtual void cpu_sleep() override;
|
2021-02-13 15:50:07 +01:00
|
|
|
virtual void cpu_on_stop() override;
|
2016-07-27 23:43:22 +02:00
|
|
|
virtual ~ppu_thread() override;
|
|
|
|
|
|
2022-07-04 15:02:17 +02:00
|
|
|
SAVESTATE_INIT_POS(3);
|
2016-07-27 23:43:22 +02:00
|
|
|
|
2022-07-04 15:02:17 +02:00
|
|
|
ppu_thread(const ppu_thread_params&, std::string_view name, u32 prio, int detached = 0);
|
|
|
|
|
ppu_thread(utils::serial& ar);
|
2021-03-30 17:31:46 +02:00
|
|
|
ppu_thread(const ppu_thread&) = delete;
|
|
|
|
|
ppu_thread& operator=(const ppu_thread&) = delete;
|
2022-07-04 15:02:17 +02:00
|
|
|
bool savable() const;
|
|
|
|
|
void serialize_common(utils::serial& ar);
|
|
|
|
|
void save(utils::serial& ar);
|
2021-03-30 17:31:46 +02:00
|
|
|
|
2021-06-27 12:18:48 +02:00
|
|
|
using cpu_thread::operator=;
|
|
|
|
|
|
2016-07-27 23:43:22 +02:00
|
|
|
u64 gpr[32] = {}; // General-Purpose Registers
|
|
|
|
|
f64 fpr[32] = {}; // Floating Point Registers
|
|
|
|
|
v128 vr[32] = {}; // Vector Registers
|
|
|
|
|
|
2019-04-18 10:58:08 +02:00
|
|
|
union alignas(16) cr_bits
|
2017-06-25 22:34:15 +02:00
|
|
|
{
|
2019-04-18 10:58:08 +02:00
|
|
|
u8 bits[32];
|
|
|
|
|
u32 fields[8];
|
2016-07-27 23:43:22 +02:00
|
|
|
|
2020-12-18 08:39:54 +01:00
|
|
|
u8& operator [](usz i)
|
2019-03-19 09:20:02 +01:00
|
|
|
{
|
|
|
|
|
return bits[i];
|
|
|
|
|
}
|
2017-04-13 02:32:28 +02:00
|
|
|
|
2019-03-19 09:20:02 +01:00
|
|
|
// Pack CR bits
|
|
|
|
|
u32 pack() const
|
|
|
|
|
{
|
|
|
|
|
u32 result{};
|
2016-07-27 23:43:22 +02:00
|
|
|
|
2019-03-19 09:20:02 +01:00
|
|
|
for (u32 bit : bits)
|
|
|
|
|
{
|
|
|
|
|
result <<= 1;
|
|
|
|
|
result |= bit;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-05 15:28:41 +02:00
|
|
|
return result;
|
2019-03-19 09:20:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Unpack CR bits
|
|
|
|
|
void unpack(u32 value)
|
2016-07-27 23:43:22 +02:00
|
|
|
{
|
2019-03-19 09:20:02 +01:00
|
|
|
for (u8& b : bits)
|
|
|
|
|
{
|
2022-07-04 15:02:17 +02:00
|
|
|
b = !!(value & (1u << 31));
|
|
|
|
|
value <<= 1;
|
2019-03-19 09:20:02 +01:00
|
|
|
}
|
2016-07-27 23:43:22 +02:00
|
|
|
}
|
2019-03-19 09:20:02 +01:00
|
|
|
};
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2019-03-19 09:20:02 +01:00
|
|
|
cr_bits cr{}; // Condition Registers (unpacked)
|
2016-04-25 12:49:12 +02:00
|
|
|
|
2019-03-19 09:20:02 +01:00
|
|
|
// Floating-Point Status and Control Register (unpacked)
|
|
|
|
|
union
|
2016-07-27 23:43:22 +02:00
|
|
|
{
|
2019-03-19 09:20:02 +01:00
|
|
|
struct
|
2016-07-27 23:43:22 +02:00
|
|
|
{
|
2019-03-19 09:20:02 +01:00
|
|
|
// TODO
|
|
|
|
|
bool _start[16];
|
|
|
|
|
bool fl; // FPCC.FL
|
|
|
|
|
bool fg; // FPCC.FG
|
|
|
|
|
bool fe; // FPCC.FE
|
|
|
|
|
bool fu; // FPCC.FU
|
|
|
|
|
bool _end[12];
|
|
|
|
|
};
|
|
|
|
|
|
2019-04-18 10:58:08 +02:00
|
|
|
u32 fields[8];
|
2019-03-19 09:20:02 +01:00
|
|
|
cr_bits bits;
|
2016-07-27 23:43:22 +02:00
|
|
|
}
|
2019-03-19 09:20:02 +01:00
|
|
|
fpscr{};
|
|
|
|
|
|
|
|
|
|
u64 lr{}; // Link Register
|
|
|
|
|
u64 ctr{}; // Counter Register
|
|
|
|
|
u32 vrsave{0xffffffff}; // VR Save Register
|
|
|
|
|
u32 cia{}; // Current Instruction Address
|
2013-06-30 10:46:29 +02:00
|
|
|
|
2016-07-27 23:43:22 +02:00
|
|
|
// Fixed-Point Exception Register (abstract representation)
|
|
|
|
|
struct
|
|
|
|
|
{
|
2022-07-04 15:02:17 +02:00
|
|
|
ENABLE_BITWISE_SERIALIZATION;
|
|
|
|
|
|
2016-07-27 23:43:22 +02:00
|
|
|
bool so{}; // Summary Overflow
|
|
|
|
|
bool ov{}; // Overflow
|
|
|
|
|
bool ca{}; // Carry
|
|
|
|
|
u8 cnt{}; // 0..6
|
|
|
|
|
}
|
|
|
|
|
xer;
|
2018-04-03 16:19:07 +02:00
|
|
|
|
2016-04-14 01:09:41 +02:00
|
|
|
/*
|
2013-06-30 10:46:29 +02:00
|
|
|
Non-Java. A mode control bit that determines whether vector floating-point operations will be performed
|
2014-07-12 16:53:36 +02:00
|
|
|
in a Java-IEEE-C9X-compliant mode or a possibly faster non-Java/non-IEEE mode.
|
|
|
|
|
0 The Java-IEEE-C9X-compliant mode is selected. Denormalized values are handled as specified
|
2013-06-30 10:46:29 +02:00
|
|
|
by Java, IEEE, and C9X standard.
|
2014-07-12 16:53:36 +02:00
|
|
|
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
|
2016-07-27 23:43:22 +02:00
|
|
|
exception, the corresponding element in the target vr is cleared to '0'. In both cases, the '0'
|
2013-06-30 10:46:29 +02:00
|
|
|
has the same sign as the denormalized or underflowing value.
|
2016-04-14 01:09:41 +02:00
|
|
|
*/
|
2020-07-25 08:41:41 +02:00
|
|
|
bool nj = true;
|
|
|
|
|
|
2021-11-26 18:01:29 +01:00
|
|
|
// Sticky saturation bit
|
|
|
|
|
v128 sat{};
|
|
|
|
|
|
2020-07-25 08:41:41 +02:00
|
|
|
// Optimization: precomputed java-mode mask for handling denormals
|
|
|
|
|
u32 jm_mask = 0x7f80'0000;
|
2016-04-14 01:09:41 +02:00
|
|
|
|
2017-02-17 20:35:57 +01:00
|
|
|
u32 raddr{0}; // Reservation addr
|
|
|
|
|
u64 rtime{0};
|
2020-10-01 17:15:07 +02:00
|
|
|
alignas(64) std::byte rdata[128]{}; // Reservation data
|
2020-04-07 19:29:11 +02:00
|
|
|
bool use_full_rdata{};
|
2018-04-03 16:19:07 +02:00
|
|
|
|
2019-11-01 20:21:15 +01:00
|
|
|
atomic_t<s32> prio{0}; // Thread priority (0..3071)
|
2016-07-27 23:43:22 +02:00
|
|
|
const u32 stack_size; // Stack size
|
|
|
|
|
const u32 stack_addr; // Stack address
|
2018-04-03 16:19:07 +02:00
|
|
|
|
2020-03-03 21:39:40 +01:00
|
|
|
atomic_t<ppu_join_status> joiner; // Joining thread or status
|
2015-07-01 00:25:52 +02:00
|
|
|
|
2017-01-30 14:20:09 +01:00
|
|
|
lf_fifo<atomic_t<cmd64>, 127> cmd_queue; // Command queue for asynchronous operations.
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2016-08-09 16:14:41 +02:00
|
|
|
void cmd_push(cmd64);
|
|
|
|
|
void cmd_list(std::initializer_list<cmd64>);
|
2016-07-27 23:43:22 +02:00
|
|
|
void cmd_pop(u32 = 0);
|
2016-08-09 16:14:41 +02:00
|
|
|
cmd64 cmd_wait(); // Empty command means caller must return, like true from cpu_thread::check_status().
|
|
|
|
|
cmd64 cmd_get(u32 index) { return cmd_queue[cmd_queue.peek() + index].load(); }
|
2021-02-13 15:50:07 +01:00
|
|
|
atomic_t<u32> cmd_notify = 0;
|
2014-09-24 20:44:26 +02:00
|
|
|
|
2021-03-16 14:41:32 +01:00
|
|
|
alignas(64) const ppu_func_opd_t entry_func;
|
2017-02-22 11:10:55 +01:00
|
|
|
u64 start_time{0}; // Sleep start timepoint
|
2021-03-16 14:41:32 +01:00
|
|
|
u64 syscall_args[8]{0}; // Last syscall arguments stored
|
2019-07-09 19:44:07 +02:00
|
|
|
const char* current_function{}; // Current function name for diagnosis, optimized for speed.
|
|
|
|
|
const char* last_function{}; // Sticky copy of current_function, is not cleared on function return
|
2015-08-30 18:16:38 +02:00
|
|
|
|
2022-07-04 15:02:17 +02:00
|
|
|
const bool is_interrupt_thread; // True for interrupts-handler threads
|
|
|
|
|
|
2020-02-28 08:43:37 +01:00
|
|
|
// Thread name
|
2020-11-26 10:30:51 +01:00
|
|
|
atomic_ptr<std::string> ppu_tname;
|
2012-11-15 00:39:56 +01:00
|
|
|
|
2021-01-31 19:38:47 +01:00
|
|
|
u64 saved_native_sp = 0; // Host thread's stack pointer for emulated longjmp
|
|
|
|
|
|
2020-10-29 19:46:50 +01:00
|
|
|
u64 last_ftsc = 0;
|
|
|
|
|
u64 last_ftime = 0;
|
|
|
|
|
u32 last_faddr = 0;
|
|
|
|
|
u64 last_fail = 0;
|
|
|
|
|
u64 last_succ = 0;
|
2021-12-30 17:39:18 +01:00
|
|
|
u64 exec_bytes = 0; // Amount of "bytes" executed (4 for each instruction)
|
2020-10-29 19:46:50 +01:00
|
|
|
|
2021-02-19 12:53:09 +01:00
|
|
|
u32 dbg_step_pc = 0;
|
|
|
|
|
|
2021-07-10 10:56:48 +02:00
|
|
|
struct call_history_t
|
|
|
|
|
{
|
|
|
|
|
std::vector<u32> data;
|
|
|
|
|
u64 index = 0;
|
2021-07-18 16:02:34 +02:00
|
|
|
u64 last_r1 = umax;
|
|
|
|
|
u64 last_r2 = umax;
|
2021-07-10 10:56:48 +02:00
|
|
|
} call_history;
|
|
|
|
|
|
|
|
|
|
static constexpr u32 call_history_max_size = 4096;
|
|
|
|
|
|
2021-09-06 09:33:44 +02:00
|
|
|
struct hle_func_call_with_toc_info_t
|
|
|
|
|
{
|
|
|
|
|
u32 cia;
|
|
|
|
|
u64 saved_lr;
|
|
|
|
|
u64 saved_r2;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
std::vector<hle_func_call_with_toc_info_t> hle_func_calls_with_toc_info;
|
|
|
|
|
|
2021-05-01 08:34:52 +02:00
|
|
|
// For named_thread ctor
|
|
|
|
|
const struct thread_name_t
|
|
|
|
|
{
|
|
|
|
|
const ppu_thread* _this;
|
|
|
|
|
|
|
|
|
|
operator std::string() const;
|
|
|
|
|
} thread_name{ this };
|
|
|
|
|
|
2022-07-04 15:02:17 +02:00
|
|
|
// For savestates
|
2022-07-05 13:12:21 +02:00
|
|
|
bool stop_flag_removal_protection = false; // If set, Emulator::Run won't remove stop flag
|
2022-07-04 15:02:17 +02:00
|
|
|
bool loaded_from_savestate = false; // Indicates the thread had just started straight from savestate load
|
2022-07-05 13:12:21 +02:00
|
|
|
std::shared_ptr<utils::serial> optional_savestate_state;
|
2022-07-04 15:02:17 +02:00
|
|
|
bool interrupt_thread_executing = false;
|
|
|
|
|
|
2016-04-14 01:09:41 +02:00
|
|
|
be_t<u64>* get_stack_arg(s32 i, u64 align = alignof(u64));
|
2016-07-27 23:43:22 +02:00
|
|
|
void exec_task();
|
2022-07-04 15:02:17 +02:00
|
|
|
void fast_call(u32 addr, u64 rtoc);
|
2016-08-09 16:14:41 +02:00
|
|
|
|
2021-06-26 13:15:10 +02:00
|
|
|
static std::pair<vm::addr_t, u32> stack_push(u32 size, u32 align_v);
|
2016-08-09 16:14:41 +02:00
|
|
|
static void stack_pop_verbose(u32 addr, u32 size) noexcept;
|
2013-06-30 10:46:29 +02:00
|
|
|
};
|
|
|
|
|
|
2020-03-14 18:06:58 +01:00
|
|
|
static_assert(ppu_join_status::max <= ppu_join_status{ppu_thread::id_base});
|
2020-03-03 21:39:40 +01:00
|
|
|
|
2016-04-14 01:09:41 +02:00
|
|
|
template<typename T, typename = void>
|
|
|
|
|
struct ppu_gpr_cast_impl
|
2014-11-19 15:16:30 +01:00
|
|
|
{
|
2016-04-14 01:09:41 +02:00
|
|
|
static_assert(!sizeof(T), "Invalid type for ppu_gpr_cast<>");
|
2015-01-07 17:44:47 +01:00
|
|
|
};
|
|
|
|
|
|
2016-04-14 01:09:41 +02:00
|
|
|
template<typename T>
|
|
|
|
|
struct ppu_gpr_cast_impl<T, std::enable_if_t<std::is_integral<T>::value || std::is_enum<T>::value>>
|
2015-01-07 17:44:47 +01:00
|
|
|
{
|
2016-04-14 01:09:41 +02:00
|
|
|
static_assert(sizeof(T) <= 8, "Too big integral type for ppu_gpr_cast<>()");
|
2016-08-12 18:24:29 +02:00
|
|
|
static_assert(std::is_same<std::decay_t<T>, bool>::value == false, "bool type is deprecated in ppu_gpr_cast<>(), use b8 instead");
|
2015-01-19 15:16:31 +01:00
|
|
|
|
2016-04-14 01:09:41 +02:00
|
|
|
static inline u64 to(const T& value)
|
2015-01-19 15:16:31 +01:00
|
|
|
{
|
2016-04-14 01:09:41 +02:00
|
|
|
return static_cast<u64>(value);
|
2015-01-07 17:44:47 +01:00
|
|
|
}
|
2015-01-19 15:16:31 +01:00
|
|
|
|
2016-04-14 01:09:41 +02:00
|
|
|
static inline T from(const u64 reg)
|
2015-01-19 15:16:31 +01:00
|
|
|
{
|
2016-04-14 01:09:41 +02:00
|
|
|
return static_cast<T>(reg);
|
2015-01-19 15:16:31 +01:00
|
|
|
}
|
2015-01-07 17:44:47 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<>
|
2016-04-14 01:09:41 +02:00
|
|
|
struct ppu_gpr_cast_impl<b8, void>
|
2015-01-07 17:44:47 +01:00
|
|
|
{
|
2016-04-14 01:09:41 +02:00
|
|
|
static inline u64 to(const b8& value)
|
2015-01-07 17:44:47 +01:00
|
|
|
{
|
|
|
|
|
return value;
|
|
|
|
|
}
|
2015-01-19 15:16:31 +01:00
|
|
|
|
2016-04-14 01:09:41 +02:00
|
|
|
static inline b8 from(const u64 reg)
|
2015-01-19 15:16:31 +01:00
|
|
|
{
|
2016-04-14 01:09:41 +02:00
|
|
|
return static_cast<u32>(reg) != 0;
|
2015-01-19 15:16:31 +01:00
|
|
|
}
|
2015-01-07 17:44:47 +01:00
|
|
|
};
|
|
|
|
|
|
2016-04-14 01:09:41 +02:00
|
|
|
template<typename T, typename AT>
|
|
|
|
|
struct ppu_gpr_cast_impl<vm::_ptr_base<T, AT>, void>
|
2015-01-07 17:44:47 +01:00
|
|
|
{
|
2016-04-14 01:09:41 +02:00
|
|
|
static inline u64 to(const vm::_ptr_base<T, AT>& value)
|
2015-01-07 17:44:47 +01:00
|
|
|
{
|
2016-04-14 01:09:41 +02:00
|
|
|
return ppu_gpr_cast_impl<AT>::to(value.addr());
|
2015-01-07 17:44:47 +01:00
|
|
|
}
|
2015-01-19 15:16:31 +01:00
|
|
|
|
2016-04-14 01:09:41 +02:00
|
|
|
static inline vm::_ptr_base<T, AT> from(const u64 reg)
|
2015-01-19 15:16:31 +01:00
|
|
|
{
|
2016-05-13 15:55:34 +02:00
|
|
|
return vm::cast(ppu_gpr_cast_impl<AT>::from(reg));
|
2015-01-19 15:16:31 +01:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2016-04-14 01:09:41 +02:00
|
|
|
template<typename T, typename AT>
|
|
|
|
|
struct ppu_gpr_cast_impl<vm::_ref_base<T, AT>, void>
|
2015-01-19 15:16:31 +01:00
|
|
|
{
|
2016-04-14 01:09:41 +02:00
|
|
|
static inline u64 to(const vm::_ref_base<T, AT>& value)
|
2015-01-19 15:16:31 +01:00
|
|
|
{
|
2016-04-14 01:09:41 +02:00
|
|
|
return ppu_gpr_cast_impl<AT>::to(value.addr());
|
2015-01-19 15:16:31 +01:00
|
|
|
}
|
|
|
|
|
|
2016-04-14 01:09:41 +02:00
|
|
|
static inline vm::_ref_base<T, AT> from(const u64 reg)
|
2015-01-19 15:16:31 +01:00
|
|
|
{
|
2016-05-13 15:55:34 +02:00
|
|
|
return vm::cast(ppu_gpr_cast_impl<AT>::from(reg));
|
2015-01-19 15:16:31 +01:00
|
|
|
}
|
2015-01-07 17:44:47 +01:00
|
|
|
};
|
2015-01-14 20:45:36 +01:00
|
|
|
|
2017-10-01 03:40:11 +02:00
|
|
|
template <>
|
|
|
|
|
struct ppu_gpr_cast_impl<vm::null_t, void>
|
|
|
|
|
{
|
2019-12-26 21:01:48 +01:00
|
|
|
static inline u64 to(const vm::null_t& /*value*/)
|
2017-10-01 03:40:11 +02:00
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-26 21:01:48 +01:00
|
|
|
static inline vm::null_t from(const u64 /*reg*/)
|
2017-10-01 03:40:11 +02:00
|
|
|
{
|
|
|
|
|
return vm::null;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2016-04-14 01:09:41 +02:00
|
|
|
template<typename To = u64, typename From>
|
|
|
|
|
inline To ppu_gpr_cast(const From& value)
|
2015-01-14 20:45:36 +01:00
|
|
|
{
|
2016-04-14 01:09:41 +02:00
|
|
|
return ppu_gpr_cast_impl<To>::from(ppu_gpr_cast_impl<From>::to(value));
|
2015-01-14 20:45:36 +01:00
|
|
|
}
|