* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
+#include "qemu/osdep.h"
#include "cpu.h"
#include "exec/helper-proto.h"
msa_move_v(pwd, pwx);
}
+#define MSA_FN_VECTOR(FUNC, DEST, OPERATION) \
+void helper_msa_ ## FUNC(CPUMIPSState *env, uint32_t wd, uint32_t ws, \
+ uint32_t wt) \
+{ \
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr); \
+ wr_t *pwt = &(env->active_fpu.fpr[wt].wr); \
+ uint32_t i; \
+ for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { \
+ DEST = OPERATION; \
+ } \
+}
+
+MSA_FN_VECTOR(and_v, pwd->d[i], pws->d[i] & pwt->d[i])
+MSA_FN_VECTOR(or_v, pwd->d[i], pws->d[i] | pwt->d[i])
+MSA_FN_VECTOR(nor_v, pwd->d[i], ~(pws->d[i] | pwt->d[i]))
+MSA_FN_VECTOR(xor_v, pwd->d[i], pws->d[i] ^ pwt->d[i])
+MSA_FN_VECTOR(bmnz_v, pwd->d[i],
+ BIT_MOVE_IF_NOT_ZERO(pwd->d[i], pws->d[i], pwt->d[i], DF_DOUBLE))
+MSA_FN_VECTOR(bmz_v, pwd->d[i],
+ BIT_MOVE_IF_ZERO(pwd->d[i], pws->d[i], pwt->d[i], DF_DOUBLE))
+MSA_FN_VECTOR(bsel_v, pwd->d[i],
+ BIT_SELECT(pwd->d[i], pws->d[i], pwt->d[i], DF_DOUBLE))
+#undef BIT_MOVE_IF_NOT_ZERO
+#undef BIT_MOVE_IF_ZERO
+#undef BIT_SELECT
+#undef MSA_FN_VECTOR
+
static inline int64_t msa_addv_df(uint32_t df, int64_t arg1, int64_t arg2)
{
return arg1 + arg2;
break;
case 1:
env->active_tc.msacsr = (int32_t)elm & MSACSR_MASK;
- /* set float_status rounding mode */
- set_float_rounding_mode(
- ieee_rm[(env->active_tc.msacsr & MSACSR_RM_MASK) >> MSACSR_RM],
- &env->active_tc.msa_fp_status);
- /* set float_status flush modes */
- set_flush_to_zero(
- (env->active_tc.msacsr & MSACSR_FS_MASK) != 0 ? 1 : 0,
- &env->active_tc.msa_fp_status);
- set_flush_inputs_to_zero(
- (env->active_tc.msacsr & MSACSR_FS_MASK) != 0 ? 1 : 0,
- &env->active_tc.msa_fp_status);
+ restore_msa_fp_status(env);
/* check exception */
if ((GET_FP_ENABLE(env->active_tc.msacsr) | FP_UNIMPLEMENTED)
& GET_FP_CAUSE(env->active_tc.msacsr)) {
- helper_raise_exception(env, EXCP_MSAFPE);
+ do_raise_exception(env, EXCP_MSAFPE, GETPC());
}
break;
}
msa_move_v(pwd, pws);
}
+static inline int64_t msa_pcnt_df(uint32_t df, int64_t arg)
+{
+ uint64_t x;
+
+ x = UNSIGNED(arg, df);
+
+ x = (x & 0x5555555555555555ULL) + ((x >> 1) & 0x5555555555555555ULL);
+ x = (x & 0x3333333333333333ULL) + ((x >> 2) & 0x3333333333333333ULL);
+ x = (x & 0x0F0F0F0F0F0F0F0FULL) + ((x >> 4) & 0x0F0F0F0F0F0F0F0FULL);
+ x = (x & 0x00FF00FF00FF00FFULL) + ((x >> 8) & 0x00FF00FF00FF00FFULL);
+ x = (x & 0x0000FFFF0000FFFFULL) + ((x >> 16) & 0x0000FFFF0000FFFFULL);
+ x = (x & 0x00000000FFFFFFFFULL) + ((x >> 32));
+
+ return x;
+}
+
+static inline int64_t msa_nlzc_df(uint32_t df, int64_t arg)
+{
+ uint64_t x, y;
+ int n, c;
+
+ x = UNSIGNED(arg, df);
+ n = DF_BITS(df);
+ c = DF_BITS(df) / 2;
+
+ do {
+ y = x >> c;
+ if (y != 0) {
+ n = n - c;
+ x = y;
+ }
+ c = c >> 1;
+ } while (c != 0);
+
+ return n - x;
+}
+
+static inline int64_t msa_nloc_df(uint32_t df, int64_t arg)
+{
+ return msa_nlzc_df(df, UNSIGNED((~arg), df));
+}
+
+void helper_msa_fill_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
+ uint32_t rs)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ uint32_t i;
+
+ switch (df) {
+ case DF_BYTE:
+ for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) {
+ pwd->b[i] = (int8_t)env->active_tc.gpr[rs];
+ }
+ break;
+ case DF_HALF:
+ for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) {
+ pwd->h[i] = (int16_t)env->active_tc.gpr[rs];
+ }
+ break;
+ case DF_WORD:
+ for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) {
+ pwd->w[i] = (int32_t)env->active_tc.gpr[rs];
+ }
+ break;
+ case DF_DOUBLE:
+ for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) {
+ pwd->d[i] = (int64_t)env->active_tc.gpr[rs];
+ }
+ break;
+ default:
+ assert(0);
+ }
+}
+
+#define MSA_UNOP_DF(func) \
+void helper_msa_ ## func ## _df(CPUMIPSState *env, uint32_t df, \
+ uint32_t wd, uint32_t ws) \
+{ \
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr); \
+ uint32_t i; \
+ \
+ switch (df) { \
+ case DF_BYTE: \
+ for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) { \
+ pwd->b[i] = msa_ ## func ## _df(df, pws->b[i]); \
+ } \
+ break; \
+ case DF_HALF: \
+ for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) { \
+ pwd->h[i] = msa_ ## func ## _df(df, pws->h[i]); \
+ } \
+ break; \
+ case DF_WORD: \
+ for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { \
+ pwd->w[i] = msa_ ## func ## _df(df, pws->w[i]); \
+ } \
+ break; \
+ case DF_DOUBLE: \
+ for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { \
+ pwd->d[i] = msa_ ## func ## _df(df, pws->d[i]); \
+ } \
+ break; \
+ default: \
+ assert(0); \
+ } \
+}
+
+MSA_UNOP_DF(nlzc)
+MSA_UNOP_DF(nloc)
+MSA_UNOP_DF(pcnt)
+#undef MSA_UNOP_DF
+
#define FLOAT_ONE32 make_float32(0x3f8 << 20)
#define FLOAT_ONE64 make_float64(0x3ffULL << 52)
SET_FP_CAUSE(env->active_tc.msacsr, 0);
}
-static inline void check_msacsr_cause(CPUMIPSState *env)
+static inline void check_msacsr_cause(CPUMIPSState *env, uintptr_t retaddr)
{
if ((GET_FP_CAUSE(env->active_tc.msacsr) &
(GET_FP_ENABLE(env->active_tc.msacsr) | FP_UNIMPLEMENTED)) == 0) {
UPDATE_FP_FLAGS(env->active_tc.msacsr,
GET_FP_CAUSE(env->active_tc.msacsr));
} else {
- helper_raise_exception(env, EXCP_MSAFPE);
+ do_raise_exception(env, EXCP_MSAFPE, retaddr);
}
}
return c & enable;
}
-static inline float16 float16_from_float32(int32 a, flag ieee STATUS_PARAM)
+static inline float16 float16_from_float32(int32_t a, flag ieee,
+ float_status *status)
{
float16 f_val;
- f_val = float32_to_float16((float32)a, ieee STATUS_VAR);
+ f_val = float32_to_float16((float32)a, ieee, status);
f_val = float16_maybe_silence_nan(f_val);
return a < 0 ? (f_val | (1 << 15)) : f_val;
}
-static inline float32 float32_from_float64(int64 a STATUS_PARAM)
+static inline float32 float32_from_float64(int64_t a, float_status *status)
{
float32 f_val;
- f_val = float64_to_float32((float64)a STATUS_VAR);
+ f_val = float64_to_float32((float64)a, status);
f_val = float32_maybe_silence_nan(f_val);
return a < 0 ? (f_val | (1 << 31)) : f_val;
}
-static inline float32 float32_from_float16(int16_t a, flag ieee STATUS_PARAM)
+static inline float32 float32_from_float16(int16_t a, flag ieee,
+ float_status *status)
{
float32 f_val;
- f_val = float16_to_float32((float16)a, ieee STATUS_VAR);
+ f_val = float16_to_float32((float16)a, ieee, status);
f_val = float32_maybe_silence_nan(f_val);
return a < 0 ? (f_val | (1 << 31)) : f_val;
}
-static inline float64 float64_from_float32(int32 a STATUS_PARAM)
+static inline float64 float64_from_float32(int32_t a, float_status *status)
{
float64 f_val;
- f_val = float32_to_float64((float64)a STATUS_VAR);
+ f_val = float32_to_float64((float64)a, status);
f_val = float64_maybe_silence_nan(f_val);
return a < 0 ? (f_val | (1ULL << 63)) : f_val;
}
-static inline float32 float32_from_q16(int16_t a STATUS_PARAM)
+static inline float32 float32_from_q16(int16_t a, float_status *status)
{
float32 f_val;
/* conversion as integer and scaling */
- f_val = int32_to_float32(a STATUS_VAR);
- f_val = float32_scalbn(f_val, -15 STATUS_VAR);
+ f_val = int32_to_float32(a, status);
+ f_val = float32_scalbn(f_val, -15, status);
return f_val;
}
-static inline float64 float64_from_q32(int32 a STATUS_PARAM)
+static inline float64 float64_from_q32(int32_t a, float_status *status)
{
float64 f_val;
/* conversion as integer and scaling */
- f_val = int32_to_float64(a STATUS_VAR);
- f_val = float64_scalbn(f_val, -31 STATUS_VAR);
+ f_val = int32_to_float64(a, status);
+ f_val = float64_scalbn(f_val, -31, status);
return f_val;
}
-static inline int16_t float32_to_q16(float32 a STATUS_PARAM)
+static inline int16_t float32_to_q16(float32 a, float_status *status)
{
- int32 q_val;
- int32 q_min = 0xffff8000;
- int32 q_max = 0x00007fff;
+ int32_t q_val;
+ int32_t q_min = 0xffff8000;
+ int32_t q_max = 0x00007fff;
int ieee_ex;
if (float32_is_any_nan(a)) {
- float_raise(float_flag_invalid STATUS_VAR);
+ float_raise(float_flag_invalid, status);
return 0;
}
/* scaling */
- a = float32_scalbn(a, 15 STATUS_VAR);
+ a = float32_scalbn(a, 15, status);
ieee_ex = get_float_exception_flags(status);
set_float_exception_flags(ieee_ex & (~float_flag_underflow)
- STATUS_VAR);
+ , status);
if (ieee_ex & float_flag_overflow) {
- float_raise(float_flag_inexact STATUS_VAR);
- return (int32)a < 0 ? q_min : q_max;
+ float_raise(float_flag_inexact, status);
+ return (int32_t)a < 0 ? q_min : q_max;
}
/* conversion to int */
- q_val = float32_to_int32(a STATUS_VAR);
+ q_val = float32_to_int32(a, status);
ieee_ex = get_float_exception_flags(status);
set_float_exception_flags(ieee_ex & (~float_flag_underflow)
- STATUS_VAR);
+ , status);
if (ieee_ex & float_flag_invalid) {
set_float_exception_flags(ieee_ex & (~float_flag_invalid)
- STATUS_VAR);
- float_raise(float_flag_overflow | float_flag_inexact STATUS_VAR);
- return (int32)a < 0 ? q_min : q_max;
+ , status);
+ float_raise(float_flag_overflow | float_flag_inexact, status);
+ return (int32_t)a < 0 ? q_min : q_max;
}
if (q_val < q_min) {
- float_raise(float_flag_overflow | float_flag_inexact STATUS_VAR);
+ float_raise(float_flag_overflow | float_flag_inexact, status);
return (int16_t)q_min;
}
if (q_max < q_val) {
- float_raise(float_flag_overflow | float_flag_inexact STATUS_VAR);
+ float_raise(float_flag_overflow | float_flag_inexact, status);
return (int16_t)q_max;
}
return (int16_t)q_val;
}
-static inline int32 float64_to_q32(float64 a STATUS_PARAM)
+static inline int32_t float64_to_q32(float64 a, float_status *status)
{
- int64 q_val;
- int64 q_min = 0xffffffff80000000LL;
- int64 q_max = 0x000000007fffffffLL;
+ int64_t q_val;
+ int64_t q_min = 0xffffffff80000000LL;
+ int64_t q_max = 0x000000007fffffffLL;
int ieee_ex;
if (float64_is_any_nan(a)) {
- float_raise(float_flag_invalid STATUS_VAR);
+ float_raise(float_flag_invalid, status);
return 0;
}
/* scaling */
- a = float64_scalbn(a, 31 STATUS_VAR);
+ a = float64_scalbn(a, 31, status);
ieee_ex = get_float_exception_flags(status);
set_float_exception_flags(ieee_ex & (~float_flag_underflow)
- STATUS_VAR);
+ , status);
if (ieee_ex & float_flag_overflow) {
- float_raise(float_flag_inexact STATUS_VAR);
- return (int64)a < 0 ? q_min : q_max;
+ float_raise(float_flag_inexact, status);
+ return (int64_t)a < 0 ? q_min : q_max;
}
/* conversion to integer */
- q_val = float64_to_int64(a STATUS_VAR);
+ q_val = float64_to_int64(a, status);
ieee_ex = get_float_exception_flags(status);
set_float_exception_flags(ieee_ex & (~float_flag_underflow)
- STATUS_VAR);
+ , status);
if (ieee_ex & float_flag_invalid) {
set_float_exception_flags(ieee_ex & (~float_flag_invalid)
- STATUS_VAR);
- float_raise(float_flag_overflow | float_flag_inexact STATUS_VAR);
- return (int64)a < 0 ? q_min : q_max;
+ , status);
+ float_raise(float_flag_overflow | float_flag_inexact, status);
+ return (int64_t)a < 0 ? q_min : q_max;
}
if (q_val < q_min) {
- float_raise(float_flag_overflow | float_flag_inexact STATUS_VAR);
- return (int32)q_min;
+ float_raise(float_flag_overflow | float_flag_inexact, status);
+ return (int32_t)q_min;
}
if (q_max < q_val) {
- float_raise(float_flag_overflow | float_flag_inexact STATUS_VAR);
- return (int32)q_max;
+ float_raise(float_flag_overflow | float_flag_inexact, status);
+ return (int32_t)q_max;
}
- return (int32)q_val;
+ return (int32_t)q_val;
}
#define MSA_FLOAT_COND(DEST, OP, ARG1, ARG2, BITS, QUIET) \
do { \
+ float_status *status = &env->active_tc.msa_fp_status; \
int c; \
int64_t cond; \
- set_float_exception_flags(0, &env->active_tc.msa_fp_status); \
+ set_float_exception_flags(0, status); \
if (!QUIET) { \
- cond = float ## BITS ## _ ## OP(ARG1, ARG2, \
- &env->active_tc.msa_fp_status); \
+ cond = float ## BITS ## _ ## OP(ARG1, ARG2, status); \
} else { \
- cond = float ## BITS ## _ ## OP ## _quiet(ARG1, ARG2, \
- &env->active_tc.msa_fp_status); \
+ cond = float ## BITS ## _ ## OP ## _quiet(ARG1, ARG2, status); \
} \
DEST = cond ? M_MAX_UINT(BITS) : 0; \
c = update_msacsr(env, CLEAR_IS_INEXACT, 0); \
} while (0)
static inline void compare_af(CPUMIPSState *env, wr_t *pwd, wr_t *pws,
- wr_t *pwt, uint32_t df, int quiet)
+ wr_t *pwt, uint32_t df, int quiet,
+ uintptr_t retaddr)
{
wr_t wx, *pwx = &wx;
uint32_t i;
assert(0);
}
- check_msacsr_cause(env);
+ check_msacsr_cause(env, retaddr);
msa_move_v(pwd, pwx);
}
static inline void compare_un(CPUMIPSState *env, wr_t *pwd, wr_t *pws,
- wr_t *pwt, uint32_t df, int quiet)
+ wr_t *pwt, uint32_t df, int quiet,
+ uintptr_t retaddr)
{
wr_t wx, *pwx = &wx;
uint32_t i;
assert(0);
}
- check_msacsr_cause(env);
+ check_msacsr_cause(env, retaddr);
msa_move_v(pwd, pwx);
}
static inline void compare_eq(CPUMIPSState *env, wr_t *pwd, wr_t *pws,
- wr_t *pwt, uint32_t df, int quiet)
+ wr_t *pwt, uint32_t df, int quiet,
+ uintptr_t retaddr)
{
wr_t wx, *pwx = &wx;
uint32_t i;
assert(0);
}
- check_msacsr_cause(env);
+ check_msacsr_cause(env, retaddr);
msa_move_v(pwd, pwx);
}
static inline void compare_ueq(CPUMIPSState *env, wr_t *pwd, wr_t *pws,
- wr_t *pwt, uint32_t df, int quiet)
+ wr_t *pwt, uint32_t df, int quiet,
+ uintptr_t retaddr)
{
wr_t wx, *pwx = &wx;
uint32_t i;
assert(0);
}
- check_msacsr_cause(env);
+ check_msacsr_cause(env, retaddr);
msa_move_v(pwd, pwx);
}
static inline void compare_lt(CPUMIPSState *env, wr_t *pwd, wr_t *pws,
- wr_t *pwt, uint32_t df, int quiet)
+ wr_t *pwt, uint32_t df, int quiet,
+ uintptr_t retaddr)
{
wr_t wx, *pwx = &wx;
uint32_t i;
assert(0);
}
- check_msacsr_cause(env);
+ check_msacsr_cause(env, retaddr);
msa_move_v(pwd, pwx);
}
static inline void compare_ult(CPUMIPSState *env, wr_t *pwd, wr_t *pws,
- wr_t *pwt, uint32_t df, int quiet)
+ wr_t *pwt, uint32_t df, int quiet,
+ uintptr_t retaddr)
{
wr_t wx, *pwx = &wx;
uint32_t i;
assert(0);
}
- check_msacsr_cause(env);
+ check_msacsr_cause(env, retaddr);
msa_move_v(pwd, pwx);
}
static inline void compare_le(CPUMIPSState *env, wr_t *pwd, wr_t *pws,
- wr_t *pwt, uint32_t df, int quiet)
+ wr_t *pwt, uint32_t df, int quiet,
+ uintptr_t retaddr)
{
wr_t wx, *pwx = &wx;
uint32_t i;
assert(0);
}
- check_msacsr_cause(env);
+ check_msacsr_cause(env, retaddr);
msa_move_v(pwd, pwx);
}
static inline void compare_ule(CPUMIPSState *env, wr_t *pwd, wr_t *pws,
- wr_t *pwt, uint32_t df, int quiet)
+ wr_t *pwt, uint32_t df, int quiet,
+ uintptr_t retaddr)
{
wr_t wx, *pwx = &wx;
uint32_t i;
assert(0);
}
- check_msacsr_cause(env);
+ check_msacsr_cause(env, retaddr);
msa_move_v(pwd, pwx);
}
static inline void compare_or(CPUMIPSState *env, wr_t *pwd, wr_t *pws,
- wr_t *pwt, uint32_t df, int quiet)
+ wr_t *pwt, uint32_t df, int quiet,
+ uintptr_t retaddr)
{
wr_t wx, *pwx = &wx;
uint32_t i;
assert(0);
}
- check_msacsr_cause(env);
+ check_msacsr_cause(env, retaddr);
msa_move_v(pwd, pwx);
}
static inline void compare_une(CPUMIPSState *env, wr_t *pwd, wr_t *pws,
- wr_t *pwt, uint32_t df, int quiet)
+ wr_t *pwt, uint32_t df, int quiet,
+ uintptr_t retaddr)
{
wr_t wx, *pwx = &wx;
uint32_t i;
assert(0);
}
- check_msacsr_cause(env);
+ check_msacsr_cause(env, retaddr);
msa_move_v(pwd, pwx);
}
static inline void compare_ne(CPUMIPSState *env, wr_t *pwd, wr_t *pws,
- wr_t *pwt, uint32_t df, int quiet) {
+ wr_t *pwt, uint32_t df, int quiet,
+ uintptr_t retaddr)
+{
wr_t wx, *pwx = &wx;
uint32_t i;
assert(0);
}
- check_msacsr_cause(env);
+ check_msacsr_cause(env, retaddr);
msa_move_v(pwd, pwx);
}
wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
wr_t *pws = &(env->active_fpu.fpr[ws].wr);
wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
- compare_af(env, pwd, pws, pwt, df, 1);
+ compare_af(env, pwd, pws, pwt, df, 1, GETPC());
}
void helper_msa_fcun_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
wr_t *pws = &(env->active_fpu.fpr[ws].wr);
wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
- compare_un(env, pwd, pws, pwt, df, 1);
+ compare_un(env, pwd, pws, pwt, df, 1, GETPC());
}
void helper_msa_fceq_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
wr_t *pws = &(env->active_fpu.fpr[ws].wr);
wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
- compare_eq(env, pwd, pws, pwt, df, 1);
+ compare_eq(env, pwd, pws, pwt, df, 1, GETPC());
}
void helper_msa_fcueq_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
wr_t *pws = &(env->active_fpu.fpr[ws].wr);
wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
- compare_ueq(env, pwd, pws, pwt, df, 1);
+ compare_ueq(env, pwd, pws, pwt, df, 1, GETPC());
}
void helper_msa_fclt_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
wr_t *pws = &(env->active_fpu.fpr[ws].wr);
wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
- compare_lt(env, pwd, pws, pwt, df, 1);
+ compare_lt(env, pwd, pws, pwt, df, 1, GETPC());
}
void helper_msa_fcult_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
wr_t *pws = &(env->active_fpu.fpr[ws].wr);
wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
- compare_ult(env, pwd, pws, pwt, df, 1);
+ compare_ult(env, pwd, pws, pwt, df, 1, GETPC());
}
void helper_msa_fcle_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
wr_t *pws = &(env->active_fpu.fpr[ws].wr);
wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
- compare_le(env, pwd, pws, pwt, df, 1);
+ compare_le(env, pwd, pws, pwt, df, 1, GETPC());
}
void helper_msa_fcule_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
wr_t *pws = &(env->active_fpu.fpr[ws].wr);
wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
- compare_ule(env, pwd, pws, pwt, df, 1);
+ compare_ule(env, pwd, pws, pwt, df, 1, GETPC());
}
void helper_msa_fsaf_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
wr_t *pws = &(env->active_fpu.fpr[ws].wr);
wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
- compare_af(env, pwd, pws, pwt, df, 0);
+ compare_af(env, pwd, pws, pwt, df, 0, GETPC());
}
void helper_msa_fsun_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
wr_t *pws = &(env->active_fpu.fpr[ws].wr);
wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
- compare_un(env, pwd, pws, pwt, df, 0);
+ compare_un(env, pwd, pws, pwt, df, 0, GETPC());
}
void helper_msa_fseq_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
wr_t *pws = &(env->active_fpu.fpr[ws].wr);
wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
- compare_eq(env, pwd, pws, pwt, df, 0);
+ compare_eq(env, pwd, pws, pwt, df, 0, GETPC());
}
void helper_msa_fsueq_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
wr_t *pws = &(env->active_fpu.fpr[ws].wr);
wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
- compare_ueq(env, pwd, pws, pwt, df, 0);
+ compare_ueq(env, pwd, pws, pwt, df, 0, GETPC());
}
void helper_msa_fslt_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
wr_t *pws = &(env->active_fpu.fpr[ws].wr);
wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
- compare_lt(env, pwd, pws, pwt, df, 0);
+ compare_lt(env, pwd, pws, pwt, df, 0, GETPC());
}
void helper_msa_fsult_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
wr_t *pws = &(env->active_fpu.fpr[ws].wr);
wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
- compare_ult(env, pwd, pws, pwt, df, 0);
+ compare_ult(env, pwd, pws, pwt, df, 0, GETPC());
}
void helper_msa_fsle_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
wr_t *pws = &(env->active_fpu.fpr[ws].wr);
wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
- compare_le(env, pwd, pws, pwt, df, 0);
+ compare_le(env, pwd, pws, pwt, df, 0, GETPC());
}
void helper_msa_fsule_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
wr_t *pws = &(env->active_fpu.fpr[ws].wr);
wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
- compare_ule(env, pwd, pws, pwt, df, 0);
+ compare_ule(env, pwd, pws, pwt, df, 0, GETPC());
}
void helper_msa_fcor_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
wr_t *pws = &(env->active_fpu.fpr[ws].wr);
wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
- compare_or(env, pwd, pws, pwt, df, 1);
+ compare_or(env, pwd, pws, pwt, df, 1, GETPC());
}
void helper_msa_fcune_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
wr_t *pws = &(env->active_fpu.fpr[ws].wr);
wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
- compare_une(env, pwd, pws, pwt, df, 1);
+ compare_une(env, pwd, pws, pwt, df, 1, GETPC());
}
void helper_msa_fcne_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
wr_t *pws = &(env->active_fpu.fpr[ws].wr);
wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
- compare_ne(env, pwd, pws, pwt, df, 1);
+ compare_ne(env, pwd, pws, pwt, df, 1, GETPC());
}
void helper_msa_fsor_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
wr_t *pws = &(env->active_fpu.fpr[ws].wr);
wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
- compare_or(env, pwd, pws, pwt, df, 0);
+ compare_or(env, pwd, pws, pwt, df, 0, GETPC());
}
void helper_msa_fsune_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
wr_t *pws = &(env->active_fpu.fpr[ws].wr);
wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
- compare_une(env, pwd, pws, pwt, df, 0);
+ compare_une(env, pwd, pws, pwt, df, 0, GETPC());
}
void helper_msa_fsne_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
wr_t *pws = &(env->active_fpu.fpr[ws].wr);
wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
- compare_ne(env, pwd, pws, pwt, df, 0);
+ compare_ne(env, pwd, pws, pwt, df, 0, GETPC());
}
#define float16_is_zero(ARG) 0
#define MSA_FLOAT_BINOP(DEST, OP, ARG1, ARG2, BITS) \
do { \
+ float_status *status = &env->active_tc.msa_fp_status; \
int c; \
\
- set_float_exception_flags(0, &env->active_tc.msa_fp_status); \
- DEST = float ## BITS ## _ ## OP(ARG1, ARG2, \
- &env->active_tc.msa_fp_status); \
+ set_float_exception_flags(0, status); \
+ DEST = float ## BITS ## _ ## OP(ARG1, ARG2, status); \
c = update_msacsr(env, 0, IS_DENORMAL(DEST, BITS)); \
\
if (get_enabled_exceptions(env, c)) { \
assert(0);
}
- check_msacsr_cause(env);
+ check_msacsr_cause(env, GETPC());
msa_move_v(pwd, pwx);
}
assert(0);
}
- check_msacsr_cause(env);
+ check_msacsr_cause(env, GETPC());
msa_move_v(pwd, pwx);
}
assert(0);
}
- check_msacsr_cause(env);
+ check_msacsr_cause(env, GETPC());
msa_move_v(pwd, pwx);
}
assert(0);
}
- check_msacsr_cause(env);
+ check_msacsr_cause(env, GETPC());
msa_move_v(pwd, pwx);
}
#define MSA_FLOAT_MULADD(DEST, ARG1, ARG2, ARG3, NEGATE, BITS) \
do { \
+ float_status *status = &env->active_tc.msa_fp_status; \
int c; \
\
- set_float_exception_flags(0, &env->active_tc.msa_fp_status); \
- DEST = float ## BITS ## _muladd(ARG2, ARG3, ARG1, NEGATE, \
- &env->active_tc.msa_fp_status); \
+ set_float_exception_flags(0, status); \
+ DEST = float ## BITS ## _muladd(ARG2, ARG3, ARG1, NEGATE, status); \
c = update_msacsr(env, 0, IS_DENORMAL(DEST, BITS)); \
\
if (get_enabled_exceptions(env, c)) { \
assert(0);
}
- check_msacsr_cause(env);
+ check_msacsr_cause(env, GETPC());
msa_move_v(pwd, pwx);
}
assert(0);
}
- check_msacsr_cause(env);
+ check_msacsr_cause(env, GETPC());
msa_move_v(pwd, pwx);
}
assert(0);
}
- check_msacsr_cause(env);
+ check_msacsr_cause(env, GETPC());
msa_move_v(pwd, pwx);
}
#define MSA_FLOAT_UNOP(DEST, OP, ARG, BITS) \
do { \
+ float_status *status = &env->active_tc.msa_fp_status; \
int c; \
\
- set_float_exception_flags(0, &env->active_tc.msa_fp_status); \
- DEST = float ## BITS ## _ ## OP(ARG, &env->active_tc.msa_fp_status);\
+ set_float_exception_flags(0, status); \
+ DEST = float ## BITS ## _ ## OP(ARG, status); \
c = update_msacsr(env, 0, IS_DENORMAL(DEST, BITS)); \
\
if (get_enabled_exceptions(env, c)) { \
wr_t *pwt = &(env->active_fpu.fpr[wt].wr);
uint32_t i;
+ clear_msacsr_cause(env);
+
switch (df) {
case DF_WORD:
for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) {
assert(0);
}
- check_msacsr_cause(env);
+ check_msacsr_cause(env, GETPC());
msa_move_v(pwd, pwx);
}
#define MSA_FLOAT_UNOP_XD(DEST, OP, ARG, BITS, XBITS) \
do { \
+ float_status *status = &env->active_tc.msa_fp_status; \
int c; \
\
- set_float_exception_flags(0, &env->active_tc.msa_fp_status); \
- DEST = float ## BITS ## _ ## OP(ARG, &env->active_tc.msa_fp_status);\
+ set_float_exception_flags(0, status); \
+ DEST = float ## BITS ## _ ## OP(ARG, status); \
c = update_msacsr(env, CLEAR_FS_UNDERFLOW, 0); \
\
if (get_enabled_exceptions(env, c)) { \
assert(0);
}
- check_msacsr_cause(env);
+ check_msacsr_cause(env, GETPC());
msa_move_v(pwd, pwx);
}
#define MSA_FLOAT_MAXOP(DEST, OP, ARG1, ARG2, BITS) \
do { \
+ float_status *status = &env->active_tc.msa_fp_status; \
int c; \
\
- set_float_exception_flags(0, &env->active_tc.msa_fp_status); \
- DEST = float ## BITS ## _ ## OP(ARG1, ARG2, \
- &env->active_tc.msa_fp_status); \
+ set_float_exception_flags(0, status); \
+ DEST = float ## BITS ## _ ## OP(ARG1, ARG2, status); \
c = update_msacsr(env, 0, 0); \
\
if (get_enabled_exceptions(env, c)) { \
assert(0);
}
- check_msacsr_cause(env);
+ check_msacsr_cause(env, GETPC());
msa_move_v(pwd, pwx);
}
assert(0);
}
- check_msacsr_cause(env);
+ check_msacsr_cause(env, GETPC());
msa_move_v(pwd, pwx);
}
assert(0);
}
- check_msacsr_cause(env);
+ check_msacsr_cause(env, GETPC());
msa_move_v(pwd, pwx);
}
assert(0);
}
- check_msacsr_cause(env);
+ check_msacsr_cause(env, GETPC());
+
+ msa_move_v(pwd, pwx);
+}
+
+void helper_msa_fclass_df(CPUMIPSState *env, uint32_t df,
+ uint32_t wd, uint32_t ws)
+{
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ if (df == DF_WORD) {
+ pwd->w[0] = helper_float_class_s(pws->w[0]);
+ pwd->w[1] = helper_float_class_s(pws->w[1]);
+ pwd->w[2] = helper_float_class_s(pws->w[2]);
+ pwd->w[3] = helper_float_class_s(pws->w[3]);
+ } else {
+ pwd->d[0] = helper_float_class_d(pws->d[0]);
+ pwd->d[1] = helper_float_class_d(pws->d[1]);
+ }
+}
+
+#define MSA_FLOAT_UNOP0(DEST, OP, ARG, BITS) \
+ do { \
+ float_status *status = &env->active_tc.msa_fp_status; \
+ int c; \
+ \
+ set_float_exception_flags(0, status); \
+ DEST = float ## BITS ## _ ## OP(ARG, status); \
+ c = update_msacsr(env, CLEAR_FS_UNDERFLOW, 0); \
+ \
+ if (get_enabled_exceptions(env, c)) { \
+ DEST = ((FLOAT_SNAN ## BITS >> 6) << 6) | c; \
+ } else if (float ## BITS ## _is_any_nan(ARG)) { \
+ DEST = 0; \
+ } \
+ } while (0)
+
+void helper_msa_ftrunc_s_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
+ uint32_t ws)
+{
+ wr_t wx, *pwx = &wx;
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ uint32_t i;
+
+ clear_msacsr_cause(env);
+
+ switch (df) {
+ case DF_WORD:
+ for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) {
+ MSA_FLOAT_UNOP0(pwx->w[i], to_int32_round_to_zero, pws->w[i], 32);
+ }
+ break;
+ case DF_DOUBLE:
+ for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) {
+ MSA_FLOAT_UNOP0(pwx->d[i], to_int64_round_to_zero, pws->d[i], 64);
+ }
+ break;
+ default:
+ assert(0);
+ }
+
+ check_msacsr_cause(env, GETPC());
+
+ msa_move_v(pwd, pwx);
+}
+
+void helper_msa_ftrunc_u_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
+ uint32_t ws)
+{
+ wr_t wx, *pwx = &wx;
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ uint32_t i;
+
+ clear_msacsr_cause(env);
+
+ switch (df) {
+ case DF_WORD:
+ for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) {
+ MSA_FLOAT_UNOP0(pwx->w[i], to_uint32_round_to_zero, pws->w[i], 32);
+ }
+ break;
+ case DF_DOUBLE:
+ for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) {
+ MSA_FLOAT_UNOP0(pwx->d[i], to_uint64_round_to_zero, pws->d[i], 64);
+ }
+ break;
+ default:
+ assert(0);
+ }
+
+ check_msacsr_cause(env, GETPC());
+
+ msa_move_v(pwd, pwx);
+}
+
+void helper_msa_fsqrt_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
+ uint32_t ws)
+{
+ wr_t wx, *pwx = &wx;
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ uint32_t i;
+
+ clear_msacsr_cause(env);
+
+ switch (df) {
+ case DF_WORD:
+ for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) {
+ MSA_FLOAT_UNOP(pwx->w[i], sqrt, pws->w[i], 32);
+ }
+ break;
+ case DF_DOUBLE:
+ for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) {
+ MSA_FLOAT_UNOP(pwx->d[i], sqrt, pws->d[i], 64);
+ }
+ break;
+ default:
+ assert(0);
+ }
+
+ check_msacsr_cause(env, GETPC());
+
+ msa_move_v(pwd, pwx);
+}
+
+#define MSA_FLOAT_RECIPROCAL(DEST, ARG, BITS) \
+ do { \
+ float_status *status = &env->active_tc.msa_fp_status; \
+ int c; \
+ \
+ set_float_exception_flags(0, status); \
+ DEST = float ## BITS ## _ ## div(FLOAT_ONE ## BITS, ARG, status); \
+ c = update_msacsr(env, float ## BITS ## _is_infinity(ARG) || \
+ float ## BITS ## _is_quiet_nan(DEST) ? \
+ 0 : RECIPROCAL_INEXACT, \
+ IS_DENORMAL(DEST, BITS)); \
+ \
+ if (get_enabled_exceptions(env, c)) { \
+ DEST = ((FLOAT_SNAN ## BITS >> 6) << 6) | c; \
+ } \
+ } while (0)
+
+void helper_msa_frsqrt_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
+ uint32_t ws)
+{
+ wr_t wx, *pwx = &wx;
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ uint32_t i;
+
+ clear_msacsr_cause(env);
+
+ switch (df) {
+ case DF_WORD:
+ for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) {
+ MSA_FLOAT_RECIPROCAL(pwx->w[i], float32_sqrt(pws->w[i],
+ &env->active_tc.msa_fp_status), 32);
+ }
+ break;
+ case DF_DOUBLE:
+ for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) {
+ MSA_FLOAT_RECIPROCAL(pwx->d[i], float64_sqrt(pws->d[i],
+ &env->active_tc.msa_fp_status), 64);
+ }
+ break;
+ default:
+ assert(0);
+ }
+
+ check_msacsr_cause(env, GETPC());
+
+ msa_move_v(pwd, pwx);
+}
+
+void helper_msa_frcp_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
+ uint32_t ws)
+{
+ wr_t wx, *pwx = &wx;
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ uint32_t i;
+
+ clear_msacsr_cause(env);
+
+ switch (df) {
+ case DF_WORD:
+ for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) {
+ MSA_FLOAT_RECIPROCAL(pwx->w[i], pws->w[i], 32);
+ }
+ break;
+ case DF_DOUBLE:
+ for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) {
+ MSA_FLOAT_RECIPROCAL(pwx->d[i], pws->d[i], 64);
+ }
+ break;
+ default:
+ assert(0);
+ }
+
+ check_msacsr_cause(env, GETPC());
+
+ msa_move_v(pwd, pwx);
+}
+
+void helper_msa_frint_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
+ uint32_t ws)
+{
+ wr_t wx, *pwx = &wx;
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ uint32_t i;
+
+ clear_msacsr_cause(env);
+
+ switch (df) {
+ case DF_WORD:
+ for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) {
+ MSA_FLOAT_UNOP(pwx->w[i], round_to_int, pws->w[i], 32);
+ }
+ break;
+ case DF_DOUBLE:
+ for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) {
+ MSA_FLOAT_UNOP(pwx->d[i], round_to_int, pws->d[i], 64);
+ }
+ break;
+ default:
+ assert(0);
+ }
+
+ check_msacsr_cause(env, GETPC());
+
+ msa_move_v(pwd, pwx);
+}
+
+#define MSA_FLOAT_LOGB(DEST, ARG, BITS) \
+ do { \
+ float_status *status = &env->active_tc.msa_fp_status; \
+ int c; \
+ \
+ set_float_exception_flags(0, status); \
+ set_float_rounding_mode(float_round_down, status); \
+ DEST = float ## BITS ## _ ## log2(ARG, status); \
+ DEST = float ## BITS ## _ ## round_to_int(DEST, status); \
+ set_float_rounding_mode(ieee_rm[(env->active_tc.msacsr & \
+ MSACSR_RM_MASK) >> MSACSR_RM], \
+ status); \
+ \
+ set_float_exception_flags(get_float_exception_flags(status) & \
+ (~float_flag_inexact), \
+ status); \
+ \
+ c = update_msacsr(env, 0, IS_DENORMAL(DEST, BITS)); \
+ \
+ if (get_enabled_exceptions(env, c)) { \
+ DEST = ((FLOAT_SNAN ## BITS >> 6) << 6) | c; \
+ } \
+ } while (0)
+
+void helper_msa_flog2_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
+ uint32_t ws)
+{
+ wr_t wx, *pwx = &wx;
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ uint32_t i;
+
+ clear_msacsr_cause(env);
+
+ switch (df) {
+ case DF_WORD:
+ for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) {
+ MSA_FLOAT_LOGB(pwx->w[i], pws->w[i], 32);
+ }
+ break;
+ case DF_DOUBLE:
+ for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) {
+ MSA_FLOAT_LOGB(pwx->d[i], pws->d[i], 64);
+ }
+ break;
+ default:
+ assert(0);
+ }
+
+ check_msacsr_cause(env, GETPC());
+
+ msa_move_v(pwd, pwx);
+}
+
+void helper_msa_fexupl_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
+ uint32_t ws)
+{
+ wr_t wx, *pwx = &wx;
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ uint32_t i;
+
+ clear_msacsr_cause(env);
+
+ switch (df) {
+ case DF_WORD:
+ for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) {
+ /* Half precision floats come in two formats: standard
+ IEEE and "ARM" format. The latter gains extra exponent
+ range by omitting the NaN/Inf encodings. */
+ flag ieee = 1;
+
+ MSA_FLOAT_BINOP(pwx->w[i], from_float16, Lh(pws, i), ieee, 32);
+ }
+ break;
+ case DF_DOUBLE:
+ for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) {
+ MSA_FLOAT_UNOP(pwx->d[i], from_float32, Lw(pws, i), 64);
+ }
+ break;
+ default:
+ assert(0);
+ }
+
+ check_msacsr_cause(env, GETPC());
+ msa_move_v(pwd, pwx);
+}
+
+void helper_msa_fexupr_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
+ uint32_t ws)
+{
+ wr_t wx, *pwx = &wx;
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ uint32_t i;
+
+ clear_msacsr_cause(env);
+
+ switch (df) {
+ case DF_WORD:
+ for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) {
+ /* Half precision floats come in two formats: standard
+ IEEE and "ARM" format. The latter gains extra exponent
+ range by omitting the NaN/Inf encodings. */
+ flag ieee = 1;
+
+ MSA_FLOAT_BINOP(pwx->w[i], from_float16, Rh(pws, i), ieee, 32);
+ }
+ break;
+ case DF_DOUBLE:
+ for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) {
+ MSA_FLOAT_UNOP(pwx->d[i], from_float32, Rw(pws, i), 64);
+ }
+ break;
+ default:
+ assert(0);
+ }
+
+ check_msacsr_cause(env, GETPC());
+ msa_move_v(pwd, pwx);
+}
+
+void helper_msa_ffql_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
+ uint32_t ws)
+{
+ wr_t wx, *pwx = &wx;
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ uint32_t i;
+
+ switch (df) {
+ case DF_WORD:
+ for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) {
+ MSA_FLOAT_UNOP(pwx->w[i], from_q16, Lh(pws, i), 32);
+ }
+ break;
+ case DF_DOUBLE:
+ for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) {
+ MSA_FLOAT_UNOP(pwx->d[i], from_q32, Lw(pws, i), 64);
+ }
+ break;
+ default:
+ assert(0);
+ }
+
+ msa_move_v(pwd, pwx);
+}
+
+void helper_msa_ffqr_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
+ uint32_t ws)
+{
+ wr_t wx, *pwx = &wx;
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ uint32_t i;
+
+ switch (df) {
+ case DF_WORD:
+ for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) {
+ MSA_FLOAT_UNOP(pwx->w[i], from_q16, Rh(pws, i), 32);
+ }
+ break;
+ case DF_DOUBLE:
+ for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) {
+ MSA_FLOAT_UNOP(pwx->d[i], from_q32, Rw(pws, i), 64);
+ }
+ break;
+ default:
+ assert(0);
+ }
+
+ msa_move_v(pwd, pwx);
+}
+
+void helper_msa_ftint_s_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
+ uint32_t ws)
+{
+ wr_t wx, *pwx = &wx;
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ uint32_t i;
+
+ clear_msacsr_cause(env);
+
+ switch (df) {
+ case DF_WORD:
+ for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) {
+ MSA_FLOAT_UNOP0(pwx->w[i], to_int32, pws->w[i], 32);
+ }
+ break;
+ case DF_DOUBLE:
+ for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) {
+ MSA_FLOAT_UNOP0(pwx->d[i], to_int64, pws->d[i], 64);
+ }
+ break;
+ default:
+ assert(0);
+ }
+
+ check_msacsr_cause(env, GETPC());
+
+ msa_move_v(pwd, pwx);
+}
+
+void helper_msa_ftint_u_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
+ uint32_t ws)
+{
+ wr_t wx, *pwx = &wx;
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ uint32_t i;
+
+ clear_msacsr_cause(env);
+
+ switch (df) {
+ case DF_WORD:
+ for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) {
+ MSA_FLOAT_UNOP0(pwx->w[i], to_uint32, pws->w[i], 32);
+ }
+ break;
+ case DF_DOUBLE:
+ for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) {
+ MSA_FLOAT_UNOP0(pwx->d[i], to_uint64, pws->d[i], 64);
+ }
+ break;
+ default:
+ assert(0);
+ }
+
+ check_msacsr_cause(env, GETPC());
+
+ msa_move_v(pwd, pwx);
+}
+
+#define float32_from_int32 int32_to_float32
+#define float32_from_uint32 uint32_to_float32
+
+#define float64_from_int64 int64_to_float64
+#define float64_from_uint64 uint64_to_float64
+
+void helper_msa_ffint_s_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
+ uint32_t ws)
+{
+ wr_t wx, *pwx = &wx;
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ uint32_t i;
+
+ clear_msacsr_cause(env);
+
+ switch (df) {
+ case DF_WORD:
+ for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) {
+ MSA_FLOAT_UNOP(pwx->w[i], from_int32, pws->w[i], 32);
+ }
+ break;
+ case DF_DOUBLE:
+ for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) {
+ MSA_FLOAT_UNOP(pwx->d[i], from_int64, pws->d[i], 64);
+ }
+ break;
+ default:
+ assert(0);
+ }
+
+ check_msacsr_cause(env, GETPC());
+
+ msa_move_v(pwd, pwx);
+}
+
+void helper_msa_ffint_u_df(CPUMIPSState *env, uint32_t df, uint32_t wd,
+ uint32_t ws)
+{
+ wr_t wx, *pwx = &wx;
+ wr_t *pwd = &(env->active_fpu.fpr[wd].wr);
+ wr_t *pws = &(env->active_fpu.fpr[ws].wr);
+ uint32_t i;
+
+ clear_msacsr_cause(env);
+
+ switch (df) {
+ case DF_WORD:
+ for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) {
+ MSA_FLOAT_UNOP(pwx->w[i], from_uint32, pws->w[i], 32);
+ }
+ break;
+ case DF_DOUBLE:
+ for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) {
+ MSA_FLOAT_UNOP(pwx->d[i], from_uint64, pws->d[i], 64);
+ }
+ break;
+ default:
+ assert(0);
+ }
+
+ check_msacsr_cause(env, GETPC());
msa_move_v(pwd, pwx);
}