2012-11-01 15:19:01 +00:00
|
|
|
// Copyright (c) 2012- PPSSPP Project.
|
|
|
|
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
2012-11-04 22:01:49 +00:00
|
|
|
// the Free Software Foundation, version 2.0 or later versions.
|
2012-11-01 15:19:01 +00:00
|
|
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
|
|
|
|
// Official git repository and contact information can be found at
|
|
|
|
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
|
|
|
|
2013-04-13 19:24:07 +00:00
|
|
|
// TODO: Test and maybe fix: https://code.google.com/p/jpcsp/source/detail?r=3082#
|
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
#include <cmath>
|
|
|
|
#include <limits>
|
2013-09-17 04:48:14 +00:00
|
|
|
#include <algorithm>
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2014-03-15 09:45:39 +00:00
|
|
|
#include "math/math_util.h"
|
|
|
|
|
|
|
|
#include "Core/Core.h"
|
|
|
|
#include "Core/Reporting.h"
|
|
|
|
#include "Core/MemMap.h"
|
|
|
|
|
|
|
|
#include "Core/MIPS/MIPS.h"
|
|
|
|
#include "Core/MIPS/MIPSInt.h"
|
|
|
|
#include "Core/MIPS/MIPSTables.h"
|
|
|
|
#include "Core/MIPS/MIPSVFPUUtils.h"
|
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
#define R(i) (currentMIPS->r[i])
|
2013-11-27 21:45:17 +00:00
|
|
|
#define V(i) (currentMIPS->v[voffset[i]])
|
|
|
|
#define VI(i) (currentMIPS->vi[voffset[i]])
|
2013-06-11 19:36:59 +00:00
|
|
|
#define FI(i) (currentMIPS->fi[i])
|
|
|
|
#define FsI(i) (currentMIPS->fs[i])
|
2012-11-01 15:19:01 +00:00
|
|
|
#define PC (currentMIPS->pc)
|
|
|
|
|
2014-03-03 16:16:53 +00:00
|
|
|
#define _RS ((op>>21) & 0x1F)
|
|
|
|
#define _RT ((op>>16) & 0x1F)
|
2012-11-01 15:19:01 +00:00
|
|
|
#define _RD ((op>>11) & 0x1F)
|
|
|
|
#define _FS ((op>>11) & 0x1F)
|
2014-03-03 16:16:53 +00:00
|
|
|
#define _FT ((op>>16) & 0x1F)
|
2012-11-01 15:19:01 +00:00
|
|
|
#define _FD ((op>>6 ) & 0x1F)
|
|
|
|
#define _POS ((op>>6 ) & 0x1F)
|
2014-03-03 16:16:53 +00:00
|
|
|
#define _SIZE ((op>>11) & 0x1F)
|
2012-11-01 15:19:01 +00:00
|
|
|
|
|
|
|
#define HI currentMIPS->hi
|
|
|
|
#define LO currentMIPS->lo
|
|
|
|
|
|
|
|
#ifndef M_LOG2E
|
2012-11-11 21:38:19 +00:00
|
|
|
#define M_E 2.71828182845904523536f
|
|
|
|
#define M_LOG2E 1.44269504088896340736f
|
|
|
|
#define M_LOG10E 0.434294481903251827651f
|
|
|
|
#define M_LN2 0.693147180559945309417f
|
|
|
|
#define M_LN10 2.30258509299404568402f
|
2013-04-19 07:23:02 +00:00
|
|
|
#undef M_PI
|
2012-11-11 21:38:19 +00:00
|
|
|
#define M_PI 3.14159265358979323846f
|
2014-06-15 09:03:00 +00:00
|
|
|
#ifndef M_PI_2
|
2012-11-11 21:38:19 +00:00
|
|
|
#define M_PI_2 1.57079632679489661923f
|
2014-06-15 09:03:00 +00:00
|
|
|
#endif
|
2012-11-11 21:38:19 +00:00
|
|
|
#define M_PI_4 0.785398163397448309616f
|
|
|
|
#define M_1_PI 0.318309886183790671538f
|
|
|
|
#define M_2_PI 0.636619772367581343076f
|
|
|
|
#define M_2_SQRTPI 1.12837916709551257390f
|
|
|
|
#define M_SQRT2 1.41421356237309504880f
|
|
|
|
#define M_SQRT1_2 0.707106781186547524401f
|
2012-11-01 15:19:01 +00:00
|
|
|
#endif
|
|
|
|
|
2014-09-02 05:33:01 +00:00
|
|
|
union FloatBits {
|
|
|
|
float f[4];
|
|
|
|
u32 u[4];
|
|
|
|
int i[4];
|
|
|
|
};
|
|
|
|
|
2013-02-24 22:39:13 +00:00
|
|
|
// Preserves NaN in first param, takes sign of equal second param.
|
|
|
|
// Technically, std::max may do this but it's undefined.
|
|
|
|
inline float nanmax(float f, float cst)
|
|
|
|
{
|
|
|
|
return f <= cst ? cst : f;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Preserves NaN in first param, takes sign of equal second param.
|
|
|
|
inline float nanmin(float f, float cst)
|
|
|
|
{
|
|
|
|
return f >= cst ? cst : f;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Preserves NaN in first param, takes sign of equal value in others.
|
|
|
|
inline float nanclamp(float f, float lower, float upper)
|
|
|
|
{
|
|
|
|
return nanmin(nanmax(f, lower), upper);
|
|
|
|
}
|
|
|
|
|
2013-01-29 01:15:23 +00:00
|
|
|
|
2013-11-27 21:45:17 +00:00
|
|
|
void ApplyPrefixST(float *r, u32 data, VectorSize size)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
2013-06-05 17:08:58 +00:00
|
|
|
// Possible optimization shortcut:
|
|
|
|
if (data == 0xe4)
|
|
|
|
return;
|
2012-11-01 15:19:01 +00:00
|
|
|
|
|
|
|
int n = GetNumVectorElements(size);
|
|
|
|
float origV[4];
|
|
|
|
static const float constantArray[8] = {0.f, 1.f, 2.f, 0.5f, 3.f, 1.f/3.f, 0.25f, 1.f/6.f};
|
|
|
|
|
|
|
|
for (int i = 0; i < n; i++)
|
|
|
|
{
|
2013-11-27 21:45:17 +00:00
|
|
|
origV[i] = r[i];
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < n; i++)
|
|
|
|
{
|
|
|
|
int regnum = (data >> (i*2)) & 3;
|
|
|
|
int abs = (data >> (8+i)) & 1;
|
|
|
|
int negate = (data >> (16+i)) & 1;
|
|
|
|
int constants = (data >> (12+i)) & 1;
|
|
|
|
|
|
|
|
if (!constants)
|
|
|
|
{
|
2013-02-16 05:49:20 +00:00
|
|
|
// Prefix may say "z, z, z, z" but if this is a pair, we force to x.
|
|
|
|
// TODO: But some ops seem to use const 0 instead?
|
2013-07-31 08:33:44 +00:00
|
|
|
if (regnum >= n) {
|
2014-03-15 09:45:39 +00:00
|
|
|
ERROR_LOG_REPORT(CPU, "Invalid VFPU swizzle: %08x: %i / %d at PC = %08x (%s)", data, regnum, n, currentMIPS->pc, MIPSDisasmAt(currentMIPS->pc));
|
2013-07-31 08:33:44 +00:00
|
|
|
//for (int i = 0; i < 12; i++) {
|
|
|
|
// ERROR_LOG(CPU, " vfpuCtrl[%i] = %08x", i, currentMIPS->vfpuCtrl[i]);
|
|
|
|
//}
|
2013-02-16 05:49:20 +00:00
|
|
|
regnum = 0;
|
2013-02-16 10:04:04 +00:00
|
|
|
}
|
2013-02-16 05:49:20 +00:00
|
|
|
|
2013-11-27 21:45:17 +00:00
|
|
|
r[i] = origV[regnum];
|
2012-11-01 15:19:01 +00:00
|
|
|
if (abs)
|
2019-03-30 18:19:08 +00:00
|
|
|
((u32 *)r)[i] = ((u32 *)r)[i] & 0x7FFFFFFF;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-11-27 21:45:17 +00:00
|
|
|
r[i] = constantArray[regnum + (abs<<2)];
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (negate)
|
2019-03-30 18:19:08 +00:00
|
|
|
((u32 *)r)[i] = ((u32 *)r)[i] ^ 0x80000000;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-17 14:06:10 +00:00
|
|
|
inline void ApplySwizzleS(float *v, VectorSize size)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
|
|
|
ApplyPrefixST(v, currentMIPS->vfpuCtrl[VFPU_CTRL_SPREFIX], size);
|
|
|
|
}
|
|
|
|
|
2012-11-17 14:06:10 +00:00
|
|
|
inline void ApplySwizzleT(float *v, VectorSize size)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
|
|
|
ApplyPrefixST(v, currentMIPS->vfpuCtrl[VFPU_CTRL_TPREFIX], size);
|
|
|
|
}
|
|
|
|
|
2012-11-11 21:38:19 +00:00
|
|
|
void ApplyPrefixD(float *v, VectorSize size, bool onlyWriteMask = false)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
2012-11-17 14:06:10 +00:00
|
|
|
u32 data = currentMIPS->vfpuCtrl[VFPU_CTRL_DPREFIX];
|
2013-02-18 06:46:12 +00:00
|
|
|
if (!data || onlyWriteMask)
|
2012-11-17 14:06:10 +00:00
|
|
|
return;
|
2012-11-01 15:19:01 +00:00
|
|
|
int n = GetNumVectorElements(size);
|
|
|
|
for (int i = 0; i < n; i++)
|
|
|
|
{
|
2013-02-18 06:46:12 +00:00
|
|
|
int sat = (data >> (i * 2)) & 3;
|
|
|
|
if (sat == 1)
|
2016-05-15 20:10:04 +00:00
|
|
|
v[i] = vfpu_clamp(v[i], 0.0f, 1.0f);
|
2013-02-18 06:46:12 +00:00
|
|
|
else if (sat == 3)
|
2016-05-15 20:10:04 +00:00
|
|
|
v[i] = vfpu_clamp(v[i], -1.0f, 1.0f);
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void EatPrefixes()
|
|
|
|
{
|
2012-11-17 14:06:10 +00:00
|
|
|
currentMIPS->vfpuCtrl[VFPU_CTRL_SPREFIX] = 0xe4; // passthru
|
|
|
|
currentMIPS->vfpuCtrl[VFPU_CTRL_TPREFIX] = 0xe4; // passthru
|
2012-11-01 15:19:01 +00:00
|
|
|
currentMIPS->vfpuCtrl[VFPU_CTRL_DPREFIX] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace MIPSInt
|
|
|
|
{
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_VPFX(MIPSOpcode op)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
2019-03-30 18:57:11 +00:00
|
|
|
int data = op & 0x000FFFFF;
|
2012-11-01 15:19:01 +00:00
|
|
|
int regnum = (op >> 24) & 3;
|
2019-03-11 03:28:01 +00:00
|
|
|
if (regnum == VFPU_CTRL_DPREFIX)
|
|
|
|
data &= 0x00000FFF;
|
2012-11-01 15:19:01 +00:00
|
|
|
currentMIPS->vfpuCtrl[VFPU_CTRL_SPREFIX + regnum] = data;
|
|
|
|
PC += 4;
|
|
|
|
}
|
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_SVQ(MIPSOpcode op)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
|
|
|
int imm = (signed short)(op&0xFFFC);
|
|
|
|
int rs = _RS;
|
|
|
|
int vt = (((op >> 16) & 0x1f)) | ((op&1) << 5);
|
|
|
|
|
|
|
|
u32 addr = R(rs) + imm;
|
|
|
|
|
|
|
|
switch (op >> 26)
|
|
|
|
{
|
|
|
|
case 53: //lvl.q/lvr.q
|
2012-11-18 22:34:37 +00:00
|
|
|
{
|
2013-08-11 13:31:54 +00:00
|
|
|
if (addr & 0x3)
|
2012-11-18 22:34:37 +00:00
|
|
|
{
|
2013-08-11 13:31:54 +00:00
|
|
|
_dbg_assert_msg_(CPU, 0, "Misaligned lvX.q");
|
2012-11-18 22:34:37 +00:00
|
|
|
}
|
|
|
|
float d[4];
|
|
|
|
ReadVector(d, V_Quad, vt);
|
|
|
|
int offset = (addr >> 2) & 3;
|
2013-08-11 13:31:54 +00:00
|
|
|
if ((op & 2) == 0)
|
|
|
|
{
|
|
|
|
// It's an LVL
|
|
|
|
for (int i = 0; i < offset + 1; i++)
|
|
|
|
{
|
|
|
|
d[3 - i] = Memory::Read_Float(addr - 4 * i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2012-11-18 22:34:37 +00:00
|
|
|
{
|
2013-08-11 13:31:54 +00:00
|
|
|
// It's an LVR
|
|
|
|
for (int i = 0; i < (3 - offset) + 1; i++)
|
|
|
|
{
|
|
|
|
d[i] = Memory::Read_Float(addr + 4 * i);
|
|
|
|
}
|
2012-11-18 22:34:37 +00:00
|
|
|
}
|
|
|
|
WriteVector(d, V_Quad, vt);
|
|
|
|
}
|
|
|
|
break;
|
2012-11-01 15:19:01 +00:00
|
|
|
|
|
|
|
case 54: //lv.q
|
2012-11-18 22:34:37 +00:00
|
|
|
if (addr & 0xF)
|
|
|
|
{
|
|
|
|
_dbg_assert_msg_(CPU, 0, "Misaligned lv.q");
|
|
|
|
}
|
2013-07-30 14:40:35 +00:00
|
|
|
#ifndef COMMON_BIG_ENDIAN
|
2012-11-01 15:19:01 +00:00
|
|
|
WriteVector((const float*)Memory::GetPointer(addr), V_Quad, vt);
|
2013-07-30 14:40:35 +00:00
|
|
|
#else
|
|
|
|
float lvqd[4];
|
|
|
|
|
|
|
|
lvqd[0] = Memory::Read_Float(addr);
|
|
|
|
lvqd[1] = Memory::Read_Float(addr + 4);
|
|
|
|
lvqd[2] = Memory::Read_Float(addr + 8);
|
|
|
|
lvqd[3] = Memory::Read_Float(addr + 12);
|
|
|
|
|
|
|
|
WriteVector(lvqd, V_Quad, vt);
|
|
|
|
#endif
|
2012-11-01 15:19:01 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 61: // svl.q/svr.q
|
2012-11-18 22:34:37 +00:00
|
|
|
{
|
2013-08-11 13:31:54 +00:00
|
|
|
if (addr & 0x3)
|
2012-11-18 22:34:37 +00:00
|
|
|
{
|
2013-08-11 13:31:54 +00:00
|
|
|
_dbg_assert_msg_(CPU, 0, "Misaligned svX.q");
|
2012-11-18 22:34:37 +00:00
|
|
|
}
|
|
|
|
float d[4];
|
|
|
|
ReadVector(d, V_Quad, vt);
|
|
|
|
int offset = (addr >> 2) & 3;
|
2013-08-11 13:31:54 +00:00
|
|
|
if ((op&2) == 0)
|
2012-11-18 22:34:37 +00:00
|
|
|
{
|
2013-08-11 13:31:54 +00:00
|
|
|
// It's an SVL
|
|
|
|
for (int i = 0; i < offset + 1; i++)
|
|
|
|
{
|
|
|
|
Memory::Write_Float(d[3 - i], addr - i * 4);
|
|
|
|
}
|
2012-11-18 22:34:37 +00:00
|
|
|
}
|
2013-08-11 13:31:54 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// It's an SVR
|
|
|
|
for (int i = 0; i < (3 - offset) + 1; i++)
|
|
|
|
{
|
|
|
|
Memory::Write_Float(d[i], addr + 4 * i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2012-11-18 22:34:37 +00:00
|
|
|
}
|
2012-11-01 15:19:01 +00:00
|
|
|
|
|
|
|
case 62: //sv.q
|
2012-11-18 22:34:37 +00:00
|
|
|
if (addr & 0xF)
|
|
|
|
{
|
|
|
|
_dbg_assert_msg_(CPU, 0, "Misaligned sv.q");
|
|
|
|
}
|
2013-07-30 14:40:35 +00:00
|
|
|
#ifndef COMMON_BIG_ENDIAN
|
2015-01-19 16:51:30 +00:00
|
|
|
ReadVector(reinterpret_cast<float *>(Memory::GetPointer(addr)), V_Quad, vt);
|
2013-07-30 14:40:35 +00:00
|
|
|
#else
|
|
|
|
float svqd[4];
|
|
|
|
ReadVector(svqd, V_Quad, vt);
|
|
|
|
|
|
|
|
Memory::Write_Float(svqd[0], addr);
|
|
|
|
Memory::Write_Float(svqd[1], addr + 4);
|
|
|
|
Memory::Write_Float(svqd[2], addr + 8);
|
|
|
|
Memory::Write_Float(svqd[3], addr + 12);
|
|
|
|
#endif
|
2012-11-01 15:19:01 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
_dbg_assert_msg_(CPU,0,"Trying to interpret VQ instruction that can't be interpreted");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
PC += 4;
|
|
|
|
}
|
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_VMatrixInit(MIPSOpcode op)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
|
|
|
static const float idt[16] =
|
|
|
|
{
|
|
|
|
1,0,0,0,
|
|
|
|
0,1,0,0,
|
|
|
|
0,0,1,0,
|
|
|
|
0,0,0,1,
|
|
|
|
};
|
|
|
|
static const float zero[16] =
|
|
|
|
{
|
|
|
|
0,0,0,0,
|
|
|
|
0,0,0,0,
|
|
|
|
0,0,0,0,
|
|
|
|
0,0,0,0,
|
|
|
|
};
|
|
|
|
static const float one[16] =
|
|
|
|
{
|
|
|
|
1,1,1,1,
|
|
|
|
1,1,1,1,
|
|
|
|
1,1,1,1,
|
|
|
|
1,1,1,1,
|
|
|
|
};
|
|
|
|
int vd = _VD;
|
|
|
|
MatrixSize sz = GetMtxSize(op);
|
|
|
|
const float *m;
|
|
|
|
|
|
|
|
switch ((op >> 16) & 0xF)
|
|
|
|
{
|
2012-11-11 21:38:19 +00:00
|
|
|
case 3: m=idt; break; //identity // vmidt
|
2013-07-05 01:16:57 +00:00
|
|
|
case 6: m=zero; break; // vmzero
|
|
|
|
case 7: m=one; break; // vmone
|
2012-11-01 15:19:01 +00:00
|
|
|
default:
|
|
|
|
_dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted");
|
2013-08-11 23:28:20 +00:00
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
2012-11-01 15:19:01 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
WriteMatrix(m, sz, vd);
|
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_VVectorInit(MIPSOpcode op)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
|
|
|
int vd = _VD;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
2019-02-24 20:18:11 +00:00
|
|
|
float d[4];
|
|
|
|
|
2019-03-31 17:33:26 +00:00
|
|
|
VFPUConst constant = VFPUConst::ZERO;
|
2019-02-24 20:18:11 +00:00
|
|
|
switch ((op >> 16) & 0xF) {
|
2019-03-31 17:33:26 +00:00
|
|
|
case 6: constant = VFPUConst::ZERO; break; //vzero
|
|
|
|
case 7: constant = VFPUConst::ONE; break; //vone
|
2012-11-01 15:19:01 +00:00
|
|
|
default:
|
2019-02-24 20:18:11 +00:00
|
|
|
_dbg_assert_msg_(CPU, 0, "Trying to interpret instruction that can't be interpreted");
|
2013-08-11 23:28:20 +00:00
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
2012-11-01 15:19:01 +00:00
|
|
|
return;
|
|
|
|
}
|
2019-02-24 20:18:11 +00:00
|
|
|
|
|
|
|
// The S prefix generates constants, but negate is still respected.
|
|
|
|
u32 sprefixRemove = VFPU_ANY_SWIZZLE();
|
2019-03-31 17:33:26 +00:00
|
|
|
u32 sprefixAdd = VFPU_MAKE_CONSTANTS(constant, constant, constant, constant);
|
2019-02-24 20:18:11 +00:00
|
|
|
ApplyPrefixST(d, VFPURewritePrefix(VFPU_CTRL_SPREFIX, sprefixRemove, sprefixAdd), sz);
|
|
|
|
|
|
|
|
ApplyPrefixD(d, sz);
|
|
|
|
WriteVector(d, sz, vd);
|
2012-11-01 15:19:01 +00:00
|
|
|
|
|
|
|
EatPrefixes();
|
|
|
|
PC += 4;
|
|
|
|
}
|
|
|
|
|
2019-03-02 20:41:58 +00:00
|
|
|
void Int_Viim(MIPSOpcode op) {
|
2012-11-01 15:19:01 +00:00
|
|
|
int vt = _VT;
|
2012-11-11 15:46:25 +00:00
|
|
|
s32 imm = (s16)(op&0xFFFF);
|
|
|
|
u16 uimm16 = (op&0xFFFF);
|
2012-11-11 21:38:19 +00:00
|
|
|
float f[1];
|
2012-11-01 15:19:01 +00:00
|
|
|
int type = (op >> 23) & 7;
|
2019-03-02 20:41:58 +00:00
|
|
|
if (type == 6) {
|
2012-11-11 21:38:19 +00:00
|
|
|
f[0] = (float)imm; // viim
|
2019-03-02 20:41:58 +00:00
|
|
|
} else if (type == 7) {
|
2012-11-11 21:38:19 +00:00
|
|
|
f[0] = Float16ToFloat32((u16)uimm16); // vfim
|
2019-03-02 20:41:58 +00:00
|
|
|
} else {
|
2012-11-01 15:19:01 +00:00
|
|
|
_dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted");
|
2015-04-08 18:31:12 +00:00
|
|
|
f[0] = 0;
|
|
|
|
}
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2012-11-11 21:38:19 +00:00
|
|
|
ApplyPrefixD(f, V_Single);
|
2019-03-02 20:41:58 +00:00
|
|
|
WriteVector(f, V_Single, vt);
|
2012-11-01 15:19:01 +00:00
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
|
|
|
|
2019-02-24 20:18:11 +00:00
|
|
|
void Int_Vidt(MIPSOpcode op) {
|
2012-11-01 15:19:01 +00:00
|
|
|
int vd = _VD;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
|
|
|
float f[4];
|
2019-02-24 20:18:11 +00:00
|
|
|
|
|
|
|
// The S prefix generates constants, but negate is still respected.
|
|
|
|
int offmask = sz == V_Quad || sz == V_Triple ? 3 : 1;
|
|
|
|
int off = vd & offmask;
|
2019-03-31 17:33:26 +00:00
|
|
|
// If it's a pair, the identity starts in a different position.
|
|
|
|
VFPUConst constX = off == (0 & offmask) ? VFPUConst::ONE : VFPUConst::ZERO;
|
|
|
|
VFPUConst constY = off == (1 & offmask) ? VFPUConst::ONE : VFPUConst::ZERO;
|
|
|
|
VFPUConst constZ = off == (2 & offmask) ? VFPUConst::ONE : VFPUConst::ZERO;
|
|
|
|
VFPUConst constW = off == (3 & offmask) ? VFPUConst::ONE : VFPUConst::ZERO;
|
|
|
|
|
2019-02-24 20:18:11 +00:00
|
|
|
u32 sprefixRemove = VFPU_ANY_SWIZZLE();
|
2019-03-31 17:33:26 +00:00
|
|
|
u32 sprefixAdd = VFPU_MAKE_CONSTANTS(constX, constY, constZ, constW);
|
2019-02-24 20:18:11 +00:00
|
|
|
ApplyPrefixST(f, VFPURewritePrefix(VFPU_CTRL_SPREFIX, sprefixRemove, sprefixAdd), sz);
|
|
|
|
|
2012-11-11 21:38:19 +00:00
|
|
|
ApplyPrefixD(f, sz);
|
2012-11-01 15:19:01 +00:00
|
|
|
WriteVector(f, sz, vd);
|
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
2019-02-24 20:18:11 +00:00
|
|
|
|
2012-11-22 17:12:56 +00:00
|
|
|
// The test really needs some work.
|
2019-03-10 23:39:08 +00:00
|
|
|
void Int_Vmmul(MIPSOpcode op) {
|
|
|
|
float s[16]{}, t[16]{}, d[16];
|
2012-11-01 15:19:01 +00:00
|
|
|
|
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
int vt = _VT;
|
|
|
|
MatrixSize sz = GetMtxSize(op);
|
|
|
|
int n = GetMatrixSide(sz);
|
|
|
|
|
|
|
|
ReadMatrix(s, sz, vs);
|
|
|
|
ReadMatrix(t, sz, vt);
|
|
|
|
|
2019-03-10 23:39:08 +00:00
|
|
|
for (int a = 0; a < n; a++) {
|
|
|
|
for (int b = 0; b < n; b++) {
|
2012-11-01 15:19:01 +00:00
|
|
|
float sum = 0.0f;
|
2019-03-10 23:39:08 +00:00
|
|
|
if (a == n - 1 && b == n - 1) {
|
|
|
|
// S and T prefixes work on the final (or maybe first, in reverse?) dot.
|
|
|
|
ApplySwizzleS(&s[b * 4], V_Quad);
|
|
|
|
ApplySwizzleT(&t[a * 4], V_Quad);
|
|
|
|
for (int c = 0; c < 4; c++) {
|
|
|
|
sum += s[b * 4 + c] * t[a * 4 + c];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (int c = 0; c < n; c++) {
|
|
|
|
sum += s[b * 4 + c] * t[a * 4 + c];
|
|
|
|
}
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
2019-03-10 23:39:08 +00:00
|
|
|
d[a * 4 + b] = sum;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-10 23:39:08 +00:00
|
|
|
// The D prefix applies ONLY to the final element, but sat does work.
|
|
|
|
u32 lastmask = (currentMIPS->vfpuCtrl[VFPU_CTRL_DPREFIX] & (1 << 8)) << (n - 1);
|
|
|
|
u32 lastsat = (currentMIPS->vfpuCtrl[VFPU_CTRL_DPREFIX] & 3) << (n + n - 2);
|
|
|
|
currentMIPS->vfpuCtrl[VFPU_CTRL_DPREFIX] = lastmask | lastsat;
|
|
|
|
ApplyPrefixD(&d[4 * (n - 1)], V_Quad, false);
|
2012-11-01 15:19:01 +00:00
|
|
|
WriteMatrix(d, sz, vd);
|
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
|
|
|
|
2019-03-10 23:39:08 +00:00
|
|
|
void Int_Vmscl(MIPSOpcode op) {
|
|
|
|
float s[16]{}, t[4]{}, d[16];
|
2012-11-18 22:34:37 +00:00
|
|
|
|
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
int vt = _VT;
|
|
|
|
MatrixSize sz = GetMtxSize(op);
|
|
|
|
int n = GetMatrixSide(sz);
|
|
|
|
|
|
|
|
ReadMatrix(s, sz, vs);
|
|
|
|
ReadVector(t, V_Single, vt);
|
|
|
|
|
2019-03-10 23:39:08 +00:00
|
|
|
for (int a = 0; a < n - 1; a++) {
|
|
|
|
for (int b = 0; b < n; b++) {
|
|
|
|
d[a * 4 + b] = s[a * 4 + b] * t[0];
|
2012-11-18 22:34:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-10 23:39:08 +00:00
|
|
|
// S prefix applies to the last row.
|
|
|
|
ApplySwizzleS(&s[(n - 1) * 4], V_Quad);
|
|
|
|
// T prefix applies only for the last row, and is used per element.
|
|
|
|
// This is like vscl, but instead of zzzz it uses xxxx.
|
|
|
|
u32 tprefixRemove = VFPU_ANY_SWIZZLE();
|
|
|
|
u32 tprefixAdd = VFPU_SWIZZLE(0, 0, 0, 0);
|
|
|
|
ApplyPrefixST(t, VFPURewritePrefix(VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), V_Quad);
|
|
|
|
|
|
|
|
for (int b = 0; b < n; b++) {
|
|
|
|
d[(n - 1) * 4 + b] = s[(n - 1) * 4 + b] * t[b];
|
|
|
|
}
|
|
|
|
|
|
|
|
// The D prefix is applied to the last row.
|
|
|
|
ApplyPrefixD(&d[(n - 1) * 4], V_Quad);
|
2012-11-18 22:34:37 +00:00
|
|
|
WriteMatrix(d, sz, vd);
|
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2019-03-10 23:39:08 +00:00
|
|
|
void Int_Vmmov(MIPSOpcode op) {
|
|
|
|
float s[16]{};
|
2012-11-01 15:19:01 +00:00
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
MatrixSize sz = GetMtxSize(op);
|
|
|
|
ReadMatrix(s, sz, vs);
|
2019-03-10 23:39:08 +00:00
|
|
|
// S and D prefixes are applied to the last row.
|
|
|
|
int off = GetMatrixSide(sz) - 1;
|
|
|
|
ApplySwizzleS(&s[off * 4], V_Quad);
|
|
|
|
ApplyPrefixD(&s[off * 4], V_Quad);
|
2012-11-18 22:34:37 +00:00
|
|
|
WriteMatrix(s, sz, vd);
|
2012-11-01 15:19:01 +00:00
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_Vflush(MIPSOpcode op)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
2019-03-16 16:28:54 +00:00
|
|
|
VERBOSE_LOG(CPU, "vflush");
|
2012-11-01 15:19:01 +00:00
|
|
|
PC += 4;
|
2019-03-16 16:28:54 +00:00
|
|
|
// Anything with 0xFC000000 is a nop, but only 0xFFFF0000 retains prefixes.
|
|
|
|
if ((op & 0xFFFF0000) != 0xFFFF0000)
|
|
|
|
EatPrefixes();
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_VV2Op(MIPSOpcode op)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
|
|
|
float s[4], d[4];
|
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
|
|
|
ReadVector(s, sz, vs);
|
|
|
|
ApplySwizzleS(s, sz);
|
|
|
|
for (int i = 0; i < GetNumVectorElements(sz); i++)
|
|
|
|
{
|
|
|
|
switch ((op >> 16) & 0x1f)
|
|
|
|
{
|
|
|
|
case 0: d[i] = s[i]; break; //vmov
|
|
|
|
case 1: d[i] = fabsf(s[i]); break; //vabs
|
|
|
|
case 2: d[i] = -s[i]; break; //vneg
|
2014-05-16 07:36:05 +00:00
|
|
|
// vsat0 changes -0.0 to +0.0, both retain NAN.
|
2013-02-19 06:06:49 +00:00
|
|
|
case 4: if (s[i] <= 0) d[i] = 0; else {if(s[i] > 1.0f) d[i] = 1.0f; else d[i] = s[i];} break; // vsat0
|
2012-11-01 15:19:01 +00:00
|
|
|
case 5: if (s[i] < -1.0f) d[i] = -1.0f; else {if(s[i] > 1.0f) d[i] = 1.0f; else d[i] = s[i];} break; // vsat1
|
|
|
|
case 16: d[i] = 1.0f / s[i]; break; //vrcp
|
|
|
|
case 17: d[i] = 1.0f / sqrtf(s[i]); break; //vrsq
|
2014-06-15 09:03:00 +00:00
|
|
|
|
|
|
|
case 18: { d[i] = vfpu_sin(s[i]); } break; //vsin
|
|
|
|
case 19: { d[i] = vfpu_cos(s[i]); } break; //vcos
|
2013-02-19 04:02:58 +00:00
|
|
|
case 20: d[i] = powf(2.0f, s[i]); break; //vexp2
|
|
|
|
case 21: d[i] = logf(s[i])/log(2.0f); break; //vlog2
|
2013-02-19 05:46:33 +00:00
|
|
|
case 22: d[i] = fabsf(sqrtf(s[i])); break; //vsqrt
|
2013-03-24 10:34:29 +00:00
|
|
|
case 23: d[i] = asinf(s[i]) / M_PI_2; break; //vasin
|
2013-01-06 22:23:36 +00:00
|
|
|
case 24: d[i] = -1.0f / s[i]; break; // vnrcp
|
2014-06-15 09:03:00 +00:00
|
|
|
case 26: { d[i] = -vfpu_sin(s[i]); } break; // vnsin
|
2013-03-17 20:52:34 +00:00
|
|
|
case 28: d[i] = 1.0f / powf(2.0, s[i]); break; // vrexp2
|
2012-11-01 15:19:01 +00:00
|
|
|
default:
|
|
|
|
_dbg_assert_msg_(CPU,0,"Trying to interpret VV2Op instruction that can't be interpreted");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ApplyPrefixD(d, sz);
|
|
|
|
WriteVector(d, sz, vd);
|
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_Vocp(MIPSOpcode op)
|
2012-11-15 09:15:40 +00:00
|
|
|
{
|
2019-02-23 17:15:26 +00:00
|
|
|
float s[4], t[4], d[4];
|
2012-11-15 09:15:40 +00:00
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
|
|
|
ReadVector(s, sz, vs);
|
2019-02-23 17:15:26 +00:00
|
|
|
|
|
|
|
// S prefix forces the negate flags.
|
2019-02-24 13:28:36 +00:00
|
|
|
u32 sprefixAdd = VFPU_NEGATE(1, 1, 1, 1);
|
|
|
|
ApplyPrefixST(s, VFPURewritePrefix(VFPU_CTRL_SPREFIX, 0, sprefixAdd), sz);
|
2019-02-23 17:15:26 +00:00
|
|
|
|
|
|
|
// T prefix forces constants on and regnum to 1.
|
|
|
|
// That means negate still works, and abs activates a different constant.
|
2019-02-24 13:28:36 +00:00
|
|
|
u32 tprefixRemove = VFPU_ANY_SWIZZLE();
|
2019-03-31 17:33:26 +00:00
|
|
|
u32 tprefixAdd = VFPU_MAKE_CONSTANTS(VFPUConst::ONE, VFPUConst::ONE, VFPUConst::ONE, VFPUConst::ONE);
|
2019-02-24 13:28:36 +00:00
|
|
|
ApplyPrefixST(t, VFPURewritePrefix(VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), sz);
|
2019-02-23 17:15:26 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < GetNumVectorElements(sz); i++) {
|
|
|
|
// Always positive NaN. Note that s is always negated from the registers.
|
|
|
|
d[i] = my_isnan(s[i]) ? fabsf(s[i]) : t[i] + s[i];
|
2012-11-15 09:15:40 +00:00
|
|
|
}
|
|
|
|
ApplyPrefixD(d, sz);
|
|
|
|
WriteVector(d, sz, vd);
|
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
2012-12-21 03:05:53 +00:00
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_Vsocp(MIPSOpcode op)
|
2012-12-21 03:05:53 +00:00
|
|
|
{
|
2019-02-23 18:05:13 +00:00
|
|
|
float s[4], t[4], d[4];
|
2012-12-21 03:05:53 +00:00
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
2019-02-23 18:05:13 +00:00
|
|
|
VectorSize outSize = GetDoubleVectorSize(sz);
|
2012-12-21 03:05:53 +00:00
|
|
|
ReadVector(s, sz, vs);
|
2019-02-23 18:05:13 +00:00
|
|
|
|
|
|
|
// S prefix forces negate in even/odd and xxyy swizzle.
|
|
|
|
// abs works, and applies to final position (not source.)
|
2019-02-24 13:28:36 +00:00
|
|
|
u32 sprefixRemove = VFPU_ANY_SWIZZLE() | VFPU_NEGATE(1, 1, 1, 1);
|
|
|
|
u32 sprefixAdd = VFPU_SWIZZLE(0, 0, 1, 1) | VFPU_NEGATE(1, 0, 1, 0);
|
|
|
|
ApplyPrefixST(s, VFPURewritePrefix(VFPU_CTRL_SPREFIX, sprefixRemove, sprefixAdd), outSize);
|
2019-02-23 18:05:13 +00:00
|
|
|
|
2019-03-31 17:33:26 +00:00
|
|
|
// T prefix forces constants on and regnum to 1, 0, 1, 0.
|
2019-02-23 18:05:13 +00:00
|
|
|
// That means negate still works, and abs activates a different constant.
|
2019-02-24 13:28:36 +00:00
|
|
|
u32 tprefixRemove = VFPU_ANY_SWIZZLE();
|
2019-03-31 17:33:26 +00:00
|
|
|
u32 tprefixAdd = VFPU_MAKE_CONSTANTS(VFPUConst::ONE, VFPUConst::ZERO, VFPUConst::ONE, VFPUConst::ZERO);
|
2019-02-24 13:28:36 +00:00
|
|
|
ApplyPrefixST(t, VFPURewritePrefix(VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), outSize);
|
2019-02-23 18:05:13 +00:00
|
|
|
|
2013-01-06 15:19:47 +00:00
|
|
|
int n = GetNumVectorElements(sz);
|
2019-02-23 18:05:13 +00:00
|
|
|
// Essentially D prefix saturation is forced.
|
|
|
|
d[0] = nanclamp(t[0] + s[0], 0.0f, 1.0f);
|
|
|
|
d[1] = nanclamp(t[1] + s[1], 0.0f, 1.0f);
|
|
|
|
if (outSize == V_Quad) {
|
|
|
|
d[2] = nanclamp(t[2] + s[2], 0.0f, 1.0f);
|
|
|
|
d[3] = nanclamp(t[3] + s[3], 0.0f, 1.0f);
|
2019-02-22 03:02:16 +00:00
|
|
|
}
|
|
|
|
ApplyPrefixD(d, sz);
|
2013-01-06 15:19:47 +00:00
|
|
|
WriteVector(d, outSize, vd);
|
2012-12-21 03:05:53 +00:00
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_Vsgn(MIPSOpcode op)
|
2012-11-15 09:15:40 +00:00
|
|
|
{
|
|
|
|
float s[4], d[4];
|
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
|
|
|
ReadVector(s, sz, vs);
|
|
|
|
ApplySwizzleS(s, sz);
|
|
|
|
for (int i = 0; i < GetNumVectorElements(sz); i++)
|
|
|
|
{
|
|
|
|
// To handle NaNs correctly, we do this with integer hackery
|
|
|
|
u32 val;
|
|
|
|
memcpy(&val, &s[i], sizeof(u32));
|
|
|
|
if (val == 0 || val == 0x80000000)
|
|
|
|
d[i] = 0.0f;
|
|
|
|
else if ((val >> 31) == 0)
|
2012-11-11 21:38:19 +00:00
|
|
|
d[i] = 1.0f;
|
|
|
|
else
|
2012-11-15 09:15:40 +00:00
|
|
|
d[i] = -1.0f;
|
|
|
|
}
|
|
|
|
ApplyPrefixD(d, sz);
|
|
|
|
WriteVector(d, sz, vd);
|
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2013-08-07 19:30:57 +00:00
|
|
|
inline int round_vfpu_n(double param) {
|
2013-07-29 20:36:31 +00:00
|
|
|
// return floorf(param);
|
|
|
|
return (int)round_ieee_754(param);
|
|
|
|
}
|
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_Vf2i(MIPSOpcode op) {
|
2012-11-01 15:19:01 +00:00
|
|
|
float s[4];
|
|
|
|
int d[4];
|
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
int imm = (op >> 16) & 0x1f;
|
2013-04-19 07:23:02 +00:00
|
|
|
float mult = (float)(1UL << imm);
|
2012-11-01 15:19:01 +00:00
|
|
|
VectorSize sz = GetVecSize(op);
|
|
|
|
ReadVector(s, sz, vs);
|
2019-02-24 23:40:58 +00:00
|
|
|
// Negate, abs, and constants apply as you'd expect to the bits.
|
|
|
|
ApplySwizzleS(s, sz);
|
2013-08-07 19:30:57 +00:00
|
|
|
for (int i = 0; i < GetNumVectorElements(sz); i++) {
|
2013-04-13 19:51:38 +00:00
|
|
|
if (my_isnan(s[i])) {
|
2013-03-24 13:28:32 +00:00
|
|
|
d[i] = 0x7FFFFFFF;
|
|
|
|
continue;
|
|
|
|
}
|
2013-04-19 10:16:45 +00:00
|
|
|
double sv = s[i] * mult; // (float)0x7fffffff == (float)0x80000000
|
2013-01-22 19:28:55 +00:00
|
|
|
// Cap/floor it to 0x7fffffff / 0x80000000
|
2013-08-07 19:30:57 +00:00
|
|
|
if (sv > (double)0x7fffffff) {
|
|
|
|
d[i] = 0x7fffffff;
|
|
|
|
} else if (sv <= (double)(int)0x80000000) {
|
|
|
|
d[i] = 0x80000000;
|
|
|
|
} else {
|
|
|
|
switch ((op >> 21) & 0x1f)
|
|
|
|
{
|
2014-06-28 23:06:10 +00:00
|
|
|
case 16: d[i] = (int)round_vfpu_n(sv); break; //(floor(sv + 0.5f)); break; //n
|
2013-08-07 19:30:57 +00:00
|
|
|
case 17: d[i] = s[i]>=0 ? (int)floor(sv) : (int)ceil(sv); break; //z
|
|
|
|
case 18: d[i] = (int)ceil(sv); break; //u
|
|
|
|
case 19: d[i] = (int)floor(sv); break; //d
|
|
|
|
default: d[i] = 0x7FFFFFFF; break;
|
|
|
|
}
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
}
|
2019-02-24 23:40:58 +00:00
|
|
|
// Does not apply sat, but does apply mask.
|
2015-01-19 16:51:30 +00:00
|
|
|
ApplyPrefixD(reinterpret_cast<float *>(d), sz, true);
|
|
|
|
WriteVector(reinterpret_cast<float *>(d), sz, vd);
|
2012-11-01 15:19:01 +00:00
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
|
|
|
|
2019-02-24 23:40:58 +00:00
|
|
|
void Int_Vi2f(MIPSOpcode op) {
|
2012-11-01 15:19:01 +00:00
|
|
|
int s[4];
|
|
|
|
float d[4];
|
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
int imm = (op >> 16) & 0x1f;
|
2013-04-19 07:23:02 +00:00
|
|
|
float mult = 1.0f/(float)(1UL << imm);
|
2012-11-01 15:19:01 +00:00
|
|
|
VectorSize sz = GetVecSize(op);
|
2015-01-19 16:51:30 +00:00
|
|
|
ReadVector(reinterpret_cast<float *>(s), sz, vs);
|
2019-02-24 23:40:58 +00:00
|
|
|
// Negate, abs, and constants apply as you'd expect to the bits.
|
|
|
|
ApplySwizzleS(reinterpret_cast<float *>(s), sz);
|
|
|
|
for (int i = 0; i < GetNumVectorElements(sz); i++) {
|
2012-11-01 15:19:01 +00:00
|
|
|
d[i] = (float)s[i] * mult;
|
|
|
|
}
|
2019-02-24 23:40:58 +00:00
|
|
|
// Sat and mask apply normally.
|
|
|
|
ApplyPrefixD(d, sz);
|
2012-11-01 15:19:01 +00:00
|
|
|
WriteVector(d, sz, vd);
|
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
2012-11-06 19:56:19 +00:00
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_Vh2f(MIPSOpcode op)
|
2012-11-11 21:38:19 +00:00
|
|
|
{
|
2013-01-13 19:47:40 +00:00
|
|
|
u32 s[4];
|
2012-11-11 21:38:19 +00:00
|
|
|
float d[4];
|
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
2015-01-19 16:51:30 +00:00
|
|
|
ReadVector(reinterpret_cast<float *>(s), sz, vs);
|
|
|
|
ApplySwizzleS(reinterpret_cast<float *>(s), sz);
|
2012-11-11 21:38:19 +00:00
|
|
|
|
2013-01-13 19:47:40 +00:00
|
|
|
VectorSize outsize = V_Pair;
|
|
|
|
switch (sz) {
|
|
|
|
case V_Single:
|
|
|
|
outsize = V_Pair;
|
|
|
|
d[0] = ExpandHalf(s[0] & 0xFFFF);
|
|
|
|
d[1] = ExpandHalf(s[0] >> 16);
|
|
|
|
break;
|
|
|
|
case V_Pair:
|
|
|
|
outsize = V_Quad;
|
|
|
|
d[0] = ExpandHalf(s[0] & 0xFFFF);
|
|
|
|
d[1] = ExpandHalf(s[0] >> 16);
|
|
|
|
d[2] = ExpandHalf(s[1] & 0xFFFF);
|
|
|
|
d[3] = ExpandHalf(s[1] >> 16);
|
|
|
|
break;
|
2014-12-20 17:11:45 +00:00
|
|
|
default:
|
2013-01-20 02:31:04 +00:00
|
|
|
_dbg_assert_msg_(CPU, 0, "Trying to interpret Int_Vh2f instruction that can't be interpreted");
|
2015-01-19 16:53:38 +00:00
|
|
|
memset(d, 0, sizeof(d));
|
2013-01-20 02:31:04 +00:00
|
|
|
break;
|
2012-11-11 21:38:19 +00:00
|
|
|
}
|
2013-02-23 19:34:32 +00:00
|
|
|
ApplyPrefixD(d, outsize);
|
2013-02-19 23:24:21 +00:00
|
|
|
WriteVector(d, outsize, vd);
|
2012-11-11 21:38:19 +00:00
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_Vf2h(MIPSOpcode op)
|
2012-11-06 19:56:19 +00:00
|
|
|
{
|
2013-02-23 17:52:24 +00:00
|
|
|
float s[4];
|
|
|
|
u32 d[4];
|
2012-11-06 19:56:19 +00:00
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
2013-02-23 17:52:24 +00:00
|
|
|
ReadVector(s, sz, vs);
|
2013-02-23 19:34:32 +00:00
|
|
|
ApplySwizzleS(s, sz);
|
2012-11-06 19:56:19 +00:00
|
|
|
|
2013-02-23 17:52:24 +00:00
|
|
|
VectorSize outsize = V_Single;
|
|
|
|
switch (sz) {
|
|
|
|
case V_Pair:
|
|
|
|
outsize = V_Single;
|
|
|
|
d[0] = ShrinkToHalf(s[0]) | ((u32)ShrinkToHalf(s[1]) << 16);
|
|
|
|
break;
|
|
|
|
case V_Quad:
|
|
|
|
outsize = V_Pair;
|
|
|
|
d[0] = ShrinkToHalf(s[0]) | ((u32)ShrinkToHalf(s[1]) << 16);
|
|
|
|
d[1] = ShrinkToHalf(s[2]) | ((u32)ShrinkToHalf(s[3]) << 16);
|
|
|
|
break;
|
2014-12-20 17:11:45 +00:00
|
|
|
default:
|
2013-02-23 17:52:24 +00:00
|
|
|
_dbg_assert_msg_(CPU, 0, "Trying to interpret Int_Vf2h instruction that can't be interpreted");
|
2015-04-08 18:31:12 +00:00
|
|
|
d[0] = 0;
|
|
|
|
d[1] = 0;
|
2013-02-23 17:52:24 +00:00
|
|
|
break;
|
2012-11-06 19:56:19 +00:00
|
|
|
}
|
2015-01-19 16:51:30 +00:00
|
|
|
ApplyPrefixD(reinterpret_cast<float *>(d), outsize);
|
|
|
|
WriteVector(reinterpret_cast<float *>(d), outsize, vd);
|
2012-11-06 19:56:19 +00:00
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_Vx2i(MIPSOpcode op)
|
2012-11-11 17:44:20 +00:00
|
|
|
{
|
2013-04-19 07:23:02 +00:00
|
|
|
u32 s[4];
|
2013-02-18 22:37:53 +00:00
|
|
|
u32 d[4] = {0};
|
2012-11-11 17:44:20 +00:00
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
|
|
|
VectorSize oz = sz;
|
2015-01-19 16:51:30 +00:00
|
|
|
ReadVector(reinterpret_cast<float *>(s), sz, vs);
|
2012-11-11 17:44:20 +00:00
|
|
|
// ForbidVPFXS
|
|
|
|
|
|
|
|
switch ((op >> 16) & 3) {
|
|
|
|
case 0: // vuc2i
|
2012-11-11 23:04:57 +00:00
|
|
|
// Quad is the only option.
|
|
|
|
// This operation is weird. This particular way of working matches hw but does not
|
|
|
|
// seem quite sane.
|
2014-11-08 08:39:40 +00:00
|
|
|
// I guess it's used for fixed-point math, and fills more bits to facilitate
|
|
|
|
// conversion between 8-bit and 16-bit values. But then why not do it in vc2i?
|
2012-11-11 17:44:20 +00:00
|
|
|
{
|
|
|
|
u32 value = s[0];
|
|
|
|
for (int i = 0; i < 4; i++) {
|
2012-11-11 23:04:57 +00:00
|
|
|
d[i] = (u32)((value & 0xFF) * 0x01010101) >> 1;
|
2012-11-11 17:44:20 +00:00
|
|
|
value >>= 8;
|
|
|
|
}
|
2012-11-11 23:04:57 +00:00
|
|
|
oz = V_Quad;
|
2012-11-11 17:44:20 +00:00
|
|
|
}
|
|
|
|
break;
|
2012-11-11 23:04:57 +00:00
|
|
|
|
2012-11-11 17:44:20 +00:00
|
|
|
case 1: // vc2i
|
|
|
|
// Quad is the only option
|
|
|
|
{
|
|
|
|
u32 value = s[0];
|
|
|
|
d[0] = (value & 0xFF) << 24;
|
|
|
|
d[1] = (value & 0xFF00) << 16;
|
|
|
|
d[2] = (value & 0xFF0000) << 8;
|
|
|
|
d[3] = (value & 0xFF000000);
|
2012-11-11 23:04:57 +00:00
|
|
|
oz = V_Quad;
|
2012-11-11 17:44:20 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2: // vus2i
|
2012-11-12 13:35:10 +00:00
|
|
|
oz = V_Pair;
|
2013-05-18 17:17:58 +00:00
|
|
|
switch (sz)
|
|
|
|
{
|
|
|
|
case V_Pair:
|
|
|
|
oz = V_Quad;
|
|
|
|
// Intentional fallthrough.
|
|
|
|
case V_Single:
|
|
|
|
for (int i = 0; i < GetNumVectorElements(sz); i++) {
|
|
|
|
u32 value = s[i];
|
|
|
|
d[i * 2] = (value & 0xFFFF) << 15;
|
|
|
|
d[i * 2 + 1] = (value & 0xFFFF0000) >> 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
ERROR_LOG_REPORT(CPU, "vus2i with more than 2 elements.");
|
|
|
|
break;
|
|
|
|
}
|
2012-11-12 13:35:10 +00:00
|
|
|
break;
|
|
|
|
|
2012-11-11 17:44:20 +00:00
|
|
|
case 3: // vs2i
|
|
|
|
oz = V_Pair;
|
2013-05-18 17:17:58 +00:00
|
|
|
switch (sz)
|
|
|
|
{
|
|
|
|
case V_Pair:
|
|
|
|
oz = V_Quad;
|
|
|
|
// Intentional fallthrough.
|
|
|
|
case V_Single:
|
|
|
|
for (int i = 0; i < GetNumVectorElements(sz); i++) {
|
|
|
|
u32 value = s[i];
|
|
|
|
d[i * 2] = (value & 0xFFFF) << 16;
|
|
|
|
d[i * 2 + 1] = value & 0xFFFF0000;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
ERROR_LOG_REPORT(CPU, "vs2i with more than 2 elements.");
|
|
|
|
break;
|
|
|
|
}
|
2012-11-11 17:44:20 +00:00
|
|
|
break;
|
2013-05-18 17:17:58 +00:00
|
|
|
|
2012-11-11 17:44:20 +00:00
|
|
|
default:
|
|
|
|
_dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-01-19 16:51:30 +00:00
|
|
|
ApplyPrefixD(reinterpret_cast<float *>(d),oz, true); // Only write mask
|
|
|
|
WriteVector(reinterpret_cast<float *>(d),oz,vd);
|
2012-11-11 17:44:20 +00:00
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_Vi2x(MIPSOpcode op)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
|
|
|
int s[4];
|
2012-11-18 22:34:37 +00:00
|
|
|
u32 d[2] = {0};
|
2012-11-01 15:19:01 +00:00
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
|
|
|
VectorSize oz;
|
2015-01-19 16:51:30 +00:00
|
|
|
ReadVector(reinterpret_cast<float *>(s), sz, vs);
|
|
|
|
ApplySwizzleS(reinterpret_cast<float *>(s), sz); //TODO: and the mask to kill everything but swizzle
|
2012-11-01 15:19:01 +00:00
|
|
|
switch ((op >> 16)&3)
|
|
|
|
{
|
|
|
|
case 0: //vi2uc
|
|
|
|
{
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
|
|
{
|
|
|
|
int v = s[i];
|
|
|
|
if (v < 0) v = 0;
|
|
|
|
v >>= 23;
|
|
|
|
d[0] |= ((u32)v & 0xFF) << (i * 8);
|
|
|
|
}
|
|
|
|
oz = V_Single;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1: //vi2c
|
2012-11-18 22:34:37 +00:00
|
|
|
{
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
|
|
{
|
2012-11-22 17:12:56 +00:00
|
|
|
u32 v = s[i];
|
|
|
|
d[0] |= (v >> 24) << (i * 8);
|
2012-11-18 22:34:37 +00:00
|
|
|
}
|
|
|
|
oz = V_Single;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2: //vi2us
|
2012-11-07 18:10:52 +00:00
|
|
|
{
|
|
|
|
for (int i = 0; i < GetNumVectorElements(sz) / 2; i++) {
|
|
|
|
int low = s[i * 2];
|
|
|
|
int high = s[i * 2 + 1];
|
|
|
|
if (low < 0) low = 0;
|
|
|
|
if (high < 0) high = 0;
|
|
|
|
low >>= 15;
|
|
|
|
high >>= 15;
|
|
|
|
d[i] = low | (high << 16);
|
|
|
|
}
|
2013-10-27 01:31:14 +00:00
|
|
|
switch (sz) {
|
|
|
|
case V_Quad: oz = V_Pair; break;
|
|
|
|
case V_Pair: oz = V_Single; break;
|
|
|
|
default:
|
|
|
|
_dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted");
|
|
|
|
oz = V_Single;
|
|
|
|
break;
|
|
|
|
}
|
2012-11-07 18:10:52 +00:00
|
|
|
}
|
|
|
|
break;
|
2012-11-01 15:19:01 +00:00
|
|
|
case 3: //vi2s
|
2012-11-07 18:10:52 +00:00
|
|
|
{
|
|
|
|
for (int i = 0; i < GetNumVectorElements(sz) / 2; i++) {
|
|
|
|
u32 low = s[i * 2];
|
|
|
|
u32 high = s[i * 2 + 1];
|
|
|
|
low >>= 16;
|
|
|
|
high >>= 16;
|
|
|
|
d[i] = low | (high << 16);
|
|
|
|
}
|
2013-10-27 01:31:14 +00:00
|
|
|
switch (sz) {
|
|
|
|
case V_Quad: oz = V_Pair; break;
|
|
|
|
case V_Pair: oz = V_Single; break;
|
|
|
|
default:
|
|
|
|
_dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted");
|
|
|
|
oz = V_Single;
|
|
|
|
break;
|
|
|
|
}
|
2012-11-07 18:10:52 +00:00
|
|
|
}
|
|
|
|
break;
|
2012-11-01 15:19:01 +00:00
|
|
|
default:
|
|
|
|
_dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted");
|
2013-03-02 21:50:38 +00:00
|
|
|
oz = V_Single;
|
2012-11-01 15:19:01 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-01-19 16:51:30 +00:00
|
|
|
ApplyPrefixD(reinterpret_cast<float *>(d),oz);
|
|
|
|
WriteVector(reinterpret_cast<float *>(d),oz,vd);
|
2012-11-01 15:19:01 +00:00
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_ColorConv(MIPSOpcode op)
|
2012-11-18 22:34:37 +00:00
|
|
|
{
|
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
u32 s[4];
|
|
|
|
VectorSize sz = V_Quad;
|
2015-01-19 16:51:30 +00:00
|
|
|
ReadVector(reinterpret_cast<float *>(s), sz, vs);
|
2016-05-15 20:16:03 +00:00
|
|
|
ApplySwizzleS(reinterpret_cast<float *>(s), sz);
|
2012-11-18 22:34:37 +00:00
|
|
|
u16 colors[4];
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
|
|
{
|
|
|
|
u32 in = s[i];
|
|
|
|
u16 col = 0;
|
|
|
|
switch ((op >> 16) & 3)
|
|
|
|
{
|
|
|
|
case 1: // 4444
|
|
|
|
{
|
|
|
|
int a = ((in >> 24) & 0xFF) >> 4;
|
|
|
|
int b = ((in >> 16) & 0xFF) >> 4;
|
|
|
|
int g = ((in >> 8) & 0xFF) >> 4;
|
|
|
|
int r = ((in) & 0xFF) >> 4;
|
|
|
|
col = (a << 12) | (b << 8) | (g << 4 ) | (r);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 2: // 5551
|
|
|
|
{
|
|
|
|
int a = ((in >> 24) & 0xFF) >> 7;
|
|
|
|
int b = ((in >> 16) & 0xFF) >> 3;
|
|
|
|
int g = ((in >> 8) & 0xFF) >> 3;
|
|
|
|
int r = ((in) & 0xFF) >> 3;
|
|
|
|
col = (a << 15) | (b << 10) | (g << 5) | (r);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 3: // 565
|
|
|
|
{
|
|
|
|
int b = ((in >> 16) & 0xFF) >> 3;
|
|
|
|
int g = ((in >> 8) & 0xFF) >> 2;
|
|
|
|
int r = ((in) & 0xFF) >> 3;
|
|
|
|
col = (b << 11) | (g << 5) | (r);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
colors[i] = col;
|
|
|
|
}
|
|
|
|
u32 ov[2] = {(u32)colors[0] | (colors[1] << 16), (u32)colors[2] | (colors[3] << 16)};
|
2016-05-15 20:16:03 +00:00
|
|
|
ApplyPrefixD(reinterpret_cast<float *>(ov), V_Pair);
|
2012-11-18 22:34:37 +00:00
|
|
|
WriteVector((const float *)ov, V_Pair, vd);
|
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_VDot(MIPSOpcode op)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
|
|
|
float s[4], t[4];
|
|
|
|
float d;
|
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
int vt = _VT;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
|
|
|
ReadVector(s, sz, vs);
|
|
|
|
ApplySwizzleS(s, sz);
|
|
|
|
ReadVector(t, sz, vt);
|
|
|
|
ApplySwizzleT(t, sz);
|
|
|
|
float sum = 0.0f;
|
|
|
|
int n = GetNumVectorElements(sz);
|
|
|
|
for (int i = 0; i < n; i++)
|
|
|
|
{
|
|
|
|
sum += s[i]*t[i];
|
|
|
|
}
|
|
|
|
d = sum;
|
|
|
|
ApplyPrefixD(&d,V_Single);
|
2013-02-17 23:24:18 +00:00
|
|
|
WriteVector(&d, V_Single, vd);
|
2012-11-01 15:19:01 +00:00
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_VHdp(MIPSOpcode op)
|
2012-12-18 21:54:08 +00:00
|
|
|
{
|
|
|
|
float s[4], t[4];
|
|
|
|
float d;
|
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
int vt = _VT;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
|
|
|
ReadVector(s, sz, vs);
|
|
|
|
ApplySwizzleS(s, sz);
|
|
|
|
ReadVector(t, sz, vt);
|
|
|
|
ApplySwizzleT(t, sz);
|
|
|
|
float sum = 0.0f;
|
|
|
|
int n = GetNumVectorElements(sz);
|
|
|
|
for (int i = 0; i < n; i++)
|
|
|
|
{
|
|
|
|
sum += (i == n - 1) ? t[i] : s[i]*t[i];
|
|
|
|
}
|
2013-04-13 19:51:38 +00:00
|
|
|
d = my_isnan(sum) ? fabsf(sum) : sum;
|
2012-12-18 21:54:08 +00:00
|
|
|
ApplyPrefixD(&d,V_Single);
|
2013-03-17 20:52:34 +00:00
|
|
|
WriteVector(&d, V_Single, vd);
|
2012-12-18 21:54:08 +00:00
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
|
|
|
|
2019-02-24 03:51:37 +00:00
|
|
|
void Int_Vbfy(MIPSOpcode op) {
|
|
|
|
float s[4]{}, t[4]{}, d[4];
|
2012-11-01 15:19:01 +00:00
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
|
|
|
ReadVector(s, sz, vs);
|
2019-02-24 03:51:37 +00:00
|
|
|
ReadVector(t, sz, vs);
|
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
int n = GetNumVectorElements(sz);
|
2019-02-24 03:51:37 +00:00
|
|
|
if (op & 0x10000) {
|
2013-04-27 18:52:42 +00:00
|
|
|
// vbfy2
|
2019-02-24 03:51:37 +00:00
|
|
|
// S prefix forces the negate flags (so z and w are negative.)
|
2019-02-24 13:28:36 +00:00
|
|
|
u32 sprefixAdd = VFPU_NEGATE(0, 0, 1, 1);
|
|
|
|
ApplyPrefixST(s, VFPURewritePrefix(VFPU_CTRL_SPREFIX, 0, sprefixAdd), sz);
|
2019-02-24 03:51:37 +00:00
|
|
|
|
|
|
|
// T prefix forces swizzle (zwxy.)
|
|
|
|
// That means negate still works, but constants are a bit weird.
|
2019-02-24 13:28:36 +00:00
|
|
|
u32 tprefixRemove = VFPU_ANY_SWIZZLE();
|
|
|
|
u32 tprefixAdd = VFPU_SWIZZLE(2, 3, 0, 1);
|
|
|
|
ApplyPrefixST(t, VFPURewritePrefix(VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), sz);
|
2019-02-24 03:51:37 +00:00
|
|
|
|
|
|
|
// Other sizes don't seem completely predictable.
|
|
|
|
if (sz != V_Quad) {
|
|
|
|
ERROR_LOG_REPORT_ONCE(vbfy2, CPU, "vfby2 with incorrect size");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// vbfy1
|
|
|
|
// S prefix forces the negate flags (so y and w are negative.)
|
2019-02-24 13:28:36 +00:00
|
|
|
u32 sprefixAdd = VFPU_NEGATE(0, 1, 0, 1);
|
|
|
|
ApplyPrefixST(s, VFPURewritePrefix(VFPU_CTRL_SPREFIX, 0, sprefixAdd), sz);
|
2019-02-24 03:51:37 +00:00
|
|
|
|
|
|
|
// T prefix forces swizzle (yxwz.)
|
|
|
|
// That means negate still works, but constants are a bit weird.
|
2019-02-24 13:28:36 +00:00
|
|
|
u32 tprefixRemove = VFPU_ANY_SWIZZLE();
|
|
|
|
u32 tprefixAdd = VFPU_SWIZZLE(1, 0, 3, 2);
|
|
|
|
ApplyPrefixST(t, VFPURewritePrefix(VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), sz);
|
2019-02-24 03:51:37 +00:00
|
|
|
|
|
|
|
if (sz != V_Quad && sz != V_Pair) {
|
|
|
|
ERROR_LOG_REPORT_ONCE(vbfy2, CPU, "vfby1 with incorrect size");
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
}
|
2019-02-24 03:51:37 +00:00
|
|
|
|
|
|
|
d[0] = s[0] + t[0];
|
|
|
|
d[1] = s[1] + t[1];
|
|
|
|
d[2] = s[2] + t[2];
|
|
|
|
d[3] = s[3] + t[3];
|
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
ApplyPrefixD(d, sz);
|
|
|
|
WriteVector(d, sz, vd);
|
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
2012-12-21 06:30:34 +00:00
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_Vsrt1(MIPSOpcode op)
|
2012-12-21 06:30:34 +00:00
|
|
|
{
|
|
|
|
float s[4];
|
|
|
|
float d[4];
|
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
|
|
|
ReadVector(s, sz, vs);
|
|
|
|
ApplySwizzleS(s, sz);
|
|
|
|
float x = s[0];
|
|
|
|
float y = s[1];
|
|
|
|
float z = s[2];
|
|
|
|
float w = s[3];
|
|
|
|
d[0] = std::min(x, y);
|
|
|
|
d[1] = std::max(x, y);
|
|
|
|
d[2] = std::min(z, w);
|
|
|
|
d[3] = std::max(z, w);
|
|
|
|
ApplyPrefixD(d, sz);
|
|
|
|
WriteVector(d, sz, vd);
|
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_Vsrt2(MIPSOpcode op)
|
2012-12-21 06:30:34 +00:00
|
|
|
{
|
|
|
|
float s[4];
|
|
|
|
float d[4];
|
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
|
|
|
ReadVector(s, sz, vs);
|
|
|
|
ApplySwizzleS(s, sz);
|
|
|
|
float x = s[0];
|
|
|
|
float y = s[1];
|
|
|
|
float z = s[2];
|
|
|
|
float w = s[3];
|
|
|
|
d[0] = std::min(x, w);
|
|
|
|
d[1] = std::min(y, z);
|
|
|
|
d[2] = std::max(y, z);
|
|
|
|
d[3] = std::max(x, w);
|
|
|
|
ApplyPrefixD(d, sz);
|
|
|
|
WriteVector(d, sz, vd);
|
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_Vsrt3(MIPSOpcode op)
|
2012-12-21 06:30:34 +00:00
|
|
|
{
|
|
|
|
float s[4];
|
|
|
|
float d[4];
|
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
|
|
|
ReadVector(s, sz, vs);
|
|
|
|
ApplySwizzleS(s, sz);
|
|
|
|
float x = s[0];
|
|
|
|
float y = s[1];
|
|
|
|
float z = s[2];
|
|
|
|
float w = s[3];
|
|
|
|
d[0] = std::max(x, y);
|
|
|
|
d[1] = std::min(x, y);
|
|
|
|
d[2] = std::max(z, w);
|
|
|
|
d[3] = std::min(z, w);
|
|
|
|
ApplyPrefixD(d, sz);
|
|
|
|
WriteVector(d, sz, vd);
|
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_Vsrt4(MIPSOpcode op)
|
2012-12-21 06:30:34 +00:00
|
|
|
{
|
|
|
|
float s[4];
|
|
|
|
float d[4];
|
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
|
|
|
ReadVector(s, sz, vs);
|
|
|
|
ApplySwizzleS(s, sz);
|
|
|
|
float x = s[0];
|
|
|
|
float y = s[1];
|
|
|
|
float z = s[2];
|
|
|
|
float w = s[3];
|
|
|
|
d[0] = std::max(x, w);
|
|
|
|
d[1] = std::max(y, z);
|
|
|
|
d[2] = std::min(y, z);
|
|
|
|
d[3] = std::min(x, w);
|
|
|
|
ApplyPrefixD(d, sz);
|
|
|
|
WriteVector(d, sz, vd);
|
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_Vcrs(MIPSOpcode op)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
|
|
|
//half a cross product
|
|
|
|
float s[4], t[4];
|
|
|
|
float d[4];
|
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
int vt = _VT;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
|
|
|
if (sz != V_Triple)
|
|
|
|
_dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted");
|
|
|
|
|
|
|
|
ReadVector(s, sz, vs);
|
|
|
|
ReadVector(t, sz, vt);
|
|
|
|
// no swizzles allowed
|
|
|
|
d[0] = s[1] * t[2];
|
|
|
|
d[1] = s[2] * t[0];
|
|
|
|
d[2] = s[0] * t[1];
|
|
|
|
ApplyPrefixD(d, sz);
|
|
|
|
WriteVector(d, sz, vd);
|
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
2012-12-20 13:11:21 +00:00
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_Vdet(MIPSOpcode op)
|
2012-12-20 13:11:21 +00:00
|
|
|
{
|
|
|
|
float s[4], t[4];
|
|
|
|
float d[4];
|
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
int vt = _VT;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
|
|
|
if (sz != V_Pair)
|
|
|
|
_dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted");
|
|
|
|
ReadVector(s, sz, vs);
|
2013-03-17 20:52:34 +00:00
|
|
|
ApplySwizzleS(s, sz);
|
2012-12-20 13:11:21 +00:00
|
|
|
ReadVector(t, sz, vt);
|
2014-09-02 05:33:01 +00:00
|
|
|
// TODO: The swizzle on t behaves oddly with constants, but sign changes seem to work.
|
|
|
|
// Also, seems to round in a non-standard way (sometimes toward zero, not always.)
|
2012-12-20 13:11:21 +00:00
|
|
|
d[0] = s[0] * t[1] - s[1] * t[0];
|
|
|
|
ApplyPrefixD(d, sz);
|
2013-03-17 20:52:34 +00:00
|
|
|
WriteVector(d, V_Single, vd);
|
2012-12-20 13:11:21 +00:00
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_Vfad(MIPSOpcode op)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
|
|
|
float s[4];
|
|
|
|
float d;
|
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
|
|
|
ReadVector(s, sz, vs);
|
|
|
|
ApplySwizzleS(s, sz);
|
|
|
|
float sum = 0.0f;
|
|
|
|
int n = GetNumVectorElements(sz);
|
|
|
|
for (int i = 0; i < n; i++)
|
|
|
|
{
|
|
|
|
sum += s[i];
|
|
|
|
}
|
|
|
|
d = sum;
|
|
|
|
ApplyPrefixD(&d,V_Single);
|
|
|
|
V(vd) = d;
|
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_Vavg(MIPSOpcode op)
|
2012-11-18 22:34:37 +00:00
|
|
|
{
|
|
|
|
float s[4];
|
|
|
|
float d;
|
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
|
|
|
ReadVector(s, sz, vs);
|
|
|
|
ApplySwizzleS(s, sz);
|
|
|
|
float sum = 0.0f;
|
|
|
|
int n = GetNumVectorElements(sz);
|
|
|
|
for (int i = 0; i < n; i++)
|
|
|
|
{
|
|
|
|
sum += s[i];
|
|
|
|
}
|
|
|
|
d = sum / n;
|
|
|
|
ApplyPrefixD(&d, V_Single);
|
|
|
|
V(vd) = d;
|
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
2012-11-01 15:19:01 +00:00
|
|
|
|
2019-02-24 13:28:36 +00:00
|
|
|
void Int_VScl(MIPSOpcode op) {
|
|
|
|
float s[4], t[4], d[4];
|
2012-11-01 15:19:01 +00:00
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
int vt = _VT;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
|
|
|
ReadVector(s, sz, vs);
|
|
|
|
ApplySwizzleS(s, sz);
|
2019-02-24 13:28:36 +00:00
|
|
|
|
|
|
|
// T prefix forces swizzle (zzzz for some reason, so we force V_Quad.)
|
|
|
|
// That means negate still works, but constants are a bit weird.
|
|
|
|
t[2] = V(vt);
|
|
|
|
u32 tprefixRemove = VFPU_ANY_SWIZZLE();
|
|
|
|
u32 tprefixAdd = VFPU_SWIZZLE(2, 2, 2, 2);
|
|
|
|
ApplyPrefixST(t, VFPURewritePrefix(VFPU_CTRL_TPREFIX, tprefixRemove, tprefixAdd), V_Quad);
|
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
int n = GetNumVectorElements(sz);
|
2019-02-24 13:28:36 +00:00
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
|
d[i] = s[i] * t[i];
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
ApplyPrefixD(d, sz);
|
|
|
|
WriteVector(d, sz, vd);
|
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_Vrnds(MIPSOpcode op)
|
2012-11-18 22:34:37 +00:00
|
|
|
{
|
|
|
|
int vd = _VD;
|
|
|
|
int seed = VI(vd);
|
|
|
|
currentMIPS->rng.Init(seed);
|
2012-11-25 02:25:42 +00:00
|
|
|
PC += 4;
|
2013-02-18 22:37:53 +00:00
|
|
|
EatPrefixes();
|
2012-11-18 22:34:37 +00:00
|
|
|
}
|
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_VrndX(MIPSOpcode op)
|
2012-11-18 22:34:37 +00:00
|
|
|
{
|
2014-09-02 05:33:01 +00:00
|
|
|
FloatBits d;
|
2012-11-18 22:34:37 +00:00
|
|
|
int vd = _VD;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
|
|
|
int n = GetNumVectorElements(sz);
|
|
|
|
for (int i = 0; i < n; i++)
|
|
|
|
{
|
|
|
|
switch ((op >> 16) & 0x1f)
|
|
|
|
{
|
2014-09-02 05:33:01 +00:00
|
|
|
case 1: d.u[i] = currentMIPS->rng.R32(); break; // vrndi
|
|
|
|
case 2: d.f[i] = 1.0f + ((float)currentMIPS->rng.R32() / 0xFFFFFFFF); break; // vrndf1 TODO: make more accurate
|
|
|
|
case 3: d.f[i] = 2.0f + 2 * ((float)currentMIPS->rng.R32() / 0xFFFFFFFF); break; // vrndf2 TODO: make more accurate
|
2013-08-12 03:08:48 +00:00
|
|
|
default: _dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted");
|
2012-11-18 22:34:37 +00:00
|
|
|
}
|
|
|
|
}
|
2014-09-02 05:33:01 +00:00
|
|
|
ApplyPrefixD(d.f, sz);
|
|
|
|
WriteVector(d.f, sz, vd);
|
2012-11-18 22:34:37 +00:00
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generates one line of a rotation matrix around one of the three axes
|
2014-06-15 09:03:00 +00:00
|
|
|
void Int_Vrot(MIPSOpcode op) {
|
2019-03-10 18:48:25 +00:00
|
|
|
float d[4]{};
|
2012-11-01 15:19:01 +00:00
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
int imm = (op >> 16) & 0x1f;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
2019-03-10 18:48:25 +00:00
|
|
|
bool negSin = (imm & 0x10) != 0;
|
|
|
|
int sineLane = (imm >> 2) & 3;
|
|
|
|
int cosineLane = imm & 3;
|
|
|
|
|
2014-06-15 09:03:00 +00:00
|
|
|
float sine, cosine;
|
2019-03-10 18:48:25 +00:00
|
|
|
if (currentMIPS->vfpuCtrl[VFPU_CTRL_SPREFIX] == 0x000E4) {
|
|
|
|
vfpu_sincos(V(vs), sine, cosine);
|
|
|
|
if (negSin)
|
|
|
|
sine = -sine;
|
|
|
|
} else {
|
|
|
|
// Swizzle on S is a bit odd here, but generally only applies to sine.
|
|
|
|
float s[4]{};
|
|
|
|
ReadVector(s, V_Single, vs);
|
|
|
|
u32 sprefixRemove = VFPU_NEGATE(1, 0, 0, 0);
|
|
|
|
u32 sprefixAdd = VFPU_NEGATE(negSin, 0, 0, 0);
|
|
|
|
// TODO: Minor, but negate shouldn't apply to invalid here. Maybe always?
|
|
|
|
ApplyPrefixST(s, VFPURewritePrefix(VFPU_CTRL_SPREFIX, sprefixRemove, sprefixAdd), V_Single);
|
|
|
|
|
|
|
|
// Cosine ignores all prefixes, so take the original.
|
|
|
|
cosine = vfpu_cos(V(vs));
|
|
|
|
sine = vfpu_sin(s[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sineLane == cosineLane) {
|
2012-11-01 15:19:01 +00:00
|
|
|
for (int i = 0; i < 4; i++)
|
|
|
|
d[i] = sine;
|
2019-03-10 18:48:25 +00:00
|
|
|
} else {
|
|
|
|
d[sineLane] = sine;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
2019-03-10 18:48:25 +00:00
|
|
|
d[cosineLane] = cosine;
|
|
|
|
|
|
|
|
// D prefix works, just not for x.
|
|
|
|
currentMIPS->vfpuCtrl[VFPU_CTRL_DPREFIX] &= 0xFFEFC;
|
|
|
|
ApplyPrefixD(d, sz);
|
2012-11-01 15:19:01 +00:00
|
|
|
WriteVector(d, sz, vd);
|
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_Vtfm(MIPSOpcode op)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
int vt = _VT;
|
|
|
|
int ins = (op >> 23) & 7;
|
|
|
|
|
|
|
|
VectorSize sz = GetVecSize(op);
|
|
|
|
MatrixSize msz = GetMtxSize(op);
|
2012-11-18 22:34:37 +00:00
|
|
|
int n = GetNumVectorElements(sz);
|
|
|
|
|
|
|
|
bool homogenous = false;
|
|
|
|
if (n == ins)
|
|
|
|
{
|
|
|
|
n++;
|
|
|
|
sz = (VectorSize)((int)(sz) + 1);
|
|
|
|
msz = (MatrixSize)((int)(msz) + 1);
|
|
|
|
homogenous = true;
|
|
|
|
}
|
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
float s[16];
|
|
|
|
ReadMatrix(s, msz, vs);
|
|
|
|
float t[4];
|
|
|
|
ReadVector(t, sz, vt);
|
|
|
|
float d[4];
|
2012-11-18 22:34:37 +00:00
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
if (homogenous)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < n; i++)
|
|
|
|
{
|
|
|
|
d[i] = 0.0f;
|
|
|
|
for (int k = 0; k < n; k++)
|
|
|
|
{
|
|
|
|
d[i] += (k == n-1) ? s[i*4+k] : (s[i*4+k] * t[k]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-11-22 17:12:56 +00:00
|
|
|
else if (n == ins + 1)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
|
|
|
for (int i = 0; i < n; i++)
|
|
|
|
{
|
2018-02-11 11:47:08 +00:00
|
|
|
d[i] = s[i*4] * t[0];
|
|
|
|
for (int k = 1; k < n; k++)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
|
|
|
d[i] += s[i*4+k] * t[k];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-09-06 06:27:51 +00:00
|
|
|
Reporting::ReportMessage("Trying to interpret instruction that can't be interpreted (BADVTFM)");
|
2012-11-01 15:19:01 +00:00
|
|
|
_dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted (BADVTFM)");
|
2018-02-11 11:47:08 +00:00
|
|
|
for (int i = 0; i < n; i++)
|
|
|
|
d[i] = 0.0;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
WriteVector(d, sz, vd);
|
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
2012-11-18 22:34:37 +00:00
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_SV(MIPSOpcode op)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
|
|
|
s32 imm = (signed short)(op&0xFFFC);
|
|
|
|
int vt = ((op >> 16) & 0x1f) | ((op & 3) << 5);
|
2013-08-12 00:12:54 +00:00
|
|
|
int rs = _RS;
|
2012-11-01 15:19:01 +00:00
|
|
|
u32 addr = R(rs) + imm;
|
|
|
|
|
|
|
|
switch (op >> 26)
|
|
|
|
{
|
|
|
|
case 50: //lv.s
|
2012-11-18 22:34:37 +00:00
|
|
|
VI(vt) = Memory::Read_U32(addr);
|
2012-11-01 15:19:01 +00:00
|
|
|
break;
|
|
|
|
case 58: //sv.s
|
|
|
|
Memory::Write_U32(VI(vt), addr);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
_dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
PC += 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_Mftv(MIPSOpcode op)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
2012-11-22 19:14:24 +00:00
|
|
|
int imm = op & 0xFF;
|
2012-11-01 15:19:01 +00:00
|
|
|
int rt = _RT;
|
|
|
|
switch ((op >> 21) & 0x1f)
|
|
|
|
{
|
2012-11-22 21:26:13 +00:00
|
|
|
case 3: //mfv / mfvc
|
2013-02-14 07:56:10 +00:00
|
|
|
// rt = 0, imm = 255 appears to be used as a CPU interlock by some games.
|
|
|
|
if (rt != 0) {
|
|
|
|
if (imm < 128) {
|
|
|
|
R(rt) = VI(imm);
|
|
|
|
} else if (imm < 128 + VFPU_CTRL_MAX) { //mtvc
|
|
|
|
R(rt) = currentMIPS->vfpuCtrl[imm - 128];
|
|
|
|
} else {
|
|
|
|
//ERROR - maybe need to make this value too an "interlock" value?
|
|
|
|
_dbg_assert_msg_(CPU,0,"mfv - invalid register");
|
|
|
|
}
|
2012-11-22 19:14:24 +00:00
|
|
|
}
|
2012-11-01 15:19:01 +00:00
|
|
|
break;
|
2012-11-22 21:26:13 +00:00
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
case 7: //mtv
|
2012-11-22 19:14:24 +00:00
|
|
|
if (imm < 128) {
|
|
|
|
VI(imm) = R(rt);
|
2012-11-22 21:26:13 +00:00
|
|
|
} else if (imm < 128 + VFPU_CTRL_MAX) { //mtvc
|
2019-03-30 18:57:11 +00:00
|
|
|
u32 mask;
|
|
|
|
if (GetVFPUCtrlMask(imm - 128, &mask)) {
|
|
|
|
currentMIPS->vfpuCtrl[imm - 128] = R(rt) & mask;
|
|
|
|
}
|
2012-11-22 19:14:24 +00:00
|
|
|
} else {
|
|
|
|
//ERROR
|
|
|
|
_dbg_assert_msg_(CPU,0,"mtv - invalid register");
|
|
|
|
}
|
2012-11-01 15:19:01 +00:00
|
|
|
break;
|
2012-11-22 21:26:13 +00:00
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
default:
|
|
|
|
_dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
PC += 4;
|
|
|
|
}
|
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_Vmfvc(MIPSOpcode op) {
|
2012-11-22 21:26:13 +00:00
|
|
|
int vs = _VS;
|
|
|
|
int imm = op & 0xFF;
|
|
|
|
if (imm >= 128 && imm < 128 + VFPU_CTRL_MAX) {
|
|
|
|
VI(vs) = currentMIPS->vfpuCtrl[imm - 128];
|
|
|
|
}
|
|
|
|
PC += 4;
|
|
|
|
}
|
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_Vmtvc(MIPSOpcode op) {
|
2012-11-22 21:26:13 +00:00
|
|
|
int vs = _VS;
|
|
|
|
int imm = op & 0xFF;
|
|
|
|
if (imm >= 128 && imm < 128 + VFPU_CTRL_MAX) {
|
2019-03-30 18:57:11 +00:00
|
|
|
u32 mask;
|
|
|
|
if (GetVFPUCtrlMask(imm - 128, &mask)) {
|
|
|
|
currentMIPS->vfpuCtrl[imm - 128] = VI(vs) & mask;
|
|
|
|
}
|
2012-11-22 21:26:13 +00:00
|
|
|
}
|
|
|
|
PC += 4;
|
|
|
|
}
|
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_Vcst(MIPSOpcode op)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
|
|
|
int conNum = (op >> 16) & 0x1f;
|
|
|
|
int vd = _VD;
|
|
|
|
|
|
|
|
VectorSize sz = GetVecSize(op);
|
2013-07-27 20:14:01 +00:00
|
|
|
float c = cst_constants[conNum];
|
2012-11-01 15:19:01 +00:00
|
|
|
float temp[4] = {c,c,c,c};
|
2013-02-03 00:31:38 +00:00
|
|
|
ApplyPrefixD(temp, sz);
|
2012-11-03 21:33:53 +00:00
|
|
|
WriteVector(temp, sz, vd);
|
2012-11-01 15:19:01 +00:00
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_Vcmp(MIPSOpcode op)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
|
|
|
int vs = _VS;
|
2012-11-22 19:14:24 +00:00
|
|
|
int vt = _VT;
|
|
|
|
int cond = op & 0xf;
|
2012-11-01 15:19:01 +00:00
|
|
|
VectorSize sz = GetVecSize(op);
|
|
|
|
int n = GetNumVectorElements(sz);
|
|
|
|
float s[4];
|
|
|
|
float t[4];
|
|
|
|
ReadVector(s, sz, vs);
|
|
|
|
ApplySwizzleS(s, sz);
|
|
|
|
ReadVector(t, sz, vt);
|
|
|
|
ApplySwizzleT(t, sz);
|
|
|
|
int cc = 0;
|
|
|
|
int or_val = 0;
|
|
|
|
int and_val = 1;
|
2012-11-14 19:08:00 +00:00
|
|
|
int affected_bits = (1 << 4) | (1 << 5); // 4 and 5
|
2012-11-01 15:19:01 +00:00
|
|
|
for (int i = 0; i < n; i++)
|
|
|
|
{
|
|
|
|
int c;
|
2012-11-18 22:35:02 +00:00
|
|
|
// These set c to 0 or 1, nothing else.
|
2012-11-01 15:19:01 +00:00
|
|
|
switch (cond)
|
|
|
|
{
|
2012-11-22 19:14:24 +00:00
|
|
|
case VC_FL: c = 0; break;
|
2012-11-06 18:33:56 +00:00
|
|
|
case VC_EQ: c = s[i] == t[i]; break;
|
2012-11-01 15:19:01 +00:00
|
|
|
case VC_LT: c = s[i] < t[i]; break;
|
|
|
|
case VC_LE: c = s[i] <= t[i]; break;
|
2012-11-22 19:14:24 +00:00
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
case VC_TR: c = 1; break;
|
|
|
|
case VC_NE: c = s[i] != t[i]; break;
|
|
|
|
case VC_GE: c = s[i] >= t[i]; break;
|
2012-11-22 19:14:24 +00:00
|
|
|
case VC_GT: c = s[i] > t[i]; break;
|
|
|
|
|
|
|
|
case VC_EZ: c = s[i] == 0.0f || s[i] == -0.0f; break;
|
2013-04-13 19:51:38 +00:00
|
|
|
case VC_EN: c = my_isnan(s[i]); break;
|
|
|
|
case VC_EI: c = my_isinf(s[i]); break;
|
2013-11-12 13:07:48 +00:00
|
|
|
case VC_ES: c = my_isnanorinf(s[i]); break; // Tekken Dark Resurrection
|
2012-11-22 19:14:24 +00:00
|
|
|
|
|
|
|
case VC_NZ: c = s[i] != 0; break;
|
2013-04-13 19:51:38 +00:00
|
|
|
case VC_NN: c = !my_isnan(s[i]); break;
|
|
|
|
case VC_NI: c = !my_isinf(s[i]); break;
|
2013-11-12 13:07:48 +00:00
|
|
|
case VC_NS: c = !(my_isnanorinf(s[i])); break; // How about t[i] ?
|
2013-02-24 23:07:29 +00:00
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
default:
|
2012-11-08 13:23:55 +00:00
|
|
|
_dbg_assert_msg_(CPU,0,"Unsupported vcmp condition code %d", cond);
|
2012-11-22 19:14:24 +00:00
|
|
|
PC += 4;
|
2013-02-24 23:07:29 +00:00
|
|
|
EatPrefixes();
|
2012-11-01 15:19:01 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
cc |= (c<<i);
|
|
|
|
or_val |= c;
|
|
|
|
and_val &= c;
|
2012-11-14 19:08:00 +00:00
|
|
|
affected_bits |= 1 << i;
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
2012-11-14 19:08:00 +00:00
|
|
|
// Use masking to only change the affected bits
|
2012-11-18 22:35:02 +00:00
|
|
|
currentMIPS->vfpuCtrl[VFPU_CTRL_CC] =
|
|
|
|
(currentMIPS->vfpuCtrl[VFPU_CTRL_CC] & ~affected_bits) |
|
|
|
|
((cc | (or_val << 4) | (and_val << 5)) & affected_bits);
|
2012-11-01 15:19:01 +00:00
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_Vminmax(MIPSOpcode op) {
|
2012-11-15 12:18:44 +00:00
|
|
|
int vt = _VT;
|
|
|
|
int vs = _VS;
|
|
|
|
int vd = _VD;
|
|
|
|
int cond = op&15;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
2012-12-23 20:51:05 +00:00
|
|
|
int numElements = GetNumVectorElements(sz);
|
2014-06-21 06:54:59 +00:00
|
|
|
|
|
|
|
FloatBits s;
|
|
|
|
FloatBits t;
|
|
|
|
FloatBits d;
|
|
|
|
ReadVector(s.f, sz, vs);
|
|
|
|
ApplySwizzleS(s.f, sz);
|
|
|
|
ReadVector(t.f, sz, vt);
|
|
|
|
ApplySwizzleT(t.f, sz);
|
2014-05-16 07:29:45 +00:00
|
|
|
|
|
|
|
// If both are zero, take t's sign.
|
2014-06-21 06:54:59 +00:00
|
|
|
// Otherwise: -NAN < -INF < real < INF < NAN (higher mantissa is farther from 0.)
|
2014-05-16 07:29:45 +00:00
|
|
|
|
2012-11-15 12:18:44 +00:00
|
|
|
switch ((op >> 23) & 3) {
|
|
|
|
case 2: // vmin
|
2014-05-16 07:29:45 +00:00
|
|
|
for (int i = 0; i < numElements; i++) {
|
2014-06-21 06:54:59 +00:00
|
|
|
if (my_isnanorinf(s.f[i]) || my_isnanorinf(t.f[i])) {
|
|
|
|
// If both are negative, we flip the comparison (not two's compliment.)
|
|
|
|
if (s.i[i] < 0 && t.i[i] < 0) {
|
|
|
|
// If at least one side is NAN, we take the highest mantissa bits.
|
|
|
|
d.i[i] = std::max(t.i[i], s.i[i]);
|
|
|
|
} else {
|
|
|
|
// Otherwise, we take the lowest value (negative or lowest mantissa.)
|
|
|
|
d.i[i] = std::min(t.i[i], s.i[i]);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
d.f[i] = std::min(t.f[i], s.f[i]);
|
|
|
|
}
|
2014-05-16 07:29:45 +00:00
|
|
|
}
|
2012-11-15 12:18:44 +00:00
|
|
|
break;
|
|
|
|
case 3: // vmax
|
2014-06-21 06:54:59 +00:00
|
|
|
for (int i = 0; i < numElements; i++) {
|
|
|
|
// This is the same logic as vmin, just reversed.
|
|
|
|
if (my_isnanorinf(s.f[i]) || my_isnanorinf(t.f[i])) {
|
|
|
|
if (s.i[i] < 0 && t.i[i] < 0) {
|
|
|
|
d.i[i] = std::min(t.i[i], s.i[i]);
|
|
|
|
} else {
|
|
|
|
d.i[i] = std::max(t.i[i], s.i[i]);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
d.f[i] = std::max(t.f[i], s.f[i]);
|
|
|
|
}
|
|
|
|
}
|
2012-11-15 12:18:44 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
_dbg_assert_msg_(CPU,0,"unknown min/max op %d", cond);
|
2013-08-11 23:28:20 +00:00
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
2012-11-15 12:18:44 +00:00
|
|
|
return;
|
|
|
|
}
|
2014-06-21 06:54:59 +00:00
|
|
|
ApplyPrefixD(d.f, sz);
|
|
|
|
WriteVector(d.f, sz, vd);
|
2012-11-15 12:18:44 +00:00
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
2012-12-20 13:39:10 +00:00
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_Vscmp(MIPSOpcode op) {
|
2019-03-26 05:44:45 +00:00
|
|
|
FloatBits s, t, d;
|
2012-12-20 13:39:10 +00:00
|
|
|
int vt = _VT;
|
|
|
|
int vs = _VS;
|
|
|
|
int vd = _VD;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
2019-03-26 05:44:45 +00:00
|
|
|
ReadVector(s.f, sz, vs);
|
|
|
|
ApplySwizzleS(s.f, sz);
|
|
|
|
ReadVector(t.f, sz, vt);
|
|
|
|
ApplySwizzleT(t.f, sz);
|
2012-12-20 13:39:10 +00:00
|
|
|
int n = GetNumVectorElements(sz);
|
|
|
|
for (int i = 0; i < n ; i++) {
|
2019-03-26 05:44:45 +00:00
|
|
|
float a = s.f[i] - t.f[i];
|
|
|
|
if (my_isnan(a)) {
|
|
|
|
// NAN/INF are treated as just larger numbers, as in vmin/vmax.
|
|
|
|
int sMagnitude = s.u[i] & 0x7FFFFFFF;
|
|
|
|
int tMagnitude = t.u[i] & 0x7FFFFFFF;
|
|
|
|
int b = (s.i[i] < 0 ? -sMagnitude : sMagnitude) - (t.i[i] < 0 ? -tMagnitude : tMagnitude);
|
|
|
|
d.f[i] = (float)((0 < b) - (b < 0));
|
|
|
|
} else {
|
|
|
|
d.f[i] = (float)((0.0f < a) - (a < 0.0f));
|
|
|
|
}
|
2012-12-20 13:39:10 +00:00
|
|
|
}
|
2019-03-26 05:44:45 +00:00
|
|
|
ApplyPrefixD(d.f, sz);
|
|
|
|
WriteVector(d.f, sz, vd);
|
2012-12-20 13:39:10 +00:00
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
2013-03-24 13:28:32 +00:00
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_Vsge(MIPSOpcode op) {
|
2012-11-22 17:12:56 +00:00
|
|
|
int vt = _VT;
|
|
|
|
int vs = _VS;
|
|
|
|
int vd = _VD;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
2012-12-23 20:51:05 +00:00
|
|
|
int numElements = GetNumVectorElements(sz);
|
2012-11-22 17:12:56 +00:00
|
|
|
float s[4];
|
|
|
|
float t[4];
|
|
|
|
float d[4];
|
|
|
|
ReadVector(s, sz, vs);
|
|
|
|
ApplySwizzleS(s, sz);
|
|
|
|
ReadVector(t, sz, vt);
|
|
|
|
ApplySwizzleT(t, sz);
|
2013-01-29 01:15:23 +00:00
|
|
|
for (int i = 0; i < GetNumVectorElements(sz); i++) {
|
2013-04-13 19:51:38 +00:00
|
|
|
if ( my_isnan(s[i]) || my_isnan(t[i]) )
|
2013-01-29 01:15:23 +00:00
|
|
|
d[i] = 0.0f;
|
|
|
|
else
|
|
|
|
d[i] = s[i] >= t[i] ? 1.0f : 0.0f;
|
|
|
|
}
|
2012-11-22 17:12:56 +00:00
|
|
|
ApplyPrefixD(d, sz);
|
|
|
|
WriteVector(d, sz, vd);
|
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_Vslt(MIPSOpcode op) {
|
2012-11-22 17:12:56 +00:00
|
|
|
int vt = _VT;
|
|
|
|
int vs = _VS;
|
|
|
|
int vd = _VD;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
2012-12-23 20:51:05 +00:00
|
|
|
int numElements = GetNumVectorElements(sz);
|
2012-11-22 17:12:56 +00:00
|
|
|
float s[4];
|
|
|
|
float t[4];
|
|
|
|
float d[4];
|
|
|
|
ReadVector(s, sz, vs);
|
|
|
|
ApplySwizzleS(s, sz);
|
|
|
|
ReadVector(t, sz, vt);
|
|
|
|
ApplySwizzleT(t, sz);
|
2013-01-29 01:15:23 +00:00
|
|
|
for (int i = 0; i < GetNumVectorElements(sz); i++) {
|
2013-04-13 19:51:38 +00:00
|
|
|
if ( my_isnan(s[i]) || my_isnan(t[i]) )
|
2013-01-29 01:15:23 +00:00
|
|
|
d[i] = 0.0f;
|
|
|
|
else
|
|
|
|
d[i] = s[i] < t[i] ? 1.0f : 0.0f;
|
|
|
|
}
|
2012-11-22 17:12:56 +00:00
|
|
|
ApplyPrefixD(d, sz);
|
|
|
|
WriteVector(d, sz, vd);
|
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-02-24 16:42:14 +00:00
|
|
|
void Int_Vcmov(MIPSOpcode op) {
|
2012-11-01 15:19:01 +00:00
|
|
|
int vs = _VS;
|
2013-03-24 13:28:32 +00:00
|
|
|
int vd = _VD;
|
2012-11-14 19:08:00 +00:00
|
|
|
int tf = (op >> 19) & 1;
|
|
|
|
int imm3 = (op >> 16) & 7;
|
2012-11-01 15:19:01 +00:00
|
|
|
VectorSize sz = GetVecSize(op);
|
|
|
|
int n = GetNumVectorElements(sz);
|
|
|
|
float s[4];
|
|
|
|
float d[4];
|
|
|
|
ReadVector(s, sz, vs);
|
|
|
|
ApplySwizzleS(s, sz);
|
2019-02-24 16:42:14 +00:00
|
|
|
// Not only is D read (as T), but the T prefix applies to it.
|
|
|
|
ReadVector(d, sz, vd);
|
|
|
|
ApplySwizzleT(d, sz);
|
2012-11-01 15:19:01 +00:00
|
|
|
|
|
|
|
int CC = currentMIPS->vfpuCtrl[VFPU_CTRL_CC];
|
|
|
|
|
2019-02-24 16:42:14 +00:00
|
|
|
if (imm3 < 6) {
|
|
|
|
if (((CC >> imm3) & 1) == !tf) {
|
2012-11-01 15:19:01 +00:00
|
|
|
for (int i = 0; i < n; i++)
|
|
|
|
d[i] = s[i];
|
|
|
|
}
|
2019-02-24 16:42:14 +00:00
|
|
|
} else if (imm3 == 6) {
|
|
|
|
for (int i = 0; i < n; i++) {
|
2012-11-14 19:08:00 +00:00
|
|
|
if (((CC >> i) & 1) == !tf)
|
2012-11-01 15:19:01 +00:00
|
|
|
d[i] = s[i];
|
|
|
|
}
|
2019-02-24 16:42:14 +00:00
|
|
|
} else {
|
2013-09-06 06:27:51 +00:00
|
|
|
ERROR_LOG_REPORT(CPU, "Bad Imm3 in cmov: %d", imm3);
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|
|
|
|
ApplyPrefixD(d, sz);
|
|
|
|
WriteVector(d, sz, vd);
|
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_VecDo3(MIPSOpcode op)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
int vt = _VT;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
|
|
|
float s[4];
|
|
|
|
float t[4];
|
|
|
|
float d[4];
|
|
|
|
ReadVector(s, sz, vs);
|
|
|
|
ApplySwizzleS(s, sz);
|
|
|
|
ReadVector(t, sz, vt);
|
|
|
|
ApplySwizzleT(t, sz);
|
|
|
|
for (int i = 0; i < GetNumVectorElements(sz); i++)
|
|
|
|
{
|
|
|
|
switch(op >> 26)
|
|
|
|
{
|
|
|
|
case 24: //VFPU0
|
|
|
|
switch ((op >> 23)&7)
|
|
|
|
{
|
|
|
|
case 0: d[i] = s[i] + t[i]; break; //vadd
|
|
|
|
case 1: d[i] = s[i] - t[i]; break; //vsub
|
|
|
|
case 7: d[i] = s[i] / t[i]; break; //vdiv
|
|
|
|
default: goto bad;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 25: //VFPU1
|
|
|
|
switch ((op >> 23)&7)
|
|
|
|
{
|
|
|
|
case 0: d[i] = s[i] * t[i]; break; //vmul
|
|
|
|
default: goto bad;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
bad:
|
|
|
|
_dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ApplyPrefixD(d, sz);
|
|
|
|
WriteVector(d, sz, vd);
|
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
|
|
|
|
2012-11-11 21:38:19 +00:00
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_CrossQuat(MIPSOpcode op)
|
2012-11-01 15:19:01 +00:00
|
|
|
{
|
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
int vt = _VT;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
|
|
|
float s[4];
|
|
|
|
float t[4];
|
|
|
|
float d[4];
|
|
|
|
ReadVector(s, sz, vs);
|
|
|
|
ReadVector(t, sz, vt);
|
|
|
|
switch (sz)
|
|
|
|
{
|
2012-11-22 17:12:56 +00:00
|
|
|
case V_Triple: // vcrsp.t
|
2012-11-01 15:19:01 +00:00
|
|
|
d[0] = s[1]*t[2] - s[2]*t[1];
|
|
|
|
d[1] = s[2]*t[0] - s[0]*t[2];
|
|
|
|
d[2] = s[0]*t[1] - s[1]*t[0];
|
|
|
|
break;
|
2012-11-22 17:12:56 +00:00
|
|
|
|
|
|
|
case V_Quad: // vqmul.q
|
|
|
|
d[0] = s[0]*t[3] + s[1]*t[2] - s[2]*t[1] + s[3]*t[0];
|
|
|
|
d[1] = -s[0]*t[2] + s[1]*t[3] + s[2]*t[0] + s[3]*t[1];
|
|
|
|
d[2] = s[0]*t[1] - s[1]*t[0] + s[2]*t[3] + s[3]*t[2];
|
|
|
|
d[3] = -s[0]*t[0] - s[1]*t[1] - s[2]*t[2] + s[3]*t[3];
|
|
|
|
break;
|
|
|
|
|
2012-11-01 15:19:01 +00:00
|
|
|
default:
|
2013-09-06 06:27:51 +00:00
|
|
|
Reporting::ReportMessage("CrossQuat instruction with wrong size");
|
2012-11-01 15:19:01 +00:00
|
|
|
_dbg_assert_msg_(CPU,0,"Trying to interpret instruction that can't be interpreted");
|
2015-04-08 18:31:12 +00:00
|
|
|
d[0] = 0;
|
|
|
|
d[1] = 0;
|
2012-11-01 15:19:01 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
WriteVector(d, sz, vd);
|
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
|
|
|
}
|
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_Vlgb(MIPSOpcode op)
|
2013-02-02 22:47:00 +00:00
|
|
|
{
|
2019-02-23 23:04:54 +00:00
|
|
|
// Vector log binary (extract exponent)
|
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
|
|
|
|
|
|
|
FloatBits d;
|
|
|
|
FloatBits s;
|
|
|
|
|
|
|
|
ReadVector(s.f, sz, vs);
|
|
|
|
// TODO: Test swizzle, t?
|
|
|
|
ApplySwizzleS(s.f, sz);
|
|
|
|
|
|
|
|
if (sz != V_Single) {
|
|
|
|
ERROR_LOG_REPORT(CPU, "vlgb not implemented for size %d", GetNumVectorElements(sz));
|
2013-10-14 07:51:08 +00:00
|
|
|
}
|
2019-02-23 23:04:54 +00:00
|
|
|
for (int i = 0; i < GetNumVectorElements(sz); ++i) {
|
|
|
|
int exp = (s.u[i] & 0x7F800000) >> 23;
|
|
|
|
if (exp == 0xFF) {
|
|
|
|
d.f[i] = s.f[i];
|
|
|
|
} else if (exp == 0) {
|
|
|
|
d.f[i] = -INFINITY;
|
|
|
|
} else {
|
|
|
|
d.f[i] = (float)(exp - 127);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ApplyPrefixD(d.f, sz);
|
|
|
|
WriteVector(d.f, sz, vd);
|
2013-05-19 11:12:35 +00:00
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
2013-02-02 22:47:00 +00:00
|
|
|
}
|
|
|
|
|
2013-05-19 11:12:35 +00:00
|
|
|
// There has to be a concise way of expressing this in terms of
|
|
|
|
// bit manipulation on the raw floats.
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_Vwbn(MIPSOpcode op) {
|
2013-05-19 11:12:35 +00:00
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
2014-02-16 07:44:59 +00:00
|
|
|
VectorSize sz = GetVecSize(op);
|
2013-05-19 11:12:35 +00:00
|
|
|
|
2014-02-16 07:44:59 +00:00
|
|
|
FloatBits d;
|
|
|
|
FloatBits s;
|
|
|
|
u8 exp = (u8)((op >> 16) & 0xFF);
|
2013-05-19 11:12:35 +00:00
|
|
|
|
2014-02-16 07:44:59 +00:00
|
|
|
ReadVector(s.f, sz, vs);
|
|
|
|
// TODO: Test swizzle, t?
|
|
|
|
ApplySwizzleS(s.f, sz);
|
|
|
|
|
|
|
|
if (sz != V_Single) {
|
|
|
|
ERROR_LOG_REPORT(CPU, "vwbn not implemented for size %d", GetNumVectorElements(sz));
|
2013-05-19 11:12:35 +00:00
|
|
|
}
|
2014-02-16 07:44:59 +00:00
|
|
|
for (int i = 0; i < GetNumVectorElements(sz); ++i) {
|
|
|
|
u32 sigbit = s.u[i] & 0x80000000;
|
|
|
|
u32 prevExp = (s.u[i] & 0x7F800000) >> 23;
|
2014-02-16 08:00:29 +00:00
|
|
|
u32 mantissa = (s.u[i] & 0x007FFFFF) | 0x00800000;
|
2014-02-16 07:44:59 +00:00
|
|
|
if (prevExp != 0xFF && prevExp != 0) {
|
|
|
|
if (exp > prevExp) {
|
|
|
|
s8 shift = (exp - prevExp) & 0xF;
|
|
|
|
mantissa = mantissa >> shift;
|
|
|
|
} else {
|
|
|
|
s8 shift = (prevExp - exp) & 0xF;
|
|
|
|
mantissa = mantissa << shift;
|
|
|
|
}
|
|
|
|
d.u[i] = sigbit | (mantissa & 0x007FFFFF) | (exp << 23);
|
|
|
|
} else {
|
|
|
|
d.u[i] = s.u[i] | (exp << 23);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ApplyPrefixD(d.f, sz);
|
|
|
|
WriteVector(d.f, sz, vd);
|
2013-05-19 11:12:35 +00:00
|
|
|
PC += 4;
|
2014-02-16 07:44:59 +00:00
|
|
|
EatPrefixes();
|
2013-02-02 22:47:00 +00:00
|
|
|
}
|
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_Vsbn(MIPSOpcode op)
|
2013-02-02 22:47:00 +00:00
|
|
|
{
|
2014-02-16 05:40:13 +00:00
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
int vt = _VT;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
|
|
|
|
|
|
|
FloatBits d;
|
|
|
|
FloatBits s;
|
2014-02-16 07:44:59 +00:00
|
|
|
u8 exp = (u8)(127 + VI(vt));
|
2014-02-16 05:40:13 +00:00
|
|
|
|
|
|
|
ReadVector(s.f, sz, vs);
|
|
|
|
// TODO: Test swizzle, t?
|
|
|
|
ApplySwizzleS(s.f, sz);
|
|
|
|
|
|
|
|
if (sz != V_Single) {
|
|
|
|
ERROR_LOG_REPORT(CPU, "vsbn not implemented for size %d", GetNumVectorElements(sz));
|
|
|
|
}
|
|
|
|
for (int i = 0; i < GetNumVectorElements(sz); ++i) {
|
2014-06-15 09:03:00 +00:00
|
|
|
// Simply replace the exponent bits.
|
2014-02-16 05:40:13 +00:00
|
|
|
u32 prev = s.u[i] & 0x7F800000;
|
|
|
|
if (prev != 0 && prev != 0x7F800000) {
|
|
|
|
d.u[i] = (s.u[i] & ~0x7F800000) | (exp << 23);
|
|
|
|
} else {
|
|
|
|
d.u[i] = s.u[i];
|
|
|
|
}
|
2013-10-14 07:51:08 +00:00
|
|
|
}
|
2014-02-16 05:40:13 +00:00
|
|
|
ApplyPrefixD(d.f, sz);
|
|
|
|
WriteVector(d.f, sz, vd);
|
2013-05-19 11:12:35 +00:00
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
2013-02-02 22:47:00 +00:00
|
|
|
}
|
|
|
|
|
2013-08-24 21:43:49 +00:00
|
|
|
void Int_Vsbz(MIPSOpcode op)
|
2013-02-02 22:47:00 +00:00
|
|
|
{
|
2019-02-23 23:04:54 +00:00
|
|
|
// Vector scale by zero (set exp to 0 to extract mantissa)
|
|
|
|
int vd = _VD;
|
|
|
|
int vs = _VS;
|
|
|
|
VectorSize sz = GetVecSize(op);
|
|
|
|
|
|
|
|
FloatBits d;
|
|
|
|
FloatBits s;
|
|
|
|
|
|
|
|
ReadVector(s.f, sz, vs);
|
|
|
|
// TODO: Test swizzle, t?
|
|
|
|
ApplySwizzleS(s.f, sz);
|
|
|
|
|
|
|
|
if (sz != V_Single) {
|
|
|
|
ERROR_LOG_REPORT(CPU, "vsbz not implemented for size %d", GetNumVectorElements(sz));
|
2013-10-14 07:51:08 +00:00
|
|
|
}
|
2019-02-23 23:04:54 +00:00
|
|
|
for (int i = 0; i < GetNumVectorElements(sz); ++i) {
|
|
|
|
// NAN and denormals pass through.
|
|
|
|
if (my_isnan(s.f[i]) || (s.u[i] & 0x7F800000) == 0) {
|
|
|
|
d.u[i] = s.u[i];
|
|
|
|
} else {
|
|
|
|
d.u[i] = (127 << 23) | (s.u[i] & 0x007FFFFF);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ApplyPrefixD(d.f, sz);
|
|
|
|
WriteVector(d.f, sz, vd);
|
2013-05-19 11:12:35 +00:00
|
|
|
PC += 4;
|
|
|
|
EatPrefixes();
|
2013-02-02 22:47:00 +00:00
|
|
|
}
|
2012-11-01 15:19:01 +00:00
|
|
|
}
|