2020-12-05 13:08:24 +01:00
|
|
|
#include "stdafx.h"
|
2025-04-24 12:41:04 +02:00
|
|
|
#include "rx/cpu/cell/ppu/Decoder.hpp"
|
2018-09-29 00:12:00 +02:00
|
|
|
#include "PPUInterpreter.h"
|
|
|
|
|
|
2018-09-25 22:34:45 +02:00
|
|
|
#include "Emu/Memory/vm_reservation.h"
|
2020-02-15 23:36:20 +01:00
|
|
|
#include "Emu/system_config.h"
|
2016-04-14 01:09:41 +02:00
|
|
|
#include "PPUThread.h"
|
2019-05-10 19:24:14 +02:00
|
|
|
#include "Emu/Cell/Common.h"
|
2020-12-14 12:32:04 +01:00
|
|
|
#include "Emu/Cell/PPUFunction.h"
|
2021-12-30 17:39:18 +01:00
|
|
|
#include "Emu/Cell/PPUAnalyser.h"
|
2021-03-23 20:32:50 +01:00
|
|
|
#include "Emu/Cell/timers.hpp"
|
2021-05-17 13:22:27 +02:00
|
|
|
#include "Emu/IdManager.h"
|
2016-05-13 15:55:34 +02:00
|
|
|
|
2020-05-03 08:32:10 +02:00
|
|
|
#include <bit>
|
|
|
|
|
#include <cmath>
|
2021-05-22 09:35:15 +02:00
|
|
|
#include <climits>
|
2016-04-14 01:09:41 +02:00
|
|
|
|
2025-10-05 18:28:03 +02:00
|
|
|
#include "rx/asm.hpp"
|
2020-12-13 14:34:45 +01:00
|
|
|
#include "util/v128.hpp"
|
2021-12-30 17:39:18 +01:00
|
|
|
#include "util/simd.hpp"
|
2020-12-18 10:55:54 +01:00
|
|
|
#include "util/sysinfo.hpp"
|
2025-04-08 18:46:57 +02:00
|
|
|
#include "util/JIT.h"
|
2020-11-07 23:56:35 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
#if !defined(_MSC_VER)
|
2020-02-21 13:39:40 +01:00
|
|
|
#pragma GCC diagnostic push
|
|
|
|
|
#pragma GCC diagnostic ignored "-Wold-style-cast"
|
2022-09-13 15:08:55 +02:00
|
|
|
#pragma GCC diagnostic ignored "-Wuninitialized"
|
2020-02-21 13:39:40 +01:00
|
|
|
#endif
|
|
|
|
|
|
2025-03-01 17:08:10 +01:00
|
|
|
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
|
|
|
|
|
void ppubreak(ppu_thread& ppu)
|
|
|
|
|
{
|
|
|
|
|
if (!g_breakpoint_handler.IsBreakOnBPM())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!ppu.state.test_and_set(cpu_flag::dbg_pause))
|
|
|
|
|
{
|
|
|
|
|
ppu.check_state();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define PPU_WRITE_8(addr, value) vm::write8(addr, value, &ppu);
|
|
|
|
|
#define PPU_WRITE_16(addr, value) vm::write16(addr, value, &ppu);
|
|
|
|
|
#define PPU_WRITE_32(addr, value) vm::write32(addr, value, &ppu);
|
|
|
|
|
#define PPU_WRITE_64(addr, value) vm::write64(addr, value, &ppu);
|
|
|
|
|
#else
|
|
|
|
|
#define PPU_WRITE_8(addr, value) vm::write8(addr, value);
|
|
|
|
|
#define PPU_WRITE_16(addr, value) vm::write16(addr, value);
|
|
|
|
|
#define PPU_WRITE_32(addr, value) vm::write32(addr, value);
|
|
|
|
|
#define PPU_WRITE_64(addr, value) vm::write64(addr, value);
|
|
|
|
|
#endif
|
|
|
|
|
|
2022-03-25 18:51:55 +01:00
|
|
|
extern bool is_debugger_present();
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
extern const ppu_decoder<ppu_itype> g_ppu_itype;
|
|
|
|
|
extern const ppu_decoder<ppu_iname> g_ppu_iname;
|
|
|
|
|
|
|
|
|
|
enum class ppu_exec_bit : u64
|
|
|
|
|
{
|
|
|
|
|
has_oe,
|
|
|
|
|
has_rc,
|
|
|
|
|
set_sat,
|
|
|
|
|
use_nj,
|
2022-01-15 12:30:13 +01:00
|
|
|
fix_nj,
|
2021-12-30 17:39:18 +01:00
|
|
|
set_vnan,
|
|
|
|
|
fix_vnan,
|
|
|
|
|
set_fpcc,
|
|
|
|
|
use_dfma,
|
|
|
|
|
set_cr_stats,
|
2022-06-07 11:11:47 +02:00
|
|
|
set_call_history,
|
2022-06-07 11:23:08 +02:00
|
|
|
use_feed_data,
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-10-04 23:54:46 +02:00
|
|
|
bitset_last = use_feed_data,
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
using enum ppu_exec_bit;
|
|
|
|
|
|
|
|
|
|
// Helper for combining only used subset of exec flags at compile time
|
|
|
|
|
template <ppu_exec_bit... Flags0>
|
|
|
|
|
struct ppu_exec_select
|
|
|
|
|
{
|
|
|
|
|
template <ppu_exec_bit Flag, ppu_exec_bit... Flags, typename F>
|
2025-10-04 21:19:57 +02:00
|
|
|
static ppu_intrp_func_t select(rx::EnumBitSet<ppu_exec_bit> selected, F func)
|
2021-12-30 17:39:18 +01:00
|
|
|
{
|
|
|
|
|
// Make sure there is no flag duplication, otherwise skip flag
|
2022-01-15 23:00:37 +01:00
|
|
|
if constexpr (((Flags0 != Flag) && ...))
|
2021-12-30 17:39:18 +01:00
|
|
|
{
|
|
|
|
|
// Test only relevant flags at runtime initialization (compile both variants)
|
|
|
|
|
if (selected & Flag)
|
|
|
|
|
{
|
|
|
|
|
// In this branch, selected flag is added to Flags0
|
|
|
|
|
return ppu_exec_select<Flags0..., Flag>::template select<Flags...>(selected, func);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ppu_exec_select<Flags0...>::template select<Flags...>(selected, func);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename F>
|
2025-10-04 21:19:57 +02:00
|
|
|
static ppu_intrp_func_t select(rx::EnumBitSet<ppu_exec_bit>, F func)
|
2021-12-30 17:39:18 +01:00
|
|
|
{
|
|
|
|
|
// Instantiate interpreter function with required set of flags
|
|
|
|
|
return func.template operator()<Flags0...>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <ppu_exec_bit... Flags1>
|
|
|
|
|
static auto select()
|
|
|
|
|
{
|
|
|
|
|
#ifndef __INTELLISENSE__
|
2025-10-04 21:19:57 +02:00
|
|
|
return [](rx::EnumBitSet<ppu_exec_bit> selected, auto func)
|
2021-12-30 17:39:18 +01:00
|
|
|
{
|
|
|
|
|
return ppu_exec_select::select<Flags1...>(selected, func);
|
|
|
|
|
};
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Switch between inlined interpreter invocation (exec) and builder function
|
|
|
|
|
#if defined(ARCH_X64)
|
2025-04-05 21:50:45 +02:00
|
|
|
#define RETURN(...) \
|
|
|
|
|
if constexpr (Build == 0) \
|
|
|
|
|
{ \
|
|
|
|
|
static_cast<void>(exec); \
|
2022-01-19 00:41:32 +01:00
|
|
|
static const ppu_intrp_func_t f = build_function_asm<ppu_intrp_func_t, asmjit::ppu_builder>("ppu_"s + __func__, [&](asmjit::ppu_builder& c, native_args&) { \
|
2025-04-05 21:50:45 +02:00
|
|
|
static ppu_opcode_t op{}; \
|
|
|
|
|
static ppu_abstract_t ppu; \
|
|
|
|
|
exec(__VA_ARGS__); \
|
|
|
|
|
c.ppu_ret(); \
|
|
|
|
|
return !c.fail_flag; \
|
|
|
|
|
}); \
|
|
|
|
|
if (f) \
|
|
|
|
|
return f; \
|
|
|
|
|
ppu_log.error("Can't build instruction %s", __func__); \
|
|
|
|
|
RETURN_(__VA_ARGS__); \
|
2021-12-30 17:39:18 +01:00
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
#define RETURN RETURN_
|
|
|
|
|
#endif
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
#define RETURN_(...) \
|
|
|
|
|
if constexpr (Build == 0) \
|
|
|
|
|
{ \
|
|
|
|
|
static_cast<void>(exec); \
|
|
|
|
|
if (is_debugger_present()) \
|
|
|
|
|
return +[](ppu_thread& ppu, ppu_opcode_t op, be_t<u32>* this_op, ppu_intrp_func* next_fn) { \
|
|
|
|
|
exec(__VA_ARGS__); \
|
|
|
|
|
const auto next_op = this_op + 1; \
|
|
|
|
|
const auto fn = atomic_storage<ppu_intrp_func_t>::load(next_fn->fn); \
|
|
|
|
|
ppu.cia = vm::get_addr(next_op); \
|
|
|
|
|
return fn(ppu, {*next_op}, next_op, next_fn + 1); \
|
|
|
|
|
}; \
|
|
|
|
|
return +[](ppu_thread& ppu, ppu_opcode_t op, be_t<u32>* this_op, ppu_intrp_func* next_fn) { \
|
|
|
|
|
exec(__VA_ARGS__); \
|
|
|
|
|
const auto next_op = this_op + 1; \
|
|
|
|
|
const auto fn = atomic_storage<ppu_intrp_func_t>::observe(next_fn->fn); \
|
|
|
|
|
return fn(ppu, {*next_op}, next_op, next_fn + 1); \
|
|
|
|
|
}; \
|
2021-12-30 17:39:18 +01:00
|
|
|
}
|
|
|
|
|
|
2024-08-19 21:44:32 +02:00
|
|
|
#ifdef ARCH_X64
|
2021-12-30 17:39:18 +01:00
|
|
|
static constexpr ppu_opcode_t s_op{};
|
2024-08-19 21:44:32 +02:00
|
|
|
#endif
|
2021-12-30 17:39:18 +01:00
|
|
|
|
|
|
|
|
namespace asmjit
|
|
|
|
|
{
|
|
|
|
|
#if defined(ARCH_X64)
|
|
|
|
|
struct ppu_builder : vec_builder
|
|
|
|
|
{
|
|
|
|
|
using base = vec_builder;
|
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
static constexpr x86::Gp arg_ppu = x86::rcx;
|
|
|
|
|
static constexpr x86::Gp arg_op = x86::edx;
|
|
|
|
|
static constexpr x86::Gp arg_this_op = x86::r8;
|
|
|
|
|
static constexpr x86::Gp arg_next_fn = x86::r9;
|
|
|
|
|
#else
|
|
|
|
|
static constexpr x86::Gp arg_ppu = x86::rdi;
|
|
|
|
|
static constexpr x86::Gp arg_op = x86::esi;
|
|
|
|
|
static constexpr x86::Gp arg_this_op = x86::rdx;
|
|
|
|
|
static constexpr x86::Gp arg_next_fn = x86::rcx;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
u32 xmm_count = 0;
|
|
|
|
|
u32 ppu_base = 0;
|
|
|
|
|
x86::Xmm tmp;
|
|
|
|
|
|
|
|
|
|
ppu_builder(CodeHolder* ch)
|
|
|
|
|
: base(ch)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Indexed offset to ppu.member
|
2025-04-24 12:41:04 +02:00
|
|
|
template <uint I, uint N>
|
|
|
|
|
x86::Mem ppu_mem(const bf_t<u32, I, N>&, std::size_t offset, std::size_t size, std::size_t elemSize, bool last = false)
|
2021-12-30 17:39:18 +01:00
|
|
|
{
|
|
|
|
|
// Required index shift for array indexing
|
2025-04-24 12:41:04 +02:00
|
|
|
u32 Shift = std::countr_zero(elemSize);
|
2021-12-30 17:39:18 +01:00
|
|
|
|
|
|
|
|
auto tmp_r32 = x86::eax;
|
|
|
|
|
auto reg_ppu = arg_ppu;
|
|
|
|
|
|
|
|
|
|
if (last)
|
|
|
|
|
{
|
|
|
|
|
tmp_r32 = arg_op.r32();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
base::mov(tmp_r32, arg_op);
|
|
|
|
|
|
|
|
|
|
if (offset % 16 == 0 && ppu_base != offset)
|
|
|
|
|
{
|
|
|
|
|
// Optimistically precompute offset to avoid [ppu + tmp*x + offset] addressing
|
|
|
|
|
base::lea(x86::r10, x86::qword_ptr(arg_ppu, static_cast<s32>(offset)));
|
|
|
|
|
ppu_base = offset;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ppu_base == offset)
|
|
|
|
|
{
|
|
|
|
|
reg_ppu = x86::r10;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Use max possible index shift
|
2025-04-24 12:41:04 +02:00
|
|
|
u32 X86Shift = Shift > 3 ? 3 : Shift;
|
|
|
|
|
u32 AddShift = Shift - X86Shift;
|
|
|
|
|
u32 AndMask = (1u << N) - 1;
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-24 12:41:04 +02:00
|
|
|
if (I >= AddShift)
|
2021-12-30 17:39:18 +01:00
|
|
|
{
|
2025-04-24 12:41:04 +02:00
|
|
|
if (I != AddShift)
|
2021-12-30 17:39:18 +01:00
|
|
|
base::shr(tmp_r32, I - AddShift);
|
|
|
|
|
base::and_(tmp_r32, AndMask << AddShift);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
base::and_(tmp_r32, AndMask << I);
|
|
|
|
|
base::shl(tmp_r32, I + AddShift);
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-24 12:41:04 +02:00
|
|
|
return x86::ptr(reg_ppu, tmp_r32.r64(), X86Shift, static_cast<s32>(offset - ppu_base), size);
|
2021-12-30 17:39:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Generic offset to ppu.member
|
2025-04-24 12:41:04 +02:00
|
|
|
x86::Mem ppu_mem(std::uint32_t offset, std::size_t size)
|
2021-12-30 17:39:18 +01:00
|
|
|
{
|
2025-04-24 12:41:04 +02:00
|
|
|
return x86::ptr(arg_ppu, offset, size);
|
2021-12-30 17:39:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <u32 Size = 16, uint I, uint N>
|
|
|
|
|
x86::Mem ppu_vr(const bf_t<u32, I, N>& bf, bool last = false)
|
|
|
|
|
{
|
2025-04-24 12:41:04 +02:00
|
|
|
return ppu_mem(bf, OFFSET_OF(ppu_thread, vr), Size, sizeof(ppu_thread::vr[0]), last);
|
2021-12-30 17:39:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
x86::Mem ppu_sat()
|
|
|
|
|
{
|
2025-04-24 12:41:04 +02:00
|
|
|
return ppu_mem(OFFSET_OF(ppu_thread, sat), sizeof(ppu_thread::sat));
|
2021-12-30 17:39:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ppu_ret(bool last = true)
|
|
|
|
|
{
|
2022-03-25 18:51:55 +01:00
|
|
|
// Initialize pointer to next function
|
|
|
|
|
base::mov(x86::rax, x86::qword_ptr(arg_next_fn));
|
2021-12-30 17:39:18 +01:00
|
|
|
base::add(arg_this_op, 4);
|
2022-03-25 18:51:55 +01:00
|
|
|
if (is_debugger_present())
|
2025-04-24 12:41:04 +02:00
|
|
|
base::mov(ppu_mem(OFFSET_OF(ppu_thread, cia), sizeof(ppu_thread::cia)), arg_this_op.r32());
|
2021-12-30 17:39:18 +01:00
|
|
|
base::mov(arg_op, x86::dword_ptr(arg_this_op));
|
|
|
|
|
base::bswap(arg_op);
|
|
|
|
|
base::add(arg_next_fn, 8);
|
2022-03-25 18:51:55 +01:00
|
|
|
base::jmp(x86::rax);
|
2021-12-30 17:39:18 +01:00
|
|
|
|
|
|
|
|
// Embed constants (TODO: after last return)
|
|
|
|
|
if (last)
|
|
|
|
|
base::emit_consts();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
#elif defined(ARCH_ARM64)
|
|
|
|
|
struct ppu_builder : a64::Assembler
|
|
|
|
|
{
|
|
|
|
|
};
|
|
|
|
|
#else
|
|
|
|
|
struct ppu_builder
|
|
|
|
|
{
|
|
|
|
|
};
|
|
|
|
|
#endif
|
2025-04-05 21:50:45 +02:00
|
|
|
} // namespace asmjit
|
2021-12-30 17:39:18 +01:00
|
|
|
|
|
|
|
|
struct ppu_abstract_t
|
|
|
|
|
{
|
|
|
|
|
struct abstract_vr
|
|
|
|
|
{
|
|
|
|
|
template <uint I, uint N>
|
|
|
|
|
struct lazy_vr : asmjit::mem_lazy
|
|
|
|
|
{
|
|
|
|
|
const asmjit::Operand& eval(bool is_lv)
|
|
|
|
|
{
|
|
|
|
|
if (is_lv && !this->isReg())
|
|
|
|
|
{
|
|
|
|
|
Operand::operator=(g_vc->vec_alloc());
|
2025-04-05 21:50:45 +02:00
|
|
|
#if defined(ARCH_X64)
|
2021-12-30 17:39:18 +01:00
|
|
|
g_vc->emit(asmjit::x86::Inst::kIdMovaps, *this, static_cast<asmjit::ppu_builder*>(g_vc)->ppu_vr(bf_t<u32, I, N>{}, false));
|
2025-04-05 21:50:45 +02:00
|
|
|
#endif
|
2021-12-30 17:39:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!is_lv)
|
|
|
|
|
{
|
|
|
|
|
if (this->isReg())
|
|
|
|
|
{
|
|
|
|
|
g_vc->vec_dealloc(asmjit::vec_type{this->id()});
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
#if defined(ARCH_X64)
|
2021-12-30 17:39:18 +01:00
|
|
|
Operand::operator=(static_cast<asmjit::ppu_builder*>(g_vc)->ppu_vr(bf_t<u32, I, N>{}, false));
|
2025-04-05 21:50:45 +02:00
|
|
|
#endif
|
2021-12-30 17:39:18 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
2024-08-19 21:44:32 +02:00
|
|
|
void operator=([[maybe_unused]] T&& _val) const
|
2021-12-30 17:39:18 +01:00
|
|
|
{
|
|
|
|
|
FOR_X64(store_op, kIdMovaps, kIdVmovaps, static_cast<asmjit::ppu_builder*>(g_vc)->ppu_vr(bf_t<u32, I, N>{}, true), std::forward<T>(_val));
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template <uint I, uint N>
|
|
|
|
|
lazy_vr<I, N> operator[](const bf_t<u32, I, N>&) const
|
|
|
|
|
{
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
} vr;
|
|
|
|
|
|
2022-01-17 22:08:41 +01:00
|
|
|
struct abstract_sat : asmjit::mem_type
|
2021-12-30 17:39:18 +01:00
|
|
|
{
|
2022-01-17 22:08:41 +01:00
|
|
|
abstract_sat()
|
2025-04-05 21:50:45 +02:00
|
|
|
#if defined(ARCH_X64)
|
2022-01-17 22:08:41 +01:00
|
|
|
: asmjit::mem_type(static_cast<asmjit::ppu_builder*>(g_vc)->ppu_sat())
|
2025-04-05 21:50:45 +02:00
|
|
|
#endif
|
2022-01-17 22:08:41 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename T>
|
2024-08-19 21:44:32 +02:00
|
|
|
void operator=([[maybe_unused]] T&& _val) const
|
2021-12-30 17:39:18 +01:00
|
|
|
{
|
2022-01-17 22:08:41 +01:00
|
|
|
FOR_X64(store_op, kIdMovaps, kIdVmovaps, *this, std::forward<T>(_val));
|
2021-12-30 17:39:18 +01:00
|
|
|
}
|
|
|
|
|
} sat{};
|
|
|
|
|
};
|
2020-03-24 18:07:35 +01:00
|
|
|
|
2020-09-25 16:29:25 +02:00
|
|
|
extern void do_cell_atomic_128_store(u32 addr, const void* to_write);
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
inline u64 dup32(u32 x)
|
|
|
|
|
{
|
|
|
|
|
return x | static_cast<u64>(x) << 32;
|
|
|
|
|
}
|
2016-04-14 01:09:41 +02:00
|
|
|
|
2016-07-27 23:43:22 +02:00
|
|
|
// Write values to CR field
|
|
|
|
|
inline void ppu_cr_set(ppu_thread& ppu, u32 field, bool le, bool gt, bool eq, bool so)
|
|
|
|
|
{
|
|
|
|
|
ppu.cr[field * 4 + 0] = le;
|
|
|
|
|
ppu.cr[field * 4 + 1] = gt;
|
|
|
|
|
ppu.cr[field * 4 + 2] = eq;
|
|
|
|
|
ppu.cr[field * 4 + 3] = so;
|
2017-10-05 23:24:50 +02:00
|
|
|
|
2020-02-05 08:00:08 +01:00
|
|
|
if (g_cfg.core.ppu_debug) [[unlikely]]
|
2017-10-05 23:24:50 +02:00
|
|
|
{
|
2019-11-29 23:28:06 +01:00
|
|
|
*reinterpret_cast<u32*>(vm::g_stat_addr + ppu.cia) |= *reinterpret_cast<u32*>(ppu.cr.bits + field * 4);
|
2017-10-05 23:24:50 +02:00
|
|
|
}
|
2016-07-27 23:43:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Write comparison results to CR field
|
2025-04-05 21:50:45 +02:00
|
|
|
template <typename T>
|
2016-07-27 23:43:22 +02:00
|
|
|
inline void ppu_cr_set(ppu_thread& ppu, u32 field, const T& a, const T& b)
|
|
|
|
|
{
|
2025-04-24 12:41:04 +02:00
|
|
|
ppu_cr_set(ppu, field, (a < b), (a > b), a == b, ppu.xer_so);
|
2016-07-27 23:43:22 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
// TODO
|
|
|
|
|
template <ppu_exec_bit... Flags>
|
|
|
|
|
void ppu_set_cr(ppu_thread& ppu, u32 field, bool le, bool gt, bool eq, bool so)
|
|
|
|
|
{
|
|
|
|
|
ppu.cr[field * 4 + 0] = le;
|
|
|
|
|
ppu.cr[field * 4 + 1] = gt;
|
|
|
|
|
ppu.cr[field * 4 + 2] = eq;
|
|
|
|
|
ppu.cr[field * 4 + 3] = so;
|
|
|
|
|
|
|
|
|
|
if constexpr (((Flags == set_cr_stats) || ...))
|
|
|
|
|
{
|
|
|
|
|
*reinterpret_cast<u32*>(vm::g_stat_addr + ppu.cia) |= *reinterpret_cast<u32*>(ppu.cr.bits + field * 4);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-27 23:43:22 +02:00
|
|
|
// Set XER.OV bit (overflow)
|
|
|
|
|
inline void ppu_ov_set(ppu_thread& ppu, bool bit)
|
|
|
|
|
{
|
2025-04-24 12:41:04 +02:00
|
|
|
ppu.xer_ov = bit;
|
|
|
|
|
ppu.xer_so |= bit;
|
2016-07-27 23:43:22 +02:00
|
|
|
}
|
|
|
|
|
|
2019-04-18 10:58:08 +02:00
|
|
|
// Write comparison results to FPCC field with optional CR field update
|
2021-12-30 17:39:18 +01:00
|
|
|
template <ppu_exec_bit... Flags>
|
|
|
|
|
void ppu_set_fpcc(ppu_thread& ppu, f64 a, f64 b, u64 cr_field = 1)
|
|
|
|
|
{
|
|
|
|
|
if constexpr (((Flags == set_fpcc || Flags == has_rc) || ...))
|
|
|
|
|
{
|
|
|
|
|
static_assert(std::endian::native == std::endian::little, "Not implemented");
|
|
|
|
|
|
|
|
|
|
bool fpcc[4];
|
|
|
|
|
#if defined(ARCH_X64) && !defined(_M_X64)
|
|
|
|
|
__asm__("comisd %[b], %[a]\n"
|
2025-04-05 21:50:45 +02:00
|
|
|
: "=@ccb"(fpcc[0]), "=@cca"(fpcc[1]), "=@ccz"(fpcc[2]), "=@ccp"(fpcc[3])
|
|
|
|
|
: [a] "x"(a), [b] "x"(b)
|
2021-12-30 17:39:18 +01:00
|
|
|
: "cc");
|
|
|
|
|
if (fpcc[3]) [[unlikely]]
|
|
|
|
|
{
|
|
|
|
|
fpcc[0] = fpcc[1] = fpcc[2] = false;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
const auto cmp = a <=> b;
|
|
|
|
|
fpcc[0] = cmp == std::partial_ordering::less;
|
|
|
|
|
fpcc[1] = cmp == std::partial_ordering::greater;
|
|
|
|
|
fpcc[2] = cmp == std::partial_ordering::equivalent;
|
|
|
|
|
fpcc[3] = cmp == std::partial_ordering::unordered;
|
|
|
|
|
#endif
|
2019-04-18 10:58:08 +02:00
|
|
|
|
2025-04-24 12:41:04 +02:00
|
|
|
auto data = std::bit_cast<CrField>(fpcc);
|
2019-04-18 10:58:08 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
// Write FPCC
|
|
|
|
|
ppu.fpscr.fields[4] = data;
|
2019-04-18 10:58:08 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
2019-04-18 10:58:08 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
// Previous behaviour was throwing an exception; TODO
|
|
|
|
|
ppu.cr.fields[cr_field] = data;
|
|
|
|
|
|
|
|
|
|
if (g_cfg.core.ppu_debug) [[unlikely]]
|
|
|
|
|
{
|
2025-04-24 12:41:04 +02:00
|
|
|
*reinterpret_cast<u32*>(vm::g_stat_addr + ppu.cia) |= std::bit_cast<u32>(data);
|
2021-12-30 17:39:18 +01:00
|
|
|
}
|
2019-04-18 10:58:08 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-13 21:36:00 +02:00
|
|
|
// Validate read data in case does not match reservation
|
2022-06-07 11:23:08 +02:00
|
|
|
template <typename T, ppu_exec_bit... Flags>
|
2021-12-30 17:39:18 +01:00
|
|
|
auto ppu_feed_data(ppu_thread& ppu, u64 addr)
|
2020-10-13 21:36:00 +02:00
|
|
|
{
|
|
|
|
|
static_assert(sizeof(T) <= 128, "Incompatible type-size, break down into smaller loads");
|
|
|
|
|
|
2020-12-09 16:04:52 +01:00
|
|
|
auto value = vm::_ref<T>(vm::cast(addr));
|
2020-10-13 21:36:00 +02:00
|
|
|
|
2025-03-01 17:08:10 +01:00
|
|
|
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
|
|
|
|
|
if (g_breakpoint_handler.HasBreakpoint(addr, breakpoint_types::bp_read))
|
|
|
|
|
{
|
|
|
|
|
debugbp_log.success("BPMR: breakpoint reading 0x%x at 0x%x", value, addr);
|
|
|
|
|
ppubreak(ppu);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2022-06-07 11:23:08 +02:00
|
|
|
if constexpr (!((Flags == use_feed_data) || ...))
|
|
|
|
|
{
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ppu.use_full_rdata)
|
2020-10-13 21:36:00 +02:00
|
|
|
{
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const u32 raddr = ppu.raddr;
|
|
|
|
|
|
|
|
|
|
if (addr / 128 > raddr / 128 || (addr + sizeof(T) - 1) / 128 < raddr / 128)
|
|
|
|
|
{
|
|
|
|
|
// Out of range or reservation does not exist
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sizeof(T) == 1 || addr / 128 == (addr + sizeof(T) - 1) / 128)
|
|
|
|
|
{
|
|
|
|
|
// Optimized comparison
|
|
|
|
|
if (std::memcmp(&value, &ppu.rdata[addr & 127], sizeof(T)))
|
|
|
|
|
{
|
|
|
|
|
// Reservation was lost
|
|
|
|
|
ppu.raddr = 0;
|
PPU/cellSpurs: MGS4: Fix cellSpursAddUrgentCommand race condition
cellSpursAddUrgentCommand searches in 4 slots for an empty slot to put the command at.
At first, it seems to do so unordered.
Meanwhile, on SPU side, it expects an order between all the commands because it pops them it in FIFO manner.
Not keeping track of how many commands are queued in total.
After second observation of cellSpursAddUrgentCommand, something odd comes takes places here.
Usually, reservation loops are individual and are expected to be closed without any changes of the previous loop affected by the proceeding one.
But in this case, after a single failure, the entire operayion is reset, a loop of 4 reservation operations suddenly is reset completely.
This makes one wonder if it the HW expects sometjing else here, perhaps it caches the reservation internally here?
After some adjustments to LDARX and STDCX to cache the reservation between succeeding loops, Metal Gear Solid 4 no longer freezes!
2025-03-23 05:58:35 +01:00
|
|
|
ppu.res_cached = 0;
|
2020-10-13 21:36:00 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
alignas(16) std::byte buffer[sizeof(T)];
|
|
|
|
|
std::memcpy(buffer, &value, sizeof(value)); // Put in memory explicitly (ensure the compiler won't do it beforehand)
|
|
|
|
|
|
|
|
|
|
const std::byte* src;
|
|
|
|
|
u32 size;
|
|
|
|
|
u32 offs = 0;
|
2020-11-07 23:56:35 +01:00
|
|
|
|
2020-10-13 21:36:00 +02:00
|
|
|
if (raddr / 128 == addr / 128)
|
|
|
|
|
src = &ppu.rdata[addr & 127], size = std::min<u32>(128 - (addr % 128), sizeof(T));
|
|
|
|
|
else
|
|
|
|
|
src = &ppu.rdata[0], size = (addr + u32{sizeof(T)}) % 127, offs = sizeof(T) - size;
|
|
|
|
|
|
|
|
|
|
if (std::memcmp(buffer + offs, src, size))
|
|
|
|
|
{
|
|
|
|
|
ppu.raddr = 0;
|
PPU/cellSpurs: MGS4: Fix cellSpursAddUrgentCommand race condition
cellSpursAddUrgentCommand searches in 4 slots for an empty slot to put the command at.
At first, it seems to do so unordered.
Meanwhile, on SPU side, it expects an order between all the commands because it pops them it in FIFO manner.
Not keeping track of how many commands are queued in total.
After second observation of cellSpursAddUrgentCommand, something odd comes takes places here.
Usually, reservation loops are individual and are expected to be closed without any changes of the previous loop affected by the proceeding one.
But in this case, after a single failure, the entire operayion is reset, a loop of 4 reservation operations suddenly is reset completely.
This makes one wonder if it the HW expects sometjing else here, perhaps it caches the reservation internally here?
After some adjustments to LDARX and STDCX to cache the reservation between succeeding loops, Metal Gear Solid 4 no longer freezes!
2025-03-23 05:58:35 +01:00
|
|
|
ppu.res_cached = 0;
|
2020-10-13 21:36:00 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-10 10:56:48 +02:00
|
|
|
// Push called address to custom call history for debugging
|
2022-06-07 11:11:47 +02:00
|
|
|
template <ppu_exec_bit... Flags>
|
|
|
|
|
u32 ppu_record_call(ppu_thread& ppu, u32 new_cia, ppu_opcode_t op, bool indirect = false)
|
2021-07-10 10:56:48 +02:00
|
|
|
{
|
2022-06-07 11:11:47 +02:00
|
|
|
if constexpr (!((Flags == set_call_history) || ...))
|
|
|
|
|
{
|
|
|
|
|
return new_cia;
|
|
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2021-07-10 10:56:48 +02:00
|
|
|
if (auto& history = ppu.call_history; !history.data.empty())
|
|
|
|
|
{
|
2021-07-18 16:02:34 +02:00
|
|
|
if (!op.lk)
|
|
|
|
|
{
|
|
|
|
|
if (indirect)
|
|
|
|
|
{
|
|
|
|
|
// Register LLE exported function trampolines
|
|
|
|
|
// Trampolines do not change the stack pointer, and ones to exported functions change RTOC
|
|
|
|
|
if (ppu.gpr[1] == history.last_r1 && ppu.gpr[2] != history.last_r2)
|
|
|
|
|
{
|
|
|
|
|
// Cancel condition
|
|
|
|
|
history.last_r1 = umax;
|
|
|
|
|
history.last_r2 = ppu.gpr[2];
|
|
|
|
|
|
|
|
|
|
// Register trampolie with TOC
|
|
|
|
|
history.data[history.index++ % ppu.call_history_max_size] = new_cia;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return new_cia;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-10 10:56:48 +02:00
|
|
|
history.data[history.index++ % ppu.call_history_max_size] = new_cia;
|
2021-07-18 16:02:34 +02:00
|
|
|
history.last_r1 = ppu.gpr[1];
|
|
|
|
|
history.last_r2 = ppu.gpr[2];
|
2021-07-10 10:56:48 +02:00
|
|
|
}
|
2022-06-07 11:11:47 +02:00
|
|
|
|
|
|
|
|
return new_cia;
|
2016-04-27 00:27:24 +02:00
|
|
|
}
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
template <typename T>
|
2016-04-27 00:27:24 +02:00
|
|
|
struct add_flags_result_t
|
|
|
|
|
{
|
|
|
|
|
T result;
|
|
|
|
|
bool carry;
|
|
|
|
|
|
|
|
|
|
add_flags_result_t() = default;
|
|
|
|
|
|
|
|
|
|
// Straighforward ADD with flags
|
|
|
|
|
add_flags_result_t(T a, T b)
|
2025-04-05 21:50:45 +02:00
|
|
|
: result(a + b), carry(result < a)
|
2016-04-27 00:27:24 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Straighforward ADC with flags
|
|
|
|
|
add_flags_result_t(T a, T b, bool c)
|
|
|
|
|
: add_flags_result_t(a, b)
|
|
|
|
|
{
|
|
|
|
|
add_flags_result_t r(result, c);
|
|
|
|
|
result = r.result;
|
|
|
|
|
carry |= r.carry;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static add_flags_result_t<u64> add64_flags(u64 a, u64 b)
|
|
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
return {a, b};
|
2016-04-27 00:27:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static add_flags_result_t<u64> add64_flags(u64 a, u64 b, bool c)
|
|
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
return {a, b, c};
|
2016-04-27 00:27:24 +02:00
|
|
|
}
|
|
|
|
|
|
2016-07-27 23:43:22 +02:00
|
|
|
extern void ppu_execute_syscall(ppu_thread& ppu, u64 code);
|
2016-04-14 01:09:41 +02:00
|
|
|
|
2017-02-17 20:35:57 +01:00
|
|
|
extern u32 ppu_lwarx(ppu_thread& ppu, u32 addr);
|
|
|
|
|
extern u64 ppu_ldarx(ppu_thread& ppu, u32 addr);
|
|
|
|
|
extern bool ppu_stwcx(ppu_thread& ppu, u32 addr, u32 reg_value);
|
|
|
|
|
extern bool ppu_stdcx(ppu_thread& ppu, u32 addr, u64 reg_value);
|
2020-05-15 17:57:48 +02:00
|
|
|
extern void ppu_trap(ppu_thread& ppu, u64 addr);
|
2018-02-09 15:49:37 +01:00
|
|
|
|
2020-05-14 14:21:15 +02:00
|
|
|
// NaNs production precedence: NaN from Va, Vb, Vc
|
|
|
|
|
// and lastly the result of the operation in case none of the operands is a NaN
|
|
|
|
|
// Signaling NaNs are 'quieted' (MSB of fraction is set) with other bits of data remain the same
|
2021-12-30 17:39:18 +01:00
|
|
|
inline v128 ppu_select_vnan(v128 a)
|
2020-05-14 14:21:15 +02:00
|
|
|
{
|
|
|
|
|
return a;
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
inline v128 ppu_select_vnan(v128 a, v128 b)
|
2020-05-03 08:32:10 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
return gv_selectfs(gv_eqfs(a, a), b, a | gv_bcst32(0x7fc00000u));
|
2020-05-14 14:21:15 +02:00
|
|
|
}
|
|
|
|
|
|
2025-04-24 12:41:04 +02:00
|
|
|
inline v128 ppu_select_vnan(v128 a, v128 b, rx::Vector128 auto... args)
|
2020-05-14 14:21:15 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
return ppu_select_vnan(a, ppu_select_vnan(b, args...));
|
2020-05-14 14:21:15 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
// Flush denormals to zero if NJ is 1
|
2022-01-15 12:30:13 +01:00
|
|
|
template <bool Result = false, ppu_exec_bit... Flags>
|
2021-12-30 17:39:18 +01:00
|
|
|
inline v128 ppu_flush_denormal(const v128& mask, const v128& a)
|
2020-05-14 14:21:15 +02:00
|
|
|
{
|
2022-01-15 12:30:13 +01:00
|
|
|
if constexpr (((Flags == use_nj) || ...) || (Result && ((Flags == fix_nj) || ...)))
|
2021-12-30 17:39:18 +01:00
|
|
|
{
|
|
|
|
|
return gv_andn(gv_shr32(gv_eq32(mask & a, gv_bcst32(0)), 1), a);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return a;
|
|
|
|
|
}
|
2020-05-03 08:32:10 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
inline v128 ppu_fix_vnan(v128 r)
|
2020-05-03 08:32:10 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
return gv_selectfs(gv_eqfs(r, r), r, gv_bcst32(0x7fc00000u));
|
2020-05-03 08:32:10 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <ppu_exec_bit... Flags>
|
2025-04-24 12:41:04 +02:00
|
|
|
inline v128 ppu_set_vnan(v128 r, rx::Vector128 auto... args)
|
2020-05-03 08:32:10 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == set_vnan) || ...) && sizeof...(args) > 0)
|
|
|
|
|
{
|
|
|
|
|
// Full propagation
|
|
|
|
|
return ppu_select_vnan(args..., ppu_fix_vnan(r));
|
|
|
|
|
}
|
|
|
|
|
else if constexpr (((Flags == fix_vnan) || ...))
|
|
|
|
|
{
|
|
|
|
|
// Only fix the result
|
|
|
|
|
return ppu_fix_vnan(r);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Return as is
|
|
|
|
|
return r;
|
|
|
|
|
}
|
2020-05-03 08:32:10 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto MFVSCR()
|
2020-07-25 08:41:41 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_sat>();
|
2020-07-25 08:41:41 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& sat, auto&& nj)
|
|
|
|
|
{
|
|
|
|
|
u32 sat_bit = 0;
|
|
|
|
|
if constexpr (((Flags == set_sat) || ...))
|
|
|
|
|
sat_bit = !gv_testz(sat); //!!sat._u;
|
|
|
|
|
d._u64[0] = 0;
|
|
|
|
|
d._u64[1] = u64(sat_bit | (u32{nj} << 16)) << 32;
|
|
|
|
|
};
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu.vr[op.vd], ppu.sat, ppu.nj);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto MTVSCR()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-01-15 12:30:13 +01:00
|
|
|
return ppu_exec_select<Flags...>::template select<set_sat, use_nj, fix_nj>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& sat, auto&& nj, auto&& jm_mask, auto&& b)
|
|
|
|
|
{
|
|
|
|
|
const u32 vscr = b._u32[3];
|
|
|
|
|
if constexpr (((Flags == set_sat) || ...))
|
|
|
|
|
sat._u = vscr & 1;
|
2022-01-15 12:30:13 +01:00
|
|
|
if constexpr (((Flags == use_nj || Flags == fix_nj) || ...))
|
2021-12-30 17:39:18 +01:00
|
|
|
jm_mask = (vscr & 0x10000) ? 0x7f80'0000 : 0x7fff'ffff;
|
|
|
|
|
nj = (vscr & 0x10000) != 0;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.sat, ppu.nj, ppu.jm_mask, ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VADDCUW()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
|
|
|
|
// ~a is how much can be added to a without carry
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_sub32(gv_geu32(gv_not32(std::move(a)), std::move(b)), gv_bcst32(-1));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VADDFP()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-01-15 12:30:13 +01:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_nj, fix_nj, set_vnan, fix_vnan>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& a_, auto&& b_, auto&& jm_mask)
|
|
|
|
|
{
|
2025-04-24 12:41:04 +02:00
|
|
|
auto m = gv_bcst32(jm_mask);
|
2022-01-16 05:47:42 +01:00
|
|
|
auto a = ppu_flush_denormal<false, Flags...>(m, std::move(a_));
|
|
|
|
|
auto b = ppu_flush_denormal<false, Flags...>(m, std::move(b_));
|
|
|
|
|
d = ppu_flush_denormal<true, Flags...>(std::move(m), ppu_set_vnan<Flags...>(gv_addfs(a, b), a, b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.jm_mask);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VADDSBS()
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_sat>();
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& sat)
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == set_sat) || ...))
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
auto r = gv_adds_s8(a, b);
|
2022-01-16 05:47:42 +01:00
|
|
|
sat = gv_or32(gv_xor32(gv_add8(std::move(a), std::move(b)), r), std::move(sat));
|
|
|
|
|
d = std::move(r);
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
d = gv_adds_s8(std::move(a), std::move(b));
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.sat);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VADDSHS()
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_sat>();
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& sat)
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == set_sat) || ...))
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
auto r = gv_adds_s16(a, b);
|
2022-01-16 05:47:42 +01:00
|
|
|
sat = gv_or32(gv_xor32(gv_add16(std::move(a), std::move(b)), r), std::move(sat));
|
|
|
|
|
d = std::move(r);
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
d = gv_adds_s16(std::move(a), std::move(b));
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.sat);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VADDSWS()
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_sat>();
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& sat)
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == set_sat) || ...))
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
auto r = gv_adds_s32(a, b);
|
2022-01-16 05:47:42 +01:00
|
|
|
sat = gv_or32(gv_xor32(gv_add32(std::move(a), std::move(b)), r), std::move(sat));
|
|
|
|
|
d = std::move(r);
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
d = gv_adds_s32(std::move(a), std::move(b));
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.sat);
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VADDUBM()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
|
|
|
|
d = gv_add8(std::move(a), std::move(b));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VADDUBS()
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_sat>();
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& sat)
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == set_sat) || ...))
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
auto r = gv_addus_u8(a, b);
|
2022-01-16 05:47:42 +01:00
|
|
|
sat = gv_or32(gv_xor32(gv_add8(std::move(a), std::move(b)), r), std::move(sat));
|
|
|
|
|
d = std::move(r);
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
d = gv_addus_u8(std::move(a), std::move(b));
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.sat);
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VADDUHM()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
|
|
|
|
d = gv_add16(std::move(a), std::move(b));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
|
|
|
|
}
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VADDUHS()
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_sat>();
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& sat)
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == set_sat) || ...))
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
auto r = gv_addus_u16(a, b);
|
2022-01-16 05:47:42 +01:00
|
|
|
sat = gv_or32(gv_xor32(gv_add16(std::move(a), std::move(b)), r), std::move(sat));
|
|
|
|
|
d = std::move(r);
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
d = gv_addus_u16(std::move(a), std::move(b));
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.sat);
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VADDUWM()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
|
|
|
|
d = gv_add32(std::move(a), std::move(b));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VADDUWS()
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_sat>();
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& sat)
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == set_sat) || ...))
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
auto r = gv_addus_u32(a, b);
|
2022-01-16 05:47:42 +01:00
|
|
|
sat = gv_or32(gv_xor32(gv_add32(std::move(a), std::move(b)), r), std::move(sat));
|
|
|
|
|
d = std::move(r);
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
d = gv_addus_u32(std::move(a), std::move(b));
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
RETURN(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.sat);
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VAND()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
|
|
|
|
d = gv_andfs(std::move(a), std::move(b));
|
|
|
|
|
};
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VANDC()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
|
|
|
|
d = gv_andnfs(std::move(b), std::move(a));
|
|
|
|
|
};
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VAVGSB()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_avgs8(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VAVGSH()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_avgs16(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VAVGSW()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_avgs32(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VAVGUB()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_avgu8(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VAVGUH()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_avgu16(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VAVGUW()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_avgu32(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VCFSX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& b, u32 i)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_subus_u16(gv_cvts32_tofs(std::move(b)), gv_bcst32(i));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.vb], op.vuimm << 23);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VCFUX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& b, u32 i)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_subus_u16(gv_cvtu32_tofs(std::move(b)), gv_bcst32(i));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.vb], op.vuimm << 23);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VCMPBFP()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](ppu_thread& ppu, auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
auto sign = gv_bcstfs(-0.);
|
|
|
|
|
auto cmp1 = gv_nlefs(a, b);
|
|
|
|
|
auto cmp2 = gv_ngefs(a, b ^ sign);
|
|
|
|
|
auto r = (std::move(cmp1) & sign) | gv_shr32(std::move(cmp2) & sign, 1);
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == has_oe) || ...))
|
|
|
|
|
ppu_cr_set(ppu, 6, false, false, gv_testz(r), false);
|
2022-01-16 05:47:42 +01:00
|
|
|
d = std::move(r);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu, ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VCMPEQFP()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](ppu_thread& ppu, auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
auto r = gv_eqfs(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == has_oe) || ...))
|
|
|
|
|
ppu_cr_set(ppu, 6, gv_testall1(r), false, gv_testall0(r), false);
|
|
|
|
|
d = r;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu, ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VCMPEQUB()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](ppu_thread& ppu, auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
auto r = gv_eq8(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == has_oe) || ...))
|
|
|
|
|
ppu_cr_set(ppu, 6, gv_testall1(r), false, gv_testall0(r), false);
|
|
|
|
|
d = r;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu, ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VCMPEQUH()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](ppu_thread& ppu, auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
auto r = gv_eq16(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == has_oe) || ...))
|
|
|
|
|
ppu_cr_set(ppu, 6, gv_testall1(r), false, gv_testall0(r), false);
|
|
|
|
|
d = r;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu, ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VCMPEQUW()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](ppu_thread& ppu, auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
auto r = gv_eq32(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == has_oe) || ...))
|
|
|
|
|
ppu_cr_set(ppu, 6, gv_testall1(r), false, gv_testall0(r), false);
|
|
|
|
|
d = r;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu, ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VCMPGEFP()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](ppu_thread& ppu, auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
auto r = gv_gefs(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == has_oe) || ...))
|
|
|
|
|
ppu_cr_set(ppu, 6, gv_testall1(r), false, gv_testall0(r), false);
|
|
|
|
|
d = r;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu, ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VCMPGTFP()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](ppu_thread& ppu, auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
auto r = gv_gtfs(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == has_oe) || ...))
|
|
|
|
|
ppu_cr_set(ppu, 6, gv_testall1(r), false, gv_testall0(r), false);
|
|
|
|
|
d = r;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu, ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VCMPGTSB()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](ppu_thread& ppu, auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
auto r = gv_gts8(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == has_oe) || ...))
|
|
|
|
|
ppu_cr_set(ppu, 6, gv_testall1(r), false, gv_testall0(r), false);
|
|
|
|
|
d = r;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu, ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VCMPGTSH()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](ppu_thread& ppu, auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
auto r = gv_gts16(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == has_oe) || ...))
|
|
|
|
|
ppu_cr_set(ppu, 6, gv_testall1(r), false, gv_testall0(r), false);
|
|
|
|
|
d = r;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu, ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VCMPGTSW()
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](ppu_thread& ppu, auto&& d, auto&& a, auto&& b)
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
auto r = gv_gts32(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == has_oe) || ...))
|
|
|
|
|
ppu_cr_set(ppu, 6, gv_testall1(r), false, gv_testall0(r), false);
|
|
|
|
|
d = r;
|
|
|
|
|
};
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu, ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VCMPGTUB()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](ppu_thread& ppu, auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
auto r = gv_gtu8(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == has_oe) || ...))
|
|
|
|
|
ppu_cr_set(ppu, 6, gv_testall1(r), false, gv_testall0(r), false);
|
|
|
|
|
d = r;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu, ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VCMPGTUH()
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](ppu_thread& ppu, auto&& d, auto&& a, auto&& b)
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
auto r = gv_gtu16(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == has_oe) || ...))
|
|
|
|
|
ppu_cr_set(ppu, 6, gv_testall1(r), false, gv_testall0(r), false);
|
|
|
|
|
d = r;
|
|
|
|
|
};
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu, ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VCMPGTUW()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](ppu_thread& ppu, auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
auto r = gv_gtu32(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == has_oe) || ...))
|
|
|
|
|
ppu_cr_set(ppu, 6, gv_testall1(r), false, gv_testall0(r), false);
|
|
|
|
|
d = r;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu, ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VCTSXS()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<fix_vnan, set_sat>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& b, auto&& sat, u32 i)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
auto r = gv_mulfs(b, gv_bcst32(i));
|
|
|
|
|
auto l = gv_ltfs(r, gv_bcstfs(-2147483648.));
|
|
|
|
|
auto h = gv_gefs(r, gv_bcstfs(2147483648.));
|
2021-12-30 17:39:18 +01:00
|
|
|
#if !defined(ARCH_X64) && !defined(ARCH_ARM64)
|
2022-01-16 05:47:42 +01:00
|
|
|
r = gv_selectfs(l, gv_bcstfs(-2147483648.), std::move(r));
|
2021-12-30 17:39:18 +01:00
|
|
|
#endif
|
2022-01-16 05:47:42 +01:00
|
|
|
r = gv_cvtfs_tos32(std::move(r));
|
2021-12-30 17:39:18 +01:00
|
|
|
#if !defined(ARCH_ARM64)
|
2022-01-16 05:47:42 +01:00
|
|
|
r = gv_select32(h, gv_bcst32(0x7fffffff), std::move(r));
|
2021-12-30 17:39:18 +01:00
|
|
|
#endif
|
|
|
|
|
if constexpr (((Flags == fix_vnan) || ...))
|
2022-01-16 05:47:42 +01:00
|
|
|
r = gv_and32(std::move(r), gv_eqfs(b, b));
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == set_sat) || ...))
|
2022-01-16 05:47:42 +01:00
|
|
|
sat = gv_or32(gv_or32(std::move(l), std::move(h)), std::move(sat));
|
|
|
|
|
d = std::move(r);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.vb], ppu.sat, (op.vuimm + 127) << 23);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VCTUXS()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<fix_vnan, set_sat>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& b, auto&& sat, u32 i)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
auto r = gv_mulfs(b, gv_bcst32(i));
|
|
|
|
|
auto l = gv_ltfs(r, gv_bcstfs(0.));
|
|
|
|
|
auto h = gv_gefs(r, gv_bcstfs(4294967296.));
|
|
|
|
|
r = gv_cvtfs_tou32(std::move(r));
|
2021-12-30 17:39:18 +01:00
|
|
|
#if !defined(ARCH_ARM64)
|
2022-01-16 05:47:42 +01:00
|
|
|
r = gv_andn32(l, std::move(r)); // saturate to zero
|
2021-12-30 17:39:18 +01:00
|
|
|
#endif
|
|
|
|
|
#if !defined(__AVX512VL__) && !defined(ARCH_ARM64)
|
2022-01-16 05:47:42 +01:00
|
|
|
r = gv_or32(std::move(r), h); // saturate to 0xffffffff
|
2021-12-30 17:39:18 +01:00
|
|
|
#endif
|
|
|
|
|
if constexpr (((Flags == fix_vnan) || ...))
|
2022-01-16 05:47:42 +01:00
|
|
|
r = gv_and32(std::move(r), gv_eqfs(b, b));
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == set_sat) || ...))
|
2022-01-16 05:47:42 +01:00
|
|
|
sat = gv_or32(gv_or32(std::move(l), std::move(h)), std::move(sat));
|
|
|
|
|
d = std::move(r);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.vb], ppu.sat, (op.vuimm + 127) << 23);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VEXPTEFP()
|
2019-09-14 11:00:05 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<fix_vnan>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& b)
|
|
|
|
|
{
|
|
|
|
|
// for (u32 i = 0; i < 4; i++) d._f[i] = std::exp2f(b._f[i]);
|
2022-01-16 05:47:42 +01:00
|
|
|
d = ppu_set_vnan<Flags...>(gv_exp2_approxfs(std::move(b)));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.vb]);
|
2019-09-14 11:00:05 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VLOGEFP()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<fix_vnan>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& b)
|
|
|
|
|
{
|
|
|
|
|
// for (u32 i = 0; i < 4; i++) d._f[i] = std::log2f(b._f[i]);
|
2022-01-16 05:47:42 +01:00
|
|
|
d = ppu_set_vnan<Flags...>(gv_log2_approxfs(std::move(b)));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMADDFP()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-01-15 12:30:13 +01:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_nj, fix_nj, set_vnan, fix_vnan>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& a_, auto&& b_, auto&& c_, auto&& jm_mask)
|
|
|
|
|
{
|
2025-04-24 12:41:04 +02:00
|
|
|
auto m = gv_bcst32(jm_mask);
|
2022-01-16 05:47:42 +01:00
|
|
|
auto a = ppu_flush_denormal<false, Flags...>(m, std::move(a_));
|
|
|
|
|
auto b = ppu_flush_denormal<false, Flags...>(m, std::move(b_));
|
|
|
|
|
auto c = ppu_flush_denormal<false, Flags...>(m, std::move(c_));
|
|
|
|
|
d = ppu_flush_denormal<true, Flags...>(std::move(m), ppu_set_vnan<Flags...>(gv_fmafs(a, c, b)));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.vr[op.vc], ppu.jm_mask);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMAXFP()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-01-15 12:30:13 +01:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_nj, fix_nj, set_vnan, fix_vnan>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& jm_mask)
|
|
|
|
|
{
|
2025-04-24 12:41:04 +02:00
|
|
|
d = ppu_flush_denormal<true, Flags...>(gv_bcst32(jm_mask), ppu_set_vnan<Flags...>(gv_maxfs(a, b), a, b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.jm_mask);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMAXSB()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_maxs8(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMAXSH()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_maxs16(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMAXSW()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_maxs32(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMAXUB()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_maxu8(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMAXUH()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_maxu16(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMAXUW()
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_maxu32(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMHADDSHS()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_sat>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& c, auto&& sat)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
auto m = gv_muls_hds16(a, b);
|
|
|
|
|
auto f = gv_gts16(gv_bcst16(0), c);
|
|
|
|
|
auto x = gv_eq16(gv_maxs16(std::move(a), std::move(b)), gv_bcst16(0x8000));
|
|
|
|
|
auto r = gv_sub16(gv_adds_s16(m, c), gv_and32(x, f));
|
|
|
|
|
auto s = gv_add16(std::move(m), std::move(c));
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == set_sat) || ...))
|
2022-01-16 05:47:42 +01:00
|
|
|
sat = gv_or32(gv_or32(gv_andn32(std::move(f), x), gv_andn32(x, gv_xor32(std::move(s), r))), sat);
|
|
|
|
|
d = std::move(r);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.vr[op.vc], ppu.sat);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMHRADDSHS()
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_sat>();
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& c, auto&& sat)
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags != set_sat) && ...))
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_rmuladds_hds16(std::move(a), std::move(b), std::move(c));
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
auto m = gv_rmuls_hds16(a, b);
|
|
|
|
|
auto f = gv_gts16(gv_bcst16(0), c);
|
|
|
|
|
auto x = gv_eq16(gv_maxs16(std::move(a), std::move(b)), gv_bcst16(0x8000));
|
|
|
|
|
auto r = gv_sub16(gv_adds_s16(m, c), gv_and32(x, f));
|
|
|
|
|
auto s = gv_add16(std::move(m), std::move(c));
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == set_sat) || ...))
|
2022-01-16 05:47:42 +01:00
|
|
|
sat = gv_or32(gv_or32(gv_andn32(std::move(f), x), gv_andn32(x, gv_xor32(std::move(s), r))), sat);
|
|
|
|
|
d = std::move(r);
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.vr[op.vc], ppu.sat);
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMINFP()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-01-15 12:30:13 +01:00
|
|
|
return ppu_exec_select<Flags...>::template select<fix_nj, set_vnan, fix_vnan>();
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& jm_mask)
|
|
|
|
|
{
|
2025-04-24 12:41:04 +02:00
|
|
|
d = ppu_flush_denormal<true, Flags...>(gv_bcst32(jm_mask), ppu_set_vnan<Flags...>(gv_minfs(a, b), a, b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.jm_mask);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMINSB()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_mins8(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMINSH()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_mins16(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMINSW()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_mins32(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMINUB()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_minu8(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMINUH()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_minu16(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMINUW()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_minu32(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMLADDUHM()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& c)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_muladd16(std::move(a), std::move(b), std::move(c));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.vr[op.vc]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMRGHB()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
2016-04-14 01:09:41 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_unpackhi8(std::move(b), std::move(a));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
|
|
|
|
}
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMRGHH()
|
|
|
|
|
{
|
|
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_unpackhi16(std::move(b), std::move(a));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMRGHW()
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_unpackhi32(std::move(b), std::move(a));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
|
|
|
|
}
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMRGLB()
|
|
|
|
|
{
|
|
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_unpacklo8(std::move(b), std::move(a));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMRGLH()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_unpacklo16(std::move(b), std::move(a));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMRGLW()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_unpacklo32(std::move(b), std::move(a));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMSUMMBM()
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& c)
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_dotu8s8x4(std::move(b), std::move(a), std::move(c));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.vr[op.vc]);
|
|
|
|
|
}
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMSUMSHM()
|
|
|
|
|
{
|
|
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& c)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_dots16x2(std::move(a), std::move(b), std::move(c));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.vr[op.vc]);
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMSUMSHS()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_sat>();
|
2016-04-14 01:09:41 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& c, auto&& sat)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2022-01-16 19:00:22 +01:00
|
|
|
auto r = gv_dots_s16x2(a, b, c);
|
2022-01-16 05:47:42 +01:00
|
|
|
auto s = gv_dots16x2(std::move(a), std::move(b), std::move(c));
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == set_sat) || ...))
|
2022-01-16 05:47:42 +01:00
|
|
|
sat = gv_or32(gv_xor32(std::move(s), r), std::move(sat));
|
|
|
|
|
d = std::move(r);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.vr[op.vc], ppu.sat);
|
|
|
|
|
}
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMSUMUBM()
|
|
|
|
|
{
|
|
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& c)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_dotu8x4(std::move(a), std::move(b), std::move(c));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.vr[op.vc]);
|
|
|
|
|
}
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMSUMUHM()
|
|
|
|
|
{
|
|
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& c)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_add32(std::move(c), gv_dotu16x2(std::move(a), std::move(b)));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.vr[op.vc]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMSUMUHS()
|
|
|
|
|
{
|
|
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_sat>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& c, auto&& sat)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
auto m1 = gv_mul_even_u16(a, b);
|
|
|
|
|
auto m2 = gv_mul_odds_u16(std::move(a), std::move(b));
|
|
|
|
|
auto s1 = gv_add32(m1, m2);
|
|
|
|
|
auto x1 = gv_gtu32(m1, s1);
|
|
|
|
|
auto s2 = gv_or32(gv_add32(s1, std::move(c)), x1);
|
|
|
|
|
auto x2 = gv_gtu32(std::move(s1), s2);
|
|
|
|
|
if constexpr (((Flags == set_sat) || ...))
|
|
|
|
|
sat = gv_or32(gv_or32(std::move(x1), x2), std::move(sat));
|
|
|
|
|
d = gv_or32(std::move(s2), std::move(x2));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.vr[op.vc], ppu.sat);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMULESB()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_mul16(gv_sar16(std::move(a), 8), gv_sar16(std::move(b), 8));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMULESH()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-16 05:47:42 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
|
|
|
|
d = gv_mul_odds_s16(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-16 05:47:42 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMULEUB()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-16 05:47:42 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
|
|
|
|
d = gv_mul16(gv_shr16(std::move(a), 8), gv_shr16(std::move(b), 8));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-16 05:47:42 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMULEUH()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-16 05:47:42 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
|
|
|
|
d = gv_mul_odds_u16(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-16 05:47:42 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMULOSB()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-16 05:47:42 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
|
|
|
|
d = gv_mul16(gv_sar16(gv_shl16(std::move(a), 8), 8), gv_sar16(gv_shl16(std::move(b), 8), 8));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-16 05:47:42 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMULOSH()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-16 05:47:42 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
|
|
|
|
d = gv_mul_even_s16(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-16 05:47:42 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMULOUB()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-16 05:47:42 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
|
|
|
|
auto mask = gv_bcst16(0x00ff);
|
|
|
|
|
d = gv_mul16(gv_and32(std::move(a), mask), gv_and32(std::move(b), mask));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-16 05:47:42 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VMULOUH()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-16 05:47:42 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
|
|
|
|
d = gv_mul_even_u16(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-16 05:47:42 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VNMSUBFP()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-01-15 12:30:13 +01:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_nj, fix_nj, set_vnan, fix_vnan>();
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2022-01-16 05:47:42 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a_, auto&& b_, auto&& c_, auto&& jm_mask)
|
|
|
|
|
{
|
|
|
|
|
// An odd case with (FLT_MIN, FLT_MIN, FLT_MIN) produces FLT_MIN instead of 0
|
|
|
|
|
auto s = gv_bcstfs(-0.0f);
|
2025-04-24 12:41:04 +02:00
|
|
|
auto m = gv_bcst32(jm_mask);
|
2022-01-16 05:47:42 +01:00
|
|
|
auto a = ppu_flush_denormal<false, Flags...>(m, std::move(a_));
|
|
|
|
|
auto b = ppu_flush_denormal<false, Flags...>(m, std::move(b_));
|
|
|
|
|
auto c = ppu_flush_denormal<false, Flags...>(m, std::move(c_));
|
|
|
|
|
auto r = gv_xorfs(std::move(s), gv_fmafs(std::move(a), std::move(c), gv_xorfs(std::move(b), s)));
|
|
|
|
|
d = ppu_flush_denormal<true, Flags...>(std::move(m), ppu_set_vnan<Flags...>(std::move(r)));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-16 05:47:42 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.vr[op.vc], ppu.jm_mask);
|
2020-06-07 21:43:22 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VNOR()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-16 05:47:42 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
|
|
|
|
d = gv_notfs(gv_orfs(std::move(a), std::move(b)));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-16 05:47:42 +01:00
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
RETURN(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VOR()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-16 05:47:42 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
|
|
|
|
d = gv_orfs(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-16 05:47:42 +01:00
|
|
|
|
|
|
|
|
RETURN(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VPERM()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
#if defined(ARCH_X64)
|
2022-01-16 05:47:42 +01:00
|
|
|
if constexpr (Build == 0)
|
|
|
|
|
{
|
2022-01-19 00:41:32 +01:00
|
|
|
static const ppu_intrp_func_t f = build_function_asm<ppu_intrp_func_t, asmjit::ppu_builder>("ppu_VPERM", [&](asmjit::ppu_builder& c, native_args&)
|
2025-04-05 21:50:45 +02:00
|
|
|
{
|
|
|
|
|
const auto [v0, v1, v2, v3] = c.vec_alloc<4>();
|
|
|
|
|
c.movdqa(v0, c.ppu_vr(s_op.vc));
|
|
|
|
|
c.pandn(v0, c.get_const(v128::from8p(0x1f)));
|
|
|
|
|
c.movdqa(v1, v0);
|
|
|
|
|
c.pcmpgtb(v1, c.get_const(v128::from8p(0xf)));
|
|
|
|
|
c.movdqa(v2, c.ppu_vr(s_op.va));
|
|
|
|
|
c.movdqa(v3, c.ppu_vr(s_op.vb));
|
|
|
|
|
c.pshufb(v2, v0);
|
|
|
|
|
c.pshufb(v3, v0);
|
|
|
|
|
c.pand(v2, v1);
|
|
|
|
|
c.pandn(v1, v3);
|
|
|
|
|
c.por(v1, v2);
|
|
|
|
|
c.movdqa(c.ppu_vr(s_op.vd), v1);
|
|
|
|
|
c.ppu_ret();
|
|
|
|
|
});
|
2022-01-16 05:47:42 +01:00
|
|
|
|
|
|
|
|
if (utils::has_ssse3())
|
|
|
|
|
{
|
|
|
|
|
return f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& c)
|
|
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
#if defined(ARCH_ARM64)
|
2022-01-16 05:47:42 +01:00
|
|
|
uint8x16x2_t ab;
|
|
|
|
|
ab.val[0] = b;
|
|
|
|
|
ab.val[1] = a;
|
|
|
|
|
d = vqtbl2q_u8(ab, vbicq_u8(vdupq_n_u8(0x1f), c));
|
2025-04-05 21:50:45 +02:00
|
|
|
#else
|
2022-01-16 05:47:42 +01:00
|
|
|
u8 ab[32];
|
|
|
|
|
std::memcpy(ab + 0, &b, 16);
|
|
|
|
|
std::memcpy(ab + 16, &a, 16);
|
|
|
|
|
|
|
|
|
|
for (u32 i = 0; i < 16; i++)
|
|
|
|
|
{
|
|
|
|
|
d._u8[i] = ab[~c._u8[i] & 0x1f];
|
|
|
|
|
}
|
2025-04-05 21:50:45 +02:00
|
|
|
#endif
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-16 05:47:42 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.vr[op.vc]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VPKPX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-16 19:00:22 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
|
|
|
|
auto a1 = gv_sar32(gv_shl32(a, 7), 7 + 9);
|
|
|
|
|
auto b1 = gv_sar32(gv_shl32(b, 7), 7 + 9);
|
|
|
|
|
auto a2 = gv_sar32(gv_shl32(a, 16), 16 + 3);
|
|
|
|
|
auto b2 = gv_sar32(gv_shl32(b, 16), 16 + 3);
|
|
|
|
|
auto p1 = gv_packss_s32(b1, a1);
|
|
|
|
|
auto p2 = gv_packss_s32(b2, a2);
|
|
|
|
|
d = gv_or32(gv_or32(gv_and32(p1, gv_bcst16(0xfc00)), gv_shl16(gv_and32(p1, gv_bcst16(0x7c)), 3)), gv_and32(p2, gv_bcst16(0x1f)));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-16 19:00:22 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VPKSHSS()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_sat>();
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2022-01-16 19:00:22 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& sat)
|
|
|
|
|
{
|
|
|
|
|
if constexpr (((Flags == set_sat) || ...))
|
|
|
|
|
sat = gv_or32(gv_shr16(gv_add16(a, gv_bcst16(0x80)) | gv_add16(b, gv_bcst16(0x80)), 8), std::move(sat));
|
|
|
|
|
d = gv_packss_s16(std::move(b), std::move(a));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-16 19:00:22 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.sat);
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VPKSHUS()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_sat>();
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2022-01-16 19:00:22 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& sat)
|
|
|
|
|
{
|
|
|
|
|
if constexpr (((Flags == set_sat) || ...))
|
|
|
|
|
sat = gv_or32(gv_shr16(a | b, 8), std::move(sat));
|
|
|
|
|
d = gv_packus_s16(std::move(b), std::move(a));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-16 19:00:22 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.sat);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VPKSWSS()
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_sat>();
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2022-01-16 19:00:22 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& sat)
|
|
|
|
|
{
|
|
|
|
|
if constexpr (((Flags == set_sat) || ...))
|
|
|
|
|
sat = gv_or32(gv_shr32(gv_add32(a, gv_bcst32(0x8000)) | gv_add32(b, gv_bcst32(0x8000)), 16), std::move(sat));
|
|
|
|
|
d = gv_packss_s32(std::move(b), std::move(a));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-16 19:00:22 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.sat);
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VPKSWUS()
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_sat>();
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2022-01-16 19:00:22 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& sat)
|
|
|
|
|
{
|
|
|
|
|
if constexpr (((Flags == set_sat) || ...))
|
|
|
|
|
sat = gv_or32(gv_shr32(a | b, 16), std::move(sat));
|
|
|
|
|
d = gv_packus_s32(std::move(b), std::move(a));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-16 19:00:22 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.sat);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VPKUHUM()
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2022-01-16 19:00:22 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
|
|
|
|
d = gv_packtu16(std::move(b), std::move(a));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-16 19:00:22 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VPKUHUS()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_sat>();
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2022-01-16 19:00:22 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& sat)
|
|
|
|
|
{
|
|
|
|
|
if constexpr (((Flags == set_sat) || ...))
|
|
|
|
|
sat = gv_or32(gv_shr16(a | b, 8), std::move(sat));
|
|
|
|
|
d = gv_packus_u16(std::move(b), std::move(a));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-16 19:00:22 +01:00
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.sat);
|
2021-12-30 17:39:18 +01:00
|
|
|
}
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VPKUWUM()
|
|
|
|
|
{
|
|
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2022-01-16 19:00:22 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
|
|
|
|
d = gv_packtu32(std::move(b), std::move(a));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-16 19:00:22 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2021-12-30 17:39:18 +01:00
|
|
|
}
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VPKUWUS()
|
|
|
|
|
{
|
|
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_sat>();
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2022-01-16 19:00:22 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& sat)
|
|
|
|
|
{
|
|
|
|
|
if constexpr (((Flags == set_sat) || ...))
|
|
|
|
|
sat = gv_or32(gv_shr32(a | b, 16), std::move(sat));
|
|
|
|
|
d = gv_packus_u32(std::move(b), std::move(a));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-16 19:00:22 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.sat);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VREFP()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-01-15 12:30:13 +01:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_nj, fix_nj, set_vnan, fix_vnan>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2022-01-17 09:32:44 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& b_, auto&& jm_mask)
|
|
|
|
|
{
|
2025-04-24 12:41:04 +02:00
|
|
|
auto m = gv_bcst32(jm_mask);
|
2022-01-17 09:32:44 +01:00
|
|
|
auto b = ppu_flush_denormal<false, Flags...>(m, std::move(b_));
|
|
|
|
|
d = ppu_flush_denormal<true, Flags...>(std::move(m), ppu_set_vnan<Flags...>(gv_divfs(gv_bcstfs(1.0f), b), b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-17 09:32:44 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.vb], ppu.jm_mask);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VRFIM()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-01-15 12:30:13 +01:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_nj, fix_nj, set_vnan, fix_vnan>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2022-01-17 09:32:44 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& b_, auto&& jm_mask)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2025-04-24 12:41:04 +02:00
|
|
|
auto m = gv_bcst32(jm_mask);
|
2022-01-17 09:32:44 +01:00
|
|
|
auto b = ppu_flush_denormal<false, Flags...>(m, std::move(b_));
|
|
|
|
|
d = ppu_flush_denormal<true, Flags...>(std::move(m), ppu_set_vnan<Flags...>(gv_roundfs_floor(b), b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-17 09:32:44 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.vb], ppu.jm_mask);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VRFIN()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-01-15 12:30:13 +01:00
|
|
|
return ppu_exec_select<Flags...>::template select<fix_nj, set_vnan, fix_vnan>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2022-01-17 09:32:44 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& b, auto&& jm_mask)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2025-04-24 12:41:04 +02:00
|
|
|
auto m = gv_bcst32(jm_mask);
|
2022-01-17 09:32:44 +01:00
|
|
|
d = ppu_flush_denormal<true, Flags...>(std::move(m), ppu_set_vnan<Flags...>(gv_roundfs_even(b), b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-17 09:32:44 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.vb], ppu.jm_mask);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VRFIP()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-01-15 12:30:13 +01:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_nj, fix_nj, set_vnan, fix_vnan>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2022-01-17 09:32:44 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& b_, auto&& jm_mask)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2025-04-24 12:41:04 +02:00
|
|
|
auto m = gv_bcst32(jm_mask);
|
2022-01-17 09:32:44 +01:00
|
|
|
auto b = ppu_flush_denormal<false, Flags...>(m, std::move(b_));
|
|
|
|
|
d = ppu_flush_denormal<true, Flags...>(std::move(m), ppu_set_vnan<Flags...>(gv_roundfs_ceil(b), b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-17 09:32:44 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.vb], ppu.jm_mask);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VRFIZ()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-01-15 12:30:13 +01:00
|
|
|
return ppu_exec_select<Flags...>::template select<fix_nj, set_vnan, fix_vnan>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2022-01-17 09:32:44 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& b, auto&& jm_mask)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2025-04-24 12:41:04 +02:00
|
|
|
auto m = gv_bcst32(jm_mask);
|
2022-01-17 09:32:44 +01:00
|
|
|
d = ppu_flush_denormal<true, Flags...>(std::move(m), ppu_set_vnan<Flags...>(gv_roundfs_trunc(b), b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-17 09:32:44 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.vb], ppu.jm_mask);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VRLB()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
2016-04-14 01:09:41 +02:00
|
|
|
{
|
2022-01-19 00:41:32 +01:00
|
|
|
d = gv_rol8(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-19 00:41:32 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VRLH()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2022-01-19 00:41:32 +01:00
|
|
|
d = gv_rol16(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-19 00:41:32 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VRLW()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2022-01-19 00:41:32 +01:00
|
|
|
d = gv_rol32(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-19 00:41:32 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VRSQRTEFP()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-01-15 12:30:13 +01:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_nj, fix_nj, set_vnan, fix_vnan>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2022-01-17 09:32:44 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& b_, auto&& jm_mask)
|
|
|
|
|
{
|
2025-04-24 12:41:04 +02:00
|
|
|
auto m = gv_bcst32(jm_mask);
|
2022-01-17 09:32:44 +01:00
|
|
|
auto b = ppu_flush_denormal<false, Flags...>(m, std::move(b_));
|
|
|
|
|
d = ppu_flush_denormal<true, Flags...>(std::move(m), ppu_set_vnan<Flags...>(gv_divfs(gv_bcstfs(1.0f), gv_sqrtfs(b)), b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-17 09:32:44 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.vb], ppu.jm_mask);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSEL()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& c)
|
|
|
|
|
{
|
|
|
|
|
auto x = gv_andfs(std::move(b), c);
|
|
|
|
|
d = gv_orfs(std::move(x), gv_andnfs(std::move(c), std::move(a)));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-19 00:41:32 +01:00
|
|
|
|
|
|
|
|
RETURN(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.vr[op.vc]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSL()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2022-01-19 00:41:32 +01:00
|
|
|
d = gv_fshl8(std::move(a), gv_shuffle_left<1>(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-19 00:41:32 +01:00
|
|
|
|
|
|
|
|
RETURN(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSLB()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2022-01-19 00:41:32 +01:00
|
|
|
d = gv_shl8(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-19 00:41:32 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
template <u32 Count>
|
|
|
|
|
struct VSLDOI
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2022-01-19 00:41:32 +01:00
|
|
|
template <ppu_exec_bit... Flags>
|
2025-10-04 21:19:57 +02:00
|
|
|
static auto select(rx::EnumBitSet<ppu_exec_bit> selected, auto func)
|
2022-01-19 00:41:32 +01:00
|
|
|
{
|
|
|
|
|
return ppu_exec_select<>::select<Flags...>(selected, func);
|
|
|
|
|
}
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
static auto impl()
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2022-01-19 00:41:32 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
|
|
|
|
d = gv_or32(gv_shuffle_left<Count>(std::move(a)), gv_shuffle_right<16 - Count>(std::move(b)));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-17 21:03:24 +01:00
|
|
|
}
|
2022-01-19 00:41:32 +01:00
|
|
|
};
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSLH()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2022-01-19 00:41:32 +01:00
|
|
|
d = gv_shl16(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-19 00:41:32 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSLO()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2022-01-19 00:41:32 +01:00
|
|
|
d._u = a._u << (b._u8[0] & 0x78);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-19 00:41:32 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSLW()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2022-01-19 00:41:32 +01:00
|
|
|
d = gv_shl32(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-19 00:41:32 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSPLTB()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& b, auto&& imm)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2022-01-19 00:41:32 +01:00
|
|
|
d = gv_bcst8(b.u8r[imm & 15]);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-19 00:41:32 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.vb], op.vuimm);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSPLTH()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& b, auto&& imm)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2022-01-19 00:41:32 +01:00
|
|
|
d = gv_bcst16(b.u16r[imm & 7]);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-19 00:41:32 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.vb], op.vuimm);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSPLTISB()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& imm)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2022-01-19 00:41:32 +01:00
|
|
|
d = gv_bcst8(imm);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-19 00:41:32 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], op.vsimm);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSPLTISH()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& imm)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2022-01-19 00:41:32 +01:00
|
|
|
d = gv_bcst16(imm);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-19 00:41:32 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], op.vsimm);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSPLTISW()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& imm)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2022-01-19 00:41:32 +01:00
|
|
|
d = gv_bcst32(imm);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-19 00:41:32 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], op.vsimm);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSPLTW()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& b, auto&& imm)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2022-01-19 00:41:32 +01:00
|
|
|
d = gv_bcst32(b.u32r[imm & 3]);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-19 00:41:32 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.vb], op.vuimm);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSR()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2022-01-19 00:41:32 +01:00
|
|
|
d = gv_fshr8(gv_shuffle_right<1>(a), std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-19 00:41:32 +01:00
|
|
|
|
|
|
|
|
RETURN(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSRAB()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2022-01-19 00:41:32 +01:00
|
|
|
d = gv_sar8(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-19 00:41:32 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSRAH()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2022-01-19 00:41:32 +01:00
|
|
|
d = gv_sar16(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-19 00:41:32 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSRAW()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2022-01-19 00:41:32 +01:00
|
|
|
d = gv_sar32(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-19 00:41:32 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSRB()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2022-01-19 00:41:32 +01:00
|
|
|
d = gv_shr8(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-19 00:41:32 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSRH()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2022-01-19 00:41:32 +01:00
|
|
|
d = gv_shr16(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-19 00:41:32 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSRO()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2022-01-19 00:41:32 +01:00
|
|
|
d._u = a._u >> (b._u8[0] & 0x78);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-19 00:41:32 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSRW()
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2022-01-19 00:41:32 +01:00
|
|
|
d = gv_shr32(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-19 00:41:32 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSUBCUW()
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2022-01-16 05:47:42 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
|
|
|
|
d = gv_shr32(gv_geu32(std::move(a), std::move(b)), 31);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-16 05:47:42 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSUBFP()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-01-15 12:30:13 +01:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_nj, fix_nj, set_vnan, fix_vnan>();
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2022-01-16 05:47:42 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a_, auto&& b_, auto&& jm_mask)
|
|
|
|
|
{
|
2025-04-24 12:41:04 +02:00
|
|
|
auto m = gv_bcst32(jm_mask);
|
2022-01-16 05:47:42 +01:00
|
|
|
auto a = ppu_flush_denormal<false, Flags...>(m, std::move(a_));
|
|
|
|
|
auto b = ppu_flush_denormal<false, Flags...>(m, std::move(b_));
|
|
|
|
|
d = ppu_flush_denormal<true, Flags...>(std::move(m), ppu_set_vnan<Flags...>(gv_subfs(a, b), a, b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-16 05:47:42 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.jm_mask);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSUBSBS()
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_sat>();
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& sat)
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == set_sat) || ...))
|
2022-01-16 05:47:42 +01:00
|
|
|
{
|
|
|
|
|
auto r = gv_subs_s8(a, b);
|
|
|
|
|
sat = gv_or32(gv_xor32(gv_sub8(std::move(a), std::move(b)), r), std::move(sat));
|
|
|
|
|
d = std::move(r);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
d = gv_subs_s8(std::move(a), std::move(b));
|
|
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.sat);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSUBSHS()
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_sat>();
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& sat)
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == set_sat) || ...))
|
2022-01-16 05:47:42 +01:00
|
|
|
{
|
|
|
|
|
auto r = gv_subs_s16(a, b);
|
|
|
|
|
sat = gv_or32(gv_xor32(gv_sub16(std::move(a), std::move(b)), r), std::move(sat));
|
|
|
|
|
d = std::move(r);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
d = gv_subs_s16(std::move(a), std::move(b));
|
|
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.sat);
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSUBSWS()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_sat>();
|
2016-04-14 01:09:41 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& sat)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == set_sat) || ...))
|
2022-01-16 05:47:42 +01:00
|
|
|
{
|
|
|
|
|
auto r = gv_subs_s32(a, b);
|
|
|
|
|
sat = gv_or32(gv_xor32(gv_sub32(std::move(a), std::move(b)), r), std::move(sat));
|
|
|
|
|
d = std::move(r);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
d = gv_subs_s32(std::move(a), std::move(b));
|
|
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.sat);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSUBUBM()
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_sub8(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
|
|
|
|
}
|
2016-04-14 01:09:41 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSUBUBS()
|
|
|
|
|
{
|
|
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_sat>();
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& sat)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == set_sat) || ...))
|
2022-01-16 05:47:42 +01:00
|
|
|
{
|
|
|
|
|
auto r = gv_subus_u8(a, b);
|
|
|
|
|
sat = gv_or32(gv_xor32(gv_sub8(std::move(a), std::move(b)), r), std::move(sat));
|
|
|
|
|
d = std::move(r);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
d = gv_subus_u8(std::move(a), std::move(b));
|
|
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.sat);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSUBUHM()
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_sub16(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSUBUHS()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_sat>();
|
2016-04-14 01:09:41 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& sat)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == set_sat) || ...))
|
2022-01-16 05:47:42 +01:00
|
|
|
{
|
|
|
|
|
auto r = gv_subus_u16(a, b);
|
|
|
|
|
sat = gv_or32(gv_xor32(gv_sub16(std::move(a), std::move(b)), r), std::move(sat));
|
|
|
|
|
d = std::move(r);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
d = gv_subus_u16(std::move(a), std::move(b));
|
|
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2019-03-19 21:05:10 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.sat);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSUBUWM()
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2022-01-16 05:47:42 +01:00
|
|
|
d = gv_sub32(std::move(a), std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSUBUWS()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_sat>();
|
2016-04-14 01:09:41 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& sat)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == set_sat) || ...))
|
2022-01-16 05:47:42 +01:00
|
|
|
{
|
|
|
|
|
auto r = gv_subus_u32(a, b);
|
|
|
|
|
sat = gv_or32(gv_xor32(gv_sub32(std::move(a), std::move(b)), r), std::move(sat));
|
|
|
|
|
d = std::move(r);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
d = gv_subus_u32(std::move(a), std::move(b));
|
|
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.sat);
|
|
|
|
|
}
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSUMSWS()
|
|
|
|
|
{
|
|
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_sat>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& sat)
|
|
|
|
|
{
|
|
|
|
|
s64 sum = s64{b._s32[0]} + a._s32[0] + a._s32[1] + a._s32[2] + a._s32[3];
|
2017-04-30 20:05:50 +02:00
|
|
|
if (sum > INT32_MAX)
|
|
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
sum = u32(INT32_MAX);
|
|
|
|
|
if constexpr (((Flags == set_sat) || ...))
|
|
|
|
|
sat._bytes[0] = 1;
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
|
|
|
|
else if (sum < INT32_MIN)
|
|
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
sum = u32(INT32_MIN);
|
|
|
|
|
if constexpr (((Flags == set_sat) || ...))
|
|
|
|
|
sat._bytes[0] = 1;
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
|
|
|
|
else
|
2021-12-30 17:39:18 +01:00
|
|
|
{
|
|
|
|
|
sum = static_cast<u32>(sum);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
d._u = sum;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.sat);
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSUM2SWS()
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_sat>();
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& sat)
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
#if defined(__AVX512VL__)
|
|
|
|
|
const auto x = gv_add64(gv_sar64(gv_shl64(a, 32), 32), gv_sar64(a, 32));
|
|
|
|
|
const auto y = gv_add64(x, gv_sar64(gv_shl64(b, 32), 32));
|
|
|
|
|
const auto r = _mm_unpacklo_epi32(_mm_cvtsepi64_epi32(y), _mm_setzero_si128());
|
|
|
|
|
#elif defined(ARCH_ARM64)
|
|
|
|
|
const auto x = vaddl_s32(vget_low_s32(vuzp1q_s32(a, a)), vget_low_s32(vuzp2q_s32(a, a)));
|
|
|
|
|
const auto y = vaddw_s32(x, vget_low_s32(vuzp1q_s32(b, b)));
|
|
|
|
|
const auto r = vmovl_u32(uint32x2_t(vqmovn_s64(y)));
|
|
|
|
|
#else
|
|
|
|
|
v128 y{};
|
|
|
|
|
y._s64[0] = s64{a._s32[0]} + a._s32[1] + b._s32[0];
|
|
|
|
|
y._s64[1] = s64{a._s32[2]} + a._s32[3] + b._s32[2];
|
|
|
|
|
v128 r{};
|
2025-04-05 21:50:45 +02:00
|
|
|
r._u64[0] = y._s64[0] > INT32_MAX ? INT32_MAX : y._s64[0] < INT32_MIN ? u32(INT32_MIN) :
|
|
|
|
|
static_cast<u32>(y._s64[0]);
|
|
|
|
|
r._u64[1] = y._s64[1] > INT32_MAX ? INT32_MAX : y._s64[1] < INT32_MIN ? u32(INT32_MIN) :
|
|
|
|
|
static_cast<u32>(y._s64[1]);
|
2021-12-30 17:39:18 +01:00
|
|
|
#endif
|
|
|
|
|
if constexpr (((Flags == set_sat) || ...))
|
2022-01-16 19:00:22 +01:00
|
|
|
sat = gv_or32(gv_shr64(gv_add64(y, gv_bcst64(0x80000000u)), 32), std::move(sat));
|
2021-12-30 17:39:18 +01:00
|
|
|
d = r;
|
|
|
|
|
};
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.sat);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSUM4SBS()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_sat>();
|
2016-04-14 01:09:41 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& sat)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2022-01-21 11:42:06 +01:00
|
|
|
auto r = gv_dots_u8s8x4(gv_bcst8(1), a, b);
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == set_sat) || ...))
|
2022-01-21 11:42:06 +01:00
|
|
|
sat = gv_or32(gv_xor32(gv_hadds8x4(std::move(a), std::move(b)), r), std::move(sat));
|
2022-01-16 19:00:22 +01:00
|
|
|
d = std::move(r);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.sat);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSUM4SHS()
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_sat>();
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& sat)
|
2017-04-30 20:05:50 +02:00
|
|
|
{
|
2022-01-21 11:42:06 +01:00
|
|
|
auto r = gv_dots_s16x2(a, gv_bcst16(1), b);
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == set_sat) || ...))
|
2022-01-21 11:42:06 +01:00
|
|
|
sat = gv_or32(gv_xor32(gv_hadds16x2(std::move(a), std::move(b)), r), std::move(sat));
|
2022-01-16 19:00:22 +01:00
|
|
|
d = std::move(r);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2017-04-30 20:05:50 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.sat);
|
2017-04-30 20:05:50 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VSUM4UBS()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_sat>();
|
2016-04-14 01:09:41 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b, auto&& sat)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2022-01-16 19:00:22 +01:00
|
|
|
auto x = gv_haddu8x4(a);
|
|
|
|
|
auto r = gv_addus_u32(x, b);
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (((Flags == set_sat) || ...))
|
2022-01-16 19:00:22 +01:00
|
|
|
sat = gv_or32(gv_xor32(gv_add32(std::move(x), std::move(b)), r), std::move(sat));
|
|
|
|
|
d = std::move(r);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb], ppu.sat);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VUPKHPX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& b)
|
|
|
|
|
{
|
2022-01-19 00:41:32 +01:00
|
|
|
auto x = gv_extend_hi_s16(std::move(b));
|
|
|
|
|
auto y = gv_or32(gv_and32(gv_shl32(x, 6), gv_bcst32(0x1f0000)), gv_and32(gv_shl32(x, 3), gv_bcst32(0x1f00)));
|
|
|
|
|
d = gv_or32(std::move(y), gv_and32(std::move(x), gv_bcst32(0xff00001f)));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
RETURN(ppu.vr[op.vd], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VUPKHSB()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& b)
|
|
|
|
|
{
|
2022-01-19 00:41:32 +01:00
|
|
|
d = gv_extend_hi_s8(std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
RETURN(ppu.vr[op.vd], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VUPKHSH()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& b)
|
|
|
|
|
{
|
2022-01-19 00:41:32 +01:00
|
|
|
d = gv_extend_hi_s16(std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
RETURN(ppu.vr[op.vd], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VUPKLPX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& b)
|
|
|
|
|
{
|
2022-01-19 00:41:32 +01:00
|
|
|
auto x = gv_extend_lo_s16(std::move(b));
|
|
|
|
|
auto y = gv_or32(gv_and32(gv_shl32(x, 6), gv_bcst32(0x1f0000)), gv_and32(gv_shl32(x, 3), gv_bcst32(0x1f00)));
|
|
|
|
|
d = gv_or32(std::move(y), gv_and32(std::move(x), gv_bcst32(0xff00001f)));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
RETURN(ppu.vr[op.vd], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VUPKLSB()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& b)
|
|
|
|
|
{
|
2022-01-19 00:41:32 +01:00
|
|
|
d = gv_extend_lo_s8(std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
RETURN(ppu.vr[op.vd], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VUPKLSH()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& b)
|
|
|
|
|
{
|
2022-01-19 00:41:32 +01:00
|
|
|
d = gv_extend_lo_s16(std::move(b));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
|
2022-01-19 00:41:32 +01:00
|
|
|
RETURN(ppu.vr[op.vd], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto VXOR()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](auto&& d, auto&& a, auto&& b)
|
|
|
|
|
{
|
|
|
|
|
d = gv_xorfs(std::move(a), std::move(b));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
RETURN(ppu.vr[op.vd], ppu.vr[op.va], ppu.vr[op.vb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto TDI()
|
2016-05-13 15:55:34 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
if constexpr (Build == 0)
|
|
|
|
|
return +[](ppu_thread& ppu, ppu_opcode_t op, be_t<u32>* this_op, ppu_intrp_func* next_fn)
|
|
|
|
|
{
|
|
|
|
|
const s64 a = ppu.gpr[op.ra], b = op.simm16;
|
|
|
|
|
const u64 a_ = a, b_ = b;
|
|
|
|
|
|
|
|
|
|
if (((op.bo & 0x10) && a < b) ||
|
|
|
|
|
((op.bo & 0x8) && a > b) ||
|
|
|
|
|
((op.bo & 0x4) && a == b) ||
|
|
|
|
|
((op.bo & 0x2) && a_ < b_) ||
|
|
|
|
|
((op.bo & 0x1) && a_ > b_))
|
|
|
|
|
{
|
|
|
|
|
[[unlikely]] ppu_trap(ppu, vm::get_addr(this_op));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
return next_fn->fn(ppu, {this_op[1]}, this_op + 1, next_fn + 1);
|
|
|
|
|
};
|
2016-05-13 15:55:34 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto TWI()
|
2016-05-13 15:55:34 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
if constexpr (Build == 0)
|
|
|
|
|
return +[](ppu_thread& ppu, ppu_opcode_t op, be_t<u32>* this_op, ppu_intrp_func* next_fn)
|
|
|
|
|
{
|
|
|
|
|
const s32 a = static_cast<u32>(ppu.gpr[op.ra]), b = op.simm16;
|
|
|
|
|
const u32 a_ = a, b_ = b;
|
|
|
|
|
|
|
|
|
|
if (((op.bo & 0x10) && a < b) ||
|
|
|
|
|
((op.bo & 0x8) && a > b) ||
|
|
|
|
|
((op.bo & 0x4) && a == b) ||
|
|
|
|
|
((op.bo & 0x2) && a_ < b_) ||
|
|
|
|
|
((op.bo & 0x1) && a_ > b_))
|
|
|
|
|
{
|
|
|
|
|
[[unlikely]] ppu_trap(ppu, vm::get_addr(this_op));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
return next_fn->fn(ppu, {this_op[1]}, this_op + 1, next_fn + 1);
|
|
|
|
|
};
|
2016-05-13 15:55:34 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto MULLI()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.gpr[op.rd] = static_cast<s64>(ppu.gpr[op.ra]) * op.simm16;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto SUBFIC()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 a = ppu.gpr[op.ra];
|
|
|
|
|
const s64 i = op.simm16;
|
|
|
|
|
const auto r = add64_flags(~a, i, 1);
|
|
|
|
|
ppu.gpr[op.rd] = r.result;
|
2025-04-24 12:41:04 +02:00
|
|
|
ppu.xer_ca = r.carry;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto CMPLI()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
2016-04-14 01:09:41 +02:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
if (op.l10)
|
|
|
|
|
{
|
|
|
|
|
ppu_cr_set<u64>(ppu, op.crfd, ppu.gpr[op.ra], op.uimm16);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ppu_cr_set<u32>(ppu, op.crfd, static_cast<u32>(ppu.gpr[op.ra]), op.uimm16);
|
|
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto CMPI()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
2016-04-14 01:09:41 +02:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
if (op.l10)
|
|
|
|
|
{
|
|
|
|
|
ppu_cr_set<s64>(ppu, op.crfd, ppu.gpr[op.ra], op.simm16);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ppu_cr_set<s32>(ppu, op.crfd, static_cast<u32>(ppu.gpr[op.ra]), op.simm16);
|
|
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto ADDIC()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const s64 a = ppu.gpr[op.ra];
|
|
|
|
|
const s64 i = op.simm16;
|
|
|
|
|
const auto r = add64_flags(a, i);
|
|
|
|
|
ppu.gpr[op.rd] = r.result;
|
2025-04-24 12:41:04 +02:00
|
|
|
ppu.xer_ca = r.carry;
|
2025-04-05 21:50:45 +02:00
|
|
|
if (op.main & 1) [[unlikely]]
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, r.result, 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto ADDI()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.gpr[op.rd] = op.ra ? ppu.gpr[op.ra] + op.simm16 : op.simm16;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto ADDIS()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.gpr[op.rd] = op.ra ? ppu.gpr[op.ra] + (op.simm16 * 65536) : (op.simm16 * 65536);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto BC()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:11:47 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<set_call_history>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
if constexpr (Build == 0)
|
|
|
|
|
return +[](ppu_thread& ppu, ppu_opcode_t op, be_t<u32>* this_op, ppu_intrp_func* next_fn)
|
|
|
|
|
{
|
|
|
|
|
const bool bo0 = (op.bo & 0x10) != 0;
|
|
|
|
|
const bool bo1 = (op.bo & 0x08) != 0;
|
|
|
|
|
const bool bo2 = (op.bo & 0x04) != 0;
|
|
|
|
|
const bool bo3 = (op.bo & 0x02) != 0;
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
ppu.ctr -= (bo2 ^ true);
|
|
|
|
|
const u32 link = vm::get_addr(this_op) + 4;
|
|
|
|
|
if (op.lk)
|
|
|
|
|
ppu.lr = link;
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
const bool ctr_ok = bo2 | ((ppu.ctr != 0) ^ bo3);
|
|
|
|
|
const bool cond_ok = bo0 | (!!(ppu.cr[op.bi]) ^ (bo1 ^ true));
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
const u32 old_cia = ppu.cia;
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
if (ctr_ok && cond_ok)
|
|
|
|
|
{
|
|
|
|
|
ppu.cia = vm::get_addr(this_op);
|
|
|
|
|
// Provide additional information by using the origin of the call
|
|
|
|
|
// Because this is a fixed target branch there's no abiguity about it
|
|
|
|
|
ppu_record_call<Flags...>(ppu, ppu.cia, op);
|
2021-07-10 10:56:48 +02:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
ppu.cia = (op.aa ? 0 : ppu.cia) + op.bt14;
|
|
|
|
|
}
|
|
|
|
|
else if (!ppu.state) [[likely]]
|
|
|
|
|
{
|
|
|
|
|
return next_fn->fn(ppu, {this_op[1]}, this_op + 1, next_fn + 1);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ppu.cia = link;
|
|
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
ppu.exec_bytes += link - old_cia;
|
|
|
|
|
};
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto SC()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
if constexpr (Build == 0)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
return +[](ppu_thread& ppu, ppu_opcode_t op, be_t<u32>* this_op, ppu_intrp_func*)
|
|
|
|
|
{
|
|
|
|
|
const u32 old_cia = ppu.cia;
|
|
|
|
|
ppu.cia = vm::get_addr(this_op);
|
|
|
|
|
ppu.exec_bytes += ppu.cia - old_cia;
|
|
|
|
|
if (op.opcode != ppu_instructions::SC(0))
|
|
|
|
|
{
|
|
|
|
|
fmt::throw_exception("Unknown/Illegal SC: 0x%08x", op.opcode);
|
|
|
|
|
}
|
2016-05-13 15:55:34 +02:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
ppu_execute_syscall(ppu, ppu.gpr[11]);
|
|
|
|
|
};
|
|
|
|
|
}
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto B()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:11:47 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<set_call_history>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
if constexpr (Build == 0)
|
|
|
|
|
return +[](ppu_thread& ppu, ppu_opcode_t op, be_t<u32>* this_op, ppu_intrp_func*)
|
|
|
|
|
{
|
|
|
|
|
const u32 old_cia = ppu.cia;
|
|
|
|
|
const u32 link = (ppu.cia = vm::get_addr(this_op)) + 4;
|
|
|
|
|
// Provide additional information by using the origin of the call
|
|
|
|
|
// Because this is a fixed target branch there's no abiguity about it
|
|
|
|
|
ppu_record_call<Flags...>(ppu, ppu.cia, op);
|
|
|
|
|
|
|
|
|
|
ppu.cia = (op.aa ? 0 : ppu.cia) + op.bt24;
|
|
|
|
|
if (op.lk)
|
|
|
|
|
ppu.lr = link;
|
|
|
|
|
ppu.exec_bytes += link - old_cia;
|
|
|
|
|
};
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto MCRF()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
CHECK_SIZE(ppu_thread::cr, 32);
|
|
|
|
|
ppu.cr.fields[op.crfd] = ppu.cr.fields[op.crfs];
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto BCLR()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:11:47 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<set_call_history>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
if constexpr (Build == 0)
|
|
|
|
|
return +[](ppu_thread& ppu, ppu_opcode_t op, be_t<u32>* this_op, ppu_intrp_func* next_fn)
|
|
|
|
|
{
|
|
|
|
|
const bool bo0 = (op.bo & 0x10) != 0;
|
|
|
|
|
const bool bo1 = (op.bo & 0x08) != 0;
|
|
|
|
|
const bool bo2 = (op.bo & 0x04) != 0;
|
|
|
|
|
const bool bo3 = (op.bo & 0x02) != 0;
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
ppu.ctr -= (bo2 ^ true);
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
const bool ctr_ok = bo2 | ((ppu.ctr != 0) ^ bo3);
|
|
|
|
|
const bool cond_ok = bo0 | (!!(ppu.cr[op.bi]) ^ (bo1 ^ true));
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
const u32 target = static_cast<u32>(ppu.lr) & ~3;
|
|
|
|
|
const u32 link = vm::get_addr(this_op) + 4;
|
|
|
|
|
if (op.lk)
|
|
|
|
|
ppu.lr = link;
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
const u32 old_cia = ppu.cia;
|
2018-11-23 11:49:03 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
if (ctr_ok && cond_ok)
|
|
|
|
|
{
|
|
|
|
|
ppu_record_call<Flags...>(ppu, target, op, true);
|
|
|
|
|
ppu.cia = target;
|
|
|
|
|
}
|
|
|
|
|
else if (!ppu.state) [[likely]]
|
|
|
|
|
{
|
|
|
|
|
return next_fn->fn(ppu, {this_op[1]}, this_op + 1, next_fn + 1);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ppu.cia = link;
|
|
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
ppu.exec_bytes += link - old_cia;
|
|
|
|
|
};
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto CRNOR()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.cr[op.crbd] = (ppu.cr[op.crba] | ppu.cr[op.crbb]) ^ true;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto CRANDC()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.cr[op.crbd] = ppu.cr[op.crba] & (ppu.cr[op.crbb] ^ true);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto ISYNC()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](auto&&, auto)
|
|
|
|
|
{
|
|
|
|
|
atomic_fence_acquire();
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto CRXOR()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.cr[op.crbd] = ppu.cr[op.crba] ^ ppu.cr[op.crbb];
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto CRNAND()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.cr[op.crbd] = (ppu.cr[op.crba] & ppu.cr[op.crbb]) ^ true;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto CRAND()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.cr[op.crbd] = ppu.cr[op.crba] & ppu.cr[op.crbb];
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto CREQV()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.cr[op.crbd] = (ppu.cr[op.crba] ^ ppu.cr[op.crbb]) ^ true;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto CRORC()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.cr[op.crbd] = ppu.cr[op.crba] | (ppu.cr[op.crbb] ^ true);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto CROR()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.cr[op.crbd] = ppu.cr[op.crba] | ppu.cr[op.crbb];
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto BCCTR()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:11:47 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<set_call_history>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
if constexpr (Build == 0)
|
|
|
|
|
return +[](ppu_thread& ppu, ppu_opcode_t op, be_t<u32>* this_op, ppu_intrp_func* next_fn)
|
|
|
|
|
{
|
|
|
|
|
const u32 link = vm::get_addr(this_op) + 4;
|
|
|
|
|
if (op.lk)
|
|
|
|
|
ppu.lr = link;
|
|
|
|
|
const u32 old_cia = ppu.cia;
|
2018-11-23 11:49:03 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
if (op.bo & 0x10 || ppu.cr[op.bi] == ((op.bo & 0x8) != 0))
|
|
|
|
|
{
|
|
|
|
|
const u32 target = static_cast<u32>(ppu.ctr) & ~3;
|
|
|
|
|
ppu_record_call<Flags...>(ppu, target, op, true);
|
|
|
|
|
ppu.cia = target;
|
|
|
|
|
}
|
|
|
|
|
else if (!ppu.state) [[likely]]
|
|
|
|
|
{
|
|
|
|
|
return next_fn->fn(ppu, {this_op[1]}, this_op + 1, next_fn + 1);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ppu.cia = link;
|
|
|
|
|
}
|
2017-12-16 01:21:55 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
ppu.exec_bytes += link - old_cia;
|
|
|
|
|
};
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto RLWIMI()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 mask = ppu_rotate_mask(32 + op.mb32, 32 + op.me32);
|
2025-10-05 18:28:03 +02:00
|
|
|
ppu.gpr[op.ra] = (ppu.gpr[op.ra] & ~mask) | (dup32(rx::rol32(static_cast<u32>(ppu.gpr[op.rs]), op.sh32)) & mask);
|
2025-04-05 21:50:45 +02:00
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto RLWINM()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
2025-10-05 18:28:03 +02:00
|
|
|
ppu.gpr[op.ra] = dup32(rx::rol32(static_cast<u32>(ppu.gpr[op.rs]), op.sh32)) & ppu_rotate_mask(32 + op.mb32, 32 + op.me32);
|
2025-04-05 21:50:45 +02:00
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto RLWNM()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
2025-10-05 18:28:03 +02:00
|
|
|
ppu.gpr[op.ra] = dup32(rx::rol32(static_cast<u32>(ppu.gpr[op.rs]), ppu.gpr[op.rb] & 0x1f)) & ppu_rotate_mask(32 + op.mb32, 32 + op.me32);
|
2025-04-05 21:50:45 +02:00
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto ORI()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.gpr[op.ra] = ppu.gpr[op.rs] | op.uimm16;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto ORIS()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.gpr[op.ra] = ppu.gpr[op.rs] | (u64{op.uimm16} << 16);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto XORI()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.gpr[op.ra] = ppu.gpr[op.rs] ^ op.uimm16;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto XORIS()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.gpr[op.ra] = ppu.gpr[op.rs] ^ (u64{op.uimm16} << 16);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto ANDI()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.gpr[op.ra] = ppu.gpr[op.rs] & op.uimm16;
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto ANDIS()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.gpr[op.ra] = ppu.gpr[op.rs] & (u64{op.uimm16} << 16);
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto RLDICL()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
2025-10-05 18:28:03 +02:00
|
|
|
ppu.gpr[op.ra] = rx::rol64(ppu.gpr[op.rs], op.sh64) & (~0ull >> op.mbe64);
|
2025-04-05 21:50:45 +02:00
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto RLDICR()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
2025-10-05 18:28:03 +02:00
|
|
|
ppu.gpr[op.ra] = rx::rol64(ppu.gpr[op.rs], op.sh64) & (~0ull << (op.mbe64 ^ 63));
|
2025-04-05 21:50:45 +02:00
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto RLDIC()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
2025-10-05 18:28:03 +02:00
|
|
|
ppu.gpr[op.ra] = rx::rol64(ppu.gpr[op.rs], op.sh64) & ppu_rotate_mask(op.mbe64, op.sh64 ^ 63);
|
2025-04-05 21:50:45 +02:00
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto RLDIMI()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 mask = ppu_rotate_mask(op.mbe64, op.sh64 ^ 63);
|
2025-10-05 18:28:03 +02:00
|
|
|
ppu.gpr[op.ra] = (ppu.gpr[op.ra] & ~mask) | (rx::rol64(ppu.gpr[op.rs], op.sh64) & mask);
|
2025-04-05 21:50:45 +02:00
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2016-04-14 01:09:41 +02:00
|
|
|
}
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto RLDCL()
|
2016-04-14 01:09:41 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
2025-10-05 18:28:03 +02:00
|
|
|
ppu.gpr[op.ra] = rx::rol64(ppu.gpr[op.rs], ppu.gpr[op.rb] & 0x3f) & (~0ull >> op.mbe64);
|
2025-04-05 21:50:45 +02:00
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto RLDCR()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
2025-10-05 18:28:03 +02:00
|
|
|
ppu.gpr[op.ra] = rx::rol64(ppu.gpr[op.rs], ppu.gpr[op.rb] & 0x3f) & (~0ull << (op.mbe64 ^ 63));
|
2025-04-05 21:50:45 +02:00
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2016-04-14 01:09:41 +02:00
|
|
|
}
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto CMP()
|
2016-04-14 01:09:41 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
if (op.l10)
|
|
|
|
|
{
|
|
|
|
|
ppu_cr_set<s64>(ppu, op.crfd, ppu.gpr[op.ra], ppu.gpr[op.rb]);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ppu_cr_set<s32>(ppu, op.crfd, static_cast<u32>(ppu.gpr[op.ra]), static_cast<u32>(ppu.gpr[op.rb]));
|
|
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto TW()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
if constexpr (Build == 0)
|
|
|
|
|
return +[](ppu_thread& ppu, ppu_opcode_t op, be_t<u32>* this_op, ppu_intrp_func* next_fn)
|
|
|
|
|
{
|
|
|
|
|
s32 a = static_cast<s32>(ppu.gpr[op.ra]);
|
|
|
|
|
s32 b = static_cast<s32>(ppu.gpr[op.rb]);
|
|
|
|
|
|
|
|
|
|
if ((a < b && (op.bo & 0x10)) ||
|
|
|
|
|
(a > b && (op.bo & 0x8)) ||
|
|
|
|
|
(a == b && (op.bo & 0x4)) ||
|
|
|
|
|
(static_cast<u32>(a) < static_cast<u32>(b) && (op.bo & 0x2)) ||
|
|
|
|
|
(static_cast<u32>(a) > static_cast<u32>(b) && (op.bo & 0x1)))
|
|
|
|
|
{
|
|
|
|
|
[[unlikely]] ppu_trap(ppu, vm::get_addr(this_op));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
return next_fn->fn(ppu, {this_op[1]}, this_op + 1, next_fn + 1);
|
|
|
|
|
};
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2022-01-20 20:57:21 +01:00
|
|
|
const v128 s_lvsl_base = v128::from64r(0x0001020304050607, 0x08090a0b0c0d0e0f);
|
|
|
|
|
|
|
|
|
|
const v128 s_lvsl_consts[16] =
|
2025-04-05 21:50:45 +02:00
|
|
|
{
|
|
|
|
|
gv_add8(s_lvsl_base, gv_bcst8(0)),
|
|
|
|
|
gv_add8(s_lvsl_base, gv_bcst8(1)),
|
|
|
|
|
gv_add8(s_lvsl_base, gv_bcst8(2)),
|
|
|
|
|
gv_add8(s_lvsl_base, gv_bcst8(3)),
|
|
|
|
|
gv_add8(s_lvsl_base, gv_bcst8(4)),
|
|
|
|
|
gv_add8(s_lvsl_base, gv_bcst8(5)),
|
|
|
|
|
gv_add8(s_lvsl_base, gv_bcst8(6)),
|
|
|
|
|
gv_add8(s_lvsl_base, gv_bcst8(7)),
|
|
|
|
|
gv_add8(s_lvsl_base, gv_bcst8(8)),
|
|
|
|
|
gv_add8(s_lvsl_base, gv_bcst8(9)),
|
|
|
|
|
gv_add8(s_lvsl_base, gv_bcst8(10)),
|
|
|
|
|
gv_add8(s_lvsl_base, gv_bcst8(11)),
|
|
|
|
|
gv_add8(s_lvsl_base, gv_bcst8(12)),
|
|
|
|
|
gv_add8(s_lvsl_base, gv_bcst8(13)),
|
|
|
|
|
gv_add8(s_lvsl_base, gv_bcst8(14)),
|
|
|
|
|
gv_add8(s_lvsl_base, gv_bcst8(15)),
|
2022-01-20 20:57:21 +01:00
|
|
|
};
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LVSL()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-20 20:57:21 +01:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
|
|
|
|
ppu.vr[op.vd] = s_lvsl_consts[addr % 16];
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-20 20:57:21 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LVEBX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = (op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]) & ~0xfull;
|
|
|
|
|
ppu.vr[op.vd] = ppu_feed_data<v128, Flags...>(ppu, addr);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto SUBFC()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 RA = ppu.gpr[op.ra];
|
|
|
|
|
const u64 RB = ppu.gpr[op.rb];
|
|
|
|
|
const auto r = add64_flags(~RA, RB, 1);
|
|
|
|
|
ppu.gpr[op.rd] = r.result;
|
2025-04-24 12:41:04 +02:00
|
|
|
ppu.xer_ca = r.carry;
|
2025-04-05 21:50:45 +02:00
|
|
|
if constexpr (((Flags == has_oe) || ...))
|
|
|
|
|
ppu_ov_set(ppu, (~RA >> 63 == RB >> 63) && (~RA >> 63 != ppu.gpr[op.rd] >> 63));
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, r.result, 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto MULHDU()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
2025-10-05 18:28:03 +02:00
|
|
|
ppu.gpr[op.rd] = rx::umulh64(ppu.gpr[op.ra], ppu.gpr[op.rb]);
|
2025-04-05 21:50:45 +02:00
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.rd], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto ADDC()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 RA = ppu.gpr[op.ra];
|
|
|
|
|
const u64 RB = ppu.gpr[op.rb];
|
|
|
|
|
const auto r = add64_flags(RA, RB);
|
|
|
|
|
ppu.gpr[op.rd] = r.result;
|
2025-04-24 12:41:04 +02:00
|
|
|
ppu.xer_ca = r.carry;
|
2025-04-05 21:50:45 +02:00
|
|
|
if constexpr (((Flags == has_oe) || ...))
|
|
|
|
|
ppu_ov_set(ppu, (RA >> 63 == RB >> 63) && (RA >> 63 != ppu.gpr[op.rd] >> 63));
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, r.result, 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto MULHWU()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
u32 a = static_cast<u32>(ppu.gpr[op.ra]);
|
|
|
|
|
u32 b = static_cast<u32>(ppu.gpr[op.rb]);
|
|
|
|
|
ppu.gpr[op.rd] = (u64{a} * b) >> 32;
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.rd], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2022-01-21 10:49:52 +01:00
|
|
|
template <u32 N>
|
|
|
|
|
struct MFOCRF
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2022-01-21 10:49:52 +01:00
|
|
|
template <ppu_exec_bit... Flags>
|
2025-10-04 21:19:57 +02:00
|
|
|
static auto select(rx::EnumBitSet<ppu_exec_bit> selected, auto func)
|
2022-01-21 10:49:52 +01:00
|
|
|
{
|
|
|
|
|
return ppu_exec_select<>::select<Flags...>(selected, func);
|
|
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2022-01-21 10:49:52 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
static auto impl()
|
2016-04-14 01:09:41 +02:00
|
|
|
{
|
2022-01-21 10:49:52 +01:00
|
|
|
static const auto exec = [](ppu_thread& ppu, auto&& d)
|
|
|
|
|
{
|
|
|
|
|
const u32 p = N * 4;
|
|
|
|
|
const u32 v = ppu.cr[p + 0] << 3 | ppu.cr[p + 1] << 2 | ppu.cr[p + 2] << 1 | ppu.cr[p + 3] << 0;
|
|
|
|
|
|
|
|
|
|
d = v << (p ^ 0x1c);
|
|
|
|
|
};
|
2017-12-16 01:21:55 +01:00
|
|
|
|
2022-01-21 10:49:52 +01:00
|
|
|
RETURN_(ppu, ppu.gpr[op.rd]);
|
2016-04-14 01:09:41 +02:00
|
|
|
}
|
2022-01-21 10:49:52 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto MFCR()
|
|
|
|
|
{
|
|
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
static const auto exec = [](ppu_thread& ppu, auto&& d)
|
2016-04-14 01:09:41 +02:00
|
|
|
{
|
2022-01-21 10:49:52 +01:00
|
|
|
#if defined(ARCH_X64)
|
2021-03-08 21:41:23 +01:00
|
|
|
be_t<v128> lane0, lane1;
|
|
|
|
|
std::memcpy(&lane0, ppu.cr.bits, sizeof(v128));
|
|
|
|
|
std::memcpy(&lane1, ppu.cr.bits + 16, sizeof(v128));
|
2021-12-30 17:39:18 +01:00
|
|
|
const u32 mh = _mm_movemask_epi8(_mm_slli_epi64(lane0.value(), 7));
|
|
|
|
|
const u32 ml = _mm_movemask_epi8(_mm_slli_epi64(lane1.value(), 7));
|
2016-04-14 01:09:41 +02:00
|
|
|
|
2022-01-21 10:49:52 +01:00
|
|
|
d = (mh << 16) | ml;
|
|
|
|
|
#else
|
|
|
|
|
d = ppu.cr.pack();
|
|
|
|
|
#endif
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-21 10:49:52 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu, ppu.gpr[op.rd]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LWARX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
|
|
|
|
ppu.gpr[op.rd] = ppu_lwarx(ppu, vm::cast(addr));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LDX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
|
|
|
|
ppu.gpr[op.rd] = ppu_feed_data<u64, Flags...>(ppu, addr);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LWZX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
|
|
|
|
ppu.gpr[op.rd] = ppu_feed_data<u32, Flags...>(ppu, addr);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto SLW()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.gpr[op.ra] = static_cast<u32>(ppu.gpr[op.rs] << (ppu.gpr[op.rb] & 0x3f));
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
|
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto CNTLZW()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.gpr[op.ra] = std::countl_zero(static_cast<u32>(ppu.gpr[op.rs]));
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto SLD()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u32 n = ppu.gpr[op.rb] & 0x7f;
|
|
|
|
|
ppu.gpr[op.ra] = n & 0x40 ? 0 : ppu.gpr[op.rs] << n;
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto AND()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.gpr[op.ra] = ppu.gpr[op.rs] & ppu.gpr[op.rb];
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto CMPL()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
2016-04-14 01:09:41 +02:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
if (op.l10)
|
|
|
|
|
{
|
|
|
|
|
ppu_cr_set<u64>(ppu, op.crfd, ppu.gpr[op.ra], ppu.gpr[op.rb]);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ppu_cr_set<u32>(ppu, op.crfd, static_cast<u32>(ppu.gpr[op.ra]), static_cast<u32>(ppu.gpr[op.rb]));
|
|
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2022-01-20 20:57:21 +01:00
|
|
|
const v128 s_lvsr_consts[16] =
|
2025-04-05 21:50:45 +02:00
|
|
|
{
|
|
|
|
|
gv_add8(s_lvsl_base, gv_bcst8(16)),
|
|
|
|
|
gv_add8(s_lvsl_base, gv_bcst8(15)),
|
|
|
|
|
gv_add8(s_lvsl_base, gv_bcst8(14)),
|
|
|
|
|
gv_add8(s_lvsl_base, gv_bcst8(13)),
|
|
|
|
|
gv_add8(s_lvsl_base, gv_bcst8(12)),
|
|
|
|
|
gv_add8(s_lvsl_base, gv_bcst8(11)),
|
|
|
|
|
gv_add8(s_lvsl_base, gv_bcst8(10)),
|
|
|
|
|
gv_add8(s_lvsl_base, gv_bcst8(9)),
|
|
|
|
|
gv_add8(s_lvsl_base, gv_bcst8(8)),
|
|
|
|
|
gv_add8(s_lvsl_base, gv_bcst8(7)),
|
|
|
|
|
gv_add8(s_lvsl_base, gv_bcst8(6)),
|
|
|
|
|
gv_add8(s_lvsl_base, gv_bcst8(5)),
|
|
|
|
|
gv_add8(s_lvsl_base, gv_bcst8(4)),
|
|
|
|
|
gv_add8(s_lvsl_base, gv_bcst8(3)),
|
|
|
|
|
gv_add8(s_lvsl_base, gv_bcst8(2)),
|
|
|
|
|
gv_add8(s_lvsl_base, gv_bcst8(1)),
|
2022-01-20 20:57:21 +01:00
|
|
|
};
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LVSR()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-20 20:57:21 +01:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
|
|
|
|
ppu.vr[op.vd] = s_lvsr_consts[addr % 16];
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-20 20:57:21 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LVEHX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = (op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]) & ~0xfull;
|
|
|
|
|
ppu.vr[op.vd] = ppu_feed_data<v128, Flags...>(ppu, addr);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto SUBF()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 RA = ppu.gpr[op.ra];
|
|
|
|
|
const u64 RB = ppu.gpr[op.rb];
|
|
|
|
|
ppu.gpr[op.rd] = RB - RA;
|
|
|
|
|
if constexpr (((Flags == has_oe) || ...))
|
|
|
|
|
ppu_ov_set(ppu, (~RA >> 63 == RB >> 63) && (~RA >> 63 != ppu.gpr[op.rd] >> 63));
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.rd], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LDUX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = ppu.gpr[op.ra] + ppu.gpr[op.rb];
|
|
|
|
|
ppu.gpr[op.rd] = ppu_feed_data<u64, Flags...>(ppu, addr);
|
|
|
|
|
ppu.gpr[op.ra] = addr;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto DCBST()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](auto&&, auto) {};
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LWZUX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = ppu.gpr[op.ra] + ppu.gpr[op.rb];
|
|
|
|
|
ppu.gpr[op.rd] = ppu_feed_data<u32, Flags...>(ppu, addr);
|
|
|
|
|
ppu.gpr[op.ra] = addr;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto CNTLZD()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.gpr[op.ra] = std::countl_zero(ppu.gpr[op.rs]);
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto ANDC()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.gpr[op.ra] = ppu.gpr[op.rs] & ~ppu.gpr[op.rb];
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto TD()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
if constexpr (Build == 0)
|
|
|
|
|
return +[](ppu_thread& ppu, ppu_opcode_t op, be_t<u32>* this_op, ppu_intrp_func* next_fn)
|
|
|
|
|
{
|
|
|
|
|
const s64 a = ppu.gpr[op.ra], b = ppu.gpr[op.rb];
|
|
|
|
|
const u64 a_ = a, b_ = b;
|
|
|
|
|
|
|
|
|
|
if (((op.bo & 0x10) && a < b) ||
|
|
|
|
|
((op.bo & 0x8) && a > b) ||
|
|
|
|
|
((op.bo & 0x4) && a == b) ||
|
|
|
|
|
((op.bo & 0x2) && a_ < b_) ||
|
|
|
|
|
((op.bo & 0x1) && a_ > b_))
|
|
|
|
|
{
|
|
|
|
|
[[unlikely]] ppu_trap(ppu, vm::get_addr(this_op));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
return next_fn->fn(ppu, {this_op[1]}, this_op + 1, next_fn + 1);
|
|
|
|
|
};
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LVEWX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = (op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]) & ~0xfull;
|
|
|
|
|
ppu.vr[op.vd] = ppu_feed_data<v128, Flags...>(ppu, addr);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto MULHD()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
2025-10-05 18:28:03 +02:00
|
|
|
ppu.gpr[op.rd] = rx::mulh64(ppu.gpr[op.ra], ppu.gpr[op.rb]);
|
2025-04-05 21:50:45 +02:00
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.rd], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto MULHW()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
s32 a = static_cast<s32>(ppu.gpr[op.ra]);
|
|
|
|
|
s32 b = static_cast<s32>(ppu.gpr[op.rb]);
|
|
|
|
|
ppu.gpr[op.rd] = (s64{a} * b) >> 32;
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.rd], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LDARX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
|
|
|
|
ppu.gpr[op.rd] = ppu_ldarx(ppu, vm::cast(addr));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto DCBF()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](auto&&, auto) {};
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LBZX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
|
|
|
|
ppu.gpr[op.rd] = ppu_feed_data<u8, Flags...>(ppu, addr);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LVX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = (op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]) & ~0xfull;
|
|
|
|
|
ppu.vr[op.vd] = ppu_feed_data<v128, Flags...>(ppu, addr);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto NEG()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 RA = ppu.gpr[op.ra];
|
|
|
|
|
ppu.gpr[op.rd] = 0 - RA;
|
|
|
|
|
if constexpr (((Flags == has_oe) || ...))
|
|
|
|
|
ppu_ov_set(ppu, RA == (1ull << 63));
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.rd], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LBZUX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = ppu.gpr[op.ra] + ppu.gpr[op.rb];
|
|
|
|
|
ppu.gpr[op.rd] = ppu_feed_data<u8, Flags...>(ppu, addr);
|
|
|
|
|
ppu.gpr[op.ra] = addr;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto NOR()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.gpr[op.ra] = ~(ppu.gpr[op.rs] | ppu.gpr[op.rb]);
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STVEBX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
|
|
|
|
const u8 eb = addr & 0xf;
|
|
|
|
|
PPU_WRITE_8(vm::cast(addr), ppu.vr[op.vs]._u8[15 - eb]);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto SUBFE()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 RA = ppu.gpr[op.ra];
|
|
|
|
|
const u64 RB = ppu.gpr[op.rb];
|
2025-04-24 12:41:04 +02:00
|
|
|
const auto r = add64_flags(~RA, RB, ppu.xer_ca);
|
2025-04-05 21:50:45 +02:00
|
|
|
ppu.gpr[op.rd] = r.result;
|
2025-04-24 12:41:04 +02:00
|
|
|
ppu.xer_ca = r.carry;
|
2025-04-05 21:50:45 +02:00
|
|
|
if constexpr (((Flags == has_oe) || ...))
|
|
|
|
|
ppu_ov_set(ppu, (~RA >> 63 == RB >> 63) && (~RA >> 63 != ppu.gpr[op.rd] >> 63));
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, r.result, 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto ADDE()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 RA = ppu.gpr[op.ra];
|
|
|
|
|
const u64 RB = ppu.gpr[op.rb];
|
2025-04-24 12:41:04 +02:00
|
|
|
const auto r = add64_flags(RA, RB, ppu.xer_ca);
|
2025-04-05 21:50:45 +02:00
|
|
|
ppu.gpr[op.rd] = r.result;
|
2025-04-24 12:41:04 +02:00
|
|
|
ppu.xer_ca = r.carry;
|
2025-04-05 21:50:45 +02:00
|
|
|
if constexpr (((Flags == has_oe) || ...))
|
|
|
|
|
ppu_ov_set(ppu, (RA >> 63 == RB >> 63) && (RA >> 63 != ppu.gpr[op.rd] >> 63));
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, r.result, 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto MTOCRF()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
2017-06-28 19:33:18 +02:00
|
|
|
{
|
2025-04-24 12:41:04 +02:00
|
|
|
alignas(4) static const CrField s_table[16]{
|
|
|
|
|
CrField::From(false, false, false, false),
|
|
|
|
|
CrField::From(false, false, false, true),
|
|
|
|
|
CrField::From(false, false, true, false),
|
|
|
|
|
CrField::From(false, false, true, true),
|
|
|
|
|
CrField::From(false, true, false, false),
|
|
|
|
|
CrField::From(false, true, false, true),
|
|
|
|
|
CrField::From(false, true, true, false),
|
|
|
|
|
CrField::From(false, true, true, true),
|
|
|
|
|
CrField::From(true, false, false, false),
|
|
|
|
|
CrField::From(true, false, false, true),
|
|
|
|
|
CrField::From(true, false, true, false),
|
|
|
|
|
CrField::From(true, false, true, true),
|
|
|
|
|
CrField::From(true, true, false, false),
|
|
|
|
|
CrField::From(true, true, false, true),
|
|
|
|
|
CrField::From(true, true, true, false),
|
|
|
|
|
CrField::From(true, true, true, true),
|
2025-04-05 21:50:45 +02:00
|
|
|
};
|
2016-04-14 01:09:41 +02:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
const u64 s = ppu.gpr[op.rs];
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
if (op.l11)
|
|
|
|
|
{
|
|
|
|
|
// MTOCRF
|
2016-04-14 01:09:41 +02:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
const u32 n = std::countl_zero<u32>(op.crm) & 7;
|
|
|
|
|
const u64 v = (s >> ((n * 4) ^ 0x1c)) & 0xf;
|
2025-04-24 12:41:04 +02:00
|
|
|
ppu.cr.fields[n] = s_table[v];
|
2025-04-05 21:50:45 +02:00
|
|
|
}
|
|
|
|
|
else
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
// MTCRF
|
|
|
|
|
|
|
|
|
|
for (u32 i = 0; i < 8; i++)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
if (op.crm & (128 >> i))
|
|
|
|
|
{
|
|
|
|
|
const u64 v = (s >> ((i * 4) ^ 0x1c)) & 0xf;
|
2025-04-24 12:41:04 +02:00
|
|
|
ppu.cr.fields[i] = s_table[v];
|
2025-04-05 21:50:45 +02:00
|
|
|
}
|
2015-03-17 21:03:24 +01:00
|
|
|
}
|
|
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STDX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
|
|
|
|
PPU_WRITE_64(vm::cast(addr), ppu.gpr[op.rs]);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STWCX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
2025-04-24 12:41:04 +02:00
|
|
|
ppu_cr_set(ppu, 0, false, false, ppu_stwcx(ppu, vm::cast(addr), static_cast<u32>(ppu.gpr[op.rs])), ppu.xer_so);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STWX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
|
|
|
|
PPU_WRITE_32(vm::cast(addr), static_cast<u32>(ppu.gpr[op.rs]));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STVEHX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = (op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]) & ~1ULL;
|
|
|
|
|
const u8 eb = (addr & 0xf) >> 1;
|
|
|
|
|
PPU_WRITE_16(vm::cast(addr), ppu.vr[op.vs]._u16[7 - eb]);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STDUX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = ppu.gpr[op.ra] + ppu.gpr[op.rb];
|
|
|
|
|
PPU_WRITE_64(vm::cast(addr), ppu.gpr[op.rs]);
|
|
|
|
|
ppu.gpr[op.ra] = addr;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STWUX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = ppu.gpr[op.ra] + ppu.gpr[op.rb];
|
|
|
|
|
PPU_WRITE_32(vm::cast(addr), static_cast<u32>(ppu.gpr[op.rs]));
|
|
|
|
|
ppu.gpr[op.ra] = addr;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STVEWX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = (op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]) & ~3ULL;
|
|
|
|
|
const u8 eb = (addr & 0xf) >> 2;
|
|
|
|
|
PPU_WRITE_32(vm::cast(addr), ppu.vr[op.vs]._u32[3 - eb]);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto SUBFZE()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 RA = ppu.gpr[op.ra];
|
2025-04-24 12:41:04 +02:00
|
|
|
const auto r = add64_flags(~RA, 0, ppu.xer_ca);
|
2025-04-05 21:50:45 +02:00
|
|
|
ppu.gpr[op.rd] = r.result;
|
2025-04-24 12:41:04 +02:00
|
|
|
ppu.xer_ca = r.carry;
|
2025-04-05 21:50:45 +02:00
|
|
|
if constexpr (((Flags == has_oe) || ...))
|
|
|
|
|
ppu_ov_set(ppu, (~RA >> 63 == 0) && (~RA >> 63 != ppu.gpr[op.rd] >> 63));
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, r.result, 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto ADDZE()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 RA = ppu.gpr[op.ra];
|
2025-04-24 12:41:04 +02:00
|
|
|
const auto r = add64_flags(RA, 0, ppu.xer_ca);
|
2025-04-05 21:50:45 +02:00
|
|
|
ppu.gpr[op.rd] = r.result;
|
2025-04-24 12:41:04 +02:00
|
|
|
ppu.xer_ca = r.carry;
|
2025-04-05 21:50:45 +02:00
|
|
|
if constexpr (((Flags == has_oe) || ...))
|
|
|
|
|
ppu_ov_set(ppu, (RA >> 63 == 0) && (RA >> 63 != ppu.gpr[op.rd] >> 63));
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, r.result, 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STDCX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
2025-04-24 12:41:04 +02:00
|
|
|
ppu_cr_set(ppu, 0, false, false, ppu_stdcx(ppu, vm::cast(addr), ppu.gpr[op.rs]), ppu.xer_so);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STBX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
|
|
|
|
PPU_WRITE_8(vm::cast(addr), static_cast<u8>(ppu.gpr[op.rs]));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STVX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = (op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]) & ~0xfull;
|
|
|
|
|
vm::_ref<v128>(vm::cast(addr)) = ppu.vr[op.vs];
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto MULLD()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
const s64 RA = ppu.gpr[op.ra];
|
|
|
|
|
const s64 RB = ppu.gpr[op.rb];
|
|
|
|
|
ppu.gpr[op.rd] = RA * RB;
|
|
|
|
|
if (op.oe) [[unlikely]]
|
|
|
|
|
{
|
2025-10-05 18:28:03 +02:00
|
|
|
const s64 high = rx::mulh64(RA, RB);
|
2025-04-05 21:50:45 +02:00
|
|
|
ppu_ov_set(ppu, high != s64(ppu.gpr[op.rd]) >> 63);
|
|
|
|
|
}
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.rd], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto SUBFME()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 RA = ppu.gpr[op.ra];
|
2025-04-24 12:41:04 +02:00
|
|
|
const auto r = add64_flags(~RA, ~0ull, ppu.xer_ca);
|
2025-04-05 21:50:45 +02:00
|
|
|
ppu.gpr[op.rd] = r.result;
|
2025-04-24 12:41:04 +02:00
|
|
|
ppu.xer_ca = r.carry;
|
2025-04-05 21:50:45 +02:00
|
|
|
if constexpr (((Flags == has_oe) || ...))
|
|
|
|
|
ppu_ov_set(ppu, (~RA >> 63 == 1) && (~RA >> 63 != ppu.gpr[op.rd] >> 63));
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, r.result, 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto ADDME()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const s64 RA = ppu.gpr[op.ra];
|
2025-04-24 12:41:04 +02:00
|
|
|
const auto r = add64_flags(RA, ~0ull, ppu.xer_ca);
|
2025-04-05 21:50:45 +02:00
|
|
|
ppu.gpr[op.rd] = r.result;
|
2025-04-24 12:41:04 +02:00
|
|
|
ppu.xer_ca = r.carry;
|
2025-04-05 21:50:45 +02:00
|
|
|
if constexpr (((Flags == has_oe) || ...))
|
|
|
|
|
ppu_ov_set(ppu, (u64(RA) >> 63 == 1) && (u64(RA) >> 63 != ppu.gpr[op.rd] >> 63));
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, r.result, 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto MULLW()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.gpr[op.rd] = s64{static_cast<s32>(ppu.gpr[op.ra])} * static_cast<s32>(ppu.gpr[op.rb]);
|
|
|
|
|
if constexpr (((Flags == has_oe) || ...))
|
|
|
|
|
ppu_ov_set(ppu, s64(ppu.gpr[op.rd]) < INT32_MIN || s64(ppu.gpr[op.rd]) > INT32_MAX);
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.rd], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto DCBTST()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](auto&&, auto) {};
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STBUX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = ppu.gpr[op.ra] + ppu.gpr[op.rb];
|
|
|
|
|
PPU_WRITE_8(vm::cast(addr), static_cast<u8>(ppu.gpr[op.rs]));
|
|
|
|
|
ppu.gpr[op.ra] = addr;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto ADD()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 RA = ppu.gpr[op.ra];
|
|
|
|
|
const u64 RB = ppu.gpr[op.rb];
|
|
|
|
|
ppu.gpr[op.rd] = RA + RB;
|
|
|
|
|
if constexpr (((Flags == has_oe) || ...))
|
|
|
|
|
ppu_ov_set(ppu, (RA >> 63 == RB >> 63) && (RA >> 63 != ppu.gpr[op.rd] >> 63));
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.rd], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto DCBT()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](auto&&, auto) {};
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LHZX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
|
|
|
|
ppu.gpr[op.rd] = ppu_feed_data<u16, Flags...>(ppu, addr);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto EQV()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.gpr[op.ra] = ~(ppu.gpr[op.rs] ^ ppu.gpr[op.rb]);
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto ECIWX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](auto&&, auto)
|
|
|
|
|
{
|
|
|
|
|
fmt::throw_exception("ECIWX");
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LHZUX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
|
|
|
|
ppu.gpr[op.rd] = ppu_feed_data<u16, Flags...>(ppu, addr);
|
|
|
|
|
ppu.gpr[op.ra] = addr;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto XOR()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.gpr[op.ra] = ppu.gpr[op.rs] ^ ppu.gpr[op.rb];
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto MFSPR()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
const u32 n = (op.spr >> 5) | ((op.spr & 0x1f) << 5);
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
switch (n)
|
|
|
|
|
{
|
2025-04-24 12:41:04 +02:00
|
|
|
case 0x001: ppu.gpr[op.rd] = u32{ppu.xer_so} << 31 | ppu.xer_ov << 30 | ppu.xer_ca << 29 | ppu.xer_cnt; break;
|
2025-04-05 21:50:45 +02:00
|
|
|
case 0x008: ppu.gpr[op.rd] = ppu.lr; break;
|
|
|
|
|
case 0x009: ppu.gpr[op.rd] = ppu.ctr; break;
|
|
|
|
|
case 0x100: ppu.gpr[op.rd] = ppu.vrsave; break;
|
|
|
|
|
|
|
|
|
|
case 0x10C: ppu.gpr[op.rd] = get_timebased_time(); break;
|
|
|
|
|
case 0x10D: ppu.gpr[op.rd] = get_timebased_time() >> 32; break;
|
|
|
|
|
default: fmt::throw_exception("MFSPR 0x%x", n);
|
|
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LWAX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
|
|
|
|
ppu.gpr[op.rd] = ppu_feed_data<s32, Flags...>(ppu, addr);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto DST()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](auto&&, auto) {};
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LHAX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
|
|
|
|
ppu.gpr[op.rd] = ppu_feed_data<s16, Flags...>(ppu, addr);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LVXL()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = (op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]) & ~0xfull;
|
|
|
|
|
ppu.vr[op.vd] = ppu_feed_data<v128, Flags...>(ppu, addr);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto MFTB()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
const u32 n = (op.spr >> 5) | ((op.spr & 0x1f) << 5);
|
2016-05-13 15:55:34 +02:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
switch (n)
|
|
|
|
|
{
|
|
|
|
|
case 0x10C: ppu.gpr[op.rd] = get_timebased_time(); break;
|
|
|
|
|
case 0x10D: ppu.gpr[op.rd] = get_timebased_time() >> 32; break;
|
|
|
|
|
default: fmt::throw_exception("MFTB 0x%x", n);
|
|
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LWAUX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
|
|
|
|
ppu.gpr[op.rd] = ppu_feed_data<s32, Flags...>(ppu, addr);
|
|
|
|
|
ppu.gpr[op.ra] = addr;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto DSTST()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](auto&&, auto) {};
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LHAUX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
|
|
|
|
ppu.gpr[op.rd] = ppu_feed_data<s16, Flags...>(ppu, addr);
|
|
|
|
|
ppu.gpr[op.ra] = addr;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STHX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
|
|
|
|
PPU_WRITE_16(vm::cast(addr), static_cast<u16>(ppu.gpr[op.rs]));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto ORC()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.gpr[op.ra] = ppu.gpr[op.rs] | ~ppu.gpr[op.rb];
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto ECOWX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](auto&&, auto)
|
|
|
|
|
{
|
|
|
|
|
fmt::throw_exception("ECOWX");
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STHUX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = ppu.gpr[op.ra] + ppu.gpr[op.rb];
|
|
|
|
|
PPU_WRITE_16(vm::cast(addr), static_cast<u16>(ppu.gpr[op.rs]));
|
|
|
|
|
ppu.gpr[op.ra] = addr;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto OR()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.gpr[op.ra] = ppu.gpr[op.rs] | ppu.gpr[op.rb];
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto DIVDU()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 RA = ppu.gpr[op.ra];
|
|
|
|
|
const u64 RB = ppu.gpr[op.rb];
|
|
|
|
|
ppu.gpr[op.rd] = RB == 0 ? 0 : RA / RB;
|
|
|
|
|
if constexpr (((Flags == has_oe) || ...))
|
|
|
|
|
ppu_ov_set(ppu, RB == 0);
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.rd], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto DIVWU()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u32 RA = static_cast<u32>(ppu.gpr[op.ra]);
|
|
|
|
|
const u32 RB = static_cast<u32>(ppu.gpr[op.rb]);
|
|
|
|
|
ppu.gpr[op.rd] = RB == 0 ? 0 : RA / RB;
|
|
|
|
|
if constexpr (((Flags == has_oe) || ...))
|
|
|
|
|
ppu_ov_set(ppu, RB == 0);
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.rd], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto MTSPR()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
2016-04-14 01:09:41 +02:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
const u32 n = (op.spr >> 5) | ((op.spr & 0x1f) << 5);
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
switch (n)
|
|
|
|
|
{
|
|
|
|
|
case 0x001:
|
|
|
|
|
{
|
|
|
|
|
const u64 value = ppu.gpr[op.rs];
|
2025-04-24 12:41:04 +02:00
|
|
|
ppu.xer_so = (value & 0x80000000) != 0;
|
|
|
|
|
ppu.xer_ov = (value & 0x40000000) != 0;
|
|
|
|
|
ppu.xer_ca = (value & 0x20000000) != 0;
|
|
|
|
|
ppu.xer_cnt = value & 0x7f;
|
2025-04-05 21:50:45 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 0x008: ppu.lr = ppu.gpr[op.rs]; break;
|
|
|
|
|
case 0x009: ppu.ctr = ppu.gpr[op.rs]; break;
|
|
|
|
|
case 0x100: ppu.vrsave = static_cast<u32>(ppu.gpr[op.rs]); break;
|
|
|
|
|
default: fmt::throw_exception("MTSPR 0x%x", n);
|
|
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto DCBI()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](auto&&, auto) {};
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto NAND()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.gpr[op.ra] = ~(ppu.gpr[op.rs] & ppu.gpr[op.rb]);
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STVXL()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = (op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb]) & ~0xfull;
|
|
|
|
|
vm::_ref<v128>(vm::cast(addr)) = ppu.vr[op.vs];
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto DIVD()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const s64 RA = ppu.gpr[op.ra];
|
|
|
|
|
const s64 RB = ppu.gpr[op.rb];
|
|
|
|
|
const bool o = RB == 0 || (RA == INT64_MIN && RB == -1);
|
|
|
|
|
ppu.gpr[op.rd] = o ? 0 : RA / RB;
|
|
|
|
|
if constexpr (((Flags == has_oe) || ...))
|
|
|
|
|
ppu_ov_set(ppu, o);
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.rd], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto DIVW()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const s32 RA = static_cast<s32>(ppu.gpr[op.ra]);
|
|
|
|
|
const s32 RB = static_cast<s32>(ppu.gpr[op.rb]);
|
|
|
|
|
const bool o = RB == 0 || (RA == INT32_MIN && RB == -1);
|
|
|
|
|
ppu.gpr[op.rd] = o ? 0 : static_cast<u32>(RA / RB);
|
|
|
|
|
if constexpr (((Flags == has_oe) || ...))
|
|
|
|
|
ppu_ov_set(ppu, o);
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.rd], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LVLX()
|
2017-12-19 22:01:03 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2022-01-20 12:42:16 +01:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
2022-06-07 11:23:08 +02:00
|
|
|
const u128 data = ppu_feed_data<u128, Flags...>(ppu, addr & -16);
|
2022-01-20 12:42:16 +01:00
|
|
|
ppu.vr[op.vd] = data << ((addr & 15) * 8);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-20 12:42:16 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LDBRX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
|
|
|
|
ppu.gpr[op.rd] = ppu_feed_data<le_t<u64>, Flags...>(ppu, addr);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LSWX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
2025-04-24 12:41:04 +02:00
|
|
|
u32 count = ppu.xer_cnt & 0x7f;
|
2025-04-05 21:50:45 +02:00
|
|
|
for (; count >= 4; count -= 4, addr += 4, op.rd = (op.rd + 1) & 31)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
ppu.gpr[op.rd] = ppu_feed_data<u32, Flags...>(ppu, addr);
|
|
|
|
|
}
|
|
|
|
|
if (count)
|
|
|
|
|
{
|
|
|
|
|
u32 value = 0;
|
|
|
|
|
for (u32 byte = 0; byte < count; byte++)
|
|
|
|
|
{
|
|
|
|
|
u32 byte_value = ppu_feed_data<u8, Flags...>(ppu, addr + byte);
|
|
|
|
|
value |= byte_value << ((3 ^ byte) * 8);
|
|
|
|
|
}
|
|
|
|
|
ppu.gpr[op.rd] = value;
|
2015-03-17 21:03:24 +01:00
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LWBRX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
|
|
|
|
ppu.gpr[op.rd] = ppu_feed_data<le_t<u32>, Flags...>(ppu, addr);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LFSX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
|
|
|
|
ppu.fpr[op.frd] = ppu_feed_data<f32, Flags...>(ppu, addr);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto SRW()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.gpr[op.ra] = (ppu.gpr[op.rs] & 0xffffffff) >> (ppu.gpr[op.rb] & 0x3f);
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto SRD()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u32 n = ppu.gpr[op.rb] & 0x7f;
|
|
|
|
|
ppu.gpr[op.ra] = n & 0x40 ? 0 : ppu.gpr[op.rs] >> n;
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LVRX()
|
2017-12-19 22:01:03 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2022-01-20 12:42:16 +01:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
2023-08-17 15:26:46 +02:00
|
|
|
|
|
|
|
|
// Read from instruction address if offset is 0, this prevents accessing potentially bad memory from addr (because no actual memory is dereferenced)
|
|
|
|
|
const u128 data = ppu_feed_data<u128, Flags...>(ppu, ((addr & 15) == 0 ? ppu.cia : addr) & -16);
|
2022-01-20 12:42:16 +01:00
|
|
|
ppu.vr[op.vd] = data >> ((~addr & 15) * 8) >> 8;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-20 12:42:16 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LSWI()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
u64 addr = op.ra ? ppu.gpr[op.ra] : 0;
|
|
|
|
|
u64 N = op.rb ? op.rb : 32;
|
|
|
|
|
u8 reg = op.rd;
|
|
|
|
|
|
|
|
|
|
while (N > 0)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
if (N > 3)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
ppu.gpr[reg] = ppu_feed_data<u32, Flags...>(ppu, addr);
|
|
|
|
|
addr += 4;
|
|
|
|
|
N -= 4;
|
2015-03-17 21:03:24 +01:00
|
|
|
}
|
2025-04-05 21:50:45 +02:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
u32 buf = 0;
|
|
|
|
|
u32 i = 3;
|
|
|
|
|
while (N > 0)
|
|
|
|
|
{
|
|
|
|
|
N = N - 1;
|
|
|
|
|
buf |= ppu_feed_data<u8, Flags...>(ppu, addr) << (i * 8);
|
|
|
|
|
addr++;
|
|
|
|
|
i--;
|
|
|
|
|
}
|
|
|
|
|
ppu.gpr[reg] = buf;
|
|
|
|
|
}
|
|
|
|
|
reg = (reg + 1) % 32;
|
2015-03-17 21:03:24 +01:00
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LFSUX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = ppu.gpr[op.ra] + ppu.gpr[op.rb];
|
|
|
|
|
ppu.fpr[op.frd] = ppu_feed_data<f32, Flags...>(ppu, addr);
|
|
|
|
|
ppu.gpr[op.ra] = addr;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto SYNC()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](auto&&, auto)
|
|
|
|
|
{
|
|
|
|
|
atomic_fence_seq_cst();
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LFDX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
|
|
|
|
ppu.fpr[op.frd] = ppu_feed_data<f64, Flags...>(ppu, addr);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LFDUX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = ppu.gpr[op.ra] + ppu.gpr[op.rb];
|
|
|
|
|
ppu.fpr[op.frd] = ppu_feed_data<f64, Flags...>(ppu, addr);
|
|
|
|
|
ppu.gpr[op.ra] = addr;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STVLX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-20 12:42:16 +01:00
|
|
|
static const auto exec = [](auto&& s, ppu_opcode_t op, auto&& a, auto&& b)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? a + b : b;
|
|
|
|
|
const u32 tail = u32(addr & 15);
|
2022-09-03 22:07:18 +02:00
|
|
|
u8* ptr = vm::_ptr<u8>(addr);
|
2022-01-20 12:42:16 +01:00
|
|
|
for (u32 j = 0; j < 16 - tail; j++)
|
|
|
|
|
ptr[j] = s.u8r[j];
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-20 12:42:16 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vs], op, ppu.gpr[op.ra], ppu.gpr[op.rb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STDBRX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
|
|
|
|
vm::_ref<le_t<u64>>(vm::cast(addr)) = ppu.gpr[op.rs];
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STSWX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
2025-04-24 12:41:04 +02:00
|
|
|
u32 count = ppu.xer_cnt & 0x7F;
|
2025-04-05 21:50:45 +02:00
|
|
|
for (; count >= 4; count -= 4, addr += 4, op.rs = (op.rs + 1) & 31)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
PPU_WRITE_32(vm::cast(addr), static_cast<u32>(ppu.gpr[op.rs]));
|
|
|
|
|
}
|
|
|
|
|
if (count)
|
|
|
|
|
{
|
|
|
|
|
u32 value = static_cast<u32>(ppu.gpr[op.rs]);
|
|
|
|
|
for (u32 byte = 0; byte < count; byte++)
|
|
|
|
|
{
|
|
|
|
|
u8 byte_value = static_cast<u8>(value >> ((3 ^ byte) * 8));
|
|
|
|
|
PPU_WRITE_8(vm::cast(addr + byte), byte_value);
|
|
|
|
|
}
|
2015-03-17 21:03:24 +01:00
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STWBRX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
|
|
|
|
vm::_ref<le_t<u32>>(vm::cast(addr)) = static_cast<u32>(ppu.gpr[op.rs]);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STFSX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
|
|
|
|
vm::_ref<f32>(vm::cast(addr)) = static_cast<float>(ppu.fpr[op.frs]);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STVRX()
|
2017-12-19 22:01:03 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2022-01-20 12:42:16 +01:00
|
|
|
static const auto exec = [](auto&& s, ppu_opcode_t op, auto&& a, auto&& b)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? a + b : b;
|
|
|
|
|
const u32 tail = u32(addr & 15);
|
|
|
|
|
u8* ptr = vm::_ptr<u8>(addr - 16);
|
|
|
|
|
for (u32 i = 15; i > 15 - tail; i--)
|
|
|
|
|
ptr[i] = s.u8r[i];
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-20 12:42:16 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu.vr[op.vs], op, ppu.gpr[op.ra], ppu.gpr[op.rb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STFSUX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = ppu.gpr[op.ra] + ppu.gpr[op.rb];
|
|
|
|
|
vm::_ref<f32>(vm::cast(addr)) = static_cast<float>(ppu.fpr[op.frs]);
|
|
|
|
|
ppu.gpr[op.ra] = addr;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STSWI()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
u64 addr = op.ra ? ppu.gpr[op.ra] : 0;
|
|
|
|
|
u64 N = op.rb ? op.rb : 32;
|
|
|
|
|
u8 reg = op.rd;
|
|
|
|
|
|
|
|
|
|
while (N > 0)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
if (N > 3)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
PPU_WRITE_32(vm::cast(addr), static_cast<u32>(ppu.gpr[reg]));
|
|
|
|
|
addr += 4;
|
|
|
|
|
N -= 4;
|
2015-03-17 21:03:24 +01:00
|
|
|
}
|
2025-04-05 21:50:45 +02:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
u32 buf = static_cast<u32>(ppu.gpr[reg]);
|
|
|
|
|
while (N > 0)
|
|
|
|
|
{
|
|
|
|
|
N = N - 1;
|
|
|
|
|
PPU_WRITE_8(vm::cast(addr), (0xFF000000 & buf) >> 24);
|
|
|
|
|
buf <<= 8;
|
|
|
|
|
addr++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
reg = (reg + 1) % 32;
|
2015-03-17 21:03:24 +01:00
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STFDX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
|
|
|
|
vm::_ref<f64>(vm::cast(addr)) = ppu.fpr[op.frs];
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STFDUX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = ppu.gpr[op.ra] + ppu.gpr[op.rb];
|
|
|
|
|
vm::_ref<f64>(vm::cast(addr)) = ppu.fpr[op.frs];
|
|
|
|
|
ppu.gpr[op.ra] = addr;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LVLXL()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
return LVLX<Build, Flags...>();
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LHBRX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
|
|
|
|
ppu.gpr[op.rd] = ppu_feed_data<le_t<u16>, Flags...>(ppu, addr);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto SRAW()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
s32 RS = static_cast<s32>(ppu.gpr[op.rs]);
|
|
|
|
|
u8 shift = ppu.gpr[op.rb] & 63;
|
|
|
|
|
if (shift > 31)
|
|
|
|
|
{
|
|
|
|
|
ppu.gpr[op.ra] = 0 - (RS < 0);
|
2025-04-24 12:41:04 +02:00
|
|
|
ppu.xer_ca = (RS < 0);
|
2025-04-05 21:50:45 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ppu.gpr[op.ra] = RS >> shift;
|
2025-04-24 12:41:04 +02:00
|
|
|
ppu.xer_ca = (RS < 0) && ((ppu.gpr[op.ra] << shift) != static_cast<u64>(RS));
|
2025-04-05 21:50:45 +02:00
|
|
|
}
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto SRAD()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
s64 RS = ppu.gpr[op.rs];
|
|
|
|
|
u8 shift = ppu.gpr[op.rb] & 127;
|
|
|
|
|
if (shift > 63)
|
|
|
|
|
{
|
|
|
|
|
ppu.gpr[op.ra] = 0 - (RS < 0);
|
2025-04-24 12:41:04 +02:00
|
|
|
ppu.xer_ca = (RS < 0);
|
2025-04-05 21:50:45 +02:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ppu.gpr[op.ra] = RS >> shift;
|
2025-04-24 12:41:04 +02:00
|
|
|
ppu.xer_ca = (RS < 0) && ((ppu.gpr[op.ra] << shift) != static_cast<u64>(RS));
|
2025-04-05 21:50:45 +02:00
|
|
|
}
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LVRXL()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
return LVRX<Build, Flags...>();
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto DSS()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](auto&&, auto) {};
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto SRAWI()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
s32 RS = static_cast<u32>(ppu.gpr[op.rs]);
|
|
|
|
|
ppu.gpr[op.ra] = RS >> op.sh32;
|
2025-04-24 12:41:04 +02:00
|
|
|
ppu.xer_ca = (RS < 0) && (static_cast<u32>(ppu.gpr[op.ra] << op.sh32) != static_cast<u32>(RS));
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto SRADI()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
auto sh = op.sh64;
|
|
|
|
|
s64 RS = ppu.gpr[op.rs];
|
|
|
|
|
ppu.gpr[op.ra] = RS >> sh;
|
2025-04-24 12:41:04 +02:00
|
|
|
ppu.xer_ca = (RS < 0) && ((ppu.gpr[op.ra] << sh) != static_cast<u64>(RS));
|
2015-03-17 21:03:24 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto EIEIO()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](auto&&, auto)
|
|
|
|
|
{
|
|
|
|
|
atomic_fence_seq_cst();
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STVLXL()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
return STVLX<Build, Flags...>();
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STHBRX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
|
|
|
|
vm::_ref<le_t<u16>>(vm::cast(addr)) = static_cast<u16>(ppu.gpr[op.rs]);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto EXTSH()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.gpr[op.ra] = static_cast<s16>(ppu.gpr[op.rs]);
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STVRXL()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
return STVRX<Build, Flags...>();
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto EXTSB()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.gpr[op.ra] = static_cast<s8>(ppu.gpr[op.rs]);
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STFIWX()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
|
|
|
|
PPU_WRITE_32(vm::cast(addr), static_cast<u32>(std::bit_cast<u64>(ppu.fpr[op.frs])));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto EXTSW()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.gpr[op.ra] = static_cast<s32>(ppu.gpr[op.rs]);
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto ICBI()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](auto&&, auto) {};
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto DCBZ()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
2020-09-02 23:58:29 +02:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
const u64 addr = op.ra ? ppu.gpr[op.ra] + ppu.gpr[op.rb] : ppu.gpr[op.rb];
|
|
|
|
|
const u32 addr0 = vm::cast(addr) & ~127;
|
|
|
|
|
|
|
|
|
|
if (g_cfg.core.accurate_cache_line_stores)
|
|
|
|
|
{
|
|
|
|
|
alignas(64) static constexpr u8 zero_buf[128]{};
|
|
|
|
|
do_cell_atomic_128_store(addr0, zero_buf);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-09-02 23:58:29 +02:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
std::memset(vm::base(addr0), 0, 128);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LWZ()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra || 1 ? ppu.gpr[op.ra] + op.simm16 : op.simm16;
|
|
|
|
|
ppu.gpr[op.rd] = ppu_feed_data<u32, Flags...>(ppu, addr);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LWZU()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = ppu.gpr[op.ra] + op.simm16;
|
|
|
|
|
ppu.gpr[op.rd] = ppu_feed_data<u32, Flags...>(ppu, addr);
|
|
|
|
|
ppu.gpr[op.ra] = addr;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LBZ()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra || 1 ? ppu.gpr[op.ra] + op.simm16 : op.simm16;
|
|
|
|
|
ppu.gpr[op.rd] = ppu_feed_data<u8, Flags...>(ppu, addr);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LBZU()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = ppu.gpr[op.ra] + op.simm16;
|
|
|
|
|
ppu.gpr[op.rd] = ppu_feed_data<u8, Flags...>(ppu, addr);
|
|
|
|
|
ppu.gpr[op.ra] = addr;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STW()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
2018-06-23 18:44:47 +02:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
const u64 addr = op.ra || 1 ? ppu.gpr[op.ra] + op.simm16 : op.simm16;
|
|
|
|
|
const u32 value = static_cast<u32>(ppu.gpr[op.rs]);
|
|
|
|
|
PPU_WRITE_32(vm::cast(addr), value);
|
2018-06-23 18:44:47 +02:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
// Insomniac engine v3 & v4 (newer R&C, Fuse, Resitance 3)
|
|
|
|
|
if (value == 0xAAAAAAAA) [[unlikely]]
|
|
|
|
|
{
|
|
|
|
|
vm::reservation_update(vm::cast(addr));
|
|
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STWU()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = ppu.gpr[op.ra] + op.simm16;
|
|
|
|
|
PPU_WRITE_32(vm::cast(addr), static_cast<u32>(ppu.gpr[op.rs]));
|
|
|
|
|
ppu.gpr[op.ra] = addr;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STB()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra || 1 ? ppu.gpr[op.ra] + op.simm16 : op.simm16;
|
|
|
|
|
PPU_WRITE_8(vm::cast(addr), static_cast<u8>(ppu.gpr[op.rs]));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STBU()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = ppu.gpr[op.ra] + op.simm16;
|
|
|
|
|
PPU_WRITE_8(vm::cast(addr), static_cast<u8>(ppu.gpr[op.rs]));
|
|
|
|
|
ppu.gpr[op.ra] = addr;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LHZ()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra || 1 ? ppu.gpr[op.ra] + op.simm16 : op.simm16;
|
|
|
|
|
ppu.gpr[op.rd] = ppu_feed_data<u16, Flags...>(ppu, addr);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LHZU()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = ppu.gpr[op.ra] + op.simm16;
|
|
|
|
|
ppu.gpr[op.rd] = ppu_feed_data<u16, Flags...>(ppu, addr);
|
|
|
|
|
ppu.gpr[op.ra] = addr;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LHA()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra || 1 ? ppu.gpr[op.ra] + op.simm16 : op.simm16;
|
|
|
|
|
ppu.gpr[op.rd] = ppu_feed_data<s16, Flags...>(ppu, addr);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LHAU()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = ppu.gpr[op.ra] + op.simm16;
|
|
|
|
|
ppu.gpr[op.rd] = ppu_feed_data<s16, Flags...>(ppu, addr);
|
|
|
|
|
ppu.gpr[op.ra] = addr;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STH()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra || 1 ? ppu.gpr[op.ra] + op.simm16 : op.simm16;
|
|
|
|
|
PPU_WRITE_16(vm::cast(addr), static_cast<u16>(ppu.gpr[op.rs]));
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STHU()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = ppu.gpr[op.ra] + op.simm16;
|
|
|
|
|
PPU_WRITE_16(vm::cast(addr), static_cast<u16>(ppu.gpr[op.rs]));
|
|
|
|
|
ppu.gpr[op.ra] = addr;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LMW()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
u64 addr = op.ra ? ppu.gpr[op.ra] + op.simm16 : op.simm16;
|
|
|
|
|
for (u32 i = op.rd; i < 32; ++i, addr += 4)
|
|
|
|
|
{
|
|
|
|
|
ppu.gpr[i] = ppu_feed_data<u32, Flags...>(ppu, addr);
|
|
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STMW()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
2015-03-17 21:03:24 +01:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
u64 addr = op.ra ? ppu.gpr[op.ra] + op.simm16 : op.simm16;
|
|
|
|
|
for (u32 i = op.rs; i < 32; ++i, addr += 4)
|
|
|
|
|
{
|
|
|
|
|
PPU_WRITE_32(vm::cast(addr), static_cast<u32>(ppu.gpr[i]));
|
|
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LFS()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra || 1 ? ppu.gpr[op.ra] + op.simm16 : op.simm16;
|
|
|
|
|
ppu.fpr[op.frd] = ppu_feed_data<f32, Flags...>(ppu, addr);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LFSU()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = ppu.gpr[op.ra] + op.simm16;
|
|
|
|
|
ppu.fpr[op.frd] = ppu_feed_data<f32, Flags...>(ppu, addr);
|
|
|
|
|
ppu.gpr[op.ra] = addr;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LFD()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra || 1 ? ppu.gpr[op.ra] + op.simm16 : op.simm16;
|
|
|
|
|
ppu.fpr[op.frd] = ppu_feed_data<f64, Flags...>(ppu, addr);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LFDU()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = ppu.gpr[op.ra] + op.simm16;
|
|
|
|
|
ppu.fpr[op.frd] = ppu_feed_data<f64, Flags...>(ppu, addr);
|
|
|
|
|
ppu.gpr[op.ra] = addr;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STFS()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra || 1 ? ppu.gpr[op.ra] + op.simm16 : op.simm16;
|
|
|
|
|
vm::_ref<f32>(vm::cast(addr)) = static_cast<float>(ppu.fpr[op.frs]);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STFSU()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = ppu.gpr[op.ra] + op.simm16;
|
|
|
|
|
vm::_ref<f32>(vm::cast(addr)) = static_cast<float>(ppu.fpr[op.frs]);
|
|
|
|
|
ppu.gpr[op.ra] = addr;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STFD()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = op.ra || 1 ? ppu.gpr[op.ra] + op.simm16 : op.simm16;
|
|
|
|
|
vm::_ref<f64>(vm::cast(addr)) = ppu.fpr[op.frs];
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STFDU()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = ppu.gpr[op.ra] + op.simm16;
|
|
|
|
|
vm::_ref<f64>(vm::cast(addr)) = ppu.fpr[op.frs];
|
|
|
|
|
ppu.gpr[op.ra] = addr;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LD()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = (op.simm16 & ~3) + (op.ra ? ppu.gpr[op.ra] : 0);
|
|
|
|
|
ppu.gpr[op.rd] = ppu_feed_data<u64, Flags...>(ppu, addr);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LDU()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = ppu.gpr[op.ra] + (op.simm16 & ~3);
|
|
|
|
|
ppu.gpr[op.rd] = ppu_feed_data<u64, Flags...>(ppu, addr);
|
|
|
|
|
ppu.gpr[op.ra] = addr;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto LWA()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
2022-06-07 11:23:08 +02:00
|
|
|
return ppu_exec_select<Flags...>::template select<use_feed_data>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = (op.simm16 & ~3) + (op.ra ? ppu.gpr[op.ra] : 0);
|
|
|
|
|
ppu.gpr[op.rd] = ppu_feed_data<s32, Flags...>(ppu, addr);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STD()
|
2016-04-25 12:49:12 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = (op.simm16 & ~3) + (op.ra ? ppu.gpr[op.ra] : 0);
|
|
|
|
|
PPU_WRITE_64(vm::cast(addr), ppu.gpr[op.rs]);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2016-04-25 12:49:12 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto STDU()
|
2016-04-25 12:49:12 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 addr = ppu.gpr[op.ra] + (op.simm16 & ~3);
|
|
|
|
|
PPU_WRITE_64(vm::cast(addr), ppu.gpr[op.rs]);
|
|
|
|
|
ppu.gpr[op.ra] = addr;
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2016-04-25 12:49:12 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FDIVS()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_fpcc>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.fpr[op.frd] = f32(ppu.fpr[op.fra] / ppu.fpr[op.frb]);
|
|
|
|
|
ppu_set_fpcc<Flags...>(ppu, ppu.fpr[op.frd], 0.);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FSUBS()
|
2019-04-18 10:58:08 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_fpcc>();
|
2019-04-18 10:58:08 +02:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.fpr[op.frd] = f32(ppu.fpr[op.fra] - ppu.fpr[op.frb]);
|
|
|
|
|
ppu_set_fpcc<Flags...>(ppu, ppu.fpr[op.frd], 0.);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FADDS()
|
2019-04-18 10:58:08 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_fpcc>();
|
2019-04-18 10:58:08 +02:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.fpr[op.frd] = f32(ppu.fpr[op.fra] + ppu.fpr[op.frb]);
|
|
|
|
|
ppu_set_fpcc<Flags...>(ppu, ppu.fpr[op.frd], 0.);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FSQRTS()
|
2019-04-18 10:58:08 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_fpcc>();
|
2019-04-18 10:58:08 +02:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.fpr[op.frd] = f32(std::sqrt(ppu.fpr[op.frb]));
|
|
|
|
|
ppu_set_fpcc<Flags...>(ppu, ppu.fpr[op.frd], 0.);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FRES()
|
2019-04-18 10:58:08 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_fpcc>();
|
2019-04-18 10:58:08 +02:00
|
|
|
|
2022-05-10 12:38:07 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const f64 a = ppu.fpr[op.frb];
|
|
|
|
|
const u64 b = std::bit_cast<u64>(a);
|
|
|
|
|
const u64 e = (b >> 52) & 0x7ff; // double exp
|
2025-04-05 21:50:45 +02:00
|
|
|
const u64 i = (b >> 45) & 0x7f; // mantissa LUT index
|
2022-05-10 12:38:07 +02:00
|
|
|
const u64 r = e >= (0x3ff + 0x80) ? 0 : (0x7ff - 2 - e) << 52 | u64{ppu_fres_mantissas[i]} << (32 - 3);
|
|
|
|
|
|
|
|
|
|
ppu.fpr[op.frd] = f32(std::bit_cast<f64>(a == a ? (b & 0x8000'0000'0000'0000) | r : (0x8'0000'0000'0000 | b)));
|
|
|
|
|
ppu_set_fpcc<Flags...>(ppu, ppu.fpr[op.frd], 0.);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FMULS()
|
2019-04-18 10:58:08 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_fpcc>();
|
2019-04-18 10:58:08 +02:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.fpr[op.frd] = f32(ppu.fpr[op.fra] * ppu.fpr[op.frc]);
|
|
|
|
|
ppu_set_fpcc<Flags...>(ppu, ppu.fpr[op.frd], 0.);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FMADDS()
|
2019-04-18 10:58:08 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_fpcc>();
|
2019-04-18 10:58:08 +02:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
if constexpr (((Flags == use_dfma) || ...))
|
|
|
|
|
ppu.fpr[op.frd] = f32(std::fma(ppu.fpr[op.fra], ppu.fpr[op.frc], ppu.fpr[op.frb]));
|
|
|
|
|
else
|
|
|
|
|
ppu.fpr[op.frd] = f32(ppu.fpr[op.fra] * ppu.fpr[op.frc] + ppu.fpr[op.frb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
ppu_set_fpcc<Flags...>(ppu, ppu.fpr[op.frd], 0.);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2019-04-18 10:58:08 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FMSUBS()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_fpcc, use_dfma>();
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
if constexpr (((Flags == use_dfma) || ...))
|
|
|
|
|
ppu.fpr[op.frd] = f32(std::fma(ppu.fpr[op.fra], ppu.fpr[op.frc], -ppu.fpr[op.frb]));
|
|
|
|
|
else
|
|
|
|
|
ppu.fpr[op.frd] = f32(ppu.fpr[op.fra] * ppu.fpr[op.frc] - ppu.fpr[op.frb]);
|
2019-04-18 10:58:08 +02:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
ppu_set_fpcc<Flags...>(ppu, ppu.fpr[op.frd], 0.);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FNMSUBS()
|
2019-04-18 10:58:08 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_fpcc, use_dfma>();
|
2019-04-18 10:58:08 +02:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
if constexpr (((Flags == use_dfma) || ...))
|
|
|
|
|
ppu.fpr[op.frd] = f32(-std::fma(ppu.fpr[op.fra], ppu.fpr[op.frc], -ppu.fpr[op.frb]));
|
|
|
|
|
else
|
|
|
|
|
ppu.fpr[op.frd] = f32(-(ppu.fpr[op.fra] * ppu.fpr[op.frc] - ppu.fpr[op.frb]));
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
ppu_set_fpcc<Flags...>(ppu, ppu.fpr[op.frd], 0.);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2019-04-18 10:58:08 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FNMADDS()
|
2019-04-18 10:58:08 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_fpcc, use_dfma>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
if constexpr (((Flags == use_dfma) || ...))
|
|
|
|
|
ppu.fpr[op.frd] = f32(-std::fma(ppu.fpr[op.fra], ppu.fpr[op.frc], ppu.fpr[op.frb]));
|
|
|
|
|
else
|
|
|
|
|
ppu.fpr[op.frd] = f32(-(ppu.fpr[op.fra] * ppu.fpr[op.frc] + ppu.fpr[op.frb]));
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
ppu_set_fpcc<Flags...>(ppu, ppu.fpr[op.frd], 0.);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto MTFSB1()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u32 bit = op.crbd;
|
|
|
|
|
if (bit < 16 || bit > 19)
|
|
|
|
|
ppu_log.warning("MTFSB1(%d)", bit);
|
|
|
|
|
ppu.fpscr.bits[bit] = 1;
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto MCRFS()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
if (op.crfs != 4)
|
|
|
|
|
ppu_log.warning("MCRFS(%d)", op.crfs);
|
|
|
|
|
ppu.cr.fields[op.crfd] = ppu.fpscr.fields[op.crfs];
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto MTFSB0()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u32 bit = op.crbd;
|
|
|
|
|
if (bit < 16 || bit > 19)
|
|
|
|
|
ppu_log.warning("MTFSB0(%d)", bit);
|
|
|
|
|
ppu.fpscr.bits[bit] = 0;
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto MTFSFI()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
2019-03-19 09:20:02 +01:00
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
const u32 bf = op.crfd;
|
2019-04-18 10:58:08 +02:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
if (bf != 4)
|
|
|
|
|
{
|
|
|
|
|
// Do nothing on non-FPCC field (TODO)
|
|
|
|
|
ppu_log.warning("MTFSFI(%d)", op.crfd);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2025-04-24 12:41:04 +02:00
|
|
|
static constexpr auto all_values = []
|
2019-04-18 10:58:08 +02:00
|
|
|
{
|
2025-04-24 12:41:04 +02:00
|
|
|
std::array<CrField, 16> values{};
|
2025-04-05 21:50:45 +02:00
|
|
|
|
|
|
|
|
for (u32 i = 0; i < values.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
u32 value = 0, im = i;
|
|
|
|
|
value |= (im & 1) << (8 * 3);
|
|
|
|
|
im >>= 1;
|
|
|
|
|
value |= (im & 1) << (8 * 2);
|
|
|
|
|
im >>= 1;
|
|
|
|
|
value |= (im & 1) << (8 * 1);
|
|
|
|
|
im >>= 1;
|
|
|
|
|
value |= (im & 1) << (8 * 0);
|
2025-04-24 12:41:04 +02:00
|
|
|
values[i] = std::bit_cast<CrField>(value);
|
2025-04-05 21:50:45 +02:00
|
|
|
}
|
2019-04-18 10:58:08 +02:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
return values;
|
|
|
|
|
}();
|
2019-04-18 10:58:08 +02:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
ppu.fpscr.fields[bf] = all_values[op.i];
|
|
|
|
|
}
|
2019-03-19 09:20:02 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto MFFS()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu_log.warning("MFFS");
|
|
|
|
|
ppu.fpr[op.frd] = std::bit_cast<f64>(u64{ppu.fpscr.fl} << 15 | u64{ppu.fpscr.fg} << 14 | u64{ppu.fpscr.fe} << 13 | u64{ppu.fpscr.fu} << 12);
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto MTFSF()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](auto&& ppu, auto)
|
|
|
|
|
{
|
|
|
|
|
ppu_log.warning("MTFSF");
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FCMPU()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const f64 a = ppu.fpr[op.fra];
|
|
|
|
|
const f64 b = ppu.fpr[op.frb];
|
|
|
|
|
ppu_set_fpcc<set_fpcc, has_rc, Flags...>(ppu, a, b, op.crfd);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FCTIW()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_fpcc>();
|
|
|
|
|
|
2022-01-21 14:07:48 +01:00
|
|
|
static const auto exec = [](ppu_thread& ppu, auto&& d, auto&& b)
|
|
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
#if defined(ARCH_X64)
|
2022-01-21 14:07:48 +01:00
|
|
|
const auto val = _mm_set_sd(b);
|
|
|
|
|
const auto res = _mm_xor_si128(_mm_cvtpd_epi32(val), _mm_castpd_si128(_mm_cmpge_pd(val, _mm_set1_pd(0x80000000))));
|
|
|
|
|
d = std::bit_cast<f64, s64>(_mm_cvtsi128_si32(res));
|
2025-04-05 21:50:45 +02:00
|
|
|
#elif defined(ARCH_ARM64)
|
2022-01-21 14:07:48 +01:00
|
|
|
d = std::bit_cast<f64, s64>(!(b == b) ? INT32_MIN : vqmovnd_s64(std::bit_cast<f64>(vrndi_f64(std::bit_cast<float64x1_t>(b)))));
|
2025-04-05 21:50:45 +02:00
|
|
|
#endif
|
2022-01-21 14:07:48 +01:00
|
|
|
ppu_set_fpcc<Flags...>(ppu, 0., 0.); // undefined (TODO)
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-21 14:07:48 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu, ppu.fpr[op.frd], ppu.fpr[op.frb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FCTIWZ()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_fpcc>();
|
|
|
|
|
|
2022-01-21 14:07:48 +01:00
|
|
|
static const auto exec = [](ppu_thread& ppu, auto&& d, auto&& b)
|
|
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
#if defined(ARCH_X64)
|
2022-01-21 14:07:48 +01:00
|
|
|
const auto val = _mm_set_sd(b);
|
|
|
|
|
const auto res = _mm_xor_si128(_mm_cvttpd_epi32(val), _mm_castpd_si128(_mm_cmpge_pd(val, _mm_set1_pd(0x80000000))));
|
|
|
|
|
d = std::bit_cast<f64, s64>(_mm_cvtsi128_si32(res));
|
2025-04-05 21:50:45 +02:00
|
|
|
#elif defined(ARCH_ARM64)
|
2022-01-21 14:07:48 +01:00
|
|
|
d = std::bit_cast<f64, s64>(!(b == b) ? INT32_MIN : vqmovnd_s64(std::bit_cast<s64>(vcvt_s64_f64(std::bit_cast<float64x1_t>(b)))));
|
2025-04-05 21:50:45 +02:00
|
|
|
#endif
|
2022-01-21 14:07:48 +01:00
|
|
|
ppu_set_fpcc<Flags...>(ppu, 0., 0.); // undefined (TODO)
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-21 14:07:48 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu, ppu.fpr[op.frd], ppu.fpr[op.frb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FRSP()
|
2019-04-18 10:58:08 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_fpcc>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.fpr[op.frd] = f32(ppu.fpr[op.frb]);
|
|
|
|
|
ppu_set_fpcc<Flags...>(ppu, ppu.fpr[op.frd], 0.);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2019-04-18 10:58:08 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FDIV()
|
2019-04-18 10:58:08 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_fpcc>();
|
2019-04-18 10:58:08 +02:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.fpr[op.frd] = ppu.fpr[op.fra] / ppu.fpr[op.frb];
|
|
|
|
|
ppu_set_fpcc<Flags...>(ppu, ppu.fpr[op.frd], 0.);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FSUB()
|
2019-04-18 10:58:08 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_fpcc>();
|
2019-04-18 10:58:08 +02:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.fpr[op.frd] = ppu.fpr[op.fra] - ppu.fpr[op.frb];
|
|
|
|
|
ppu_set_fpcc<Flags...>(ppu, ppu.fpr[op.frd], 0.);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FADD()
|
2019-04-18 10:58:08 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_fpcc>();
|
2019-04-18 10:58:08 +02:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.fpr[op.frd] = ppu.fpr[op.fra] + ppu.fpr[op.frb];
|
|
|
|
|
ppu_set_fpcc<Flags...>(ppu, ppu.fpr[op.frd], 0.);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FSQRT()
|
2019-04-18 10:58:08 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_fpcc>();
|
2019-04-18 10:58:08 +02:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.fpr[op.frd] = std::sqrt(ppu.fpr[op.frb]);
|
|
|
|
|
ppu_set_fpcc<Flags...>(ppu, ppu.fpr[op.frd], 0.);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2019-04-18 10:58:08 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FSEL()
|
2019-04-18 10:58:08 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.fpr[op.frd] = ppu.fpr[op.fra] >= 0.0 ? ppu.fpr[op.frc] : ppu.fpr[op.frb];
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FMUL()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_fpcc>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.fpr[op.frd] = ppu.fpr[op.fra] * ppu.fpr[op.frc];
|
|
|
|
|
ppu_set_fpcc<Flags...>(ppu, ppu.fpr[op.frd], 0.);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FRSQRTE()
|
2019-04-18 10:58:08 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_fpcc>();
|
2019-04-18 10:58:08 +02:00
|
|
|
|
2019-12-25 15:12:48 +01:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
const u64 b = std::bit_cast<u64>(ppu.fpr[op.frb]);
|
|
|
|
|
ppu.fpr[op.frd] = std::bit_cast<f64>(u64{ppu_frqrte_lut.data[b >> 49]} << 32);
|
|
|
|
|
ppu_set_fpcc<Flags...>(ppu, ppu.fpr[op.frd], 0.);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2019-12-25 15:12:48 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FMSUB()
|
2019-04-18 10:58:08 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_fpcc, use_dfma>();
|
2019-04-18 10:58:08 +02:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
if constexpr (((Flags == use_dfma) || ...))
|
|
|
|
|
ppu.fpr[op.frd] = std::fma(ppu.fpr[op.fra], ppu.fpr[op.frc], -ppu.fpr[op.frb]);
|
|
|
|
|
else
|
|
|
|
|
ppu.fpr[op.frd] = ppu.fpr[op.fra] * ppu.fpr[op.frc] - ppu.fpr[op.frb];
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
ppu_set_fpcc<Flags...>(ppu, ppu.fpr[op.frd], 0.);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2019-04-18 10:58:08 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FMADD()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_fpcc, use_dfma>();
|
2015-03-16 22:38:21 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
if constexpr (((Flags == use_dfma) || ...))
|
|
|
|
|
ppu.fpr[op.frd] = std::fma(ppu.fpr[op.fra], ppu.fpr[op.frc], ppu.fpr[op.frb]);
|
|
|
|
|
else
|
|
|
|
|
ppu.fpr[op.frd] = ppu.fpr[op.fra] * ppu.fpr[op.frc] + ppu.fpr[op.frb];
|
2019-04-18 10:58:08 +02:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
ppu_set_fpcc<Flags...>(ppu, ppu.fpr[op.frd], 0.);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FNMSUB()
|
2019-04-18 10:58:08 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_fpcc, use_dfma>();
|
2019-04-18 10:58:08 +02:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
if constexpr (((Flags == use_dfma) || ...))
|
|
|
|
|
ppu.fpr[op.frd] = -std::fma(ppu.fpr[op.fra], ppu.fpr[op.frc], -ppu.fpr[op.frb]);
|
|
|
|
|
else
|
|
|
|
|
ppu.fpr[op.frd] = -(ppu.fpr[op.fra] * ppu.fpr[op.frc] - ppu.fpr[op.frb]);
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
ppu_set_fpcc<Flags...>(ppu, ppu.fpr[op.frd], 0.);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2019-04-18 10:58:08 +02:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FNMADD()
|
2019-04-18 10:58:08 +02:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_fpcc, use_dfma>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
if constexpr (((Flags == use_dfma) || ...))
|
|
|
|
|
ppu.fpr[op.frd] = -std::fma(ppu.fpr[op.fra], ppu.fpr[op.frc], ppu.fpr[op.frb]);
|
|
|
|
|
else
|
|
|
|
|
ppu.fpr[op.frd] = -(ppu.fpr[op.fra] * ppu.fpr[op.frc] + ppu.fpr[op.frb]);
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
ppu_set_fpcc<Flags...>(ppu, ppu.fpr[op.frd], 0.);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FCMPO()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
return FCMPU<Build, Flags...>();
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FNEG()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<use_dfma>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.fpr[op.frd] = -ppu.fpr[op.frb];
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FMR()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.fpr[op.frd] = ppu.fpr[op.frb];
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FNABS()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.fpr[op.frd] = -std::fabs(ppu.fpr[op.frb]);
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FABS()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op)
|
|
|
|
|
{
|
|
|
|
|
ppu.fpr[op.frd] = std::fabs(ppu.fpr[op.frb]);
|
|
|
|
|
if constexpr (((Flags == has_rc) || ...))
|
|
|
|
|
ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
|
|
|
|
RETURN_(ppu, op);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FCTID()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_fpcc>();
|
|
|
|
|
|
2022-01-21 14:07:48 +01:00
|
|
|
static const auto exec = [](ppu_thread& ppu, auto&& d, auto&& b)
|
|
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
#if defined(ARCH_X64)
|
2022-01-21 14:07:48 +01:00
|
|
|
const auto val = _mm_set_sd(b);
|
|
|
|
|
const auto res = _mm_xor_si128(_mm_set1_epi64x(_mm_cvtsd_si64(val)), _mm_castpd_si128(_mm_cmpge_pd(val, _mm_set1_pd(f64(1ull << 63)))));
|
|
|
|
|
d = std::bit_cast<f64>(_mm_cvtsi128_si64(res));
|
2025-04-05 21:50:45 +02:00
|
|
|
#elif defined(ARCH_ARM64)
|
2022-01-21 14:07:48 +01:00
|
|
|
d = std::bit_cast<f64, s64>(!(b == b) ? f64{INT64_MIN} : std::bit_cast<f64>(vrndi_f64(std::bit_cast<float64x1_t>(b))));
|
2025-04-05 21:50:45 +02:00
|
|
|
#endif
|
2022-01-21 14:07:48 +01:00
|
|
|
ppu_set_fpcc<Flags...>(ppu, 0., 0.); // undefined (TODO)
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-21 14:07:48 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu, ppu.fpr[op.frd], ppu.fpr[op.frb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FCTIDZ()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_fpcc>();
|
|
|
|
|
|
2022-01-21 14:07:48 +01:00
|
|
|
static const auto exec = [](ppu_thread& ppu, auto&& d, auto&& b)
|
|
|
|
|
{
|
2025-04-05 21:50:45 +02:00
|
|
|
#if defined(ARCH_X64)
|
2022-01-21 14:07:48 +01:00
|
|
|
const auto val = _mm_set_sd(b);
|
|
|
|
|
const auto res = _mm_xor_si128(_mm_set1_epi64x(_mm_cvttsd_si64(val)), _mm_castpd_si128(_mm_cmpge_pd(val, _mm_set1_pd(f64(1ull << 63)))));
|
|
|
|
|
d = std::bit_cast<f64>(_mm_cvtsi128_si64(res));
|
2025-04-05 21:50:45 +02:00
|
|
|
#elif defined(ARCH_ARM64)
|
2022-01-21 14:07:48 +01:00
|
|
|
d = std::bit_cast<f64>(!(b == b) ? int64x1_t{INT64_MIN} : vcvt_s64_f64(std::bit_cast<float64x1_t>(b)));
|
2025-04-05 21:50:45 +02:00
|
|
|
#endif
|
2022-01-21 14:07:48 +01:00
|
|
|
ppu_set_fpcc<Flags...>(ppu, 0., 0.); // undefined (TODO)
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-21 14:07:48 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu, ppu.fpr[op.frd], ppu.fpr[op.frb]);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto FCFID()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<set_fpcc>();
|
|
|
|
|
|
2022-01-21 14:07:48 +01:00
|
|
|
static const auto exec = [](ppu_thread& ppu, auto&& d, auto&& b)
|
|
|
|
|
{
|
2024-06-30 10:35:36 +02:00
|
|
|
f64 r = static_cast<f64>(std::bit_cast<s64>(b));
|
2022-01-21 14:07:48 +01:00
|
|
|
d = r;
|
|
|
|
|
ppu_set_fpcc<Flags...>(ppu, r, 0.);
|
2021-12-30 17:39:18 +01:00
|
|
|
};
|
2022-01-21 14:07:48 +01:00
|
|
|
|
|
|
|
|
RETURN_(ppu, ppu.fpr[op.frd], ppu.fpr[op.frb]);
|
2021-12-30 17:39:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <u32 Build, ppu_exec_bit... Flags>
|
|
|
|
|
auto UNK()
|
|
|
|
|
{
|
|
|
|
|
if constexpr (Build == 0xf1a6)
|
|
|
|
|
return ppu_exec_select<Flags...>::template select<>();
|
|
|
|
|
|
|
|
|
|
if constexpr (Build == 0)
|
|
|
|
|
{
|
|
|
|
|
return +[](ppu_thread& ppu, ppu_opcode_t op, be_t<u32>* this_op, ppu_intrp_func*)
|
|
|
|
|
{
|
|
|
|
|
const u32 old_cia = ppu.cia;
|
|
|
|
|
ppu.cia = vm::get_addr(this_op);
|
|
|
|
|
ppu.exec_bytes += ppu.cia - old_cia;
|
|
|
|
|
|
|
|
|
|
// HLE function index
|
|
|
|
|
const u32 index = (ppu.cia - g_fxo->get<ppu_function_manager>().addr) / 8;
|
|
|
|
|
|
|
|
|
|
const auto& hle_funcs = ppu_function_manager::get();
|
|
|
|
|
|
|
|
|
|
if (ppu.cia % 8 == 4 && index < hle_funcs.size())
|
|
|
|
|
{
|
|
|
|
|
return hle_funcs[index](ppu, op, this_op, nullptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fmt::throw_exception("Unknown/Illegal opcode: 0x%08x at 0x%x", op.opcode, ppu.cia);
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <typename IT>
|
|
|
|
|
struct ppu_interpreter_t
|
|
|
|
|
{
|
|
|
|
|
IT MFVSCR;
|
|
|
|
|
IT MTVSCR;
|
|
|
|
|
IT VADDCUW;
|
|
|
|
|
IT VADDFP;
|
|
|
|
|
IT VADDSBS;
|
|
|
|
|
IT VADDSHS;
|
|
|
|
|
IT VADDSWS;
|
|
|
|
|
IT VADDUBM;
|
|
|
|
|
IT VADDUBS;
|
|
|
|
|
IT VADDUHM;
|
|
|
|
|
IT VADDUHS;
|
|
|
|
|
IT VADDUWM;
|
|
|
|
|
IT VADDUWS;
|
|
|
|
|
IT VAND;
|
|
|
|
|
IT VANDC;
|
|
|
|
|
IT VAVGSB;
|
|
|
|
|
IT VAVGSH;
|
|
|
|
|
IT VAVGSW;
|
|
|
|
|
IT VAVGUB;
|
|
|
|
|
IT VAVGUH;
|
|
|
|
|
IT VAVGUW;
|
|
|
|
|
IT VCFSX;
|
|
|
|
|
IT VCFUX;
|
|
|
|
|
IT VCMPBFP;
|
|
|
|
|
IT VCMPBFP_;
|
|
|
|
|
IT VCMPEQFP;
|
|
|
|
|
IT VCMPEQFP_;
|
|
|
|
|
IT VCMPEQUB;
|
|
|
|
|
IT VCMPEQUB_;
|
|
|
|
|
IT VCMPEQUH;
|
|
|
|
|
IT VCMPEQUH_;
|
|
|
|
|
IT VCMPEQUW;
|
|
|
|
|
IT VCMPEQUW_;
|
|
|
|
|
IT VCMPGEFP;
|
|
|
|
|
IT VCMPGEFP_;
|
|
|
|
|
IT VCMPGTFP;
|
|
|
|
|
IT VCMPGTFP_;
|
|
|
|
|
IT VCMPGTSB;
|
|
|
|
|
IT VCMPGTSB_;
|
|
|
|
|
IT VCMPGTSH;
|
|
|
|
|
IT VCMPGTSH_;
|
|
|
|
|
IT VCMPGTSW;
|
|
|
|
|
IT VCMPGTSW_;
|
|
|
|
|
IT VCMPGTUB;
|
|
|
|
|
IT VCMPGTUB_;
|
|
|
|
|
IT VCMPGTUH;
|
|
|
|
|
IT VCMPGTUH_;
|
|
|
|
|
IT VCMPGTUW;
|
|
|
|
|
IT VCMPGTUW_;
|
|
|
|
|
IT VCTSXS;
|
|
|
|
|
IT VCTUXS;
|
|
|
|
|
IT VEXPTEFP;
|
|
|
|
|
IT VLOGEFP;
|
|
|
|
|
IT VMADDFP;
|
|
|
|
|
IT VMAXFP;
|
|
|
|
|
IT VMAXSB;
|
|
|
|
|
IT VMAXSH;
|
|
|
|
|
IT VMAXSW;
|
|
|
|
|
IT VMAXUB;
|
|
|
|
|
IT VMAXUH;
|
|
|
|
|
IT VMAXUW;
|
|
|
|
|
IT VMHADDSHS;
|
|
|
|
|
IT VMHRADDSHS;
|
|
|
|
|
IT VMINFP;
|
|
|
|
|
IT VMINSB;
|
|
|
|
|
IT VMINSH;
|
|
|
|
|
IT VMINSW;
|
|
|
|
|
IT VMINUB;
|
|
|
|
|
IT VMINUH;
|
|
|
|
|
IT VMINUW;
|
|
|
|
|
IT VMLADDUHM;
|
|
|
|
|
IT VMRGHB;
|
|
|
|
|
IT VMRGHH;
|
|
|
|
|
IT VMRGHW;
|
|
|
|
|
IT VMRGLB;
|
|
|
|
|
IT VMRGLH;
|
|
|
|
|
IT VMRGLW;
|
|
|
|
|
IT VMSUMMBM;
|
|
|
|
|
IT VMSUMSHM;
|
|
|
|
|
IT VMSUMSHS;
|
|
|
|
|
IT VMSUMUBM;
|
|
|
|
|
IT VMSUMUHM;
|
|
|
|
|
IT VMSUMUHS;
|
|
|
|
|
IT VMULESB;
|
|
|
|
|
IT VMULESH;
|
|
|
|
|
IT VMULEUB;
|
|
|
|
|
IT VMULEUH;
|
|
|
|
|
IT VMULOSB;
|
|
|
|
|
IT VMULOSH;
|
|
|
|
|
IT VMULOUB;
|
|
|
|
|
IT VMULOUH;
|
|
|
|
|
IT VNMSUBFP;
|
|
|
|
|
IT VNOR;
|
|
|
|
|
IT VOR;
|
|
|
|
|
IT VPERM;
|
|
|
|
|
IT VPKPX;
|
|
|
|
|
IT VPKSHSS;
|
|
|
|
|
IT VPKSHUS;
|
|
|
|
|
IT VPKSWSS;
|
|
|
|
|
IT VPKSWUS;
|
|
|
|
|
IT VPKUHUM;
|
|
|
|
|
IT VPKUHUS;
|
|
|
|
|
IT VPKUWUM;
|
|
|
|
|
IT VPKUWUS;
|
|
|
|
|
IT VREFP;
|
|
|
|
|
IT VRFIM;
|
|
|
|
|
IT VRFIN;
|
|
|
|
|
IT VRFIP;
|
|
|
|
|
IT VRFIZ;
|
|
|
|
|
IT VRLB;
|
|
|
|
|
IT VRLH;
|
|
|
|
|
IT VRLW;
|
|
|
|
|
IT VRSQRTEFP;
|
|
|
|
|
IT VSEL;
|
|
|
|
|
IT VSL;
|
|
|
|
|
IT VSLB;
|
2022-01-19 00:41:32 +01:00
|
|
|
IT VSLDOI{};
|
|
|
|
|
IT VSLDOI_[16];
|
2021-12-30 17:39:18 +01:00
|
|
|
IT VSLH;
|
|
|
|
|
IT VSLO;
|
|
|
|
|
IT VSLW;
|
|
|
|
|
IT VSPLTB;
|
|
|
|
|
IT VSPLTH;
|
|
|
|
|
IT VSPLTISB;
|
|
|
|
|
IT VSPLTISH;
|
|
|
|
|
IT VSPLTISW;
|
|
|
|
|
IT VSPLTW;
|
|
|
|
|
IT VSR;
|
|
|
|
|
IT VSRAB;
|
|
|
|
|
IT VSRAH;
|
|
|
|
|
IT VSRAW;
|
|
|
|
|
IT VSRB;
|
|
|
|
|
IT VSRH;
|
|
|
|
|
IT VSRO;
|
|
|
|
|
IT VSRW;
|
|
|
|
|
IT VSUBCUW;
|
|
|
|
|
IT VSUBFP;
|
|
|
|
|
IT VSUBSBS;
|
|
|
|
|
IT VSUBSHS;
|
|
|
|
|
IT VSUBSWS;
|
|
|
|
|
IT VSUBUBM;
|
|
|
|
|
IT VSUBUBS;
|
|
|
|
|
IT VSUBUHM;
|
|
|
|
|
IT VSUBUHS;
|
|
|
|
|
IT VSUBUWM;
|
|
|
|
|
IT VSUBUWS;
|
|
|
|
|
IT VSUMSWS;
|
|
|
|
|
IT VSUM2SWS;
|
|
|
|
|
IT VSUM4SBS;
|
|
|
|
|
IT VSUM4SHS;
|
|
|
|
|
IT VSUM4UBS;
|
|
|
|
|
IT VUPKHPX;
|
|
|
|
|
IT VUPKHSB;
|
|
|
|
|
IT VUPKHSH;
|
|
|
|
|
IT VUPKLPX;
|
|
|
|
|
IT VUPKLSB;
|
|
|
|
|
IT VUPKLSH;
|
|
|
|
|
IT VXOR;
|
|
|
|
|
IT TDI;
|
|
|
|
|
IT TWI;
|
|
|
|
|
IT MULLI;
|
|
|
|
|
IT SUBFIC;
|
|
|
|
|
IT CMPLI;
|
|
|
|
|
IT CMPI;
|
|
|
|
|
IT ADDIC;
|
|
|
|
|
IT ADDI;
|
|
|
|
|
IT ADDIS;
|
|
|
|
|
IT BC;
|
|
|
|
|
IT SC;
|
|
|
|
|
IT B;
|
|
|
|
|
IT MCRF;
|
|
|
|
|
IT BCLR;
|
|
|
|
|
IT CRNOR;
|
|
|
|
|
IT CRANDC;
|
|
|
|
|
IT ISYNC;
|
|
|
|
|
IT CRXOR;
|
|
|
|
|
IT CRNAND;
|
|
|
|
|
IT CRAND;
|
|
|
|
|
IT CREQV;
|
|
|
|
|
IT CRORC;
|
|
|
|
|
IT CROR;
|
|
|
|
|
IT BCCTR;
|
|
|
|
|
IT RLWIMI;
|
|
|
|
|
IT RLWINM;
|
|
|
|
|
IT RLWNM;
|
|
|
|
|
IT ORI;
|
|
|
|
|
IT ORIS;
|
|
|
|
|
IT XORI;
|
|
|
|
|
IT XORIS;
|
|
|
|
|
IT ANDI;
|
|
|
|
|
IT ANDIS;
|
|
|
|
|
IT RLDICL;
|
|
|
|
|
IT RLDICR;
|
|
|
|
|
IT RLDIC;
|
|
|
|
|
IT RLDIMI;
|
|
|
|
|
IT RLDCL;
|
|
|
|
|
IT RLDCR;
|
|
|
|
|
IT CMP;
|
|
|
|
|
IT TW;
|
|
|
|
|
IT LVSL;
|
|
|
|
|
IT LVEBX;
|
|
|
|
|
IT SUBFC;
|
|
|
|
|
IT ADDC;
|
|
|
|
|
IT MULHDU;
|
|
|
|
|
IT MULHWU;
|
2022-01-21 10:49:52 +01:00
|
|
|
IT MFOCRF{};
|
|
|
|
|
IT MFOCRF_[8];
|
|
|
|
|
IT MFCR; //+
|
2021-12-30 17:39:18 +01:00
|
|
|
IT LWARX;
|
|
|
|
|
IT LDX;
|
|
|
|
|
IT LWZX;
|
|
|
|
|
IT SLW;
|
|
|
|
|
IT CNTLZW;
|
|
|
|
|
IT SLD;
|
|
|
|
|
IT AND;
|
|
|
|
|
IT CMPL;
|
|
|
|
|
IT LVSR;
|
|
|
|
|
IT LVEHX;
|
|
|
|
|
IT SUBF;
|
|
|
|
|
IT LDUX;
|
|
|
|
|
IT DCBST;
|
|
|
|
|
IT LWZUX;
|
|
|
|
|
IT CNTLZD;
|
|
|
|
|
IT ANDC;
|
|
|
|
|
IT TD;
|
|
|
|
|
IT LVEWX;
|
|
|
|
|
IT MULHD;
|
|
|
|
|
IT MULHW;
|
|
|
|
|
IT LDARX;
|
|
|
|
|
IT DCBF;
|
|
|
|
|
IT LBZX;
|
|
|
|
|
IT LVX;
|
|
|
|
|
IT NEG;
|
|
|
|
|
IT LBZUX;
|
|
|
|
|
IT NOR;
|
|
|
|
|
IT STVEBX;
|
|
|
|
|
IT SUBFE;
|
|
|
|
|
IT ADDE;
|
|
|
|
|
IT MTOCRF;
|
|
|
|
|
IT STDX;
|
|
|
|
|
IT STWCX;
|
|
|
|
|
IT STWX;
|
|
|
|
|
IT STVEHX;
|
|
|
|
|
IT STDUX;
|
|
|
|
|
IT STWUX;
|
|
|
|
|
IT STVEWX;
|
|
|
|
|
IT SUBFZE;
|
|
|
|
|
IT ADDZE;
|
|
|
|
|
IT STDCX;
|
|
|
|
|
IT STBX;
|
|
|
|
|
IT STVX;
|
|
|
|
|
IT SUBFME;
|
|
|
|
|
IT MULLD;
|
|
|
|
|
IT ADDME;
|
|
|
|
|
IT MULLW;
|
|
|
|
|
IT DCBTST;
|
|
|
|
|
IT STBUX;
|
|
|
|
|
IT ADD;
|
|
|
|
|
IT DCBT;
|
|
|
|
|
IT LHZX;
|
|
|
|
|
IT EQV;
|
|
|
|
|
IT ECIWX;
|
|
|
|
|
IT LHZUX;
|
|
|
|
|
IT XOR;
|
|
|
|
|
IT MFSPR;
|
|
|
|
|
IT LWAX;
|
|
|
|
|
IT DST;
|
|
|
|
|
IT LHAX;
|
|
|
|
|
IT LVXL;
|
|
|
|
|
IT MFTB;
|
|
|
|
|
IT LWAUX;
|
|
|
|
|
IT DSTST;
|
|
|
|
|
IT LHAUX;
|
|
|
|
|
IT STHX;
|
|
|
|
|
IT ORC;
|
|
|
|
|
IT ECOWX;
|
|
|
|
|
IT STHUX;
|
|
|
|
|
IT OR;
|
|
|
|
|
IT DIVDU;
|
|
|
|
|
IT DIVWU;
|
|
|
|
|
IT MTSPR;
|
|
|
|
|
IT DCBI;
|
|
|
|
|
IT NAND;
|
|
|
|
|
IT STVXL;
|
|
|
|
|
IT DIVD;
|
|
|
|
|
IT DIVW;
|
|
|
|
|
IT LVLX;
|
|
|
|
|
IT LDBRX;
|
|
|
|
|
IT LSWX;
|
|
|
|
|
IT LWBRX;
|
|
|
|
|
IT LFSX;
|
|
|
|
|
IT SRW;
|
|
|
|
|
IT SRD;
|
|
|
|
|
IT LVRX;
|
|
|
|
|
IT LSWI;
|
|
|
|
|
IT LFSUX;
|
|
|
|
|
IT SYNC;
|
|
|
|
|
IT LFDX;
|
|
|
|
|
IT LFDUX;
|
|
|
|
|
IT STVLX;
|
|
|
|
|
IT STDBRX;
|
|
|
|
|
IT STSWX;
|
|
|
|
|
IT STWBRX;
|
|
|
|
|
IT STFSX;
|
|
|
|
|
IT STVRX;
|
|
|
|
|
IT STFSUX;
|
|
|
|
|
IT STSWI;
|
|
|
|
|
IT STFDX;
|
|
|
|
|
IT STFDUX;
|
|
|
|
|
IT LVLXL;
|
|
|
|
|
IT LHBRX;
|
|
|
|
|
IT SRAW;
|
|
|
|
|
IT SRAD;
|
|
|
|
|
IT LVRXL;
|
|
|
|
|
IT DSS;
|
|
|
|
|
IT SRAWI;
|
|
|
|
|
IT SRADI;
|
|
|
|
|
IT EIEIO;
|
|
|
|
|
IT STVLXL;
|
|
|
|
|
IT STHBRX;
|
|
|
|
|
IT EXTSH;
|
|
|
|
|
IT STVRXL;
|
|
|
|
|
IT EXTSB;
|
|
|
|
|
IT STFIWX;
|
|
|
|
|
IT EXTSW;
|
|
|
|
|
IT ICBI;
|
|
|
|
|
IT DCBZ;
|
|
|
|
|
IT LWZ;
|
|
|
|
|
IT LWZU;
|
|
|
|
|
IT LBZ;
|
|
|
|
|
IT LBZU;
|
|
|
|
|
IT STW;
|
|
|
|
|
IT STWU;
|
|
|
|
|
IT STB;
|
|
|
|
|
IT STBU;
|
|
|
|
|
IT LHZ;
|
|
|
|
|
IT LHZU;
|
|
|
|
|
IT LHA;
|
|
|
|
|
IT LHAU;
|
|
|
|
|
IT STH;
|
|
|
|
|
IT STHU;
|
|
|
|
|
IT LMW;
|
|
|
|
|
IT STMW;
|
|
|
|
|
IT LFS;
|
|
|
|
|
IT LFSU;
|
|
|
|
|
IT LFD;
|
|
|
|
|
IT LFDU;
|
|
|
|
|
IT STFS;
|
|
|
|
|
IT STFSU;
|
|
|
|
|
IT STFD;
|
|
|
|
|
IT STFDU;
|
|
|
|
|
IT LD;
|
|
|
|
|
IT LDU;
|
|
|
|
|
IT LWA;
|
|
|
|
|
IT STD;
|
|
|
|
|
IT STDU;
|
|
|
|
|
IT FDIVS;
|
|
|
|
|
IT FSUBS;
|
|
|
|
|
IT FADDS;
|
|
|
|
|
IT FSQRTS;
|
|
|
|
|
IT FRES;
|
|
|
|
|
IT FMULS;
|
|
|
|
|
IT FMADDS;
|
|
|
|
|
IT FMSUBS;
|
|
|
|
|
IT FNMSUBS;
|
|
|
|
|
IT FNMADDS;
|
|
|
|
|
IT MTFSB1;
|
|
|
|
|
IT MCRFS;
|
|
|
|
|
IT MTFSB0;
|
|
|
|
|
IT MTFSFI;
|
|
|
|
|
IT MFFS;
|
|
|
|
|
IT MTFSF;
|
|
|
|
|
IT FCMPU;
|
|
|
|
|
IT FRSP;
|
|
|
|
|
IT FCTIW;
|
|
|
|
|
IT FCTIWZ;
|
|
|
|
|
IT FDIV;
|
|
|
|
|
IT FSUB;
|
|
|
|
|
IT FADD;
|
|
|
|
|
IT FSQRT;
|
|
|
|
|
IT FSEL;
|
|
|
|
|
IT FMUL;
|
|
|
|
|
IT FRSQRTE;
|
|
|
|
|
IT FMSUB;
|
|
|
|
|
IT FMADD;
|
|
|
|
|
IT FNMSUB;
|
|
|
|
|
IT FNMADD;
|
|
|
|
|
IT FCMPO;
|
|
|
|
|
IT FNEG;
|
|
|
|
|
IT FMR;
|
|
|
|
|
IT FNABS;
|
|
|
|
|
IT FABS;
|
|
|
|
|
IT FCTID;
|
|
|
|
|
IT FCTIDZ;
|
|
|
|
|
IT FCFID;
|
|
|
|
|
IT UNK;
|
|
|
|
|
|
|
|
|
|
IT SUBFCO;
|
|
|
|
|
IT ADDCO;
|
|
|
|
|
IT SUBFO;
|
|
|
|
|
IT NEGO;
|
|
|
|
|
IT SUBFEO;
|
|
|
|
|
IT ADDEO;
|
|
|
|
|
IT SUBFZEO;
|
|
|
|
|
IT ADDZEO;
|
|
|
|
|
IT SUBFMEO;
|
|
|
|
|
IT MULLDO;
|
|
|
|
|
IT ADDMEO;
|
|
|
|
|
IT MULLWO;
|
|
|
|
|
IT ADDO;
|
|
|
|
|
IT DIVDUO;
|
|
|
|
|
IT DIVWUO;
|
|
|
|
|
IT DIVDO;
|
|
|
|
|
IT DIVWO;
|
|
|
|
|
|
|
|
|
|
IT SUBFCO_;
|
|
|
|
|
IT ADDCO_;
|
|
|
|
|
IT SUBFO_;
|
|
|
|
|
IT NEGO_;
|
|
|
|
|
IT SUBFEO_;
|
|
|
|
|
IT ADDEO_;
|
|
|
|
|
IT SUBFZEO_;
|
|
|
|
|
IT ADDZEO_;
|
|
|
|
|
IT SUBFMEO_;
|
|
|
|
|
IT MULLDO_;
|
|
|
|
|
IT ADDMEO_;
|
|
|
|
|
IT MULLWO_;
|
|
|
|
|
IT ADDO_;
|
|
|
|
|
IT DIVDUO_;
|
|
|
|
|
IT DIVWUO_;
|
|
|
|
|
IT DIVDO_;
|
|
|
|
|
IT DIVWO_;
|
|
|
|
|
|
|
|
|
|
IT RLWIMI_;
|
|
|
|
|
IT RLWINM_;
|
|
|
|
|
IT RLWNM_;
|
|
|
|
|
IT RLDICL_;
|
|
|
|
|
IT RLDICR_;
|
|
|
|
|
IT RLDIC_;
|
|
|
|
|
IT RLDIMI_;
|
|
|
|
|
IT RLDCL_;
|
|
|
|
|
IT RLDCR_;
|
|
|
|
|
IT SUBFC_;
|
|
|
|
|
IT MULHDU_;
|
|
|
|
|
IT ADDC_;
|
|
|
|
|
IT MULHWU_;
|
|
|
|
|
IT SLW_;
|
|
|
|
|
IT CNTLZW_;
|
|
|
|
|
IT SLD_;
|
|
|
|
|
IT AND_;
|
|
|
|
|
IT SUBF_;
|
|
|
|
|
IT CNTLZD_;
|
|
|
|
|
IT ANDC_;
|
|
|
|
|
IT MULHD_;
|
|
|
|
|
IT MULHW_;
|
|
|
|
|
IT NEG_;
|
|
|
|
|
IT NOR_;
|
|
|
|
|
IT SUBFE_;
|
|
|
|
|
IT ADDE_;
|
|
|
|
|
IT SUBFZE_;
|
|
|
|
|
IT ADDZE_;
|
|
|
|
|
IT MULLD_;
|
|
|
|
|
IT SUBFME_;
|
|
|
|
|
IT ADDME_;
|
|
|
|
|
IT MULLW_;
|
|
|
|
|
IT ADD_;
|
|
|
|
|
IT EQV_;
|
|
|
|
|
IT XOR_;
|
|
|
|
|
IT ORC_;
|
|
|
|
|
IT OR_;
|
|
|
|
|
IT DIVDU_;
|
|
|
|
|
IT DIVWU_;
|
|
|
|
|
IT NAND_;
|
|
|
|
|
IT DIVD_;
|
|
|
|
|
IT DIVW_;
|
|
|
|
|
IT SRW_;
|
|
|
|
|
IT SRD_;
|
|
|
|
|
IT SRAW_;
|
|
|
|
|
IT SRAD_;
|
|
|
|
|
IT SRAWI_;
|
|
|
|
|
IT SRADI_;
|
|
|
|
|
IT EXTSH_;
|
|
|
|
|
IT EXTSB_;
|
|
|
|
|
IT EXTSW_;
|
|
|
|
|
IT FDIVS_;
|
|
|
|
|
IT FSUBS_;
|
|
|
|
|
IT FADDS_;
|
|
|
|
|
IT FSQRTS_;
|
|
|
|
|
IT FRES_;
|
|
|
|
|
IT FMULS_;
|
|
|
|
|
IT FMADDS_;
|
|
|
|
|
IT FMSUBS_;
|
|
|
|
|
IT FNMSUBS_;
|
|
|
|
|
IT FNMADDS_;
|
|
|
|
|
IT MTFSB1_;
|
|
|
|
|
IT MTFSB0_;
|
|
|
|
|
IT MTFSFI_;
|
|
|
|
|
IT MFFS_;
|
|
|
|
|
IT MTFSF_;
|
|
|
|
|
IT FRSP_;
|
|
|
|
|
IT FCTIW_;
|
|
|
|
|
IT FCTIWZ_;
|
|
|
|
|
IT FDIV_;
|
|
|
|
|
IT FSUB_;
|
|
|
|
|
IT FADD_;
|
|
|
|
|
IT FSQRT_;
|
|
|
|
|
IT FSEL_;
|
|
|
|
|
IT FMUL_;
|
|
|
|
|
IT FRSQRTE_;
|
|
|
|
|
IT FMSUB_;
|
|
|
|
|
IT FMADD_;
|
|
|
|
|
IT FNMSUB_;
|
|
|
|
|
IT FNMADD_;
|
|
|
|
|
IT FNEG_;
|
|
|
|
|
IT FMR_;
|
|
|
|
|
IT FNABS_;
|
|
|
|
|
IT FABS_;
|
|
|
|
|
IT FCTID_;
|
|
|
|
|
IT FCTIDZ_;
|
|
|
|
|
IT FCFID_;
|
|
|
|
|
|
|
|
|
|
/* Optimized variants */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
ppu_interpreter_rt_base::ppu_interpreter_rt_base() noexcept
|
|
|
|
|
{
|
|
|
|
|
// Obtain required set of flags from settings
|
2025-10-04 21:19:57 +02:00
|
|
|
rx::EnumBitSet<ppu_exec_bit> selected{};
|
2021-12-30 17:39:18 +01:00
|
|
|
if (g_cfg.core.ppu_set_sat_bit)
|
|
|
|
|
selected += set_sat;
|
|
|
|
|
if (g_cfg.core.ppu_use_nj_bit)
|
2022-01-15 23:00:37 +01:00
|
|
|
selected += use_nj + fix_nj;
|
2022-01-15 12:30:13 +01:00
|
|
|
if (g_cfg.core.ppu_llvm_nj_fixup)
|
|
|
|
|
selected += fix_nj;
|
2021-12-30 17:39:18 +01:00
|
|
|
if (g_cfg.core.ppu_set_vnan)
|
2022-01-15 23:00:37 +01:00
|
|
|
selected += set_vnan + fix_vnan;
|
2021-12-30 17:39:18 +01:00
|
|
|
if (g_cfg.core.ppu_fix_vnan)
|
|
|
|
|
selected += fix_vnan;
|
|
|
|
|
if (g_cfg.core.ppu_set_fpcc)
|
|
|
|
|
selected += set_fpcc;
|
|
|
|
|
if (g_cfg.core.use_accurate_dfma)
|
|
|
|
|
selected += use_dfma;
|
|
|
|
|
if (g_cfg.core.ppu_debug)
|
|
|
|
|
selected += set_cr_stats; // TODO
|
2022-06-07 11:11:47 +02:00
|
|
|
if (g_cfg.core.ppu_call_history)
|
|
|
|
|
selected += set_call_history;
|
2022-06-07 11:23:08 +02:00
|
|
|
if (g_cfg.core.ppu_128_reservations_loop_max_length != 0)
|
|
|
|
|
selected += use_feed_data;
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2022-01-16 05:47:42 +01:00
|
|
|
if (selected & use_nj)
|
|
|
|
|
ppu_log.success("Enabled: Accurate Non-Java Mode");
|
|
|
|
|
else if (selected & fix_nj)
|
|
|
|
|
ppu_log.success("Enabled: Non-Java Mode Fixup");
|
|
|
|
|
if (selected & set_vnan)
|
|
|
|
|
ppu_log.success("Enabled: Accurate VNAN");
|
|
|
|
|
else if (selected & fix_vnan)
|
|
|
|
|
ppu_log.success("Enabled: VNAN Fixup");
|
|
|
|
|
if (selected & set_sat)
|
|
|
|
|
ppu_log.success("Enabled: Accurate SAT");
|
|
|
|
|
if (selected & set_fpcc)
|
|
|
|
|
ppu_log.success("Enabled: Accurate FPCC");
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
ptrs = std::make_unique<decltype(ptrs)::element_type>();
|
|
|
|
|
|
|
|
|
|
#ifndef __INTELLISENSE__
|
|
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
#define INIT_VCMP(name) \
|
2021-12-30 17:39:18 +01:00
|
|
|
ptrs->name = ::name<0>(); \
|
2025-04-05 21:50:45 +02:00
|
|
|
ptrs->name##_ = ::name<0, has_oe>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
#define INIT_OV(name) \
|
2021-12-30 17:39:18 +01:00
|
|
|
ptrs->name = ::name<0>(); \
|
2025-04-05 21:50:45 +02:00
|
|
|
ptrs->name##O = ::name<0, has_oe>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
#define INIT_RC(name) \
|
|
|
|
|
ptrs->name = ::name<0xf1a6>()(selected, []<ppu_exec_bit... Flags>() { \
|
|
|
|
|
return ::name<0, Flags...>(); \
|
|
|
|
|
}); \
|
|
|
|
|
ptrs->name##_ = ::name<0xf1a6, set_fpcc>()(selected, []<ppu_exec_bit... Flags>() { \
|
2021-12-30 17:39:18 +01:00
|
|
|
/* Minor optimization: has_rc implies set_fpcc so don't compile has_rc alone */ \
|
2025-04-05 21:50:45 +02:00
|
|
|
return ::name<0, has_rc, Flags...>(); \
|
|
|
|
|
});
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
#define INIT_RC_OV(name) \
|
|
|
|
|
ptrs->name = ::name<0>(); \
|
2021-12-30 17:39:18 +01:00
|
|
|
ptrs->name##O = ::name<0, has_oe>(); \
|
|
|
|
|
ptrs->name##_ = ::name<0, has_rc>(); \
|
2025-04-05 21:50:45 +02:00
|
|
|
ptrs->name##O_ = ::name<0, has_oe, has_rc>();
|
2021-12-30 17:39:18 +01:00
|
|
|
|
|
|
|
|
// Initialize instructions with their own sets of supported flags (except INIT_VCMP, INIT_OV, INIT_RC_OV)
|
2025-04-05 21:50:45 +02:00
|
|
|
#define INIT(name) \
|
2021-12-30 17:39:18 +01:00
|
|
|
ptrs->name = ::name<0xf1a6>()(selected, []<ppu_exec_bit... Flags>() { \
|
2025-04-05 21:50:45 +02:00
|
|
|
return ::name<0, Flags...>(); \
|
|
|
|
|
});
|
2021-12-30 17:39:18 +01:00
|
|
|
|
2025-04-05 21:50:45 +02:00
|
|
|
#define INIT_ONE(name, bits) \
|
2022-01-19 00:41:32 +01:00
|
|
|
ptrs->name##_[0b##bits] = ::name<0b##bits>::select(selected, []<ppu_exec_bit... Flags>() { \
|
2025-04-05 21:50:45 +02:00
|
|
|
return ::name<0b##bits>::impl<0, Flags...>(); \
|
|
|
|
|
});
|
2022-01-19 00:41:32 +01:00
|
|
|
|
|
|
|
|
#define INIT_PACK2(name, bits) \
|
2025-04-05 21:50:45 +02:00
|
|
|
INIT_ONE(name, bits##0) \
|
|
|
|
|
INIT_ONE(name, bits##1)
|
2022-01-19 00:41:32 +01:00
|
|
|
|
|
|
|
|
#define INIT_PACK4(name, bits) \
|
2025-04-05 21:50:45 +02:00
|
|
|
INIT_PACK2(name, bits##0) \
|
|
|
|
|
INIT_PACK2(name, bits##1)
|
2022-01-19 00:41:32 +01:00
|
|
|
|
|
|
|
|
#define INIT_PACK8(name, bits) \
|
2025-04-05 21:50:45 +02:00
|
|
|
INIT_PACK4(name, bits##0) \
|
|
|
|
|
INIT_PACK4(name, bits##1)
|
2022-01-19 00:41:32 +01:00
|
|
|
|
|
|
|
|
#define INIT_PACK16(name, bits) \
|
2025-04-05 21:50:45 +02:00
|
|
|
INIT_PACK8(name, bits##0) \
|
|
|
|
|
INIT_PACK8(name, bits##1)
|
2022-01-19 00:41:32 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
INIT(MFVSCR);
|
|
|
|
|
INIT(MTVSCR);
|
|
|
|
|
INIT(VADDCUW);
|
|
|
|
|
INIT(VADDFP);
|
|
|
|
|
INIT(VADDSBS);
|
|
|
|
|
INIT(VADDSHS);
|
|
|
|
|
INIT(VADDSWS);
|
|
|
|
|
INIT(VADDUBM);
|
|
|
|
|
INIT(VADDUBS);
|
|
|
|
|
INIT(VADDUHM);
|
|
|
|
|
INIT(VADDUHS);
|
|
|
|
|
INIT(VADDUWM);
|
|
|
|
|
INIT(VADDUWS);
|
|
|
|
|
INIT(VAND);
|
|
|
|
|
INIT(VANDC);
|
|
|
|
|
INIT(VAVGSB);
|
|
|
|
|
INIT(VAVGSH);
|
|
|
|
|
INIT(VAVGSW);
|
|
|
|
|
INIT(VAVGUB);
|
|
|
|
|
INIT(VAVGUH);
|
|
|
|
|
INIT(VAVGUW);
|
|
|
|
|
INIT(VCFSX);
|
|
|
|
|
INIT(VCFUX);
|
|
|
|
|
INIT_VCMP(VCMPBFP);
|
|
|
|
|
INIT_VCMP(VCMPEQFP);
|
|
|
|
|
INIT_VCMP(VCMPEQUB);
|
|
|
|
|
INIT_VCMP(VCMPEQUH);
|
|
|
|
|
INIT_VCMP(VCMPEQUW);
|
|
|
|
|
INIT_VCMP(VCMPGEFP);
|
|
|
|
|
INIT_VCMP(VCMPGTFP);
|
|
|
|
|
INIT_VCMP(VCMPGTSB);
|
|
|
|
|
INIT_VCMP(VCMPGTSH);
|
|
|
|
|
INIT_VCMP(VCMPGTSW);
|
|
|
|
|
INIT_VCMP(VCMPGTUB);
|
|
|
|
|
INIT_VCMP(VCMPGTUH);
|
|
|
|
|
INIT_VCMP(VCMPGTUW);
|
|
|
|
|
INIT(VCTSXS);
|
|
|
|
|
INIT(VCTUXS);
|
|
|
|
|
INIT(VEXPTEFP);
|
|
|
|
|
INIT(VLOGEFP);
|
|
|
|
|
INIT(VMADDFP);
|
|
|
|
|
INIT(VMAXFP);
|
|
|
|
|
INIT(VMAXSB);
|
|
|
|
|
INIT(VMAXSH);
|
|
|
|
|
INIT(VMAXSW);
|
|
|
|
|
INIT(VMAXUB);
|
|
|
|
|
INIT(VMAXUH);
|
|
|
|
|
INIT(VMAXUW);
|
|
|
|
|
INIT(VMHADDSHS);
|
|
|
|
|
INIT(VMHRADDSHS);
|
|
|
|
|
INIT(VMINFP);
|
|
|
|
|
INIT(VMINSB);
|
|
|
|
|
INIT(VMINSH);
|
|
|
|
|
INIT(VMINSW);
|
|
|
|
|
INIT(VMINUB);
|
|
|
|
|
INIT(VMINUH);
|
|
|
|
|
INIT(VMINUW);
|
|
|
|
|
INIT(VMLADDUHM);
|
|
|
|
|
INIT(VMRGHB);
|
|
|
|
|
INIT(VMRGHH);
|
|
|
|
|
INIT(VMRGHW);
|
|
|
|
|
INIT(VMRGLB);
|
|
|
|
|
INIT(VMRGLH);
|
|
|
|
|
INIT(VMRGLW);
|
|
|
|
|
INIT(VMSUMMBM);
|
|
|
|
|
INIT(VMSUMSHM);
|
|
|
|
|
INIT(VMSUMSHS);
|
|
|
|
|
INIT(VMSUMUBM);
|
|
|
|
|
INIT(VMSUMUHM);
|
|
|
|
|
INIT(VMSUMUHS);
|
|
|
|
|
INIT(VMULESB);
|
|
|
|
|
INIT(VMULESH);
|
|
|
|
|
INIT(VMULEUB);
|
|
|
|
|
INIT(VMULEUH);
|
|
|
|
|
INIT(VMULOSB);
|
|
|
|
|
INIT(VMULOSH);
|
|
|
|
|
INIT(VMULOUB);
|
|
|
|
|
INIT(VMULOUH);
|
|
|
|
|
INIT(VNMSUBFP);
|
|
|
|
|
INIT(VNOR);
|
|
|
|
|
INIT(VOR);
|
|
|
|
|
INIT(VPERM);
|
|
|
|
|
INIT(VPKPX);
|
|
|
|
|
INIT(VPKSHSS);
|
|
|
|
|
INIT(VPKSHUS);
|
|
|
|
|
INIT(VPKSWSS);
|
|
|
|
|
INIT(VPKSWUS);
|
|
|
|
|
INIT(VPKUHUM);
|
|
|
|
|
INIT(VPKUHUS);
|
|
|
|
|
INIT(VPKUWUM);
|
|
|
|
|
INIT(VPKUWUS);
|
|
|
|
|
INIT(VREFP);
|
|
|
|
|
INIT(VRFIM);
|
|
|
|
|
INIT(VRFIN);
|
|
|
|
|
INIT(VRFIP);
|
|
|
|
|
INIT(VRFIZ);
|
|
|
|
|
INIT(VRLB);
|
|
|
|
|
INIT(VRLH);
|
|
|
|
|
INIT(VRLW);
|
|
|
|
|
INIT(VRSQRTEFP);
|
|
|
|
|
INIT(VSEL);
|
|
|
|
|
INIT(VSL);
|
|
|
|
|
INIT(VSLB);
|
2025-04-05 21:50:45 +02:00
|
|
|
INIT_PACK16(VSLDOI, );
|
2021-12-30 17:39:18 +01:00
|
|
|
INIT(VSLH);
|
|
|
|
|
INIT(VSLO);
|
|
|
|
|
INIT(VSLW);
|
|
|
|
|
INIT(VSPLTB);
|
|
|
|
|
INIT(VSPLTH);
|
|
|
|
|
INIT(VSPLTISB);
|
|
|
|
|
INIT(VSPLTISH);
|
|
|
|
|
INIT(VSPLTISW);
|
|
|
|
|
INIT(VSPLTW);
|
|
|
|
|
INIT(VSR);
|
|
|
|
|
INIT(VSRAB);
|
|
|
|
|
INIT(VSRAH);
|
|
|
|
|
INIT(VSRAW);
|
|
|
|
|
INIT(VSRB);
|
|
|
|
|
INIT(VSRH);
|
|
|
|
|
INIT(VSRO);
|
|
|
|
|
INIT(VSRW);
|
|
|
|
|
INIT(VSUBCUW);
|
|
|
|
|
INIT(VSUBFP);
|
|
|
|
|
INIT(VSUBSBS);
|
|
|
|
|
INIT(VSUBSHS);
|
|
|
|
|
INIT(VSUBSWS);
|
|
|
|
|
INIT(VSUBUBM);
|
|
|
|
|
INIT(VSUBUBS);
|
|
|
|
|
INIT(VSUBUHM);
|
|
|
|
|
INIT(VSUBUHS);
|
|
|
|
|
INIT(VSUBUWM);
|
|
|
|
|
INIT(VSUBUWS);
|
|
|
|
|
INIT(VSUMSWS);
|
|
|
|
|
INIT(VSUM2SWS);
|
|
|
|
|
INIT(VSUM4SBS);
|
|
|
|
|
INIT(VSUM4SHS);
|
|
|
|
|
INIT(VSUM4UBS);
|
|
|
|
|
INIT(VUPKHPX);
|
|
|
|
|
INIT(VUPKHSB);
|
|
|
|
|
INIT(VUPKHSH);
|
|
|
|
|
INIT(VUPKLPX);
|
|
|
|
|
INIT(VUPKLSB);
|
|
|
|
|
INIT(VUPKLSH);
|
|
|
|
|
INIT(VXOR);
|
|
|
|
|
INIT(TDI);
|
|
|
|
|
INIT(TWI);
|
|
|
|
|
INIT(MULLI);
|
|
|
|
|
INIT(SUBFIC);
|
|
|
|
|
INIT(CMPLI);
|
|
|
|
|
INIT(CMPI);
|
|
|
|
|
INIT(ADDIC);
|
|
|
|
|
INIT(ADDI);
|
|
|
|
|
INIT(ADDIS);
|
|
|
|
|
INIT(BC);
|
|
|
|
|
INIT(SC);
|
|
|
|
|
INIT(B);
|
|
|
|
|
INIT(MCRF);
|
|
|
|
|
INIT(BCLR);
|
|
|
|
|
INIT(CRNOR);
|
|
|
|
|
INIT(CRANDC);
|
|
|
|
|
INIT(ISYNC);
|
|
|
|
|
INIT(CRXOR);
|
|
|
|
|
INIT(CRNAND);
|
|
|
|
|
INIT(CRAND);
|
|
|
|
|
INIT(CREQV);
|
|
|
|
|
INIT(CRORC);
|
|
|
|
|
INIT(CROR);
|
|
|
|
|
INIT(BCCTR);
|
|
|
|
|
INIT_RC(RLWIMI);
|
|
|
|
|
INIT_RC(RLWINM);
|
|
|
|
|
INIT_RC(RLWNM);
|
|
|
|
|
INIT(ORI);
|
|
|
|
|
INIT(ORIS);
|
|
|
|
|
INIT(XORI);
|
|
|
|
|
INIT(XORIS);
|
|
|
|
|
INIT(ANDI);
|
|
|
|
|
INIT(ANDIS);
|
|
|
|
|
INIT_RC(RLDICL);
|
|
|
|
|
INIT_RC(RLDICR);
|
|
|
|
|
INIT_RC(RLDIC);
|
|
|
|
|
INIT_RC(RLDIMI);
|
|
|
|
|
INIT_RC(RLDCL);
|
|
|
|
|
INIT_RC(RLDCR);
|
|
|
|
|
INIT(CMP);
|
|
|
|
|
INIT(TW);
|
|
|
|
|
INIT(LVSL);
|
|
|
|
|
INIT(LVEBX);
|
|
|
|
|
INIT_RC_OV(SUBFC);
|
|
|
|
|
INIT_RC_OV(ADDC);
|
|
|
|
|
INIT_RC(MULHDU);
|
|
|
|
|
INIT_RC(MULHWU);
|
2025-04-05 21:50:45 +02:00
|
|
|
INIT_PACK8(MFOCRF, );
|
2022-01-21 10:49:52 +01:00
|
|
|
INIT(MFCR); //+
|
2021-12-30 17:39:18 +01:00
|
|
|
INIT(LWARX);
|
|
|
|
|
INIT(LDX);
|
|
|
|
|
INIT(LWZX);
|
|
|
|
|
INIT_RC(SLW);
|
|
|
|
|
INIT_RC(CNTLZW);
|
|
|
|
|
INIT_RC(SLD);
|
|
|
|
|
INIT_RC(AND);
|
|
|
|
|
INIT(CMPL);
|
|
|
|
|
INIT(LVSR);
|
|
|
|
|
INIT(LVEHX);
|
|
|
|
|
INIT_RC_OV(SUBF);
|
|
|
|
|
INIT(LDUX);
|
|
|
|
|
INIT(DCBST);
|
|
|
|
|
INIT(LWZUX);
|
|
|
|
|
INIT_RC(CNTLZD);
|
|
|
|
|
INIT_RC(ANDC);
|
|
|
|
|
INIT(TD);
|
|
|
|
|
INIT(LVEWX);
|
|
|
|
|
INIT_RC(MULHD);
|
|
|
|
|
INIT_RC(MULHW);
|
|
|
|
|
INIT(LDARX);
|
|
|
|
|
INIT(DCBF);
|
|
|
|
|
INIT(LBZX);
|
|
|
|
|
INIT(LVX);
|
|
|
|
|
INIT_RC_OV(NEG);
|
|
|
|
|
INIT(LBZUX);
|
|
|
|
|
INIT_RC(NOR);
|
|
|
|
|
INIT(STVEBX);
|
|
|
|
|
INIT_OV(SUBFE);
|
|
|
|
|
INIT_OV(ADDE);
|
|
|
|
|
INIT(MTOCRF);
|
|
|
|
|
INIT(STDX);
|
|
|
|
|
INIT(STWCX);
|
|
|
|
|
INIT(STWX);
|
|
|
|
|
INIT(STVEHX);
|
|
|
|
|
INIT(STDUX);
|
|
|
|
|
INIT(STWUX);
|
|
|
|
|
INIT(STVEWX);
|
|
|
|
|
INIT_RC_OV(SUBFZE);
|
|
|
|
|
INIT_RC_OV(ADDZE);
|
|
|
|
|
INIT(STDCX);
|
|
|
|
|
INIT(STBX);
|
|
|
|
|
INIT(STVX);
|
|
|
|
|
INIT_RC_OV(SUBFME);
|
|
|
|
|
INIT_RC_OV(MULLD);
|
|
|
|
|
INIT_RC_OV(ADDME);
|
|
|
|
|
INIT_RC_OV(MULLW);
|
|
|
|
|
INIT(DCBTST);
|
|
|
|
|
INIT(STBUX);
|
|
|
|
|
INIT_RC_OV(ADD);
|
|
|
|
|
INIT(DCBT);
|
|
|
|
|
INIT(LHZX);
|
|
|
|
|
INIT_RC(EQV);
|
|
|
|
|
INIT(ECIWX);
|
|
|
|
|
INIT(LHZUX);
|
|
|
|
|
INIT_RC(XOR);
|
|
|
|
|
INIT(MFSPR);
|
|
|
|
|
INIT(LWAX);
|
|
|
|
|
INIT(DST);
|
|
|
|
|
INIT(LHAX);
|
|
|
|
|
INIT(LVXL);
|
|
|
|
|
INIT(MFTB);
|
|
|
|
|
INIT(LWAUX);
|
|
|
|
|
INIT(DSTST);
|
|
|
|
|
INIT(LHAUX);
|
|
|
|
|
INIT(STHX);
|
|
|
|
|
INIT_RC(ORC);
|
|
|
|
|
INIT(ECOWX);
|
|
|
|
|
INIT(STHUX);
|
|
|
|
|
INIT_RC(OR);
|
|
|
|
|
INIT_RC_OV(DIVDU);
|
|
|
|
|
INIT_RC_OV(DIVWU);
|
|
|
|
|
INIT(MTSPR);
|
|
|
|
|
INIT(DCBI);
|
|
|
|
|
INIT_RC(NAND);
|
|
|
|
|
INIT(STVXL);
|
|
|
|
|
INIT_RC_OV(DIVD);
|
|
|
|
|
INIT_RC_OV(DIVW);
|
|
|
|
|
INIT(LVLX);
|
|
|
|
|
INIT(LDBRX);
|
|
|
|
|
INIT(LSWX);
|
|
|
|
|
INIT(LWBRX);
|
|
|
|
|
INIT(LFSX);
|
|
|
|
|
INIT_RC(SRW);
|
|
|
|
|
INIT_RC(SRD);
|
|
|
|
|
INIT(LVRX);
|
|
|
|
|
INIT(LSWI);
|
|
|
|
|
INIT(LFSUX);
|
|
|
|
|
INIT(SYNC);
|
|
|
|
|
INIT(LFDX);
|
|
|
|
|
INIT(LFDUX);
|
|
|
|
|
INIT(STVLX);
|
|
|
|
|
INIT(STDBRX);
|
|
|
|
|
INIT(STSWX);
|
|
|
|
|
INIT(STWBRX);
|
|
|
|
|
INIT(STFSX);
|
|
|
|
|
INIT(STVRX);
|
|
|
|
|
INIT(STFSUX);
|
|
|
|
|
INIT(STSWI);
|
|
|
|
|
INIT(STFDX);
|
|
|
|
|
INIT(STFDUX);
|
|
|
|
|
INIT(LVLXL);
|
|
|
|
|
INIT(LHBRX);
|
|
|
|
|
INIT_RC(SRAW);
|
|
|
|
|
INIT_RC(SRAD);
|
|
|
|
|
INIT(LVRXL);
|
|
|
|
|
INIT(DSS);
|
|
|
|
|
INIT_RC(SRAWI);
|
|
|
|
|
INIT_RC(SRADI);
|
|
|
|
|
INIT(EIEIO);
|
|
|
|
|
INIT(STVLXL);
|
|
|
|
|
INIT(STHBRX);
|
|
|
|
|
INIT_RC(EXTSH);
|
|
|
|
|
INIT(STVRXL);
|
|
|
|
|
INIT_RC(EXTSB);
|
|
|
|
|
INIT(STFIWX);
|
|
|
|
|
INIT_RC(EXTSW);
|
|
|
|
|
INIT(ICBI);
|
|
|
|
|
INIT(DCBZ);
|
|
|
|
|
INIT(LWZ);
|
|
|
|
|
INIT(LWZU);
|
|
|
|
|
INIT(LBZ);
|
|
|
|
|
INIT(LBZU);
|
|
|
|
|
INIT(STW);
|
|
|
|
|
INIT(STWU);
|
|
|
|
|
INIT(STB);
|
|
|
|
|
INIT(STBU);
|
|
|
|
|
INIT(LHZ);
|
|
|
|
|
INIT(LHZU);
|
|
|
|
|
INIT(LHA);
|
|
|
|
|
INIT(LHAU);
|
|
|
|
|
INIT(STH);
|
|
|
|
|
INIT(STHU);
|
|
|
|
|
INIT(LMW);
|
|
|
|
|
INIT(STMW);
|
|
|
|
|
INIT(LFS);
|
|
|
|
|
INIT(LFSU);
|
|
|
|
|
INIT(LFD);
|
|
|
|
|
INIT(LFDU);
|
|
|
|
|
INIT(STFS);
|
|
|
|
|
INIT(STFSU);
|
|
|
|
|
INIT(STFD);
|
|
|
|
|
INIT(STFDU);
|
|
|
|
|
INIT(LD);
|
|
|
|
|
INIT(LDU);
|
|
|
|
|
INIT(LWA);
|
|
|
|
|
INIT(STD);
|
|
|
|
|
INIT(STDU);
|
|
|
|
|
INIT_RC(FDIVS);
|
|
|
|
|
INIT_RC(FSUBS);
|
|
|
|
|
INIT_RC(FADDS);
|
|
|
|
|
INIT_RC(FSQRTS);
|
|
|
|
|
INIT_RC(FRES);
|
|
|
|
|
INIT_RC(FMULS);
|
|
|
|
|
INIT_RC(FMADDS);
|
|
|
|
|
INIT_RC(FMSUBS);
|
|
|
|
|
INIT_RC(FNMSUBS);
|
|
|
|
|
INIT_RC(FNMADDS);
|
|
|
|
|
INIT_RC(MTFSB1);
|
|
|
|
|
INIT(MCRFS);
|
|
|
|
|
INIT_RC(MTFSB0);
|
|
|
|
|
INIT_RC(MTFSFI);
|
|
|
|
|
INIT_RC(MFFS);
|
|
|
|
|
INIT_RC(MTFSF);
|
|
|
|
|
INIT(FCMPU);
|
|
|
|
|
INIT_RC(FRSP);
|
|
|
|
|
INIT_RC(FCTIW);
|
|
|
|
|
INIT_RC(FCTIWZ);
|
|
|
|
|
INIT_RC(FDIV);
|
|
|
|
|
INIT_RC(FSUB);
|
|
|
|
|
INIT_RC(FADD);
|
|
|
|
|
INIT_RC(FSQRT);
|
|
|
|
|
INIT_RC(FSEL);
|
|
|
|
|
INIT_RC(FMUL);
|
|
|
|
|
INIT_RC(FRSQRTE);
|
|
|
|
|
INIT_RC(FMSUB);
|
|
|
|
|
INIT_RC(FMADD);
|
|
|
|
|
INIT_RC(FNMSUB);
|
|
|
|
|
INIT_RC(FNMADD);
|
|
|
|
|
INIT(FCMPO);
|
|
|
|
|
INIT_RC(FNEG);
|
|
|
|
|
INIT_RC(FMR);
|
|
|
|
|
INIT_RC(FNABS);
|
|
|
|
|
INIT_RC(FABS);
|
|
|
|
|
INIT_RC(FCTID);
|
|
|
|
|
INIT_RC(FCTIDZ);
|
|
|
|
|
INIT_RC(FCFID);
|
|
|
|
|
INIT(UNK);
|
|
|
|
|
#endif
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
ppu_interpreter_rt_base::~ppu_interpreter_rt_base()
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ppu_interpreter_rt::ppu_interpreter_rt() noexcept
|
2025-04-05 21:50:45 +02:00
|
|
|
: ppu_interpreter_rt_base(), table(*ptrs)
|
2021-12-30 17:39:18 +01:00
|
|
|
{
|
|
|
|
|
}
|
2020-12-14 12:32:04 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
ppu_intrp_func_t ppu_interpreter_rt::decode(u32 opv) const noexcept
|
|
|
|
|
{
|
|
|
|
|
const auto op = ppu_opcode_t{opv};
|
2020-12-14 12:32:04 +01:00
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
switch (g_ppu_itype.decode(opv))
|
|
|
|
|
{
|
|
|
|
|
case ppu_itype::LWZ:
|
|
|
|
|
case ppu_itype::LBZ:
|
|
|
|
|
case ppu_itype::STW:
|
|
|
|
|
case ppu_itype::STB:
|
|
|
|
|
case ppu_itype::LHZ:
|
|
|
|
|
case ppu_itype::LHA:
|
|
|
|
|
case ppu_itype::STH:
|
|
|
|
|
case ppu_itype::LFS:
|
|
|
|
|
case ppu_itype::LFD:
|
|
|
|
|
case ppu_itype::STFS:
|
|
|
|
|
case ppu_itype::STFD:
|
2020-12-14 12:32:04 +01:00
|
|
|
{
|
2021-12-30 17:39:18 +01:00
|
|
|
// Minor optimization: 16-bit absolute addressing never points to a valid memory
|
|
|
|
|
if (!op.ra)
|
|
|
|
|
{
|
|
|
|
|
return [](ppu_thread&, ppu_opcode_t op, be_t<u32>*, ppu_intrp_func*)
|
|
|
|
|
{
|
|
|
|
|
fmt::throw_exception("Invalid instruction: %s r%d,0x%016x(r0)", g_ppu_iname.decode(op.opcode), op.rd, op.simm16);
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
2022-01-19 00:41:32 +01:00
|
|
|
case ppu_itype::VSLDOI: return ptrs->VSLDOI_[op.vsh];
|
2022-01-21 10:49:52 +01:00
|
|
|
case ppu_itype::MFOCRF:
|
|
|
|
|
{
|
|
|
|
|
if (op.l11)
|
|
|
|
|
{
|
|
|
|
|
const u32 n = std::countl_zero<u32>(op.crm) & 7;
|
|
|
|
|
|
|
|
|
|
if (0x80u >> n != op.crm)
|
|
|
|
|
{
|
|
|
|
|
return [](ppu_thread&, ppu_opcode_t op, be_t<u32>*, ppu_intrp_func*)
|
|
|
|
|
{
|
|
|
|
|
fmt::throw_exception("Invalid instruction: MFOCRF with bits 0x%x", op.crm);
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ptrs->MFOCRF_[n];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ptrs->MFCR;
|
|
|
|
|
}
|
2021-12-30 17:39:18 +01:00
|
|
|
default: break;
|
2020-12-14 12:32:04 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-30 17:39:18 +01:00
|
|
|
return table.decode(opv);
|
2015-03-16 22:38:21 +01:00
|
|
|
}
|
2025-04-24 12:41:04 +02:00
|
|
|
|
|
|
|
|
using isel_type = void (*)(PPUContext&, rx::cell::ppu::Instruction);
|
|
|
|
|
|
|
|
|
|
#define IMPORT_DECODER(x) extern "C" isel_type ISEL_PPU_##x##_DEC
|
|
|
|
|
#define IMPORT_DECODER_ALIAS(x, name) \
|
|
|
|
|
extern "C" isel_type ISEL_PPU_##name##_DEC; \
|
|
|
|
|
inline isel_type ISEL_PPU_##x##_DEC = ISEL_PPU_##name##_DEC;
|
|
|
|
|
|
|
|
|
|
IMPORT_DECODER(MFVSCR);
|
|
|
|
|
IMPORT_DECODER(MTVSCR);
|
|
|
|
|
IMPORT_DECODER(VADDCUW);
|
|
|
|
|
IMPORT_DECODER(VADDFP);
|
|
|
|
|
IMPORT_DECODER(VADDSBS);
|
|
|
|
|
IMPORT_DECODER(VADDSHS);
|
|
|
|
|
IMPORT_DECODER(VADDSWS);
|
|
|
|
|
IMPORT_DECODER(VADDUBM);
|
|
|
|
|
IMPORT_DECODER(VADDUBS);
|
|
|
|
|
IMPORT_DECODER(VADDUHM);
|
|
|
|
|
IMPORT_DECODER(VADDUHS);
|
|
|
|
|
IMPORT_DECODER(VADDUWM);
|
|
|
|
|
IMPORT_DECODER(VADDUWS);
|
|
|
|
|
IMPORT_DECODER(VAND);
|
|
|
|
|
IMPORT_DECODER(VANDC);
|
|
|
|
|
IMPORT_DECODER(VAVGSB);
|
|
|
|
|
IMPORT_DECODER(VAVGSH);
|
|
|
|
|
IMPORT_DECODER(VAVGSW);
|
|
|
|
|
IMPORT_DECODER(VAVGUB);
|
|
|
|
|
IMPORT_DECODER(VAVGUH);
|
|
|
|
|
IMPORT_DECODER(VAVGUW);
|
|
|
|
|
IMPORT_DECODER(VCFSX);
|
|
|
|
|
IMPORT_DECODER(VCFUX);
|
|
|
|
|
IMPORT_DECODER(VCMPBFP);
|
|
|
|
|
IMPORT_DECODER_ALIAS(VCMPBFP_, VCMPBFP);
|
|
|
|
|
IMPORT_DECODER(VCMPEQFP);
|
|
|
|
|
IMPORT_DECODER_ALIAS(VCMPEQFP_, VCMPEQFP);
|
|
|
|
|
IMPORT_DECODER(VCMPEQUB);
|
|
|
|
|
IMPORT_DECODER_ALIAS(VCMPEQUB_, VCMPEQUB);
|
|
|
|
|
IMPORT_DECODER(VCMPEQUH);
|
|
|
|
|
IMPORT_DECODER_ALIAS(VCMPEQUH_, VCMPEQUH);
|
|
|
|
|
IMPORT_DECODER(VCMPEQUW);
|
|
|
|
|
IMPORT_DECODER_ALIAS(VCMPEQUW_, VCMPEQUW);
|
|
|
|
|
IMPORT_DECODER(VCMPGEFP);
|
|
|
|
|
IMPORT_DECODER_ALIAS(VCMPGEFP_, VCMPGEFP);
|
|
|
|
|
IMPORT_DECODER(VCMPGTFP);
|
|
|
|
|
IMPORT_DECODER_ALIAS(VCMPGTFP_, VCMPGTFP);
|
|
|
|
|
IMPORT_DECODER(VCMPGTSB);
|
|
|
|
|
IMPORT_DECODER_ALIAS(VCMPGTSB_, VCMPGTSB);
|
|
|
|
|
IMPORT_DECODER(VCMPGTSH);
|
|
|
|
|
IMPORT_DECODER_ALIAS(VCMPGTSH_, VCMPGTSH);
|
|
|
|
|
IMPORT_DECODER(VCMPGTSW);
|
|
|
|
|
IMPORT_DECODER_ALIAS(VCMPGTSW_, VCMPGTSW);
|
|
|
|
|
IMPORT_DECODER(VCMPGTUB);
|
|
|
|
|
IMPORT_DECODER_ALIAS(VCMPGTUB_, VCMPGTUB);
|
|
|
|
|
IMPORT_DECODER(VCMPGTUH);
|
|
|
|
|
IMPORT_DECODER_ALIAS(VCMPGTUH_, VCMPGTUH);
|
|
|
|
|
IMPORT_DECODER(VCMPGTUW);
|
|
|
|
|
IMPORT_DECODER_ALIAS(VCMPGTUW_, VCMPGTUW);
|
|
|
|
|
IMPORT_DECODER(VCTSXS);
|
|
|
|
|
IMPORT_DECODER(VCTUXS);
|
|
|
|
|
IMPORT_DECODER(VEXPTEFP);
|
|
|
|
|
IMPORT_DECODER(VLOGEFP);
|
|
|
|
|
IMPORT_DECODER(VMADDFP);
|
|
|
|
|
IMPORT_DECODER(VMAXFP);
|
|
|
|
|
IMPORT_DECODER(VMAXSB);
|
|
|
|
|
IMPORT_DECODER(VMAXSH);
|
|
|
|
|
IMPORT_DECODER(VMAXSW);
|
|
|
|
|
IMPORT_DECODER(VMAXUB);
|
|
|
|
|
IMPORT_DECODER(VMAXUH);
|
|
|
|
|
IMPORT_DECODER(VMAXUW);
|
|
|
|
|
IMPORT_DECODER(VMHADDSHS);
|
|
|
|
|
IMPORT_DECODER(VMHRADDSHS);
|
|
|
|
|
IMPORT_DECODER(VMINFP);
|
|
|
|
|
IMPORT_DECODER(VMINSB);
|
|
|
|
|
IMPORT_DECODER(VMINSH);
|
|
|
|
|
IMPORT_DECODER(VMINSW);
|
|
|
|
|
IMPORT_DECODER(VMINUB);
|
|
|
|
|
IMPORT_DECODER(VMINUH);
|
|
|
|
|
IMPORT_DECODER(VMINUW);
|
|
|
|
|
IMPORT_DECODER(VMLADDUHM);
|
|
|
|
|
IMPORT_DECODER(VMRGHB);
|
|
|
|
|
IMPORT_DECODER(VMRGHH);
|
|
|
|
|
IMPORT_DECODER(VMRGHW);
|
|
|
|
|
IMPORT_DECODER(VMRGLB);
|
|
|
|
|
IMPORT_DECODER(VMRGLH);
|
|
|
|
|
IMPORT_DECODER(VMRGLW);
|
|
|
|
|
IMPORT_DECODER(VMSUMMBM);
|
|
|
|
|
IMPORT_DECODER(VMSUMSHM);
|
|
|
|
|
IMPORT_DECODER(VMSUMSHS);
|
|
|
|
|
IMPORT_DECODER(VMSUMUBM);
|
|
|
|
|
IMPORT_DECODER(VMSUMUHM);
|
|
|
|
|
IMPORT_DECODER(VMSUMUHS);
|
|
|
|
|
IMPORT_DECODER(VMULESB);
|
|
|
|
|
IMPORT_DECODER(VMULESH);
|
|
|
|
|
IMPORT_DECODER(VMULEUB);
|
|
|
|
|
IMPORT_DECODER(VMULEUH);
|
|
|
|
|
IMPORT_DECODER(VMULOSB);
|
|
|
|
|
IMPORT_DECODER(VMULOSH);
|
|
|
|
|
IMPORT_DECODER(VMULOUB);
|
|
|
|
|
IMPORT_DECODER(VMULOUH);
|
|
|
|
|
IMPORT_DECODER(VNMSUBFP);
|
|
|
|
|
IMPORT_DECODER(VNOR);
|
|
|
|
|
IMPORT_DECODER(VOR);
|
|
|
|
|
IMPORT_DECODER(VPERM);
|
|
|
|
|
IMPORT_DECODER(VPKPX);
|
|
|
|
|
IMPORT_DECODER(VPKSHSS);
|
|
|
|
|
IMPORT_DECODER(VPKSHUS);
|
|
|
|
|
IMPORT_DECODER(VPKSWSS);
|
|
|
|
|
IMPORT_DECODER(VPKSWUS);
|
|
|
|
|
IMPORT_DECODER(VPKUHUM);
|
|
|
|
|
IMPORT_DECODER(VPKUHUS);
|
|
|
|
|
IMPORT_DECODER(VPKUWUM);
|
|
|
|
|
IMPORT_DECODER(VPKUWUS);
|
|
|
|
|
IMPORT_DECODER(VREFP);
|
|
|
|
|
IMPORT_DECODER(VRFIM);
|
|
|
|
|
IMPORT_DECODER(VRFIN);
|
|
|
|
|
IMPORT_DECODER(VRFIP);
|
|
|
|
|
IMPORT_DECODER(VRFIZ);
|
|
|
|
|
IMPORT_DECODER(VRLB);
|
|
|
|
|
IMPORT_DECODER(VRLH);
|
|
|
|
|
IMPORT_DECODER(VRLW);
|
|
|
|
|
IMPORT_DECODER(VRSQRTEFP);
|
|
|
|
|
IMPORT_DECODER(VSEL);
|
|
|
|
|
IMPORT_DECODER(VSL);
|
|
|
|
|
IMPORT_DECODER(VSLB);
|
|
|
|
|
IMPORT_DECODER(VSLDOI);
|
|
|
|
|
IMPORT_DECODER(VSLH);
|
|
|
|
|
IMPORT_DECODER(VSLO);
|
|
|
|
|
IMPORT_DECODER(VSLW);
|
|
|
|
|
IMPORT_DECODER(VSPLTB);
|
|
|
|
|
IMPORT_DECODER(VSPLTH);
|
|
|
|
|
IMPORT_DECODER(VSPLTISB);
|
|
|
|
|
IMPORT_DECODER(VSPLTISH);
|
|
|
|
|
IMPORT_DECODER(VSPLTISW);
|
|
|
|
|
IMPORT_DECODER(VSPLTW);
|
|
|
|
|
IMPORT_DECODER(VSR);
|
|
|
|
|
IMPORT_DECODER(VSRAB);
|
|
|
|
|
IMPORT_DECODER(VSRAH);
|
|
|
|
|
IMPORT_DECODER(VSRAW);
|
|
|
|
|
IMPORT_DECODER(VSRB);
|
|
|
|
|
IMPORT_DECODER(VSRH);
|
|
|
|
|
IMPORT_DECODER(VSRO);
|
|
|
|
|
IMPORT_DECODER(VSRW);
|
|
|
|
|
IMPORT_DECODER(VSUBCUW);
|
|
|
|
|
IMPORT_DECODER(VSUBFP);
|
|
|
|
|
IMPORT_DECODER(VSUBSBS);
|
|
|
|
|
IMPORT_DECODER(VSUBSHS);
|
|
|
|
|
IMPORT_DECODER(VSUBSWS);
|
|
|
|
|
IMPORT_DECODER(VSUBUBM);
|
|
|
|
|
IMPORT_DECODER(VSUBUBS);
|
|
|
|
|
IMPORT_DECODER(VSUBUHM);
|
|
|
|
|
IMPORT_DECODER(VSUBUHS);
|
|
|
|
|
IMPORT_DECODER(VSUBUWM);
|
|
|
|
|
IMPORT_DECODER(VSUBUWS);
|
|
|
|
|
IMPORT_DECODER(VSUMSWS);
|
|
|
|
|
IMPORT_DECODER(VSUM2SWS);
|
|
|
|
|
IMPORT_DECODER(VSUM4SBS);
|
|
|
|
|
IMPORT_DECODER(VSUM4SHS);
|
|
|
|
|
IMPORT_DECODER(VSUM4UBS);
|
|
|
|
|
IMPORT_DECODER(VUPKHPX);
|
|
|
|
|
IMPORT_DECODER(VUPKHSB);
|
|
|
|
|
IMPORT_DECODER(VUPKHSH);
|
|
|
|
|
IMPORT_DECODER(VUPKLPX);
|
|
|
|
|
IMPORT_DECODER(VUPKLSB);
|
|
|
|
|
IMPORT_DECODER(VUPKLSH);
|
|
|
|
|
IMPORT_DECODER(VXOR);
|
|
|
|
|
IMPORT_DECODER(TDI);
|
|
|
|
|
IMPORT_DECODER(TWI);
|
|
|
|
|
IMPORT_DECODER(MULLI);
|
|
|
|
|
IMPORT_DECODER(SUBFIC);
|
|
|
|
|
IMPORT_DECODER(CMPLI);
|
|
|
|
|
IMPORT_DECODER(CMPI);
|
|
|
|
|
IMPORT_DECODER(ADDIC);
|
|
|
|
|
IMPORT_DECODER(ADDI);
|
|
|
|
|
IMPORT_DECODER(ADDIS);
|
|
|
|
|
IMPORT_DECODER(BC);
|
|
|
|
|
IMPORT_DECODER(SC);
|
|
|
|
|
IMPORT_DECODER(B);
|
|
|
|
|
IMPORT_DECODER(MCRF);
|
|
|
|
|
IMPORT_DECODER(BCLR);
|
|
|
|
|
IMPORT_DECODER(RFID);
|
|
|
|
|
IMPORT_DECODER(CRNOR);
|
|
|
|
|
IMPORT_DECODER(RFSCV);
|
|
|
|
|
IMPORT_DECODER(CRANDC);
|
|
|
|
|
IMPORT_DECODER(ISYNC);
|
|
|
|
|
IMPORT_DECODER(CRXOR);
|
|
|
|
|
IMPORT_DECODER(CRNAND);
|
|
|
|
|
IMPORT_DECODER(CRAND);
|
|
|
|
|
IMPORT_DECODER(HRFID);
|
|
|
|
|
IMPORT_DECODER(CREQV);
|
|
|
|
|
IMPORT_DECODER(URFID);
|
|
|
|
|
IMPORT_DECODER(STOP);
|
|
|
|
|
IMPORT_DECODER(CRORC);
|
|
|
|
|
IMPORT_DECODER(CROR);
|
|
|
|
|
IMPORT_DECODER(BCCTR);
|
|
|
|
|
IMPORT_DECODER(RLWIMI);
|
|
|
|
|
IMPORT_DECODER(RLWINM);
|
|
|
|
|
IMPORT_DECODER(RLWNM);
|
|
|
|
|
IMPORT_DECODER(ORI);
|
|
|
|
|
IMPORT_DECODER(ORIS);
|
|
|
|
|
IMPORT_DECODER(XORI);
|
|
|
|
|
IMPORT_DECODER(XORIS);
|
|
|
|
|
IMPORT_DECODER(ANDI);
|
|
|
|
|
IMPORT_DECODER(ANDIS);
|
|
|
|
|
IMPORT_DECODER(RLDICL);
|
|
|
|
|
IMPORT_DECODER(RLDICR);
|
|
|
|
|
IMPORT_DECODER(RLDIC);
|
|
|
|
|
IMPORT_DECODER(RLDIMI);
|
|
|
|
|
IMPORT_DECODER(RLDCL);
|
|
|
|
|
IMPORT_DECODER(RLDCR);
|
|
|
|
|
IMPORT_DECODER(CMP);
|
|
|
|
|
IMPORT_DECODER(TW);
|
|
|
|
|
IMPORT_DECODER(LVSL);
|
|
|
|
|
IMPORT_DECODER(LVEBX);
|
|
|
|
|
IMPORT_DECODER(SUBFC);
|
|
|
|
|
IMPORT_DECODER(MULHDU);
|
|
|
|
|
IMPORT_DECODER(ADDC);
|
|
|
|
|
IMPORT_DECODER(MULHWU);
|
|
|
|
|
IMPORT_DECODER(MFOCRF);
|
|
|
|
|
IMPORT_DECODER(LWARX);
|
|
|
|
|
IMPORT_DECODER(LDX);
|
|
|
|
|
IMPORT_DECODER(LWZX);
|
|
|
|
|
IMPORT_DECODER(SLW);
|
|
|
|
|
IMPORT_DECODER(CNTLZW);
|
|
|
|
|
IMPORT_DECODER(SLD);
|
|
|
|
|
IMPORT_DECODER(AND);
|
|
|
|
|
IMPORT_DECODER(CMPL);
|
|
|
|
|
IMPORT_DECODER(LVSR);
|
|
|
|
|
IMPORT_DECODER(LVEHX);
|
|
|
|
|
IMPORT_DECODER(SUBF);
|
|
|
|
|
IMPORT_DECODER(LDUX);
|
|
|
|
|
IMPORT_DECODER(DCBST);
|
|
|
|
|
IMPORT_DECODER(LWZUX);
|
|
|
|
|
IMPORT_DECODER(CNTLZD);
|
|
|
|
|
IMPORT_DECODER(ANDC);
|
|
|
|
|
IMPORT_DECODER(TD);
|
|
|
|
|
IMPORT_DECODER(LVEWX);
|
|
|
|
|
IMPORT_DECODER(MULHD);
|
|
|
|
|
IMPORT_DECODER(MULHW);
|
|
|
|
|
IMPORT_DECODER(LDARX);
|
|
|
|
|
IMPORT_DECODER(DCBF);
|
|
|
|
|
IMPORT_DECODER(LBZX);
|
|
|
|
|
IMPORT_DECODER(LVX);
|
|
|
|
|
IMPORT_DECODER(NEG);
|
|
|
|
|
IMPORT_DECODER(LBZUX);
|
|
|
|
|
IMPORT_DECODER(NOR);
|
|
|
|
|
IMPORT_DECODER(STVEBX);
|
|
|
|
|
IMPORT_DECODER(SUBFE);
|
|
|
|
|
IMPORT_DECODER(ADDE);
|
|
|
|
|
IMPORT_DECODER(MTOCRF);
|
|
|
|
|
IMPORT_DECODER(STDX);
|
|
|
|
|
IMPORT_DECODER(STWCX);
|
|
|
|
|
IMPORT_DECODER(STWX);
|
|
|
|
|
IMPORT_DECODER(STVEHX);
|
|
|
|
|
IMPORT_DECODER(STDUX);
|
|
|
|
|
IMPORT_DECODER(STWUX);
|
|
|
|
|
IMPORT_DECODER(STVEWX);
|
|
|
|
|
IMPORT_DECODER(SUBFZE);
|
|
|
|
|
IMPORT_DECODER(ADDZE);
|
|
|
|
|
IMPORT_DECODER(STDCX);
|
|
|
|
|
IMPORT_DECODER(STBX);
|
|
|
|
|
IMPORT_DECODER(STVX);
|
|
|
|
|
IMPORT_DECODER(MULLD);
|
|
|
|
|
IMPORT_DECODER(SUBFME);
|
|
|
|
|
IMPORT_DECODER(ADDME);
|
|
|
|
|
IMPORT_DECODER(MULLW);
|
|
|
|
|
IMPORT_DECODER(DCBTST);
|
|
|
|
|
IMPORT_DECODER(STBUX);
|
|
|
|
|
IMPORT_DECODER(ADD);
|
|
|
|
|
IMPORT_DECODER(DCBT);
|
|
|
|
|
IMPORT_DECODER(LHZX);
|
|
|
|
|
IMPORT_DECODER(EQV);
|
|
|
|
|
IMPORT_DECODER(ECIWX);
|
|
|
|
|
IMPORT_DECODER(LHZUX);
|
|
|
|
|
IMPORT_DECODER(XOR);
|
|
|
|
|
IMPORT_DECODER(MFSPR);
|
|
|
|
|
IMPORT_DECODER(LWAX);
|
|
|
|
|
IMPORT_DECODER(DST);
|
|
|
|
|
IMPORT_DECODER(LHAX);
|
|
|
|
|
IMPORT_DECODER(LVXL);
|
|
|
|
|
IMPORT_DECODER(MFTB);
|
|
|
|
|
IMPORT_DECODER(LWAUX);
|
|
|
|
|
IMPORT_DECODER(DSTST);
|
|
|
|
|
IMPORT_DECODER(LHAUX);
|
|
|
|
|
IMPORT_DECODER(STHX);
|
|
|
|
|
IMPORT_DECODER(ORC);
|
|
|
|
|
IMPORT_DECODER(ECOWX);
|
|
|
|
|
IMPORT_DECODER(STHUX);
|
|
|
|
|
IMPORT_DECODER(OR);
|
|
|
|
|
IMPORT_DECODER(DIVDU);
|
|
|
|
|
IMPORT_DECODER(DIVWU);
|
|
|
|
|
IMPORT_DECODER(MTSPR);
|
|
|
|
|
IMPORT_DECODER(DCBI);
|
|
|
|
|
IMPORT_DECODER(NAND);
|
|
|
|
|
IMPORT_DECODER(STVXL);
|
|
|
|
|
IMPORT_DECODER(DIVD);
|
|
|
|
|
IMPORT_DECODER(DIVW);
|
|
|
|
|
IMPORT_DECODER(LVLX);
|
|
|
|
|
IMPORT_DECODER(LDBRX);
|
|
|
|
|
IMPORT_DECODER(LSWX);
|
|
|
|
|
IMPORT_DECODER(LWBRX);
|
|
|
|
|
IMPORT_DECODER(LFSX);
|
|
|
|
|
IMPORT_DECODER(SRW);
|
|
|
|
|
IMPORT_DECODER(SRD);
|
|
|
|
|
IMPORT_DECODER(LVRX);
|
|
|
|
|
IMPORT_DECODER(LSWI);
|
|
|
|
|
IMPORT_DECODER(LFSUX);
|
|
|
|
|
IMPORT_DECODER(SYNC);
|
|
|
|
|
IMPORT_DECODER(LFDX);
|
|
|
|
|
IMPORT_DECODER(LFDUX);
|
|
|
|
|
IMPORT_DECODER(STVLX);
|
|
|
|
|
IMPORT_DECODER(STDBRX);
|
|
|
|
|
IMPORT_DECODER(STSWX);
|
|
|
|
|
IMPORT_DECODER(STWBRX);
|
|
|
|
|
IMPORT_DECODER(STFSX);
|
|
|
|
|
IMPORT_DECODER(STVRX);
|
|
|
|
|
IMPORT_DECODER(STFSUX);
|
|
|
|
|
IMPORT_DECODER(STSWI);
|
|
|
|
|
IMPORT_DECODER(STFDX);
|
|
|
|
|
IMPORT_DECODER(STFDUX);
|
|
|
|
|
IMPORT_DECODER(LVLXL);
|
|
|
|
|
IMPORT_DECODER(LHBRX);
|
|
|
|
|
IMPORT_DECODER(SRAW);
|
|
|
|
|
IMPORT_DECODER(SRAD);
|
|
|
|
|
IMPORT_DECODER(LVRXL);
|
|
|
|
|
IMPORT_DECODER(DSS);
|
|
|
|
|
IMPORT_DECODER(SRAWI);
|
|
|
|
|
IMPORT_DECODER(SRADI);
|
|
|
|
|
IMPORT_DECODER(EIEIO);
|
|
|
|
|
IMPORT_DECODER(STVLXL);
|
|
|
|
|
IMPORT_DECODER(STHBRX);
|
|
|
|
|
IMPORT_DECODER(EXTSH);
|
|
|
|
|
IMPORT_DECODER(STVRXL);
|
|
|
|
|
IMPORT_DECODER(EXTSB);
|
|
|
|
|
IMPORT_DECODER(STFIWX);
|
|
|
|
|
IMPORT_DECODER(EXTSW);
|
|
|
|
|
IMPORT_DECODER(ICBI);
|
|
|
|
|
IMPORT_DECODER(DCBZ);
|
|
|
|
|
IMPORT_DECODER(LWZ);
|
|
|
|
|
IMPORT_DECODER(LWZU);
|
|
|
|
|
IMPORT_DECODER(LBZ);
|
|
|
|
|
IMPORT_DECODER(LBZU);
|
|
|
|
|
IMPORT_DECODER(STW);
|
|
|
|
|
IMPORT_DECODER(STWU);
|
|
|
|
|
IMPORT_DECODER(STB);
|
|
|
|
|
IMPORT_DECODER(STBU);
|
|
|
|
|
IMPORT_DECODER(LHZ);
|
|
|
|
|
IMPORT_DECODER(LHZU);
|
|
|
|
|
IMPORT_DECODER(LHA);
|
|
|
|
|
IMPORT_DECODER(LHAU);
|
|
|
|
|
IMPORT_DECODER(STH);
|
|
|
|
|
IMPORT_DECODER(STHU);
|
|
|
|
|
IMPORT_DECODER(LMW);
|
|
|
|
|
IMPORT_DECODER(STMW);
|
|
|
|
|
IMPORT_DECODER(LFS);
|
|
|
|
|
IMPORT_DECODER(LFSU);
|
|
|
|
|
IMPORT_DECODER(LFD);
|
|
|
|
|
IMPORT_DECODER(LFDU);
|
|
|
|
|
IMPORT_DECODER(STFS);
|
|
|
|
|
IMPORT_DECODER(STFSU);
|
|
|
|
|
IMPORT_DECODER(STFD);
|
|
|
|
|
IMPORT_DECODER(STFDU);
|
|
|
|
|
IMPORT_DECODER(LD);
|
|
|
|
|
IMPORT_DECODER(LDU);
|
|
|
|
|
IMPORT_DECODER(LWA);
|
|
|
|
|
IMPORT_DECODER(STD);
|
|
|
|
|
IMPORT_DECODER(STDU);
|
|
|
|
|
IMPORT_DECODER(FDIVS);
|
|
|
|
|
IMPORT_DECODER(FSUBS);
|
|
|
|
|
IMPORT_DECODER(FADDS);
|
|
|
|
|
IMPORT_DECODER(FSQRTS);
|
|
|
|
|
IMPORT_DECODER(FRES);
|
|
|
|
|
IMPORT_DECODER(FMULS);
|
|
|
|
|
IMPORT_DECODER(FMADDS);
|
|
|
|
|
IMPORT_DECODER(FMSUBS);
|
|
|
|
|
IMPORT_DECODER(FNMSUBS);
|
|
|
|
|
IMPORT_DECODER(FNMADDS);
|
|
|
|
|
IMPORT_DECODER(MTFSB1);
|
|
|
|
|
IMPORT_DECODER(MCRFS);
|
|
|
|
|
IMPORT_DECODER(MTFSB0);
|
|
|
|
|
IMPORT_DECODER(MTFSFI);
|
|
|
|
|
IMPORT_DECODER(MFFS);
|
|
|
|
|
IMPORT_DECODER(MTFSF);
|
|
|
|
|
IMPORT_DECODER(FCMPU);
|
|
|
|
|
IMPORT_DECODER(FRSP);
|
|
|
|
|
IMPORT_DECODER(FCTIW);
|
|
|
|
|
IMPORT_DECODER(FCTIWZ);
|
|
|
|
|
IMPORT_DECODER(FDIV);
|
|
|
|
|
IMPORT_DECODER(FSUB);
|
|
|
|
|
IMPORT_DECODER(FADD);
|
|
|
|
|
IMPORT_DECODER(FSQRT);
|
|
|
|
|
IMPORT_DECODER(FSEL);
|
|
|
|
|
IMPORT_DECODER(FMUL);
|
|
|
|
|
IMPORT_DECODER(FRSQRTE);
|
|
|
|
|
IMPORT_DECODER(FMSUB);
|
|
|
|
|
IMPORT_DECODER(FMADD);
|
|
|
|
|
IMPORT_DECODER(FNMSUB);
|
|
|
|
|
IMPORT_DECODER(FNMADD);
|
|
|
|
|
IMPORT_DECODER(FCMPO);
|
|
|
|
|
IMPORT_DECODER(FNEG);
|
|
|
|
|
IMPORT_DECODER(FMR);
|
|
|
|
|
IMPORT_DECODER(FNABS);
|
|
|
|
|
IMPORT_DECODER(FABS);
|
|
|
|
|
IMPORT_DECODER(FCTID);
|
|
|
|
|
IMPORT_DECODER(FCTIDZ);
|
|
|
|
|
IMPORT_DECODER(FCFID);
|
|
|
|
|
IMPORT_DECODER(UNK);
|
|
|
|
|
IMPORT_DECODER(SUBFCO);
|
|
|
|
|
IMPORT_DECODER(ADDCO);
|
|
|
|
|
IMPORT_DECODER(SUBFO);
|
|
|
|
|
IMPORT_DECODER(NEGO);
|
|
|
|
|
IMPORT_DECODER(SUBFEO);
|
|
|
|
|
IMPORT_DECODER(ADDEO);
|
|
|
|
|
IMPORT_DECODER(SUBFZEO);
|
|
|
|
|
IMPORT_DECODER(ADDZEO);
|
|
|
|
|
IMPORT_DECODER(SUBFMEO);
|
|
|
|
|
IMPORT_DECODER(MULLDO);
|
|
|
|
|
IMPORT_DECODER(ADDMEO);
|
|
|
|
|
IMPORT_DECODER(MULLWO);
|
|
|
|
|
IMPORT_DECODER(ADDO);
|
|
|
|
|
IMPORT_DECODER(DIVDUO);
|
|
|
|
|
IMPORT_DECODER(DIVWUO);
|
|
|
|
|
IMPORT_DECODER(DIVDO);
|
|
|
|
|
IMPORT_DECODER(DIVWO);
|
|
|
|
|
IMPORT_DECODER_ALIAS(SUBFCO_, SUBFCO);
|
|
|
|
|
IMPORT_DECODER_ALIAS(ADDCO_, ADDCO);
|
|
|
|
|
IMPORT_DECODER_ALIAS(SUBFO_, SUBFO);
|
|
|
|
|
IMPORT_DECODER_ALIAS(NEGO_, NEGO);
|
|
|
|
|
IMPORT_DECODER_ALIAS(SUBFEO_, SUBFEO);
|
|
|
|
|
IMPORT_DECODER_ALIAS(ADDEO_, ADDEO);
|
|
|
|
|
IMPORT_DECODER_ALIAS(SUBFZEO_, SUBFZEO);
|
|
|
|
|
IMPORT_DECODER_ALIAS(ADDZEO_, ADDZEO);
|
|
|
|
|
IMPORT_DECODER_ALIAS(SUBFMEO_, SUBFMEO);
|
|
|
|
|
IMPORT_DECODER_ALIAS(MULLDO_, MULLDO);
|
|
|
|
|
IMPORT_DECODER_ALIAS(ADDMEO_, ADDMEO);
|
|
|
|
|
IMPORT_DECODER_ALIAS(MULLWO_, MULLWO);
|
|
|
|
|
IMPORT_DECODER_ALIAS(ADDO_, ADDO);
|
|
|
|
|
IMPORT_DECODER_ALIAS(DIVDUO_, DIVDUO);
|
|
|
|
|
IMPORT_DECODER_ALIAS(DIVWUO_, DIVWUO);
|
|
|
|
|
IMPORT_DECODER_ALIAS(DIVDO_, DIVDO);
|
|
|
|
|
IMPORT_DECODER_ALIAS(DIVWO_, DIVWO);
|
|
|
|
|
IMPORT_DECODER_ALIAS(RLWIMI_, RLWIMI);
|
|
|
|
|
IMPORT_DECODER_ALIAS(RLWINM_, RLWINM);
|
|
|
|
|
IMPORT_DECODER_ALIAS(RLWNM_, RLWNM);
|
|
|
|
|
IMPORT_DECODER_ALIAS(RLDICL_, RLDICL);
|
|
|
|
|
IMPORT_DECODER_ALIAS(RLDICR_, RLDICR);
|
|
|
|
|
IMPORT_DECODER_ALIAS(RLDIC_, RLDIC);
|
|
|
|
|
IMPORT_DECODER_ALIAS(RLDIMI_, RLDIMI);
|
|
|
|
|
IMPORT_DECODER_ALIAS(RLDCL_, RLDCL);
|
|
|
|
|
IMPORT_DECODER_ALIAS(RLDCR_, RLDCR);
|
|
|
|
|
IMPORT_DECODER_ALIAS(SUBFC_, SUBFC);
|
|
|
|
|
IMPORT_DECODER_ALIAS(MULHDU_, MULHDU);
|
|
|
|
|
IMPORT_DECODER_ALIAS(ADDC_, ADDC);
|
|
|
|
|
IMPORT_DECODER_ALIAS(MULHWU_, MULHWU);
|
|
|
|
|
IMPORT_DECODER_ALIAS(SLW_, SLW);
|
|
|
|
|
IMPORT_DECODER_ALIAS(CNTLZW_, CNTLZW);
|
|
|
|
|
IMPORT_DECODER_ALIAS(SLD_, SLD);
|
|
|
|
|
IMPORT_DECODER_ALIAS(AND_, AND);
|
|
|
|
|
IMPORT_DECODER_ALIAS(SUBF_, SUBF);
|
|
|
|
|
IMPORT_DECODER_ALIAS(CNTLZD_, CNTLZD);
|
|
|
|
|
IMPORT_DECODER_ALIAS(ANDC_, ANDC);
|
|
|
|
|
IMPORT_DECODER_ALIAS(MULHD_, MULHD);
|
|
|
|
|
IMPORT_DECODER_ALIAS(MULHW_, MULHW);
|
|
|
|
|
IMPORT_DECODER_ALIAS(NEG_, NEG);
|
|
|
|
|
IMPORT_DECODER_ALIAS(NOR_, NOR);
|
|
|
|
|
IMPORT_DECODER_ALIAS(SUBFE_, SUBFE);
|
|
|
|
|
IMPORT_DECODER_ALIAS(ADDE_, ADDE);
|
|
|
|
|
IMPORT_DECODER_ALIAS(SUBFZE_, SUBFZE);
|
|
|
|
|
IMPORT_DECODER_ALIAS(ADDZE_, ADDZE);
|
|
|
|
|
IMPORT_DECODER_ALIAS(MULLD_, MULLD);
|
|
|
|
|
IMPORT_DECODER_ALIAS(SUBFME_, SUBFME);
|
|
|
|
|
IMPORT_DECODER_ALIAS(ADDME_, ADDME);
|
|
|
|
|
IMPORT_DECODER_ALIAS(MULLW_, MULLW);
|
|
|
|
|
IMPORT_DECODER_ALIAS(ADD_, ADD);
|
|
|
|
|
IMPORT_DECODER_ALIAS(EQV_, EQV);
|
|
|
|
|
IMPORT_DECODER_ALIAS(XOR_, XOR);
|
|
|
|
|
IMPORT_DECODER_ALIAS(ORC_, ORC);
|
|
|
|
|
IMPORT_DECODER_ALIAS(OR_, OR);
|
|
|
|
|
IMPORT_DECODER_ALIAS(DIVDU_, DIVDU);
|
|
|
|
|
IMPORT_DECODER_ALIAS(DIVWU_, DIVWU);
|
|
|
|
|
IMPORT_DECODER_ALIAS(NAND_, NAND);
|
|
|
|
|
IMPORT_DECODER_ALIAS(DIVD_, DIVD);
|
|
|
|
|
IMPORT_DECODER_ALIAS(DIVW_, DIVW);
|
|
|
|
|
IMPORT_DECODER_ALIAS(SRW_, SRW);
|
|
|
|
|
IMPORT_DECODER_ALIAS(SRD_, SRD);
|
|
|
|
|
IMPORT_DECODER_ALIAS(SRAW_, SRAW);
|
|
|
|
|
IMPORT_DECODER_ALIAS(SRAD_, SRAD);
|
|
|
|
|
IMPORT_DECODER_ALIAS(SRAWI_, SRAWI);
|
|
|
|
|
IMPORT_DECODER_ALIAS(SRADI_, SRADI);
|
|
|
|
|
IMPORT_DECODER_ALIAS(EXTSH_, EXTSH);
|
|
|
|
|
IMPORT_DECODER_ALIAS(EXTSB_, EXTSB);
|
|
|
|
|
IMPORT_DECODER_ALIAS(EXTSW_, EXTSW);
|
|
|
|
|
IMPORT_DECODER_ALIAS(FDIVS_, FDIVS);
|
|
|
|
|
IMPORT_DECODER_ALIAS(FSUBS_, FSUBS);
|
|
|
|
|
IMPORT_DECODER_ALIAS(FADDS_, FADDS);
|
|
|
|
|
IMPORT_DECODER_ALIAS(FSQRTS_, FSQRTS);
|
|
|
|
|
IMPORT_DECODER_ALIAS(FRES_, FRES);
|
|
|
|
|
IMPORT_DECODER_ALIAS(FMULS_, FMULS);
|
|
|
|
|
IMPORT_DECODER_ALIAS(FMADDS_, FMADDS);
|
|
|
|
|
IMPORT_DECODER_ALIAS(FMSUBS_, FMSUBS);
|
|
|
|
|
IMPORT_DECODER_ALIAS(FNMSUBS_, FNMSUBS);
|
|
|
|
|
IMPORT_DECODER_ALIAS(FNMADDS_, FNMADDS);
|
|
|
|
|
IMPORT_DECODER_ALIAS(MTFSB1_, MTFSB1);
|
|
|
|
|
IMPORT_DECODER_ALIAS(MTFSB0_, MTFSB0);
|
|
|
|
|
IMPORT_DECODER_ALIAS(MTFSFI_, MTFSFI);
|
|
|
|
|
IMPORT_DECODER_ALIAS(MFFS_, MFFS);
|
|
|
|
|
IMPORT_DECODER_ALIAS(MTFSF_, MTFSF);
|
|
|
|
|
IMPORT_DECODER_ALIAS(FRSP_, FRSP);
|
|
|
|
|
IMPORT_DECODER_ALIAS(FCTIW_, FCTIW);
|
|
|
|
|
IMPORT_DECODER_ALIAS(FCTIWZ_, FCTIWZ);
|
|
|
|
|
IMPORT_DECODER_ALIAS(FDIV_, FDIV);
|
|
|
|
|
IMPORT_DECODER_ALIAS(FSUB_, FSUB);
|
|
|
|
|
IMPORT_DECODER_ALIAS(FADD_, FADD);
|
|
|
|
|
IMPORT_DECODER_ALIAS(FSQRT_, FSQRT);
|
|
|
|
|
IMPORT_DECODER_ALIAS(FSEL_, FSEL);
|
|
|
|
|
IMPORT_DECODER_ALIAS(FMUL_, FMUL);
|
|
|
|
|
IMPORT_DECODER_ALIAS(FRSQRTE_, FRSQRTE);
|
|
|
|
|
IMPORT_DECODER_ALIAS(FMSUB_, FMSUB);
|
|
|
|
|
IMPORT_DECODER_ALIAS(FMADD_, FMADD);
|
|
|
|
|
IMPORT_DECODER_ALIAS(FNMSUB_, FNMSUB);
|
|
|
|
|
IMPORT_DECODER_ALIAS(FNMADD_, FNMADD);
|
|
|
|
|
IMPORT_DECODER_ALIAS(FNEG_, FNEG);
|
|
|
|
|
IMPORT_DECODER_ALIAS(FMR_, FMR);
|
|
|
|
|
IMPORT_DECODER_ALIAS(FNABS_, FNABS);
|
|
|
|
|
IMPORT_DECODER_ALIAS(FABS_, FABS);
|
|
|
|
|
IMPORT_DECODER_ALIAS(FCTID_, FCTID);
|
|
|
|
|
IMPORT_DECODER_ALIAS(FCTIDZ_, FCTIDZ);
|
|
|
|
|
IMPORT_DECODER_ALIAS(FCFID_, FCFID);
|
|
|
|
|
#undef IMPORT_DECODER
|
|
|
|
|
#undef IMPORT_DECODER_ALIAS
|
|
|
|
|
|
|
|
|
|
PPUInterpreter::PPUInterpreter()
|
|
|
|
|
{
|
|
|
|
|
for (auto& isel : impl)
|
|
|
|
|
{
|
|
|
|
|
isel = [](PPUContext&, rx::cell::ppu::Instruction)
|
|
|
|
|
{
|
|
|
|
|
fmt::throw_exception("PPU Invalid Instruction");
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
#define DEFINE_DECODER(x) \
|
|
|
|
|
impl[static_cast<int>(rx::cell::ppu::Opcode::x)] = ISEL_PPU_##x##_DEC
|
|
|
|
|
|
|
|
|
|
DEFINE_DECODER(MFVSCR);
|
|
|
|
|
DEFINE_DECODER(MTVSCR);
|
|
|
|
|
DEFINE_DECODER(VADDCUW);
|
|
|
|
|
DEFINE_DECODER(VADDFP);
|
|
|
|
|
DEFINE_DECODER(VADDSBS);
|
|
|
|
|
DEFINE_DECODER(VADDSHS);
|
|
|
|
|
DEFINE_DECODER(VADDSWS);
|
|
|
|
|
DEFINE_DECODER(VADDUBM);
|
|
|
|
|
DEFINE_DECODER(VADDUBS);
|
|
|
|
|
DEFINE_DECODER(VADDUHM);
|
|
|
|
|
DEFINE_DECODER(VADDUHS);
|
|
|
|
|
DEFINE_DECODER(VADDUWM);
|
|
|
|
|
DEFINE_DECODER(VADDUWS);
|
|
|
|
|
DEFINE_DECODER(VAND);
|
|
|
|
|
DEFINE_DECODER(VANDC);
|
|
|
|
|
DEFINE_DECODER(VAVGSB);
|
|
|
|
|
DEFINE_DECODER(VAVGSH);
|
|
|
|
|
DEFINE_DECODER(VAVGSW);
|
|
|
|
|
DEFINE_DECODER(VAVGUB);
|
|
|
|
|
DEFINE_DECODER(VAVGUH);
|
|
|
|
|
DEFINE_DECODER(VAVGUW);
|
|
|
|
|
DEFINE_DECODER(VCFSX);
|
|
|
|
|
DEFINE_DECODER(VCFUX);
|
|
|
|
|
DEFINE_DECODER(VCMPBFP);
|
|
|
|
|
DEFINE_DECODER(VCMPBFP_);
|
|
|
|
|
DEFINE_DECODER(VCMPEQFP);
|
|
|
|
|
DEFINE_DECODER(VCMPEQFP_);
|
|
|
|
|
DEFINE_DECODER(VCMPEQUB);
|
|
|
|
|
DEFINE_DECODER(VCMPEQUB_);
|
|
|
|
|
DEFINE_DECODER(VCMPEQUH);
|
|
|
|
|
DEFINE_DECODER(VCMPEQUH_);
|
|
|
|
|
DEFINE_DECODER(VCMPEQUW);
|
|
|
|
|
DEFINE_DECODER(VCMPEQUW_);
|
|
|
|
|
DEFINE_DECODER(VCMPGEFP);
|
|
|
|
|
DEFINE_DECODER(VCMPGEFP_);
|
|
|
|
|
DEFINE_DECODER(VCMPGTFP);
|
|
|
|
|
DEFINE_DECODER(VCMPGTFP_);
|
|
|
|
|
DEFINE_DECODER(VCMPGTSB);
|
|
|
|
|
DEFINE_DECODER(VCMPGTSB_);
|
|
|
|
|
DEFINE_DECODER(VCMPGTSH);
|
|
|
|
|
DEFINE_DECODER(VCMPGTSH_);
|
|
|
|
|
DEFINE_DECODER(VCMPGTSW);
|
|
|
|
|
DEFINE_DECODER(VCMPGTSW_);
|
|
|
|
|
DEFINE_DECODER(VCMPGTUB);
|
|
|
|
|
DEFINE_DECODER(VCMPGTUB_);
|
|
|
|
|
DEFINE_DECODER(VCMPGTUH);
|
|
|
|
|
DEFINE_DECODER(VCMPGTUH_);
|
|
|
|
|
DEFINE_DECODER(VCMPGTUW);
|
|
|
|
|
DEFINE_DECODER(VCMPGTUW_);
|
|
|
|
|
DEFINE_DECODER(VCTSXS);
|
|
|
|
|
DEFINE_DECODER(VCTUXS);
|
|
|
|
|
DEFINE_DECODER(VEXPTEFP);
|
|
|
|
|
DEFINE_DECODER(VLOGEFP);
|
|
|
|
|
DEFINE_DECODER(VMADDFP);
|
|
|
|
|
DEFINE_DECODER(VMAXFP);
|
|
|
|
|
DEFINE_DECODER(VMAXSB);
|
|
|
|
|
DEFINE_DECODER(VMAXSH);
|
|
|
|
|
DEFINE_DECODER(VMAXSW);
|
|
|
|
|
DEFINE_DECODER(VMAXUB);
|
|
|
|
|
DEFINE_DECODER(VMAXUH);
|
|
|
|
|
DEFINE_DECODER(VMAXUW);
|
|
|
|
|
DEFINE_DECODER(VMHADDSHS);
|
|
|
|
|
DEFINE_DECODER(VMHRADDSHS);
|
|
|
|
|
DEFINE_DECODER(VMINFP);
|
|
|
|
|
DEFINE_DECODER(VMINSB);
|
|
|
|
|
DEFINE_DECODER(VMINSH);
|
|
|
|
|
DEFINE_DECODER(VMINSW);
|
|
|
|
|
DEFINE_DECODER(VMINUB);
|
|
|
|
|
DEFINE_DECODER(VMINUH);
|
|
|
|
|
DEFINE_DECODER(VMINUW);
|
|
|
|
|
DEFINE_DECODER(VMLADDUHM);
|
|
|
|
|
DEFINE_DECODER(VMRGHB);
|
|
|
|
|
DEFINE_DECODER(VMRGHH);
|
|
|
|
|
DEFINE_DECODER(VMRGHW);
|
|
|
|
|
DEFINE_DECODER(VMRGLB);
|
|
|
|
|
DEFINE_DECODER(VMRGLH);
|
|
|
|
|
DEFINE_DECODER(VMRGLW);
|
|
|
|
|
DEFINE_DECODER(VMSUMMBM);
|
|
|
|
|
DEFINE_DECODER(VMSUMSHM);
|
|
|
|
|
DEFINE_DECODER(VMSUMSHS);
|
|
|
|
|
DEFINE_DECODER(VMSUMUBM);
|
|
|
|
|
DEFINE_DECODER(VMSUMUHM);
|
|
|
|
|
DEFINE_DECODER(VMSUMUHS);
|
|
|
|
|
DEFINE_DECODER(VMULESB);
|
|
|
|
|
DEFINE_DECODER(VMULESH);
|
|
|
|
|
DEFINE_DECODER(VMULEUB);
|
|
|
|
|
DEFINE_DECODER(VMULEUH);
|
|
|
|
|
DEFINE_DECODER(VMULOSB);
|
|
|
|
|
DEFINE_DECODER(VMULOSH);
|
|
|
|
|
DEFINE_DECODER(VMULOUB);
|
|
|
|
|
DEFINE_DECODER(VMULOUH);
|
|
|
|
|
DEFINE_DECODER(VNMSUBFP);
|
|
|
|
|
DEFINE_DECODER(VNOR);
|
|
|
|
|
DEFINE_DECODER(VOR);
|
|
|
|
|
DEFINE_DECODER(VPERM);
|
|
|
|
|
DEFINE_DECODER(VPKPX);
|
|
|
|
|
DEFINE_DECODER(VPKSHSS);
|
|
|
|
|
DEFINE_DECODER(VPKSHUS);
|
|
|
|
|
DEFINE_DECODER(VPKSWSS);
|
|
|
|
|
DEFINE_DECODER(VPKSWUS);
|
|
|
|
|
DEFINE_DECODER(VPKUHUM);
|
|
|
|
|
DEFINE_DECODER(VPKUHUS);
|
|
|
|
|
DEFINE_DECODER(VPKUWUM);
|
|
|
|
|
DEFINE_DECODER(VPKUWUS);
|
|
|
|
|
DEFINE_DECODER(VREFP);
|
|
|
|
|
DEFINE_DECODER(VRFIM);
|
|
|
|
|
DEFINE_DECODER(VRFIN);
|
|
|
|
|
DEFINE_DECODER(VRFIP);
|
|
|
|
|
DEFINE_DECODER(VRFIZ);
|
|
|
|
|
DEFINE_DECODER(VRLB);
|
|
|
|
|
DEFINE_DECODER(VRLH);
|
|
|
|
|
DEFINE_DECODER(VRLW);
|
|
|
|
|
DEFINE_DECODER(VRSQRTEFP);
|
|
|
|
|
DEFINE_DECODER(VSEL);
|
|
|
|
|
DEFINE_DECODER(VSL);
|
|
|
|
|
DEFINE_DECODER(VSLB);
|
|
|
|
|
DEFINE_DECODER(VSLDOI);
|
|
|
|
|
DEFINE_DECODER(VSLH);
|
|
|
|
|
DEFINE_DECODER(VSLO);
|
|
|
|
|
DEFINE_DECODER(VSLW);
|
|
|
|
|
DEFINE_DECODER(VSPLTB);
|
|
|
|
|
DEFINE_DECODER(VSPLTH);
|
|
|
|
|
DEFINE_DECODER(VSPLTISB);
|
|
|
|
|
DEFINE_DECODER(VSPLTISH);
|
|
|
|
|
DEFINE_DECODER(VSPLTISW);
|
|
|
|
|
DEFINE_DECODER(VSPLTW);
|
|
|
|
|
DEFINE_DECODER(VSR);
|
|
|
|
|
DEFINE_DECODER(VSRAB);
|
|
|
|
|
DEFINE_DECODER(VSRAH);
|
|
|
|
|
DEFINE_DECODER(VSRAW);
|
|
|
|
|
DEFINE_DECODER(VSRB);
|
|
|
|
|
DEFINE_DECODER(VSRH);
|
|
|
|
|
DEFINE_DECODER(VSRO);
|
|
|
|
|
DEFINE_DECODER(VSRW);
|
|
|
|
|
DEFINE_DECODER(VSUBCUW);
|
|
|
|
|
DEFINE_DECODER(VSUBFP);
|
|
|
|
|
DEFINE_DECODER(VSUBSBS);
|
|
|
|
|
DEFINE_DECODER(VSUBSHS);
|
|
|
|
|
DEFINE_DECODER(VSUBSWS);
|
|
|
|
|
DEFINE_DECODER(VSUBUBM);
|
|
|
|
|
DEFINE_DECODER(VSUBUBS);
|
|
|
|
|
DEFINE_DECODER(VSUBUHM);
|
|
|
|
|
DEFINE_DECODER(VSUBUHS);
|
|
|
|
|
DEFINE_DECODER(VSUBUWM);
|
|
|
|
|
DEFINE_DECODER(VSUBUWS);
|
|
|
|
|
DEFINE_DECODER(VSUMSWS);
|
|
|
|
|
DEFINE_DECODER(VSUM2SWS);
|
|
|
|
|
DEFINE_DECODER(VSUM4SBS);
|
|
|
|
|
DEFINE_DECODER(VSUM4SHS);
|
|
|
|
|
DEFINE_DECODER(VSUM4UBS);
|
|
|
|
|
DEFINE_DECODER(VUPKHPX);
|
|
|
|
|
DEFINE_DECODER(VUPKHSB);
|
|
|
|
|
DEFINE_DECODER(VUPKHSH);
|
|
|
|
|
DEFINE_DECODER(VUPKLPX);
|
|
|
|
|
DEFINE_DECODER(VUPKLSB);
|
|
|
|
|
DEFINE_DECODER(VUPKLSH);
|
|
|
|
|
DEFINE_DECODER(VXOR);
|
|
|
|
|
DEFINE_DECODER(TDI);
|
|
|
|
|
DEFINE_DECODER(TWI);
|
|
|
|
|
DEFINE_DECODER(MULLI);
|
|
|
|
|
DEFINE_DECODER(SUBFIC);
|
|
|
|
|
DEFINE_DECODER(CMPLI);
|
|
|
|
|
DEFINE_DECODER(CMPI);
|
|
|
|
|
DEFINE_DECODER(ADDIC);
|
|
|
|
|
DEFINE_DECODER(ADDI);
|
|
|
|
|
DEFINE_DECODER(ADDIS);
|
|
|
|
|
DEFINE_DECODER(BC);
|
|
|
|
|
DEFINE_DECODER(SC);
|
|
|
|
|
DEFINE_DECODER(B);
|
|
|
|
|
DEFINE_DECODER(MCRF);
|
|
|
|
|
DEFINE_DECODER(BCLR);
|
|
|
|
|
DEFINE_DECODER(RFID);
|
|
|
|
|
DEFINE_DECODER(CRNOR);
|
|
|
|
|
DEFINE_DECODER(RFSCV);
|
|
|
|
|
DEFINE_DECODER(CRANDC);
|
|
|
|
|
DEFINE_DECODER(ISYNC);
|
|
|
|
|
DEFINE_DECODER(CRXOR);
|
|
|
|
|
DEFINE_DECODER(CRNAND);
|
|
|
|
|
DEFINE_DECODER(CRAND);
|
|
|
|
|
DEFINE_DECODER(HRFID);
|
|
|
|
|
DEFINE_DECODER(CREQV);
|
|
|
|
|
DEFINE_DECODER(URFID);
|
|
|
|
|
DEFINE_DECODER(STOP);
|
|
|
|
|
DEFINE_DECODER(CRORC);
|
|
|
|
|
DEFINE_DECODER(CROR);
|
|
|
|
|
DEFINE_DECODER(BCCTR);
|
|
|
|
|
DEFINE_DECODER(RLWIMI);
|
|
|
|
|
DEFINE_DECODER(RLWINM);
|
|
|
|
|
DEFINE_DECODER(RLWNM);
|
|
|
|
|
DEFINE_DECODER(ORI);
|
|
|
|
|
DEFINE_DECODER(ORIS);
|
|
|
|
|
DEFINE_DECODER(XORI);
|
|
|
|
|
DEFINE_DECODER(XORIS);
|
|
|
|
|
DEFINE_DECODER(ANDI);
|
|
|
|
|
DEFINE_DECODER(ANDIS);
|
|
|
|
|
DEFINE_DECODER(RLDICL);
|
|
|
|
|
DEFINE_DECODER(RLDICR);
|
|
|
|
|
DEFINE_DECODER(RLDIC);
|
|
|
|
|
DEFINE_DECODER(RLDIMI);
|
|
|
|
|
DEFINE_DECODER(RLDCL);
|
|
|
|
|
DEFINE_DECODER(RLDCR);
|
|
|
|
|
DEFINE_DECODER(CMP);
|
|
|
|
|
DEFINE_DECODER(TW);
|
|
|
|
|
DEFINE_DECODER(LVSL);
|
|
|
|
|
DEFINE_DECODER(LVEBX);
|
|
|
|
|
DEFINE_DECODER(SUBFC);
|
|
|
|
|
DEFINE_DECODER(MULHDU);
|
|
|
|
|
DEFINE_DECODER(ADDC);
|
|
|
|
|
DEFINE_DECODER(MULHWU);
|
|
|
|
|
DEFINE_DECODER(MFOCRF);
|
|
|
|
|
DEFINE_DECODER(LWARX);
|
|
|
|
|
DEFINE_DECODER(LDX);
|
|
|
|
|
DEFINE_DECODER(LWZX);
|
|
|
|
|
DEFINE_DECODER(SLW);
|
|
|
|
|
DEFINE_DECODER(CNTLZW);
|
|
|
|
|
DEFINE_DECODER(SLD);
|
|
|
|
|
DEFINE_DECODER(AND);
|
|
|
|
|
DEFINE_DECODER(CMPL);
|
|
|
|
|
DEFINE_DECODER(LVSR);
|
|
|
|
|
DEFINE_DECODER(LVEHX);
|
|
|
|
|
DEFINE_DECODER(SUBF);
|
|
|
|
|
DEFINE_DECODER(LDUX);
|
|
|
|
|
DEFINE_DECODER(DCBST);
|
|
|
|
|
DEFINE_DECODER(LWZUX);
|
|
|
|
|
DEFINE_DECODER(CNTLZD);
|
|
|
|
|
DEFINE_DECODER(ANDC);
|
|
|
|
|
DEFINE_DECODER(TD);
|
|
|
|
|
DEFINE_DECODER(LVEWX);
|
|
|
|
|
DEFINE_DECODER(MULHD);
|
|
|
|
|
DEFINE_DECODER(MULHW);
|
|
|
|
|
DEFINE_DECODER(LDARX);
|
|
|
|
|
DEFINE_DECODER(DCBF);
|
|
|
|
|
DEFINE_DECODER(LBZX);
|
|
|
|
|
DEFINE_DECODER(LVX);
|
|
|
|
|
DEFINE_DECODER(NEG);
|
|
|
|
|
DEFINE_DECODER(LBZUX);
|
|
|
|
|
DEFINE_DECODER(NOR);
|
|
|
|
|
DEFINE_DECODER(STVEBX);
|
|
|
|
|
DEFINE_DECODER(SUBFE);
|
|
|
|
|
DEFINE_DECODER(ADDE);
|
|
|
|
|
DEFINE_DECODER(MTOCRF);
|
|
|
|
|
DEFINE_DECODER(STDX);
|
|
|
|
|
DEFINE_DECODER(STWCX);
|
|
|
|
|
DEFINE_DECODER(STWX);
|
|
|
|
|
DEFINE_DECODER(STVEHX);
|
|
|
|
|
DEFINE_DECODER(STDUX);
|
|
|
|
|
DEFINE_DECODER(STWUX);
|
|
|
|
|
DEFINE_DECODER(STVEWX);
|
|
|
|
|
DEFINE_DECODER(SUBFZE);
|
|
|
|
|
DEFINE_DECODER(ADDZE);
|
|
|
|
|
DEFINE_DECODER(STDCX);
|
|
|
|
|
DEFINE_DECODER(STBX);
|
|
|
|
|
DEFINE_DECODER(STVX);
|
|
|
|
|
DEFINE_DECODER(MULLD);
|
|
|
|
|
DEFINE_DECODER(SUBFME);
|
|
|
|
|
DEFINE_DECODER(ADDME);
|
|
|
|
|
DEFINE_DECODER(MULLW);
|
|
|
|
|
DEFINE_DECODER(DCBTST);
|
|
|
|
|
DEFINE_DECODER(STBUX);
|
|
|
|
|
DEFINE_DECODER(ADD);
|
|
|
|
|
DEFINE_DECODER(DCBT);
|
|
|
|
|
DEFINE_DECODER(LHZX);
|
|
|
|
|
DEFINE_DECODER(EQV);
|
|
|
|
|
DEFINE_DECODER(ECIWX);
|
|
|
|
|
DEFINE_DECODER(LHZUX);
|
|
|
|
|
DEFINE_DECODER(XOR);
|
|
|
|
|
DEFINE_DECODER(MFSPR);
|
|
|
|
|
DEFINE_DECODER(LWAX);
|
|
|
|
|
DEFINE_DECODER(DST);
|
|
|
|
|
DEFINE_DECODER(LHAX);
|
|
|
|
|
DEFINE_DECODER(LVXL);
|
|
|
|
|
DEFINE_DECODER(MFTB);
|
|
|
|
|
DEFINE_DECODER(LWAUX);
|
|
|
|
|
DEFINE_DECODER(DSTST);
|
|
|
|
|
DEFINE_DECODER(LHAUX);
|
|
|
|
|
DEFINE_DECODER(STHX);
|
|
|
|
|
DEFINE_DECODER(ORC);
|
|
|
|
|
DEFINE_DECODER(ECOWX);
|
|
|
|
|
DEFINE_DECODER(STHUX);
|
|
|
|
|
DEFINE_DECODER(OR);
|
|
|
|
|
DEFINE_DECODER(DIVDU);
|
|
|
|
|
DEFINE_DECODER(DIVWU);
|
|
|
|
|
DEFINE_DECODER(MTSPR);
|
|
|
|
|
DEFINE_DECODER(DCBI);
|
|
|
|
|
DEFINE_DECODER(NAND);
|
|
|
|
|
DEFINE_DECODER(STVXL);
|
|
|
|
|
DEFINE_DECODER(DIVD);
|
|
|
|
|
DEFINE_DECODER(DIVW);
|
|
|
|
|
DEFINE_DECODER(LVLX);
|
|
|
|
|
DEFINE_DECODER(LDBRX);
|
|
|
|
|
DEFINE_DECODER(LSWX);
|
|
|
|
|
DEFINE_DECODER(LWBRX);
|
|
|
|
|
DEFINE_DECODER(LFSX);
|
|
|
|
|
DEFINE_DECODER(SRW);
|
|
|
|
|
DEFINE_DECODER(SRD);
|
|
|
|
|
DEFINE_DECODER(LVRX);
|
|
|
|
|
DEFINE_DECODER(LSWI);
|
|
|
|
|
DEFINE_DECODER(LFSUX);
|
|
|
|
|
DEFINE_DECODER(SYNC);
|
|
|
|
|
DEFINE_DECODER(LFDX);
|
|
|
|
|
DEFINE_DECODER(LFDUX);
|
|
|
|
|
DEFINE_DECODER(STVLX);
|
|
|
|
|
DEFINE_DECODER(STDBRX);
|
|
|
|
|
DEFINE_DECODER(STSWX);
|
|
|
|
|
DEFINE_DECODER(STWBRX);
|
|
|
|
|
DEFINE_DECODER(STFSX);
|
|
|
|
|
DEFINE_DECODER(STVRX);
|
|
|
|
|
DEFINE_DECODER(STFSUX);
|
|
|
|
|
DEFINE_DECODER(STSWI);
|
|
|
|
|
DEFINE_DECODER(STFDX);
|
|
|
|
|
DEFINE_DECODER(STFDUX);
|
|
|
|
|
DEFINE_DECODER(LVLXL);
|
|
|
|
|
DEFINE_DECODER(LHBRX);
|
|
|
|
|
DEFINE_DECODER(SRAW);
|
|
|
|
|
DEFINE_DECODER(SRAD);
|
|
|
|
|
DEFINE_DECODER(LVRXL);
|
|
|
|
|
DEFINE_DECODER(DSS);
|
|
|
|
|
DEFINE_DECODER(SRAWI);
|
|
|
|
|
DEFINE_DECODER(SRADI);
|
|
|
|
|
DEFINE_DECODER(EIEIO);
|
|
|
|
|
DEFINE_DECODER(STVLXL);
|
|
|
|
|
DEFINE_DECODER(STHBRX);
|
|
|
|
|
DEFINE_DECODER(EXTSH);
|
|
|
|
|
DEFINE_DECODER(STVRXL);
|
|
|
|
|
DEFINE_DECODER(EXTSB);
|
|
|
|
|
DEFINE_DECODER(STFIWX);
|
|
|
|
|
DEFINE_DECODER(EXTSW);
|
|
|
|
|
DEFINE_DECODER(ICBI);
|
|
|
|
|
DEFINE_DECODER(DCBZ);
|
|
|
|
|
DEFINE_DECODER(LWZ);
|
|
|
|
|
DEFINE_DECODER(LWZU);
|
|
|
|
|
DEFINE_DECODER(LBZ);
|
|
|
|
|
DEFINE_DECODER(LBZU);
|
|
|
|
|
DEFINE_DECODER(STW);
|
|
|
|
|
DEFINE_DECODER(STWU);
|
|
|
|
|
DEFINE_DECODER(STB);
|
|
|
|
|
DEFINE_DECODER(STBU);
|
|
|
|
|
DEFINE_DECODER(LHZ);
|
|
|
|
|
DEFINE_DECODER(LHZU);
|
|
|
|
|
DEFINE_DECODER(LHA);
|
|
|
|
|
DEFINE_DECODER(LHAU);
|
|
|
|
|
DEFINE_DECODER(STH);
|
|
|
|
|
DEFINE_DECODER(STHU);
|
|
|
|
|
DEFINE_DECODER(LMW);
|
|
|
|
|
DEFINE_DECODER(STMW);
|
|
|
|
|
DEFINE_DECODER(LFS);
|
|
|
|
|
DEFINE_DECODER(LFSU);
|
|
|
|
|
DEFINE_DECODER(LFD);
|
|
|
|
|
DEFINE_DECODER(LFDU);
|
|
|
|
|
DEFINE_DECODER(STFS);
|
|
|
|
|
DEFINE_DECODER(STFSU);
|
|
|
|
|
DEFINE_DECODER(STFD);
|
|
|
|
|
DEFINE_DECODER(STFDU);
|
|
|
|
|
DEFINE_DECODER(LD);
|
|
|
|
|
DEFINE_DECODER(LDU);
|
|
|
|
|
DEFINE_DECODER(LWA);
|
|
|
|
|
DEFINE_DECODER(STD);
|
|
|
|
|
DEFINE_DECODER(STDU);
|
|
|
|
|
DEFINE_DECODER(FDIVS);
|
|
|
|
|
DEFINE_DECODER(FSUBS);
|
|
|
|
|
DEFINE_DECODER(FADDS);
|
|
|
|
|
DEFINE_DECODER(FSQRTS);
|
|
|
|
|
DEFINE_DECODER(FRES);
|
|
|
|
|
DEFINE_DECODER(FMULS);
|
|
|
|
|
DEFINE_DECODER(FMADDS);
|
|
|
|
|
DEFINE_DECODER(FMSUBS);
|
|
|
|
|
DEFINE_DECODER(FNMSUBS);
|
|
|
|
|
DEFINE_DECODER(FNMADDS);
|
|
|
|
|
DEFINE_DECODER(MTFSB1);
|
|
|
|
|
DEFINE_DECODER(MCRFS);
|
|
|
|
|
DEFINE_DECODER(MTFSB0);
|
|
|
|
|
DEFINE_DECODER(MTFSFI);
|
|
|
|
|
DEFINE_DECODER(MFFS);
|
|
|
|
|
DEFINE_DECODER(MTFSF);
|
|
|
|
|
DEFINE_DECODER(FCMPU);
|
|
|
|
|
DEFINE_DECODER(FRSP);
|
|
|
|
|
DEFINE_DECODER(FCTIW);
|
|
|
|
|
DEFINE_DECODER(FCTIWZ);
|
|
|
|
|
DEFINE_DECODER(FDIV);
|
|
|
|
|
DEFINE_DECODER(FSUB);
|
|
|
|
|
DEFINE_DECODER(FADD);
|
|
|
|
|
DEFINE_DECODER(FSQRT);
|
|
|
|
|
DEFINE_DECODER(FSEL);
|
|
|
|
|
DEFINE_DECODER(FMUL);
|
|
|
|
|
DEFINE_DECODER(FRSQRTE);
|
|
|
|
|
DEFINE_DECODER(FMSUB);
|
|
|
|
|
DEFINE_DECODER(FMADD);
|
|
|
|
|
DEFINE_DECODER(FNMSUB);
|
|
|
|
|
DEFINE_DECODER(FNMADD);
|
|
|
|
|
DEFINE_DECODER(FCMPO);
|
|
|
|
|
DEFINE_DECODER(FNEG);
|
|
|
|
|
DEFINE_DECODER(FMR);
|
|
|
|
|
DEFINE_DECODER(FNABS);
|
|
|
|
|
DEFINE_DECODER(FABS);
|
|
|
|
|
DEFINE_DECODER(FCTID);
|
|
|
|
|
DEFINE_DECODER(FCTIDZ);
|
|
|
|
|
DEFINE_DECODER(FCFID);
|
|
|
|
|
DEFINE_DECODER(UNK);
|
|
|
|
|
DEFINE_DECODER(SUBFCO);
|
|
|
|
|
DEFINE_DECODER(ADDCO);
|
|
|
|
|
DEFINE_DECODER(SUBFO);
|
|
|
|
|
DEFINE_DECODER(NEGO);
|
|
|
|
|
DEFINE_DECODER(SUBFEO);
|
|
|
|
|
DEFINE_DECODER(ADDEO);
|
|
|
|
|
DEFINE_DECODER(SUBFZEO);
|
|
|
|
|
DEFINE_DECODER(ADDZEO);
|
|
|
|
|
DEFINE_DECODER(SUBFMEO);
|
|
|
|
|
DEFINE_DECODER(MULLDO);
|
|
|
|
|
DEFINE_DECODER(ADDMEO);
|
|
|
|
|
DEFINE_DECODER(MULLWO);
|
|
|
|
|
DEFINE_DECODER(ADDO);
|
|
|
|
|
DEFINE_DECODER(DIVDUO);
|
|
|
|
|
DEFINE_DECODER(DIVWUO);
|
|
|
|
|
DEFINE_DECODER(DIVDO);
|
|
|
|
|
DEFINE_DECODER(DIVWO);
|
|
|
|
|
DEFINE_DECODER(SUBFCO_);
|
|
|
|
|
DEFINE_DECODER(ADDCO_);
|
|
|
|
|
DEFINE_DECODER(SUBFO_);
|
|
|
|
|
DEFINE_DECODER(NEGO_);
|
|
|
|
|
DEFINE_DECODER(SUBFEO_);
|
|
|
|
|
DEFINE_DECODER(ADDEO_);
|
|
|
|
|
DEFINE_DECODER(SUBFZEO_);
|
|
|
|
|
DEFINE_DECODER(ADDZEO_);
|
|
|
|
|
DEFINE_DECODER(SUBFMEO_);
|
|
|
|
|
DEFINE_DECODER(MULLDO_);
|
|
|
|
|
DEFINE_DECODER(ADDMEO_);
|
|
|
|
|
DEFINE_DECODER(MULLWO_);
|
|
|
|
|
DEFINE_DECODER(ADDO_);
|
|
|
|
|
DEFINE_DECODER(DIVDUO_);
|
|
|
|
|
DEFINE_DECODER(DIVWUO_);
|
|
|
|
|
DEFINE_DECODER(DIVDO_);
|
|
|
|
|
DEFINE_DECODER(DIVWO_);
|
|
|
|
|
DEFINE_DECODER(RLWIMI_);
|
|
|
|
|
DEFINE_DECODER(RLWINM_);
|
|
|
|
|
DEFINE_DECODER(RLWNM_);
|
|
|
|
|
DEFINE_DECODER(RLDICL_);
|
|
|
|
|
DEFINE_DECODER(RLDICR_);
|
|
|
|
|
DEFINE_DECODER(RLDIC_);
|
|
|
|
|
DEFINE_DECODER(RLDIMI_);
|
|
|
|
|
DEFINE_DECODER(RLDCL_);
|
|
|
|
|
DEFINE_DECODER(RLDCR_);
|
|
|
|
|
DEFINE_DECODER(SUBFC_);
|
|
|
|
|
DEFINE_DECODER(MULHDU_);
|
|
|
|
|
DEFINE_DECODER(ADDC_);
|
|
|
|
|
DEFINE_DECODER(MULHWU_);
|
|
|
|
|
DEFINE_DECODER(SLW_);
|
|
|
|
|
DEFINE_DECODER(CNTLZW_);
|
|
|
|
|
DEFINE_DECODER(SLD_);
|
|
|
|
|
DEFINE_DECODER(AND_);
|
|
|
|
|
DEFINE_DECODER(SUBF_);
|
|
|
|
|
DEFINE_DECODER(CNTLZD_);
|
|
|
|
|
DEFINE_DECODER(ANDC_);
|
|
|
|
|
DEFINE_DECODER(MULHD_);
|
|
|
|
|
DEFINE_DECODER(MULHW_);
|
|
|
|
|
DEFINE_DECODER(NEG_);
|
|
|
|
|
DEFINE_DECODER(NOR_);
|
|
|
|
|
DEFINE_DECODER(SUBFE_);
|
|
|
|
|
DEFINE_DECODER(ADDE_);
|
|
|
|
|
DEFINE_DECODER(SUBFZE_);
|
|
|
|
|
DEFINE_DECODER(ADDZE_);
|
|
|
|
|
DEFINE_DECODER(MULLD_);
|
|
|
|
|
DEFINE_DECODER(SUBFME_);
|
|
|
|
|
DEFINE_DECODER(ADDME_);
|
|
|
|
|
DEFINE_DECODER(MULLW_);
|
|
|
|
|
DEFINE_DECODER(ADD_);
|
|
|
|
|
DEFINE_DECODER(EQV_);
|
|
|
|
|
DEFINE_DECODER(XOR_);
|
|
|
|
|
DEFINE_DECODER(ORC_);
|
|
|
|
|
DEFINE_DECODER(OR_);
|
|
|
|
|
DEFINE_DECODER(DIVDU_);
|
|
|
|
|
DEFINE_DECODER(DIVWU_);
|
|
|
|
|
DEFINE_DECODER(NAND_);
|
|
|
|
|
DEFINE_DECODER(DIVD_);
|
|
|
|
|
DEFINE_DECODER(DIVW_);
|
|
|
|
|
DEFINE_DECODER(SRW_);
|
|
|
|
|
DEFINE_DECODER(SRD_);
|
|
|
|
|
DEFINE_DECODER(SRAW_);
|
|
|
|
|
DEFINE_DECODER(SRAD_);
|
|
|
|
|
DEFINE_DECODER(SRAWI_);
|
|
|
|
|
DEFINE_DECODER(SRADI_);
|
|
|
|
|
DEFINE_DECODER(EXTSH_);
|
|
|
|
|
DEFINE_DECODER(EXTSB_);
|
|
|
|
|
DEFINE_DECODER(EXTSW_);
|
|
|
|
|
DEFINE_DECODER(FDIVS_);
|
|
|
|
|
DEFINE_DECODER(FSUBS_);
|
|
|
|
|
DEFINE_DECODER(FADDS_);
|
|
|
|
|
DEFINE_DECODER(FSQRTS_);
|
|
|
|
|
DEFINE_DECODER(FRES_);
|
|
|
|
|
DEFINE_DECODER(FMULS_);
|
|
|
|
|
DEFINE_DECODER(FMADDS_);
|
|
|
|
|
DEFINE_DECODER(FMSUBS_);
|
|
|
|
|
DEFINE_DECODER(FNMSUBS_);
|
|
|
|
|
DEFINE_DECODER(FNMADDS_);
|
|
|
|
|
DEFINE_DECODER(MTFSB1_);
|
|
|
|
|
DEFINE_DECODER(MTFSB0_);
|
|
|
|
|
DEFINE_DECODER(MTFSFI_);
|
|
|
|
|
DEFINE_DECODER(MFFS_);
|
|
|
|
|
DEFINE_DECODER(MTFSF_);
|
|
|
|
|
DEFINE_DECODER(FRSP_);
|
|
|
|
|
DEFINE_DECODER(FCTIW_);
|
|
|
|
|
DEFINE_DECODER(FCTIWZ_);
|
|
|
|
|
DEFINE_DECODER(FDIV_);
|
|
|
|
|
DEFINE_DECODER(FSUB_);
|
|
|
|
|
DEFINE_DECODER(FADD_);
|
|
|
|
|
DEFINE_DECODER(FSQRT_);
|
|
|
|
|
DEFINE_DECODER(FSEL_);
|
|
|
|
|
DEFINE_DECODER(FMUL_);
|
|
|
|
|
DEFINE_DECODER(FRSQRTE_);
|
|
|
|
|
DEFINE_DECODER(FMSUB_);
|
|
|
|
|
DEFINE_DECODER(FMADD_);
|
|
|
|
|
DEFINE_DECODER(FNMSUB_);
|
|
|
|
|
DEFINE_DECODER(FNMADD_);
|
|
|
|
|
DEFINE_DECODER(FNEG_);
|
|
|
|
|
DEFINE_DECODER(FMR_);
|
|
|
|
|
DEFINE_DECODER(FNABS_);
|
|
|
|
|
DEFINE_DECODER(FABS_);
|
|
|
|
|
DEFINE_DECODER(FCTID_);
|
|
|
|
|
DEFINE_DECODER(FCTIDZ_);
|
|
|
|
|
DEFINE_DECODER(FCFID_);
|
|
|
|
|
#undef DEFINE_DECODER
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static ppu_intrp_func ppu_ret = {[](ppu_thread& ppu, ppu_opcode_t, be_t<u32>* this_op, ppu_intrp_func*)
|
|
|
|
|
{
|
|
|
|
|
// Fix PC and return (step execution)
|
|
|
|
|
ppu.cia = vm::get_addr(this_op);
|
|
|
|
|
return;
|
|
|
|
|
}};
|
|
|
|
|
|
|
|
|
|
void PPUInterpreter::interpret(PPUContext& context, std::uint32_t inst)
|
|
|
|
|
{
|
|
|
|
|
auto op = rx::cell::ppu::getOpcode(inst);
|
|
|
|
|
auto instructionAddress = context.cia;
|
|
|
|
|
|
|
|
|
|
auto this_op = reinterpret_cast<be_t<u32>*>(vm::g_base_addr + instructionAddress);
|
|
|
|
|
|
|
|
|
|
const auto fn = *reinterpret_cast<ppu_intrp_func_t*>(vm::g_exec_addr + u64{instructionAddress} * 2);
|
|
|
|
|
|
|
|
|
|
if (fn)
|
|
|
|
|
{
|
|
|
|
|
fn(static_cast<ppu_thread&>(context), std::bit_cast<ppu_opcode_t>(inst), this_op, &ppu_ret);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if (op == rx::cell::ppu::Opcode::Invalid)
|
|
|
|
|
{
|
|
|
|
|
if (g_fxo->get<ppu_function_manager>().is_func(context.cia))
|
|
|
|
|
{
|
|
|
|
|
ppu_intrp_func_t hle_function = nullptr;
|
|
|
|
|
auto hle_addr = g_fxo->get<ppu_function_manager>().addr;
|
|
|
|
|
// HLE function index
|
|
|
|
|
const u32 index = (context.cia - hle_addr) / 8;
|
|
|
|
|
|
|
|
|
|
if (context.cia % 8 == 4 && index < ppu_function_manager::get().size())
|
|
|
|
|
{
|
|
|
|
|
// HLE function placement
|
|
|
|
|
hle_function = ppu_function_manager::get()[index];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (hle_function)
|
|
|
|
|
{
|
|
|
|
|
hle_function(static_cast<ppu_thread&>(context), std::bit_cast<ppu_opcode_t>(inst), this_op, nullptr);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// std::fprintf(stderr, "%08x: %s\n", instructionAddress, std::format("{}", op).c_str());
|
|
|
|
|
impl[static_cast<int>(op)](context, std::bit_cast<rx::cell::ppu::Instruction>(inst));
|
|
|
|
|
|
|
|
|
|
if (context.cia == instructionAddress &&
|
|
|
|
|
op != rx::cell::ppu::Opcode::B &&
|
|
|
|
|
op != rx::cell::ppu::Opcode::BC &&
|
|
|
|
|
op != rx::cell::ppu::Opcode::BCLR &&
|
|
|
|
|
op != rx::cell::ppu::Opcode::BCCTR)
|
|
|
|
|
{
|
|
|
|
|
context.cia += sizeof(std::uint32_t);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extern "C"
|
|
|
|
|
{
|
|
|
|
|
[[noreturn]] void rpcsx_trap()
|
|
|
|
|
{
|
|
|
|
|
fmt::throw_exception("PPU Trap");
|
|
|
|
|
}
|
|
|
|
|
[[noreturn]] void rpcsx_invalid_instruction()
|
|
|
|
|
{
|
|
|
|
|
fmt::throw_exception("PPU Invalid Instruction");
|
|
|
|
|
}
|
|
|
|
|
[[noreturn]] void rpcsx_unimplemented_instruction()
|
|
|
|
|
{
|
|
|
|
|
fmt::throw_exception("PPU Unimplemented Instruction");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void rpcsx_vm_read(std::uint64_t vaddr, void* dest, std::size_t size)
|
|
|
|
|
{
|
|
|
|
|
std::memcpy(dest, vm::g_base_addr + vaddr, size);
|
|
|
|
|
}
|
|
|
|
|
void rpcsx_vm_write(std::uint64_t vaddr, const void* src, std::size_t size)
|
|
|
|
|
{
|
|
|
|
|
std::memcpy(vm::g_base_addr + vaddr, src, size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::uint64_t rpcsx_get_tb()
|
|
|
|
|
{
|
|
|
|
|
return get_timebased_time();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ppu_execute_syscall(PPUContext& context, u64 code)
|
|
|
|
|
{
|
|
|
|
|
return ppu_execute_syscall(static_cast<ppu_thread&>(context), code);
|
|
|
|
|
}
|
|
|
|
|
u32 ppu_lwarx(PPUContext& context, u32 addr)
|
|
|
|
|
{
|
|
|
|
|
return ppu_lwarx(static_cast<ppu_thread&>(context), addr);
|
|
|
|
|
}
|
|
|
|
|
u64 ppu_ldarx(PPUContext& context, u32 addr)
|
|
|
|
|
{
|
|
|
|
|
return ppu_ldarx(static_cast<ppu_thread&>(context), addr);
|
|
|
|
|
}
|
|
|
|
|
bool ppu_stwcx(PPUContext& context, u32 addr, u32 reg_value)
|
|
|
|
|
{
|
|
|
|
|
return ppu_stwcx(static_cast<ppu_thread&>(context), addr, reg_value);
|
|
|
|
|
}
|
|
|
|
|
bool ppu_stdcx(PPUContext& context, u32 addr, u64 reg_value)
|
|
|
|
|
{
|
|
|
|
|
return ppu_stdcx(static_cast<ppu_thread&>(context), addr, reg_value);
|
|
|
|
|
}
|
|
|
|
|
void ppu_trap(PPUContext& context, u64 addr)
|
|
|
|
|
{
|
|
|
|
|
return ppu_trap(static_cast<ppu_thread&>(context), addr);
|
|
|
|
|
}
|