rpcsx/rpcs3/Emu/Cell/PPUInterpreter.h

4720 lines
111 KiB
C
Raw Normal View History

#pragma once
#include "Emu/Cell/PPUOpcodes.h"
#include "Emu/Memory/Memory.h"
2014-08-22 23:15:02 +02:00
2015-11-16 16:04:49 +01:00
#if defined(_MSC_VER)
#include <intrin.h>
2013-11-19 11:30:58 +01:00
#else
#include <x86intrin.h>
2014-04-28 06:07:12 +02:00
#define _rotl64(x,r) (((u64)(x) << (r)) | ((u64)(x) >> (64 - (r))))
2013-11-19 11:30:58 +01:00
#endif
2015-11-16 16:04:49 +01:00
#if defined(__GNUG__)
inline std::uint64_t UMULH64(std::uint64_t a, std::uint64_t b)
{
std::uint64_t result;
__asm__("mulq %[b]" : "=d" (result) : [a] "a" (a), [b] "rm" (b));
return result;
}
inline std::int64_t MULH64(std::int64_t a, std::int64_t b)
{
std::int64_t result;
__asm__("imulq %[b]" : "=d" (result) : [a] "a" (a), [b] "rm" (b));
return result;
}
#else
#define UMULH64 __umulh
#define MULH64 __mulh
#endif
#include <fenv.h>
extern u64 rotate_mask[64][64]; // defined in PPUThread.cpp
extern u64 get_timebased_time();
2015-03-16 22:38:21 +01:00
inline void InitRotateMask()
{
static bool inited = false;
if(inited) return;
for(u32 mb=0; mb<64; mb++) for(u32 me=0; me<64; me++)
{
const u64 mask = ((u64)-1 >> mb) ^ ((me >= 63) ? 0 : (u64)-1 >> (me + 1));
rotate_mask[mb][me] = mb > me ? ~mask : mask;
}
inited = true;
}
inline u8 rotl8(const u8 x, const u8 n) { return (x << n) | (x >> (8 - n)); }
inline u8 rotr8(const u8 x, const u8 n) { return (x >> n) | (x << (8 - n)); }
inline u16 rotl16(const u16 x, const u8 n) { return (x << n) | (x >> (16 - n)); }
inline u16 rotr16(const u16 x, const u8 n) { return (x >> n) | (x << (16 - n)); }
/*
u32 rotl32(const u32 x, const u8 n) { return (x << n) | (x >> (32 - n)); }
u32 rotr32(const u32 x, const u8 n) { return (x >> n) | (x << (32 - n)); }
u64 rotl64(const u64 x, const u8 n) { return (x << n) | (x >> (64 - n)); }
u64 rotr64(const u64 x, const u8 n) { return (x >> n) | (x << (64 - n)); }
*/
2014-03-19 15:47:28 +01:00
#define rotl32(x, n) _rotl64((u64)(u32)x | ((u64)(u32)x << 32), n)
#define rotr32(x, n) _rotr64((u64)(u32)x | ((u64)(u32)x << 32), n)
#define rotl64 _rotl64
#define rotr64 _rotr64
static double SilenceNaN(double x)
{
u64 bits = (u64&)x;
bits |= 0x0008000000000000ULL;
return (double&)bits;
}
2015-04-03 18:56:57 +02:00
static float SilenceNaN(float x)
{
return static_cast<float>(SilenceNaN(static_cast<double>(x)));
}
static void SetHostRoundingMode(u32 rn)
{
switch (rn)
{
case FPSCR_RN_NEAR:
fesetround(FE_TONEAREST);
break;
case FPSCR_RN_ZERO:
fesetround(FE_TOWARDZERO);
break;
case FPSCR_RN_PINF:
fesetround(FE_UPWARD);
break;
case FPSCR_RN_MINF:
fesetround(FE_DOWNWARD);
break;
}
}
2014-10-25 03:08:47 +02:00
namespace ppu_recompiler_llvm {
class Compiler;
class RecompilationEngine;
2014-10-25 03:08:47 +02:00
}
class ppu_llvm_test_class;
class PPUInterpreter : public PPUOpcodes
{
#ifdef PPU_LLVM_RECOMPILER
friend class ppu_recompiler_llvm::Compiler;
friend class ppu_llvm_test_class;
friend class ppu_recompiler_llvm::RecompilationEngine;
#endif
private:
PPUThread& CPU;
public:
PPUInterpreter(PPUThread& cpu) : CPU(cpu)
{
}
private:
void CheckHostFPExceptions()
{
CPU.SetFPSCR_FI(fetestexcept(FE_INEXACT) != 0);
if (fetestexcept(FE_UNDERFLOW)) CPU.SetFPSCRException(FPSCR_UX);
if (fetestexcept(FE_OVERFLOW)) CPU.SetFPSCRException(FPSCR_OX);
}
2016-01-06 11:47:06 +01:00
void NULL_OP() override
{
throw EXCEPTION("Null operation");
}
2016-01-06 11:47:06 +01:00
void NOP() override
{
//__asm nop
}
float CheckVSCR_NJ(const float v) const
{
if(!CPU.VSCR.NJ) return v;
2013-11-19 11:30:58 +01:00
const int fpc = _fpclass(v);
#ifdef __GNUG__
if(fpc == FP_SUBNORMAL)
return std::signbit(v) ? -0.0f : 0.0f;
2013-11-19 11:30:58 +01:00
#else
if(fpc & _FPCLASS_ND) return -0.0f;
if(fpc & _FPCLASS_PD) return 0.0f;
2013-11-19 11:30:58 +01:00
#endif
return v;
}
2013-07-04 16:20:36 +02:00
bool CheckCondition(u32 bo, u32 bi)
{
const u8 bo0 = (bo & 0x10) ? 1 : 0;
const u8 bo1 = (bo & 0x08) ? 1 : 0;
const u8 bo2 = (bo & 0x04) ? 1 : 0;
const u8 bo3 = (bo & 0x02) ? 1 : 0;
if(!bo2) --CPU.CTR;
const u8 ctr_ok = bo2 | ((CPU.CTR != 0) ^ bo3);
const u8 cond_ok = bo0 | (CPU.IsCR(bi) ^ (~bo1 & 0x1));
return ctr_ok && cond_ok;
}
u64 ReadSPR(u32 spr)
{
const u32 n = (spr >> 5) | ((spr & 0x1f) << 5);
switch (n)
{
case 0x001: return CPU.XER.XER;
case 0x008: return CPU.LR;
case 0x009: return CPU.CTR;
case 0x100: return CPU.VRSAVE;
case 0x103: return CPU.SPRG[3];
case 0x10C: CPU.TB = get_timebased_time(); return CPU.TB;
case 0x10D: CPU.TB = get_timebased_time(); return CPU.TB >> 32;
case 0x110:
case 0x111:
case 0x112:
case 0x113:
case 0x114:
case 0x115:
case 0x116:
case 0x117: return CPU.SPRG[n - 0x110];
}
throw EXCEPTION("Unknown SPR (spr=0x%x, n=0x%x)", spr, n);
}
void WriteSPR(u32 spr, u64 value)
{
const u32 n = (spr >> 5) | ((spr & 0x1f) << 5);
switch (n)
{
case 0x001: CPU.XER.XER = value; return;
case 0x008: CPU.LR = value; return;
case 0x009: CPU.CTR = value; return;
case 0x100: CPU.VRSAVE = (u32)value; return;
case 0x103: throw EXCEPTION("WriteSPR(0x103, 0x%llx): Write to read-only SPR", value);
case 0x10C: throw EXCEPTION("WriteSPR(0x10C, 0x%llx): Write to time-based SPR", value);
case 0x10D: throw EXCEPTION("WriteSPR(0x10D, 0x%llx): Write to time-based SPR", value);
case 0x110:
case 0x111:
case 0x112:
case 0x113:
case 0x114:
case 0x115:
case 0x116:
2014-11-21 14:52:01 +01:00
case 0x117: CPU.SPRG[n - 0x110] = value; return;
}
throw EXCEPTION("Unknown SPR (spr=0x%x, n=0x%x, value=0x%llx)", spr, n, value);
}
2016-01-06 11:47:06 +01:00
void TDI(u32 to, u32 ra, s32 simm16) override
{
s64 a = CPU.GPR[ra];
if( (a < (s64)simm16 && (to & 0x10)) ||
(a > (s64)simm16 && (to & 0x8)) ||
(a == (s64)simm16 && (to & 0x4)) ||
((u64)a < (u64)simm16 && (to & 0x2)) ||
((u64)a > (u64)simm16 && (to & 0x1)) )
{
throw EXCEPTION("Trap! (tdi 0x%x, r%d, 0x%x)", to, ra, simm16);
}
}
static void TWI_impl(PPUThread *CPU, u32 to, u32 ra, s32 simm16)
{
s32 a = (s32)CPU->GPR[ra];
if ((a < simm16 && (to & 0x10)) ||
(a > simm16 && (to & 0x8)) ||
(a == simm16 && (to & 0x4)) ||
((u32)a < (u32)simm16 && (to & 0x2)) ||
((u32)a > (u32)simm16 && (to & 0x1)) )
{
throw EXCEPTION("Trap! (twi 0x%x, r%d, 0x%x)", to, ra, simm16);
}
}
2016-01-06 11:47:06 +01:00
void TWI(u32 to, u32 ra, s32 simm16) override
{
TWI_impl(&CPU, to, ra, simm16);
}
2016-01-06 11:47:06 +01:00
void MFVSCR(u32 vd) override //nf
2013-07-04 16:20:36 +02:00
{
CPU.VPR[vd].clear();
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u32[0] = CPU.VSCR.VSCR;
}
2016-01-06 11:47:06 +01:00
void MTVSCR(u32 vb) override
2013-07-04 16:20:36 +02:00
{
CPU.VSCR.VSCR = CPU.VPR[vb]._u32[0];
CPU.VSCR.X = CPU.VSCR.Y = 0;
}
2016-01-06 11:47:06 +01:00
void VADDCUW(u32 vd, u32 va, u32 vb) override //nf
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u32[w] = ~CPU.VPR[va]._u32[w] < CPU.VPR[vb]._u32[w];
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VADDFP(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
SetHostRoundingMode(FPSCR_RN_NEAR);
2013-07-04 16:20:36 +02:00
for (uint w = 0; w < 4; w++)
{
const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]);
const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]);
if (std::isnan(a))
CPU.VPR[vd]._f[w] = SilenceNaN(a);
else if (std::isnan(b))
CPU.VPR[vd]._f[w] = SilenceNaN(b);
else if (std::isinf(a) && std::isinf(b) && a != b)
CPU.VPR[vd]._f[w] = (float)FPR_NAN;
else
CPU.VPR[vd]._f[w] = CheckVSCR_NJ(a + b);
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VADDSBS(u32 vd, u32 va, u32 vb) override //nf
2013-07-04 16:20:36 +02:00
{
for(u32 b=0; b<16; ++b)
{
2013-07-04 16:20:36 +02:00
s16 result = (s16)CPU.VPR[va]._s8[b] + (s16)CPU.VPR[vb]._s8[b];
if (result > 0x7f)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._s8[b] = 0x7f;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else if (result < -0x80)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._s8[b] = -0x80;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else
2014-08-30 19:51:00 +02:00
CPU.VPR[vd]._s8[b] = (s8)result;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VADDSHS(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint h = 0; h < 8; h++)
{
2013-07-04 16:20:36 +02:00
s32 result = (s32)CPU.VPR[va]._s16[h] + (s32)CPU.VPR[vb]._s16[h];
2013-07-04 16:20:36 +02:00
if (result > 0x7fff)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._s16[h] = 0x7fff;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else if (result < -0x8000)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._s16[h] = -0x8000;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else
CPU.VPR[vd]._s16[h] = result;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VADDSWS(u32 vd, u32 va, u32 vb) override //nf
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
s64 result = (s64)CPU.VPR[va]._s32[w] + (s64)CPU.VPR[vb]._s32[w];
if (result > 0x7fffffff)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._s32[w] = 0x7fffffff;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else if (result < (s32)0x80000000)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._s32[w] = 0x80000000;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else
2014-08-30 19:51:00 +02:00
CPU.VPR[vd]._s32[w] = (s32)result;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VADDUBM(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint b = 0; b < 16; b++)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u8[b] = CPU.VPR[va]._u8[b] + CPU.VPR[vb]._u8[b];
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VADDUBS(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint b = 0; b < 16; b++)
{
2013-07-04 16:20:36 +02:00
u16 result = (u16)CPU.VPR[va]._u8[b] + (u16)CPU.VPR[vb]._u8[b];
2013-07-04 16:20:36 +02:00
if (result > 0xff)
{
CPU.VPR[vd]._u8[b] = 0xff;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else
2014-08-30 19:51:00 +02:00
CPU.VPR[vd]._u8[b] = (u8)result;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VADDUHM(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint h = 0; h < 8; h++)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u16[h] = CPU.VPR[va]._u16[h] + CPU.VPR[vb]._u16[h];
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VADDUHS(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint h = 0; h < 8; h++)
{
2013-07-04 16:20:36 +02:00
u32 result = (u32)CPU.VPR[va]._u16[h] + (u32)CPU.VPR[vb]._u16[h];
2013-07-04 16:20:36 +02:00
if (result > 0xffff)
{
CPU.VPR[vd]._u16[h] = 0xffff;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else
CPU.VPR[vd]._u16[h] = result;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VADDUWM(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] + CPU.VPR[vb]._u32[w];
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VADDUWS(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
u64 result = (u64)CPU.VPR[va]._u32[w] + (u64)CPU.VPR[vb]._u32[w];
if (result > 0xffffffff)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u32[w] = 0xffffffff;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else
2014-08-30 19:51:00 +02:00
CPU.VPR[vd]._u32[w] = (u32)result;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VAND(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] & CPU.VPR[vb]._u32[w];
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VANDC(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] & (~CPU.VPR[vb]._u32[w]);
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VAVGSB(u32 vd, u32 va, u32 vb) override //nf
2013-07-04 16:20:36 +02:00
{
for (uint b = 0; b < 16; b++)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._s8[b] = (CPU.VPR[va]._s8[b] + CPU.VPR[vb]._s8[b] + 1) >> 1;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VAVGSH(u32 vd, u32 va, u32 vb) override //nf
2013-07-04 16:20:36 +02:00
{
for (uint h = 0; h < 8; h++)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._s16[h] = (CPU.VPR[va]._s16[h] + CPU.VPR[vb]._s16[h] + 1) >> 1;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VAVGSW(u32 vd, u32 va, u32 vb) override //nf
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._s32[w] = ((s64)CPU.VPR[va]._s32[w] + (s64)CPU.VPR[vb]._s32[w] + 1) >> 1;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VAVGUB(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint b = 0; b < 16; b++)
CPU.VPR[vd]._u8[b] = (CPU.VPR[va]._u8[b] + CPU.VPR[vb]._u8[b] + 1) >> 1;
}
2016-01-06 11:47:06 +01:00
void VAVGUH(u32 vd, u32 va, u32 vb) override //nf
2013-07-04 16:20:36 +02:00
{
for (uint h = 0; h < 8; h++)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u16[h] = (CPU.VPR[va]._u16[h] + CPU.VPR[vb]._u16[h] + 1) >> 1;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VAVGUW(u32 vd, u32 va, u32 vb) override //nf
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u32[w] = ((u64)CPU.VPR[va]._u32[w] + (u64)CPU.VPR[vb]._u32[w] + 1) >> 1;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VCFSX(u32 vd, u32 uimm5, u32 vb) override
2013-07-04 16:20:36 +02:00
{
SetHostRoundingMode(FPSCR_RN_NEAR);
2013-07-04 16:20:36 +02:00
u32 scale = 1 << uimm5;
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._f[w] = ((float)CPU.VPR[vb]._s32[w]) / scale;
}
}
2016-01-06 11:47:06 +01:00
void VCFUX(u32 vd, u32 uimm5, u32 vb) override
2013-07-04 16:20:36 +02:00
{
SetHostRoundingMode(FPSCR_RN_NEAR);
2013-07-04 16:20:36 +02:00
u32 scale = 1 << uimm5;
2013-07-04 16:20:36 +02:00
for (uint w = 0; w < 4; w++)
{
CPU.VPR[vd]._f[w] = ((float)CPU.VPR[vb]._u32[w]) / scale;
}
2013-07-04 16:20:36 +02:00
}
2015-07-03 18:07:36 +02:00
void VCMPBFP(u32 vd, u32 va, u32 vb, u32 rc)
2013-07-04 16:20:36 +02:00
{
bool allInBounds = true;
2013-07-04 16:20:36 +02:00
for (uint w = 0; w < 4; w++)
{
u32 mask = 1<<31 | 1<<30;
const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]);
const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]);
if (a <= b) mask &= ~(1 << 31);
if (a >= -b) mask &= ~(1 << 30);
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u32[w] = mask;
2013-07-04 16:20:36 +02:00
if (mask)
allInBounds = false;
}
if (rc)
2013-07-04 16:20:36 +02:00
{
// Bit n<>2 of CR6
CPU.SetCR(6, 0);
CPU.SetCRBit(6, 0x2, allInBounds);
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VCMPBFP(u32 vd, u32 va, u32 vb) override {VCMPBFP(vd, va, vb, false);}
void VCMPBFP_(u32 vd, u32 va, u32 vb) override {VCMPBFP(vd, va, vb, true);}
2015-07-03 18:07:36 +02:00
void VCMPEQFP(u32 vd, u32 va, u32 vb, u32 rc)
2013-07-04 16:20:36 +02:00
{
int all_equal = 0x8;
int none_equal = 0x2;
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
if (CPU.VPR[va]._f[w] == CPU.VPR[vb]._f[w])
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u32[w] = 0xffffffff;
none_equal = 0;
}
2013-07-04 16:20:36 +02:00
else
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u32[w] = 0;
all_equal = 0;
}
2013-07-04 16:20:36 +02:00
}
if (rc) CPU.CR.cr6 = all_equal | none_equal;
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VCMPEQFP(u32 vd, u32 va, u32 vb) override {VCMPEQFP(vd, va, vb, false);}
void VCMPEQFP_(u32 vd, u32 va, u32 vb) override {VCMPEQFP(vd, va, vb, true);}
2015-07-03 18:07:36 +02:00
void VCMPEQUB(u32 vd, u32 va, u32 vb, u32 rc)
2013-07-04 16:20:36 +02:00
{
int all_equal = 0x8;
int none_equal = 0x2;
for (uint b = 0; b < 16; b++)
{
2013-07-04 16:20:36 +02:00
if (CPU.VPR[va]._u8[b] == CPU.VPR[vb]._u8[b])
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u8[b] = 0xff;
none_equal = 0;
}
2013-07-04 16:20:36 +02:00
else
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u8[b] = 0;
all_equal = 0;
}
2013-07-04 16:20:36 +02:00
}
if (rc) CPU.CR.cr6 = all_equal | none_equal;
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VCMPEQUB(u32 vd, u32 va, u32 vb) override {VCMPEQUB(vd, va, vb, false);}
void VCMPEQUB_(u32 vd, u32 va, u32 vb) override {VCMPEQUB(vd, va, vb, true);}
2015-07-03 18:07:36 +02:00
void VCMPEQUH(u32 vd, u32 va, u32 vb, u32 rc) //nf
2013-07-04 16:20:36 +02:00
{
int all_equal = 0x8;
int none_equal = 0x2;
for (uint h = 0; h < 8; h++)
{
2013-07-04 16:20:36 +02:00
if (CPU.VPR[va]._u16[h] == CPU.VPR[vb]._u16[h])
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u16[h] = 0xffff;
none_equal = 0;
}
2013-07-04 16:20:36 +02:00
else
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u16[h] = 0;
all_equal = 0;
}
2013-07-04 16:20:36 +02:00
}
if (rc) CPU.CR.cr6 = all_equal | none_equal;
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VCMPEQUH(u32 vd, u32 va, u32 vb) override {VCMPEQUH(vd, va, vb, false);}
void VCMPEQUH_(u32 vd, u32 va, u32 vb) override {VCMPEQUH(vd, va, vb, true);}
2015-07-03 18:07:36 +02:00
void VCMPEQUW(u32 vd, u32 va, u32 vb, u32 rc)
2013-07-04 16:20:36 +02:00
{
int all_equal = 0x8;
int none_equal = 0x2;
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
if (CPU.VPR[va]._u32[w] == CPU.VPR[vb]._u32[w])
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u32[w] = 0xffffffff;
none_equal = 0;
}
2013-07-04 16:20:36 +02:00
else
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u32[w] = 0;
all_equal = 0;
}
2013-07-04 16:20:36 +02:00
}
if (rc) CPU.CR.cr6 = all_equal | none_equal;
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VCMPEQUW(u32 vd, u32 va, u32 vb) override {VCMPEQUW(vd, va, vb, false);}
void VCMPEQUW_(u32 vd, u32 va, u32 vb) override {VCMPEQUW(vd, va, vb, true);}
2015-07-03 18:07:36 +02:00
void VCMPGEFP(u32 vd, u32 va, u32 vb, u32 rc)
2013-07-04 16:20:36 +02:00
{
int all_ge = 0x8;
int none_ge = 0x2;
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
if (CPU.VPR[va]._f[w] >= CPU.VPR[vb]._f[w])
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u32[w] = 0xffffffff;
none_ge = 0;
}
2013-07-04 16:20:36 +02:00
else
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u32[w] = 0;
all_ge = 0;
}
2013-07-04 16:20:36 +02:00
}
if (rc) CPU.CR.cr6 = all_ge | none_ge;
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VCMPGEFP(u32 vd, u32 va, u32 vb) override {VCMPGEFP(vd, va, vb, false);}
void VCMPGEFP_(u32 vd, u32 va, u32 vb) override {VCMPGEFP(vd, va, vb, true);}
2015-07-03 18:07:36 +02:00
void VCMPGTFP(u32 vd, u32 va, u32 vb, u32 rc)
2013-07-04 16:20:36 +02:00
{
int all_ge = 0x8;
int none_ge = 0x2;
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
if (CPU.VPR[va]._f[w] > CPU.VPR[vb]._f[w])
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u32[w] = 0xffffffff;
none_ge = 0;
}
2013-07-04 16:20:36 +02:00
else
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u32[w] = 0;
all_ge = 0;
}
2013-07-04 16:20:36 +02:00
}
if (rc) CPU.CR.cr6 = all_ge | none_ge;
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VCMPGTFP(u32 vd, u32 va, u32 vb) override {VCMPGTFP(vd, va, vb, false);}
void VCMPGTFP_(u32 vd, u32 va, u32 vb) override {VCMPGTFP(vd, va, vb, true);}
2015-07-03 18:07:36 +02:00
void VCMPGTSB(u32 vd, u32 va, u32 vb, u32 rc) //nf
2013-07-04 16:20:36 +02:00
{
int all_gt = 0x8;
int none_gt = 0x2;
for (uint b = 0; b < 16; b++)
{
2013-07-04 16:20:36 +02:00
if (CPU.VPR[va]._s8[b] > CPU.VPR[vb]._s8[b])
{
CPU.VPR[vd]._u8[b] = 0xff;
none_gt = 0;
}
else
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u8[b] = 0;
all_gt = 0;
}
}
2013-07-04 16:20:36 +02:00
if (rc) CPU.CR.cr6 = all_gt | none_gt;
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VCMPGTSB(u32 vd, u32 va, u32 vb) override {VCMPGTSB(vd, va, vb, false);}
void VCMPGTSB_(u32 vd, u32 va, u32 vb) override {VCMPGTSB(vd, va, vb, true);}
2015-07-03 18:07:36 +02:00
void VCMPGTSH(u32 vd, u32 va, u32 vb, u32 rc)
2013-07-04 16:20:36 +02:00
{
int all_gt = 0x8;
int none_gt = 0x2;
for (uint h = 0; h < 8; h++)
{
2013-07-04 16:20:36 +02:00
if (CPU.VPR[va]._s16[h] > CPU.VPR[vb]._s16[h])
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u16[h] = 0xffff;
none_gt = 0;
}
2013-07-04 16:20:36 +02:00
else
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u16[h] = 0;
all_gt = 0;
}
2013-07-04 16:20:36 +02:00
}
if (rc) CPU.CR.cr6 = all_gt | none_gt;
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VCMPGTSH(u32 vd, u32 va, u32 vb) override {VCMPGTSH(vd, va, vb, false);}
void VCMPGTSH_(u32 vd, u32 va, u32 vb) override {VCMPGTSH(vd, va, vb, true);}
2015-07-03 18:07:36 +02:00
void VCMPGTSW(u32 vd, u32 va, u32 vb, u32 rc)
2013-07-04 16:20:36 +02:00
{
int all_gt = 0x8;
int none_gt = 0x2;
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
if (CPU.VPR[va]._s32[w] > CPU.VPR[vb]._s32[w])
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u32[w] = 0xffffffff;
none_gt = 0;
}
2013-07-04 16:20:36 +02:00
else
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u32[w] = 0;
all_gt = 0;
}
2013-07-04 16:20:36 +02:00
}
if (rc) CPU.CR.cr6 = all_gt | none_gt;
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VCMPGTSW(u32 vd, u32 va, u32 vb) override {VCMPGTSW(vd, va, vb, false);}
void VCMPGTSW_(u32 vd, u32 va, u32 vb) override {VCMPGTSW(vd, va, vb, true);}
2015-07-03 18:07:36 +02:00
void VCMPGTUB(u32 vd, u32 va, u32 vb, u32 rc)
2013-07-04 16:20:36 +02:00
{
int all_gt = 0x8;
int none_gt = 0x2;
for (uint b = 0; b < 16; b++)
{
2013-07-04 16:20:36 +02:00
if (CPU.VPR[va]._u8[b] > CPU.VPR[vb]._u8[b])
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u8[b] = 0xff;
none_gt = 0;
}
2013-07-04 16:20:36 +02:00
else
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u8[b] = 0;
all_gt = 0;
}
2013-07-04 16:20:36 +02:00
}
if (rc) CPU.CR.cr6 = all_gt | none_gt;
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VCMPGTUB(u32 vd, u32 va, u32 vb) override {VCMPGTUB(vd, va, vb, false);}
void VCMPGTUB_(u32 vd, u32 va, u32 vb) override {VCMPGTUB(vd, va, vb, true);}
2015-07-03 18:07:36 +02:00
void VCMPGTUH(u32 vd, u32 va, u32 vb, u32 rc)
2013-07-04 16:20:36 +02:00
{
int all_gt = 0x8;
int none_gt = 0x2;
for (uint h = 0; h < 8; h++)
{
2013-07-04 16:20:36 +02:00
if (CPU.VPR[va]._u16[h] > CPU.VPR[vb]._u16[h])
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u16[h] = 0xffff;
none_gt = 0;
}
2013-07-04 16:20:36 +02:00
else
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u16[h] = 0;
all_gt = 0;
}
2013-07-04 16:20:36 +02:00
}
if (rc) CPU.CR.cr6 = all_gt | none_gt;
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VCMPGTUH(u32 vd, u32 va, u32 vb) override {VCMPGTUH(vd, va, vb, false);}
void VCMPGTUH_(u32 vd, u32 va, u32 vb) override {VCMPGTUH(vd, va, vb, true);}
2015-07-03 18:07:36 +02:00
void VCMPGTUW(u32 vd, u32 va, u32 vb, u32 rc)
2013-07-04 16:20:36 +02:00
{
int all_gt = 0x8;
int none_gt = 0x2;
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
if (CPU.VPR[va]._u32[w] > CPU.VPR[vb]._u32[w])
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u32[w] = 0xffffffff;
none_gt = 0;
}
2013-07-04 16:20:36 +02:00
else
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u32[w] = 0;
all_gt = 0;
}
}
2013-07-04 16:20:36 +02:00
if (rc) CPU.CR.cr6 = all_gt | none_gt;
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VCMPGTUW(u32 vd, u32 va, u32 vb) override {VCMPGTUW(vd, va, vb, false);}
void VCMPGTUW_(u32 vd, u32 va, u32 vb) override {VCMPGTUW(vd, va, vb, true);}
void VCTSXS(u32 vd, u32 uimm5, u32 vb) override
2013-07-04 16:20:36 +02:00
{
u32 nScale = 1 << uimm5;
2013-07-04 16:20:36 +02:00
for (uint w = 0; w < 4; w++)
{
const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]);
if (std::isnan(b))
2014-11-23 14:36:20 +01:00
{
CPU.VPR[vd]._s32[w] = 0;
2014-11-23 14:36:20 +01:00
}
else
2014-11-23 14:36:20 +01:00
{
double result = (double)b * nScale;
if (result > 0x7fffffff)
{
CPU.VPR[vd]._s32[w] = (int)0x7fffffff;
CPU.VSCR.SAT = 1;
}
else if (result < -pow(2, 31))
{
CPU.VPR[vd]._s32[w] = (int)0x80000000;
CPU.VSCR.SAT = 1;
}
else
CPU.VPR[vd]._s32[w] = (int)trunc(result);
2014-11-23 14:36:20 +01:00
}
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VCTUXS(u32 vd, u32 uimm5, u32 vb) override
2013-07-04 16:20:36 +02:00
{
u32 nScale = 1 << uimm5;
2013-07-04 16:20:36 +02:00
for (uint w = 0; w < 4; w++)
{
const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]);
if (std::isnan(b))
2014-11-23 14:36:20 +01:00
{
CPU.VPR[vd]._s32[w] = 0;
2014-11-23 14:36:20 +01:00
}
else
2014-11-23 14:36:20 +01:00
{
double result = (double)b * nScale;
if (result > 0xffffffffu)
{
CPU.VPR[vd]._u32[w] = 0xffffffffu;
CPU.VSCR.SAT = 1;
}
else if (result < 0)
{
CPU.VPR[vd]._u32[w] = 0;
CPU.VSCR.SAT = 1;
}
else
CPU.VPR[vd]._u32[w] = (u32)trunc(result);
2014-11-23 14:36:20 +01:00
}
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VEXPTEFP(u32 vd, u32 vb) override
2013-07-04 16:20:36 +02:00
{
2014-11-23 14:36:20 +01:00
// vd = 2^x
2013-07-04 16:20:36 +02:00
// ISA : Note that the value placed into the element of vD may vary between implementations
// and between different executions on the same implementation.
SetHostRoundingMode(FPSCR_RN_NEAR);
2013-07-04 16:20:36 +02:00
for (uint w = 0; w < 4; w++)
{
const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]);
if (std::isnan(b))
CPU.VPR[vd]._f[w] = SilenceNaN(b);
else
CPU.VPR[vd]._f[w] = CheckVSCR_NJ(powf(2.0f, b));
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VLOGEFP(u32 vd, u32 vb) override
2013-07-04 16:20:36 +02:00
{
// ISA : Note that the value placed into the element of vD may vary between implementations
// and between different executions on the same implementation.
SetHostRoundingMode(FPSCR_RN_NEAR);
2013-07-04 16:20:36 +02:00
for (uint w = 0; w < 4; w++)
{
const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]);
if (std::isnan(b))
CPU.VPR[vd]._f[w] = SilenceNaN(b);
else
CPU.VPR[vd]._f[w] = log2f(b); // Can never be denormal.
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMADDFP(u32 vd, u32 va, u32 vc, u32 vb) override
2013-07-04 16:20:36 +02:00
{
SetHostRoundingMode(FPSCR_RN_NEAR);
2013-07-04 16:20:36 +02:00
for (uint w = 0; w < 4; w++)
{
const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]);
const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]);
const float c = CheckVSCR_NJ(CPU.VPR[vc]._f[w]);
if (std::isnan(a))
CPU.VPR[vd]._f[w] = SilenceNaN(a);
else if (std::isnan(b))
CPU.VPR[vd]._f[w] = SilenceNaN(b);
else if (std::isnan(c))
CPU.VPR[vd]._f[w] = SilenceNaN(c);
else if ((std::isinf(a) && c == 0) || (a == 0 && std::isinf(c)))
CPU.VPR[vd]._f[w] = (float)FPR_NAN;
else
{
const float result = fmaf(a, c, b);
if (std::isnan(result))
CPU.VPR[vd]._f[w] = (float)FPR_NAN;
else
CPU.VPR[vd]._f[w] = CheckVSCR_NJ(result);
}
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMAXFP(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]);
const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]);
if (std::isnan(a))
CPU.VPR[vd]._f[w] = SilenceNaN(a);
else if (std::isnan(b))
CPU.VPR[vd]._f[w] = SilenceNaN(b);
else if (a > b)
CPU.VPR[vd]._f[w] = a;
else if (b > a)
CPU.VPR[vd]._f[w] = b;
else if (CPU.VPR[vb]._u32[w] == 0x80000000)
CPU.VPR[vd]._f[w] = a; // max(+0,-0) = +0
else
CPU.VPR[vd]._f[w] = b;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMAXSB(u32 vd, u32 va, u32 vb) override //nf
2013-07-04 16:20:36 +02:00
{
for (uint b = 0; b < 16; b++)
CPU.VPR[vd]._s8[b] = std::max(CPU.VPR[va]._s8[b], CPU.VPR[vb]._s8[b]);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMAXSH(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint h = 0; h < 8; h++)
{
CPU.VPR[vd]._s16[h] = std::max(CPU.VPR[va]._s16[h], CPU.VPR[vb]._s16[h]);
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMAXSW(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
CPU.VPR[vd]._s32[w] = std::max(CPU.VPR[va]._s32[w], CPU.VPR[vb]._s32[w]);
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMAXUB(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint b = 0; b < 16; b++)
CPU.VPR[vd]._u8[b] = std::max(CPU.VPR[va]._u8[b], CPU.VPR[vb]._u8[b]);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMAXUH(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint h = 0; h < 8; h++)
{
CPU.VPR[vd]._u16[h] = std::max(CPU.VPR[va]._u16[h], CPU.VPR[vb]._u16[h]);
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMAXUW(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
CPU.VPR[vd]._u32[w] = std::max(CPU.VPR[va]._u32[w], CPU.VPR[vb]._u32[w]);
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMHADDSHS(u32 vd, u32 va, u32 vb, u32 vc) override
2013-07-04 16:20:36 +02:00
{
for (uint h = 0; h < 8; h++)
{
2014-11-23 14:36:20 +01:00
s32 result = (s32)CPU.VPR[va]._s16[h] * (s32)CPU.VPR[vb]._s16[h];
result = (result >> 15) + (s32)CPU.VPR[vc]._s16[h];
2013-07-04 16:20:36 +02:00
if (result > INT16_MAX)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._s16[h] = (s16)INT16_MAX;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else if (result < INT16_MIN)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._s16[h] = (s16)INT16_MIN;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else
CPU.VPR[vd]._s16[h] = (s16)result;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMHRADDSHS(u32 vd, u32 va, u32 vb, u32 vc) override
2013-07-04 16:20:36 +02:00
{
for (uint h = 0; h < 8; h++)
{
2014-11-23 14:36:20 +01:00
s32 result = ((s32)CPU.VPR[va]._s16[h] * (s32)CPU.VPR[vb]._s16[h]) + 0x4000;
result = (result >> 15) + (s32)CPU.VPR[vc]._s16[h];
2013-07-04 16:20:36 +02:00
if (result > INT16_MAX)
{
CPU.VPR[vd]._s16[h] = (s16)INT16_MAX;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else if (result < INT16_MIN)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._s16[h] = (s16)INT16_MIN;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else
CPU.VPR[vd]._s16[h] = (s16)result;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMINFP(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]);
const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]);
if (std::isnan(a))
CPU.VPR[vd]._f[w] = SilenceNaN(a);
else if (std::isnan(b))
CPU.VPR[vd]._f[w] = SilenceNaN(b);
else if (a < b)
CPU.VPR[vd]._f[w] = a;
else if (b < a)
CPU.VPR[vd]._f[w] = b;
else if (CPU.VPR[vb]._u32[w] == 0x00000000)
CPU.VPR[vd]._f[w] = a; // min(-0,+0) = -0
else
CPU.VPR[vd]._f[w] = b;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMINSB(u32 vd, u32 va, u32 vb) override //nf
2013-07-04 16:20:36 +02:00
{
for (uint b = 0; b < 16; b++)
{
CPU.VPR[vd]._s8[b] = std::min(CPU.VPR[va]._s8[b], CPU.VPR[vb]._s8[b]);
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMINSH(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint h = 0; h < 8; h++)
{
CPU.VPR[vd]._s16[h] = std::min(CPU.VPR[va]._s16[h], CPU.VPR[vb]._s16[h]);
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMINSW(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
CPU.VPR[vd]._s32[w] = std::min(CPU.VPR[va]._s32[w], CPU.VPR[vb]._s32[w]);
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMINUB(u32 vd, u32 va, u32 vb)override
2013-07-04 16:20:36 +02:00
{
for (uint b = 0; b < 16; b++)
{
CPU.VPR[vd]._u8[b] = std::min(CPU.VPR[va]._u8[b], CPU.VPR[vb]._u8[b]);
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMINUH(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint h = 0; h < 8; h++)
{
CPU.VPR[vd]._u16[h] = std::min(CPU.VPR[va]._u16[h], CPU.VPR[vb]._u16[h]);
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMINUW(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
CPU.VPR[vd]._u32[w] = std::min(CPU.VPR[va]._u32[w], CPU.VPR[vb]._u32[w]);
2013-07-04 16:20:36 +02:00
}
}
2016-01-06 11:47:06 +01:00
void VMLADDUHM(u32 vd, u32 va, u32 vb, u32 vc) override
2013-07-04 16:20:36 +02:00
{
for (uint h = 0; h < 8; h++)
{
CPU.VPR[vd]._u16[h] = CPU.VPR[va]._u16[h] * CPU.VPR[vb]._u16[h] + CPU.VPR[vc]._u16[h];
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMRGHB(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
v128 VA = CPU.VPR[va];
v128 VB = CPU.VPR[vb];
2013-07-04 16:20:36 +02:00
for (uint h = 0; h < 8; h++)
{
CPU.VPR[vd]._u8[15 - h*2] = VA._u8[15 - h];
CPU.VPR[vd]._u8[15 - h*2 - 1] = VB._u8[15 - h];
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMRGHH(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
v128 VA = CPU.VPR[va];
v128 VB = CPU.VPR[vb];
2013-07-04 16:20:36 +02:00
for (uint w = 0; w < 4; w++)
{
CPU.VPR[vd]._u16[7 - w*2] = VA._u16[7 - w];
CPU.VPR[vd]._u16[7 - w*2 - 1] = VB._u16[7 - w];
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMRGHW(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
v128 VA = CPU.VPR[va];
v128 VB = CPU.VPR[vb];
2013-07-04 16:20:36 +02:00
for (uint d = 0; d < 2; d++)
{
CPU.VPR[vd]._u32[3 - d*2] = VA._u32[3 - d];
CPU.VPR[vd]._u32[3 - d*2 - 1] = VB._u32[3 - d];
2013-07-04 16:20:36 +02:00
}
}
2016-01-06 11:47:06 +01:00
void VMRGLB(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
v128 VA = CPU.VPR[va];
v128 VB = CPU.VPR[vb];
2013-07-04 16:20:36 +02:00
for (uint h = 0; h < 8; h++)
{
CPU.VPR[vd]._u8[15 - h*2] = VA._u8[7 - h];
CPU.VPR[vd]._u8[15 - h*2 - 1] = VB._u8[7 - h];
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMRGLH(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
v128 VA = CPU.VPR[va];
v128 VB = CPU.VPR[vb];
2013-07-04 16:20:36 +02:00
for (uint w = 0; w < 4; w++)
{
CPU.VPR[vd]._u16[7 - w*2] = VA._u16[3 - w];
CPU.VPR[vd]._u16[7 - w*2 - 1] = VB._u16[3 - w];
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMRGLW(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
v128 VA = CPU.VPR[va];
v128 VB = CPU.VPR[vb];
2013-07-04 16:20:36 +02:00
for (uint d = 0; d < 2; d++)
{
CPU.VPR[vd]._u32[3 - d*2] = VA._u32[1 - d];
CPU.VPR[vd]._u32[3 - d*2 - 1] = VB._u32[1 - d];
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMSUMMBM(u32 vd, u32 va, u32 vb, u32 vc) override //nf
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
s32 result = 0;
for (uint b = 0; b < 4; b++)
{
2013-07-04 16:20:36 +02:00
result += CPU.VPR[va]._s8[w*4 + b] * CPU.VPR[vb]._u8[w*4 + b];
}
2013-07-04 16:20:36 +02:00
result += CPU.VPR[vc]._s32[w];
CPU.VPR[vd]._s32[w] = result;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMSUMSHM(u32 vd, u32 va, u32 vb, u32 vc) override //nf
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
s32 result = 0;
for (uint h = 0; h < 2; h++)
{
2013-07-04 16:20:36 +02:00
result += CPU.VPR[va]._s16[w*2 + h] * CPU.VPR[vb]._s16[w*2 + h];
}
2013-07-04 16:20:36 +02:00
result += CPU.VPR[vc]._s32[w];
CPU.VPR[vd]._s32[w] = result;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMSUMSHS(u32 vd, u32 va, u32 vb, u32 vc) override //nf
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
s64 result = 0;
s32 saturated = 0;
for (uint h = 0; h < 2; h++)
{
2013-07-04 16:20:36 +02:00
result += CPU.VPR[va]._s16[w*2 + h] * CPU.VPR[vb]._s16[w*2 + h];
}
2013-07-04 16:20:36 +02:00
result += CPU.VPR[vc]._s32[w];
2014-09-06 15:33:01 +02:00
if (result > 0x7fffffff)
2013-07-04 16:20:36 +02:00
{
2014-09-06 15:33:01 +02:00
saturated = 0x7fffffff;
2013-07-04 16:20:36 +02:00
CPU.VSCR.SAT = 1;
}
2014-09-06 15:33:01 +02:00
else if (result < (s64)(s32)0x80000000)
2013-07-04 16:20:36 +02:00
{
2014-09-06 15:33:01 +02:00
saturated = 0x80000000;
2013-07-04 16:20:36 +02:00
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else
saturated = (s32)result;
CPU.VPR[vd]._s32[w] = saturated;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMSUMUBM(u32 vd, u32 va, u32 vb, u32 vc) override
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
u32 result = 0;
for (uint b = 0; b < 4; b++)
{
result += (u32)CPU.VPR[va]._u8[w*4 + b] * (u32)CPU.VPR[vb]._u8[w*4 + b];
2013-07-04 16:20:36 +02:00
}
2013-07-04 16:20:36 +02:00
result += CPU.VPR[vc]._u32[w];
CPU.VPR[vd]._u32[w] = result;
}
}
2016-01-06 11:47:06 +01:00
void VMSUMUHM(u32 vd, u32 va, u32 vb, u32 vc) override //nf
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
u32 result = 0;
2013-07-04 16:20:36 +02:00
for (uint h = 0; h < 2; h++)
{
result += (u32)CPU.VPR[va]._u16[w*2 + h] * (u32)CPU.VPR[vb]._u16[w*2 + h];
}
2013-07-04 16:20:36 +02:00
result += CPU.VPR[vc]._u32[w];
CPU.VPR[vd]._u32[w] = result;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMSUMUHS(u32 vd, u32 va, u32 vb, u32 vc) override //nf
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
u64 result = 0;
u32 saturated = 0;
2013-07-04 16:20:36 +02:00
for (uint h = 0; h < 2; h++)
{
result += (u64)CPU.VPR[va]._u16[w*2 + h] * (u64)CPU.VPR[vb]._u16[w*2 + h];
}
2013-07-04 16:20:36 +02:00
result += CPU.VPR[vc]._u32[w];
2014-09-06 15:33:01 +02:00
if (result > 0xffffffffu)
{
2014-09-06 15:33:01 +02:00
saturated = 0xffffffff;
2013-07-04 16:20:36 +02:00
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else
saturated = (u32)result;
CPU.VPR[vd]._u32[w] = saturated;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMULESB(u32 vd, u32 va, u32 vb) override //nf
2013-07-04 16:20:36 +02:00
{
for (uint h = 0; h < 8; h++)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._s16[h] = (s16)CPU.VPR[va]._s8[h*2+1] * (s16)CPU.VPR[vb]._s8[h*2+1];
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMULESH(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._s32[w] = (s32)CPU.VPR[va]._s16[w*2+1] * (s32)CPU.VPR[vb]._s16[w*2+1];
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMULEUB(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint h = 0; h < 8; h++)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u16[h] = (u16)CPU.VPR[va]._u8[h*2+1] * (u16)CPU.VPR[vb]._u8[h*2+1];
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMULEUH(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u32[w] = (u32)CPU.VPR[va]._u16[w*2+1] * (u32)CPU.VPR[vb]._u16[w*2+1];
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMULOSB(u32 vd, u32 va, u32 vb) override //nf
2013-07-04 16:20:36 +02:00
{
for (uint h = 0; h < 8; h++)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._s16[h] = (s16)CPU.VPR[va]._s8[h*2] * (s16)CPU.VPR[vb]._s8[h*2];
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMULOSH(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._s32[w] = (s32)CPU.VPR[va]._s16[w*2] * (s32)CPU.VPR[vb]._s16[w*2];
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMULOUB(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint h = 0; h < 8; h++)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u16[h] = (u16)CPU.VPR[va]._u8[h*2] * (u16)CPU.VPR[vb]._u8[h*2];
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VMULOUH(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u32[w] = (u32)CPU.VPR[va]._u16[w*2] * (u32)CPU.VPR[vb]._u16[w*2];
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VNMSUBFP(u32 vd, u32 va, u32 vc, u32 vb) override
2013-07-04 16:20:36 +02:00
{
SetHostRoundingMode(FPSCR_RN_NEAR);
2013-07-04 16:20:36 +02:00
for (uint w = 0; w < 4; w++)
{
const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]);
const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]);
const float c = CheckVSCR_NJ(CPU.VPR[vc]._f[w]);
if (std::isnan(a))
CPU.VPR[vd]._f[w] = SilenceNaN(a);
else if (std::isnan(b))
CPU.VPR[vd]._f[w] = SilenceNaN(b);
else if (std::isnan(c))
CPU.VPR[vd]._f[w] = SilenceNaN(c);
else if ((std::isinf(a) && c == 0) || (a == 0 && std::isinf(c)))
CPU.VPR[vd]._f[w] = (float)FPR_NAN;
else
{
const float result = -fmaf(a, c, -b);
if (std::isnan(result))
CPU.VPR[vd]._f[w] = (float)FPR_NAN;
else
CPU.VPR[vd]._f[w] = CheckVSCR_NJ(result);
}
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VNOR(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u32[w] = ~(CPU.VPR[va]._u32[w] | CPU.VPR[vb]._u32[w]);
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VOR(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] | CPU.VPR[vb]._u32[w];
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VPERM(u32 vd, u32 va, u32 vb, u32 vc) override
2013-07-04 16:20:36 +02:00
{
u8 tmpSRC[32];
std::memcpy(tmpSRC, CPU.VPR + vb, 16);
std::memcpy(tmpSRC + 16, CPU.VPR + va, 16);
2013-07-04 16:20:36 +02:00
for (uint b = 0; b < 16; b++)
{
2013-07-04 16:20:36 +02:00
u8 index = CPU.VPR[vc]._u8[b] & 0x1f;
CPU.VPR[vd]._u8[b] = tmpSRC[0x1f - index];
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VPKPX(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
v128 VA = CPU.VPR[va];
v128 VB = CPU.VPR[vb];
2013-07-04 16:20:36 +02:00
for (uint h = 0; h < 4; h++)
{
u16 bb7 = VB._u8[15 - (h*4 + 0)] & 0x1;
u16 bb8 = VB._u8[15 - (h*4 + 1)] >> 3;
u16 bb16 = VB._u8[15 - (h*4 + 2)] >> 3;
u16 bb24 = VB._u8[15 - (h*4 + 3)] >> 3;
u16 ab7 = VA._u8[15 - (h*4 + 0)] & 0x1;
u16 ab8 = VA._u8[15 - (h*4 + 1)] >> 3;
u16 ab16 = VA._u8[15 - (h*4 + 2)] >> 3;
u16 ab24 = VA._u8[15 - (h*4 + 3)] >> 3;
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u16[3 - h] = (bb7 << 15) | (bb8 << 10) | (bb16 << 5) | bb24;
CPU.VPR[vd]._u16[4 + (3 - h)] = (ab7 << 15) | (ab8 << 10) | (ab16 << 5) | ab24;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VPKSHSS(u32 vd, u32 va, u32 vb) override //nf
2013-07-04 16:20:36 +02:00
{
v128 VA = CPU.VPR[va];
v128 VB = CPU.VPR[vb];
2013-07-04 16:20:36 +02:00
for (uint b = 0; b < 8; b++)
{
s16 result = VA._s16[b];
2013-07-04 16:20:36 +02:00
if (result > INT8_MAX)
{
2013-07-04 16:20:36 +02:00
result = INT8_MAX;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else if (result < INT8_MIN)
{
2013-07-04 16:20:36 +02:00
result = INT8_MIN;
CPU.VSCR.SAT = 1;
}
2014-08-30 19:51:00 +02:00
CPU.VPR[vd]._s8[b+8] = (s8)result;
result = VB._s16[b];
2013-07-04 16:20:36 +02:00
if (result > INT8_MAX)
{
result = INT8_MAX;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else if (result < INT8_MIN)
{
2013-07-04 16:20:36 +02:00
result = INT8_MIN;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
2014-08-30 19:51:00 +02:00
CPU.VPR[vd]._s8[b] = (s8)result;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VPKSHUS(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
v128 VA = CPU.VPR[va];
v128 VB = CPU.VPR[vb];
2013-07-04 16:20:36 +02:00
for (uint b = 0; b < 8; b++)
{
s16 result = VA._s16[b];
2013-07-04 16:20:36 +02:00
if (result > UINT8_MAX)
{
2013-07-04 16:20:36 +02:00
result = UINT8_MAX;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else if (result < 0)
{
2013-07-04 16:20:36 +02:00
result = 0;
CPU.VSCR.SAT = 1;
}
2014-08-30 19:51:00 +02:00
CPU.VPR[vd]._u8[b+8] = (u8)result;
result = VB._s16[b];
2013-07-04 16:20:36 +02:00
if (result > UINT8_MAX)
{
result = UINT8_MAX;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else if (result < 0)
{
2013-07-04 16:20:36 +02:00
result = 0;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
2014-08-30 19:51:00 +02:00
CPU.VPR[vd]._u8[b] = (u8)result;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VPKSWSS(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
v128 VA = CPU.VPR[va];
v128 VB = CPU.VPR[vb];
2013-07-04 16:20:36 +02:00
for (uint h = 0; h < 4; h++)
{
s32 result = VA._s32[h];
2013-07-04 16:20:36 +02:00
if (result > INT16_MAX)
{
result = INT16_MAX;
CPU.VSCR.SAT = 1;
}
else if (result < INT16_MIN)
{
result = INT16_MIN;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._s16[h+4] = result;
result = VB._s32[h];
2013-07-04 16:20:36 +02:00
if (result > INT16_MAX)
{
2013-07-04 16:20:36 +02:00
result = INT16_MAX;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else if (result < INT16_MIN)
{
2013-07-04 16:20:36 +02:00
result = INT16_MIN;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._s16[h] = result;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VPKSWUS(u32 vd, u32 va, u32 vb) override //nf
2013-07-04 16:20:36 +02:00
{
v128 VA = CPU.VPR[va];
v128 VB = CPU.VPR[vb];
2013-07-04 16:20:36 +02:00
for (uint h = 0; h < 4; h++)
{
s32 result = VA._s32[h];
2013-07-04 16:20:36 +02:00
if (result > UINT16_MAX)
{
2013-07-04 16:20:36 +02:00
result = UINT16_MAX;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else if (result < 0)
{
2013-07-04 16:20:36 +02:00
result = 0;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u16[h+4] = result;
result = VB._s32[h];
2013-07-04 16:20:36 +02:00
if (result > UINT16_MAX)
{
2013-07-04 16:20:36 +02:00
result = UINT16_MAX;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else if (result < 0)
{
2013-07-04 16:20:36 +02:00
result = 0;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u16[h] = result;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VPKUHUM(u32 vd, u32 va, u32 vb) override //nf
2013-07-04 16:20:36 +02:00
{
v128 VA = CPU.VPR[va];
v128 VB = CPU.VPR[vb];
2013-07-04 16:20:36 +02:00
for (uint b = 0; b < 8; b++)
{
CPU.VPR[vd]._u8[b+8] = VA._u8[b*2];
CPU.VPR[vd]._u8[b ] = VB._u8[b*2];
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VPKUHUS(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
v128 VA = CPU.VPR[va];
v128 VB = CPU.VPR[vb];
2013-07-04 16:20:36 +02:00
for (uint b = 0; b < 8; b++)
{
u16 result = VA._u16[b];
2013-07-04 16:20:36 +02:00
if (result > UINT8_MAX)
{
2013-07-04 16:20:36 +02:00
result = UINT8_MAX;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
2014-08-30 19:51:00 +02:00
CPU.VPR[vd]._u8[b+8] = (u8)result;
2013-07-04 16:20:36 +02:00
result = VB._u16[b];
2013-07-04 16:20:36 +02:00
if (result > UINT8_MAX)
{
2013-07-04 16:20:36 +02:00
result = UINT8_MAX;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
2014-08-30 19:51:00 +02:00
CPU.VPR[vd]._u8[b] = (u8)result;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VPKUWUM(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
v128 VA = CPU.VPR[va];
v128 VB = CPU.VPR[vb];
2013-07-04 16:20:36 +02:00
for (uint h = 0; h < 4; h++)
{
CPU.VPR[vd]._u16[h+4] = VA._u16[h*2];
CPU.VPR[vd]._u16[h ] = VB._u16[h*2];
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VPKUWUS(u32 vd, u32 va, u32 vb) override //nf
2013-07-04 16:20:36 +02:00
{
v128 VA = CPU.VPR[va];
v128 VB = CPU.VPR[vb];
2013-07-04 16:20:36 +02:00
for (uint h = 0; h < 4; h++)
{
u32 result = VA._u32[h];
2013-07-04 16:20:36 +02:00
if (result > UINT16_MAX)
{
2013-07-04 16:20:36 +02:00
result = UINT16_MAX;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u16[h+4] = result;
result = VB._u32[h];
2013-07-04 16:20:36 +02:00
if (result > UINT16_MAX)
{
2013-07-04 16:20:36 +02:00
result = UINT16_MAX;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u16[h] = result;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VREFP(u32 vd, u32 vb) override
2013-07-04 16:20:36 +02:00
{
SetHostRoundingMode(FPSCR_RN_NEAR);
2013-07-04 16:20:36 +02:00
for (uint w = 0; w < 4; w++)
{
const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]);
if (std::isnan(b))
CPU.VPR[vd]._f[w] = SilenceNaN(b);
else
CPU.VPR[vd]._f[w] = CheckVSCR_NJ(1.0f / b);
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VRFIM(u32 vd, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]);
if (std::isnan(b))
CPU.VPR[vd]._f[w] = SilenceNaN(b);
else
CPU.VPR[vd]._f[w] = floorf(CPU.VPR[vb]._f[w]);
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VRFIN(u32 vd, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]);
if (std::isnan(b))
CPU.VPR[vd]._f[w] = SilenceNaN(b);
else
{
SetHostRoundingMode(FPSCR_RN_NEAR);
CPU.VPR[vd]._f[w] = nearbyintf(CPU.VPR[vb]._f[w]);
}
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VRFIP(u32 vd, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]);
if (std::isnan(b))
CPU.VPR[vd]._f[w] = SilenceNaN(b);
else
CPU.VPR[vd]._f[w] = ceilf(CPU.VPR[vb]._f[w]);
2013-07-04 16:20:36 +02:00
}
}
2016-01-06 11:47:06 +01:00
void VRFIZ(u32 vd, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]);
if (std::isnan(b))
CPU.VPR[vd]._f[w] = SilenceNaN(b);
else
CPU.VPR[vd]._f[w] = truncf(CPU.VPR[vb]._f[w]);
2013-07-04 16:20:36 +02:00
}
}
2016-01-06 11:47:06 +01:00
void VRLB(u32 vd, u32 va, u32 vb) override //nf
2013-07-04 16:20:36 +02:00
{
for (uint b = 0; b < 16; b++)
{
int nRot = CPU.VPR[vb]._u8[b] & 0x7;
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u8[b] = (CPU.VPR[va]._u8[b] << nRot) | (CPU.VPR[va]._u8[b] >> (8 - nRot));
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VRLH(u32 vd, u32 va, u32 vb) override //nf
2013-07-04 16:20:36 +02:00
{
for (uint h = 0; h < 8; h++)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u16[h] = rotl16(CPU.VPR[va]._u16[h], CPU.VPR[vb]._u8[h*2] & 0xf);
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VRLW(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
2014-08-30 19:51:00 +02:00
CPU.VPR[vd]._u32[w] = (u32)rotl32(CPU.VPR[va]._u32[w], CPU.VPR[vb]._u8[w*4] & 0x1f);
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VRSQRTEFP(u32 vd, u32 vb) override
2013-07-04 16:20:36 +02:00
{
SetHostRoundingMode(FPSCR_RN_NEAR);
2013-07-04 16:20:36 +02:00
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
//TODO: accurate div
const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]);
if (std::isnan(b))
CPU.VPR[vd]._f[w] = SilenceNaN(b);
else if (b < 0)
CPU.VPR[vd]._f[w] = (float)FPR_NAN;
else
CPU.VPR[vd]._f[w] = 1.0f / sqrtf(b); // Can never be denormal.
2013-07-04 16:20:36 +02:00
}
}
2016-01-06 11:47:06 +01:00
void VSEL(u32 vd, u32 va, u32 vb, u32 vc) override
2013-07-04 16:20:36 +02:00
{
for (uint b = 0; b < 16; b++)
{
CPU.VPR[vd]._u8[b] = (CPU.VPR[vb]._u8[b] & CPU.VPR[vc]._u8[b]) | (CPU.VPR[va]._u8[b] & (~CPU.VPR[vc]._u8[b]));
}
}
2016-01-06 11:47:06 +01:00
void VSL(u32 vd, u32 va, u32 vb) override //nf
2013-07-04 16:20:36 +02:00
{
v128 VA = CPU.VPR[va];
2013-07-04 16:20:36 +02:00
u8 sh = CPU.VPR[vb]._u8[0] & 0x7;
CPU.VPR[vd]._u8[0] = VA._u8[0] << sh;
2014-10-18 22:27:54 +02:00
for (uint b = 1; b < 16; b++)
{
CPU.VPR[vd]._u8[b] = (VA._u8[b] << sh) | (VA._u8[b-1] >> (8 - sh));
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VSLB(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint b = 0; b < 16; b++)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u8[b] = CPU.VPR[va]._u8[b] << (CPU.VPR[vb]._u8[b] & 0x7);
}
}
2016-01-06 11:47:06 +01:00
void VSLDOI(u32 vd, u32 va, u32 vb, u32 sh) override
2013-07-04 16:20:36 +02:00
{
u8 tmpSRC[32];
std::memcpy(tmpSRC, CPU.VPR + vb, 16);
std::memcpy(tmpSRC + 16, CPU.VPR + va, 16);
for(uint b=0; b<16; b++)
2013-07-04 16:20:36 +02:00
{
CPU.VPR[vd]._u8[15 - b] = tmpSRC[31 - (b + sh)];
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VSLH(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint h = 0; h < 8; h++)
{
CPU.VPR[vd]._u16[h] = CPU.VPR[va]._u16[h] << (CPU.VPR[vb]._u16[h] & 0xf);
2013-07-04 16:20:36 +02:00
}
}
2016-01-06 11:47:06 +01:00
void VSLO(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
v128 VA = CPU.VPR[va];
2013-07-04 16:20:36 +02:00
u8 nShift = (CPU.VPR[vb]._u8[0] >> 3) & 0xf;
CPU.VPR[vd].clear();
2013-07-04 16:20:36 +02:00
for (u8 b = 0; b < 16 - nShift; b++)
{
CPU.VPR[vd]._u8[15 - b] = VA._u8[15 - (b + nShift)];
2013-07-04 16:20:36 +02:00
}
}
2016-01-06 11:47:06 +01:00
void VSLW(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
2014-01-23 19:40:49 +01:00
CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] << (CPU.VPR[vb]._u32[w] & 0x1f);
2013-07-04 16:20:36 +02:00
}
}
2016-01-06 11:47:06 +01:00
void VSPLTB(u32 vd, u32 uimm5, u32 vb) override
2013-07-04 16:20:36 +02:00
{
u8 byte = CPU.VPR[vb]._u8[15 - uimm5];
2013-07-04 16:20:36 +02:00
for (uint b = 0; b < 16; b++)
{
CPU.VPR[vd]._u8[b] = byte;
}
}
2016-01-06 11:47:06 +01:00
void VSPLTH(u32 vd, u32 uimm5, u32 vb) override
2013-07-04 16:20:36 +02:00
{
assert(uimm5 < 8);
u16 hword = CPU.VPR[vb]._u16[7 - uimm5];
for (uint h = 0; h < 8; h++)
{
CPU.VPR[vd]._u16[h] = hword;
}
}
2016-01-06 11:47:06 +01:00
void VSPLTISB(u32 vd, s32 simm5) override
2013-07-04 16:20:36 +02:00
{
for (uint b = 0; b < 16; b++)
{
CPU.VPR[vd]._u8[b] = simm5;
}
}
2016-01-06 11:47:06 +01:00
void VSPLTISH(u32 vd, s32 simm5) override
2013-07-04 16:20:36 +02:00
{
for (uint h = 0; h < 8; h++)
{
CPU.VPR[vd]._u16[h] = (s16)simm5;
}
}
2016-01-06 11:47:06 +01:00
void VSPLTISW(u32 vd, s32 simm5) override
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
CPU.VPR[vd]._u32[w] = (s32)simm5;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VSPLTW(u32 vd, u32 uimm5, u32 vb) override
2013-07-04 16:20:36 +02:00
{
assert(uimm5 < 4);
u32 word = CPU.VPR[vb]._u32[3 - uimm5];
2013-07-04 16:20:36 +02:00
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u32[w] = word;
}
}
2016-01-06 11:47:06 +01:00
void VSR(u32 vd, u32 va, u32 vb) override //nf
2013-07-04 16:20:36 +02:00
{
v128 VA = CPU.VPR[va];
2013-07-04 16:20:36 +02:00
u8 sh = CPU.VPR[vb]._u8[0] & 0x7;
CPU.VPR[vd]._u8[15] = VA._u8[15] >> sh;
2014-10-18 22:27:54 +02:00
for (uint b = 14; ~b; b--)
{
CPU.VPR[vd]._u8[b] = (VA._u8[b] >> sh) | (VA._u8[b+1] << (8 - sh));
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VSRAB(u32 vd, u32 va, u32 vb) override //nf
2013-07-04 16:20:36 +02:00
{
for (uint b = 0; b < 16; b++)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._s8[b] = CPU.VPR[va]._s8[b] >> (CPU.VPR[vb]._u8[b] & 0x7);
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VSRAH(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint h = 0; h < 8; h++)
{
CPU.VPR[vd]._s16[h] = CPU.VPR[va]._s16[h] >> (CPU.VPR[vb]._u16[h] & 0xf);
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VSRAW(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
CPU.VPR[vd]._s32[w] = CPU.VPR[va]._s32[w] >> (CPU.VPR[vb]._u32[w] & 0x1f);
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VSRB(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint b = 0; b < 16; b++)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u8[b] = CPU.VPR[va]._u8[b] >> (CPU.VPR[vb]._u8[b] & 0x7);
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VSRH(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint h = 0; h < 8; h++)
{
CPU.VPR[vd]._u16[h] = CPU.VPR[va]._u16[h] >> (CPU.VPR[vb]._u16[h] & 0xf);
2013-07-04 16:20:36 +02:00
}
}
2016-01-06 11:47:06 +01:00
void VSRO(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
v128 VA = CPU.VPR[va];
2013-07-04 16:20:36 +02:00
u8 nShift = (CPU.VPR[vb]._u8[0] >> 3) & 0xf;
CPU.VPR[vd].clear();
2013-07-04 16:20:36 +02:00
for (u8 b = 0; b < 16 - nShift; b++)
{
CPU.VPR[vd]._u8[b] = VA._u8[b + nShift];
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VSRW(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] >> (CPU.VPR[vb]._u32[w] & 0x1f);
2013-07-04 16:20:36 +02:00
}
}
2016-01-06 11:47:06 +01:00
void VSUBCUW(u32 vd, u32 va, u32 vb) override //nf
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] < CPU.VPR[vb]._u32[w] ? 0 : 1;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VSUBFP(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
SetHostRoundingMode(FPSCR_RN_NEAR);
2013-07-04 16:20:36 +02:00
for (uint w = 0; w < 4; w++)
{
const float a = CheckVSCR_NJ(CPU.VPR[va]._f[w]);
const float b = CheckVSCR_NJ(CPU.VPR[vb]._f[w]);
if (std::isnan(a))
CPU.VPR[vd]._f[w] = SilenceNaN(a);
else if (std::isnan(b))
CPU.VPR[vd]._f[w] = SilenceNaN(b);
else if (std::isinf(a) && std::isinf(b) && a == b)
CPU.VPR[vd]._f[w] = (float)FPR_NAN;
else
CPU.VPR[vd]._f[w] = CheckVSCR_NJ(a - b);
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VSUBSBS(u32 vd, u32 va, u32 vb) override //nf
2013-07-04 16:20:36 +02:00
{
for (uint b = 0; b < 16; b++)
{
2013-07-04 16:20:36 +02:00
s16 result = (s16)CPU.VPR[va]._s8[b] - (s16)CPU.VPR[vb]._s8[b];
if (result < INT8_MIN)
{
CPU.VPR[vd]._s8[b] = INT8_MIN;
CPU.VSCR.SAT = 1;
}
else if (result > INT8_MAX)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._s8[b] = INT8_MAX;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else
CPU.VPR[vd]._s8[b] = (s8)result;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VSUBSHS(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint h = 0; h < 8; h++)
{
2013-07-04 16:20:36 +02:00
s32 result = (s32)CPU.VPR[va]._s16[h] - (s32)CPU.VPR[vb]._s16[h];
2013-07-04 16:20:36 +02:00
if (result < INT16_MIN)
{
CPU.VPR[vd]._s16[h] = (s16)INT16_MIN;
CPU.VSCR.SAT = 1;
}
else if (result > INT16_MAX)
{
CPU.VPR[vd]._s16[h] = (s16)INT16_MAX;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else
CPU.VPR[vd]._s16[h] = (s16)result;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VSUBSWS(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
s64 result = (s64)CPU.VPR[va]._s32[w] - (s64)CPU.VPR[vb]._s32[w];
2013-07-04 16:20:36 +02:00
if (result < INT32_MIN)
{
CPU.VPR[vd]._s32[w] = (s32)INT32_MIN;
CPU.VSCR.SAT = 1;
}
else if (result > INT32_MAX)
{
CPU.VPR[vd]._s32[w] = (s32)INT32_MAX;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else
CPU.VPR[vd]._s32[w] = (s32)result;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VSUBUBM(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint b = 0; b < 16; b++)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u8[b] = (u8)((CPU.VPR[va]._u8[b] - CPU.VPR[vb]._u8[b]) & 0xff);
}
}
2016-01-06 11:47:06 +01:00
void VSUBUBS(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint b = 0; b < 16; b++)
{
s16 result = (s16)CPU.VPR[va]._u8[b] - (s16)CPU.VPR[vb]._u8[b];
if (result < 0)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u8[b] = 0;
CPU.VSCR.SAT = 1;
}
else
CPU.VPR[vd]._u8[b] = (u8)result;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VSUBUHM(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint h = 0; h < 8; h++)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u16[h] = CPU.VPR[va]._u16[h] - CPU.VPR[vb]._u16[h];
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VSUBUHS(u32 vd, u32 va, u32 vb) override //nf
2013-07-04 16:20:36 +02:00
{
for (uint h = 0; h < 8; h++)
{
2013-07-04 16:20:36 +02:00
s32 result = (s32)CPU.VPR[va]._u16[h] - (s32)CPU.VPR[vb]._u16[h];
2013-07-04 16:20:36 +02:00
if (result < 0)
{
CPU.VPR[vd]._u16[h] = 0;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else
CPU.VPR[vd]._u16[h] = (u16)result;
}
}
2016-01-06 11:47:06 +01:00
void VSUBUWM(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
CPU.VPR[vd]._u32[w] = CPU.VPR[va]._u32[w] - CPU.VPR[vb]._u32[w];
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VSUBUWS(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
s64 result = (s64)CPU.VPR[va]._u32[w] - (s64)CPU.VPR[vb]._u32[w];
if (result < 0)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u32[w] = 0;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else
CPU.VPR[vd]._u32[w] = (u32)result;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VSUMSWS(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
s64 sum = CPU.VPR[vb]._s32[0];
2013-07-04 16:20:36 +02:00
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
sum += CPU.VPR[va]._s32[w];
}
CPU.VPR[vd].clear();
2013-07-04 16:20:36 +02:00
if (sum > INT32_MAX)
{
CPU.VPR[vd]._s32[0] = (s32)INT32_MAX;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else if (sum < INT32_MIN)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._s32[0] = (s32)INT32_MIN;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else
CPU.VPR[vd]._s32[0] = (s32)sum;
}
2016-01-06 11:47:06 +01:00
void VSUM2SWS(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint n = 0; n < 2; n++)
{
2013-07-04 16:20:36 +02:00
s64 sum = (s64)CPU.VPR[va]._s32[n*2] + CPU.VPR[va]._s32[n*2 + 1] + CPU.VPR[vb]._s32[n*2];
2013-07-04 16:20:36 +02:00
if (sum > INT32_MAX)
{
CPU.VPR[vd]._s32[n*2] = (s32)INT32_MAX;
CPU.VSCR.SAT = 1;
}
else if (sum < INT32_MIN)
{
CPU.VPR[vd]._s32[n*2] = (s32)INT32_MIN;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else
CPU.VPR[vd]._s32[n*2] = (s32)sum;
}
2014-03-06 12:50:45 +01:00
CPU.VPR[vd]._s32[1] = 0;
CPU.VPR[vd]._s32[3] = 0;
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VSUM4SBS(u32 vd, u32 va, u32 vb) override //nf
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
s64 sum = CPU.VPR[vb]._s32[w];
2013-07-04 16:20:36 +02:00
for (uint b = 0; b < 4; b++)
{
2013-07-04 16:20:36 +02:00
sum += CPU.VPR[va]._s8[w*4 + b];
}
if (sum > INT32_MAX)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._s32[w] = (s32)INT32_MAX;
CPU.VSCR.SAT = 1;
}
else if (sum < INT32_MIN)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._s32[w] = (s32)INT32_MIN;
CPU.VSCR.SAT = 1;
}
else
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._s32[w] = (s32)sum;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VSUM4SHS(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
s64 sum = CPU.VPR[vb]._s32[w];
2013-07-04 16:20:36 +02:00
for (uint h = 0; h < 2; h++)
{
2013-07-04 16:20:36 +02:00
sum += CPU.VPR[va]._s16[w*2 + h];
}
2013-07-04 16:20:36 +02:00
if (sum > INT32_MAX)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._s32[w] = (s32)INT32_MAX;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else if (sum < INT32_MIN)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._s32[w] = (s32)INT32_MIN;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else
CPU.VPR[vd]._s32[w] = (s32)sum;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VSUM4UBS(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
for (uint w = 0; w < 4; w++)
{
2013-07-04 16:20:36 +02:00
u64 sum = CPU.VPR[vb]._u32[w];
2013-07-04 16:20:36 +02:00
for (uint b = 0; b < 4; b++)
{
sum += CPU.VPR[va]._u8[w*4 + b];
}
2013-07-04 16:20:36 +02:00
if (sum > UINT32_MAX)
{
2013-07-04 16:20:36 +02:00
CPU.VPR[vd]._u32[w] = (u32)UINT32_MAX;
CPU.VSCR.SAT = 1;
}
2013-07-04 16:20:36 +02:00
else
CPU.VPR[vd]._u32[w] = (u32)sum;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VUPKHPX(u32 vd, u32 vb) override
2013-07-04 16:20:36 +02:00
{
v128 VB = CPU.VPR[vb];
2013-07-04 16:20:36 +02:00
for (uint w = 0; w < 4; w++)
{
CPU.VPR[vd]._s8[w*4 + 3] = VB._s8[8 + w*2 + 1] >> 7; // signed shift sign extends
CPU.VPR[vd]._u8[w*4 + 2] = (VB._u8[8 + w*2 + 1] >> 2) & 0x1f;
CPU.VPR[vd]._u8[w*4 + 1] = ((VB._u8[8 + w*2 + 1] & 0x3) << 3) | ((VB._u8[8 + w*2 + 0] >> 5) & 0x7);
CPU.VPR[vd]._u8[w*4 + 0] = VB._u8[8 + w*2 + 0] & 0x1f;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VUPKHSB(u32 vd, u32 vb) override
2013-07-04 16:20:36 +02:00
{
v128 VB = CPU.VPR[vb];
2013-07-04 16:20:36 +02:00
for (uint h = 0; h < 8; h++)
{
CPU.VPR[vd]._s16[h] = VB._s8[8 + h];
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VUPKHSH(u32 vd, u32 vb) override
2013-07-04 16:20:36 +02:00
{
v128 VB = CPU.VPR[vb];
2013-07-04 16:20:36 +02:00
for (uint w = 0; w < 4; w++)
{
CPU.VPR[vd]._s32[w] = VB._s16[4 + w];
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VUPKLPX(u32 vd, u32 vb) override
2013-07-04 16:20:36 +02:00
{
v128 VB = CPU.VPR[vb];
2013-07-04 16:20:36 +02:00
for (uint w = 0; w < 4; w++)
{
CPU.VPR[vd]._s8[w*4 + 3] = VB._s8[w*2 + 1] >> 7; // signed shift sign extends
CPU.VPR[vd]._u8[w*4 + 2] = (VB._u8[w*2 + 1] >> 2) & 0x1f;
CPU.VPR[vd]._u8[w*4 + 1] = ((VB._u8[w*2 + 1] & 0x3) << 3) | ((VB._u8[w*2 + 0] >> 5) & 0x7);
CPU.VPR[vd]._u8[w*4 + 0] = VB._u8[w*2 + 0] & 0x1f;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VUPKLSB(u32 vd, u32 vb) override //nf
2013-07-04 16:20:36 +02:00
{
v128 VB = CPU.VPR[vb];
2013-07-04 16:20:36 +02:00
for (uint h = 0; h < 8; h++)
{
CPU.VPR[vd]._s16[h] = VB._s8[h];
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VUPKLSH(u32 vd, u32 vb) override
2013-07-04 16:20:36 +02:00
{
v128 VB = CPU.VPR[vb];
2013-07-04 16:20:36 +02:00
for (uint w = 0; w < 4; w++)
{
CPU.VPR[vd]._s32[w] = VB._s16[w];
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void VXOR(u32 vd, u32 va, u32 vb) override
2013-07-04 16:20:36 +02:00
{
CPU.VPR[vd]._u32[0] = CPU.VPR[va]._u32[0] ^ CPU.VPR[vb]._u32[0];
CPU.VPR[vd]._u32[1] = CPU.VPR[va]._u32[1] ^ CPU.VPR[vb]._u32[1];
CPU.VPR[vd]._u32[2] = CPU.VPR[va]._u32[2] ^ CPU.VPR[vb]._u32[2];
CPU.VPR[vd]._u32[3] = CPU.VPR[va]._u32[3] ^ CPU.VPR[vb]._u32[3];
}
static void MULLI_impl(PPUThread *CPU, u32 rd, u32 ra, s32 simm16)
{
CPU->GPR[rd] = (s64)CPU->GPR[ra] * simm16;
}
2016-01-06 11:47:06 +01:00
void MULLI(u32 rd, u32 ra, s32 simm16) override
{
MULLI_impl(&CPU, rd, ra, simm16);
}
static void SUBFIC_impl(PPUThread *CPU, u32 rd, u32 ra, s32 simm16)
{
const u64 RA = CPU->GPR[ra];
const u64 IMM = (s64)simm16;
CPU->GPR[rd] = ~RA + IMM + 1;
CPU->XER.CA = CPU->IsCarry(~RA, IMM, 1);
}
2016-01-06 11:47:06 +01:00
void SUBFIC(u32 rd, u32 ra, s32 simm16) override
{
SUBFIC_impl(&CPU, rd, ra, simm16);
}
static void CMPLI_impl(PPUThread *CPU, u32 crfd, u32 l, u32 ra, u32 uimm16)
{
CPU->UpdateCRnU(l, crfd, CPU->GPR[ra], uimm16);
}
void CMPLI(u32 crfd, u32 l, u32 ra, u32 uimm16) override
{
CMPLI_impl(&CPU, crfd, l, ra, uimm16);
}
static void CMPI_impl(PPUThread *CPU, u32 crfd, u32 l, u32 ra, s32 simm16)
{
CPU->UpdateCRnS(l, crfd, CPU->GPR[ra], simm16);
}
void CMPI(u32 crfd, u32 l, u32 ra, s32 simm16) override
{
CMPI_impl(&CPU, crfd, l, ra, simm16);
}
static void ADDIC_impl(PPUThread *CPU, u32 rd, u32 ra, s32 simm16)
{
const u64 RA = CPU->GPR[ra];
CPU->GPR[rd] = RA + simm16;
CPU->XER.CA = CPU->IsCarry(RA, simm16);
}
2016-01-06 11:47:06 +01:00
void ADDIC(u32 rd, u32 ra, s32 simm16) override
{
ADDIC_impl(&CPU, rd, ra, simm16);
}
static void ADDIC__impl(PPUThread *CPU, u32 rd, u32 ra, s32 simm16)
{
const u64 RA = CPU->GPR[ra];
CPU->GPR[rd] = RA + simm16;
CPU->XER.CA = CPU->IsCarry(RA, simm16);
CPU->UpdateCR0<s64>(CPU->GPR[rd]);
}
2016-01-06 11:47:06 +01:00
void ADDIC_(u32 rd, u32 ra, s32 simm16) override
{
ADDIC__impl(&CPU, rd, ra, simm16);
}
static void ADDI_impl(PPUThread *CPU, u32 rd, u32 ra, s32 simm16)
{
CPU->GPR[rd] = ra ? ((s64)CPU->GPR[ra] + simm16) : simm16;
}
void ADDI(u32 rd, u32 ra, s32 simm16) override
{
ADDI_impl(&CPU, rd, ra, simm16);
}
static void ADDIS_impl(PPUThread *CPU, u32 rd, u32 ra, s32 simm16)
{
CPU->GPR[rd] = ra ? ((s64)CPU->GPR[ra] + (static_cast<s64>(simm16) << 16)) : (static_cast<s64>(simm16) << 16);
}
void ADDIS(u32 rd, u32 ra, s32 simm16) override
{
ADDIS_impl(&CPU, rd, ra, simm16);
}
2016-01-06 11:47:06 +01:00
void BC(u32 bo, u32 bi, s32 bd, u32 aa, u32 lk) override
{
2014-01-23 19:40:49 +01:00
if (CheckCondition(bo, bi))
{
2014-09-15 00:17:24 +02:00
const u32 nextLR = CPU.PC + 4;
2015-07-01 00:25:52 +02:00
CPU.PC = branchTarget((aa ? 0 : CPU.PC), bd) - 4;
if(lk) CPU.LR = nextLR;
2014-01-23 19:40:49 +01:00
}
}
2016-01-06 11:47:06 +01:00
void HACK(u32 index) override
{
extern void execute_ppu_func_by_index(PPUThread& ppu, u32 index);
2015-02-21 12:30:26 +01:00
execute_ppu_func_by_index(CPU, index);
}
2016-01-06 11:47:06 +01:00
void SC(u32 lev) override
{
extern void execute_syscall_by_index(PPUThread& ppu, u64 code);
switch (lev)
{
case 0x0: execute_syscall_by_index(CPU, CPU.GPR[11]); break;
case 0x1: throw EXCEPTION("HyperCall LV1");
2015-07-19 13:36:32 +02:00
case 0x3: CPU.fast_stop(); break;
default: throw EXCEPTION("Unknown level (0x%x)", lev);
}
}
2016-01-06 11:47:06 +01:00
void B(s32 ll, u32 aa, u32 lk) override
{
2014-09-15 00:17:24 +02:00
const u32 nextLR = CPU.PC + 4;
2015-07-01 00:25:52 +02:00
CPU.PC = branchTarget(aa ? 0 : CPU.PC, ll) - 4;
if(lk) CPU.LR = nextLR;
}
static void MCRF_impl(PPUThread *CPU, u32 crfd, u32 crfs)
{
CPU->SetCR(crfd, CPU->GetCR(crfs));
}
2016-01-06 11:47:06 +01:00
void MCRF(u32 crfd, u32 crfs) override
2013-07-04 16:20:36 +02:00
{
MCRF_impl(&CPU, crfd, crfs);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void BCLR(u32 bo, u32 bi, u32 bh, u32 lk) override
2013-07-04 16:20:36 +02:00
{
2014-01-23 19:40:49 +01:00
if (CheckCondition(bo, bi))
{
2014-09-15 00:17:24 +02:00
const u32 nextLR = CPU.PC + 4;
2015-07-01 00:25:52 +02:00
CPU.PC = branchTarget(0, (u32)CPU.LR) - 4;
if(lk) CPU.LR = nextLR;
2014-01-23 19:40:49 +01:00
}
2013-07-04 16:20:36 +02:00
}
static void CRNOR_impl(PPUThread *CPU, u32 crbd, u32 crba, u32 crbb)
{
const u8 v = 1 ^ (CPU->IsCR(crba) | CPU->IsCR(crbb));
CPU->SetCRBit2(crbd, v & 0x1);
}
2016-01-06 11:47:06 +01:00
void CRNOR(u32 crbd, u32 crba, u32 crbb) override
2013-07-04 16:20:36 +02:00
{
CRNOR_impl(&CPU, crbd, crba, crbb);
}
static void CRANDC_impl(PPUThread *CPU, u32 crbd, u32 crba, u32 crbb)
{
const u8 v = CPU->IsCR(crba) & (1 ^ CPU->IsCR(crbb));
CPU->SetCRBit2(crbd, v & 0x1);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void CRANDC(u32 crbd, u32 crba, u32 crbb) override
2013-07-04 16:20:36 +02:00
{
CRANDC_impl(&CPU, crbd, crba, crbb);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void ISYNC() override
2013-07-04 16:20:36 +02:00
{
2014-01-19 11:52:30 +01:00
_mm_mfence();
2013-07-04 16:20:36 +02:00
}
static void CRXOR_impl(PPUThread *CPU, u32 crbd, u32 crba, u32 crbb)
{
const u8 v = CPU->IsCR(crba) ^ CPU->IsCR(crbb);
CPU->SetCRBit2(crbd, v & 0x1);
}
2016-01-06 11:47:06 +01:00
void CRXOR(u32 crbd, u32 crba, u32 crbb) override
2013-07-04 16:20:36 +02:00
{
CRXOR_impl(&CPU, crbd, crba, crbb);
}
static void CRNAND_impl(PPUThread *CPU, u32 crbd, u32 crba, u32 crbb)
{
const u8 v = 1 ^ (CPU->IsCR(crba) & CPU->IsCR(crbb));
CPU->SetCRBit2(crbd, v & 0x1);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void CRNAND(u32 crbd, u32 crba, u32 crbb)override
2013-07-04 16:20:36 +02:00
{
CRNAND_impl(&CPU, crbd, crba, crbb);
}
static void CRAND_impl(PPUThread *CPU, u32 crbd, u32 crba, u32 crbb)
{
const u8 v = CPU->IsCR(crba) & CPU->IsCR(crbb);
CPU->SetCRBit2(crbd, v & 0x1);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void CRAND(u32 crbd, u32 crba, u32 crbb) override
2013-07-04 16:20:36 +02:00
{
CRAND_impl(&CPU, crbd, crba, crbb);
}
static void CREQV_impl(PPUThread *CPU, u32 crbd, u32 crba, u32 crbb)
{
const u8 v = 1 ^ (CPU->IsCR(crba) ^ CPU->IsCR(crbb));
CPU->SetCRBit2(crbd, v & 0x1);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void CREQV(u32 crbd, u32 crba, u32 crbb) override
2013-07-04 16:20:36 +02:00
{
CREQV_impl(&CPU, crbd, crba, crbb);
}
static void CRORC_impl(PPUThread *CPU, u32 crbd, u32 crba, u32 crbb)
{
const u8 v = CPU->IsCR(crba) | (1 ^ CPU->IsCR(crbb));
CPU->SetCRBit2(crbd, v & 0x1);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void CRORC(u32 crbd, u32 crba, u32 crbb) override
2013-07-04 16:20:36 +02:00
{
CRORC_impl(&CPU, crbd, crba, crbb);
}
static void CROR_impl(PPUThread *CPU, u32 crbd, u32 crba, u32 crbb)
{
const u8 v = CPU->IsCR(crba) | CPU->IsCR(crbb);
CPU->SetCRBit2(crbd, v & 0x1);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void CROR(u32 crbd, u32 crba, u32 crbb) override
2013-07-04 16:20:36 +02:00
{
CROR_impl(&CPU, crbd, crba, crbb);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void BCCTR(u32 bo, u32 bi, u32 bh, u32 lk) override
2013-07-04 16:20:36 +02:00
{
2015-01-17 23:01:16 +01:00
if(bo & 0x10 || CPU.IsCR(bi) == ((bo & 0x8) != 0))
{
2014-09-15 00:17:24 +02:00
const u32 nextLR = CPU.PC + 4;
2015-07-01 00:25:52 +02:00
CPU.PC = branchTarget(0, (u32)CPU.CTR) - 4;
if(lk) CPU.LR = nextLR;
}
2013-07-04 16:20:36 +02:00
}
static void RLWIMI_impl(PPUThread *CPU, u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc)
{
2014-03-19 15:47:28 +01:00
const u64 mask = rotate_mask[32 + mb][32 + me];
CPU->GPR[ra] = (CPU->GPR[ra] & ~mask) | (rotl32(CPU->GPR[rs], sh) & mask);
if(rc) CPU->UpdateCR0<s64>(CPU->GPR[ra]);
}
2016-01-06 11:47:06 +01:00
void RLWIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) override
{
RLWIMI_impl(&CPU, ra, rs, sh, mb, me, rc);
}
static void RLWINM_impl(PPUThread *CPU, u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc)
{
CPU->GPR[ra] = rotl32(CPU->GPR[rs], sh) & rotate_mask[32 + mb][32 + me];
if(rc) CPU->UpdateCR0<s64>(CPU->GPR[ra]);
}
void RLWINM(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, u32 rc) override
{
RLWINM_impl(&CPU, ra, rs, sh, mb, me, rc);
}
static void RLWNM_impl(PPUThread *CPU, u32 ra, u32 rs, u32 rb, u32 mb, u32 me, u32 rc)
{
CPU->GPR[ra] = rotl32(CPU->GPR[rs], CPU->GPR[rb] & 0x1f) & rotate_mask[32 + mb][32 + me];
if(rc) CPU->UpdateCR0<s64>(CPU->GPR[ra]);
}
2016-01-06 11:47:06 +01:00
void RLWNM(u32 ra, u32 rs, u32 rb, u32 mb, u32 me, u32 rc) override
{
RLWNM_impl(&CPU, ra, rs, rb, mb, me, rc);
}
static void ORI_impl(PPUThread *CPU, u32 ra, u32 rs, u32 uimm16)
{
CPU->GPR[ra] = CPU->GPR[rs] | uimm16;
}
2016-01-06 11:47:06 +01:00
void ORI(u32 ra, u32 rs, u32 uimm16) override
{
ORI_impl(&CPU, ra, rs, uimm16);
}
static void ORIS_impl(PPUThread *CPU, u32 ra, u32 rs, u32 uimm16)
{
CPU->GPR[ra] = CPU->GPR[rs] | ((u64)uimm16 << 16);
}
2016-01-06 11:47:06 +01:00
void ORIS(u32 ra, u32 rs, u32 uimm16) override
{
ORIS_impl(&CPU, ra, rs, uimm16);
}
static void XORI_impl(PPUThread *CPU, u32 ra, u32 rs, u32 uimm16)
{
CPU->GPR[ra] = CPU->GPR[rs] ^ uimm16;
}
2016-01-06 11:47:06 +01:00
void XORI(u32 ra, u32 rs, u32 uimm16) override
{
XORI_impl(&CPU, ra, rs, uimm16);
}
static void XORIS_impl(PPUThread *CPU, u32 ra, u32 rs, u32 uimm16)
{
CPU->GPR[ra] = CPU->GPR[rs] ^ ((u64)uimm16 << 16);
}
2016-01-06 11:47:06 +01:00
void XORIS(u32 ra, u32 rs, u32 uimm16) override
{
XORIS_impl(&CPU, ra, rs, uimm16);
}
static void ANDI__impl(PPUThread *CPU, u32 ra, u32 rs, u32 uimm16)
{
CPU->GPR[ra] = CPU->GPR[rs] & uimm16;
CPU->UpdateCR0<s64>(CPU->GPR[ra]);
}
2016-01-06 11:47:06 +01:00
void ANDI_(u32 ra, u32 rs, u32 uimm16) override
{
ANDI__impl(&CPU, ra, rs, uimm16);
}
static void ANDIS__impl(PPUThread *CPU, u32 ra, u32 rs, u32 uimm16)
{
CPU->GPR[ra] = CPU->GPR[rs] & ((u64)uimm16 << 16);
CPU->UpdateCR0<s64>(CPU->GPR[ra]);
}
2016-01-06 11:47:06 +01:00
void ANDIS_(u32 ra, u32 rs, u32 uimm16) override
{
ANDIS__impl(&CPU, ra, rs, uimm16);
}
static
void RLDICL_impl(PPUThread *CPU, u32 ra, u32 rs, u32 sh, u32 mb, u32 rc)
2013-07-04 16:20:36 +02:00
{
CPU->GPR[ra] = rotl64(CPU->GPR[rs], sh) & rotate_mask[mb][63];
if(rc) CPU->UpdateCR0<s64>(CPU->GPR[ra]);
2013-07-04 16:20:36 +02:00
}
void RLDICL(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) override
{
RLDICL_impl(&CPU, ra, rs, sh, mb, rc);
}
static
void RLDICR_impl(PPUThread *CPU, u32 ra, u32 rs, u32 sh, u32 me, u32 rc)
{
CPU->GPR[ra] = rotl64(CPU->GPR[rs], sh) & rotate_mask[0][me];
if(rc) CPU->UpdateCR0<s64>(CPU->GPR[ra]);
}
2016-01-06 11:47:06 +01:00
void RLDICR(u32 ra, u32 rs, u32 sh, u32 me, u32 rc) override
2013-07-04 16:20:36 +02:00
{
RLDICR_impl(&CPU, ra, rs, sh, me, rc);
}
static void RLDIC_impl(PPUThread *CPU, u32 ra, u32 rs, u32 sh, u32 mb, u32 rc)
{
CPU->GPR[ra] = rotl64(CPU->GPR[rs], sh) & rotate_mask[mb][63 - sh];
if(rc) CPU->UpdateCR0<s64>(CPU->GPR[ra]);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void RLDIC(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) override
2013-07-04 16:20:36 +02:00
{
RLDIC_impl(&CPU, ra, rs, sh, mb, rc);
}
static void RLDIMI_impl(PPUThread *CPU, u32 ra, u32 rs, u32 sh, u32 mb, u32 rc)
{
const u64 mask = rotate_mask[mb][63 - sh];
CPU->GPR[ra] = (CPU->GPR[ra] & ~mask) | (rotl64(CPU->GPR[rs], sh) & mask);
if(rc) CPU->UpdateCR0<s64>(CPU->GPR[ra]);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void RLDIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 rc) override
2013-07-04 16:20:36 +02:00
{
RLDIMI_impl(&CPU, ra, rs, sh, mb, rc);
2013-07-04 16:20:36 +02:00
}
static void RLDC_LR_impl(PPUThread *CPU, u32 ra, u32 rs, u32 rb, u32 m_eb, u32 is_r, u32 rc)
{
if (is_r) // rldcr
{
RLDICR_impl(CPU, ra, rs, (u32)(CPU->GPR[rb] & 0x3F), m_eb, rc);
}
else // rldcl
{
RLDICL_impl(CPU, ra, rs, (u32)(CPU->GPR[rb] & 0x3F), m_eb, rc);
}
}
2016-01-06 11:47:06 +01:00
void RLDC_LR(u32 ra, u32 rs, u32 rb, u32 m_eb, u32 is_r, u32 rc) override
{
RLDC_LR_impl(&CPU, ra, rs, rb, m_eb, is_r, rc);
}
static void CMP_impl(PPUThread *CPU, u32 crfd, u32 l, u32 ra, u32 rb)
{
CPU->UpdateCRnS(l, crfd, CPU->GPR[ra], CPU->GPR[rb]);
}
void CMP(u32 crfd, u32 l, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
CMP_impl(&CPU, crfd, l, ra, rb);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void TW(u32 to, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
2014-08-30 19:51:00 +02:00
s32 a = (s32)CPU.GPR[ra];
s32 b = (s32)CPU.GPR[rb];
2013-07-04 16:20:36 +02:00
if( (a < b && (to & 0x10)) ||
(a > b && (to & 0x8)) ||
(a == b && (to & 0x4)) ||
((u32)a < (u32)b && (to & 0x2)) ||
((u32)a > (u32)b && (to & 0x1)) )
{
throw EXCEPTION("Trap! (tw 0x%x, r%d, r%d)", to, ra, rb);
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void LVSL(u32 vd, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
static const u64 lvsl_values[0x10][2] =
{
{0x08090A0B0C0D0E0F, 0x0001020304050607},
{0x090A0B0C0D0E0F10, 0x0102030405060708},
{0x0A0B0C0D0E0F1011, 0x0203040506070809},
{0x0B0C0D0E0F101112, 0x030405060708090A},
{0x0C0D0E0F10111213, 0x0405060708090A0B},
{0x0D0E0F1011121314, 0x05060708090A0B0C},
{0x0E0F101112131415, 0x060708090A0B0C0D},
{0x0F10111213141516, 0x0708090A0B0C0D0E},
{0x1011121314151617, 0x08090A0B0C0D0E0F},
{0x1112131415161718, 0x090A0B0C0D0E0F10},
{0x1213141516171819, 0x0A0B0C0D0E0F1011},
{0x131415161718191A, 0x0B0C0D0E0F101112},
{0x1415161718191A1B, 0x0C0D0E0F10111213},
{0x15161718191A1B1C, 0x0D0E0F1011121314},
{0x161718191A1B1C1D, 0x0E0F101112131415},
{0x1718191A1B1C1D1E, 0x0F10111213141516},
};
CPU.VPR[vd]._u64[0] = lvsl_values[addr & 0xf][0];
CPU.VPR[vd]._u64[1] = lvsl_values[addr & 0xf][1];
}
2016-01-06 11:47:06 +01:00
void LVEBX(u32 vd, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
2014-09-11 23:10:44 +02:00
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
2015-07-03 01:11:44 +02:00
CPU.VPR[vd]._u8[15 - (addr & 0xf)] = vm::read8(VM_CAST(addr));
// It's bad idea to read 128 bit there
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void SUBFC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override
2013-07-04 16:20:36 +02:00
{
const u64 RA = CPU.GPR[ra];
const u64 RB = CPU.GPR[rb];
CPU.GPR[rd] = ~RA + RB + 1;
CPU.XER.CA = CPU.IsCarry(~RA, RB, 1);
2015-01-17 23:00:58 +01:00
if(oe) CPU.SetOV((~RA>>63 == RB>>63) && (~RA>>63 != CPU.GPR[rd]>>63));
2013-07-04 16:20:36 +02:00
if(rc) CPU.UpdateCR0<s64>(CPU.GPR[rd]);
}
2016-01-06 11:47:06 +01:00
void MULHDU(u32 rd, u32 ra, u32 rb, u32 rc) override
2015-03-17 21:03:24 +01:00
{
2015-11-16 16:04:49 +01:00
CPU.GPR[rd] = UMULH64(CPU.GPR[ra], CPU.GPR[rb]);
2015-03-17 21:03:24 +01:00
if(rc) CPU.UpdateCR0<s64>(CPU.GPR[rd]);
}
2016-01-06 11:47:06 +01:00
void ADDC(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override
2013-07-04 16:20:36 +02:00
{
2015-01-17 23:00:58 +01:00
const u64 RA = CPU.GPR[ra];
const u64 RB = CPU.GPR[rb];
2013-07-04 16:20:36 +02:00
CPU.GPR[rd] = RA + RB;
CPU.XER.CA = CPU.IsCarry(RA, RB);
2015-01-17 23:00:58 +01:00
if(oe) CPU.SetOV((RA>>63 == RB>>63) && (RA>>63 != CPU.GPR[rd]>>63));
2013-07-04 16:20:36 +02:00
if(rc) CPU.UpdateCR0<s64>(CPU.GPR[rd]);
}
2016-01-06 11:47:06 +01:00
void MULHWU(u32 rd, u32 ra, u32 rb, u32 rc) override
2013-07-04 16:20:36 +02:00
{
2014-08-30 19:51:00 +02:00
u32 a = (u32)CPU.GPR[ra];
u32 b = (u32)CPU.GPR[rb];
CPU.GPR[rd] = ((u64)a * (u64)b) >> 32;
if(rc) CPU.UpdateCR0<s64>(CPU.GPR[rd]);
2013-07-04 16:20:36 +02:00
}
static void MFOCRF_impl(PPUThread *CPU, u32 a, u32 rd, u32 crm)
2013-07-04 16:20:36 +02:00
{
CPU->GPR[rd] = CPU->CR.CR;
2013-07-04 16:20:36 +02:00
}
void MFOCRF(u32 a, u32 rd, u32 crm) override
2013-07-04 16:20:36 +02:00
{
MFOCRF_impl(&CPU, a, rd, crm);
}
static void LWARX_impl(PPUThread *CPU, u32 rd, u32 ra, u32 rb)
{
const u64 addr = ra ? CPU->GPR[ra] + CPU->GPR[rb] : CPU->GPR[rb];
2015-02-07 00:39:51 +01:00
be_t<u32> value;
2015-07-03 01:11:44 +02:00
vm::reservation_acquire(&value, VM_CAST(addr), sizeof(value));
2015-02-07 00:39:51 +01:00
CPU->GPR[rd] = value;
}
2016-01-06 11:47:06 +01:00
void LWARX(u32 rd, u32 ra, u32 rb) override
{
LWARX_impl(&CPU, rd, ra, rb);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void LDX(u32 rd, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
2014-10-24 15:24:09 +02:00
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
CPU.GPR[rd] = vm::ps3::read64(VM_CAST(addr));
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void LWZX(u32 rd, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
2014-10-24 15:24:09 +02:00
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
CPU.GPR[rd] = vm::ps3::read32(VM_CAST(addr));
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void SLW(u32 ra, u32 rs, u32 rb, u32 rc) override
2013-07-04 16:20:36 +02:00
{
u32 n = CPU.GPR[rb] & 0x1f;
2014-08-30 19:51:00 +02:00
u32 r = (u32)rotl32((u32)CPU.GPR[rs], n);
u32 m = ((u32)CPU.GPR[rb] & 0x20) ? 0 : (u32)rotate_mask[32][63 - n];
2013-07-04 16:20:36 +02:00
CPU.GPR[ra] = r & m;
if(rc) CPU.UpdateCR0<s64>(CPU.GPR[ra]);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void CNTLZW(u32 ra, u32 rs, u32 rc) override
2013-07-04 16:20:36 +02:00
{
u32 i;
for(i=0; i < 32; i++)
{
if(CPU.GPR[rs] & (1ULL << (31 - i))) break;
}
2013-07-04 16:20:36 +02:00
CPU.GPR[ra] = i;
2014-09-26 14:40:24 +02:00
if(rc) CPU.UpdateCR0<s64>(CPU.GPR[ra]);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void SLD(u32 ra, u32 rs, u32 rb, u32 rc) override
2013-07-04 16:20:36 +02:00
{
u32 n = CPU.GPR[rb] & 0x3f;
u64 r = rotl64(CPU.GPR[rs], n);
u64 m = (CPU.GPR[rb] & 0x40) ? 0 : rotate_mask[0][63 - n];
CPU.GPR[ra] = r & m;
2013-07-04 16:20:36 +02:00
if(rc) CPU.UpdateCR0<s64>(CPU.GPR[ra]);
}
static void AND_impl(PPUThread *CPU, u32 ra, u32 rs, u32 rb, u32 rc)
2013-07-04 16:20:36 +02:00
{
CPU->GPR[ra] = CPU->GPR[rs] & CPU->GPR[rb];
if(rc) CPU->UpdateCR0<s64>(CPU->GPR[ra]);
}
void AND(u32 ra, u32 rs, u32 rb, u32 rc) override
{
AND_impl(&CPU, ra, rs, rb, rc);
}
static void CMPL_impl(PPUThread *CPU, u32 crfd, u32 l, u32 ra, u32 rb)
{
CPU->UpdateCRnU(l, crfd, CPU->GPR[ra], CPU->GPR[rb]);
2013-07-04 16:20:36 +02:00
}
void CMPL(u32 crfd, u32 l, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
CMPL_impl(&CPU, crfd, l, ra, rb);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void LVSR(u32 vd, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
static const u64 lvsr_values[0x10][2] =
{
{0x18191A1B1C1D1E1F, 0x1011121314151617},
{0x1718191A1B1C1D1E, 0x0F10111213141516},
{0x161718191A1B1C1D, 0x0E0F101112131415},
{0x15161718191A1B1C, 0x0D0E0F1011121314},
{0x1415161718191A1B, 0x0C0D0E0F10111213},
{0x131415161718191A, 0x0B0C0D0E0F101112},
{0x1213141516171819, 0x0A0B0C0D0E0F1011},
{0x1112131415161718, 0x090A0B0C0D0E0F10},
{0x1011121314151617, 0x08090A0B0C0D0E0F},
{0x0F10111213141516, 0x0708090A0B0C0D0E},
{0x0E0F101112131415, 0x060708090A0B0C0D},
{0x0D0E0F1011121314, 0x05060708090A0B0C},
{0x0C0D0E0F10111213, 0x0405060708090A0B},
{0x0B0C0D0E0F101112, 0x030405060708090A},
{0x0A0B0C0D0E0F1011, 0x0203040506070809},
{0x090A0B0C0D0E0F10, 0x0102030405060708},
};
CPU.VPR[vd]._u64[0] = lvsr_values[addr & 0xf][0];
CPU.VPR[vd]._u64[1] = lvsr_values[addr & 0xf][1];
}
2016-01-06 11:47:06 +01:00
void LVEHX(u32 vd, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
2014-09-11 23:10:44 +02:00
const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~1ULL;
CPU.VPR[vd]._u16[7 - ((addr >> 1) & 0x7)] = vm::ps3::read16(VM_CAST(addr));
// It's bad idea to read 128 bit there
2013-07-04 16:20:36 +02:00
}
static void SUBF_impl(PPUThread *CPU, u32 rd, u32 ra, u32 rb, u32 oe, u32 rc)
2013-07-04 16:20:36 +02:00
{
const u64 RA = CPU->GPR[ra];
const u64 RB = CPU->GPR[rb];
CPU->GPR[rd] = RB - RA;
if(oe) CPU->SetOV((~RA >> 63 == RB >> 63) && (~RA >> 63 != CPU->GPR[rd] >> 63));
if(rc) CPU->UpdateCR0<s64>(CPU->GPR[rd]);
2013-07-04 16:20:36 +02:00
}
void SUBF(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override
{
SUBF_impl(&CPU, rd, ra, rb, oe, rc);
}
2016-01-06 11:47:06 +01:00
void LDUX(u32 rd, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
const u64 addr = CPU.GPR[ra] + CPU.GPR[rb];
CPU.GPR[rd] = vm::ps3::read64(VM_CAST(addr));
2013-07-04 16:20:36 +02:00
CPU.GPR[ra] = addr;
}
2016-01-06 11:47:06 +01:00
void DCBST(u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
}
2016-01-06 11:47:06 +01:00
void LWZUX(u32 rd, u32 ra, u32 rb) override
{
const u64 addr = CPU.GPR[ra] + CPU.GPR[rb];
CPU.GPR[rd] = vm::ps3::read32(VM_CAST(addr));
CPU.GPR[ra] = addr;
}
2016-01-06 11:47:06 +01:00
void CNTLZD(u32 ra, u32 rs, u32 rc) override
2013-07-04 16:20:36 +02:00
{
u32 i;
for(i=0; i < 64; i++)
{
if(CPU.GPR[rs] & (1ULL << (63 - i))) break;
}
2013-07-04 16:20:36 +02:00
CPU.GPR[ra] = i;
2014-09-26 14:40:24 +02:00
if(rc) CPU.UpdateCR0<s64>(CPU.GPR[ra]);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void ANDC(u32 ra, u32 rs, u32 rb, u32 rc) override
2013-07-04 16:20:36 +02:00
{
CPU.GPR[ra] = CPU.GPR[rs] & ~CPU.GPR[rb];
if(rc) CPU.UpdateCR0<s64>(CPU.GPR[ra]);
}
2016-01-06 11:47:06 +01:00
void TD(u32 to, u32 ra, u32 rb) override
2014-05-08 08:28:34 +02:00
{
throw EXCEPTION("");
2014-05-08 08:28:34 +02:00
}
2016-01-06 11:47:06 +01:00
void LVEWX(u32 vd, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
2014-09-11 23:10:44 +02:00
const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~3ULL;
CPU.VPR[vd]._u32[3 - ((addr >> 2) & 0x3)] = vm::ps3::read32(VM_CAST(addr));
// It's bad idea to read 128 bit there
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void MULHD(u32 rd, u32 ra, u32 rb, u32 rc) override
2013-07-04 16:20:36 +02:00
{
2015-11-16 16:04:49 +01:00
CPU.GPR[rd] = MULH64(CPU.GPR[ra], CPU.GPR[rb]);
2013-07-04 16:20:36 +02:00
if(rc) CPU.UpdateCR0<s64>(CPU.GPR[rd]);
}
2016-01-06 11:47:06 +01:00
void MULHW(u32 rd, u32 ra, u32 rb, u32 rc) override
2013-07-04 16:20:36 +02:00
{
2014-08-30 19:51:00 +02:00
s32 a = (s32)CPU.GPR[ra];
s32 b = (s32)CPU.GPR[rb];
CPU.GPR[rd] = ((s64)a * (s64)b) >> 32;
if(rc) CPU.UpdateCR0<s64>(CPU.GPR[rd]);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void LDARX(u32 rd, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
2015-02-07 00:39:51 +01:00
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
be_t<u64> value;
2015-07-03 01:11:44 +02:00
vm::reservation_acquire(&value, VM_CAST(addr), sizeof(value));
2015-02-07 00:39:51 +01:00
CPU.GPR[rd] = value;
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void DCBF(u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
}
2016-01-06 11:47:06 +01:00
void LBZX(u32 rd, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
2014-10-24 15:24:09 +02:00
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
2015-07-03 01:11:44 +02:00
CPU.GPR[rd] = vm::read8(VM_CAST(addr));
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void LVX(u32 vd, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
2015-04-03 18:56:57 +02:00
const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~0xfull;
CPU.VPR[vd] = vm::ps3::_ref<v128>(VM_CAST(addr));
2013-07-04 16:20:36 +02:00
}
static void NEG_impl(PPUThread *CPU, u32 rd, u32 ra, u32 oe, u32 rc)
2013-07-04 16:20:36 +02:00
{
const u64 RA = CPU->GPR[ra];
CPU->GPR[rd] = 0 - RA;
if(oe) CPU->SetOV((~RA >> 63 == 0) && (~RA >> 63 != CPU->GPR[rd] >> 63));
if(rc) CPU->UpdateCR0<s64>(CPU->GPR[rd]);
2013-07-04 16:20:36 +02:00
}
void NEG(u32 rd, u32 ra, u32 oe, u32 rc) override
{
NEG_impl(&CPU, rd, ra, oe, rc);
}
2016-01-06 11:47:06 +01:00
void LBZUX(u32 rd, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
const u64 addr = CPU.GPR[ra] + CPU.GPR[rb];
2015-07-03 01:11:44 +02:00
CPU.GPR[rd] = vm::read8(VM_CAST(addr));
2013-07-04 16:20:36 +02:00
CPU.GPR[ra] = addr;
}
2016-01-06 11:47:06 +01:00
void NOR(u32 ra, u32 rs, u32 rb, u32 rc) override
2013-07-04 16:20:36 +02:00
{
CPU.GPR[ra] = ~(CPU.GPR[rs] | CPU.GPR[rb]);
if(rc) CPU.UpdateCR0<s64>(CPU.GPR[ra]);
}
2016-01-06 11:47:06 +01:00
void STVEBX(u32 vs, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
const u8 eb = addr & 0xf;
2015-07-03 01:11:44 +02:00
vm::write8(VM_CAST(addr), CPU.VPR[vs]._u8[15 - eb]);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void SUBFE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override
2013-07-04 16:20:36 +02:00
{
const u64 RA = CPU.GPR[ra];
const u64 RB = CPU.GPR[rb];
CPU.GPR[rd] = ~RA + RB + CPU.XER.CA;
CPU.XER.CA = CPU.IsCarry(~RA, RB, CPU.XER.CA);
2015-01-17 23:00:58 +01:00
if(oe) CPU.SetOV((~RA>>63 == RB>>63) && (~RA>>63 != CPU.GPR[rd]>>63));
2013-07-04 16:20:36 +02:00
if(rc) CPU.UpdateCR0<s64>(CPU.GPR[rd]);
}
2016-01-06 11:47:06 +01:00
void ADDE(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override
2013-07-04 16:20:36 +02:00
{
2014-01-23 19:40:49 +01:00
const u64 RA = CPU.GPR[ra];
const u64 RB = CPU.GPR[rb];
if (CPU.XER.CA)
{
if (RA == ~0ULL) //-1
{
CPU.GPR[rd] = RB;
CPU.XER.CA = 1;
}
else
{
CPU.GPR[rd] = RA + 1 + RB;
CPU.XER.CA = CPU.IsCarry(RA + 1, RB);
}
}
else
{
CPU.GPR[rd] = RA + RB;
CPU.XER.CA = CPU.IsCarry(RA, RB);
}
2015-01-17 23:00:58 +01:00
if(oe) CPU.SetOV((RA>>63 == RB>>63) && (RA>>63 != CPU.GPR[rd]>>63));
2013-07-04 16:20:36 +02:00
if(rc) CPU.UpdateCR0<s64>(CPU.GPR[rd]);
}
static void MTOCRF_impl(PPUThread *CPU, u32 l, u32 crm, u32 rs)
2013-07-04 16:20:36 +02:00
{
if(l)
{
u32 n = 0, count = 0;
for(u32 i=0; i<8; ++i)
{
if (crm & (1 << i))
{
n = i;
count++;
}
}
2013-07-04 16:20:36 +02:00
if(count == 1)
{
//CR[4*n : 4*n+3] = RS[32+4*n : 32+4*n+3];
CPU->SetCR(7 - n, (CPU->GPR[rs] >> (4 * n)) & 0xf);
}
else
CPU->CR.CR = 0;
}
else
{
for(u32 i=0; i<8; ++i)
{
if(crm & (1 << i))
{
CPU->SetCR(7 - i, (CPU->GPR[rs] >> (i * 4)) & 0xf);
}
}
}
2013-07-04 16:20:36 +02:00
}
void MTOCRF(u32 l, u32 crm, u32 rs) override
{
MTOCRF_impl(&CPU, l, crm, rs);
}
2016-01-06 11:47:06 +01:00
void STDX(u32 rs, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
2014-10-24 15:24:09 +02:00
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
vm::ps3::write64(VM_CAST(addr), CPU.GPR[rs]);
2013-07-04 16:20:36 +02:00
}
static void STWCX__impl(PPUThread* CPU, u32 rs, u32 ra, u32 rb)
2013-07-04 16:20:36 +02:00
{
const u64 addr = ra ? CPU->GPR[ra] + CPU->GPR[rb] : CPU->GPR[rb];
const be_t<u32> value = (u32)CPU->GPR[rs];
CPU->SetCR_EQ(0, vm::reservation_update(VM_CAST(addr), &value, sizeof(value)));
}
2016-01-06 11:47:06 +01:00
void STWCX_(u32 rs, u32 ra, u32 rb) override
{
STWCX__impl(&CPU, rs, ra, rb);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void STWX(u32 rs, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
2014-10-24 15:24:09 +02:00
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
vm::ps3::write32(VM_CAST(addr), (u32)CPU.GPR[rs]);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void STVEHX(u32 vs, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~1ULL;
const u8 eb = (addr & 0xf) >> 1;
vm::ps3::write16(VM_CAST(addr), CPU.VPR[vs]._u16[7 - eb]);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void STDUX(u32 rs, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
const u64 addr = CPU.GPR[ra] + CPU.GPR[rb];
vm::ps3::write64(VM_CAST(addr), CPU.GPR[rs]);
2013-07-04 16:20:36 +02:00
CPU.GPR[ra] = addr;
}
2016-01-06 11:47:06 +01:00
void STWUX(u32 rs, u32 ra, u32 rb) override
{
const u64 addr = CPU.GPR[ra] + CPU.GPR[rb];
vm::ps3::write32(VM_CAST(addr), (u32)CPU.GPR[rs]);
CPU.GPR[ra] = addr;
}
2016-01-06 11:47:06 +01:00
void STVEWX(u32 vs, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~3ULL;
const u8 eb = (addr & 0xf) >> 2;
vm::ps3::write32(VM_CAST(addr), CPU.VPR[vs]._u32[3 - eb]);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void SUBFZE(u32 rd, u32 ra, u32 oe, u32 rc) override
{
const u64 RA = CPU.GPR[ra];
CPU.GPR[rd] = ~RA + CPU.XER.CA;
CPU.XER.CA = CPU.IsCarry(~RA, CPU.XER.CA);
2015-01-17 23:00:58 +01:00
if(oe) CPU.SetOV((~RA>>63 == 0) && (~RA>>63 != CPU.GPR[rd]>>63));
if(rc) CPU.UpdateCR0<s64>(CPU.GPR[rd]);
}
2016-01-06 11:47:06 +01:00
void ADDZE(u32 rd, u32 ra, u32 oe, u32 rc) override
2015-03-17 21:03:24 +01:00
{
const u64 RA = CPU.GPR[ra];
CPU.GPR[rd] = RA + CPU.XER.CA;
CPU.XER.CA = CPU.IsCarry(RA, CPU.XER.CA);
if(oe) CPU.SetOV((RA>>63 == 0) && (RA>>63 != CPU.GPR[rd]>>63));
if(rc) CPU.UpdateCR0<s64>(CPU.GPR[rd]);
}
2016-01-06 11:47:06 +01:00
void STDCX_(u32 rs, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
const be_t<u64> value = CPU.GPR[rs];
2015-07-03 01:11:44 +02:00
CPU.SetCR_EQ(0, vm::reservation_update(VM_CAST(addr), &value, sizeof(value)));
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void STBX(u32 rs, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
2014-10-24 15:24:09 +02:00
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
2015-07-03 01:11:44 +02:00
vm::write8(VM_CAST(addr), (u8)CPU.GPR[rs]);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void STVX(u32 vs, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
2015-04-03 18:56:57 +02:00
const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~0xfull;
vm::ps3::_ref<v128>(VM_CAST(addr)) = CPU.VPR[vs];
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void MULLD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override
2013-07-04 16:20:36 +02:00
{
2015-01-17 23:00:58 +01:00
const s64 RA = CPU.GPR[ra];
const s64 RB = CPU.GPR[rb];
CPU.GPR[rd] = (s64)(RA * RB);
if(oe)
{
2015-11-16 16:04:49 +01:00
const s64 high = MULH64(RA, RB);
2015-01-17 23:00:58 +01:00
CPU.SetOV(high != s64(CPU.GPR[rd]) >> 63);
}
2013-07-04 16:20:36 +02:00
if(rc) CPU.UpdateCR0<s64>(CPU.GPR[rd]);
}
2016-01-06 11:47:06 +01:00
void SUBFME(u32 rd, u32 ra, u32 oe, u32 rc) override
2015-03-17 21:03:24 +01:00
{
const u64 RA = CPU.GPR[ra];
CPU.GPR[rd] = ~RA + CPU.XER.CA + ~0ULL;
CPU.XER.CA = CPU.IsCarry(~RA, CPU.XER.CA, ~0ULL);
if(oe) CPU.SetOV((~RA>>63 == 1) && (~RA>>63 != CPU.GPR[rd]>>63));
if(rc) CPU.UpdateCR0<s64>(CPU.GPR[rd]);
}
2016-01-06 11:47:06 +01:00
void ADDME(u32 rd, u32 ra, u32 oe, u32 rc) override
2013-07-04 16:20:36 +02:00
{
const s64 RA = CPU.GPR[ra];
CPU.GPR[rd] = RA + CPU.XER.CA - 1;
CPU.XER.CA |= RA != 0;
2015-01-17 23:00:58 +01:00
if(oe) CPU.SetOV((u64(RA)>>63 == 1) && (u64(RA)>>63 != CPU.GPR[rd]>>63));
2013-07-04 16:20:36 +02:00
if(rc) CPU.UpdateCR0<s64>(CPU.GPR[rd]);
}
static void MULLW_impl(PPUThread *CPU, u32 rd, u32 ra, u32 rb, u32 oe, u32 rc)
2013-07-04 16:20:36 +02:00
{
CPU->GPR[rd] = (s64)((s64)(s32)CPU->GPR[ra] * (s64)(s32)CPU->GPR[rb]);
if(oe) CPU->SetOV(s64(CPU->GPR[rd]) < s64(-1) << 31 || s64(CPU->GPR[rd]) >= s64(1) << 31);
if(rc) CPU->UpdateCR0<s64>(CPU->GPR[rd]);
2013-07-04 16:20:36 +02:00
}
void MULLW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override
{
MULLW_impl(&CPU, rd, ra, rb, oe, rc);
}
2016-01-06 11:47:06 +01:00
void DCBTST(u32 ra, u32 rb, u32 th) override
2013-07-04 16:20:36 +02:00
{
}
2016-01-06 11:47:06 +01:00
void STBUX(u32 rs, u32 ra, u32 rb) override
{
const u64 addr = CPU.GPR[ra] + CPU.GPR[rb];
2015-07-03 01:11:44 +02:00
vm::write8(VM_CAST(addr), (u8)CPU.GPR[rs]);
CPU.GPR[ra] = addr;
}
static void ADD_impl(PPUThread *CPU, u32 rd, u32 ra, u32 rb, u32 oe, u32 rc)
2013-07-04 16:20:36 +02:00
{
const u64 RA = CPU->GPR[ra];
const u64 RB = CPU->GPR[rb];
CPU->GPR[rd] = RA + RB;
if(oe) CPU->SetOV((RA >> 63 == RB >> 63) && (RA >> 63 != CPU->GPR[rd] >> 63));
if(rc) CPU->UpdateCR0<s64>(CPU->GPR[rd]);
}
void ADD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override
{
ADD_impl(&CPU, rd, ra, rb, oe, rc);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void DCBT(u32 ra, u32 rb, u32 th) override
2013-07-04 16:20:36 +02:00
{
}
2016-01-06 11:47:06 +01:00
void LHZX(u32 rd, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
2014-10-24 15:24:09 +02:00
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
CPU.GPR[rd] = vm::ps3::read16(VM_CAST(addr));
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void EQV(u32 ra, u32 rs, u32 rb, u32 rc) override
2013-07-04 16:20:36 +02:00
{
CPU.GPR[ra] = ~(CPU.GPR[rs] ^ CPU.GPR[rb]);
if(rc) CPU.UpdateCR0<s64>(CPU.GPR[ra]);
}
2016-01-06 11:47:06 +01:00
void ECIWX(u32 rd, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
2015-07-01 19:09:26 +02:00
throw EXCEPTION("Privileged instruction");
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void LHZUX(u32 rd, u32 ra, u32 rb)override
2013-07-04 16:20:36 +02:00
{
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
CPU.GPR[rd] = vm::ps3::read16(VM_CAST(addr));
2013-07-04 16:20:36 +02:00
CPU.GPR[ra] = addr;
}
2016-01-06 11:47:06 +01:00
void XOR(u32 ra, u32 rs, u32 rb, u32 rc) override
2013-07-04 16:20:36 +02:00
{
CPU.GPR[ra] = CPU.GPR[rs] ^ CPU.GPR[rb];
if(rc) CPU.UpdateCR0<s64>(CPU.GPR[ra]);
}
2016-01-06 11:47:06 +01:00
void MFSPR(u32 rd, u32 spr) override
2013-07-04 16:20:36 +02:00
{
CPU.GPR[rd] = ReadSPR(spr);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void LWAX(u32 rd, u32 ra, u32 rb) override
{
2014-10-24 15:24:09 +02:00
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
CPU.GPR[rd] = (s64)(s32)vm::ps3::read32(VM_CAST(addr));
}
2016-01-06 11:47:06 +01:00
void DST(u32 ra, u32 rb, u32 strm, u32 t) override
2013-07-04 16:20:36 +02:00
{
}
2016-01-06 11:47:06 +01:00
void LHAX(u32 rd, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
2014-10-24 15:24:09 +02:00
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
CPU.GPR[rd] = (s64)(s16)vm::ps3::read16(VM_CAST(addr));
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void LVXL(u32 vd, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
2015-04-03 18:56:57 +02:00
const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~0xfull;
CPU.VPR[vd] = vm::ps3::_ref<v128>(VM_CAST(addr));
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void MFTB(u32 rd, u32 spr) override
2013-07-04 16:20:36 +02:00
{
const u32 n = (spr >> 5) | ((spr & 0x1f) << 5);
CPU.TB = get_timebased_time();
2013-07-04 16:20:36 +02:00
switch(n)
{
2013-07-04 16:20:36 +02:00
case 0x10C: CPU.GPR[rd] = CPU.TB; break;
case 0x10D: CPU.GPR[rd] = CPU.TB >> 32; break;
default: throw EXCEPTION("mftb r%d, %d", rd, spr);
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void LWAUX(u32 rd, u32 ra, u32 rb) override
{
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
CPU.GPR[rd] = (s64)(s32)vm::ps3::read32(VM_CAST(addr));
CPU.GPR[ra] = addr;
}
2016-01-06 11:47:06 +01:00
void DSTST(u32 ra, u32 rb, u32 strm, u32 t) override
2013-07-04 16:20:36 +02:00
{
}
2016-01-06 11:47:06 +01:00
void LHAUX(u32 rd, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
CPU.GPR[rd] = (s64)(s16)vm::ps3::read16(VM_CAST(addr));
2013-07-04 16:20:36 +02:00
CPU.GPR[ra] = addr;
}
2016-01-06 11:47:06 +01:00
void STHX(u32 rs, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
2014-10-24 15:24:09 +02:00
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
vm::ps3::write16(VM_CAST(addr), (u16)CPU.GPR[rs]);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void ORC(u32 ra, u32 rs, u32 rb, u32 rc) override
2013-07-04 16:20:36 +02:00
{
CPU.GPR[ra] = CPU.GPR[rs] | ~CPU.GPR[rb];
if(rc) CPU.UpdateCR0<s64>(CPU.GPR[ra]);
}
2016-01-06 11:47:06 +01:00
void ECOWX(u32 rs, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
2015-07-01 19:09:26 +02:00
throw EXCEPTION("Privileged instruction");
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void STHUX(u32 rs, u32 ra, u32 rb) override
{
const u64 addr = CPU.GPR[ra] + CPU.GPR[rb];
vm::ps3::write16(VM_CAST(addr), (u16)CPU.GPR[rs]);
CPU.GPR[ra] = addr;
}
static void OR_impl(PPUThread *CPU, u32 ra, u32 rs, u32 rb, u32 rc)
2013-07-04 16:20:36 +02:00
{
CPU->GPR[ra] = CPU->GPR[rs] | CPU->GPR[rb];
if(rc) CPU->UpdateCR0<s64>(CPU->GPR[ra]);
}
void OR(u32 ra, u32 rs, u32 rb, u32 rc) override
{
OR_impl(&CPU, ra, rs, rb, rc);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void DIVDU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override
2013-07-04 16:20:36 +02:00
{
const u64 RA = CPU.GPR[ra];
const u64 RB = CPU.GPR[rb];
2013-07-04 16:20:36 +02:00
if(RB == 0)
{
2015-01-17 23:00:58 +01:00
if(oe) CPU.SetOV(true);
2013-07-04 16:20:36 +02:00
CPU.GPR[rd] = 0;
}
2013-07-04 16:20:36 +02:00
else
{
2015-01-17 23:00:58 +01:00
if(oe) CPU.SetOV(false);
2013-07-04 16:20:36 +02:00
CPU.GPR[rd] = RA / RB;
}
2013-07-04 16:20:36 +02:00
if(rc) CPU.UpdateCR0<s64>(CPU.GPR[rd]);
}
static void DIVWU_impl(PPUThread *CPU, u32 rd, u32 ra, u32 rb, u32 oe, u32 rc)
2013-07-04 16:20:36 +02:00
{
const u32 RA = (u32)CPU->GPR[ra];
const u32 RB = (u32)CPU->GPR[rb];
2013-07-04 16:20:36 +02:00
if(RB == 0)
{
if(oe) CPU->SetOV(true);
CPU->GPR[rd] = 0;
}
2013-07-04 16:20:36 +02:00
else
{
if(oe) CPU->SetOV(false);
CPU->GPR[rd] = RA / RB;
}
if(rc) CPU->UpdateCR0<s64>(CPU->GPR[rd]);
2013-07-04 16:20:36 +02:00
}
void DIVWU(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override
{
DIVWU_impl(&CPU, rd, ra, rb, oe, rc);
}
2016-01-06 11:47:06 +01:00
void MTSPR(u32 spr, u32 rs) override
2013-07-04 16:20:36 +02:00
{
WriteSPR(spr, CPU.GPR[rs]);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void DCBI(u32 ra, u32 rb) override
2014-10-25 22:53:55 +02:00
{
}
2016-01-06 11:47:06 +01:00
void NAND(u32 ra, u32 rs, u32 rb, u32 rc) override
2013-07-04 16:20:36 +02:00
{
CPU.GPR[ra] = ~(CPU.GPR[rs] & CPU.GPR[rb]);
2013-07-04 16:20:36 +02:00
if(rc) CPU.UpdateCR0<s64>(CPU.GPR[ra]);
}
2016-01-06 11:47:06 +01:00
void STVXL(u32 vs, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
2015-04-03 18:56:57 +02:00
const u64 addr = (ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]) & ~0xfull;
vm::ps3::_ref<v128>(VM_CAST(addr)) = CPU.VPR[vs];
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void DIVD(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override
2013-07-04 16:20:36 +02:00
{
const s64 RA = CPU.GPR[ra];
const s64 RB = CPU.GPR[rb];
if (RB == 0 || ((u64)RA == (1ULL << 63) && RB == -1))
{
2015-01-17 23:00:58 +01:00
if(oe) CPU.SetOV(true);
CPU.GPR[rd] = /*(((u64)RA & (1ULL << 63)) && RB == 0) ? -1 :*/ 0;
}
2013-07-04 16:20:36 +02:00
else
{
2015-01-17 23:00:58 +01:00
if(oe) CPU.SetOV(false);
2013-07-04 16:20:36 +02:00
CPU.GPR[rd] = RA / RB;
}
2013-07-04 16:20:36 +02:00
if(rc) CPU.UpdateCR0<s64>(CPU.GPR[rd]);
}
static void DIVW_impl(PPUThread *CPU, u32 rd, u32 ra, u32 rb, u32 oe, u32 rc)
2013-07-04 16:20:36 +02:00
{
const s32 RA = (s32)CPU->GPR[ra];
const s32 RB = (s32)CPU->GPR[rb];
2013-07-04 16:20:36 +02:00
if (RB == 0 || ((u32)RA == (1 << 31) && RB == -1))
{
if(oe) CPU->SetOV(true);
CPU->GPR[rd] = /*(((u32)RA & (1 << 31)) && RB == 0) ? -1 :*/ 0;
}
2013-07-04 16:20:36 +02:00
else
{
if(oe) CPU->SetOV(false);
CPU->GPR[rd] = (u32)(RA / RB);
}
if(rc) CPU->UpdateCR0<s64>(CPU->GPR[rd]);
}
void DIVW(u32 rd, u32 ra, u32 rb, u32 oe, u32 rc) override
{
DIVW_impl(&CPU, rd, ra, rb, oe, rc);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void LVLX(u32 vd, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
2014-09-15 00:17:24 +02:00
const u32 eb = addr & 0xf;
CPU.VPR[vd].clear();
2015-07-03 01:11:44 +02:00
for (u32 i = 0; i < 16u - eb; ++i) CPU.VPR[vd]._u8[15 - i] = vm::read8(VM_CAST(addr + i));
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void LDBRX(u32 rd, u32 ra, u32 rb) override
{
2014-10-24 15:24:09 +02:00
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
CPU.GPR[rd] = vm::ps3::_ref<le_t<u64>>(VM_CAST(addr));
}
2016-01-06 11:47:06 +01:00
void LSWX(u32 rd, u32 ra, u32 rb) override
{
2015-01-17 23:00:58 +01:00
u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
u32 count = CPU.XER.XER & 0x7F;
for (; count >= 4; count -= 4, addr += 4, rd = (rd+1) & 31)
{
CPU.GPR[rd] = vm::ps3::_ref<u32>(VM_CAST(addr));
2015-01-17 23:00:58 +01:00
}
if (count)
{
u32 value = 0;
for (u32 byte = 0; byte < count; byte++)
{
u32 byte_value = vm::ps3::_ref<u8>(VM_CAST(addr+byte));
2015-01-17 23:00:58 +01:00
value |= byte_value << ((3^byte)*8);
}
CPU.GPR[rd] = value;
}
}
2016-01-06 11:47:06 +01:00
void LWBRX(u32 rd, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
2014-10-24 15:24:09 +02:00
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
CPU.GPR[rd] = vm::ps3::_ref<le_t<u32>>(VM_CAST(addr));
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void LFSX(u32 frd, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
2014-10-24 15:24:09 +02:00
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
const f32 val = vm::ps3::_ref<f32>(VM_CAST(addr));
2015-01-17 23:02:50 +01:00
if (!FPRdouble::IsNaN(val))
{
CPU.FPR[frd] = val;
}
else
{
u64 bits = (u32&)val;
(u64&)CPU.FPR[frd] = (bits & 0x80000000) << 32 | 7ULL << 60 | (bits & 0x7fffffff) << 29;
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void SRW(u32 ra, u32 rs, u32 rb, u32 rc) override
2013-07-04 16:20:36 +02:00
{
u32 n = CPU.GPR[rb] & 0x1f;
2014-08-30 19:51:00 +02:00
u32 r = (u32)rotl32((u32)CPU.GPR[rs], 64 - n);
u32 m = ((u32)CPU.GPR[rb] & 0x20) ? 0 : (u32)rotate_mask[32 + n][63];
CPU.GPR[ra] = r & m;
if(rc) CPU.UpdateCR0<s64>(CPU.GPR[ra]);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void SRD(u32 ra, u32 rs, u32 rb, u32 rc) override
2013-07-04 16:20:36 +02:00
{
u32 n = CPU.GPR[rb] & 0x3f;
u64 r = rotl64(CPU.GPR[rs], 64 - n);
2013-11-22 16:15:04 +01:00
u64 m = (CPU.GPR[rb] & 0x40) ? 0 : rotate_mask[n][63];
CPU.GPR[ra] = r & m;
2013-07-04 16:20:36 +02:00
if(rc) CPU.UpdateCR0<s64>(CPU.GPR[ra]);
}
2016-01-06 11:47:06 +01:00
void LVRX(u32 vd, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
const u8 eb = addr & 0xf;
CPU.VPR[vd].clear();
2015-07-03 01:11:44 +02:00
for (u32 i = 16 - eb; i < 16; ++i) CPU.VPR[vd]._u8[15 - i] = vm::read8(VM_CAST(addr + i - 16));
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void LSWI(u32 rd, u32 ra, u32 nb) override
2014-03-20 02:48:02 +01:00
{
2014-10-24 15:24:09 +02:00
u64 addr = ra ? CPU.GPR[ra] : 0;
2014-03-20 02:48:02 +01:00
u64 N = nb ? nb : 32;
2014-10-18 22:27:54 +02:00
u8 reg = rd;
2014-03-20 02:48:02 +01:00
while (N > 0)
{
if (N > 3)
{
CPU.GPR[reg] = vm::ps3::read32(VM_CAST(addr));
2014-10-24 15:24:09 +02:00
addr += 4;
2014-03-20 02:48:02 +01:00
N -= 4;
}
else
{
u32 buf = 0;
u32 i = 3;
2014-03-20 02:48:02 +01:00
while (N > 0)
{
N = N - 1;
2015-07-03 01:11:44 +02:00
buf |= vm::read8(VM_CAST(addr)) << (i * 8);
2014-10-24 15:24:09 +02:00
addr++;
i--;
2014-03-20 02:48:02 +01:00
}
CPU.GPR[reg] = buf;
}
reg = (reg + 1) % 32;
}
}
2016-01-06 11:47:06 +01:00
void LFSUX(u32 frd, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
const u64 addr = CPU.GPR[ra] + CPU.GPR[rb];
const f32 val = vm::ps3::_ref<f32>(VM_CAST(addr));
2015-01-17 23:02:50 +01:00
if (!FPRdouble::IsNaN(val))
{
CPU.FPR[frd] = val;
}
else
{
u64 bits = (u32&)val;
(u64&)CPU.FPR[frd] = (bits & 0x80000000) << 32 | 7ULL << 60 | (bits & 0x7fffffff) << 29;
}
2013-07-04 16:20:36 +02:00
CPU.GPR[ra] = addr;
}
2016-01-06 11:47:06 +01:00
void SYNC(u32 l) override
2013-07-04 16:20:36 +02:00
{
2014-01-19 11:52:30 +01:00
_mm_mfence();
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void LFDX(u32 frd, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
2014-10-24 15:24:09 +02:00
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
CPU.FPR[frd]._double = vm::ps3::_ref<f64>(VM_CAST(addr));
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void LFDUX(u32 frd, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
const u64 addr = CPU.GPR[ra] + CPU.GPR[rb];
CPU.FPR[frd]._double = vm::ps3::_ref<f64>(VM_CAST(addr));
2013-07-04 16:20:36 +02:00
CPU.GPR[ra] = addr;
}
2016-01-06 11:47:06 +01:00
void STVLX(u32 vs, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
2014-09-15 00:17:24 +02:00
const u32 eb = addr & 0xf;
2015-07-03 01:11:44 +02:00
for (u32 i = 0; i < 16u - eb; ++i) vm::write8(VM_CAST(addr + i), CPU.VPR[vs]._u8[15 - i]);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void STDBRX(u32 rs, u32 ra, u32 rb) override
2015-01-17 23:00:58 +01:00
{
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
vm::ps3::_ref<le_t<u64>>(VM_CAST(addr)) = CPU.GPR[rs];
2015-01-17 23:00:58 +01:00
}
2016-01-06 11:47:06 +01:00
void STSWX(u32 rs, u32 ra, u32 rb) override
{
2015-01-17 23:00:58 +01:00
u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
u32 count = CPU.XER.XER & 0x7F;
for (; count >= 4; count -= 4, addr += 4, rs = (rs+1) & 31)
{
vm::ps3::write32(VM_CAST(addr), (u32)CPU.GPR[rs]);
2015-01-17 23:00:58 +01:00
}
if (count)
{
u32 value = (u32)CPU.GPR[rs];
for (u32 byte = 0; byte < count; byte++)
{
u32 byte_value = (u8)(value >> ((3^byte)*8));
2015-07-03 01:11:44 +02:00
vm::write8(VM_CAST(addr+byte), byte_value);
2015-01-17 23:00:58 +01:00
}
}
}
2016-01-06 11:47:06 +01:00
void STWBRX(u32 rs, u32 ra, u32 rb) override
{
2014-10-24 15:24:09 +02:00
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
vm::ps3::_ref<le_t<u32>>(VM_CAST(addr)) = (u32)CPU.GPR[rs];
}
2016-01-06 11:47:06 +01:00
void STFSX(u32 frs, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
2014-10-24 15:24:09 +02:00
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
2015-01-17 23:02:50 +01:00
double val = CPU.FPR[frs];
if (!FPRdouble::IsNaN(val))
{
vm::ps3::_ref<f32>(VM_CAST(addr)) = (float)val;
2015-01-17 23:02:50 +01:00
}
else
{
u64 bits = (u64&)val;
u32 bits32 = (bits>>32 & 0x80000000) | (bits>>29 & 0x7fffffff);
vm::ps3::_ref<u32>(VM_CAST(addr)) = bits32;
2015-01-17 23:02:50 +01:00
}
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void STVRX(u32 vs, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
const u8 eb = addr & 0xf;
2015-07-03 01:11:44 +02:00
for (u32 i = 16 - eb; i < 16; ++i) vm::write8(VM_CAST(addr + i - 16), CPU.VPR[vs]._u8[15 - i]);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void STFSUX(u32 frs, u32 ra, u32 rb) override
{
const u64 addr = CPU.GPR[ra] + CPU.GPR[rb];
2015-01-17 23:02:50 +01:00
double val = CPU.FPR[frs];
if (!FPRdouble::IsNaN(val))
{
vm::ps3::_ref<f32>(VM_CAST(addr)) = (float)val;
2015-01-17 23:02:50 +01:00
}
else
{
u64 bits = (u64&)val;
u32 bits32 = (bits>>32 & 0x80000000) | (bits>>29 & 0x7fffffff);
vm::ps3::_ref<u32>(VM_CAST(addr)) = bits32;
2015-01-17 23:02:50 +01:00
}
CPU.GPR[ra] = addr;
}
2016-01-06 11:47:06 +01:00
void STSWI(u32 rd, u32 ra, u32 nb) override
2014-03-20 02:48:02 +01:00
{
2014-10-24 15:24:09 +02:00
u64 addr = ra ? CPU.GPR[ra] : 0;
2014-08-30 19:51:00 +02:00
u64 N = nb ? nb : 32;
2014-10-18 22:27:54 +02:00
u8 reg = rd;
2014-03-20 02:48:02 +01:00
2014-08-30 19:51:00 +02:00
while (N > 0)
{
if (N > 3)
2014-03-20 02:48:02 +01:00
{
vm::ps3::write32(VM_CAST(addr), (u32)CPU.GPR[reg]);
2014-10-24 15:24:09 +02:00
addr += 4;
2014-08-30 19:51:00 +02:00
N -= 4;
}
else
{
u32 buf = (u32)CPU.GPR[reg];
while (N > 0)
2014-03-20 02:48:02 +01:00
{
2014-08-30 19:51:00 +02:00
N = N - 1;
2015-07-03 01:11:44 +02:00
vm::write8(VM_CAST(addr), (0xFF000000 & buf) >> 24);
2014-08-30 19:51:00 +02:00
buf <<= 8;
2014-10-24 15:24:09 +02:00
addr++;
2014-03-20 02:48:02 +01:00
}
}
2014-08-30 19:51:00 +02:00
reg = (reg + 1) % 32;
}
2014-03-20 02:48:02 +01:00
}
2016-01-06 11:47:06 +01:00
void STFDX(u32 frs, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
2014-10-24 15:24:09 +02:00
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
vm::ps3::_ref<f64>(VM_CAST(addr)) = CPU.FPR[frs];
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void STFDUX(u32 frs, u32 ra, u32 rb) override
{
const u64 addr = CPU.GPR[ra] + CPU.GPR[rb];
vm::ps3::_ref<f64>(VM_CAST(addr)) = CPU.FPR[frs];
CPU.GPR[ra] = addr;
}
2016-01-06 11:47:06 +01:00
void LVLXL(u32 vd, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
2014-09-15 00:17:24 +02:00
const u32 eb = addr & 0xf;
CPU.VPR[vd].clear();
2015-07-03 01:11:44 +02:00
for (u32 i = 0; i < 16u - eb; ++i) CPU.VPR[vd]._u8[15 - i] = vm::read8(VM_CAST(addr + i));
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void LHBRX(u32 rd, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
2014-10-24 15:24:09 +02:00
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
CPU.GPR[rd] = vm::ps3::_ref<le_t<u16>>(VM_CAST(addr));
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void SRAW(u32 ra, u32 rs, u32 rb, u32 rc) override
{
2014-08-30 19:51:00 +02:00
s32 RS = (s32)CPU.GPR[rs];
u8 shift = CPU.GPR[rb] & 63;
if (shift > 31)
{
CPU.GPR[ra] = 0 - (RS < 0);
CPU.XER.CA = (RS < 0);
}
else
{
CPU.GPR[ra] = RS >> shift;
CPU.XER.CA = (RS < 0) & ((CPU.GPR[ra] << shift) != RS);
}
2013-07-04 16:20:36 +02:00
if(rc) CPU.UpdateCR0<s64>(CPU.GPR[ra]);
}
2016-01-06 11:47:06 +01:00
void SRAD(u32 ra, u32 rs, u32 rb, u32 rc) override
2013-07-04 16:20:36 +02:00
{
s64 RS = CPU.GPR[rs];
u8 shift = CPU.GPR[rb] & 127;
if (shift > 63)
{
CPU.GPR[ra] = 0 - (RS < 0);
CPU.XER.CA = (RS < 0);
}
else
{
CPU.GPR[ra] = RS >> shift;
CPU.XER.CA = (RS < 0) & ((CPU.GPR[ra] << shift) != RS);
}
2013-07-04 16:20:36 +02:00
if(rc) CPU.UpdateCR0<s64>(CPU.GPR[ra]);
}
2016-01-06 11:47:06 +01:00
void LVRXL(u32 vd, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
const u8 eb = addr & 0xf;
CPU.VPR[vd].clear();
2015-07-03 01:11:44 +02:00
for (u32 i = 16 - eb; i < 16; ++i) CPU.VPR[vd]._u8[15 - i] = vm::read8(VM_CAST(addr + i - 16));
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void DSS(u32 strm, u32 a) override
2013-07-04 16:20:36 +02:00
{
}
static void SRAWI_impl(PPUThread *CPU, u32 ra, u32 rs, u32 sh, u32 rc)
2013-07-04 16:20:36 +02:00
{
s32 RS = (u32)CPU->GPR[rs];
CPU->GPR[ra] = RS >> sh;
CPU->XER.CA = (RS < 0) & ((u32)(CPU->GPR[ra] << sh) != RS);
if(rc) CPU->UpdateCR0<s64>(CPU->GPR[ra]);
}
void SRAWI(u32 ra, u32 rs, u32 sh, u32 rc) override
{
SRAWI_impl(&CPU, ra, rs, sh, rc);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void SRADI1(u32 ra, u32 rs, u32 sh, u32 rc) override
2013-07-04 16:20:36 +02:00
{
s64 RS = CPU.GPR[rs];
CPU.GPR[ra] = RS >> sh;
CPU.XER.CA = (RS < 0) & ((CPU.GPR[ra] << sh) != RS);
2013-07-04 16:20:36 +02:00
if(rc) CPU.UpdateCR0<s64>(CPU.GPR[ra]);
}
2016-01-06 11:47:06 +01:00
void SRADI2(u32 ra, u32 rs, u32 sh, u32 rc) override
2013-07-04 16:20:36 +02:00
{
SRADI1(ra, rs, sh, rc);
}
2016-01-06 11:47:06 +01:00
void EIEIO() override
2013-07-04 16:20:36 +02:00
{
2014-01-23 19:40:49 +01:00
_mm_mfence();
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void STVLXL(u32 vs, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
2014-09-15 00:17:24 +02:00
const u32 eb = addr & 0xf;
2013-07-04 16:20:36 +02:00
2015-07-03 01:11:44 +02:00
for (u32 i = 0; i < 16u - eb; ++i) vm::write8(VM_CAST(addr + i), CPU.VPR[vs]._u8[15 - i]);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void STHBRX(u32 rs, u32 ra, u32 rb) override
{
2014-10-24 15:24:09 +02:00
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
vm::ps3::_ref<le_t<u16>>(VM_CAST(addr)) = (u16)CPU.GPR[rs];
}
2016-01-06 11:47:06 +01:00
void EXTSH(u32 ra, u32 rs, u32 rc) override
2013-07-04 16:20:36 +02:00
{
CPU.GPR[ra] = (s64)(s16)CPU.GPR[rs];
if(rc) CPU.UpdateCR0<s64>(CPU.GPR[ra]);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void STVRXL(u32 vs, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
const u8 eb = addr & 0xf;
2015-07-03 01:11:44 +02:00
for (u32 i = 16 - eb; i < 16; ++i) vm::write8(VM_CAST(addr + i - 16), CPU.VPR[vs]._u8[15 - i]);
2013-07-04 16:20:36 +02:00
}
static void EXTSB_impl(PPUThread *CPU, u32 ra, u32 rs, u32 rc)
2013-07-04 16:20:36 +02:00
{
CPU->GPR[ra] = (s64)(s8)CPU->GPR[rs];
if(rc) CPU->UpdateCR0<s64>(CPU->GPR[ra]);
}
void EXTSB(u32 ra, u32 rs, u32 rc) override
{
EXTSB_impl(&CPU, ra, rs, rc);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void STFIWX(u32 frs, u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
2014-10-24 15:24:09 +02:00
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
vm::ps3::write32(VM_CAST(addr), (u32&)CPU.FPR[frs]);
2013-07-04 16:20:36 +02:00
}
static void EXTSW_impl(PPUThread *CPU, u32 ra, u32 rs, u32 rc)
2013-07-04 16:20:36 +02:00
{
CPU->GPR[ra] = (s64)(s32)CPU->GPR[rs];
if(rc) CPU->UpdateCR0<s64>(CPU->GPR[ra]);
2013-07-04 16:20:36 +02:00
}
void EXTSW(u32 ra, u32 rs, u32 rc) override
{
EXTSW_impl(&CPU, ra, rs, rc);
}
2016-01-06 11:47:06 +01:00
void ICBI(u32 ra, u32 rs) override
2014-05-08 08:53:19 +02:00
{
// Clear jit for the specified block? Nothing to do in the interpreter.
}
2016-01-06 11:47:06 +01:00
void DCBZ(u32 ra, u32 rb) override
2013-07-04 16:20:36 +02:00
{
const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb];
std::memset(vm::base(VM_CAST(addr) & ~127), 0, 128);
2013-07-04 16:20:36 +02:00
}
static void LWZ_impl(PPUThread *CPU, u32 rd, u32 ra, s32 d)
{
const u64 addr = ra ? CPU->GPR[ra] + d : d;
CPU->GPR[rd] = vm::ps3::read32(VM_CAST(addr));
}
void LWZ(u32 rd, u32 ra, s32 d) override
{
LWZ_impl(&CPU, rd, ra, d);
}
2016-01-06 11:47:06 +01:00
void LWZU(u32 rd, u32 ra, s32 d) override
{
const u64 addr = CPU.GPR[ra] + d;
CPU.GPR[rd] = vm::ps3::read32(VM_CAST(addr));
CPU.GPR[ra] = addr;
}
static void LBZ_impl(PPUThread *CPU, u32 rd, u32 ra, s32 d)
{
const u64 addr = ra ? CPU->GPR[ra] + d : d;
CPU->GPR[rd] = vm::read8(VM_CAST(addr));
}
void LBZ(u32 rd, u32 ra, s32 d) override
{
LBZ_impl(&CPU, rd, ra, d);
}
2016-01-06 11:47:06 +01:00
void LBZU(u32 rd, u32 ra, s32 d) override
{
const u64 addr = CPU.GPR[ra] + d;
2015-07-03 01:11:44 +02:00
CPU.GPR[rd] = vm::read8(VM_CAST(addr));
CPU.GPR[ra] = addr;
}
static void STW_impl(PPUThread *CPU, u32 rs, u32 ra, s32 d)
{
const u64 addr = ra ? CPU->GPR[ra] + d : d;
vm::ps3::write32(VM_CAST(addr), (u32)CPU->GPR[rs]);
}
2016-01-06 11:47:06 +01:00
void STW(u32 rs, u32 ra, s32 d) override
{
STW_impl(&CPU, rs, ra, d);
}
2016-01-06 11:47:06 +01:00
void STWU(u32 rs, u32 ra, s32 d) override
{
const u64 addr = CPU.GPR[ra] + d;
vm::ps3::write32(VM_CAST(addr), (u32)CPU.GPR[rs]);
CPU.GPR[ra] = addr;
}
2016-01-06 11:47:06 +01:00
void STB(u32 rs, u32 ra, s32 d) override
{
2014-10-24 15:24:09 +02:00
const u64 addr = ra ? CPU.GPR[ra] + d : d;
2015-07-03 01:11:44 +02:00
vm::write8(VM_CAST(addr), (u8)CPU.GPR[rs]);
}
2016-01-06 11:47:06 +01:00
void STBU(u32 rs, u32 ra, s32 d) override
{
const u64 addr = CPU.GPR[ra] + d;
2015-07-03 01:11:44 +02:00
vm::write8(VM_CAST(addr), (u8)CPU.GPR[rs]);
CPU.GPR[ra] = addr;
}
static void LHZ_impl(PPUThread *CPU, u32 rd, u32 ra, s32 d)
{
const u64 addr = ra ? CPU->GPR[ra] + d : d;
CPU->GPR[rd] = vm::ps3::read16(VM_CAST(addr));
}
2016-01-06 11:47:06 +01:00
void LHZ(u32 rd, u32 ra, s32 d) override
{
LHZ_impl(&CPU, rd, ra, d);
}
2016-01-06 11:47:06 +01:00
void LHZU(u32 rd, u32 ra, s32 d) override
{
const u64 addr = CPU.GPR[ra] + d;
CPU.GPR[rd] = vm::ps3::read16(VM_CAST(addr));
CPU.GPR[ra] = addr;
}
2016-01-06 11:47:06 +01:00
void LHA(u32 rd, u32 ra, s32 d) override
{
2014-10-24 15:24:09 +02:00
const u64 addr = ra ? CPU.GPR[ra] + d : d;
CPU.GPR[rd] = (s64)(s16)vm::ps3::read16(VM_CAST(addr));
}
2016-01-06 11:47:06 +01:00
void LHAU(u32 rd, u32 ra, s32 d) override
{
const u64 addr = CPU.GPR[ra] + d;
CPU.GPR[rd] = (s64)(s16)vm::ps3::read16(VM_CAST(addr));
CPU.GPR[ra] = addr;
}
2016-01-06 11:47:06 +01:00
void STH(u32 rs, u32 ra, s32 d) override
{
2014-10-24 15:24:09 +02:00
const u64 addr = ra ? CPU.GPR[ra] + d : d;
vm::ps3::write16(VM_CAST(addr), (u16)CPU.GPR[rs]);
}
2016-01-06 11:47:06 +01:00
void STHU(u32 rs, u32 ra, s32 d) override
{
const u64 addr = CPU.GPR[ra] + d;
vm::ps3::write16(VM_CAST(addr), (u16)CPU.GPR[rs]);
CPU.GPR[ra] = addr;
}
2016-01-06 11:47:06 +01:00
void LMW(u32 rd, u32 ra, s32 d) override
{
u64 addr = ra ? CPU.GPR[ra] + d : d;
for(u32 i=rd; i<32; ++i, addr += 4)
{
CPU.GPR[i] = vm::ps3::read32(VM_CAST(addr));
}
}
2016-01-06 11:47:06 +01:00
void STMW(u32 rs, u32 ra, s32 d) override
{
u64 addr = ra ? CPU.GPR[ra] + d : d;
for(u32 i=rs; i<32; ++i, addr += 4)
{
vm::ps3::write32(VM_CAST(addr), (u32)CPU.GPR[i]);
}
}
static void LFS_impl(PPUThread *CPU, u32 frd, u32 ra, s32 d)
{
const u64 addr = ra ? CPU->GPR[ra] + d : d;
const f32 val = vm::ps3::_ref<f32>(VM_CAST(addr));
2015-01-17 23:02:50 +01:00
if (!FPRdouble::IsNaN(val))
{
CPU->FPR[frd] = val;
2015-01-17 23:02:50 +01:00
}
else
{
u64 bits = (u32&)val;
(u64&)CPU->FPR[frd] = (bits & 0x80000000) << 32 | 7ULL << 60 | (bits & 0x7fffffff) << 29;
2015-01-17 23:02:50 +01:00
}
}
void LFS(u32 frd, u32 ra, s32 d) override
{
LFS_impl(&CPU, frd, ra, d);
}
2016-01-06 11:47:06 +01:00
void LFSU(u32 frd, u32 ra, s32 ds) override
{
const u64 addr = CPU.GPR[ra] + ds;
const f32 val = vm::ps3::_ref<f32>(VM_CAST(addr));
2015-01-17 23:02:50 +01:00
if (!FPRdouble::IsNaN(val))
{
CPU.FPR[frd] = val;
}
else
{
u64 bits = (u32&)val;
(u64&)CPU.FPR[frd] = (bits & 0x80000000) << 32 | 7ULL << 60 | (bits & 0x7fffffff) << 29;
}
CPU.GPR[ra] = addr;
}
2016-01-06 11:47:06 +01:00
void LFD(u32 frd, u32 ra, s32 d) override
{
2014-10-24 15:24:09 +02:00
const u64 addr = ra ? CPU.GPR[ra] + d : d;
CPU.FPR[frd]._double = vm::ps3::_ref<f64>(VM_CAST(addr));
}
2016-01-06 11:47:06 +01:00
void LFDU(u32 frd, u32 ra, s32 ds) override
{
const u64 addr = CPU.GPR[ra] + ds;
CPU.FPR[frd]._double = vm::ps3::_ref<f64>(VM_CAST(addr));
CPU.GPR[ra] = addr;
}
static void STFS_impl(PPUThread *CPU, u32 frs, u32 ra, s32 d)
{
const u64 addr = ra ? CPU->GPR[ra] + d : d;
double val = CPU->FPR[frs];
2015-01-17 23:02:50 +01:00
if (!FPRdouble::IsNaN(val))
{
vm::ps3::_ref<f32>(VM_CAST(addr)) = (float)val;
2015-01-17 23:02:50 +01:00
}
else
{
u64 bits = (u64&)val;
u32 bits32 = (bits>>32 & 0x80000000) | (bits>>29 & 0x7fffffff);
vm::ps3::_ref<u32>(VM_CAST(addr)) = bits32;
2015-01-17 23:02:50 +01:00
}
}
void STFS(u32 frs, u32 ra, s32 d) override
{
STFS_impl(&CPU, frs, ra, d);
}
2016-01-06 11:47:06 +01:00
void STFSU(u32 frs, u32 ra, s32 d) override
{
const u64 addr = CPU.GPR[ra] + d;
2015-01-17 23:02:50 +01:00
double val = CPU.FPR[frs];
if (!FPRdouble::IsNaN(val))
{
vm::ps3::_ref<f32>(VM_CAST(addr)) = (float)val;
2015-01-17 23:02:50 +01:00
}
else
{
u64 bits = (u64&)val;
u32 bits32 = (bits>>32 & 0x80000000) | (bits>>29 & 0x7fffffff);
vm::ps3::_ref<u32>(VM_CAST(addr)) = bits32;
2015-01-17 23:02:50 +01:00
}
CPU.GPR[ra] = addr;
}
2016-01-06 11:47:06 +01:00
void STFD(u32 frs, u32 ra, s32 d) override
{
2014-10-24 15:24:09 +02:00
const u64 addr = ra ? CPU.GPR[ra] + d : d;
vm::ps3::_ref<f64>(VM_CAST(addr)) = CPU.FPR[frs];
}
2016-01-06 11:47:06 +01:00
void STFDU(u32 frs, u32 ra, s32 d) override
{
const u64 addr = CPU.GPR[ra] + d;
vm::ps3::_ref<f64>(VM_CAST(addr)) = CPU.FPR[frs];
CPU.GPR[ra] = addr;
}
static void LD_impl(PPUThread *CPU, u32 rd, u32 ra, s32 ds)
{
const u64 addr = ra ? CPU->GPR[ra] + ds : ds;
CPU->GPR[rd] = vm::ps3::read64(VM_CAST(addr));
}
void LD(u32 rd, u32 ra, s32 ds) override
2013-07-04 16:20:36 +02:00
{
LD_impl(&CPU, rd, ra, ds);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void LDU(u32 rd, u32 ra, s32 ds) override
2013-07-04 16:20:36 +02:00
{
const u64 addr = CPU.GPR[ra] + ds;
CPU.GPR[rd] = vm::ps3::read64(VM_CAST(addr));
2013-07-04 16:20:36 +02:00
CPU.GPR[ra] = addr;
}
2016-01-06 11:47:06 +01:00
void LWA(u32 rd, u32 ra, s32 ds) override
{
2014-10-24 15:24:09 +02:00
const u64 addr = ra ? CPU.GPR[ra] + ds : ds;
CPU.GPR[rd] = (s64)(s32)vm::ps3::read32(VM_CAST(addr));
}
2016-01-06 11:47:06 +01:00
void FDIVS(u32 frd, u32 fra, u32 frb, u32 rc) override {FDIV(frd, fra, frb, rc, true);}
void FSUBS(u32 frd, u32 fra, u32 frb, u32 rc) override {FSUB(frd, fra, frb, rc, true);}
void FADDS(u32 frd, u32 fra, u32 frb, u32 rc) override {FADD(frd, fra, frb, rc, true);}
void FSQRTS(u32 frd, u32 frb, u32 rc) override {FSQRT(frd, frb, rc, true);}
void FRES(u32 frd, u32 frb, u32 rc) override
2013-07-04 16:20:36 +02:00
{
SetHostRoundingMode(CPU.FPSCR.RN);
const double b = CPU.FPR[frb];
if(FPRdouble::IsSNaN(b))
{
CPU.SetFPSCRException(FPSCR_VXSNAN);
CPU.FPSCR.FR = 0;
CPU.FPSCR.FI = 0;
if(CPU.FPSCR.VE)
{
if(rc) CPU.UpdateCR1();
return;
}
}
if(FPRdouble::IsNaN(b))
{
CPU.FPR[frd] = SilenceNaN(b);
}
else if(b == 0.0)
{
CPU.SetFPSCRException(FPSCR_ZX);
CPU.FPSCR.FR = 0;
CPU.FPSCR.FI = 0;
if (CPU.FPSCR.ZE)
{
if(rc) CPU.UpdateCR1();
return;
}
CPU.FPR[frd] = 1.0 / b;
}
else
{
feclearexcept(FE_ALL_EXCEPT);
CPU.FPR[frd] = static_cast<float>(1.0 / b);
CheckHostFPExceptions();
}
CPU.FPSCR.FPRF = CPU.FPR[frd].GetType();
2015-01-17 23:00:58 +01:00
if(rc) CPU.UpdateCR1();
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void FMULS(u32 frd, u32 fra, u32 frc, u32 rc) override {FMUL(frd, fra, frc, rc, true);}
void FMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override {FMADD(frd, fra, frc, frb, rc, false, false, true);}
void FMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override {FMADD(frd, fra, frc, frb, rc, false, true, true);}
void FNMSUBS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override {FMADD(frd, fra, frc, frb, rc, true, true, true);}
void FNMADDS(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override {FMADD(frd, fra, frc, frb, rc, true, false, true);}
static void STD_impl(PPUThread *CPU, u32 rs, u32 ra, s32 d)
2013-07-04 16:20:36 +02:00
{
const u64 addr = ra ? CPU->GPR[ra] + d : d;
vm::ps3::write64(VM_CAST(addr), CPU->GPR[rs]);
2013-07-04 16:20:36 +02:00
}
void STD(u32 rs, u32 ra, s32 d) override
2013-07-04 16:20:36 +02:00
{
STD_impl(&CPU, rs, ra, d);
2013-07-04 16:20:36 +02:00
}
static void STDU_impl(PPUThread *CPU, u32 rs, u32 ra, s32 ds)
{
const u64 addr = CPU->GPR[ra] + ds;
vm::ps3::write64(VM_CAST(addr), CPU->GPR[rs]);
CPU->GPR[ra] = addr;
}
void STDU(u32 rs, u32 ra, s32 ds) override
{
STDU_impl(&CPU, rs, ra, ds);
}
2016-01-06 11:47:06 +01:00
void MTFSB1(u32 crbd, u32 rc) override
2013-07-04 16:20:36 +02:00
{
2015-04-03 18:56:57 +02:00
u32 mask = 1 << (31 - crbd);
if ((crbd >= 3 && crbd <= 6) && !(CPU.FPSCR.FPSCR & mask)) mask |= 1 << 31; //FPSCR.FX
if ((crbd == 29) && !CPU.FPSCR.NI) LOG_WARNING(PPU, "Non-IEEE mode enabled");
2015-01-17 23:02:11 +01:00
CPU.SetFPSCR(CPU.FPSCR.FPSCR | mask);
2015-01-17 23:00:58 +01:00
if(rc) CPU.UpdateCR1();
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void MCRFS(u32 crbd, u32 crbs) override
2013-07-04 16:20:36 +02:00
{
2015-01-17 23:02:11 +01:00
CPU.SetCR(crbd, (CPU.FPSCR.FPSCR >> ((7 - crbs) * 4)) & 0xf);
const u32 exceptions_mask = 0x9FF80700;
CPU.SetFPSCR(CPU.FPSCR.FPSCR & ~(exceptions_mask & 0xf << ((7 - crbs) * 4)));
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void MTFSB0(u32 crbd, u32 rc) override
2013-07-04 16:20:36 +02:00
{
2015-04-03 18:56:57 +02:00
u32 mask = 1 << (31 - crbd);
if ((crbd == 29) && !CPU.FPSCR.NI) LOG_WARNING(PPU, "Non-IEEE mode disabled");
2015-01-17 23:02:11 +01:00
CPU.SetFPSCR(CPU.FPSCR.FPSCR & ~mask);
2015-01-17 23:00:58 +01:00
if(rc) CPU.UpdateCR1();
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void MTFSFI(u32 crfd, u32 i, u32 rc) override
2013-07-04 16:20:36 +02:00
{
u32 mask = 0xF0000000 >> (crfd * 4);
u32 val = (i & 0xF) << ((7 - crfd) * 4);
2013-07-11 16:28:10 +02:00
const u32 oldNI = CPU.FPSCR.NI;
2015-01-17 23:02:11 +01:00
CPU.SetFPSCR((CPU.FPSCR.FPSCR & ~mask) | val);
if (CPU.FPSCR.NI != oldNI)
2013-07-11 16:28:10 +02:00
{
if (oldNI)
LOG_WARNING(PPU, "Non-IEEE mode disabled");
else
LOG_WARNING(PPU, "Non-IEEE mode enabled");
2013-07-11 16:28:10 +02:00
}
2015-01-17 23:00:58 +01:00
if(rc) CPU.UpdateCR1();
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void MFFS(u32 frd, u32 rc) override
2013-07-04 16:20:36 +02:00
{
(u64&)CPU.FPR[frd] = CPU.FPSCR.FPSCR;
2015-01-17 23:00:58 +01:00
if(rc) CPU.UpdateCR1();
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void MTFSF(u32 flm, u32 frb, u32 rc) override
2013-07-04 16:20:36 +02:00
{
u32 mask = 0;
for(u32 i=0; i<8; ++i)
{
2013-07-04 16:20:36 +02:00
if(flm & (1 << i)) mask |= 0xf << (i * 4);
}
2015-01-17 23:02:11 +01:00
mask &= ~0x60000000;
const u32 oldNI = CPU.FPSCR.NI;
2015-01-17 23:02:11 +01:00
CPU.SetFPSCR((CPU.FPSCR.FPSCR & ~mask) | ((u32&)CPU.FPR[frb] & mask));
if (CPU.FPSCR.NI != oldNI)
{
if (oldNI)
LOG_WARNING(PPU, "Non-IEEE mode disabled");
else
LOG_WARNING(PPU, "Non-IEEE mode enabled");
}
2015-01-17 23:00:58 +01:00
if(rc) CPU.UpdateCR1();
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void FCMPU(u32 crfd, u32 fra, u32 frb) override
2013-07-04 16:20:36 +02:00
{
int cmp_res = FPRdouble::Cmp(CPU.FPR[fra], CPU.FPR[frb]);
if(cmp_res == CR_SO)
{
2013-07-04 16:20:36 +02:00
if(FPRdouble::IsSNaN(CPU.FPR[fra]) || FPRdouble::IsSNaN(CPU.FPR[frb]))
{
CPU.SetFPSCRException(FPSCR_VXSNAN);
}
}
2013-07-04 16:20:36 +02:00
CPU.FPSCR.FPRF = cmp_res;
CPU.SetCR(crfd, cmp_res);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void FRSP(u32 frd, u32 frb, u32 rc) override
2013-07-04 16:20:36 +02:00
{
SetHostRoundingMode(CPU.FPSCR.RN);
2013-07-04 16:20:36 +02:00
const double b = CPU.FPR[frb];
if (FPRdouble::IsSNaN(b))
{
CPU.SetFPSCRException(FPSCR_VXSNAN);
CPU.FPSCR.FR = 0;
CPU.FPSCR.FI = 0;
if (CPU.FPSCR.VE)
{
if(rc) CPU.UpdateCR1();
return;
}
}
2013-07-04 16:20:36 +02:00
double b0 = b;
if(CPU.FPSCR.NI)
{
2013-07-04 16:20:36 +02:00
if (((u64&)b0 & DOUBLE_EXP) < 0x3800000000000000ULL) (u64&)b0 &= DOUBLE_SIGN;
}
feclearexcept(FE_ALL_EXCEPT);
2013-07-04 16:20:36 +02:00
const double r = static_cast<float>(b0);
if (FPRdouble::IsNaN(r))
{
CPU.FPSCR.FR = 0;
CPU.FPSCR.FI = 0;
}
else
{
CPU.FPSCR.FR = fabs(r) > fabs(b);
CheckHostFPExceptions();
}
2015-01-17 23:03:02 +01:00
u32 type = PPCdouble(r).GetType();
if (type == FPR_PN && r < ldexp(1.0, -126)) type = FPR_PD;
else if (type == FPR_NN && r > ldexp(-1.0, -126)) type = FPR_ND;
CPU.FPSCR.FPRF = type;
2013-07-04 16:20:36 +02:00
CPU.FPR[frd] = r;
if(rc) CPU.UpdateCR1();
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void FCTIW(u32 frd, u32 frb, u32 rc) override {FCTIW(frd, frb, rc, false);}
2015-07-03 18:07:36 +02:00
void FCTIW(u32 frd, u32 frb, u32 rc, bool truncate)
2013-07-04 16:20:36 +02:00
{
const double b = CPU.FPR[frb];
u32 r;
if (FPRdouble::IsNaN(b) || b < -(double)0x80000000)
{
2013-07-04 16:20:36 +02:00
CPU.SetFPSCRException(FPSCR_VXCVI);
if(FPRdouble::IsSNaN(b)) CPU.SetFPSCRException(FPSCR_VXSNAN);
CPU.FPSCR.FI = 0;
CPU.FPSCR.FR = 0;
if(CPU.FPSCR.VE)
{
if(rc) CPU.UpdateCR1();
return;
}
r = 0x80000000;
}
else if(b > (double)0x7fffffff)
{
2013-07-04 16:20:36 +02:00
CPU.SetFPSCRException(FPSCR_VXCVI);
CPU.FPSCR.FI = 0;
CPU.FPSCR.FR = 0;
if(CPU.FPSCR.VE)
{
if(rc) CPU.UpdateCR1();
return;
}
r = 0x7fffffff;
}
2013-07-04 16:20:36 +02:00
else
{
2013-07-04 16:20:36 +02:00
s32 i = 0;
const u32 rn = truncate ? FPSCR_RN_ZERO : CPU.FPSCR.RN;
switch(rn)
{
2013-07-04 16:20:36 +02:00
case FPSCR_RN_NEAR:
SetHostRoundingMode(FPSCR_RN_NEAR);
2015-01-17 23:04:22 +01:00
i = (s32)nearbyint(b);
break;
2013-07-04 16:20:36 +02:00
case FPSCR_RN_ZERO:
i = (s32)b;
break;
case FPSCR_RN_PINF:
2015-01-17 23:04:22 +01:00
i = (s32)ceil(b);
2013-07-04 16:20:36 +02:00
break;
case FPSCR_RN_MINF:
2015-01-17 23:04:22 +01:00
i = (s32)floor(b);
2013-07-04 16:20:36 +02:00
break;
}
r = (u32)i;
double di = i;
if (di == b)
{
CPU.SetFPSCR_FI(0);
CPU.FPSCR.FR = 0;
}
else
{
2013-07-04 16:20:36 +02:00
CPU.SetFPSCR_FI(1);
CPU.FPSCR.FR = fabs(di) > fabs(b);
}
2013-07-04 16:20:36 +02:00
}
(u64&)CPU.FPR[frd] = r;
2015-01-17 23:00:58 +01:00
if(rc) CPU.UpdateCR1();
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void FCTIWZ(u32 frd, u32 frb, u32 rc) override {FCTIW(frd, frb, rc, true);}
void FDIV(u32 frd, u32 fra, u32 frb, u32 rc) override {FDIV(frd, fra, frb, rc, false);}
2015-07-03 18:07:36 +02:00
void FDIV(u32 frd, u32 fra, u32 frb, u32 rc, bool single)
2013-07-04 16:20:36 +02:00
{
SetHostRoundingMode(CPU.FPSCR.RN);
const double a = CPU.FPR[fra];
const double b = CPU.FPR[frb];
if(FPRdouble::IsSNaN(a) || FPRdouble::IsSNaN(b))
{
CPU.SetFPSCRException(FPSCR_VXSNAN);
CPU.FPSCR.FR = 0;
CPU.FPSCR.FI = 0;
if(CPU.FPSCR.VE)
{
if(rc) CPU.UpdateCR1();
return;
}
}
if(FPRdouble::IsNaN(a))
{
CPU.FPR[frd] = SilenceNaN(a);
}
else if(FPRdouble::IsNaN(b))
{
CPU.FPR[frd] = SilenceNaN(b);
}
else if(a == 0.0 && b == 0.0)
{
CPU.SetFPSCRException(FPSCR_VXZDZ);
CPU.FPSCR.FR = 0;
CPU.FPSCR.FI = 0;
if(CPU.FPSCR.VE)
{
if(rc) CPU.UpdateCR1();
return;
}
CPU.FPR[frd] = FPR_NAN;
}
else if(FPRdouble::IsINF(a) && FPRdouble::IsINF(b))
{
CPU.SetFPSCRException(FPSCR_VXIDI);
CPU.FPSCR.FR = 0;
CPU.FPSCR.FI = 0;
if(CPU.FPSCR.VE)
{
if(rc) CPU.UpdateCR1();
return;
}
CPU.FPR[frd] = FPR_NAN;
}
else
{
if(b == 0.0)
{
CPU.SetFPSCRException(FPSCR_ZX);
CPU.FPSCR.FR = 0;
CPU.FPSCR.FI = 0;
if (CPU.FPSCR.ZE)
{
if(rc) CPU.UpdateCR1();
return;
}
}
feclearexcept(FE_ALL_EXCEPT);
const double res = a / b;
if(single) CPU.FPR[frd] = (float)res;
else CPU.FPR[frd] = res;
CheckHostFPExceptions();
}
2013-07-04 16:20:36 +02:00
CPU.FPSCR.FPRF = CPU.FPR[frd].GetType();
2015-01-17 23:00:58 +01:00
if(rc) CPU.UpdateCR1();
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void FSUB(u32 frd, u32 fra, u32 frb, u32 rc) override {FSUB(frd, fra, frb, rc, false);}
2015-07-03 18:07:36 +02:00
void FSUB(u32 frd, u32 fra, u32 frb, u32 rc, bool single)
2013-07-04 16:20:36 +02:00
{
SetHostRoundingMode(CPU.FPSCR.RN);
const double a = CPU.FPR[fra];
const double b = CPU.FPR[frb];
if(FPRdouble::IsSNaN(a) || FPRdouble::IsSNaN(b))
{
CPU.SetFPSCRException(FPSCR_VXSNAN);
CPU.FPSCR.FR = 0;
CPU.FPSCR.FI = 0;
if(CPU.FPSCR.VE)
{
if(rc) CPU.UpdateCR1();
return;
}
}
if(FPRdouble::IsNaN(a))
{
CPU.FPR[frd] = SilenceNaN(a);
}
else if(FPRdouble::IsNaN(b))
{
CPU.FPR[frd] = SilenceNaN(b);
}
else if(FPRdouble::IsINF(a) && FPRdouble::IsINF(b) && a == b)
{
CPU.SetFPSCRException(FPSCR_VXISI);
CPU.FPSCR.FR = 0;
CPU.FPSCR.FI = 0;
if(CPU.FPSCR.VE)
{
if(rc) CPU.UpdateCR1();
return;
}
CPU.FPR[frd] = FPR_NAN;
}
else
{
feclearexcept(FE_ALL_EXCEPT);
const double res = a - b;
if(single) CPU.FPR[frd] = (float)res;
else CPU.FPR[frd] = res;
CheckHostFPExceptions();
}
CPU.FPSCR.FPRF = CPU.FPR[frd].GetType();
2015-01-17 23:00:58 +01:00
if(rc) CPU.UpdateCR1();
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void FADD(u32 frd, u32 fra, u32 frb, u32 rc) override {FADD(frd, fra, frb, rc, false);}
2015-07-03 18:07:36 +02:00
void FADD(u32 frd, u32 fra, u32 frb, u32 rc, bool single)
2013-07-04 16:20:36 +02:00
{
SetHostRoundingMode(CPU.FPSCR.RN);
const double a = CPU.FPR[fra];
const double b = CPU.FPR[frb];
if(FPRdouble::IsSNaN(a) || FPRdouble::IsSNaN(b))
{
CPU.SetFPSCRException(FPSCR_VXSNAN);
CPU.FPSCR.FR = 0;
CPU.FPSCR.FI = 0;
if(CPU.FPSCR.VE)
{
if(rc) CPU.UpdateCR1();
return;
}
}
if(FPRdouble::IsNaN(a))
{
CPU.FPR[frd] = SilenceNaN(a);
}
else if(FPRdouble::IsNaN(b))
{
CPU.FPR[frd] = SilenceNaN(b);
}
else if(FPRdouble::IsINF(a) && FPRdouble::IsINF(b) && a != b)
{
CPU.SetFPSCRException(FPSCR_VXISI);
CPU.FPSCR.FR = 0;
CPU.FPSCR.FI = 0;
if(CPU.FPSCR.VE)
{
if(rc) CPU.UpdateCR1();
return;
}
CPU.FPR[frd] = FPR_NAN;
}
else
{
feclearexcept(FE_ALL_EXCEPT);
const double res = a + b;
if(single) CPU.FPR[frd] = (float)res;
else CPU.FPR[frd] = res;
CheckHostFPExceptions();
}
CPU.FPSCR.FPRF = CPU.FPR[frd].GetType();
2015-01-17 23:00:58 +01:00
if(rc) CPU.UpdateCR1();
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void FSQRT(u32 frd, u32 frb, u32 rc) override {FSQRT(frd, frb, rc, false);}
2015-07-03 18:07:36 +02:00
void FSQRT(u32 frd, u32 frb, u32 rc, bool single)
2013-07-04 16:20:36 +02:00
{
SetHostRoundingMode(CPU.FPSCR.RN);
const double b = CPU.FPR[frb];
if(FPRdouble::IsSNaN(b))
{
CPU.SetFPSCRException(FPSCR_VXSNAN);
CPU.FPSCR.FR = 0;
CPU.FPSCR.FI = 0;
if(CPU.FPSCR.VE)
{
if(rc) CPU.UpdateCR1();
return;
}
}
if(FPRdouble::IsNaN(b))
{
CPU.FPR[frd] = SilenceNaN(b);
}
else if(b < 0.0)
{
CPU.SetFPSCRException(FPSCR_VXSQRT);
CPU.FPSCR.FR = 0;
CPU.FPSCR.FI = 0;
if(CPU.FPSCR.VE)
{
if(rc) CPU.UpdateCR1();
return;
}
CPU.FPR[frd] = FPR_NAN;
}
else
{
feclearexcept(FE_ALL_EXCEPT);
const double res = sqrt(b);
if(single) CPU.FPR[frd] = (float)res;
else CPU.FPR[frd] = res;
CheckHostFPExceptions();
}
CPU.FPSCR.FPRF = CPU.FPR[frd].GetType();
2015-01-17 23:00:58 +01:00
if(rc) CPU.UpdateCR1();
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void FSEL(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override
2013-07-04 16:20:36 +02:00
{
CPU.FPR[frd] = CPU.FPR[fra] >= 0.0 ? CPU.FPR[frc] : CPU.FPR[frb];
2015-01-17 23:00:58 +01:00
if(rc) CPU.UpdateCR1();
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void FMUL(u32 frd, u32 fra, u32 frc, u32 rc) override {FMUL(frd, fra, frc, rc, false);}
2015-07-03 18:07:36 +02:00
void FMUL(u32 frd, u32 fra, u32 frc, u32 rc, bool single)
2013-07-04 16:20:36 +02:00
{
SetHostRoundingMode(CPU.FPSCR.RN);
const double a = CPU.FPR[fra];
const double c = CPU.FPR[frc];
if(FPRdouble::IsSNaN(a) || FPRdouble::IsSNaN(c))
{
CPU.SetFPSCRException(FPSCR_VXSNAN);
CPU.FPSCR.FR = 0;
CPU.FPSCR.FI = 0;
if(CPU.FPSCR.VE)
{
if(rc) CPU.UpdateCR1();
return;
}
}
if(FPRdouble::IsNaN(a))
{
CPU.FPR[frd] = SilenceNaN(a);
}
else if(FPRdouble::IsNaN(c))
{
CPU.FPR[frd] = SilenceNaN(c);
}
else if((FPRdouble::IsINF(a) && c == 0.0) || (a == 0.0 && FPRdouble::IsINF(c)))
{
CPU.SetFPSCRException(FPSCR_VXIMZ);
CPU.FPSCR.FR = 0;
CPU.FPSCR.FI = 0;
if(CPU.FPSCR.VE)
{
if(rc) CPU.UpdateCR1();
return;
}
CPU.FPR[frd] = FPR_NAN;
}
else
{
feclearexcept(FE_ALL_EXCEPT);
const double res = a * c;
if(single) CPU.FPR[frd] = (float)res;
else CPU.FPR[frd] = res;
CheckHostFPExceptions();
}
CPU.FPSCR.FPRF = CPU.FPR[frd].GetType();
2015-01-17 23:00:58 +01:00
if(rc) CPU.UpdateCR1();
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void FRSQRTE(u32 frd, u32 frb, u32 rc) override
2013-07-04 16:20:36 +02:00
{
SetHostRoundingMode(CPU.FPSCR.RN);
const double b = CPU.FPR[frb];
if(FPRdouble::IsSNaN(b))
{
CPU.SetFPSCRException(FPSCR_VXSNAN);
CPU.FPSCR.FR = 0;
CPU.FPSCR.FI = 0;
if(CPU.FPSCR.VE)
{
if(rc) CPU.UpdateCR1();
return;
}
}
if(FPRdouble::IsNaN(b))
{
CPU.FPR[frd] = SilenceNaN(b);
}
else if(b < 0.0)
{
CPU.SetFPSCRException(FPSCR_VXSQRT);
CPU.FPSCR.FR = 0;
CPU.FPSCR.FI = 0;
if(CPU.FPSCR.VE)
{
if(rc) CPU.UpdateCR1();
return;
}
CPU.FPR[frd] = FPR_NAN;
}
else if(b == 0.0)
{
CPU.SetFPSCRException(FPSCR_ZX);
CPU.FPSCR.FR = 0;
CPU.FPSCR.FI = 0;
if (CPU.FPSCR.ZE)
{
if(rc) CPU.UpdateCR1();
return;
}
CPU.FPR[frd] = 1.0 / b;
}
else
{
feclearexcept(FE_ALL_EXCEPT);
CPU.FPR[frd] = 1.0 / sqrt(b);
CheckHostFPExceptions();
}
CPU.FPSCR.FPRF = CPU.FPR[frd].GetType();
2015-01-17 23:00:58 +01:00
if(rc) CPU.UpdateCR1();
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void FMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override {FMADD(frd, fra, frc, frb, rc, false, true, false);}
void FMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override {FMADD(frd, fra, frc, frb, rc, false, false, false);}
2015-07-03 18:07:36 +02:00
void FMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc, bool neg, bool sub, bool single)
2013-07-04 16:20:36 +02:00
{
SetHostRoundingMode(CPU.FPSCR.RN);
const double a = CPU.FPR[fra];
const double b = CPU.FPR[frb];
const double c = CPU.FPR[frc];
if(FPRdouble::IsSNaN(a) || FPRdouble::IsSNaN(b) || FPRdouble::IsSNaN(c))
{
CPU.SetFPSCRException(FPSCR_VXSNAN);
CPU.FPSCR.FR = 0;
CPU.FPSCR.FI = 0;
if(CPU.FPSCR.VE)
{
if(rc) CPU.UpdateCR1();
return;
}
}
if(FPRdouble::IsNaN(a))
{
CPU.FPR[frd] = SilenceNaN(a);
}
else if(FPRdouble::IsNaN(b))
{
CPU.FPR[frd] = SilenceNaN(b);
}
else if(FPRdouble::IsNaN(c))
{
CPU.FPR[frd] = SilenceNaN(c);
}
else if((FPRdouble::IsINF(a) && c == 0.0) || (a == 0.0 && FPRdouble::IsINF(c)))
{
CPU.SetFPSCRException(FPSCR_VXIMZ);
CPU.FPSCR.FR = 0;
CPU.FPSCR.FI = 0;
if(CPU.FPSCR.VE)
{
if(rc) CPU.UpdateCR1();
return;
}
CPU.FPR[frd] = FPR_NAN;
}
else
{
const double res = fma(a, c, sub ? -b : b);
if(FPRdouble::IsNaN(res))
{
CPU.SetFPSCRException(FPSCR_VXISI);
CPU.FPSCR.FR = 0;
CPU.FPSCR.FI = 0;
if(CPU.FPSCR.VE)
{
if(rc) CPU.UpdateCR1();
return;
}
CPU.FPR[frd] = FPR_NAN;
}
else
{
feclearexcept(FE_ALL_EXCEPT);
if(single) CPU.FPR[frd] = (float)(neg ? -res : res);
else CPU.FPR[frd] = (neg ? -res : res);
CheckHostFPExceptions();
}
}
CPU.FPSCR.FPRF = CPU.FPR[frd].GetType();
2015-01-17 23:00:58 +01:00
if(rc) CPU.UpdateCR1();
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void FNMSUB(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override {FMADD(frd, fra, frc, frb, rc, true, true, false);}
void FNMADD(u32 frd, u32 fra, u32 frc, u32 frb, u32 rc) override {FMADD(frd, fra, frc, frb, rc, true, false, false);}
void FCMPO(u32 crfd, u32 fra, u32 frb) override
2013-07-04 16:20:36 +02:00
{
int cmp_res = FPRdouble::Cmp(CPU.FPR[fra], CPU.FPR[frb]);
if(cmp_res == CR_SO)
{
2013-07-04 16:20:36 +02:00
if(FPRdouble::IsSNaN(CPU.FPR[fra]) || FPRdouble::IsSNaN(CPU.FPR[frb]))
{
CPU.SetFPSCRException(FPSCR_VXSNAN);
if(!CPU.FPSCR.VE) CPU.SetFPSCRException(FPSCR_VXVC);
}
else
2013-07-04 16:20:36 +02:00
{
CPU.SetFPSCRException(FPSCR_VXVC);
}
CPU.FPSCR.FX = 1;
}
2013-07-04 16:20:36 +02:00
CPU.FPSCR.FPRF = cmp_res;
CPU.SetCR(crfd, cmp_res);
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void FNEG(u32 frd, u32 frb, u32 rc) override
2013-07-04 16:20:36 +02:00
{
CPU.FPR[frd] = -CPU.FPR[frb];
2015-01-17 23:00:58 +01:00
if(rc) CPU.UpdateCR1();
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void FMR(u32 frd, u32 frb, u32 rc) override
2013-07-04 16:20:36 +02:00
{
CPU.FPR[frd] = CPU.FPR[frb];
2015-01-17 23:00:58 +01:00
if(rc) CPU.UpdateCR1();
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void FNABS(u32 frd, u32 frb, u32 rc) override
2013-07-04 16:20:36 +02:00
{
CPU.FPR[frd] = -fabs(CPU.FPR[frb]);
2015-01-17 23:00:58 +01:00
if(rc) CPU.UpdateCR1();
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void FABS(u32 frd, u32 frb, u32 rc) override
2013-07-04 16:20:36 +02:00
{
CPU.FPR[frd] = fabs(CPU.FPR[frb]);
2015-01-17 23:00:58 +01:00
if(rc) CPU.UpdateCR1();
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void FCTID(u32 frd, u32 frb, u32 rc) override {FCTID(frd, frb, rc, false);}
2015-07-03 18:07:36 +02:00
void FCTID(u32 frd, u32 frb, u32 rc, bool truncate)
2013-07-04 16:20:36 +02:00
{
const double b = CPU.FPR[frb];
u64 r;
if (FPRdouble::IsNaN(b) || b < -(double)0x8000000000000000)
{
2013-07-04 16:20:36 +02:00
CPU.SetFPSCRException(FPSCR_VXCVI);
if(FPRdouble::IsSNaN(b)) CPU.SetFPSCRException(FPSCR_VXSNAN);
CPU.FPSCR.FI = 0;
CPU.FPSCR.FR = 0;
if(CPU.FPSCR.VE)
{
if(rc) CPU.UpdateCR1();
return;
}
r = 0x8000000000000000;
}
else if(b >= (double)0x8000000000000000)
{
2013-07-04 16:20:36 +02:00
CPU.SetFPSCRException(FPSCR_VXCVI);
CPU.FPSCR.FI = 0;
CPU.FPSCR.FR = 0;
if(CPU.FPSCR.VE)
{
if(rc) CPU.UpdateCR1();
return;
}
r = 0x7fffffffffffffff;
}
2013-07-04 16:20:36 +02:00
else
{
2013-07-04 16:20:36 +02:00
s64 i = 0;
const u32 rn = truncate ? FPSCR_RN_ZERO : CPU.FPSCR.RN;
switch(rn)
{
2013-07-04 16:20:36 +02:00
case FPSCR_RN_NEAR:
SetHostRoundingMode(FPSCR_RN_NEAR);
2015-01-17 23:04:22 +01:00
i = (s64)nearbyint(b);
break;
2013-07-04 16:20:36 +02:00
case FPSCR_RN_ZERO:
i = (s64)b;
break;
case FPSCR_RN_PINF:
2015-01-17 23:04:22 +01:00
i = (s64)ceil(b);
2013-07-04 16:20:36 +02:00
break;
case FPSCR_RN_MINF:
2015-01-17 23:04:22 +01:00
i = (s64)floor(b);
2013-07-04 16:20:36 +02:00
break;
}
r = (u64)i;
2014-08-30 19:51:00 +02:00
double di = (double)i;
2013-07-04 16:20:36 +02:00
if (di == b)
{
CPU.SetFPSCR_FI(0);
CPU.FPSCR.FR = 0;
}
else
{
2013-07-04 16:20:36 +02:00
CPU.SetFPSCR_FI(1);
CPU.FPSCR.FR = fabs(di) > fabs(b);
}
2013-07-04 16:20:36 +02:00
}
(u64&)CPU.FPR[frd] = r;
2015-01-17 23:00:58 +01:00
if(rc) CPU.UpdateCR1();
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void FCTIDZ(u32 frd, u32 frb, u32 rc) override {FCTID(frd, frb, rc, true);}
void FCFID(u32 frd, u32 frb, u32 rc) override
2013-07-04 16:20:36 +02:00
{
s64 bi = (s64&)CPU.FPR[frb];
double bf = (double)bi;
s64 bfi = (s64)bf;
if(bi == bfi)
{
CPU.SetFPSCR_FI(0);
CPU.FPSCR.FR = 0;
}
else
{
CPU.SetFPSCR_FI(1);
2015-07-26 22:24:37 +02:00
CPU.FPSCR.FR = std::abs(bfi) > std::abs(bi);
}
CPU.FPR[frd] = bf;
CPU.FPSCR.FPRF = CPU.FPR[frd].GetType();
2015-01-17 23:00:58 +01:00
if(rc) CPU.UpdateCR1();
2013-07-04 16:20:36 +02:00
}
2016-01-06 11:47:06 +01:00
void UNK(const u32 code, const u32 opcode, const u32 gcode) override
{
throw EXCEPTION("Unknown/Illegal opcode! (0x%08x : 0x%x : 0x%x)", code, opcode, gcode);
}
};