From patchwork Mon Jul 14 09:55:58 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yongbok Kim X-Patchwork-Id: 369560 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id A61B5140096 for ; Mon, 14 Jul 2014 20:01:55 +1000 (EST) Received: from localhost ([::1]:55552 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1X6d4z-00034M-Fi for incoming@patchwork.ozlabs.org; Mon, 14 Jul 2014 06:01:53 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:40471) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1X6czj-0003Id-Ee for qemu-devel@nongnu.org; Mon, 14 Jul 2014 05:56:34 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1X6czc-0003iF-R4 for qemu-devel@nongnu.org; Mon, 14 Jul 2014 05:56:27 -0400 Received: from mailapp01.imgtec.com ([195.59.15.196]:55464) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1X6czc-0003hd-Ai for qemu-devel@nongnu.org; Mon, 14 Jul 2014 05:56:20 -0400 Received: from KLMAIL01.kl.imgtec.org (unknown [192.168.5.35]) by Websense Email Security Gateway with ESMTPS id A0462953ABB1E; Mon, 14 Jul 2014 10:56:14 +0100 (IST) Received: from localhost.localdomain (192.168.14.85) by KLMAIL01.kl.imgtec.org (192.168.5.35) with Microsoft SMTP Server (TLS) id 14.3.195.1; Mon, 14 Jul 2014 10:56:16 +0100 From: Yongbok Kim To: Date: Mon, 14 Jul 2014 10:55:58 +0100 Message-ID: <1405331763-57126-16-git-send-email-yongbok.kim@imgtec.com> X-Mailer: git-send-email 1.7.4 In-Reply-To: <1405331763-57126-1-git-send-email-yongbok.kim@imgtec.com> References: <1405331763-57126-1-git-send-email-yongbok.kim@imgtec.com> MIME-Version: 1.0 X-Originating-IP: [192.168.14.85] X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 195.59.15.196 Cc: yongbok.kim@imgtec.com, cristian.cuna@imgtec.com, leon.alrae@imgtec.com, aurelien@aurel32.net Subject: [Qemu-devel] [PATCH 15/20] target-mips: add MSA 3RF format instructions X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org add MSA 3RF format instructions Signed-off-by: Yongbok Kim --- target-mips/helper.h | 41 ++ target-mips/msa_helper.c | 1575 +++++++++++++++++++++++++++++++++++++++++++++- target-mips/translate.c | 203 ++++++ 3 files changed, 1816 insertions(+), 3 deletions(-) diff --git a/target-mips/helper.h b/target-mips/helper.h index e13daec..fec21b6 100644 --- a/target-mips/helper.h +++ b/target-mips/helper.h @@ -740,6 +740,41 @@ DEF_HELPER_5(msa_dpadd_s_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_dpadd_u_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_dpsub_s_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_dpsub_u_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fadd_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fcaf_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fceq_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fcle_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fclt_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fcne_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fcor_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fcueq_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fcule_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fcult_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fcun_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fcune_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fdiv_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fexdo_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fexp2_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fmadd_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fmax_a_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fmax_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fmin_a_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fmin_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fmsub_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fmul_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fsaf_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fseq_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fsle_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fslt_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fsne_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fsor_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fsub_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fsueq_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fsule_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fsult_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fsun_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_fsune_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_ftq_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_hadd_s_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_hadd_u_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_hsub_s_df, void, env, i32, i32, i32, i32) @@ -751,6 +786,8 @@ DEF_HELPER_5(msa_ilvr_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_insert_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_insve_df, void, env, i32, i32, i32, i32) DEF_HELPER_4(msa_ldi_df, void, env, i32, i32, i32) +DEF_HELPER_5(msa_madd_q_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_maddr_q_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_maddv_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_max_a_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_max_s_df, void, env, i32, i32, i32, i32) @@ -765,7 +802,11 @@ DEF_HELPER_5(msa_mini_u_df, void, env, i32, i32, i32, s64) DEF_HELPER_5(msa_mod_s_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_mod_u_df, void, env, i32, i32, i32, i32) DEF_HELPER_3(msa_move_v, void, env, i32, i32) +DEF_HELPER_5(msa_msub_q_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_msubr_q_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_msubv_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_mul_q_df, void, env, i32, i32, i32, i32) +DEF_HELPER_5(msa_mulr_q_df, void, env, i32, i32, i32, i32) DEF_HELPER_5(msa_mulv_df, void, env, i32, i32, i32, i32) DEF_HELPER_4(msa_nori_b, void, env, i32, i32, i32) DEF_HELPER_4(msa_ori_b, void, env, i32, i32, i32) diff --git a/target-mips/msa_helper.c b/target-mips/msa_helper.c index 220a0cd..bb4ab66 100644 --- a/target-mips/msa_helper.c +++ b/target-mips/msa_helper.c @@ -2793,6 +2793,1578 @@ void helper_msa_sldi_df(CPUMIPSState *env, uint32_t df, uint32_t wd, } } +static inline int64_t msa_mul_q_df(CPUMIPSState *env, uint32_t df, + int64_t arg1, int64_t arg2) +{ + int64_t q_min = DF_MIN_INT(df); + int64_t q_max = DF_MAX_INT(df); + + if (arg1 == q_min && arg2 == q_min) { + return q_max; + } + + return (arg1 * arg2) >> (DF_BITS(df) - 1); +} + +void helper_msa_mul_q_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + int64_t td, ts, tt; + int i; + int df_bits = 8 * (1 << df); + + for (i = 0; i < MSA_WRLEN / df_bits; i++) { + ts = msa_load_wr_elem_s64(env, ws, df, i); + tt = msa_load_wr_elem_s64(env, wt, df, i); + td = msa_mul_q_df(env, df, ts, tt); + msa_store_wr_elem(env, td, wd, df, i); + } + + if (env->active_msa.msair & MSAIR_WRP_BIT) { + env->active_msa.msamodify |= (1 << wd); + } +} + +static inline int64_t msa_mulr_q_df(CPUMIPSState *env, uint32_t df, + int64_t arg1, int64_t arg2) +{ + int64_t q_min = DF_MIN_INT(df); + int64_t q_max = DF_MAX_INT(df); + int64_t r_bit = 1 << (DF_BITS(df) - 2); + + if (arg1 == q_min && arg2 == q_min) { + return q_max; + } + + return (arg1 * arg2 + r_bit) >> (DF_BITS(df) - 1); +} + +void helper_msa_mulr_q_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + int64_t td, ts, tt; + int i; + int df_bits = 8 * (1 << df); + + for (i = 0; i < MSA_WRLEN / df_bits; i++) { + ts = msa_load_wr_elem_s64(env, ws, df, i); + tt = msa_load_wr_elem_s64(env, wt, df, i); + td = msa_mulr_q_df(env, df, ts, tt); + msa_store_wr_elem(env, td, wd, df, i); + } + + if (env->active_msa.msair & MSAIR_WRP_BIT) { + env->active_msa.msamodify |= (1 << wd); + } +} + +static inline int64_t msa_madd_q_df(CPUMIPSState *env, uint32_t df, + int64_t dest, int64_t arg1, int64_t arg2) +{ + int64_t q_prod, q_ret; + + int64_t q_max = DF_MAX_INT(df); + int64_t q_min = DF_MIN_INT(df); + + q_prod = arg1 * arg2; + q_ret = ((dest << (DF_BITS(df) - 1)) + q_prod) >> (DF_BITS(df) - 1); + + return (q_ret < q_min) ? q_min : (q_max < q_ret) ? q_max : q_ret; +} + +void helper_msa_madd_q_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + int64_t td, ts, tt; + int i; + int df_bits = 8 * (1 << df); + + for (i = 0; i < MSA_WRLEN / df_bits; i++) { + ts = msa_load_wr_elem_s64(env, ws, df, i); + tt = msa_load_wr_elem_s64(env, wt, df, i); + td = msa_load_wr_elem_s64(env, wd, df, i); + td = msa_madd_q_df(env, df, td, ts, tt); + msa_store_wr_elem(env, td, wd, df, i); + } + + if (env->active_msa.msair & MSAIR_WRP_BIT) { + env->active_msa.msamodify |= (1 << wd); + } +} + +static inline int64_t msa_maddr_q_df(CPUMIPSState *env, uint32_t df, + int64_t dest, int64_t arg1, int64_t arg2) +{ + int64_t q_prod, q_ret; + + int64_t q_max = DF_MAX_INT(df); + int64_t q_min = DF_MIN_INT(df); + int64_t r_bit = 1 << (DF_BITS(df) - 2); + + q_prod = arg1 * arg2; + q_ret = ((dest << (DF_BITS(df) - 1)) + q_prod + r_bit) >> (DF_BITS(df) - 1); + + return (q_ret < q_min) ? q_min : (q_max < q_ret) ? q_max : q_ret; +} + +void helper_msa_maddr_q_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + int64_t td, ts, tt; + int i; + int df_bits = 8 * (1 << df); + + for (i = 0; i < MSA_WRLEN / df_bits; i++) { + ts = msa_load_wr_elem_s64(env, ws, df, i); + tt = msa_load_wr_elem_s64(env, wt, df, i); + td = msa_load_wr_elem_s64(env, wd, df, i); + td = msa_maddr_q_df(env, df, td, ts, tt); + msa_store_wr_elem(env, td, wd, df, i); + } + + if (env->active_msa.msair & MSAIR_WRP_BIT) { + env->active_msa.msamodify |= (1 << wd); + } +} + +static inline int64_t msa_msub_q_df(CPUMIPSState *env, uint32_t df, + int64_t dest, int64_t arg1, int64_t arg2) +{ + int64_t q_prod, q_ret; + + int64_t q_max = DF_MAX_INT(df); + int64_t q_min = DF_MIN_INT(df); + + q_prod = arg1 * arg2; + q_ret = ((dest << (DF_BITS(df) - 1)) - q_prod) >> (DF_BITS(df) - 1); + + return (q_ret < q_min) ? q_min : (q_max < q_ret) ? q_max : q_ret; +} + +void helper_msa_msub_q_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + int64_t td, ts, tt; + int i; + int df_bits = 8 * (1 << df); + + for (i = 0; i < MSA_WRLEN / df_bits; i++) { + ts = msa_load_wr_elem_s64(env, ws, df, i); + tt = msa_load_wr_elem_s64(env, wt, df, i); + td = msa_load_wr_elem_s64(env, wd, df, i); + td = msa_msub_q_df(env, df, td, ts, tt); + msa_store_wr_elem(env, td, wd, df, i); + } + + if (env->active_msa.msair & MSAIR_WRP_BIT) { + env->active_msa.msamodify |= (1 << wd); + } +} + +static inline int64_t msa_msubr_q_df(CPUMIPSState *env, uint32_t df, + int64_t dest, int64_t arg1, int64_t arg2) +{ + int64_t q_prod, q_ret; + + int64_t q_max = DF_MAX_INT(df); + int64_t q_min = DF_MIN_INT(df); + int64_t r_bit = 1 << (DF_BITS(df) - 2); + + q_prod = arg1 * arg2; + q_ret = ((dest << (DF_BITS(df) - 1)) - q_prod + r_bit) >> (DF_BITS(df) - 1); + + return (q_ret < q_min) ? q_min : (q_max < q_ret) ? q_max : q_ret; +} + +void helper_msa_msubr_q_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + int64_t td, ts, tt; + int i; + int df_bits = 8 * (1 << df); + + for (i = 0; i < MSA_WRLEN / df_bits; i++) { + ts = msa_load_wr_elem_s64(env, ws, df, i); + tt = msa_load_wr_elem_s64(env, wt, df, i); + td = msa_load_wr_elem_s64(env, wd, df, i); + td = msa_msubr_q_df(env, df, td, ts, tt); + msa_store_wr_elem(env, td, wd, df, i); + } + + if (env->active_msa.msair & MSAIR_WRP_BIT) { + env->active_msa.msamodify |= (1 << wd); + } +} + +#define FLOAT_SNAN16 (float16_default_nan ^ 0x0220) + /* 0x7c20 */ +#define FLOAT_SNAN32 (float32_default_nan ^ 0x00400020) + /* 0x7f800020 */ +#define FLOAT_SNAN64 (float64_default_nan ^ 0x0008000000000020ULL) + /* 0x7ff0000000000020 */ + +static inline void clear_msacsr_cause(CPUMIPSState *env) +{ + SET_FP_CAUSE(env->active_msa.msacsr, 0); +} + +static inline void check_msacsr_cause(CPUMIPSState *env) +{ + if ((GET_FP_CAUSE(env->active_msa.msacsr) & + (GET_FP_ENABLE(env->active_msa.msacsr) | FP_UNIMPLEMENTED)) == 0) { + UPDATE_FP_FLAGS(env->active_msa.msacsr, + GET_FP_CAUSE(env->active_msa.msacsr)); + } else { + helper_raise_exception(env, EXCP_MSAFPE); + } +} + +/* Flush-to-zero use cases for update_msacsr() */ +#define CLEAR_FS_UNDERFLOW 1 +#define CLEAR_IS_INEXACT 2 +#define RECIPROCAL_INEXACT 4 + +static inline int update_msacsr(CPUMIPSState *env, int action, int denormal) +{ + int ieee_ex; + + int c; + int cause; + int enable; + + ieee_ex = get_float_exception_flags(&env->active_msa.fp_status); + + /* QEMU softfloat does not signal all underflow cases */ + if (denormal) { + ieee_ex |= float_flag_underflow; + } + + c = ieee_ex_to_mips(ieee_ex); + enable = GET_FP_ENABLE(env->active_msa.msacsr) | FP_UNIMPLEMENTED; + + /* Set Inexact (I) when flushing inputs to zero */ + if ((ieee_ex & float_flag_input_denormal) && + (env->active_msa.msacsr & MSACSR_FS_BIT) != 0) { + if (action & CLEAR_IS_INEXACT) { + c &= ~FP_INEXACT; + } else { + c |= FP_INEXACT; + } + } + + /* Set Inexact (I) and Underflow (U) when flushing outputs to zero */ + if ((ieee_ex & float_flag_output_denormal) && + (env->active_msa.msacsr & MSACSR_FS_BIT) != 0) { + c |= FP_INEXACT; + if (action & CLEAR_FS_UNDERFLOW) { + c &= ~FP_UNDERFLOW; + } else { + c |= FP_UNDERFLOW; + } + } + + /* Set Inexact (I) when Overflow (O) is not enabled */ + if ((c & FP_OVERFLOW) != 0 && (enable & FP_OVERFLOW) == 0) { + c |= FP_INEXACT; + } + + /* Clear Exact Underflow when Underflow (U) is not enabled */ + if ((c & FP_UNDERFLOW) != 0 && (enable & FP_UNDERFLOW) == 0 && + (c & FP_INEXACT) == 0) { + c &= ~FP_UNDERFLOW; + } + + /* Reciprocal operations set only Inexact when valid and not + divide by zero */ + if ((action & RECIPROCAL_INEXACT) && + (c & (FP_INVALID | FP_DIV0)) == 0) { + c = FP_INEXACT; + } + + cause = c & enable; /* all current enabled exceptions */ + + if (cause == 0) { + /* No enabled exception, update the MSACSR Cause + with all current exceptions */ + SET_FP_CAUSE(env->active_msa.msacsr, + (GET_FP_CAUSE(env->active_msa.msacsr) | c)); + } else { + /* Current exceptions are enabled */ + if ((env->active_msa.msacsr & MSACSR_NX_BIT) == 0) { + /* Exception(s) will trap, update MSACSR Cause + with all enabled exceptions */ + SET_FP_CAUSE(env->active_msa.msacsr, + (GET_FP_CAUSE(env->active_msa.msacsr) | c)); + } + } + + return c; +} + +#define float16_is_zero(ARG) 0 +#define float16_is_zero_or_denormal(ARG) 0 + +#define IS_DENORMAL(ARG, BITS) \ + (!float ## BITS ## _is_zero(ARG) \ + && float ## BITS ## _is_zero_or_denormal(ARG)) + +#define MSA_FLOAT_UNOP_XD(DEST, OP, ARG, BITS, XBITS) \ + do { \ + int c; \ + int cause; \ + int enable; \ + \ + set_float_exception_flags(0, &env->active_msa.fp_status); \ + DEST = float ## BITS ## _ ## OP(ARG, &env->active_msa.fp_status); \ + c = update_msacsr(env, CLEAR_FS_UNDERFLOW, 0); \ + enable = GET_FP_ENABLE(env->active_msa.msacsr) | FP_UNIMPLEMENTED; \ + cause = c & enable; \ + \ + if (cause) { \ + DEST = ((FLOAT_SNAN ## XBITS >> 6) << 6) | c; \ + } \ + } while (0) + +#define MSA_FLOAT_UNOP(DEST, OP, ARG, BITS) \ + do { \ + int c; \ + int cause; \ + int enable; \ + \ + set_float_exception_flags(0, &env->active_msa.fp_status); \ + DEST = float ## BITS ## _ ## OP(ARG, &env->active_msa.fp_status); \ + c = update_msacsr(env, 0, IS_DENORMAL(DEST, BITS)); \ + enable = GET_FP_ENABLE(env->active_msa.msacsr) | FP_UNIMPLEMENTED; \ + cause = c & enable; \ + \ + if (cause) { \ + DEST = ((FLOAT_SNAN ## BITS >> 6) << 6) | c; \ + } \ + } while (0) + +#define MSA_FLOAT_BINOP(DEST, OP, ARG1, ARG2, BITS) \ + do { \ + int c; \ + int cause; \ + int enable; \ + \ + set_float_exception_flags(0, &env->active_msa.fp_status); \ + DEST = float ## BITS ## _ ## OP(ARG1, ARG2, \ + &env->active_msa.fp_status); \ + c = update_msacsr(env, 0, IS_DENORMAL(DEST, BITS)); \ + enable = GET_FP_ENABLE(env->active_msa.msacsr) | FP_UNIMPLEMENTED; \ + cause = c & enable; \ + \ + if (cause) { \ + DEST = ((FLOAT_SNAN ## BITS >> 6) << 6) | c; \ + } \ + } while (0) + +#define MSA_FLOAT_MAXOP(DEST, OP, ARG1, ARG2, BITS) \ + do { \ + int c; \ + int cause; \ + int enable; \ + \ + set_float_exception_flags(0, &env->active_msa.fp_status); \ + DEST = float ## BITS ## _ ## OP(ARG1, ARG2, \ + &env->active_msa.fp_status); \ + c = update_msacsr(env, 0, 0); \ + enable = GET_FP_ENABLE(env->active_msa.msacsr) | FP_UNIMPLEMENTED; \ + cause = c & enable; \ + \ + if (cause) { \ + DEST = ((FLOAT_SNAN ## BITS >> 6) << 6) | c; \ + } \ + } while (0) + +#define MSA_FLOAT_MULADD(DEST, ARG1, ARG2, ARG3, NEGATE, BITS) \ + do { \ + int c; \ + int cause; \ + int enable; \ + \ + set_float_exception_flags(0, &env->active_msa.fp_status); \ + DEST = float ## BITS ## _muladd(ARG2, ARG3, ARG1, NEGATE, \ + &env->active_msa.fp_status); \ + c = update_msacsr(env, 0, IS_DENORMAL(DEST, BITS)); \ + enable = GET_FP_ENABLE(env->active_msa.msacsr) | FP_UNIMPLEMENTED; \ + cause = c & enable; \ + \ + if (cause) { \ + DEST = ((FLOAT_SNAN ## BITS >> 6) << 6) | c; \ + } \ + } while (0) + +#define NUMBER_QNAN_PAIR(ARG1, ARG2, BITS) \ + !float ## BITS ## _is_any_nan(ARG1) \ + && float ## BITS ## _is_quiet_nan(ARG2) + +void helper_msa_fadd_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t wx, *pwx = &wx; + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_BINOP(W(pwx, i), add, W(pws, i), W(pwt, i), 32); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_BINOP(D(pwx, i), add, D(pws, i), D(pwt, i), 64); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + msa_move_v(pwd, pwx); +} + +void helper_msa_fsub_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t wx, *pwx = &wx; + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_BINOP(W(pwx, i), sub, W(pws, i), W(pwt, i), 32); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_BINOP(D(pwx, i), sub, D(pws, i), D(pwt, i), 64); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + msa_move_v(pwd, pwx); +} + +void helper_msa_fmul_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t wx, *pwx = &wx; + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_BINOP(W(pwx, i), mul, W(pws, i), W(pwt, i), 32); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_BINOP(D(pwx, i), mul, D(pws, i), D(pwt, i), 64); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_fdiv_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t wx, *pwx = &wx; + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_BINOP(W(pwx, i), div, W(pws, i), W(pwt, i), 32); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_BINOP(D(pwx, i), div, D(pws, i), D(pwt, i), 64); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_fexp2_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t wx, *pwx = &wx; + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_BINOP(W(pwx, i), scalbn, W(pws, i), + W(pwt, i) > 0x200 ? 0x200 : + W(pwt, i) < -0x200 ? -0x200 : W(pwt, i), + 32); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_BINOP(D(pwx, i), scalbn, D(pws, i), + D(pwt, i) > 0x1000 ? 0x1000 : + D(pwt, i) < -0x1000 ? -0x1000 : D(pwt, i), + 64); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_fmadd_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t wx, *pwx = &wx; + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_MULADD(W(pwx, i), W(pwd, i), + W(pws, i), W(pwt, i), 0, 32); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_MULADD(D(pwx, i), D(pwd, i), + D(pws, i), D(pwt, i), 0, 64); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_fmsub_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t wx, *pwx = &wx; + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_MULADD(W(pwx, i), W(pwd, i), + W(pws, i), W(pwt, i), + float_muladd_negate_product, 32); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_MULADD(D(pwx, i), D(pwd, i), + D(pws, i), D(pwt, i), + float_muladd_negate_product, 64); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +#define FMAXMIN_A(F, G, X, _S, _T, BITS) \ +{ \ + uint## BITS ##_t S = _S, T = _T; \ + if (NUMBER_QNAN_PAIR(S, T, BITS)) { \ + T = S; \ + } \ + else if (NUMBER_QNAN_PAIR(T, S, BITS)) { \ + S = T; \ + } \ + uint## BITS ##_t as = float## BITS ##_abs(S); \ + uint## BITS ##_t at = float## BITS ##_abs(T); \ + uint## BITS ##_t xs, xt, xd; \ + MSA_FLOAT_MAXOP(xs, F, S, T, BITS); \ + MSA_FLOAT_MAXOP(xt, G, S, T, BITS); \ + MSA_FLOAT_MAXOP(xd, F, as, at, BITS); \ + X = (as == at || xd == float## BITS ##_abs(xs)) ? xs : xt; \ +} + +void helper_msa_fmax_a_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t wx, *pwx = &wx; + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + FMAXMIN_A(max, min, W(pwx, i), W(pws, i), W(pwt, i), 32); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + FMAXMIN_A(max, min, D(pwx, i), D(pws, i), D(pwt, i), 64); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_fmax_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t wx, *pwx = &wx; + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + if (NUMBER_QNAN_PAIR(W(pws, i), W(pwt, i), 32)) { + MSA_FLOAT_MAXOP(W(pwx, i), max, W(pws, i), W(pws, i), 32); + } else if (NUMBER_QNAN_PAIR(W(pwt, i), W(pws, i), 32)) { + MSA_FLOAT_MAXOP(W(pwx, i), max, W(pwt, i), W(pwt, i), 32); + } else { + MSA_FLOAT_MAXOP(W(pwx, i), max, W(pws, i), W(pwt, i), 32); + } + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + if (NUMBER_QNAN_PAIR(D(pws, i), D(pwt, i), 64)) { + MSA_FLOAT_MAXOP(D(pwx, i), max, D(pws, i), D(pws, i), 64); + } else if (NUMBER_QNAN_PAIR(D(pwt, i), D(pws, i), 64)) { + MSA_FLOAT_MAXOP(D(pwx, i), max, D(pwt, i), D(pwt, i), 64); + } else { + MSA_FLOAT_MAXOP(D(pwx, i), max, D(pws, i), D(pwt, i), 64); + } + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_fmin_a_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t wx, *pwx = &wx; + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + FMAXMIN_A(min, max, W(pwx, i), W(pws, i), W(pwt, i), 32); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + FMAXMIN_A(min, max, D(pwx, i), D(pws, i), D(pwt, i), 64); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_fmin_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t wx, *pwx = &wx; + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + if (NUMBER_QNAN_PAIR(W(pws, i), W(pwt, i), 32)) { + MSA_FLOAT_MAXOP(W(pwx, i), min, W(pws, i), W(pws, i), 32); + } else if (NUMBER_QNAN_PAIR(W(pwt, i), W(pws, i), 32)) { + MSA_FLOAT_MAXOP(W(pwx, i), min, W(pwt, i), W(pwt, i), 32); + } else { + MSA_FLOAT_MAXOP(W(pwx, i), min, W(pws, i), W(pwt, i), 32); + } + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + if (NUMBER_QNAN_PAIR(D(pws, i), D(pwt, i), 64)) { + MSA_FLOAT_MAXOP(D(pwx, i), min, D(pws, i), D(pws, i), 64); + } else if (NUMBER_QNAN_PAIR(D(pwt, i), D(pws, i), 64)) { + MSA_FLOAT_MAXOP(D(pwx, i), min, D(pwt, i), D(pwt, i), 64); + } else { + MSA_FLOAT_MAXOP(D(pwx, i), min, D(pws, i), D(pwt, i), 64); + } + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +#define MSA_FLOAT_COND(DEST, OP, ARG1, ARG2, BITS, QUIET) \ + do { \ + int c; \ + int cause; \ + int enable; \ + int64_t cond; \ + set_float_exception_flags(0, &env->active_msa.fp_status); \ + if (!QUIET) { \ + cond = float ## BITS ## _ ## OP(ARG1, ARG2, \ + &env->active_msa.fp_status); \ + } else { \ + cond = float ## BITS ## _ ## OP ## _quiet(ARG1, ARG2, \ + &env->active_msa.fp_status); \ + } \ + DEST = cond ? M_MAX_UINT(BITS) : 0; \ + c = update_msacsr(env, CLEAR_IS_INEXACT, 0); \ + enable = GET_FP_ENABLE(env->active_msa.msacsr) | FP_UNIMPLEMENTED; \ + cause = c & enable; \ + \ + if (cause) { \ + DEST = ((FLOAT_SNAN ## BITS >> 6) << 6) | c; \ + } \ + } while (0) + +#define MSA_FLOAT_AF(DEST, ARG1, ARG2, BITS, QUIET) \ + do { \ + MSA_FLOAT_COND(DEST, eq, ARG1, ARG2, BITS, QUIET); \ + if ((DEST & M_MAX_UINT(BITS)) == M_MAX_UINT(BITS)) { \ + DEST = 0; \ + } \ + } while (0) + +#define MSA_FLOAT_UEQ(DEST, ARG1, ARG2, BITS, QUIET) \ + do { \ + MSA_FLOAT_COND(DEST, unordered, ARG1, ARG2, BITS, QUIET); \ + if (DEST == 0) { \ + MSA_FLOAT_COND(DEST, eq, ARG1, ARG2, BITS, QUIET); \ + } \ + } while (0) + +#define MSA_FLOAT_NE(DEST, ARG1, ARG2, BITS, QUIET) \ + do { \ + MSA_FLOAT_COND(DEST, lt, ARG1, ARG2, BITS, QUIET); \ + if (DEST == 0) { \ + MSA_FLOAT_COND(DEST, lt, ARG2, ARG1, BITS, QUIET); \ + } \ + } while (0) + +#define MSA_FLOAT_UNE(DEST, ARG1, ARG2, BITS, QUIET) \ + do { \ + MSA_FLOAT_COND(DEST, unordered, ARG1, ARG2, BITS, QUIET); \ + if (DEST == 0) { \ + MSA_FLOAT_COND(DEST, lt, ARG1, ARG2, BITS, QUIET); \ + if (DEST == 0) { \ + MSA_FLOAT_COND(DEST, lt, ARG2, ARG1, BITS, QUIET); \ + } \ + } \ + } while (0) + +#define MSA_FLOAT_ULE(DEST, ARG1, ARG2, BITS, QUIET) \ + do { \ + MSA_FLOAT_COND(DEST, unordered, ARG1, ARG2, BITS, QUIET); \ + if (DEST == 0) { \ + MSA_FLOAT_COND(DEST, le, ARG1, ARG2, BITS, QUIET); \ + } \ + } while (0) + +#define MSA_FLOAT_ULT(DEST, ARG1, ARG2, BITS, QUIET) \ + do { \ + MSA_FLOAT_COND(DEST, unordered, ARG1, ARG2, BITS, QUIET); \ + if (DEST == 0) { \ + MSA_FLOAT_COND(DEST, lt, ARG1, ARG2, BITS, QUIET); \ + } \ + } while (0) + +#define MSA_FLOAT_OR(DEST, ARG1, ARG2, BITS, QUIET) \ + do { \ + MSA_FLOAT_COND(DEST, le, ARG1, ARG2, BITS, QUIET); \ + if (DEST == 0) { \ + MSA_FLOAT_COND(DEST, le, ARG2, ARG1, BITS, QUIET); \ + } \ + } while (0) + +static inline void compare_af(CPUMIPSState *env, void *pwd, void *pws, + void *pwt, uint32_t df, int quiet) { + wr_t wx, *pwx = &wx; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_AF(W(pwx, i), W(pws, i), W(pwt, i), 32, quiet); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_AF(D(pwx, i), D(pws, i), D(pwt, i), 64, quiet); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_fcaf_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + compare_af(env, pwd, pws, pwt, df, 1); +} + +void helper_msa_fsaf_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + compare_af(env, pwd, pws, pwt, df, 0); +} + +static inline void compare_eq(CPUMIPSState *env, void *pwd, void *pws, + void *pwt, uint32_t df, int quiet) { + wr_t wx, *pwx = &wx; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_COND(W(pwx, i), eq, W(pws, i), W(pwt, i), 32, quiet); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_COND(D(pwx, i), eq, D(pws, i), D(pwt, i), 64, quiet); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_fceq_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + compare_eq(env, pwd, pws, pwt, df, 1); +} + +void helper_msa_fseq_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + compare_eq(env, pwd, pws, pwt, df, 0); +} + +static inline void compare_ueq(CPUMIPSState *env, void *pwd, void *pws, + void *pwt, uint32_t df, int quiet) { + wr_t wx, *pwx = &wx; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_UEQ(W(pwx, i), W(pws, i), W(pwt, i), 32, quiet); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_UEQ(D(pwx, i), D(pws, i), D(pwt, i), 64, quiet); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_fcueq_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + compare_ueq(env, pwd, pws, pwt, df, 1); +} + +void helper_msa_fsueq_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + compare_ueq(env, pwd, pws, pwt, df, 0); +} + +static inline void compare_ne(CPUMIPSState *env, void *pwd, void *pws, + void *pwt, uint32_t df, int quiet) { + wr_t wx, *pwx = &wx; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_NE(W(pwx, i), W(pws, i), W(pwt, i), 32, quiet); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_NE(D(pwx, i), D(pws, i), D(pwt, i), 64, quiet); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_fcne_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + compare_ne(env, pwd, pws, pwt, df, 1); +} + +void helper_msa_fsne_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + compare_ne(env, pwd, pws, pwt, df, 0); +} + +static inline void compare_une(CPUMIPSState *env, void *pwd, void *pws, + void *pwt, uint32_t df, int quiet) { + wr_t wx, *pwx = &wx; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_UNE(W(pwx, i), W(pws, i), W(pwt, i), 32, quiet); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_UNE(D(pwx, i), D(pws, i), D(pwt, i), 64, quiet); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_fcune_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + compare_une(env, pwd, pws, pwt, df, 1); +} + +void helper_msa_fsune_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + compare_une(env, pwd, pws, pwt, df, 0); +} + +static inline void compare_le(CPUMIPSState *env, void *pwd, void *pws, + void *pwt, uint32_t df, int quiet) { + wr_t wx, *pwx = &wx; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_COND(W(pwx, i), le, W(pws, i), W(pwt, i), 32, quiet); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_COND(D(pwx, i), le, D(pws, i), D(pwt, i), 64, quiet); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_fcle_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + compare_le(env, pwd, pws, pwt, df, 1); +} + +void helper_msa_fsle_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + compare_le(env, pwd, pws, pwt, df, 0); +} + +static inline void compare_ule(CPUMIPSState *env, void *pwd, void *pws, + void *pwt, uint32_t df, int quiet) { + wr_t wx, *pwx = &wx; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_ULE(W(pwx, i), W(pws, i), W(pwt, i), 32, quiet); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_ULE(D(pwx, i), D(pws, i), D(pwt, i), 64, quiet); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_fcule_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + compare_ule(env, pwd, pws, pwt, df, 1); +} + +void helper_msa_fsule_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + compare_ule(env, pwd, pws, pwt, df, 0); +} + +static inline void compare_lt(CPUMIPSState *env, void *pwd, void *pws, + void *pwt, uint32_t df, int quiet) { + wr_t wx, *pwx = &wx; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_COND(W(pwx, i), lt, W(pws, i), W(pwt, i), 32, quiet); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_COND(D(pwx, i), lt, D(pws, i), D(pwt, i), 64, quiet); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_fclt_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + compare_lt(env, pwd, pws, pwt, df, 1); +} + +void helper_msa_fslt_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + compare_lt(env, pwd, pws, pwt, df, 0); +} + +static inline void compare_ult(CPUMIPSState *env, void *pwd, void *pws, + void *pwt, uint32_t df, int quiet) { + wr_t wx, *pwx = &wx; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_ULT(W(pwx, i), W(pws, i), W(pwt, i), 32, quiet); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_ULT(D(pwx, i), D(pws, i), D(pwt, i), 64, quiet); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_fcult_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + compare_ult(env, pwd, pws, pwt, df, 1); +} + +void helper_msa_fsult_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + compare_ult(env, pwd, pws, pwt, df, 0); +} + +static inline void compare_un(CPUMIPSState *env, void *pwd, void *pws, + void *pwt, uint32_t df, int quiet) { + wr_t wx, *pwx = &wx; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_COND(W(pwx, i), unordered, W(pws, i), W(pwt, i), 32, + quiet); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_COND(D(pwx, i), unordered, D(pws, i), D(pwt, i), 64, + quiet); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_fcun_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + compare_un(env, pwd, pws, pwt, df, 1); +} + +void helper_msa_fsun_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + compare_un(env, pwd, pws, pwt, df, 0); +} + +static inline void compare_or(CPUMIPSState *env, void *pwd, void *pws, + void *pwt, uint32_t df, int quiet) { + wr_t wx, *pwx = &wx; + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_OR(W(pwx, i), W(pws, i), W(pwt, i), 32, quiet); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_OR(D(pwx, i), D(pws, i), D(pwt, i), 64, quiet); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + +void helper_msa_fcor_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + compare_or(env, pwd, pws, pwt, df, 1); +} + +void helper_msa_fsor_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + compare_or(env, pwd, pws, pwt, df, 0); +} + +static inline float16 float16_from_float32(int32 a, flag ieee STATUS_PARAM) +{ + float16 f_val; + + f_val = float32_to_float16((float32)a, ieee STATUS_VAR); + 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) +{ + float32 f_val; + + f_val = float64_to_float32((float64)a STATUS_VAR); + f_val = float32_maybe_silence_nan(f_val); + + return a < 0 ? (f_val | (1 << 31)) : f_val; +} + +void helper_msa_fexdo_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t wx, *pwx = &wx; + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + /* 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(HL(pwx, i), from_float32, W(pws, i), ieee, 16); + MSA_FLOAT_BINOP(HR(pwx, i), from_float32, W(pwt, i), ieee, 16); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_UNOP(WL(pwx, i), from_float64, D(pws, i), 32); + MSA_FLOAT_UNOP(WR(pwx, i), from_float64, D(pwt, i), 32); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + msa_move_v(pwd, pwx); +} + +static inline int16_t float32_to_q16(float32 a STATUS_PARAM) +{ + int32 q_val; + int32 q_min = 0xffff8000; + int32 q_max = 0x00007fff; + + int ieee_ex; + + if (float32_is_any_nan(a)) { + float_raise(float_flag_invalid STATUS_VAR); + return 0; + } + + /* scaling */ + a = float32_scalbn(a, 15 STATUS_VAR); + + ieee_ex = get_float_exception_flags(status); + set_float_exception_flags(ieee_ex & (~float_flag_underflow) + STATUS_VAR); + + if (ieee_ex & float_flag_overflow) { + float_raise(float_flag_inexact STATUS_VAR); + return (int32)a < 0 ? q_min : q_max; + } + + /* conversion to int */ + q_val = float32_to_int32(a STATUS_VAR); + + ieee_ex = get_float_exception_flags(status); + set_float_exception_flags(ieee_ex & (~float_flag_underflow) + STATUS_VAR); + + 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; + } + + if (q_val < q_min) { + float_raise(float_flag_overflow | float_flag_inexact STATUS_VAR); + return (int16_t)q_min; + } + + if (q_max < q_val) { + float_raise(float_flag_overflow | float_flag_inexact STATUS_VAR); + return (int16_t)q_max; + } + + return (int16_t)q_val; +} + +static inline int32 float64_to_q32(float64 a STATUS_PARAM) +{ + int64 q_val; + int64 q_min = 0xffffffff80000000LL; + int64 q_max = 0x000000007fffffffLL; + + int ieee_ex; + + if (float64_is_any_nan(a)) { + float_raise(float_flag_invalid STATUS_VAR); + return 0; + } + + /* scaling */ + a = float64_scalbn(a, 31 STATUS_VAR); + + ieee_ex = get_float_exception_flags(status); + set_float_exception_flags(ieee_ex & (~float_flag_underflow) + STATUS_VAR); + + if (ieee_ex & float_flag_overflow) { + float_raise(float_flag_inexact STATUS_VAR); + return (int64)a < 0 ? q_min : q_max; + } + + /* conversion to integer */ + q_val = float64_to_int64(a STATUS_VAR); + + ieee_ex = get_float_exception_flags(status); + set_float_exception_flags(ieee_ex & (~float_flag_underflow) + STATUS_VAR); + + 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; + } + + if (q_val < q_min) { + float_raise(float_flag_overflow | float_flag_inexact STATUS_VAR); + return (int32)q_min; + } + + if (q_max < q_val) { + float_raise(float_flag_overflow | float_flag_inexact STATUS_VAR); + return (int32)q_max; + } + + return (int32)q_val; +} + +void helper_msa_ftq_df(CPUMIPSState *env, uint32_t df, uint32_t wd, + uint32_t ws, uint32_t wt) +{ + wr_t wx, *pwx = &wx; + void *pwd = &(env->active_fpu.fpr[wd]); + void *pws = &(env->active_fpu.fpr[ws]); + void *pwt = &(env->active_fpu.fpr[wt]); + + clear_msacsr_cause(env); + + switch (df) { + case DF_WORD: + ALL_W_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_UNOP_XD(HL(pwx, i), to_q16, W(pws, i), 32, 16); + MSA_FLOAT_UNOP_XD(HR(pwx, i), to_q16, W(pwt, i), 32, 16); + } DONE_ALL_ELEMENTS; + break; + case DF_DOUBLE: + ALL_D_ELEMENTS(i, MSA_WRLEN) { + MSA_FLOAT_UNOP_XD(WL(pwx, i), to_q32, D(pws, i), 64, 32); + MSA_FLOAT_UNOP_XD(WR(pwx, i), to_q32, D(pwt, i), 64, 32); + } DONE_ALL_ELEMENTS; + break; + default: + /* shouldn't get here */ + assert(0); + } + + check_msacsr_cause(env); + + msa_move_v(pwd, pwx); +} + target_ulong helper_msa_cfcmsa(CPUMIPSState *env, uint32_t cs) { switch (cs) { @@ -2828,12 +4400,10 @@ void helper_msa_ctcmsa(CPUMIPSState *env, target_ulong elm, uint32_t cd) break; case MSACSR_REGISTER: env->active_msa.msacsr = (int32_t)elm & MSACSR_BITS; - /* set float_status rounding mode */ set_float_rounding_mode( ieee_rm[(env->active_msa.msacsr & MSACSR_RM_MASK) >> MSACSR_RM_POS], &env->active_msa.fp_status); - /* set float_status flush modes */ set_flush_to_zero( (env->active_msa.msacsr & MSACSR_FS_BIT) != 0 ? 1 : 0, @@ -2841,7 +4411,6 @@ void helper_msa_ctcmsa(CPUMIPSState *env, target_ulong elm, uint32_t cd) set_flush_inputs_to_zero( (env->active_msa.msacsr & MSACSR_FS_BIT) != 0 ? 1 : 0, &env->active_msa.fp_status); - /* check exception */ if ((GET_FP_ENABLE(env->active_msa.msacsr) | FP_UNIMPLEMENTED) & GET_FP_CAUSE(env->active_msa.msacsr)) { diff --git a/target-mips/translate.c b/target-mips/translate.c index 6c8caa4..39caa6d 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -15452,6 +15452,204 @@ static void gen_msa_elm(CPUMIPSState *env, DisasContext *ctx) } } +static void gen_msa_3rf(CPUMIPSState *env, DisasContext *ctx) +{ +#define MASK_MSA_3RF(op) (MASK_MSA_MINOR(op) | (op & (0xf << 22))) + uint32_t opcode = ctx->opcode; + + uint8_t df2 = (ctx->opcode >> 21) & 0x1 /* df [21:21] */; + uint8_t df1 = (ctx->opcode >> 21) & 0x1 /* df [21:21] */; + /* adjust df value for floating-point instruction */ + df2 = df2 + 2; + df1 = df1 + 1; + uint8_t wt = (ctx->opcode >> 16) & 0x1f /* wt [20:16] */; + uint8_t ws = (ctx->opcode >> 11) & 0x1f /* ws [15:11] */; + uint8_t wd = (ctx->opcode >> 6) & 0x1f /* wd [10:6] */; + + TCGv_i32 twd = tcg_const_i32(wd); + TCGv_i32 tws = tcg_const_i32(ws); + TCGv_i32 twt = tcg_const_i32(wt); + TCGv_i32 tdf2 = tcg_const_i32(df2); + TCGv_i32 tdf1 = tcg_const_i32(df1); + + switch (MASK_MSA_3RF(opcode)) { + case OPC_MSA_FCAF_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fcaf_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_FADD_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fadd_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_FCUN_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fcun_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_FSUB_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fsub_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_FCOR_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fcor_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_FCEQ_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fceq_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_FMUL_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fmul_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_FCUNE_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fcune_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_FCUEQ_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fcueq_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_FDIV_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fdiv_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_FCNE_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fcne_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_FCLT_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fclt_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_FMADD_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fmadd_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_MUL_Q_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_mul_q_df(cpu_env, tdf1, twd, tws, twt); + break; + case OPC_MSA_FCULT_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fcult_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_FMSUB_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fmsub_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_MADD_Q_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_madd_q_df(cpu_env, tdf1, twd, tws, twt); + break; + case OPC_MSA_FCLE_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fcle_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_MSUB_Q_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_msub_q_df(cpu_env, tdf1, twd, tws, twt); + break; + case OPC_MSA_FCULE_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fcule_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_FEXP2_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fexp2_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_FSAF_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fsaf_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_FEXDO_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fexdo_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_FSUN_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fsun_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_FSOR_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fsor_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_FSEQ_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fseq_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_FTQ_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_ftq_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_FSUNE_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fsune_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_FSUEQ_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fsueq_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_FSNE_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fsne_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_FSLT_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fslt_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_FMIN_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fmin_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_MULR_Q_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_mulr_q_df(cpu_env, tdf1, twd, tws, twt); + break; + case OPC_MSA_FSULT_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fsult_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_FMIN_A_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fmin_a_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_MADDR_Q_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_maddr_q_df(cpu_env, tdf1, twd, tws, twt); + break; + case OPC_MSA_FSLE_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fsle_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_FMAX_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fmax_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_MSUBR_Q_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_msubr_q_df(cpu_env, tdf1, twd, tws, twt); + break; + case OPC_MSA_FSULE_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fsule_df(cpu_env, tdf2, twd, tws, twt); + break; + case OPC_MSA_FMAX_A_df: + check_msa_access(env, ctx, wt, ws, wd); + gen_helper_msa_fmax_a_df(cpu_env, tdf2, twd, tws, twt); + break; + default: + MIPS_INVAL("MSA instruction"); + generate_exception(ctx, EXCP_RI); + break; + } + + tcg_temp_free_i32(twd); + tcg_temp_free_i32(tws); + tcg_temp_free_i32(twt); + tcg_temp_free_i32(tdf2); + tcg_temp_free_i32(tdf1); +} + static void gen_msa(CPUMIPSState *env, DisasContext *ctx) { uint32_t opcode = ctx->opcode; @@ -15485,6 +15683,11 @@ static void gen_msa(CPUMIPSState *env, DisasContext *ctx) case OPC_MSA_ELM: gen_msa_elm(env, ctx); break; + case OPC_MSA_3RF_1A: + case OPC_MSA_3RF_1B: + case OPC_MSA_3RF_1C: + gen_msa_3rf(env, ctx); + break; default: MIPS_INVAL("MSA instruction"); generate_exception(ctx, EXCP_RI);