Yongbok Kim | 42daa9b | 2014-11-01 05:28:41 +0000 | [diff] [blame] | 1 | /* |
| 2 | * MIPS SIMD Architecture Module Instruction emulation helpers for QEMU. |
| 3 | * |
| 4 | * Copyright (c) 2014 Imagination Technologies |
| 5 | * |
| 6 | * This library is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU Lesser General Public |
| 8 | * License as published by the Free Software Foundation; either |
| 9 | * version 2 of the License, or (at your option) any later version. |
| 10 | * |
| 11 | * This library is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 14 | * Lesser General Public License for more details. |
| 15 | * |
| 16 | * You should have received a copy of the GNU Lesser General Public |
| 17 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
| 18 | */ |
| 19 | |
Peter Maydell | c684822 | 2016-01-18 17:35:00 +0000 | [diff] [blame] | 20 | #include "qemu/osdep.h" |
Yongbok Kim | 42daa9b | 2014-11-01 05:28:41 +0000 | [diff] [blame] | 21 | #include "cpu.h" |
| 22 | #include "exec/helper-proto.h" |
| 23 | |
| 24 | /* Data format min and max values */ |
| 25 | #define DF_BITS(df) (1 << ((df) + 3)) |
| 26 | |
| 27 | #define DF_MAX_INT(df) (int64_t)((1LL << (DF_BITS(df) - 1)) - 1) |
| 28 | #define M_MAX_INT(m) (int64_t)((1LL << ((m) - 1)) - 1) |
| 29 | |
| 30 | #define DF_MIN_INT(df) (int64_t)(-(1LL << (DF_BITS(df) - 1))) |
| 31 | #define M_MIN_INT(m) (int64_t)(-(1LL << ((m) - 1))) |
| 32 | |
| 33 | #define DF_MAX_UINT(df) (uint64_t)(-1ULL >> (64 - DF_BITS(df))) |
| 34 | #define M_MAX_UINT(m) (uint64_t)(-1ULL >> (64 - (m))) |
| 35 | |
| 36 | #define UNSIGNED(x, df) ((x) & DF_MAX_UINT(df)) |
| 37 | #define SIGNED(x, df) \ |
| 38 | ((((int64_t)x) << (64 - DF_BITS(df))) >> (64 - DF_BITS(df))) |
| 39 | |
| 40 | /* Element-by-element access macros */ |
| 41 | #define DF_ELEMENTS(df) (MSA_WRLEN / DF_BITS(df)) |
| 42 | |
| 43 | static inline void msa_move_v(wr_t *pwd, wr_t *pws) |
| 44 | { |
| 45 | uint32_t i; |
| 46 | |
| 47 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 48 | pwd->d[i] = pws->d[i]; |
| 49 | } |
| 50 | } |
Yongbok Kim | 4c78954 | 2014-11-01 05:28:43 +0000 | [diff] [blame] | 51 | |
| 52 | #define MSA_FN_IMM8(FUNC, DEST, OPERATION) \ |
| 53 | void helper_msa_ ## FUNC(CPUMIPSState *env, uint32_t wd, uint32_t ws, \ |
| 54 | uint32_t i8) \ |
| 55 | { \ |
| 56 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \ |
| 57 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); \ |
| 58 | uint32_t i; \ |
| 59 | for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) { \ |
| 60 | DEST = OPERATION; \ |
| 61 | } \ |
| 62 | } |
| 63 | |
| 64 | MSA_FN_IMM8(andi_b, pwd->b[i], pws->b[i] & i8) |
| 65 | MSA_FN_IMM8(ori_b, pwd->b[i], pws->b[i] | i8) |
| 66 | MSA_FN_IMM8(nori_b, pwd->b[i], ~(pws->b[i] | i8)) |
| 67 | MSA_FN_IMM8(xori_b, pwd->b[i], pws->b[i] ^ i8) |
| 68 | |
| 69 | #define BIT_MOVE_IF_NOT_ZERO(dest, arg1, arg2, df) \ |
| 70 | UNSIGNED(((dest & (~arg2)) | (arg1 & arg2)), df) |
| 71 | MSA_FN_IMM8(bmnzi_b, pwd->b[i], |
| 72 | BIT_MOVE_IF_NOT_ZERO(pwd->b[i], pws->b[i], i8, DF_BYTE)) |
| 73 | |
| 74 | #define BIT_MOVE_IF_ZERO(dest, arg1, arg2, df) \ |
| 75 | UNSIGNED((dest & arg2) | (arg1 & (~arg2)), df) |
| 76 | MSA_FN_IMM8(bmzi_b, pwd->b[i], |
| 77 | BIT_MOVE_IF_ZERO(pwd->b[i], pws->b[i], i8, DF_BYTE)) |
| 78 | |
| 79 | #define BIT_SELECT(dest, arg1, arg2, df) \ |
| 80 | UNSIGNED((arg1 & (~dest)) | (arg2 & dest), df) |
| 81 | MSA_FN_IMM8(bseli_b, pwd->b[i], |
| 82 | BIT_SELECT(pwd->b[i], pws->b[i], i8, DF_BYTE)) |
| 83 | |
| 84 | #undef MSA_FN_IMM8 |
| 85 | |
| 86 | #define SHF_POS(i, imm) (((i) & 0xfc) + (((imm) >> (2 * ((i) & 0x03))) & 0x03)) |
| 87 | |
| 88 | void helper_msa_shf_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 89 | uint32_t ws, uint32_t imm) |
| 90 | { |
| 91 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 92 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 93 | wr_t wx, *pwx = &wx; |
| 94 | uint32_t i; |
| 95 | |
| 96 | switch (df) { |
| 97 | case DF_BYTE: |
| 98 | for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) { |
| 99 | pwx->b[i] = pws->b[SHF_POS(i, imm)]; |
| 100 | } |
| 101 | break; |
| 102 | case DF_HALF: |
| 103 | for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) { |
| 104 | pwx->h[i] = pws->h[SHF_POS(i, imm)]; |
| 105 | } |
| 106 | break; |
| 107 | case DF_WORD: |
| 108 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 109 | pwx->w[i] = pws->w[SHF_POS(i, imm)]; |
| 110 | } |
| 111 | break; |
| 112 | default: |
| 113 | assert(0); |
| 114 | } |
| 115 | msa_move_v(pwd, pwx); |
| 116 | } |
Yongbok Kim | 80e7159 | 2014-11-01 05:28:44 +0000 | [diff] [blame] | 117 | |
Yongbok Kim | cbe50b9 | 2014-11-01 05:28:49 +0000 | [diff] [blame] | 118 | #define MSA_FN_VECTOR(FUNC, DEST, OPERATION) \ |
| 119 | void helper_msa_ ## FUNC(CPUMIPSState *env, uint32_t wd, uint32_t ws, \ |
| 120 | uint32_t wt) \ |
| 121 | { \ |
| 122 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \ |
| 123 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); \ |
| 124 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); \ |
| 125 | uint32_t i; \ |
| 126 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { \ |
| 127 | DEST = OPERATION; \ |
| 128 | } \ |
| 129 | } |
| 130 | |
| 131 | MSA_FN_VECTOR(and_v, pwd->d[i], pws->d[i] & pwt->d[i]) |
| 132 | MSA_FN_VECTOR(or_v, pwd->d[i], pws->d[i] | pwt->d[i]) |
| 133 | MSA_FN_VECTOR(nor_v, pwd->d[i], ~(pws->d[i] | pwt->d[i])) |
| 134 | MSA_FN_VECTOR(xor_v, pwd->d[i], pws->d[i] ^ pwt->d[i]) |
| 135 | MSA_FN_VECTOR(bmnz_v, pwd->d[i], |
| 136 | BIT_MOVE_IF_NOT_ZERO(pwd->d[i], pws->d[i], pwt->d[i], DF_DOUBLE)) |
| 137 | MSA_FN_VECTOR(bmz_v, pwd->d[i], |
| 138 | BIT_MOVE_IF_ZERO(pwd->d[i], pws->d[i], pwt->d[i], DF_DOUBLE)) |
| 139 | MSA_FN_VECTOR(bsel_v, pwd->d[i], |
| 140 | BIT_SELECT(pwd->d[i], pws->d[i], pwt->d[i], DF_DOUBLE)) |
| 141 | #undef BIT_MOVE_IF_NOT_ZERO |
| 142 | #undef BIT_MOVE_IF_ZERO |
| 143 | #undef BIT_SELECT |
| 144 | #undef MSA_FN_VECTOR |
| 145 | |
Yongbok Kim | 80e7159 | 2014-11-01 05:28:44 +0000 | [diff] [blame] | 146 | static inline int64_t msa_addv_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 147 | { |
| 148 | return arg1 + arg2; |
| 149 | } |
| 150 | |
| 151 | static inline int64_t msa_subv_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 152 | { |
| 153 | return arg1 - arg2; |
| 154 | } |
| 155 | |
| 156 | static inline int64_t msa_ceq_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 157 | { |
| 158 | return arg1 == arg2 ? -1 : 0; |
| 159 | } |
| 160 | |
| 161 | static inline int64_t msa_cle_s_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 162 | { |
| 163 | return arg1 <= arg2 ? -1 : 0; |
| 164 | } |
| 165 | |
| 166 | static inline int64_t msa_cle_u_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 167 | { |
| 168 | uint64_t u_arg1 = UNSIGNED(arg1, df); |
| 169 | uint64_t u_arg2 = UNSIGNED(arg2, df); |
| 170 | return u_arg1 <= u_arg2 ? -1 : 0; |
| 171 | } |
| 172 | |
| 173 | static inline int64_t msa_clt_s_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 174 | { |
| 175 | return arg1 < arg2 ? -1 : 0; |
| 176 | } |
| 177 | |
| 178 | static inline int64_t msa_clt_u_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 179 | { |
| 180 | uint64_t u_arg1 = UNSIGNED(arg1, df); |
| 181 | uint64_t u_arg2 = UNSIGNED(arg2, df); |
| 182 | return u_arg1 < u_arg2 ? -1 : 0; |
| 183 | } |
| 184 | |
| 185 | static inline int64_t msa_max_s_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 186 | { |
| 187 | return arg1 > arg2 ? arg1 : arg2; |
| 188 | } |
| 189 | |
| 190 | static inline int64_t msa_max_u_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 191 | { |
| 192 | uint64_t u_arg1 = UNSIGNED(arg1, df); |
| 193 | uint64_t u_arg2 = UNSIGNED(arg2, df); |
| 194 | return u_arg1 > u_arg2 ? arg1 : arg2; |
| 195 | } |
| 196 | |
| 197 | static inline int64_t msa_min_s_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 198 | { |
| 199 | return arg1 < arg2 ? arg1 : arg2; |
| 200 | } |
| 201 | |
| 202 | static inline int64_t msa_min_u_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 203 | { |
| 204 | uint64_t u_arg1 = UNSIGNED(arg1, df); |
| 205 | uint64_t u_arg2 = UNSIGNED(arg2, df); |
| 206 | return u_arg1 < u_arg2 ? arg1 : arg2; |
| 207 | } |
| 208 | |
| 209 | #define MSA_BINOP_IMM_DF(helper, func) \ |
| 210 | void helper_msa_ ## helper ## _df(CPUMIPSState *env, uint32_t df, \ |
| 211 | uint32_t wd, uint32_t ws, int32_t u5) \ |
| 212 | { \ |
| 213 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \ |
| 214 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); \ |
| 215 | uint32_t i; \ |
| 216 | \ |
| 217 | switch (df) { \ |
| 218 | case DF_BYTE: \ |
| 219 | for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) { \ |
| 220 | pwd->b[i] = msa_ ## func ## _df(df, pws->b[i], u5); \ |
| 221 | } \ |
| 222 | break; \ |
| 223 | case DF_HALF: \ |
| 224 | for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) { \ |
| 225 | pwd->h[i] = msa_ ## func ## _df(df, pws->h[i], u5); \ |
| 226 | } \ |
| 227 | break; \ |
| 228 | case DF_WORD: \ |
| 229 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { \ |
| 230 | pwd->w[i] = msa_ ## func ## _df(df, pws->w[i], u5); \ |
| 231 | } \ |
| 232 | break; \ |
| 233 | case DF_DOUBLE: \ |
| 234 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { \ |
| 235 | pwd->d[i] = msa_ ## func ## _df(df, pws->d[i], u5); \ |
| 236 | } \ |
| 237 | break; \ |
| 238 | default: \ |
| 239 | assert(0); \ |
| 240 | } \ |
| 241 | } |
| 242 | |
| 243 | MSA_BINOP_IMM_DF(addvi, addv) |
| 244 | MSA_BINOP_IMM_DF(subvi, subv) |
| 245 | MSA_BINOP_IMM_DF(ceqi, ceq) |
| 246 | MSA_BINOP_IMM_DF(clei_s, cle_s) |
| 247 | MSA_BINOP_IMM_DF(clei_u, cle_u) |
| 248 | MSA_BINOP_IMM_DF(clti_s, clt_s) |
| 249 | MSA_BINOP_IMM_DF(clti_u, clt_u) |
| 250 | MSA_BINOP_IMM_DF(maxi_s, max_s) |
| 251 | MSA_BINOP_IMM_DF(maxi_u, max_u) |
| 252 | MSA_BINOP_IMM_DF(mini_s, min_s) |
| 253 | MSA_BINOP_IMM_DF(mini_u, min_u) |
| 254 | #undef MSA_BINOP_IMM_DF |
| 255 | |
| 256 | void helper_msa_ldi_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 257 | int32_t s10) |
| 258 | { |
| 259 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 260 | uint32_t i; |
| 261 | |
| 262 | switch (df) { |
| 263 | case DF_BYTE: |
| 264 | for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) { |
| 265 | pwd->b[i] = (int8_t)s10; |
| 266 | } |
| 267 | break; |
| 268 | case DF_HALF: |
| 269 | for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) { |
| 270 | pwd->h[i] = (int16_t)s10; |
| 271 | } |
| 272 | break; |
| 273 | case DF_WORD: |
| 274 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 275 | pwd->w[i] = (int32_t)s10; |
| 276 | } |
| 277 | break; |
| 278 | case DF_DOUBLE: |
| 279 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 280 | pwd->d[i] = (int64_t)s10; |
| 281 | } |
| 282 | break; |
| 283 | default: |
| 284 | assert(0); |
| 285 | } |
| 286 | } |
Yongbok Kim | d4cf28d | 2014-11-01 05:28:45 +0000 | [diff] [blame] | 287 | |
| 288 | /* Data format bit position and unsigned values */ |
| 289 | #define BIT_POSITION(x, df) ((uint64_t)(x) % DF_BITS(df)) |
| 290 | |
| 291 | static inline int64_t msa_sll_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 292 | { |
| 293 | int32_t b_arg2 = BIT_POSITION(arg2, df); |
| 294 | return arg1 << b_arg2; |
| 295 | } |
| 296 | |
| 297 | static inline int64_t msa_sra_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 298 | { |
| 299 | int32_t b_arg2 = BIT_POSITION(arg2, df); |
| 300 | return arg1 >> b_arg2; |
| 301 | } |
| 302 | |
| 303 | static inline int64_t msa_srl_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 304 | { |
| 305 | uint64_t u_arg1 = UNSIGNED(arg1, df); |
| 306 | int32_t b_arg2 = BIT_POSITION(arg2, df); |
| 307 | return u_arg1 >> b_arg2; |
| 308 | } |
| 309 | |
| 310 | static inline int64_t msa_bclr_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 311 | { |
| 312 | int32_t b_arg2 = BIT_POSITION(arg2, df); |
| 313 | return UNSIGNED(arg1 & (~(1LL << b_arg2)), df); |
| 314 | } |
| 315 | |
| 316 | static inline int64_t msa_bset_df(uint32_t df, int64_t arg1, |
| 317 | int64_t arg2) |
| 318 | { |
| 319 | int32_t b_arg2 = BIT_POSITION(arg2, df); |
| 320 | return UNSIGNED(arg1 | (1LL << b_arg2), df); |
| 321 | } |
| 322 | |
| 323 | static inline int64_t msa_bneg_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 324 | { |
| 325 | int32_t b_arg2 = BIT_POSITION(arg2, df); |
| 326 | return UNSIGNED(arg1 ^ (1LL << b_arg2), df); |
| 327 | } |
| 328 | |
| 329 | static inline int64_t msa_binsl_df(uint32_t df, int64_t dest, int64_t arg1, |
| 330 | int64_t arg2) |
| 331 | { |
| 332 | uint64_t u_arg1 = UNSIGNED(arg1, df); |
| 333 | uint64_t u_dest = UNSIGNED(dest, df); |
| 334 | int32_t sh_d = BIT_POSITION(arg2, df) + 1; |
| 335 | int32_t sh_a = DF_BITS(df) - sh_d; |
| 336 | if (sh_d == DF_BITS(df)) { |
| 337 | return u_arg1; |
| 338 | } else { |
| 339 | return UNSIGNED(UNSIGNED(u_dest << sh_d, df) >> sh_d, df) | |
| 340 | UNSIGNED(UNSIGNED(u_arg1 >> sh_a, df) << sh_a, df); |
| 341 | } |
| 342 | } |
| 343 | |
| 344 | static inline int64_t msa_binsr_df(uint32_t df, int64_t dest, int64_t arg1, |
| 345 | int64_t arg2) |
| 346 | { |
| 347 | uint64_t u_arg1 = UNSIGNED(arg1, df); |
| 348 | uint64_t u_dest = UNSIGNED(dest, df); |
| 349 | int32_t sh_d = BIT_POSITION(arg2, df) + 1; |
| 350 | int32_t sh_a = DF_BITS(df) - sh_d; |
| 351 | if (sh_d == DF_BITS(df)) { |
| 352 | return u_arg1; |
| 353 | } else { |
| 354 | return UNSIGNED(UNSIGNED(u_dest >> sh_d, df) << sh_d, df) | |
| 355 | UNSIGNED(UNSIGNED(u_arg1 << sh_a, df) >> sh_a, df); |
| 356 | } |
| 357 | } |
| 358 | |
| 359 | static inline int64_t msa_sat_s_df(uint32_t df, int64_t arg, uint32_t m) |
| 360 | { |
| 361 | return arg < M_MIN_INT(m+1) ? M_MIN_INT(m+1) : |
| 362 | arg > M_MAX_INT(m+1) ? M_MAX_INT(m+1) : |
| 363 | arg; |
| 364 | } |
| 365 | |
| 366 | static inline int64_t msa_sat_u_df(uint32_t df, int64_t arg, uint32_t m) |
| 367 | { |
| 368 | uint64_t u_arg = UNSIGNED(arg, df); |
| 369 | return u_arg < M_MAX_UINT(m+1) ? u_arg : |
| 370 | M_MAX_UINT(m+1); |
| 371 | } |
| 372 | |
| 373 | static inline int64_t msa_srar_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 374 | { |
| 375 | int32_t b_arg2 = BIT_POSITION(arg2, df); |
| 376 | if (b_arg2 == 0) { |
| 377 | return arg1; |
| 378 | } else { |
| 379 | int64_t r_bit = (arg1 >> (b_arg2 - 1)) & 1; |
| 380 | return (arg1 >> b_arg2) + r_bit; |
| 381 | } |
| 382 | } |
| 383 | |
| 384 | static inline int64_t msa_srlr_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 385 | { |
| 386 | uint64_t u_arg1 = UNSIGNED(arg1, df); |
| 387 | int32_t b_arg2 = BIT_POSITION(arg2, df); |
| 388 | if (b_arg2 == 0) { |
| 389 | return u_arg1; |
| 390 | } else { |
| 391 | uint64_t r_bit = (u_arg1 >> (b_arg2 - 1)) & 1; |
| 392 | return (u_arg1 >> b_arg2) + r_bit; |
| 393 | } |
| 394 | } |
| 395 | |
| 396 | #define MSA_BINOP_IMMU_DF(helper, func) \ |
| 397 | void helper_msa_ ## helper ## _df(CPUMIPSState *env, uint32_t df, uint32_t wd, \ |
| 398 | uint32_t ws, uint32_t u5) \ |
| 399 | { \ |
| 400 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \ |
| 401 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); \ |
| 402 | uint32_t i; \ |
| 403 | \ |
| 404 | switch (df) { \ |
| 405 | case DF_BYTE: \ |
| 406 | for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) { \ |
| 407 | pwd->b[i] = msa_ ## func ## _df(df, pws->b[i], u5); \ |
| 408 | } \ |
| 409 | break; \ |
| 410 | case DF_HALF: \ |
| 411 | for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) { \ |
| 412 | pwd->h[i] = msa_ ## func ## _df(df, pws->h[i], u5); \ |
| 413 | } \ |
| 414 | break; \ |
| 415 | case DF_WORD: \ |
| 416 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { \ |
| 417 | pwd->w[i] = msa_ ## func ## _df(df, pws->w[i], u5); \ |
| 418 | } \ |
| 419 | break; \ |
| 420 | case DF_DOUBLE: \ |
| 421 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { \ |
| 422 | pwd->d[i] = msa_ ## func ## _df(df, pws->d[i], u5); \ |
| 423 | } \ |
| 424 | break; \ |
| 425 | default: \ |
| 426 | assert(0); \ |
| 427 | } \ |
| 428 | } |
| 429 | |
| 430 | MSA_BINOP_IMMU_DF(slli, sll) |
| 431 | MSA_BINOP_IMMU_DF(srai, sra) |
| 432 | MSA_BINOP_IMMU_DF(srli, srl) |
| 433 | MSA_BINOP_IMMU_DF(bclri, bclr) |
| 434 | MSA_BINOP_IMMU_DF(bseti, bset) |
| 435 | MSA_BINOP_IMMU_DF(bnegi, bneg) |
| 436 | MSA_BINOP_IMMU_DF(sat_s, sat_s) |
| 437 | MSA_BINOP_IMMU_DF(sat_u, sat_u) |
| 438 | MSA_BINOP_IMMU_DF(srari, srar) |
| 439 | MSA_BINOP_IMMU_DF(srlri, srlr) |
| 440 | #undef MSA_BINOP_IMMU_DF |
| 441 | |
| 442 | #define MSA_TEROP_IMMU_DF(helper, func) \ |
| 443 | void helper_msa_ ## helper ## _df(CPUMIPSState *env, uint32_t df, \ |
| 444 | uint32_t wd, uint32_t ws, uint32_t u5) \ |
| 445 | { \ |
| 446 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \ |
| 447 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); \ |
| 448 | uint32_t i; \ |
| 449 | \ |
| 450 | switch (df) { \ |
| 451 | case DF_BYTE: \ |
| 452 | for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) { \ |
| 453 | pwd->b[i] = msa_ ## func ## _df(df, pwd->b[i], pws->b[i], \ |
| 454 | u5); \ |
| 455 | } \ |
| 456 | break; \ |
| 457 | case DF_HALF: \ |
| 458 | for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) { \ |
| 459 | pwd->h[i] = msa_ ## func ## _df(df, pwd->h[i], pws->h[i], \ |
| 460 | u5); \ |
| 461 | } \ |
| 462 | break; \ |
| 463 | case DF_WORD: \ |
| 464 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { \ |
| 465 | pwd->w[i] = msa_ ## func ## _df(df, pwd->w[i], pws->w[i], \ |
| 466 | u5); \ |
| 467 | } \ |
| 468 | break; \ |
| 469 | case DF_DOUBLE: \ |
| 470 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { \ |
| 471 | pwd->d[i] = msa_ ## func ## _df(df, pwd->d[i], pws->d[i], \ |
| 472 | u5); \ |
| 473 | } \ |
| 474 | break; \ |
| 475 | default: \ |
| 476 | assert(0); \ |
| 477 | } \ |
| 478 | } |
| 479 | |
| 480 | MSA_TEROP_IMMU_DF(binsli, binsl) |
| 481 | MSA_TEROP_IMMU_DF(binsri, binsr) |
| 482 | #undef MSA_TEROP_IMMU_DF |
Yongbok Kim | 28f99f0 | 2014-11-01 05:28:46 +0000 | [diff] [blame] | 483 | |
| 484 | static inline int64_t msa_max_a_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 485 | { |
| 486 | uint64_t abs_arg1 = arg1 >= 0 ? arg1 : -arg1; |
| 487 | uint64_t abs_arg2 = arg2 >= 0 ? arg2 : -arg2; |
| 488 | return abs_arg1 > abs_arg2 ? arg1 : arg2; |
| 489 | } |
| 490 | |
| 491 | static inline int64_t msa_min_a_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 492 | { |
| 493 | uint64_t abs_arg1 = arg1 >= 0 ? arg1 : -arg1; |
| 494 | uint64_t abs_arg2 = arg2 >= 0 ? arg2 : -arg2; |
| 495 | return abs_arg1 < abs_arg2 ? arg1 : arg2; |
| 496 | } |
| 497 | |
| 498 | static inline int64_t msa_add_a_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 499 | { |
| 500 | uint64_t abs_arg1 = arg1 >= 0 ? arg1 : -arg1; |
| 501 | uint64_t abs_arg2 = arg2 >= 0 ? arg2 : -arg2; |
| 502 | return abs_arg1 + abs_arg2; |
| 503 | } |
| 504 | |
| 505 | static inline int64_t msa_adds_a_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 506 | { |
| 507 | uint64_t max_int = (uint64_t)DF_MAX_INT(df); |
| 508 | uint64_t abs_arg1 = arg1 >= 0 ? arg1 : -arg1; |
| 509 | uint64_t abs_arg2 = arg2 >= 0 ? arg2 : -arg2; |
| 510 | if (abs_arg1 > max_int || abs_arg2 > max_int) { |
| 511 | return (int64_t)max_int; |
| 512 | } else { |
| 513 | return (abs_arg1 < max_int - abs_arg2) ? abs_arg1 + abs_arg2 : max_int; |
| 514 | } |
| 515 | } |
| 516 | |
| 517 | static inline int64_t msa_adds_s_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 518 | { |
| 519 | int64_t max_int = DF_MAX_INT(df); |
| 520 | int64_t min_int = DF_MIN_INT(df); |
| 521 | if (arg1 < 0) { |
| 522 | return (min_int - arg1 < arg2) ? arg1 + arg2 : min_int; |
| 523 | } else { |
| 524 | return (arg2 < max_int - arg1) ? arg1 + arg2 : max_int; |
| 525 | } |
| 526 | } |
| 527 | |
| 528 | static inline uint64_t msa_adds_u_df(uint32_t df, uint64_t arg1, uint64_t arg2) |
| 529 | { |
| 530 | uint64_t max_uint = DF_MAX_UINT(df); |
| 531 | uint64_t u_arg1 = UNSIGNED(arg1, df); |
| 532 | uint64_t u_arg2 = UNSIGNED(arg2, df); |
| 533 | return (u_arg1 < max_uint - u_arg2) ? u_arg1 + u_arg2 : max_uint; |
| 534 | } |
| 535 | |
| 536 | static inline int64_t msa_ave_s_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 537 | { |
| 538 | /* signed shift */ |
| 539 | return (arg1 >> 1) + (arg2 >> 1) + (arg1 & arg2 & 1); |
| 540 | } |
| 541 | |
| 542 | static inline uint64_t msa_ave_u_df(uint32_t df, uint64_t arg1, uint64_t arg2) |
| 543 | { |
| 544 | uint64_t u_arg1 = UNSIGNED(arg1, df); |
| 545 | uint64_t u_arg2 = UNSIGNED(arg2, df); |
| 546 | /* unsigned shift */ |
| 547 | return (u_arg1 >> 1) + (u_arg2 >> 1) + (u_arg1 & u_arg2 & 1); |
| 548 | } |
| 549 | |
| 550 | static inline int64_t msa_aver_s_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 551 | { |
| 552 | /* signed shift */ |
| 553 | return (arg1 >> 1) + (arg2 >> 1) + ((arg1 | arg2) & 1); |
| 554 | } |
| 555 | |
| 556 | static inline uint64_t msa_aver_u_df(uint32_t df, uint64_t arg1, uint64_t arg2) |
| 557 | { |
| 558 | uint64_t u_arg1 = UNSIGNED(arg1, df); |
| 559 | uint64_t u_arg2 = UNSIGNED(arg2, df); |
| 560 | /* unsigned shift */ |
| 561 | return (u_arg1 >> 1) + (u_arg2 >> 1) + ((u_arg1 | u_arg2) & 1); |
| 562 | } |
| 563 | |
| 564 | static inline int64_t msa_subs_s_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 565 | { |
| 566 | int64_t max_int = DF_MAX_INT(df); |
| 567 | int64_t min_int = DF_MIN_INT(df); |
| 568 | if (arg2 > 0) { |
| 569 | return (min_int + arg2 < arg1) ? arg1 - arg2 : min_int; |
| 570 | } else { |
| 571 | return (arg1 < max_int + arg2) ? arg1 - arg2 : max_int; |
| 572 | } |
| 573 | } |
| 574 | |
| 575 | static inline int64_t msa_subs_u_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 576 | { |
| 577 | uint64_t u_arg1 = UNSIGNED(arg1, df); |
| 578 | uint64_t u_arg2 = UNSIGNED(arg2, df); |
| 579 | return (u_arg1 > u_arg2) ? u_arg1 - u_arg2 : 0; |
| 580 | } |
| 581 | |
| 582 | static inline int64_t msa_subsus_u_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 583 | { |
| 584 | uint64_t u_arg1 = UNSIGNED(arg1, df); |
| 585 | uint64_t max_uint = DF_MAX_UINT(df); |
| 586 | if (arg2 >= 0) { |
| 587 | uint64_t u_arg2 = (uint64_t)arg2; |
| 588 | return (u_arg1 > u_arg2) ? |
| 589 | (int64_t)(u_arg1 - u_arg2) : |
| 590 | 0; |
| 591 | } else { |
| 592 | uint64_t u_arg2 = (uint64_t)(-arg2); |
| 593 | return (u_arg1 < max_uint - u_arg2) ? |
| 594 | (int64_t)(u_arg1 + u_arg2) : |
| 595 | (int64_t)max_uint; |
| 596 | } |
| 597 | } |
| 598 | |
| 599 | static inline int64_t msa_subsuu_s_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 600 | { |
| 601 | uint64_t u_arg1 = UNSIGNED(arg1, df); |
| 602 | uint64_t u_arg2 = UNSIGNED(arg2, df); |
| 603 | int64_t max_int = DF_MAX_INT(df); |
| 604 | int64_t min_int = DF_MIN_INT(df); |
| 605 | if (u_arg1 > u_arg2) { |
| 606 | return u_arg1 - u_arg2 < (uint64_t)max_int ? |
| 607 | (int64_t)(u_arg1 - u_arg2) : |
| 608 | max_int; |
| 609 | } else { |
| 610 | return u_arg2 - u_arg1 < (uint64_t)(-min_int) ? |
| 611 | (int64_t)(u_arg1 - u_arg2) : |
| 612 | min_int; |
| 613 | } |
| 614 | } |
| 615 | |
| 616 | static inline int64_t msa_asub_s_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 617 | { |
| 618 | /* signed compare */ |
| 619 | return (arg1 < arg2) ? |
| 620 | (uint64_t)(arg2 - arg1) : (uint64_t)(arg1 - arg2); |
| 621 | } |
| 622 | |
| 623 | static inline uint64_t msa_asub_u_df(uint32_t df, uint64_t arg1, uint64_t arg2) |
| 624 | { |
| 625 | uint64_t u_arg1 = UNSIGNED(arg1, df); |
| 626 | uint64_t u_arg2 = UNSIGNED(arg2, df); |
| 627 | /* unsigned compare */ |
| 628 | return (u_arg1 < u_arg2) ? |
| 629 | (uint64_t)(u_arg2 - u_arg1) : (uint64_t)(u_arg1 - u_arg2); |
| 630 | } |
| 631 | |
| 632 | static inline int64_t msa_mulv_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 633 | { |
| 634 | return arg1 * arg2; |
| 635 | } |
| 636 | |
| 637 | static inline int64_t msa_div_s_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 638 | { |
| 639 | if (arg1 == DF_MIN_INT(df) && arg2 == -1) { |
| 640 | return DF_MIN_INT(df); |
| 641 | } |
| 642 | return arg2 ? arg1 / arg2 : 0; |
| 643 | } |
| 644 | |
| 645 | static inline int64_t msa_div_u_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 646 | { |
| 647 | uint64_t u_arg1 = UNSIGNED(arg1, df); |
| 648 | uint64_t u_arg2 = UNSIGNED(arg2, df); |
| 649 | return u_arg2 ? u_arg1 / u_arg2 : 0; |
| 650 | } |
| 651 | |
| 652 | static inline int64_t msa_mod_s_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 653 | { |
| 654 | if (arg1 == DF_MIN_INT(df) && arg2 == -1) { |
| 655 | return 0; |
| 656 | } |
| 657 | return arg2 ? arg1 % arg2 : 0; |
| 658 | } |
| 659 | |
| 660 | static inline int64_t msa_mod_u_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 661 | { |
| 662 | uint64_t u_arg1 = UNSIGNED(arg1, df); |
| 663 | uint64_t u_arg2 = UNSIGNED(arg2, df); |
| 664 | return u_arg2 ? u_arg1 % u_arg2 : 0; |
| 665 | } |
| 666 | |
| 667 | #define SIGNED_EVEN(a, df) \ |
| 668 | ((((int64_t)(a)) << (64 - DF_BITS(df)/2)) >> (64 - DF_BITS(df)/2)) |
| 669 | |
| 670 | #define UNSIGNED_EVEN(a, df) \ |
| 671 | ((((uint64_t)(a)) << (64 - DF_BITS(df)/2)) >> (64 - DF_BITS(df)/2)) |
| 672 | |
| 673 | #define SIGNED_ODD(a, df) \ |
| 674 | ((((int64_t)(a)) << (64 - DF_BITS(df))) >> (64 - DF_BITS(df)/2)) |
| 675 | |
| 676 | #define UNSIGNED_ODD(a, df) \ |
| 677 | ((((uint64_t)(a)) << (64 - DF_BITS(df))) >> (64 - DF_BITS(df)/2)) |
| 678 | |
| 679 | #define SIGNED_EXTRACT(e, o, a, df) \ |
| 680 | do { \ |
| 681 | e = SIGNED_EVEN(a, df); \ |
| 682 | o = SIGNED_ODD(a, df); \ |
| 683 | } while (0); |
| 684 | |
| 685 | #define UNSIGNED_EXTRACT(e, o, a, df) \ |
| 686 | do { \ |
| 687 | e = UNSIGNED_EVEN(a, df); \ |
| 688 | o = UNSIGNED_ODD(a, df); \ |
| 689 | } while (0); |
| 690 | |
| 691 | static inline int64_t msa_dotp_s_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 692 | { |
| 693 | int64_t even_arg1; |
| 694 | int64_t even_arg2; |
| 695 | int64_t odd_arg1; |
| 696 | int64_t odd_arg2; |
| 697 | SIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); |
| 698 | SIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); |
| 699 | return (even_arg1 * even_arg2) + (odd_arg1 * odd_arg2); |
| 700 | } |
| 701 | |
| 702 | static inline int64_t msa_dotp_u_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 703 | { |
| 704 | int64_t even_arg1; |
| 705 | int64_t even_arg2; |
| 706 | int64_t odd_arg1; |
| 707 | int64_t odd_arg2; |
| 708 | UNSIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); |
| 709 | UNSIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); |
| 710 | return (even_arg1 * even_arg2) + (odd_arg1 * odd_arg2); |
| 711 | } |
| 712 | |
| 713 | #define CONCATENATE_AND_SLIDE(s, k) \ |
| 714 | do { \ |
| 715 | for (i = 0; i < s; i++) { \ |
| 716 | v[i] = pws->b[s * k + i]; \ |
| 717 | v[i + s] = pwd->b[s * k + i]; \ |
| 718 | } \ |
| 719 | for (i = 0; i < s; i++) { \ |
| 720 | pwd->b[s * k + i] = v[i + n]; \ |
| 721 | } \ |
| 722 | } while (0) |
| 723 | |
| 724 | static inline void msa_sld_df(uint32_t df, wr_t *pwd, |
| 725 | wr_t *pws, target_ulong rt) |
| 726 | { |
| 727 | uint32_t n = rt % DF_ELEMENTS(df); |
| 728 | uint8_t v[64]; |
| 729 | uint32_t i, k; |
| 730 | |
| 731 | switch (df) { |
| 732 | case DF_BYTE: |
| 733 | CONCATENATE_AND_SLIDE(DF_ELEMENTS(DF_BYTE), 0); |
| 734 | break; |
| 735 | case DF_HALF: |
| 736 | for (k = 0; k < 2; k++) { |
| 737 | CONCATENATE_AND_SLIDE(DF_ELEMENTS(DF_HALF), k); |
| 738 | } |
| 739 | break; |
| 740 | case DF_WORD: |
| 741 | for (k = 0; k < 4; k++) { |
| 742 | CONCATENATE_AND_SLIDE(DF_ELEMENTS(DF_WORD), k); |
| 743 | } |
| 744 | break; |
| 745 | case DF_DOUBLE: |
| 746 | for (k = 0; k < 8; k++) { |
| 747 | CONCATENATE_AND_SLIDE(DF_ELEMENTS(DF_DOUBLE), k); |
| 748 | } |
| 749 | break; |
| 750 | default: |
| 751 | assert(0); |
| 752 | } |
| 753 | } |
| 754 | |
| 755 | static inline int64_t msa_hadd_s_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 756 | { |
| 757 | return SIGNED_ODD(arg1, df) + SIGNED_EVEN(arg2, df); |
| 758 | } |
| 759 | |
| 760 | static inline int64_t msa_hadd_u_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 761 | { |
| 762 | return UNSIGNED_ODD(arg1, df) + UNSIGNED_EVEN(arg2, df); |
| 763 | } |
| 764 | |
| 765 | static inline int64_t msa_hsub_s_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 766 | { |
| 767 | return SIGNED_ODD(arg1, df) - SIGNED_EVEN(arg2, df); |
| 768 | } |
| 769 | |
| 770 | static inline int64_t msa_hsub_u_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 771 | { |
| 772 | return UNSIGNED_ODD(arg1, df) - UNSIGNED_EVEN(arg2, df); |
| 773 | } |
| 774 | |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 775 | static inline int64_t msa_mul_q_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 776 | { |
| 777 | int64_t q_min = DF_MIN_INT(df); |
| 778 | int64_t q_max = DF_MAX_INT(df); |
| 779 | |
| 780 | if (arg1 == q_min && arg2 == q_min) { |
| 781 | return q_max; |
| 782 | } |
| 783 | return (arg1 * arg2) >> (DF_BITS(df) - 1); |
| 784 | } |
| 785 | |
| 786 | static inline int64_t msa_mulr_q_df(uint32_t df, int64_t arg1, int64_t arg2) |
| 787 | { |
| 788 | int64_t q_min = DF_MIN_INT(df); |
| 789 | int64_t q_max = DF_MAX_INT(df); |
| 790 | int64_t r_bit = 1 << (DF_BITS(df) - 2); |
| 791 | |
| 792 | if (arg1 == q_min && arg2 == q_min) { |
| 793 | return q_max; |
| 794 | } |
| 795 | return (arg1 * arg2 + r_bit) >> (DF_BITS(df) - 1); |
| 796 | } |
| 797 | |
Yongbok Kim | 28f99f0 | 2014-11-01 05:28:46 +0000 | [diff] [blame] | 798 | #define MSA_BINOP_DF(func) \ |
| 799 | void helper_msa_ ## func ## _df(CPUMIPSState *env, uint32_t df, \ |
| 800 | uint32_t wd, uint32_t ws, uint32_t wt) \ |
| 801 | { \ |
| 802 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \ |
| 803 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); \ |
| 804 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); \ |
| 805 | uint32_t i; \ |
| 806 | \ |
| 807 | switch (df) { \ |
| 808 | case DF_BYTE: \ |
| 809 | for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) { \ |
| 810 | pwd->b[i] = msa_ ## func ## _df(df, pws->b[i], pwt->b[i]); \ |
| 811 | } \ |
| 812 | break; \ |
| 813 | case DF_HALF: \ |
| 814 | for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) { \ |
| 815 | pwd->h[i] = msa_ ## func ## _df(df, pws->h[i], pwt->h[i]); \ |
| 816 | } \ |
| 817 | break; \ |
| 818 | case DF_WORD: \ |
| 819 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { \ |
| 820 | pwd->w[i] = msa_ ## func ## _df(df, pws->w[i], pwt->w[i]); \ |
| 821 | } \ |
| 822 | break; \ |
| 823 | case DF_DOUBLE: \ |
| 824 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { \ |
| 825 | pwd->d[i] = msa_ ## func ## _df(df, pws->d[i], pwt->d[i]); \ |
| 826 | } \ |
| 827 | break; \ |
| 828 | default: \ |
| 829 | assert(0); \ |
| 830 | } \ |
| 831 | } |
| 832 | |
| 833 | MSA_BINOP_DF(sll) |
| 834 | MSA_BINOP_DF(sra) |
| 835 | MSA_BINOP_DF(srl) |
| 836 | MSA_BINOP_DF(bclr) |
| 837 | MSA_BINOP_DF(bset) |
| 838 | MSA_BINOP_DF(bneg) |
| 839 | MSA_BINOP_DF(addv) |
| 840 | MSA_BINOP_DF(subv) |
| 841 | MSA_BINOP_DF(max_s) |
| 842 | MSA_BINOP_DF(max_u) |
| 843 | MSA_BINOP_DF(min_s) |
| 844 | MSA_BINOP_DF(min_u) |
| 845 | MSA_BINOP_DF(max_a) |
| 846 | MSA_BINOP_DF(min_a) |
| 847 | MSA_BINOP_DF(ceq) |
| 848 | MSA_BINOP_DF(clt_s) |
| 849 | MSA_BINOP_DF(clt_u) |
| 850 | MSA_BINOP_DF(cle_s) |
| 851 | MSA_BINOP_DF(cle_u) |
| 852 | MSA_BINOP_DF(add_a) |
| 853 | MSA_BINOP_DF(adds_a) |
| 854 | MSA_BINOP_DF(adds_s) |
| 855 | MSA_BINOP_DF(adds_u) |
| 856 | MSA_BINOP_DF(ave_s) |
| 857 | MSA_BINOP_DF(ave_u) |
| 858 | MSA_BINOP_DF(aver_s) |
| 859 | MSA_BINOP_DF(aver_u) |
| 860 | MSA_BINOP_DF(subs_s) |
| 861 | MSA_BINOP_DF(subs_u) |
| 862 | MSA_BINOP_DF(subsus_u) |
| 863 | MSA_BINOP_DF(subsuu_s) |
| 864 | MSA_BINOP_DF(asub_s) |
| 865 | MSA_BINOP_DF(asub_u) |
| 866 | MSA_BINOP_DF(mulv) |
| 867 | MSA_BINOP_DF(div_s) |
| 868 | MSA_BINOP_DF(div_u) |
| 869 | MSA_BINOP_DF(mod_s) |
| 870 | MSA_BINOP_DF(mod_u) |
| 871 | MSA_BINOP_DF(dotp_s) |
| 872 | MSA_BINOP_DF(dotp_u) |
| 873 | MSA_BINOP_DF(srar) |
| 874 | MSA_BINOP_DF(srlr) |
| 875 | MSA_BINOP_DF(hadd_s) |
| 876 | MSA_BINOP_DF(hadd_u) |
| 877 | MSA_BINOP_DF(hsub_s) |
| 878 | MSA_BINOP_DF(hsub_u) |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 879 | |
| 880 | MSA_BINOP_DF(mul_q) |
| 881 | MSA_BINOP_DF(mulr_q) |
Yongbok Kim | 28f99f0 | 2014-11-01 05:28:46 +0000 | [diff] [blame] | 882 | #undef MSA_BINOP_DF |
| 883 | |
| 884 | void helper_msa_sld_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 885 | uint32_t ws, uint32_t rt) |
| 886 | { |
| 887 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 888 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 889 | |
| 890 | msa_sld_df(df, pwd, pws, env->active_tc.gpr[rt]); |
| 891 | } |
| 892 | |
| 893 | static inline int64_t msa_maddv_df(uint32_t df, int64_t dest, int64_t arg1, |
| 894 | int64_t arg2) |
| 895 | { |
| 896 | return dest + arg1 * arg2; |
| 897 | } |
| 898 | |
| 899 | static inline int64_t msa_msubv_df(uint32_t df, int64_t dest, int64_t arg1, |
| 900 | int64_t arg2) |
| 901 | { |
| 902 | return dest - arg1 * arg2; |
| 903 | } |
| 904 | |
| 905 | static inline int64_t msa_dpadd_s_df(uint32_t df, int64_t dest, int64_t arg1, |
| 906 | int64_t arg2) |
| 907 | { |
| 908 | int64_t even_arg1; |
| 909 | int64_t even_arg2; |
| 910 | int64_t odd_arg1; |
| 911 | int64_t odd_arg2; |
| 912 | SIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); |
| 913 | SIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); |
| 914 | return dest + (even_arg1 * even_arg2) + (odd_arg1 * odd_arg2); |
| 915 | } |
| 916 | |
| 917 | static inline int64_t msa_dpadd_u_df(uint32_t df, int64_t dest, int64_t arg1, |
| 918 | int64_t arg2) |
| 919 | { |
| 920 | int64_t even_arg1; |
| 921 | int64_t even_arg2; |
| 922 | int64_t odd_arg1; |
| 923 | int64_t odd_arg2; |
| 924 | UNSIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); |
| 925 | UNSIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); |
| 926 | return dest + (even_arg1 * even_arg2) + (odd_arg1 * odd_arg2); |
| 927 | } |
| 928 | |
| 929 | static inline int64_t msa_dpsub_s_df(uint32_t df, int64_t dest, int64_t arg1, |
| 930 | int64_t arg2) |
| 931 | { |
| 932 | int64_t even_arg1; |
| 933 | int64_t even_arg2; |
| 934 | int64_t odd_arg1; |
| 935 | int64_t odd_arg2; |
| 936 | SIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); |
| 937 | SIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); |
| 938 | return dest - ((even_arg1 * even_arg2) + (odd_arg1 * odd_arg2)); |
| 939 | } |
| 940 | |
| 941 | static inline int64_t msa_dpsub_u_df(uint32_t df, int64_t dest, int64_t arg1, |
| 942 | int64_t arg2) |
| 943 | { |
| 944 | int64_t even_arg1; |
| 945 | int64_t even_arg2; |
| 946 | int64_t odd_arg1; |
| 947 | int64_t odd_arg2; |
| 948 | UNSIGNED_EXTRACT(even_arg1, odd_arg1, arg1, df); |
| 949 | UNSIGNED_EXTRACT(even_arg2, odd_arg2, arg2, df); |
| 950 | return dest - ((even_arg1 * even_arg2) + (odd_arg1 * odd_arg2)); |
| 951 | } |
| 952 | |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 953 | static inline int64_t msa_madd_q_df(uint32_t df, int64_t dest, int64_t arg1, |
| 954 | int64_t arg2) |
| 955 | { |
| 956 | int64_t q_prod, q_ret; |
| 957 | |
| 958 | int64_t q_max = DF_MAX_INT(df); |
| 959 | int64_t q_min = DF_MIN_INT(df); |
| 960 | |
| 961 | q_prod = arg1 * arg2; |
| 962 | q_ret = ((dest << (DF_BITS(df) - 1)) + q_prod) >> (DF_BITS(df) - 1); |
| 963 | |
| 964 | return (q_ret < q_min) ? q_min : (q_max < q_ret) ? q_max : q_ret; |
| 965 | } |
| 966 | |
| 967 | static inline int64_t msa_msub_q_df(uint32_t df, int64_t dest, int64_t arg1, |
| 968 | int64_t arg2) |
| 969 | { |
| 970 | int64_t q_prod, q_ret; |
| 971 | |
| 972 | int64_t q_max = DF_MAX_INT(df); |
| 973 | int64_t q_min = DF_MIN_INT(df); |
| 974 | |
| 975 | q_prod = arg1 * arg2; |
| 976 | q_ret = ((dest << (DF_BITS(df) - 1)) - q_prod) >> (DF_BITS(df) - 1); |
| 977 | |
| 978 | return (q_ret < q_min) ? q_min : (q_max < q_ret) ? q_max : q_ret; |
| 979 | } |
| 980 | |
| 981 | static inline int64_t msa_maddr_q_df(uint32_t df, int64_t dest, int64_t arg1, |
| 982 | int64_t arg2) |
| 983 | { |
| 984 | int64_t q_prod, q_ret; |
| 985 | |
| 986 | int64_t q_max = DF_MAX_INT(df); |
| 987 | int64_t q_min = DF_MIN_INT(df); |
| 988 | int64_t r_bit = 1 << (DF_BITS(df) - 2); |
| 989 | |
| 990 | q_prod = arg1 * arg2; |
| 991 | q_ret = ((dest << (DF_BITS(df) - 1)) + q_prod + r_bit) >> (DF_BITS(df) - 1); |
| 992 | |
| 993 | return (q_ret < q_min) ? q_min : (q_max < q_ret) ? q_max : q_ret; |
| 994 | } |
| 995 | |
| 996 | static inline int64_t msa_msubr_q_df(uint32_t df, int64_t dest, int64_t arg1, |
| 997 | int64_t arg2) |
| 998 | { |
| 999 | int64_t q_prod, q_ret; |
| 1000 | |
| 1001 | int64_t q_max = DF_MAX_INT(df); |
| 1002 | int64_t q_min = DF_MIN_INT(df); |
| 1003 | int64_t r_bit = 1 << (DF_BITS(df) - 2); |
| 1004 | |
| 1005 | q_prod = arg1 * arg2; |
| 1006 | q_ret = ((dest << (DF_BITS(df) - 1)) - q_prod + r_bit) >> (DF_BITS(df) - 1); |
| 1007 | |
| 1008 | return (q_ret < q_min) ? q_min : (q_max < q_ret) ? q_max : q_ret; |
| 1009 | } |
| 1010 | |
Yongbok Kim | 28f99f0 | 2014-11-01 05:28:46 +0000 | [diff] [blame] | 1011 | #define MSA_TEROP_DF(func) \ |
| 1012 | void helper_msa_ ## func ## _df(CPUMIPSState *env, uint32_t df, uint32_t wd, \ |
| 1013 | uint32_t ws, uint32_t wt) \ |
| 1014 | { \ |
| 1015 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \ |
| 1016 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); \ |
| 1017 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); \ |
| 1018 | uint32_t i; \ |
| 1019 | \ |
| 1020 | switch (df) { \ |
| 1021 | case DF_BYTE: \ |
| 1022 | for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) { \ |
| 1023 | pwd->b[i] = msa_ ## func ## _df(df, pwd->b[i], pws->b[i], \ |
| 1024 | pwt->b[i]); \ |
| 1025 | } \ |
| 1026 | break; \ |
| 1027 | case DF_HALF: \ |
| 1028 | for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) { \ |
| 1029 | pwd->h[i] = msa_ ## func ## _df(df, pwd->h[i], pws->h[i], \ |
| 1030 | pwt->h[i]); \ |
| 1031 | } \ |
| 1032 | break; \ |
| 1033 | case DF_WORD: \ |
| 1034 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { \ |
| 1035 | pwd->w[i] = msa_ ## func ## _df(df, pwd->w[i], pws->w[i], \ |
| 1036 | pwt->w[i]); \ |
| 1037 | } \ |
| 1038 | break; \ |
| 1039 | case DF_DOUBLE: \ |
| 1040 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { \ |
| 1041 | pwd->d[i] = msa_ ## func ## _df(df, pwd->d[i], pws->d[i], \ |
| 1042 | pwt->d[i]); \ |
| 1043 | } \ |
| 1044 | break; \ |
| 1045 | default: \ |
| 1046 | assert(0); \ |
| 1047 | } \ |
| 1048 | } |
| 1049 | |
| 1050 | MSA_TEROP_DF(maddv) |
| 1051 | MSA_TEROP_DF(msubv) |
| 1052 | MSA_TEROP_DF(dpadd_s) |
| 1053 | MSA_TEROP_DF(dpadd_u) |
| 1054 | MSA_TEROP_DF(dpsub_s) |
| 1055 | MSA_TEROP_DF(dpsub_u) |
| 1056 | MSA_TEROP_DF(binsl) |
| 1057 | MSA_TEROP_DF(binsr) |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1058 | MSA_TEROP_DF(madd_q) |
| 1059 | MSA_TEROP_DF(msub_q) |
| 1060 | MSA_TEROP_DF(maddr_q) |
| 1061 | MSA_TEROP_DF(msubr_q) |
Yongbok Kim | 28f99f0 | 2014-11-01 05:28:46 +0000 | [diff] [blame] | 1062 | #undef MSA_TEROP_DF |
| 1063 | |
| 1064 | static inline void msa_splat_df(uint32_t df, wr_t *pwd, |
| 1065 | wr_t *pws, target_ulong rt) |
| 1066 | { |
| 1067 | uint32_t n = rt % DF_ELEMENTS(df); |
| 1068 | uint32_t i; |
| 1069 | |
| 1070 | switch (df) { |
| 1071 | case DF_BYTE: |
| 1072 | for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) { |
| 1073 | pwd->b[i] = pws->b[n]; |
| 1074 | } |
| 1075 | break; |
| 1076 | case DF_HALF: |
| 1077 | for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) { |
| 1078 | pwd->h[i] = pws->h[n]; |
| 1079 | } |
| 1080 | break; |
| 1081 | case DF_WORD: |
| 1082 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 1083 | pwd->w[i] = pws->w[n]; |
| 1084 | } |
| 1085 | break; |
| 1086 | case DF_DOUBLE: |
| 1087 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 1088 | pwd->d[i] = pws->d[n]; |
| 1089 | } |
| 1090 | break; |
| 1091 | default: |
| 1092 | assert(0); |
| 1093 | } |
| 1094 | } |
| 1095 | |
| 1096 | void helper_msa_splat_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 1097 | uint32_t ws, uint32_t rt) |
| 1098 | { |
| 1099 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 1100 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 1101 | |
| 1102 | msa_splat_df(df, pwd, pws, env->active_tc.gpr[rt]); |
| 1103 | } |
| 1104 | |
| 1105 | #define MSA_DO_B MSA_DO(b) |
| 1106 | #define MSA_DO_H MSA_DO(h) |
| 1107 | #define MSA_DO_W MSA_DO(w) |
| 1108 | #define MSA_DO_D MSA_DO(d) |
| 1109 | |
| 1110 | #define MSA_LOOP_B MSA_LOOP(B) |
| 1111 | #define MSA_LOOP_H MSA_LOOP(H) |
| 1112 | #define MSA_LOOP_W MSA_LOOP(W) |
| 1113 | #define MSA_LOOP_D MSA_LOOP(D) |
| 1114 | |
| 1115 | #define MSA_LOOP_COND_B MSA_LOOP_COND(DF_BYTE) |
| 1116 | #define MSA_LOOP_COND_H MSA_LOOP_COND(DF_HALF) |
| 1117 | #define MSA_LOOP_COND_W MSA_LOOP_COND(DF_WORD) |
| 1118 | #define MSA_LOOP_COND_D MSA_LOOP_COND(DF_DOUBLE) |
| 1119 | |
| 1120 | #define MSA_LOOP(DF) \ |
| 1121 | for (i = 0; i < (MSA_LOOP_COND_ ## DF) ; i++) { \ |
| 1122 | MSA_DO_ ## DF \ |
| 1123 | } |
| 1124 | |
| 1125 | #define MSA_FN_DF(FUNC) \ |
| 1126 | void helper_msa_##FUNC(CPUMIPSState *env, uint32_t df, uint32_t wd, \ |
| 1127 | uint32_t ws, uint32_t wt) \ |
| 1128 | { \ |
| 1129 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \ |
| 1130 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); \ |
| 1131 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); \ |
| 1132 | wr_t wx, *pwx = &wx; \ |
| 1133 | uint32_t i; \ |
| 1134 | switch (df) { \ |
| 1135 | case DF_BYTE: \ |
| 1136 | MSA_LOOP_B \ |
| 1137 | break; \ |
| 1138 | case DF_HALF: \ |
| 1139 | MSA_LOOP_H \ |
| 1140 | break; \ |
| 1141 | case DF_WORD: \ |
| 1142 | MSA_LOOP_W \ |
| 1143 | break; \ |
| 1144 | case DF_DOUBLE: \ |
| 1145 | MSA_LOOP_D \ |
| 1146 | break; \ |
| 1147 | default: \ |
| 1148 | assert(0); \ |
| 1149 | } \ |
| 1150 | msa_move_v(pwd, pwx); \ |
| 1151 | } |
| 1152 | |
| 1153 | #define MSA_LOOP_COND(DF) \ |
| 1154 | (DF_ELEMENTS(DF) / 2) |
| 1155 | |
| 1156 | #define Rb(pwr, i) (pwr->b[i]) |
| 1157 | #define Lb(pwr, i) (pwr->b[i + DF_ELEMENTS(DF_BYTE)/2]) |
| 1158 | #define Rh(pwr, i) (pwr->h[i]) |
| 1159 | #define Lh(pwr, i) (pwr->h[i + DF_ELEMENTS(DF_HALF)/2]) |
| 1160 | #define Rw(pwr, i) (pwr->w[i]) |
| 1161 | #define Lw(pwr, i) (pwr->w[i + DF_ELEMENTS(DF_WORD)/2]) |
| 1162 | #define Rd(pwr, i) (pwr->d[i]) |
| 1163 | #define Ld(pwr, i) (pwr->d[i + DF_ELEMENTS(DF_DOUBLE)/2]) |
| 1164 | |
| 1165 | #define MSA_DO(DF) \ |
| 1166 | do { \ |
| 1167 | R##DF(pwx, i) = pwt->DF[2*i]; \ |
| 1168 | L##DF(pwx, i) = pws->DF[2*i]; \ |
| 1169 | } while (0); |
| 1170 | MSA_FN_DF(pckev_df) |
| 1171 | #undef MSA_DO |
| 1172 | |
| 1173 | #define MSA_DO(DF) \ |
| 1174 | do { \ |
| 1175 | R##DF(pwx, i) = pwt->DF[2*i+1]; \ |
| 1176 | L##DF(pwx, i) = pws->DF[2*i+1]; \ |
| 1177 | } while (0); |
| 1178 | MSA_FN_DF(pckod_df) |
| 1179 | #undef MSA_DO |
| 1180 | |
| 1181 | #define MSA_DO(DF) \ |
| 1182 | do { \ |
| 1183 | pwx->DF[2*i] = L##DF(pwt, i); \ |
| 1184 | pwx->DF[2*i+1] = L##DF(pws, i); \ |
| 1185 | } while (0); |
| 1186 | MSA_FN_DF(ilvl_df) |
| 1187 | #undef MSA_DO |
| 1188 | |
| 1189 | #define MSA_DO(DF) \ |
| 1190 | do { \ |
| 1191 | pwx->DF[2*i] = R##DF(pwt, i); \ |
| 1192 | pwx->DF[2*i+1] = R##DF(pws, i); \ |
| 1193 | } while (0); |
| 1194 | MSA_FN_DF(ilvr_df) |
| 1195 | #undef MSA_DO |
| 1196 | |
| 1197 | #define MSA_DO(DF) \ |
| 1198 | do { \ |
| 1199 | pwx->DF[2*i] = pwt->DF[2*i]; \ |
| 1200 | pwx->DF[2*i+1] = pws->DF[2*i]; \ |
| 1201 | } while (0); |
| 1202 | MSA_FN_DF(ilvev_df) |
| 1203 | #undef MSA_DO |
| 1204 | |
| 1205 | #define MSA_DO(DF) \ |
| 1206 | do { \ |
| 1207 | pwx->DF[2*i] = pwt->DF[2*i+1]; \ |
| 1208 | pwx->DF[2*i+1] = pws->DF[2*i+1]; \ |
| 1209 | } while (0); |
| 1210 | MSA_FN_DF(ilvod_df) |
| 1211 | #undef MSA_DO |
| 1212 | #undef MSA_LOOP_COND |
| 1213 | |
| 1214 | #define MSA_LOOP_COND(DF) \ |
| 1215 | (DF_ELEMENTS(DF)) |
| 1216 | |
| 1217 | #define MSA_DO(DF) \ |
| 1218 | do { \ |
| 1219 | uint32_t n = DF_ELEMENTS(df); \ |
| 1220 | uint32_t k = (pwd->DF[i] & 0x3f) % (2 * n); \ |
| 1221 | pwx->DF[i] = \ |
| 1222 | (pwd->DF[i] & 0xc0) ? 0 : k < n ? pwt->DF[k] : pws->DF[k - n]; \ |
| 1223 | } while (0); |
| 1224 | MSA_FN_DF(vshf_df) |
| 1225 | #undef MSA_DO |
| 1226 | #undef MSA_LOOP_COND |
| 1227 | #undef MSA_FN_DF |
Yongbok Kim | 1e608ec | 2014-11-01 05:28:47 +0000 | [diff] [blame] | 1228 | |
| 1229 | void helper_msa_sldi_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 1230 | uint32_t ws, uint32_t n) |
| 1231 | { |
| 1232 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 1233 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 1234 | |
| 1235 | msa_sld_df(df, pwd, pws, n); |
| 1236 | } |
| 1237 | |
| 1238 | void helper_msa_splati_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 1239 | uint32_t ws, uint32_t n) |
| 1240 | { |
| 1241 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 1242 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 1243 | |
| 1244 | msa_splat_df(df, pwd, pws, n); |
| 1245 | } |
| 1246 | |
| 1247 | void helper_msa_copy_s_df(CPUMIPSState *env, uint32_t df, uint32_t rd, |
| 1248 | uint32_t ws, uint32_t n) |
| 1249 | { |
| 1250 | n %= DF_ELEMENTS(df); |
| 1251 | |
| 1252 | switch (df) { |
| 1253 | case DF_BYTE: |
| 1254 | env->active_tc.gpr[rd] = (int8_t)env->active_fpu.fpr[ws].wr.b[n]; |
| 1255 | break; |
| 1256 | case DF_HALF: |
| 1257 | env->active_tc.gpr[rd] = (int16_t)env->active_fpu.fpr[ws].wr.h[n]; |
| 1258 | break; |
| 1259 | case DF_WORD: |
| 1260 | env->active_tc.gpr[rd] = (int32_t)env->active_fpu.fpr[ws].wr.w[n]; |
| 1261 | break; |
| 1262 | #ifdef TARGET_MIPS64 |
| 1263 | case DF_DOUBLE: |
| 1264 | env->active_tc.gpr[rd] = (int64_t)env->active_fpu.fpr[ws].wr.d[n]; |
| 1265 | break; |
| 1266 | #endif |
| 1267 | default: |
| 1268 | assert(0); |
| 1269 | } |
| 1270 | } |
| 1271 | |
| 1272 | void helper_msa_copy_u_df(CPUMIPSState *env, uint32_t df, uint32_t rd, |
| 1273 | uint32_t ws, uint32_t n) |
| 1274 | { |
| 1275 | n %= DF_ELEMENTS(df); |
| 1276 | |
| 1277 | switch (df) { |
| 1278 | case DF_BYTE: |
| 1279 | env->active_tc.gpr[rd] = (uint8_t)env->active_fpu.fpr[ws].wr.b[n]; |
| 1280 | break; |
| 1281 | case DF_HALF: |
| 1282 | env->active_tc.gpr[rd] = (uint16_t)env->active_fpu.fpr[ws].wr.h[n]; |
| 1283 | break; |
| 1284 | case DF_WORD: |
| 1285 | env->active_tc.gpr[rd] = (uint32_t)env->active_fpu.fpr[ws].wr.w[n]; |
| 1286 | break; |
| 1287 | #ifdef TARGET_MIPS64 |
| 1288 | case DF_DOUBLE: |
| 1289 | env->active_tc.gpr[rd] = (uint64_t)env->active_fpu.fpr[ws].wr.d[n]; |
| 1290 | break; |
| 1291 | #endif |
| 1292 | default: |
| 1293 | assert(0); |
| 1294 | } |
| 1295 | } |
| 1296 | |
| 1297 | void helper_msa_insert_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 1298 | uint32_t rs_num, uint32_t n) |
| 1299 | { |
| 1300 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 1301 | target_ulong rs = env->active_tc.gpr[rs_num]; |
| 1302 | |
| 1303 | switch (df) { |
| 1304 | case DF_BYTE: |
| 1305 | pwd->b[n] = (int8_t)rs; |
| 1306 | break; |
| 1307 | case DF_HALF: |
| 1308 | pwd->h[n] = (int16_t)rs; |
| 1309 | break; |
| 1310 | case DF_WORD: |
| 1311 | pwd->w[n] = (int32_t)rs; |
| 1312 | break; |
| 1313 | case DF_DOUBLE: |
| 1314 | pwd->d[n] = (int64_t)rs; |
| 1315 | break; |
| 1316 | default: |
| 1317 | assert(0); |
| 1318 | } |
| 1319 | } |
| 1320 | |
| 1321 | void helper_msa_insve_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 1322 | uint32_t ws, uint32_t n) |
| 1323 | { |
| 1324 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 1325 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 1326 | |
| 1327 | switch (df) { |
| 1328 | case DF_BYTE: |
| 1329 | pwd->b[n] = (int8_t)pws->b[0]; |
| 1330 | break; |
| 1331 | case DF_HALF: |
| 1332 | pwd->h[n] = (int16_t)pws->h[0]; |
| 1333 | break; |
| 1334 | case DF_WORD: |
| 1335 | pwd->w[n] = (int32_t)pws->w[0]; |
| 1336 | break; |
| 1337 | case DF_DOUBLE: |
| 1338 | pwd->d[n] = (int64_t)pws->d[0]; |
| 1339 | break; |
| 1340 | default: |
| 1341 | assert(0); |
| 1342 | } |
| 1343 | } |
| 1344 | |
| 1345 | void helper_msa_ctcmsa(CPUMIPSState *env, target_ulong elm, uint32_t cd) |
| 1346 | { |
| 1347 | switch (cd) { |
| 1348 | case 0: |
| 1349 | break; |
| 1350 | case 1: |
| 1351 | env->active_tc.msacsr = (int32_t)elm & MSACSR_MASK; |
Leon Alrae | 6445111 | 2015-02-20 13:07:45 +0000 | [diff] [blame] | 1352 | restore_msa_fp_status(env); |
Yongbok Kim | 1e608ec | 2014-11-01 05:28:47 +0000 | [diff] [blame] | 1353 | /* check exception */ |
| 1354 | if ((GET_FP_ENABLE(env->active_tc.msacsr) | FP_UNIMPLEMENTED) |
| 1355 | & GET_FP_CAUSE(env->active_tc.msacsr)) { |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 1356 | do_raise_exception(env, EXCP_MSAFPE, GETPC()); |
Yongbok Kim | 1e608ec | 2014-11-01 05:28:47 +0000 | [diff] [blame] | 1357 | } |
| 1358 | break; |
| 1359 | } |
| 1360 | } |
| 1361 | |
| 1362 | target_ulong helper_msa_cfcmsa(CPUMIPSState *env, uint32_t cs) |
| 1363 | { |
| 1364 | switch (cs) { |
| 1365 | case 0: |
| 1366 | return env->msair; |
| 1367 | case 1: |
| 1368 | return env->active_tc.msacsr & MSACSR_MASK; |
| 1369 | } |
| 1370 | return 0; |
| 1371 | } |
| 1372 | |
| 1373 | void helper_msa_move_v(CPUMIPSState *env, uint32_t wd, uint32_t ws) |
| 1374 | { |
| 1375 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 1376 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 1377 | |
| 1378 | msa_move_v(pwd, pws); |
| 1379 | } |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1380 | |
Yongbok Kim | cbe50b9 | 2014-11-01 05:28:49 +0000 | [diff] [blame] | 1381 | static inline int64_t msa_pcnt_df(uint32_t df, int64_t arg) |
| 1382 | { |
| 1383 | uint64_t x; |
| 1384 | |
| 1385 | x = UNSIGNED(arg, df); |
| 1386 | |
| 1387 | x = (x & 0x5555555555555555ULL) + ((x >> 1) & 0x5555555555555555ULL); |
| 1388 | x = (x & 0x3333333333333333ULL) + ((x >> 2) & 0x3333333333333333ULL); |
| 1389 | x = (x & 0x0F0F0F0F0F0F0F0FULL) + ((x >> 4) & 0x0F0F0F0F0F0F0F0FULL); |
| 1390 | x = (x & 0x00FF00FF00FF00FFULL) + ((x >> 8) & 0x00FF00FF00FF00FFULL); |
| 1391 | x = (x & 0x0000FFFF0000FFFFULL) + ((x >> 16) & 0x0000FFFF0000FFFFULL); |
| 1392 | x = (x & 0x00000000FFFFFFFFULL) + ((x >> 32)); |
| 1393 | |
| 1394 | return x; |
| 1395 | } |
| 1396 | |
| 1397 | static inline int64_t msa_nlzc_df(uint32_t df, int64_t arg) |
| 1398 | { |
| 1399 | uint64_t x, y; |
| 1400 | int n, c; |
| 1401 | |
| 1402 | x = UNSIGNED(arg, df); |
| 1403 | n = DF_BITS(df); |
| 1404 | c = DF_BITS(df) / 2; |
| 1405 | |
| 1406 | do { |
| 1407 | y = x >> c; |
| 1408 | if (y != 0) { |
| 1409 | n = n - c; |
| 1410 | x = y; |
| 1411 | } |
| 1412 | c = c >> 1; |
| 1413 | } while (c != 0); |
| 1414 | |
| 1415 | return n - x; |
| 1416 | } |
| 1417 | |
| 1418 | static inline int64_t msa_nloc_df(uint32_t df, int64_t arg) |
| 1419 | { |
| 1420 | return msa_nlzc_df(df, UNSIGNED((~arg), df)); |
| 1421 | } |
| 1422 | |
| 1423 | void helper_msa_fill_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 1424 | uint32_t rs) |
| 1425 | { |
| 1426 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 1427 | uint32_t i; |
| 1428 | |
| 1429 | switch (df) { |
| 1430 | case DF_BYTE: |
| 1431 | for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) { |
| 1432 | pwd->b[i] = (int8_t)env->active_tc.gpr[rs]; |
| 1433 | } |
| 1434 | break; |
| 1435 | case DF_HALF: |
| 1436 | for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) { |
| 1437 | pwd->h[i] = (int16_t)env->active_tc.gpr[rs]; |
| 1438 | } |
| 1439 | break; |
| 1440 | case DF_WORD: |
| 1441 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 1442 | pwd->w[i] = (int32_t)env->active_tc.gpr[rs]; |
| 1443 | } |
| 1444 | break; |
| 1445 | case DF_DOUBLE: |
| 1446 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 1447 | pwd->d[i] = (int64_t)env->active_tc.gpr[rs]; |
| 1448 | } |
| 1449 | break; |
| 1450 | default: |
| 1451 | assert(0); |
| 1452 | } |
| 1453 | } |
| 1454 | |
| 1455 | #define MSA_UNOP_DF(func) \ |
| 1456 | void helper_msa_ ## func ## _df(CPUMIPSState *env, uint32_t df, \ |
| 1457 | uint32_t wd, uint32_t ws) \ |
| 1458 | { \ |
| 1459 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); \ |
| 1460 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); \ |
| 1461 | uint32_t i; \ |
| 1462 | \ |
| 1463 | switch (df) { \ |
| 1464 | case DF_BYTE: \ |
| 1465 | for (i = 0; i < DF_ELEMENTS(DF_BYTE); i++) { \ |
| 1466 | pwd->b[i] = msa_ ## func ## _df(df, pws->b[i]); \ |
| 1467 | } \ |
| 1468 | break; \ |
| 1469 | case DF_HALF: \ |
| 1470 | for (i = 0; i < DF_ELEMENTS(DF_HALF); i++) { \ |
| 1471 | pwd->h[i] = msa_ ## func ## _df(df, pws->h[i]); \ |
| 1472 | } \ |
| 1473 | break; \ |
| 1474 | case DF_WORD: \ |
| 1475 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { \ |
| 1476 | pwd->w[i] = msa_ ## func ## _df(df, pws->w[i]); \ |
| 1477 | } \ |
| 1478 | break; \ |
| 1479 | case DF_DOUBLE: \ |
| 1480 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { \ |
| 1481 | pwd->d[i] = msa_ ## func ## _df(df, pws->d[i]); \ |
| 1482 | } \ |
| 1483 | break; \ |
| 1484 | default: \ |
| 1485 | assert(0); \ |
| 1486 | } \ |
| 1487 | } |
| 1488 | |
| 1489 | MSA_UNOP_DF(nlzc) |
| 1490 | MSA_UNOP_DF(nloc) |
| 1491 | MSA_UNOP_DF(pcnt) |
Yongbok Kim | 3bdeb68 | 2014-11-01 05:28:50 +0000 | [diff] [blame] | 1492 | #undef MSA_UNOP_DF |
Yongbok Kim | cbe50b9 | 2014-11-01 05:28:49 +0000 | [diff] [blame] | 1493 | |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1494 | #define FLOAT_ONE32 make_float32(0x3f8 << 20) |
| 1495 | #define FLOAT_ONE64 make_float64(0x3ffULL << 52) |
| 1496 | |
| 1497 | #define FLOAT_SNAN16 (float16_default_nan ^ 0x0220) |
| 1498 | /* 0x7c20 */ |
| 1499 | #define FLOAT_SNAN32 (float32_default_nan ^ 0x00400020) |
| 1500 | /* 0x7f800020 */ |
| 1501 | #define FLOAT_SNAN64 (float64_default_nan ^ 0x0008000000000020ULL) |
| 1502 | /* 0x7ff0000000000020 */ |
| 1503 | |
| 1504 | static inline void clear_msacsr_cause(CPUMIPSState *env) |
| 1505 | { |
| 1506 | SET_FP_CAUSE(env->active_tc.msacsr, 0); |
| 1507 | } |
| 1508 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 1509 | static inline void check_msacsr_cause(CPUMIPSState *env, uintptr_t retaddr) |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1510 | { |
| 1511 | if ((GET_FP_CAUSE(env->active_tc.msacsr) & |
| 1512 | (GET_FP_ENABLE(env->active_tc.msacsr) | FP_UNIMPLEMENTED)) == 0) { |
| 1513 | UPDATE_FP_FLAGS(env->active_tc.msacsr, |
| 1514 | GET_FP_CAUSE(env->active_tc.msacsr)); |
| 1515 | } else { |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 1516 | do_raise_exception(env, EXCP_MSAFPE, retaddr); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1517 | } |
| 1518 | } |
| 1519 | |
| 1520 | /* Flush-to-zero use cases for update_msacsr() */ |
| 1521 | #define CLEAR_FS_UNDERFLOW 1 |
| 1522 | #define CLEAR_IS_INEXACT 2 |
| 1523 | #define RECIPROCAL_INEXACT 4 |
| 1524 | |
| 1525 | static inline int update_msacsr(CPUMIPSState *env, int action, int denormal) |
| 1526 | { |
| 1527 | int ieee_ex; |
| 1528 | |
| 1529 | int c; |
| 1530 | int cause; |
| 1531 | int enable; |
| 1532 | |
| 1533 | ieee_ex = get_float_exception_flags(&env->active_tc.msa_fp_status); |
| 1534 | |
| 1535 | /* QEMU softfloat does not signal all underflow cases */ |
| 1536 | if (denormal) { |
| 1537 | ieee_ex |= float_flag_underflow; |
| 1538 | } |
| 1539 | |
| 1540 | c = ieee_ex_to_mips(ieee_ex); |
| 1541 | enable = GET_FP_ENABLE(env->active_tc.msacsr) | FP_UNIMPLEMENTED; |
| 1542 | |
| 1543 | /* Set Inexact (I) when flushing inputs to zero */ |
| 1544 | if ((ieee_ex & float_flag_input_denormal) && |
| 1545 | (env->active_tc.msacsr & MSACSR_FS_MASK) != 0) { |
| 1546 | if (action & CLEAR_IS_INEXACT) { |
| 1547 | c &= ~FP_INEXACT; |
| 1548 | } else { |
| 1549 | c |= FP_INEXACT; |
| 1550 | } |
| 1551 | } |
| 1552 | |
| 1553 | /* Set Inexact (I) and Underflow (U) when flushing outputs to zero */ |
| 1554 | if ((ieee_ex & float_flag_output_denormal) && |
| 1555 | (env->active_tc.msacsr & MSACSR_FS_MASK) != 0) { |
| 1556 | c |= FP_INEXACT; |
| 1557 | if (action & CLEAR_FS_UNDERFLOW) { |
| 1558 | c &= ~FP_UNDERFLOW; |
| 1559 | } else { |
| 1560 | c |= FP_UNDERFLOW; |
| 1561 | } |
| 1562 | } |
| 1563 | |
| 1564 | /* Set Inexact (I) when Overflow (O) is not enabled */ |
| 1565 | if ((c & FP_OVERFLOW) != 0 && (enable & FP_OVERFLOW) == 0) { |
| 1566 | c |= FP_INEXACT; |
| 1567 | } |
| 1568 | |
| 1569 | /* Clear Exact Underflow when Underflow (U) is not enabled */ |
| 1570 | if ((c & FP_UNDERFLOW) != 0 && (enable & FP_UNDERFLOW) == 0 && |
| 1571 | (c & FP_INEXACT) == 0) { |
| 1572 | c &= ~FP_UNDERFLOW; |
| 1573 | } |
| 1574 | |
| 1575 | /* Reciprocal operations set only Inexact when valid and not |
| 1576 | divide by zero */ |
| 1577 | if ((action & RECIPROCAL_INEXACT) && |
| 1578 | (c & (FP_INVALID | FP_DIV0)) == 0) { |
| 1579 | c = FP_INEXACT; |
| 1580 | } |
| 1581 | |
| 1582 | cause = c & enable; /* all current enabled exceptions */ |
| 1583 | |
| 1584 | if (cause == 0) { |
| 1585 | /* No enabled exception, update the MSACSR Cause |
| 1586 | with all current exceptions */ |
| 1587 | SET_FP_CAUSE(env->active_tc.msacsr, |
| 1588 | (GET_FP_CAUSE(env->active_tc.msacsr) | c)); |
| 1589 | } else { |
| 1590 | /* Current exceptions are enabled */ |
| 1591 | if ((env->active_tc.msacsr & MSACSR_NX_MASK) == 0) { |
| 1592 | /* Exception(s) will trap, update MSACSR Cause |
| 1593 | with all enabled exceptions */ |
| 1594 | SET_FP_CAUSE(env->active_tc.msacsr, |
| 1595 | (GET_FP_CAUSE(env->active_tc.msacsr) | c)); |
| 1596 | } |
| 1597 | } |
| 1598 | |
| 1599 | return c; |
| 1600 | } |
| 1601 | |
| 1602 | static inline int get_enabled_exceptions(const CPUMIPSState *env, int c) |
| 1603 | { |
| 1604 | int enable = GET_FP_ENABLE(env->active_tc.msacsr) | FP_UNIMPLEMENTED; |
| 1605 | return c & enable; |
| 1606 | } |
| 1607 | |
Peter Maydell | f401451 | 2016-01-22 15:09:21 +0000 | [diff] [blame] | 1608 | static inline float16 float16_from_float32(int32_t a, flag ieee, |
Peter Maydell | e5a41ff | 2015-01-30 12:04:16 +0000 | [diff] [blame] | 1609 | float_status *status) |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1610 | { |
| 1611 | float16 f_val; |
| 1612 | |
Peter Maydell | ff32e16 | 2015-02-02 18:47:16 +0000 | [diff] [blame] | 1613 | f_val = float32_to_float16((float32)a, ieee, status); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1614 | f_val = float16_maybe_silence_nan(f_val); |
| 1615 | |
| 1616 | return a < 0 ? (f_val | (1 << 15)) : f_val; |
| 1617 | } |
| 1618 | |
Peter Maydell | f42c222 | 2016-01-22 15:09:20 +0000 | [diff] [blame] | 1619 | static inline float32 float32_from_float64(int64_t a, float_status *status) |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1620 | { |
| 1621 | float32 f_val; |
| 1622 | |
Peter Maydell | ff32e16 | 2015-02-02 18:47:16 +0000 | [diff] [blame] | 1623 | f_val = float64_to_float32((float64)a, status); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1624 | f_val = float32_maybe_silence_nan(f_val); |
| 1625 | |
| 1626 | return a < 0 ? (f_val | (1 << 31)) : f_val; |
| 1627 | } |
| 1628 | |
Peter Maydell | e5a41ff | 2015-01-30 12:04:16 +0000 | [diff] [blame] | 1629 | static inline float32 float32_from_float16(int16_t a, flag ieee, |
| 1630 | float_status *status) |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1631 | { |
| 1632 | float32 f_val; |
| 1633 | |
Peter Maydell | ff32e16 | 2015-02-02 18:47:16 +0000 | [diff] [blame] | 1634 | f_val = float16_to_float32((float16)a, ieee, status); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1635 | f_val = float32_maybe_silence_nan(f_val); |
| 1636 | |
| 1637 | return a < 0 ? (f_val | (1 << 31)) : f_val; |
| 1638 | } |
| 1639 | |
Peter Maydell | f401451 | 2016-01-22 15:09:21 +0000 | [diff] [blame] | 1640 | static inline float64 float64_from_float32(int32_t a, float_status *status) |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1641 | { |
| 1642 | float64 f_val; |
| 1643 | |
Peter Maydell | ff32e16 | 2015-02-02 18:47:16 +0000 | [diff] [blame] | 1644 | f_val = float32_to_float64((float64)a, status); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1645 | f_val = float64_maybe_silence_nan(f_val); |
| 1646 | |
| 1647 | return a < 0 ? (f_val | (1ULL << 63)) : f_val; |
| 1648 | } |
| 1649 | |
Peter Maydell | e5a41ff | 2015-01-30 12:04:16 +0000 | [diff] [blame] | 1650 | static inline float32 float32_from_q16(int16_t a, float_status *status) |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1651 | { |
| 1652 | float32 f_val; |
| 1653 | |
| 1654 | /* conversion as integer and scaling */ |
Peter Maydell | ff32e16 | 2015-02-02 18:47:16 +0000 | [diff] [blame] | 1655 | f_val = int32_to_float32(a, status); |
| 1656 | f_val = float32_scalbn(f_val, -15, status); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1657 | |
| 1658 | return f_val; |
| 1659 | } |
| 1660 | |
Peter Maydell | f401451 | 2016-01-22 15:09:21 +0000 | [diff] [blame] | 1661 | static inline float64 float64_from_q32(int32_t a, float_status *status) |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1662 | { |
| 1663 | float64 f_val; |
| 1664 | |
| 1665 | /* conversion as integer and scaling */ |
Peter Maydell | ff32e16 | 2015-02-02 18:47:16 +0000 | [diff] [blame] | 1666 | f_val = int32_to_float64(a, status); |
| 1667 | f_val = float64_scalbn(f_val, -31, status); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1668 | |
| 1669 | return f_val; |
| 1670 | } |
| 1671 | |
Peter Maydell | e5a41ff | 2015-01-30 12:04:16 +0000 | [diff] [blame] | 1672 | static inline int16_t float32_to_q16(float32 a, float_status *status) |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1673 | { |
Peter Maydell | f401451 | 2016-01-22 15:09:21 +0000 | [diff] [blame] | 1674 | int32_t q_val; |
| 1675 | int32_t q_min = 0xffff8000; |
| 1676 | int32_t q_max = 0x00007fff; |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1677 | |
| 1678 | int ieee_ex; |
| 1679 | |
| 1680 | if (float32_is_any_nan(a)) { |
Peter Maydell | ff32e16 | 2015-02-02 18:47:16 +0000 | [diff] [blame] | 1681 | float_raise(float_flag_invalid, status); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1682 | return 0; |
| 1683 | } |
| 1684 | |
| 1685 | /* scaling */ |
Peter Maydell | ff32e16 | 2015-02-02 18:47:16 +0000 | [diff] [blame] | 1686 | a = float32_scalbn(a, 15, status); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1687 | |
| 1688 | ieee_ex = get_float_exception_flags(status); |
| 1689 | set_float_exception_flags(ieee_ex & (~float_flag_underflow) |
Peter Maydell | ff32e16 | 2015-02-02 18:47:16 +0000 | [diff] [blame] | 1690 | , status); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1691 | |
| 1692 | if (ieee_ex & float_flag_overflow) { |
Peter Maydell | ff32e16 | 2015-02-02 18:47:16 +0000 | [diff] [blame] | 1693 | float_raise(float_flag_inexact, status); |
Peter Maydell | f401451 | 2016-01-22 15:09:21 +0000 | [diff] [blame] | 1694 | return (int32_t)a < 0 ? q_min : q_max; |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1695 | } |
| 1696 | |
| 1697 | /* conversion to int */ |
Peter Maydell | ff32e16 | 2015-02-02 18:47:16 +0000 | [diff] [blame] | 1698 | q_val = float32_to_int32(a, status); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1699 | |
| 1700 | ieee_ex = get_float_exception_flags(status); |
| 1701 | set_float_exception_flags(ieee_ex & (~float_flag_underflow) |
Peter Maydell | ff32e16 | 2015-02-02 18:47:16 +0000 | [diff] [blame] | 1702 | , status); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1703 | |
| 1704 | if (ieee_ex & float_flag_invalid) { |
| 1705 | set_float_exception_flags(ieee_ex & (~float_flag_invalid) |
Peter Maydell | ff32e16 | 2015-02-02 18:47:16 +0000 | [diff] [blame] | 1706 | , status); |
| 1707 | float_raise(float_flag_overflow | float_flag_inexact, status); |
Peter Maydell | f401451 | 2016-01-22 15:09:21 +0000 | [diff] [blame] | 1708 | return (int32_t)a < 0 ? q_min : q_max; |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1709 | } |
| 1710 | |
| 1711 | if (q_val < q_min) { |
Peter Maydell | ff32e16 | 2015-02-02 18:47:16 +0000 | [diff] [blame] | 1712 | float_raise(float_flag_overflow | float_flag_inexact, status); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1713 | return (int16_t)q_min; |
| 1714 | } |
| 1715 | |
| 1716 | if (q_max < q_val) { |
Peter Maydell | ff32e16 | 2015-02-02 18:47:16 +0000 | [diff] [blame] | 1717 | float_raise(float_flag_overflow | float_flag_inexact, status); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1718 | return (int16_t)q_max; |
| 1719 | } |
| 1720 | |
| 1721 | return (int16_t)q_val; |
| 1722 | } |
| 1723 | |
Peter Maydell | f401451 | 2016-01-22 15:09:21 +0000 | [diff] [blame] | 1724 | static inline int32_t float64_to_q32(float64 a, float_status *status) |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1725 | { |
Peter Maydell | f42c222 | 2016-01-22 15:09:20 +0000 | [diff] [blame] | 1726 | int64_t q_val; |
| 1727 | int64_t q_min = 0xffffffff80000000LL; |
| 1728 | int64_t q_max = 0x000000007fffffffLL; |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1729 | |
| 1730 | int ieee_ex; |
| 1731 | |
| 1732 | if (float64_is_any_nan(a)) { |
Peter Maydell | ff32e16 | 2015-02-02 18:47:16 +0000 | [diff] [blame] | 1733 | float_raise(float_flag_invalid, status); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1734 | return 0; |
| 1735 | } |
| 1736 | |
| 1737 | /* scaling */ |
Peter Maydell | ff32e16 | 2015-02-02 18:47:16 +0000 | [diff] [blame] | 1738 | a = float64_scalbn(a, 31, status); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1739 | |
| 1740 | ieee_ex = get_float_exception_flags(status); |
| 1741 | set_float_exception_flags(ieee_ex & (~float_flag_underflow) |
Peter Maydell | ff32e16 | 2015-02-02 18:47:16 +0000 | [diff] [blame] | 1742 | , status); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1743 | |
| 1744 | if (ieee_ex & float_flag_overflow) { |
Peter Maydell | ff32e16 | 2015-02-02 18:47:16 +0000 | [diff] [blame] | 1745 | float_raise(float_flag_inexact, status); |
Peter Maydell | f42c222 | 2016-01-22 15:09:20 +0000 | [diff] [blame] | 1746 | return (int64_t)a < 0 ? q_min : q_max; |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1747 | } |
| 1748 | |
| 1749 | /* conversion to integer */ |
Peter Maydell | ff32e16 | 2015-02-02 18:47:16 +0000 | [diff] [blame] | 1750 | q_val = float64_to_int64(a, status); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1751 | |
| 1752 | ieee_ex = get_float_exception_flags(status); |
| 1753 | set_float_exception_flags(ieee_ex & (~float_flag_underflow) |
Peter Maydell | ff32e16 | 2015-02-02 18:47:16 +0000 | [diff] [blame] | 1754 | , status); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1755 | |
| 1756 | if (ieee_ex & float_flag_invalid) { |
| 1757 | set_float_exception_flags(ieee_ex & (~float_flag_invalid) |
Peter Maydell | ff32e16 | 2015-02-02 18:47:16 +0000 | [diff] [blame] | 1758 | , status); |
| 1759 | float_raise(float_flag_overflow | float_flag_inexact, status); |
Peter Maydell | f42c222 | 2016-01-22 15:09:20 +0000 | [diff] [blame] | 1760 | return (int64_t)a < 0 ? q_min : q_max; |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1761 | } |
| 1762 | |
| 1763 | if (q_val < q_min) { |
Peter Maydell | ff32e16 | 2015-02-02 18:47:16 +0000 | [diff] [blame] | 1764 | float_raise(float_flag_overflow | float_flag_inexact, status); |
Peter Maydell | f401451 | 2016-01-22 15:09:21 +0000 | [diff] [blame] | 1765 | return (int32_t)q_min; |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1766 | } |
| 1767 | |
| 1768 | if (q_max < q_val) { |
Peter Maydell | ff32e16 | 2015-02-02 18:47:16 +0000 | [diff] [blame] | 1769 | float_raise(float_flag_overflow | float_flag_inexact, status); |
Peter Maydell | f401451 | 2016-01-22 15:09:21 +0000 | [diff] [blame] | 1770 | return (int32_t)q_max; |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1771 | } |
| 1772 | |
Peter Maydell | f401451 | 2016-01-22 15:09:21 +0000 | [diff] [blame] | 1773 | return (int32_t)q_val; |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1774 | } |
| 1775 | |
| 1776 | #define MSA_FLOAT_COND(DEST, OP, ARG1, ARG2, BITS, QUIET) \ |
| 1777 | do { \ |
Maciej W. Rozycki | 1a4d570 | 2014-12-02 17:51:12 +0000 | [diff] [blame] | 1778 | float_status *status = &env->active_tc.msa_fp_status; \ |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1779 | int c; \ |
| 1780 | int64_t cond; \ |
Maciej W. Rozycki | 1a4d570 | 2014-12-02 17:51:12 +0000 | [diff] [blame] | 1781 | set_float_exception_flags(0, status); \ |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1782 | if (!QUIET) { \ |
Maciej W. Rozycki | 1a4d570 | 2014-12-02 17:51:12 +0000 | [diff] [blame] | 1783 | cond = float ## BITS ## _ ## OP(ARG1, ARG2, status); \ |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1784 | } else { \ |
Maciej W. Rozycki | 1a4d570 | 2014-12-02 17:51:12 +0000 | [diff] [blame] | 1785 | cond = float ## BITS ## _ ## OP ## _quiet(ARG1, ARG2, status); \ |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1786 | } \ |
| 1787 | DEST = cond ? M_MAX_UINT(BITS) : 0; \ |
| 1788 | c = update_msacsr(env, CLEAR_IS_INEXACT, 0); \ |
| 1789 | \ |
| 1790 | if (get_enabled_exceptions(env, c)) { \ |
| 1791 | DEST = ((FLOAT_SNAN ## BITS >> 6) << 6) | c; \ |
| 1792 | } \ |
| 1793 | } while (0) |
| 1794 | |
| 1795 | #define MSA_FLOAT_AF(DEST, ARG1, ARG2, BITS, QUIET) \ |
| 1796 | do { \ |
| 1797 | MSA_FLOAT_COND(DEST, eq, ARG1, ARG2, BITS, QUIET); \ |
| 1798 | if ((DEST & M_MAX_UINT(BITS)) == M_MAX_UINT(BITS)) { \ |
| 1799 | DEST = 0; \ |
| 1800 | } \ |
| 1801 | } while (0) |
| 1802 | |
| 1803 | #define MSA_FLOAT_UEQ(DEST, ARG1, ARG2, BITS, QUIET) \ |
| 1804 | do { \ |
| 1805 | MSA_FLOAT_COND(DEST, unordered, ARG1, ARG2, BITS, QUIET); \ |
| 1806 | if (DEST == 0) { \ |
| 1807 | MSA_FLOAT_COND(DEST, eq, ARG1, ARG2, BITS, QUIET); \ |
| 1808 | } \ |
| 1809 | } while (0) |
| 1810 | |
| 1811 | #define MSA_FLOAT_NE(DEST, ARG1, ARG2, BITS, QUIET) \ |
| 1812 | do { \ |
| 1813 | MSA_FLOAT_COND(DEST, lt, ARG1, ARG2, BITS, QUIET); \ |
| 1814 | if (DEST == 0) { \ |
| 1815 | MSA_FLOAT_COND(DEST, lt, ARG2, ARG1, BITS, QUIET); \ |
| 1816 | } \ |
| 1817 | } while (0) |
| 1818 | |
| 1819 | #define MSA_FLOAT_UNE(DEST, ARG1, ARG2, BITS, QUIET) \ |
| 1820 | do { \ |
| 1821 | MSA_FLOAT_COND(DEST, unordered, ARG1, ARG2, BITS, QUIET); \ |
| 1822 | if (DEST == 0) { \ |
| 1823 | MSA_FLOAT_COND(DEST, lt, ARG1, ARG2, BITS, QUIET); \ |
| 1824 | if (DEST == 0) { \ |
| 1825 | MSA_FLOAT_COND(DEST, lt, ARG2, ARG1, BITS, QUIET); \ |
| 1826 | } \ |
| 1827 | } \ |
| 1828 | } while (0) |
| 1829 | |
| 1830 | #define MSA_FLOAT_ULE(DEST, ARG1, ARG2, BITS, QUIET) \ |
| 1831 | do { \ |
| 1832 | MSA_FLOAT_COND(DEST, unordered, ARG1, ARG2, BITS, QUIET); \ |
| 1833 | if (DEST == 0) { \ |
| 1834 | MSA_FLOAT_COND(DEST, le, ARG1, ARG2, BITS, QUIET); \ |
| 1835 | } \ |
| 1836 | } while (0) |
| 1837 | |
| 1838 | #define MSA_FLOAT_ULT(DEST, ARG1, ARG2, BITS, QUIET) \ |
| 1839 | do { \ |
| 1840 | MSA_FLOAT_COND(DEST, unordered, ARG1, ARG2, BITS, QUIET); \ |
| 1841 | if (DEST == 0) { \ |
| 1842 | MSA_FLOAT_COND(DEST, lt, ARG1, ARG2, BITS, QUIET); \ |
| 1843 | } \ |
| 1844 | } while (0) |
| 1845 | |
| 1846 | #define MSA_FLOAT_OR(DEST, ARG1, ARG2, BITS, QUIET) \ |
| 1847 | do { \ |
| 1848 | MSA_FLOAT_COND(DEST, le, ARG1, ARG2, BITS, QUIET); \ |
| 1849 | if (DEST == 0) { \ |
| 1850 | MSA_FLOAT_COND(DEST, le, ARG2, ARG1, BITS, QUIET); \ |
| 1851 | } \ |
| 1852 | } while (0) |
| 1853 | |
| 1854 | static inline void compare_af(CPUMIPSState *env, wr_t *pwd, wr_t *pws, |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 1855 | wr_t *pwt, uint32_t df, int quiet, |
| 1856 | uintptr_t retaddr) |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1857 | { |
| 1858 | wr_t wx, *pwx = &wx; |
| 1859 | uint32_t i; |
| 1860 | |
| 1861 | clear_msacsr_cause(env); |
| 1862 | |
| 1863 | switch (df) { |
| 1864 | case DF_WORD: |
| 1865 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 1866 | MSA_FLOAT_AF(pwx->w[i], pws->w[i], pwt->w[i], 32, quiet); |
| 1867 | } |
| 1868 | break; |
| 1869 | case DF_DOUBLE: |
| 1870 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 1871 | MSA_FLOAT_AF(pwx->d[i], pws->d[i], pwt->d[i], 64, quiet); |
| 1872 | } |
| 1873 | break; |
| 1874 | default: |
| 1875 | assert(0); |
| 1876 | } |
| 1877 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 1878 | check_msacsr_cause(env, retaddr); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1879 | |
| 1880 | msa_move_v(pwd, pwx); |
| 1881 | } |
| 1882 | |
| 1883 | static inline void compare_un(CPUMIPSState *env, wr_t *pwd, wr_t *pws, |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 1884 | wr_t *pwt, uint32_t df, int quiet, |
| 1885 | uintptr_t retaddr) |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1886 | { |
| 1887 | wr_t wx, *pwx = &wx; |
| 1888 | uint32_t i; |
| 1889 | |
| 1890 | clear_msacsr_cause(env); |
| 1891 | |
| 1892 | switch (df) { |
| 1893 | case DF_WORD: |
| 1894 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 1895 | MSA_FLOAT_COND(pwx->w[i], unordered, pws->w[i], pwt->w[i], 32, |
| 1896 | quiet); |
| 1897 | } |
| 1898 | break; |
| 1899 | case DF_DOUBLE: |
| 1900 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 1901 | MSA_FLOAT_COND(pwx->d[i], unordered, pws->d[i], pwt->d[i], 64, |
| 1902 | quiet); |
| 1903 | } |
| 1904 | break; |
| 1905 | default: |
| 1906 | assert(0); |
| 1907 | } |
| 1908 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 1909 | check_msacsr_cause(env, retaddr); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1910 | |
| 1911 | msa_move_v(pwd, pwx); |
| 1912 | } |
| 1913 | |
| 1914 | static inline void compare_eq(CPUMIPSState *env, wr_t *pwd, wr_t *pws, |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 1915 | wr_t *pwt, uint32_t df, int quiet, |
| 1916 | uintptr_t retaddr) |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1917 | { |
| 1918 | wr_t wx, *pwx = &wx; |
| 1919 | uint32_t i; |
| 1920 | |
| 1921 | clear_msacsr_cause(env); |
| 1922 | |
| 1923 | switch (df) { |
| 1924 | case DF_WORD: |
| 1925 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 1926 | MSA_FLOAT_COND(pwx->w[i], eq, pws->w[i], pwt->w[i], 32, quiet); |
| 1927 | } |
| 1928 | break; |
| 1929 | case DF_DOUBLE: |
| 1930 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 1931 | MSA_FLOAT_COND(pwx->d[i], eq, pws->d[i], pwt->d[i], 64, quiet); |
| 1932 | } |
| 1933 | break; |
| 1934 | default: |
| 1935 | assert(0); |
| 1936 | } |
| 1937 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 1938 | check_msacsr_cause(env, retaddr); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1939 | |
| 1940 | msa_move_v(pwd, pwx); |
| 1941 | } |
| 1942 | |
| 1943 | static inline void compare_ueq(CPUMIPSState *env, wr_t *pwd, wr_t *pws, |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 1944 | wr_t *pwt, uint32_t df, int quiet, |
| 1945 | uintptr_t retaddr) |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1946 | { |
| 1947 | wr_t wx, *pwx = &wx; |
| 1948 | uint32_t i; |
| 1949 | |
| 1950 | clear_msacsr_cause(env); |
| 1951 | |
| 1952 | switch (df) { |
| 1953 | case DF_WORD: |
| 1954 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 1955 | MSA_FLOAT_UEQ(pwx->w[i], pws->w[i], pwt->w[i], 32, quiet); |
| 1956 | } |
| 1957 | break; |
| 1958 | case DF_DOUBLE: |
| 1959 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 1960 | MSA_FLOAT_UEQ(pwx->d[i], pws->d[i], pwt->d[i], 64, quiet); |
| 1961 | } |
| 1962 | break; |
| 1963 | default: |
| 1964 | assert(0); |
| 1965 | } |
| 1966 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 1967 | check_msacsr_cause(env, retaddr); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1968 | |
| 1969 | msa_move_v(pwd, pwx); |
| 1970 | } |
| 1971 | |
| 1972 | static inline void compare_lt(CPUMIPSState *env, wr_t *pwd, wr_t *pws, |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 1973 | wr_t *pwt, uint32_t df, int quiet, |
| 1974 | uintptr_t retaddr) |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1975 | { |
| 1976 | wr_t wx, *pwx = &wx; |
| 1977 | uint32_t i; |
| 1978 | |
| 1979 | clear_msacsr_cause(env); |
| 1980 | |
| 1981 | switch (df) { |
| 1982 | case DF_WORD: |
| 1983 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 1984 | MSA_FLOAT_COND(pwx->w[i], lt, pws->w[i], pwt->w[i], 32, quiet); |
| 1985 | } |
| 1986 | break; |
| 1987 | case DF_DOUBLE: |
| 1988 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 1989 | MSA_FLOAT_COND(pwx->d[i], lt, pws->d[i], pwt->d[i], 64, quiet); |
| 1990 | } |
| 1991 | break; |
| 1992 | default: |
| 1993 | assert(0); |
| 1994 | } |
| 1995 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 1996 | check_msacsr_cause(env, retaddr); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 1997 | |
| 1998 | msa_move_v(pwd, pwx); |
| 1999 | } |
| 2000 | |
| 2001 | static inline void compare_ult(CPUMIPSState *env, wr_t *pwd, wr_t *pws, |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2002 | wr_t *pwt, uint32_t df, int quiet, |
| 2003 | uintptr_t retaddr) |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2004 | { |
| 2005 | wr_t wx, *pwx = &wx; |
| 2006 | uint32_t i; |
| 2007 | |
| 2008 | clear_msacsr_cause(env); |
| 2009 | |
| 2010 | switch (df) { |
| 2011 | case DF_WORD: |
| 2012 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 2013 | MSA_FLOAT_ULT(pwx->w[i], pws->w[i], pwt->w[i], 32, quiet); |
| 2014 | } |
| 2015 | break; |
| 2016 | case DF_DOUBLE: |
| 2017 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 2018 | MSA_FLOAT_ULT(pwx->d[i], pws->d[i], pwt->d[i], 64, quiet); |
| 2019 | } |
| 2020 | break; |
| 2021 | default: |
| 2022 | assert(0); |
| 2023 | } |
| 2024 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2025 | check_msacsr_cause(env, retaddr); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2026 | |
| 2027 | msa_move_v(pwd, pwx); |
| 2028 | } |
| 2029 | |
| 2030 | static inline void compare_le(CPUMIPSState *env, wr_t *pwd, wr_t *pws, |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2031 | wr_t *pwt, uint32_t df, int quiet, |
| 2032 | uintptr_t retaddr) |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2033 | { |
| 2034 | wr_t wx, *pwx = &wx; |
| 2035 | uint32_t i; |
| 2036 | |
| 2037 | clear_msacsr_cause(env); |
| 2038 | |
| 2039 | switch (df) { |
| 2040 | case DF_WORD: |
| 2041 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 2042 | MSA_FLOAT_COND(pwx->w[i], le, pws->w[i], pwt->w[i], 32, quiet); |
| 2043 | } |
| 2044 | break; |
| 2045 | case DF_DOUBLE: |
| 2046 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 2047 | MSA_FLOAT_COND(pwx->d[i], le, pws->d[i], pwt->d[i], 64, quiet); |
| 2048 | } |
| 2049 | break; |
| 2050 | default: |
| 2051 | assert(0); |
| 2052 | } |
| 2053 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2054 | check_msacsr_cause(env, retaddr); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2055 | |
| 2056 | msa_move_v(pwd, pwx); |
| 2057 | } |
| 2058 | |
| 2059 | static inline void compare_ule(CPUMIPSState *env, wr_t *pwd, wr_t *pws, |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2060 | wr_t *pwt, uint32_t df, int quiet, |
| 2061 | uintptr_t retaddr) |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2062 | { |
| 2063 | wr_t wx, *pwx = &wx; |
| 2064 | uint32_t i; |
| 2065 | |
| 2066 | clear_msacsr_cause(env); |
| 2067 | |
| 2068 | switch (df) { |
| 2069 | case DF_WORD: |
| 2070 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 2071 | MSA_FLOAT_ULE(pwx->w[i], pws->w[i], pwt->w[i], 32, quiet); |
| 2072 | } |
| 2073 | break; |
| 2074 | case DF_DOUBLE: |
| 2075 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 2076 | MSA_FLOAT_ULE(pwx->d[i], pws->d[i], pwt->d[i], 64, quiet); |
| 2077 | } |
| 2078 | break; |
| 2079 | default: |
| 2080 | assert(0); |
| 2081 | } |
| 2082 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2083 | check_msacsr_cause(env, retaddr); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2084 | |
| 2085 | msa_move_v(pwd, pwx); |
| 2086 | } |
| 2087 | |
| 2088 | static inline void compare_or(CPUMIPSState *env, wr_t *pwd, wr_t *pws, |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2089 | wr_t *pwt, uint32_t df, int quiet, |
| 2090 | uintptr_t retaddr) |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2091 | { |
| 2092 | wr_t wx, *pwx = &wx; |
| 2093 | uint32_t i; |
| 2094 | |
| 2095 | clear_msacsr_cause(env); |
| 2096 | |
| 2097 | switch (df) { |
| 2098 | case DF_WORD: |
| 2099 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 2100 | MSA_FLOAT_OR(pwx->w[i], pws->w[i], pwt->w[i], 32, quiet); |
| 2101 | } |
| 2102 | break; |
| 2103 | case DF_DOUBLE: |
| 2104 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 2105 | MSA_FLOAT_OR(pwx->d[i], pws->d[i], pwt->d[i], 64, quiet); |
| 2106 | } |
| 2107 | break; |
| 2108 | default: |
| 2109 | assert(0); |
| 2110 | } |
| 2111 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2112 | check_msacsr_cause(env, retaddr); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2113 | |
| 2114 | msa_move_v(pwd, pwx); |
| 2115 | } |
| 2116 | |
| 2117 | static inline void compare_une(CPUMIPSState *env, wr_t *pwd, wr_t *pws, |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2118 | wr_t *pwt, uint32_t df, int quiet, |
| 2119 | uintptr_t retaddr) |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2120 | { |
| 2121 | wr_t wx, *pwx = &wx; |
| 2122 | uint32_t i; |
| 2123 | |
| 2124 | clear_msacsr_cause(env); |
| 2125 | |
| 2126 | switch (df) { |
| 2127 | case DF_WORD: |
| 2128 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 2129 | MSA_FLOAT_UNE(pwx->w[i], pws->w[i], pwt->w[i], 32, quiet); |
| 2130 | } |
| 2131 | break; |
| 2132 | case DF_DOUBLE: |
| 2133 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 2134 | MSA_FLOAT_UNE(pwx->d[i], pws->d[i], pwt->d[i], 64, quiet); |
| 2135 | } |
| 2136 | break; |
| 2137 | default: |
| 2138 | assert(0); |
| 2139 | } |
| 2140 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2141 | check_msacsr_cause(env, retaddr); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2142 | |
| 2143 | msa_move_v(pwd, pwx); |
| 2144 | } |
| 2145 | |
| 2146 | static inline void compare_ne(CPUMIPSState *env, wr_t *pwd, wr_t *pws, |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2147 | wr_t *pwt, uint32_t df, int quiet, |
| 2148 | uintptr_t retaddr) |
| 2149 | { |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2150 | wr_t wx, *pwx = &wx; |
| 2151 | uint32_t i; |
| 2152 | |
| 2153 | clear_msacsr_cause(env); |
| 2154 | |
| 2155 | switch (df) { |
| 2156 | case DF_WORD: |
| 2157 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 2158 | MSA_FLOAT_NE(pwx->w[i], pws->w[i], pwt->w[i], 32, quiet); |
| 2159 | } |
| 2160 | break; |
| 2161 | case DF_DOUBLE: |
| 2162 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 2163 | MSA_FLOAT_NE(pwx->d[i], pws->d[i], pwt->d[i], 64, quiet); |
| 2164 | } |
| 2165 | break; |
| 2166 | default: |
| 2167 | assert(0); |
| 2168 | } |
| 2169 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2170 | check_msacsr_cause(env, retaddr); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2171 | |
| 2172 | msa_move_v(pwd, pwx); |
| 2173 | } |
| 2174 | |
| 2175 | void helper_msa_fcaf_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2176 | uint32_t ws, uint32_t wt) |
| 2177 | { |
| 2178 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2179 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2180 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2181 | compare_af(env, pwd, pws, pwt, df, 1, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2182 | } |
| 2183 | |
| 2184 | void helper_msa_fcun_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2185 | uint32_t ws, uint32_t wt) |
| 2186 | { |
| 2187 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2188 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2189 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2190 | compare_un(env, pwd, pws, pwt, df, 1, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2191 | } |
| 2192 | |
| 2193 | void helper_msa_fceq_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2194 | uint32_t ws, uint32_t wt) |
| 2195 | { |
| 2196 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2197 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2198 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2199 | compare_eq(env, pwd, pws, pwt, df, 1, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2200 | } |
| 2201 | |
| 2202 | void helper_msa_fcueq_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2203 | uint32_t ws, uint32_t wt) |
| 2204 | { |
| 2205 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2206 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2207 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2208 | compare_ueq(env, pwd, pws, pwt, df, 1, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2209 | } |
| 2210 | |
| 2211 | void helper_msa_fclt_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2212 | uint32_t ws, uint32_t wt) |
| 2213 | { |
| 2214 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2215 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2216 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2217 | compare_lt(env, pwd, pws, pwt, df, 1, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2218 | } |
| 2219 | |
| 2220 | void helper_msa_fcult_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2221 | uint32_t ws, uint32_t wt) |
| 2222 | { |
| 2223 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2224 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2225 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2226 | compare_ult(env, pwd, pws, pwt, df, 1, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2227 | } |
| 2228 | |
| 2229 | void helper_msa_fcle_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2230 | uint32_t ws, uint32_t wt) |
| 2231 | { |
| 2232 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2233 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2234 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2235 | compare_le(env, pwd, pws, pwt, df, 1, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2236 | } |
| 2237 | |
| 2238 | void helper_msa_fcule_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2239 | uint32_t ws, uint32_t wt) |
| 2240 | { |
| 2241 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2242 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2243 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2244 | compare_ule(env, pwd, pws, pwt, df, 1, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2245 | } |
| 2246 | |
| 2247 | void helper_msa_fsaf_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2248 | uint32_t ws, uint32_t wt) |
| 2249 | { |
| 2250 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2251 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2252 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2253 | compare_af(env, pwd, pws, pwt, df, 0, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2254 | } |
| 2255 | |
| 2256 | void helper_msa_fsun_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2257 | uint32_t ws, uint32_t wt) |
| 2258 | { |
| 2259 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2260 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2261 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2262 | compare_un(env, pwd, pws, pwt, df, 0, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2263 | } |
| 2264 | |
| 2265 | void helper_msa_fseq_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2266 | uint32_t ws, uint32_t wt) |
| 2267 | { |
| 2268 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2269 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2270 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2271 | compare_eq(env, pwd, pws, pwt, df, 0, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2272 | } |
| 2273 | |
| 2274 | void helper_msa_fsueq_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2275 | uint32_t ws, uint32_t wt) |
| 2276 | { |
| 2277 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2278 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2279 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2280 | compare_ueq(env, pwd, pws, pwt, df, 0, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2281 | } |
| 2282 | |
| 2283 | void helper_msa_fslt_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2284 | uint32_t ws, uint32_t wt) |
| 2285 | { |
| 2286 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2287 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2288 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2289 | compare_lt(env, pwd, pws, pwt, df, 0, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2290 | } |
| 2291 | |
| 2292 | void helper_msa_fsult_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2293 | uint32_t ws, uint32_t wt) |
| 2294 | { |
| 2295 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2296 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2297 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2298 | compare_ult(env, pwd, pws, pwt, df, 0, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2299 | } |
| 2300 | |
| 2301 | void helper_msa_fsle_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2302 | uint32_t ws, uint32_t wt) |
| 2303 | { |
| 2304 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2305 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2306 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2307 | compare_le(env, pwd, pws, pwt, df, 0, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2308 | } |
| 2309 | |
| 2310 | void helper_msa_fsule_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2311 | uint32_t ws, uint32_t wt) |
| 2312 | { |
| 2313 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2314 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2315 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2316 | compare_ule(env, pwd, pws, pwt, df, 0, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2317 | } |
| 2318 | |
| 2319 | void helper_msa_fcor_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2320 | uint32_t ws, uint32_t wt) |
| 2321 | { |
| 2322 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2323 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2324 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2325 | compare_or(env, pwd, pws, pwt, df, 1, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2326 | } |
| 2327 | |
| 2328 | void helper_msa_fcune_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2329 | uint32_t ws, uint32_t wt) |
| 2330 | { |
| 2331 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2332 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2333 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2334 | compare_une(env, pwd, pws, pwt, df, 1, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2335 | } |
| 2336 | |
| 2337 | void helper_msa_fcne_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2338 | uint32_t ws, uint32_t wt) |
| 2339 | { |
| 2340 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2341 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2342 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2343 | compare_ne(env, pwd, pws, pwt, df, 1, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2344 | } |
| 2345 | |
| 2346 | void helper_msa_fsor_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2347 | uint32_t ws, uint32_t wt) |
| 2348 | { |
| 2349 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2350 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2351 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2352 | compare_or(env, pwd, pws, pwt, df, 0, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2353 | } |
| 2354 | |
| 2355 | void helper_msa_fsune_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2356 | uint32_t ws, uint32_t wt) |
| 2357 | { |
| 2358 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2359 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2360 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2361 | compare_une(env, pwd, pws, pwt, df, 0, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2362 | } |
| 2363 | |
| 2364 | void helper_msa_fsne_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2365 | uint32_t ws, uint32_t wt) |
| 2366 | { |
| 2367 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2368 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2369 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2370 | compare_ne(env, pwd, pws, pwt, df, 0, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2371 | } |
| 2372 | |
| 2373 | #define float16_is_zero(ARG) 0 |
| 2374 | #define float16_is_zero_or_denormal(ARG) 0 |
| 2375 | |
| 2376 | #define IS_DENORMAL(ARG, BITS) \ |
| 2377 | (!float ## BITS ## _is_zero(ARG) \ |
| 2378 | && float ## BITS ## _is_zero_or_denormal(ARG)) |
| 2379 | |
| 2380 | #define MSA_FLOAT_BINOP(DEST, OP, ARG1, ARG2, BITS) \ |
| 2381 | do { \ |
Maciej W. Rozycki | 1a4d570 | 2014-12-02 17:51:12 +0000 | [diff] [blame] | 2382 | float_status *status = &env->active_tc.msa_fp_status; \ |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2383 | int c; \ |
| 2384 | \ |
Maciej W. Rozycki | 1a4d570 | 2014-12-02 17:51:12 +0000 | [diff] [blame] | 2385 | set_float_exception_flags(0, status); \ |
| 2386 | DEST = float ## BITS ## _ ## OP(ARG1, ARG2, status); \ |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2387 | c = update_msacsr(env, 0, IS_DENORMAL(DEST, BITS)); \ |
| 2388 | \ |
| 2389 | if (get_enabled_exceptions(env, c)) { \ |
| 2390 | DEST = ((FLOAT_SNAN ## BITS >> 6) << 6) | c; \ |
| 2391 | } \ |
| 2392 | } while (0) |
| 2393 | |
| 2394 | void helper_msa_fadd_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2395 | uint32_t ws, uint32_t wt) |
| 2396 | { |
| 2397 | wr_t wx, *pwx = &wx; |
| 2398 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2399 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2400 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
| 2401 | uint32_t i; |
| 2402 | |
| 2403 | clear_msacsr_cause(env); |
| 2404 | |
| 2405 | switch (df) { |
| 2406 | case DF_WORD: |
| 2407 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 2408 | MSA_FLOAT_BINOP(pwx->w[i], add, pws->w[i], pwt->w[i], 32); |
| 2409 | } |
| 2410 | break; |
| 2411 | case DF_DOUBLE: |
| 2412 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 2413 | MSA_FLOAT_BINOP(pwx->d[i], add, pws->d[i], pwt->d[i], 64); |
| 2414 | } |
| 2415 | break; |
| 2416 | default: |
| 2417 | assert(0); |
| 2418 | } |
| 2419 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2420 | check_msacsr_cause(env, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2421 | msa_move_v(pwd, pwx); |
| 2422 | } |
| 2423 | |
| 2424 | void helper_msa_fsub_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2425 | uint32_t ws, uint32_t wt) |
| 2426 | { |
| 2427 | wr_t wx, *pwx = &wx; |
| 2428 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2429 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2430 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
| 2431 | uint32_t i; |
| 2432 | |
| 2433 | clear_msacsr_cause(env); |
| 2434 | |
| 2435 | switch (df) { |
| 2436 | case DF_WORD: |
| 2437 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 2438 | MSA_FLOAT_BINOP(pwx->w[i], sub, pws->w[i], pwt->w[i], 32); |
| 2439 | } |
| 2440 | break; |
| 2441 | case DF_DOUBLE: |
| 2442 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 2443 | MSA_FLOAT_BINOP(pwx->d[i], sub, pws->d[i], pwt->d[i], 64); |
| 2444 | } |
| 2445 | break; |
| 2446 | default: |
| 2447 | assert(0); |
| 2448 | } |
| 2449 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2450 | check_msacsr_cause(env, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2451 | msa_move_v(pwd, pwx); |
| 2452 | } |
| 2453 | |
| 2454 | void helper_msa_fmul_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2455 | uint32_t ws, uint32_t wt) |
| 2456 | { |
| 2457 | wr_t wx, *pwx = &wx; |
| 2458 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2459 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2460 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
| 2461 | uint32_t i; |
| 2462 | |
| 2463 | clear_msacsr_cause(env); |
| 2464 | |
| 2465 | switch (df) { |
| 2466 | case DF_WORD: |
| 2467 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 2468 | MSA_FLOAT_BINOP(pwx->w[i], mul, pws->w[i], pwt->w[i], 32); |
| 2469 | } |
| 2470 | break; |
| 2471 | case DF_DOUBLE: |
| 2472 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 2473 | MSA_FLOAT_BINOP(pwx->d[i], mul, pws->d[i], pwt->d[i], 64); |
| 2474 | } |
| 2475 | break; |
| 2476 | default: |
| 2477 | assert(0); |
| 2478 | } |
| 2479 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2480 | check_msacsr_cause(env, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2481 | |
| 2482 | msa_move_v(pwd, pwx); |
| 2483 | } |
| 2484 | |
| 2485 | void helper_msa_fdiv_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2486 | uint32_t ws, uint32_t wt) |
| 2487 | { |
| 2488 | wr_t wx, *pwx = &wx; |
| 2489 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2490 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2491 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
| 2492 | uint32_t i; |
| 2493 | |
| 2494 | clear_msacsr_cause(env); |
| 2495 | |
| 2496 | switch (df) { |
| 2497 | case DF_WORD: |
| 2498 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 2499 | MSA_FLOAT_BINOP(pwx->w[i], div, pws->w[i], pwt->w[i], 32); |
| 2500 | } |
| 2501 | break; |
| 2502 | case DF_DOUBLE: |
| 2503 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 2504 | MSA_FLOAT_BINOP(pwx->d[i], div, pws->d[i], pwt->d[i], 64); |
| 2505 | } |
| 2506 | break; |
| 2507 | default: |
| 2508 | assert(0); |
| 2509 | } |
| 2510 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2511 | check_msacsr_cause(env, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2512 | |
| 2513 | msa_move_v(pwd, pwx); |
| 2514 | } |
| 2515 | |
| 2516 | #define MSA_FLOAT_MULADD(DEST, ARG1, ARG2, ARG3, NEGATE, BITS) \ |
| 2517 | do { \ |
Maciej W. Rozycki | 1a4d570 | 2014-12-02 17:51:12 +0000 | [diff] [blame] | 2518 | float_status *status = &env->active_tc.msa_fp_status; \ |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2519 | int c; \ |
| 2520 | \ |
Maciej W. Rozycki | 1a4d570 | 2014-12-02 17:51:12 +0000 | [diff] [blame] | 2521 | set_float_exception_flags(0, status); \ |
| 2522 | DEST = float ## BITS ## _muladd(ARG2, ARG3, ARG1, NEGATE, status); \ |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2523 | c = update_msacsr(env, 0, IS_DENORMAL(DEST, BITS)); \ |
| 2524 | \ |
| 2525 | if (get_enabled_exceptions(env, c)) { \ |
| 2526 | DEST = ((FLOAT_SNAN ## BITS >> 6) << 6) | c; \ |
| 2527 | } \ |
| 2528 | } while (0) |
| 2529 | |
| 2530 | void helper_msa_fmadd_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2531 | uint32_t ws, uint32_t wt) |
| 2532 | { |
| 2533 | wr_t wx, *pwx = &wx; |
| 2534 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2535 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2536 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
| 2537 | uint32_t i; |
| 2538 | |
| 2539 | clear_msacsr_cause(env); |
| 2540 | |
| 2541 | switch (df) { |
| 2542 | case DF_WORD: |
| 2543 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 2544 | MSA_FLOAT_MULADD(pwx->w[i], pwd->w[i], |
| 2545 | pws->w[i], pwt->w[i], 0, 32); |
| 2546 | } |
| 2547 | break; |
| 2548 | case DF_DOUBLE: |
| 2549 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 2550 | MSA_FLOAT_MULADD(pwx->d[i], pwd->d[i], |
| 2551 | pws->d[i], pwt->d[i], 0, 64); |
| 2552 | } |
| 2553 | break; |
| 2554 | default: |
| 2555 | assert(0); |
| 2556 | } |
| 2557 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2558 | check_msacsr_cause(env, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2559 | |
| 2560 | msa_move_v(pwd, pwx); |
| 2561 | } |
| 2562 | |
| 2563 | void helper_msa_fmsub_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2564 | uint32_t ws, uint32_t wt) |
| 2565 | { |
| 2566 | wr_t wx, *pwx = &wx; |
| 2567 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2568 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2569 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
| 2570 | uint32_t i; |
| 2571 | |
| 2572 | clear_msacsr_cause(env); |
| 2573 | |
| 2574 | switch (df) { |
| 2575 | case DF_WORD: |
| 2576 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 2577 | MSA_FLOAT_MULADD(pwx->w[i], pwd->w[i], |
| 2578 | pws->w[i], pwt->w[i], |
| 2579 | float_muladd_negate_product, 32); |
| 2580 | } |
| 2581 | break; |
| 2582 | case DF_DOUBLE: |
| 2583 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 2584 | MSA_FLOAT_MULADD(pwx->d[i], pwd->d[i], |
| 2585 | pws->d[i], pwt->d[i], |
| 2586 | float_muladd_negate_product, 64); |
| 2587 | } |
| 2588 | break; |
| 2589 | default: |
| 2590 | assert(0); |
| 2591 | } |
| 2592 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2593 | check_msacsr_cause(env, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2594 | |
| 2595 | msa_move_v(pwd, pwx); |
| 2596 | } |
| 2597 | |
| 2598 | void helper_msa_fexp2_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2599 | uint32_t ws, uint32_t wt) |
| 2600 | { |
| 2601 | wr_t wx, *pwx = &wx; |
| 2602 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2603 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2604 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
| 2605 | uint32_t i; |
| 2606 | |
| 2607 | clear_msacsr_cause(env); |
| 2608 | |
| 2609 | switch (df) { |
| 2610 | case DF_WORD: |
| 2611 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 2612 | MSA_FLOAT_BINOP(pwx->w[i], scalbn, pws->w[i], |
| 2613 | pwt->w[i] > 0x200 ? 0x200 : |
| 2614 | pwt->w[i] < -0x200 ? -0x200 : pwt->w[i], |
| 2615 | 32); |
| 2616 | } |
| 2617 | break; |
| 2618 | case DF_DOUBLE: |
| 2619 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 2620 | MSA_FLOAT_BINOP(pwx->d[i], scalbn, pws->d[i], |
| 2621 | pwt->d[i] > 0x1000 ? 0x1000 : |
| 2622 | pwt->d[i] < -0x1000 ? -0x1000 : pwt->d[i], |
| 2623 | 64); |
| 2624 | } |
| 2625 | break; |
| 2626 | default: |
| 2627 | assert(0); |
| 2628 | } |
| 2629 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2630 | check_msacsr_cause(env, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2631 | |
| 2632 | msa_move_v(pwd, pwx); |
| 2633 | } |
| 2634 | |
| 2635 | #define MSA_FLOAT_UNOP(DEST, OP, ARG, BITS) \ |
| 2636 | do { \ |
Maciej W. Rozycki | 1a4d570 | 2014-12-02 17:51:12 +0000 | [diff] [blame] | 2637 | float_status *status = &env->active_tc.msa_fp_status; \ |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2638 | int c; \ |
| 2639 | \ |
Maciej W. Rozycki | 1a4d570 | 2014-12-02 17:51:12 +0000 | [diff] [blame] | 2640 | set_float_exception_flags(0, status); \ |
| 2641 | DEST = float ## BITS ## _ ## OP(ARG, status); \ |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2642 | c = update_msacsr(env, 0, IS_DENORMAL(DEST, BITS)); \ |
| 2643 | \ |
| 2644 | if (get_enabled_exceptions(env, c)) { \ |
| 2645 | DEST = ((FLOAT_SNAN ## BITS >> 6) << 6) | c; \ |
| 2646 | } \ |
| 2647 | } while (0) |
| 2648 | |
| 2649 | void helper_msa_fexdo_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2650 | uint32_t ws, uint32_t wt) |
| 2651 | { |
| 2652 | wr_t wx, *pwx = &wx; |
| 2653 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2654 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2655 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
| 2656 | uint32_t i; |
| 2657 | |
Yongbok Kim | d4f4f0d | 2015-06-30 15:44:28 +0100 | [diff] [blame] | 2658 | clear_msacsr_cause(env); |
| 2659 | |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2660 | switch (df) { |
| 2661 | case DF_WORD: |
| 2662 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 2663 | /* Half precision floats come in two formats: standard |
| 2664 | IEEE and "ARM" format. The latter gains extra exponent |
| 2665 | range by omitting the NaN/Inf encodings. */ |
| 2666 | flag ieee = 1; |
| 2667 | |
| 2668 | MSA_FLOAT_BINOP(Lh(pwx, i), from_float32, pws->w[i], ieee, 16); |
| 2669 | MSA_FLOAT_BINOP(Rh(pwx, i), from_float32, pwt->w[i], ieee, 16); |
| 2670 | } |
| 2671 | break; |
| 2672 | case DF_DOUBLE: |
| 2673 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 2674 | MSA_FLOAT_UNOP(Lw(pwx, i), from_float64, pws->d[i], 32); |
| 2675 | MSA_FLOAT_UNOP(Rw(pwx, i), from_float64, pwt->d[i], 32); |
| 2676 | } |
| 2677 | break; |
| 2678 | default: |
| 2679 | assert(0); |
| 2680 | } |
| 2681 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2682 | check_msacsr_cause(env, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2683 | msa_move_v(pwd, pwx); |
| 2684 | } |
| 2685 | |
| 2686 | #define MSA_FLOAT_UNOP_XD(DEST, OP, ARG, BITS, XBITS) \ |
| 2687 | do { \ |
Maciej W. Rozycki | 1a4d570 | 2014-12-02 17:51:12 +0000 | [diff] [blame] | 2688 | float_status *status = &env->active_tc.msa_fp_status; \ |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2689 | int c; \ |
| 2690 | \ |
Maciej W. Rozycki | 1a4d570 | 2014-12-02 17:51:12 +0000 | [diff] [blame] | 2691 | set_float_exception_flags(0, status); \ |
| 2692 | DEST = float ## BITS ## _ ## OP(ARG, status); \ |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2693 | c = update_msacsr(env, CLEAR_FS_UNDERFLOW, 0); \ |
| 2694 | \ |
| 2695 | if (get_enabled_exceptions(env, c)) { \ |
| 2696 | DEST = ((FLOAT_SNAN ## XBITS >> 6) << 6) | c; \ |
| 2697 | } \ |
| 2698 | } while (0) |
| 2699 | |
| 2700 | void helper_msa_ftq_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2701 | uint32_t ws, uint32_t wt) |
| 2702 | { |
| 2703 | wr_t wx, *pwx = &wx; |
| 2704 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2705 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2706 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
| 2707 | uint32_t i; |
| 2708 | |
| 2709 | clear_msacsr_cause(env); |
| 2710 | |
| 2711 | switch (df) { |
| 2712 | case DF_WORD: |
| 2713 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 2714 | MSA_FLOAT_UNOP_XD(Lh(pwx, i), to_q16, pws->w[i], 32, 16); |
| 2715 | MSA_FLOAT_UNOP_XD(Rh(pwx, i), to_q16, pwt->w[i], 32, 16); |
| 2716 | } |
| 2717 | break; |
| 2718 | case DF_DOUBLE: |
| 2719 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 2720 | MSA_FLOAT_UNOP_XD(Lw(pwx, i), to_q32, pws->d[i], 64, 32); |
| 2721 | MSA_FLOAT_UNOP_XD(Rw(pwx, i), to_q32, pwt->d[i], 64, 32); |
| 2722 | } |
| 2723 | break; |
| 2724 | default: |
| 2725 | assert(0); |
| 2726 | } |
| 2727 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2728 | check_msacsr_cause(env, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2729 | |
| 2730 | msa_move_v(pwd, pwx); |
| 2731 | } |
| 2732 | |
| 2733 | #define NUMBER_QNAN_PAIR(ARG1, ARG2, BITS) \ |
| 2734 | !float ## BITS ## _is_any_nan(ARG1) \ |
| 2735 | && float ## BITS ## _is_quiet_nan(ARG2) |
| 2736 | |
| 2737 | #define MSA_FLOAT_MAXOP(DEST, OP, ARG1, ARG2, BITS) \ |
| 2738 | do { \ |
Maciej W. Rozycki | 1a4d570 | 2014-12-02 17:51:12 +0000 | [diff] [blame] | 2739 | float_status *status = &env->active_tc.msa_fp_status; \ |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2740 | int c; \ |
| 2741 | \ |
Maciej W. Rozycki | 1a4d570 | 2014-12-02 17:51:12 +0000 | [diff] [blame] | 2742 | set_float_exception_flags(0, status); \ |
| 2743 | DEST = float ## BITS ## _ ## OP(ARG1, ARG2, status); \ |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2744 | c = update_msacsr(env, 0, 0); \ |
| 2745 | \ |
| 2746 | if (get_enabled_exceptions(env, c)) { \ |
| 2747 | DEST = ((FLOAT_SNAN ## BITS >> 6) << 6) | c; \ |
| 2748 | } \ |
| 2749 | } while (0) |
| 2750 | |
| 2751 | #define FMAXMIN_A(F, G, X, _S, _T, BITS) \ |
| 2752 | do { \ |
| 2753 | uint## BITS ##_t S = _S, T = _T; \ |
| 2754 | uint## BITS ##_t as, at, xs, xt, xd; \ |
| 2755 | if (NUMBER_QNAN_PAIR(S, T, BITS)) { \ |
| 2756 | T = S; \ |
| 2757 | } \ |
| 2758 | else if (NUMBER_QNAN_PAIR(T, S, BITS)) { \ |
| 2759 | S = T; \ |
| 2760 | } \ |
| 2761 | as = float## BITS ##_abs(S); \ |
| 2762 | at = float## BITS ##_abs(T); \ |
| 2763 | MSA_FLOAT_MAXOP(xs, F, S, T, BITS); \ |
| 2764 | MSA_FLOAT_MAXOP(xt, G, S, T, BITS); \ |
| 2765 | MSA_FLOAT_MAXOP(xd, F, as, at, BITS); \ |
| 2766 | X = (as == at || xd == float## BITS ##_abs(xs)) ? xs : xt; \ |
| 2767 | } while (0) |
| 2768 | |
| 2769 | void helper_msa_fmin_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2770 | uint32_t ws, uint32_t wt) |
| 2771 | { |
| 2772 | wr_t wx, *pwx = &wx; |
| 2773 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2774 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2775 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
| 2776 | uint32_t i; |
| 2777 | |
| 2778 | clear_msacsr_cause(env); |
| 2779 | |
| 2780 | switch (df) { |
| 2781 | case DF_WORD: |
| 2782 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 2783 | if (NUMBER_QNAN_PAIR(pws->w[i], pwt->w[i], 32)) { |
| 2784 | MSA_FLOAT_MAXOP(pwx->w[i], min, pws->w[i], pws->w[i], 32); |
| 2785 | } else if (NUMBER_QNAN_PAIR(pwt->w[i], pws->w[i], 32)) { |
| 2786 | MSA_FLOAT_MAXOP(pwx->w[i], min, pwt->w[i], pwt->w[i], 32); |
| 2787 | } else { |
| 2788 | MSA_FLOAT_MAXOP(pwx->w[i], min, pws->w[i], pwt->w[i], 32); |
| 2789 | } |
| 2790 | } |
| 2791 | break; |
| 2792 | case DF_DOUBLE: |
| 2793 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 2794 | if (NUMBER_QNAN_PAIR(pws->d[i], pwt->d[i], 64)) { |
| 2795 | MSA_FLOAT_MAXOP(pwx->d[i], min, pws->d[i], pws->d[i], 64); |
| 2796 | } else if (NUMBER_QNAN_PAIR(pwt->d[i], pws->d[i], 64)) { |
| 2797 | MSA_FLOAT_MAXOP(pwx->d[i], min, pwt->d[i], pwt->d[i], 64); |
| 2798 | } else { |
| 2799 | MSA_FLOAT_MAXOP(pwx->d[i], min, pws->d[i], pwt->d[i], 64); |
| 2800 | } |
| 2801 | } |
| 2802 | break; |
| 2803 | default: |
| 2804 | assert(0); |
| 2805 | } |
| 2806 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2807 | check_msacsr_cause(env, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2808 | |
| 2809 | msa_move_v(pwd, pwx); |
| 2810 | } |
| 2811 | |
| 2812 | void helper_msa_fmin_a_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2813 | uint32_t ws, uint32_t wt) |
| 2814 | { |
| 2815 | wr_t wx, *pwx = &wx; |
| 2816 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2817 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2818 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
| 2819 | uint32_t i; |
| 2820 | |
| 2821 | clear_msacsr_cause(env); |
| 2822 | |
| 2823 | switch (df) { |
| 2824 | case DF_WORD: |
| 2825 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 2826 | FMAXMIN_A(min, max, pwx->w[i], pws->w[i], pwt->w[i], 32); |
| 2827 | } |
| 2828 | break; |
| 2829 | case DF_DOUBLE: |
| 2830 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 2831 | FMAXMIN_A(min, max, pwx->d[i], pws->d[i], pwt->d[i], 64); |
| 2832 | } |
| 2833 | break; |
| 2834 | default: |
| 2835 | assert(0); |
| 2836 | } |
| 2837 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2838 | check_msacsr_cause(env, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2839 | |
| 2840 | msa_move_v(pwd, pwx); |
| 2841 | } |
| 2842 | |
| 2843 | void helper_msa_fmax_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2844 | uint32_t ws, uint32_t wt) |
| 2845 | { |
| 2846 | wr_t wx, *pwx = &wx; |
| 2847 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2848 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2849 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
| 2850 | uint32_t i; |
| 2851 | |
| 2852 | clear_msacsr_cause(env); |
| 2853 | |
| 2854 | switch (df) { |
| 2855 | case DF_WORD: |
| 2856 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 2857 | if (NUMBER_QNAN_PAIR(pws->w[i], pwt->w[i], 32)) { |
| 2858 | MSA_FLOAT_MAXOP(pwx->w[i], max, pws->w[i], pws->w[i], 32); |
| 2859 | } else if (NUMBER_QNAN_PAIR(pwt->w[i], pws->w[i], 32)) { |
| 2860 | MSA_FLOAT_MAXOP(pwx->w[i], max, pwt->w[i], pwt->w[i], 32); |
| 2861 | } else { |
| 2862 | MSA_FLOAT_MAXOP(pwx->w[i], max, pws->w[i], pwt->w[i], 32); |
| 2863 | } |
| 2864 | } |
| 2865 | break; |
| 2866 | case DF_DOUBLE: |
| 2867 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 2868 | if (NUMBER_QNAN_PAIR(pws->d[i], pwt->d[i], 64)) { |
| 2869 | MSA_FLOAT_MAXOP(pwx->d[i], max, pws->d[i], pws->d[i], 64); |
| 2870 | } else if (NUMBER_QNAN_PAIR(pwt->d[i], pws->d[i], 64)) { |
| 2871 | MSA_FLOAT_MAXOP(pwx->d[i], max, pwt->d[i], pwt->d[i], 64); |
| 2872 | } else { |
| 2873 | MSA_FLOAT_MAXOP(pwx->d[i], max, pws->d[i], pwt->d[i], 64); |
| 2874 | } |
| 2875 | } |
| 2876 | break; |
| 2877 | default: |
| 2878 | assert(0); |
| 2879 | } |
| 2880 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2881 | check_msacsr_cause(env, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2882 | |
| 2883 | msa_move_v(pwd, pwx); |
| 2884 | } |
| 2885 | |
| 2886 | void helper_msa_fmax_a_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2887 | uint32_t ws, uint32_t wt) |
| 2888 | { |
| 2889 | wr_t wx, *pwx = &wx; |
| 2890 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2891 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2892 | wr_t *pwt = &(env->active_fpu.fpr[wt].wr); |
| 2893 | uint32_t i; |
| 2894 | |
| 2895 | clear_msacsr_cause(env); |
| 2896 | |
| 2897 | switch (df) { |
| 2898 | case DF_WORD: |
| 2899 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 2900 | FMAXMIN_A(max, min, pwx->w[i], pws->w[i], pwt->w[i], 32); |
| 2901 | } |
| 2902 | break; |
| 2903 | case DF_DOUBLE: |
| 2904 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 2905 | FMAXMIN_A(max, min, pwx->d[i], pws->d[i], pwt->d[i], 64); |
| 2906 | } |
| 2907 | break; |
| 2908 | default: |
| 2909 | assert(0); |
| 2910 | } |
| 2911 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2912 | check_msacsr_cause(env, GETPC()); |
Yongbok Kim | 7d05b9c | 2014-11-01 05:28:48 +0000 | [diff] [blame] | 2913 | |
| 2914 | msa_move_v(pwd, pwx); |
| 2915 | } |
Yongbok Kim | 3bdeb68 | 2014-11-01 05:28:50 +0000 | [diff] [blame] | 2916 | |
| 2917 | void helper_msa_fclass_df(CPUMIPSState *env, uint32_t df, |
| 2918 | uint32_t wd, uint32_t ws) |
| 2919 | { |
| 2920 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2921 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2922 | if (df == DF_WORD) { |
| 2923 | pwd->w[0] = helper_float_class_s(pws->w[0]); |
| 2924 | pwd->w[1] = helper_float_class_s(pws->w[1]); |
| 2925 | pwd->w[2] = helper_float_class_s(pws->w[2]); |
| 2926 | pwd->w[3] = helper_float_class_s(pws->w[3]); |
| 2927 | } else { |
| 2928 | pwd->d[0] = helper_float_class_d(pws->d[0]); |
| 2929 | pwd->d[1] = helper_float_class_d(pws->d[1]); |
| 2930 | } |
| 2931 | } |
| 2932 | |
| 2933 | #define MSA_FLOAT_UNOP0(DEST, OP, ARG, BITS) \ |
| 2934 | do { \ |
Maciej W. Rozycki | 1a4d570 | 2014-12-02 17:51:12 +0000 | [diff] [blame] | 2935 | float_status *status = &env->active_tc.msa_fp_status; \ |
Yongbok Kim | 3bdeb68 | 2014-11-01 05:28:50 +0000 | [diff] [blame] | 2936 | int c; \ |
| 2937 | \ |
Maciej W. Rozycki | 1a4d570 | 2014-12-02 17:51:12 +0000 | [diff] [blame] | 2938 | set_float_exception_flags(0, status); \ |
| 2939 | DEST = float ## BITS ## _ ## OP(ARG, status); \ |
Yongbok Kim | 3bdeb68 | 2014-11-01 05:28:50 +0000 | [diff] [blame] | 2940 | c = update_msacsr(env, CLEAR_FS_UNDERFLOW, 0); \ |
| 2941 | \ |
| 2942 | if (get_enabled_exceptions(env, c)) { \ |
| 2943 | DEST = ((FLOAT_SNAN ## BITS >> 6) << 6) | c; \ |
| 2944 | } else if (float ## BITS ## _is_any_nan(ARG)) { \ |
| 2945 | DEST = 0; \ |
| 2946 | } \ |
| 2947 | } while (0) |
| 2948 | |
| 2949 | void helper_msa_ftrunc_s_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2950 | uint32_t ws) |
| 2951 | { |
| 2952 | wr_t wx, *pwx = &wx; |
| 2953 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2954 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2955 | uint32_t i; |
| 2956 | |
| 2957 | clear_msacsr_cause(env); |
| 2958 | |
| 2959 | switch (df) { |
| 2960 | case DF_WORD: |
| 2961 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 2962 | MSA_FLOAT_UNOP0(pwx->w[i], to_int32_round_to_zero, pws->w[i], 32); |
| 2963 | } |
| 2964 | break; |
| 2965 | case DF_DOUBLE: |
| 2966 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 2967 | MSA_FLOAT_UNOP0(pwx->d[i], to_int64_round_to_zero, pws->d[i], 64); |
| 2968 | } |
| 2969 | break; |
| 2970 | default: |
| 2971 | assert(0); |
| 2972 | } |
| 2973 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 2974 | check_msacsr_cause(env, GETPC()); |
Yongbok Kim | 3bdeb68 | 2014-11-01 05:28:50 +0000 | [diff] [blame] | 2975 | |
| 2976 | msa_move_v(pwd, pwx); |
| 2977 | } |
| 2978 | |
| 2979 | void helper_msa_ftrunc_u_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 2980 | uint32_t ws) |
| 2981 | { |
| 2982 | wr_t wx, *pwx = &wx; |
| 2983 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 2984 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 2985 | uint32_t i; |
| 2986 | |
| 2987 | clear_msacsr_cause(env); |
| 2988 | |
| 2989 | switch (df) { |
| 2990 | case DF_WORD: |
| 2991 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 2992 | MSA_FLOAT_UNOP0(pwx->w[i], to_uint32_round_to_zero, pws->w[i], 32); |
| 2993 | } |
| 2994 | break; |
| 2995 | case DF_DOUBLE: |
| 2996 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 2997 | MSA_FLOAT_UNOP0(pwx->d[i], to_uint64_round_to_zero, pws->d[i], 64); |
| 2998 | } |
| 2999 | break; |
| 3000 | default: |
| 3001 | assert(0); |
| 3002 | } |
| 3003 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 3004 | check_msacsr_cause(env, GETPC()); |
Yongbok Kim | 3bdeb68 | 2014-11-01 05:28:50 +0000 | [diff] [blame] | 3005 | |
| 3006 | msa_move_v(pwd, pwx); |
| 3007 | } |
| 3008 | |
| 3009 | void helper_msa_fsqrt_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 3010 | uint32_t ws) |
| 3011 | { |
| 3012 | wr_t wx, *pwx = &wx; |
| 3013 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 3014 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 3015 | uint32_t i; |
| 3016 | |
| 3017 | clear_msacsr_cause(env); |
| 3018 | |
| 3019 | switch (df) { |
| 3020 | case DF_WORD: |
| 3021 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 3022 | MSA_FLOAT_UNOP(pwx->w[i], sqrt, pws->w[i], 32); |
| 3023 | } |
| 3024 | break; |
| 3025 | case DF_DOUBLE: |
| 3026 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 3027 | MSA_FLOAT_UNOP(pwx->d[i], sqrt, pws->d[i], 64); |
| 3028 | } |
| 3029 | break; |
| 3030 | default: |
| 3031 | assert(0); |
| 3032 | } |
| 3033 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 3034 | check_msacsr_cause(env, GETPC()); |
Yongbok Kim | 3bdeb68 | 2014-11-01 05:28:50 +0000 | [diff] [blame] | 3035 | |
| 3036 | msa_move_v(pwd, pwx); |
| 3037 | } |
| 3038 | |
| 3039 | #define MSA_FLOAT_RECIPROCAL(DEST, ARG, BITS) \ |
| 3040 | do { \ |
Maciej W. Rozycki | 1a4d570 | 2014-12-02 17:51:12 +0000 | [diff] [blame] | 3041 | float_status *status = &env->active_tc.msa_fp_status; \ |
Yongbok Kim | 3bdeb68 | 2014-11-01 05:28:50 +0000 | [diff] [blame] | 3042 | int c; \ |
| 3043 | \ |
Maciej W. Rozycki | 1a4d570 | 2014-12-02 17:51:12 +0000 | [diff] [blame] | 3044 | set_float_exception_flags(0, status); \ |
| 3045 | DEST = float ## BITS ## _ ## div(FLOAT_ONE ## BITS, ARG, status); \ |
Yongbok Kim | 3bdeb68 | 2014-11-01 05:28:50 +0000 | [diff] [blame] | 3046 | c = update_msacsr(env, float ## BITS ## _is_infinity(ARG) || \ |
| 3047 | float ## BITS ## _is_quiet_nan(DEST) ? \ |
| 3048 | 0 : RECIPROCAL_INEXACT, \ |
| 3049 | IS_DENORMAL(DEST, BITS)); \ |
| 3050 | \ |
| 3051 | if (get_enabled_exceptions(env, c)) { \ |
| 3052 | DEST = ((FLOAT_SNAN ## BITS >> 6) << 6) | c; \ |
| 3053 | } \ |
| 3054 | } while (0) |
| 3055 | |
| 3056 | void helper_msa_frsqrt_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 3057 | uint32_t ws) |
| 3058 | { |
| 3059 | wr_t wx, *pwx = &wx; |
| 3060 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 3061 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 3062 | uint32_t i; |
| 3063 | |
| 3064 | clear_msacsr_cause(env); |
| 3065 | |
| 3066 | switch (df) { |
| 3067 | case DF_WORD: |
| 3068 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 3069 | MSA_FLOAT_RECIPROCAL(pwx->w[i], float32_sqrt(pws->w[i], |
| 3070 | &env->active_tc.msa_fp_status), 32); |
| 3071 | } |
| 3072 | break; |
| 3073 | case DF_DOUBLE: |
| 3074 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 3075 | MSA_FLOAT_RECIPROCAL(pwx->d[i], float64_sqrt(pws->d[i], |
| 3076 | &env->active_tc.msa_fp_status), 64); |
| 3077 | } |
| 3078 | break; |
| 3079 | default: |
| 3080 | assert(0); |
| 3081 | } |
| 3082 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 3083 | check_msacsr_cause(env, GETPC()); |
Yongbok Kim | 3bdeb68 | 2014-11-01 05:28:50 +0000 | [diff] [blame] | 3084 | |
| 3085 | msa_move_v(pwd, pwx); |
| 3086 | } |
| 3087 | |
| 3088 | void helper_msa_frcp_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 3089 | uint32_t ws) |
| 3090 | { |
| 3091 | wr_t wx, *pwx = &wx; |
| 3092 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 3093 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 3094 | uint32_t i; |
| 3095 | |
| 3096 | clear_msacsr_cause(env); |
| 3097 | |
| 3098 | switch (df) { |
| 3099 | case DF_WORD: |
| 3100 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 3101 | MSA_FLOAT_RECIPROCAL(pwx->w[i], pws->w[i], 32); |
| 3102 | } |
| 3103 | break; |
| 3104 | case DF_DOUBLE: |
| 3105 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 3106 | MSA_FLOAT_RECIPROCAL(pwx->d[i], pws->d[i], 64); |
| 3107 | } |
| 3108 | break; |
| 3109 | default: |
| 3110 | assert(0); |
| 3111 | } |
| 3112 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 3113 | check_msacsr_cause(env, GETPC()); |
Yongbok Kim | 3bdeb68 | 2014-11-01 05:28:50 +0000 | [diff] [blame] | 3114 | |
| 3115 | msa_move_v(pwd, pwx); |
| 3116 | } |
| 3117 | |
| 3118 | void helper_msa_frint_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 3119 | uint32_t ws) |
| 3120 | { |
| 3121 | wr_t wx, *pwx = &wx; |
| 3122 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 3123 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 3124 | uint32_t i; |
| 3125 | |
| 3126 | clear_msacsr_cause(env); |
| 3127 | |
| 3128 | switch (df) { |
| 3129 | case DF_WORD: |
| 3130 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 3131 | MSA_FLOAT_UNOP(pwx->w[i], round_to_int, pws->w[i], 32); |
| 3132 | } |
| 3133 | break; |
| 3134 | case DF_DOUBLE: |
| 3135 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 3136 | MSA_FLOAT_UNOP(pwx->d[i], round_to_int, pws->d[i], 64); |
| 3137 | } |
| 3138 | break; |
| 3139 | default: |
| 3140 | assert(0); |
| 3141 | } |
| 3142 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 3143 | check_msacsr_cause(env, GETPC()); |
Yongbok Kim | 3bdeb68 | 2014-11-01 05:28:50 +0000 | [diff] [blame] | 3144 | |
| 3145 | msa_move_v(pwd, pwx); |
| 3146 | } |
| 3147 | |
| 3148 | #define MSA_FLOAT_LOGB(DEST, ARG, BITS) \ |
| 3149 | do { \ |
Maciej W. Rozycki | 1a4d570 | 2014-12-02 17:51:12 +0000 | [diff] [blame] | 3150 | float_status *status = &env->active_tc.msa_fp_status; \ |
Yongbok Kim | 3bdeb68 | 2014-11-01 05:28:50 +0000 | [diff] [blame] | 3151 | int c; \ |
| 3152 | \ |
Maciej W. Rozycki | 1a4d570 | 2014-12-02 17:51:12 +0000 | [diff] [blame] | 3153 | set_float_exception_flags(0, status); \ |
| 3154 | set_float_rounding_mode(float_round_down, status); \ |
| 3155 | DEST = float ## BITS ## _ ## log2(ARG, status); \ |
| 3156 | DEST = float ## BITS ## _ ## round_to_int(DEST, status); \ |
Yongbok Kim | 3bdeb68 | 2014-11-01 05:28:50 +0000 | [diff] [blame] | 3157 | set_float_rounding_mode(ieee_rm[(env->active_tc.msacsr & \ |
| 3158 | MSACSR_RM_MASK) >> MSACSR_RM], \ |
Maciej W. Rozycki | 1a4d570 | 2014-12-02 17:51:12 +0000 | [diff] [blame] | 3159 | status); \ |
Yongbok Kim | 3bdeb68 | 2014-11-01 05:28:50 +0000 | [diff] [blame] | 3160 | \ |
Maciej W. Rozycki | 1a4d570 | 2014-12-02 17:51:12 +0000 | [diff] [blame] | 3161 | set_float_exception_flags(get_float_exception_flags(status) & \ |
| 3162 | (~float_flag_inexact), \ |
| 3163 | status); \ |
Yongbok Kim | 3bdeb68 | 2014-11-01 05:28:50 +0000 | [diff] [blame] | 3164 | \ |
| 3165 | c = update_msacsr(env, 0, IS_DENORMAL(DEST, BITS)); \ |
| 3166 | \ |
| 3167 | if (get_enabled_exceptions(env, c)) { \ |
| 3168 | DEST = ((FLOAT_SNAN ## BITS >> 6) << 6) | c; \ |
| 3169 | } \ |
| 3170 | } while (0) |
| 3171 | |
| 3172 | void helper_msa_flog2_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 3173 | uint32_t ws) |
| 3174 | { |
| 3175 | wr_t wx, *pwx = &wx; |
| 3176 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 3177 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 3178 | uint32_t i; |
| 3179 | |
| 3180 | clear_msacsr_cause(env); |
| 3181 | |
| 3182 | switch (df) { |
| 3183 | case DF_WORD: |
| 3184 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 3185 | MSA_FLOAT_LOGB(pwx->w[i], pws->w[i], 32); |
| 3186 | } |
| 3187 | break; |
| 3188 | case DF_DOUBLE: |
| 3189 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 3190 | MSA_FLOAT_LOGB(pwx->d[i], pws->d[i], 64); |
| 3191 | } |
| 3192 | break; |
| 3193 | default: |
| 3194 | assert(0); |
| 3195 | } |
| 3196 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 3197 | check_msacsr_cause(env, GETPC()); |
Yongbok Kim | 3bdeb68 | 2014-11-01 05:28:50 +0000 | [diff] [blame] | 3198 | |
| 3199 | msa_move_v(pwd, pwx); |
| 3200 | } |
| 3201 | |
| 3202 | void helper_msa_fexupl_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 3203 | uint32_t ws) |
| 3204 | { |
| 3205 | wr_t wx, *pwx = &wx; |
| 3206 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 3207 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 3208 | uint32_t i; |
| 3209 | |
Yongbok Kim | d4f4f0d | 2015-06-30 15:44:28 +0100 | [diff] [blame] | 3210 | clear_msacsr_cause(env); |
| 3211 | |
Yongbok Kim | 3bdeb68 | 2014-11-01 05:28:50 +0000 | [diff] [blame] | 3212 | switch (df) { |
| 3213 | case DF_WORD: |
| 3214 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 3215 | /* Half precision floats come in two formats: standard |
| 3216 | IEEE and "ARM" format. The latter gains extra exponent |
| 3217 | range by omitting the NaN/Inf encodings. */ |
| 3218 | flag ieee = 1; |
| 3219 | |
| 3220 | MSA_FLOAT_BINOP(pwx->w[i], from_float16, Lh(pws, i), ieee, 32); |
| 3221 | } |
| 3222 | break; |
| 3223 | case DF_DOUBLE: |
| 3224 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 3225 | MSA_FLOAT_UNOP(pwx->d[i], from_float32, Lw(pws, i), 64); |
| 3226 | } |
| 3227 | break; |
| 3228 | default: |
| 3229 | assert(0); |
| 3230 | } |
| 3231 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 3232 | check_msacsr_cause(env, GETPC()); |
Yongbok Kim | 3bdeb68 | 2014-11-01 05:28:50 +0000 | [diff] [blame] | 3233 | msa_move_v(pwd, pwx); |
| 3234 | } |
| 3235 | |
| 3236 | void helper_msa_fexupr_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 3237 | uint32_t ws) |
| 3238 | { |
| 3239 | wr_t wx, *pwx = &wx; |
| 3240 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 3241 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 3242 | uint32_t i; |
| 3243 | |
Yongbok Kim | d4f4f0d | 2015-06-30 15:44:28 +0100 | [diff] [blame] | 3244 | clear_msacsr_cause(env); |
| 3245 | |
Yongbok Kim | 3bdeb68 | 2014-11-01 05:28:50 +0000 | [diff] [blame] | 3246 | switch (df) { |
| 3247 | case DF_WORD: |
| 3248 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 3249 | /* Half precision floats come in two formats: standard |
| 3250 | IEEE and "ARM" format. The latter gains extra exponent |
| 3251 | range by omitting the NaN/Inf encodings. */ |
| 3252 | flag ieee = 1; |
| 3253 | |
| 3254 | MSA_FLOAT_BINOP(pwx->w[i], from_float16, Rh(pws, i), ieee, 32); |
| 3255 | } |
| 3256 | break; |
| 3257 | case DF_DOUBLE: |
| 3258 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 3259 | MSA_FLOAT_UNOP(pwx->d[i], from_float32, Rw(pws, i), 64); |
| 3260 | } |
| 3261 | break; |
| 3262 | default: |
| 3263 | assert(0); |
| 3264 | } |
| 3265 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 3266 | check_msacsr_cause(env, GETPC()); |
Yongbok Kim | 3bdeb68 | 2014-11-01 05:28:50 +0000 | [diff] [blame] | 3267 | msa_move_v(pwd, pwx); |
| 3268 | } |
| 3269 | |
| 3270 | void helper_msa_ffql_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 3271 | uint32_t ws) |
| 3272 | { |
| 3273 | wr_t wx, *pwx = &wx; |
| 3274 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 3275 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 3276 | uint32_t i; |
| 3277 | |
| 3278 | switch (df) { |
| 3279 | case DF_WORD: |
| 3280 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 3281 | MSA_FLOAT_UNOP(pwx->w[i], from_q16, Lh(pws, i), 32); |
| 3282 | } |
| 3283 | break; |
| 3284 | case DF_DOUBLE: |
| 3285 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 3286 | MSA_FLOAT_UNOP(pwx->d[i], from_q32, Lw(pws, i), 64); |
| 3287 | } |
| 3288 | break; |
| 3289 | default: |
| 3290 | assert(0); |
| 3291 | } |
| 3292 | |
| 3293 | msa_move_v(pwd, pwx); |
| 3294 | } |
| 3295 | |
| 3296 | void helper_msa_ffqr_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 3297 | uint32_t ws) |
| 3298 | { |
| 3299 | wr_t wx, *pwx = &wx; |
| 3300 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 3301 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 3302 | uint32_t i; |
| 3303 | |
| 3304 | switch (df) { |
| 3305 | case DF_WORD: |
| 3306 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 3307 | MSA_FLOAT_UNOP(pwx->w[i], from_q16, Rh(pws, i), 32); |
| 3308 | } |
| 3309 | break; |
| 3310 | case DF_DOUBLE: |
| 3311 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 3312 | MSA_FLOAT_UNOP(pwx->d[i], from_q32, Rw(pws, i), 64); |
| 3313 | } |
| 3314 | break; |
| 3315 | default: |
| 3316 | assert(0); |
| 3317 | } |
| 3318 | |
| 3319 | msa_move_v(pwd, pwx); |
| 3320 | } |
| 3321 | |
| 3322 | void helper_msa_ftint_s_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 3323 | uint32_t ws) |
| 3324 | { |
| 3325 | wr_t wx, *pwx = &wx; |
| 3326 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 3327 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 3328 | uint32_t i; |
| 3329 | |
| 3330 | clear_msacsr_cause(env); |
| 3331 | |
| 3332 | switch (df) { |
| 3333 | case DF_WORD: |
| 3334 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 3335 | MSA_FLOAT_UNOP0(pwx->w[i], to_int32, pws->w[i], 32); |
| 3336 | } |
| 3337 | break; |
| 3338 | case DF_DOUBLE: |
| 3339 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 3340 | MSA_FLOAT_UNOP0(pwx->d[i], to_int64, pws->d[i], 64); |
| 3341 | } |
| 3342 | break; |
| 3343 | default: |
| 3344 | assert(0); |
| 3345 | } |
| 3346 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 3347 | check_msacsr_cause(env, GETPC()); |
Yongbok Kim | 3bdeb68 | 2014-11-01 05:28:50 +0000 | [diff] [blame] | 3348 | |
| 3349 | msa_move_v(pwd, pwx); |
| 3350 | } |
| 3351 | |
| 3352 | void helper_msa_ftint_u_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 3353 | uint32_t ws) |
| 3354 | { |
| 3355 | wr_t wx, *pwx = &wx; |
| 3356 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 3357 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 3358 | uint32_t i; |
| 3359 | |
| 3360 | clear_msacsr_cause(env); |
| 3361 | |
| 3362 | switch (df) { |
| 3363 | case DF_WORD: |
| 3364 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 3365 | MSA_FLOAT_UNOP0(pwx->w[i], to_uint32, pws->w[i], 32); |
| 3366 | } |
| 3367 | break; |
| 3368 | case DF_DOUBLE: |
| 3369 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 3370 | MSA_FLOAT_UNOP0(pwx->d[i], to_uint64, pws->d[i], 64); |
| 3371 | } |
| 3372 | break; |
| 3373 | default: |
| 3374 | assert(0); |
| 3375 | } |
| 3376 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 3377 | check_msacsr_cause(env, GETPC()); |
Yongbok Kim | 3bdeb68 | 2014-11-01 05:28:50 +0000 | [diff] [blame] | 3378 | |
| 3379 | msa_move_v(pwd, pwx); |
| 3380 | } |
| 3381 | |
| 3382 | #define float32_from_int32 int32_to_float32 |
| 3383 | #define float32_from_uint32 uint32_to_float32 |
| 3384 | |
| 3385 | #define float64_from_int64 int64_to_float64 |
| 3386 | #define float64_from_uint64 uint64_to_float64 |
| 3387 | |
| 3388 | void helper_msa_ffint_s_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 3389 | uint32_t ws) |
| 3390 | { |
| 3391 | wr_t wx, *pwx = &wx; |
| 3392 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 3393 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 3394 | uint32_t i; |
| 3395 | |
| 3396 | clear_msacsr_cause(env); |
| 3397 | |
| 3398 | switch (df) { |
| 3399 | case DF_WORD: |
| 3400 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 3401 | MSA_FLOAT_UNOP(pwx->w[i], from_int32, pws->w[i], 32); |
| 3402 | } |
| 3403 | break; |
| 3404 | case DF_DOUBLE: |
| 3405 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 3406 | MSA_FLOAT_UNOP(pwx->d[i], from_int64, pws->d[i], 64); |
| 3407 | } |
| 3408 | break; |
| 3409 | default: |
| 3410 | assert(0); |
| 3411 | } |
| 3412 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 3413 | check_msacsr_cause(env, GETPC()); |
Yongbok Kim | 3bdeb68 | 2014-11-01 05:28:50 +0000 | [diff] [blame] | 3414 | |
| 3415 | msa_move_v(pwd, pwx); |
| 3416 | } |
| 3417 | |
| 3418 | void helper_msa_ffint_u_df(CPUMIPSState *env, uint32_t df, uint32_t wd, |
| 3419 | uint32_t ws) |
| 3420 | { |
| 3421 | wr_t wx, *pwx = &wx; |
| 3422 | wr_t *pwd = &(env->active_fpu.fpr[wd].wr); |
| 3423 | wr_t *pws = &(env->active_fpu.fpr[ws].wr); |
| 3424 | uint32_t i; |
| 3425 | |
| 3426 | clear_msacsr_cause(env); |
| 3427 | |
| 3428 | switch (df) { |
| 3429 | case DF_WORD: |
| 3430 | for (i = 0; i < DF_ELEMENTS(DF_WORD); i++) { |
| 3431 | MSA_FLOAT_UNOP(pwx->w[i], from_uint32, pws->w[i], 32); |
| 3432 | } |
| 3433 | break; |
| 3434 | case DF_DOUBLE: |
| 3435 | for (i = 0; i < DF_ELEMENTS(DF_DOUBLE); i++) { |
| 3436 | MSA_FLOAT_UNOP(pwx->d[i], from_uint64, pws->d[i], 64); |
| 3437 | } |
| 3438 | break; |
| 3439 | default: |
| 3440 | assert(0); |
| 3441 | } |
| 3442 | |
Pavel Dovgaluk | 9c708c7 | 2015-07-10 12:57:08 +0300 | [diff] [blame] | 3443 | check_msacsr_cause(env, GETPC()); |
Yongbok Kim | 3bdeb68 | 2014-11-01 05:28:50 +0000 | [diff] [blame] | 3444 | |
| 3445 | msa_move_v(pwd, pwx); |
| 3446 | } |