]>
Commit | Line | Data |
---|---|---|
bd23cd45 BS |
1 | /* |
2 | * PowerPC floating point and SPE emulation helpers for QEMU. | |
3 | * | |
4 | * Copyright (c) 2003-2007 Jocelyn Mayer | |
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 | |
6bd039cd | 9 | * version 2.1 of the License, or (at your option) any later version. |
bd23cd45 BS |
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 | */ | |
0d75590d | 19 | #include "qemu/osdep.h" |
bd23cd45 | 20 | #include "cpu.h" |
2ef6175a | 21 | #include "exec/helper-proto.h" |
a93ecff9 | 22 | #include "exec/exec-all.h" |
985e3023 | 23 | #include "internal.h" |
24f91e81 | 24 | #include "fpu/softfloat.h" |
bd23cd45 | 25 | |
e5487803 BR |
26 | static inline float128 float128_snan_to_qnan(float128 x) |
27 | { | |
28 | float128 r; | |
29 | ||
30 | r.high = x.high | 0x0000800000000000; | |
31 | r.low = x.low; | |
32 | return r; | |
33 | } | |
34 | ||
b748863a TM |
35 | #define float64_snan_to_qnan(x) ((x) | 0x0008000000000000ULL) |
36 | #define float32_snan_to_qnan(x) ((x) | 0x00400000) | |
f566c047 | 37 | #define float16_snan_to_qnan(x) ((x) | 0x0200) |
b748863a | 38 | |
e82c42b7 RH |
39 | static inline bool fp_exceptions_enabled(CPUPPCState *env) |
40 | { | |
41 | #ifdef CONFIG_USER_ONLY | |
42 | return true; | |
43 | #else | |
44 | return (env->msr & ((1U << MSR_FE0) | (1U << MSR_FE1))) != 0; | |
45 | #endif | |
46 | } | |
47 | ||
bd23cd45 BS |
48 | /*****************************************************************************/ |
49 | /* Floating point operations helpers */ | |
86c0cab1 RH |
50 | |
51 | /* | |
52 | * This is the non-arithmatic conversion that happens e.g. on loads. | |
53 | * In the Power ISA pseudocode, this is called DOUBLE. | |
54 | */ | |
55 | uint64_t helper_todouble(uint32_t arg) | |
bd23cd45 | 56 | { |
86c0cab1 RH |
57 | uint32_t abs_arg = arg & 0x7fffffff; |
58 | uint64_t ret; | |
bd23cd45 | 59 | |
86c0cab1 | 60 | if (likely(abs_arg >= 0x00800000)) { |
a7b7b983 PC |
61 | if (unlikely(extract32(arg, 23, 8) == 0xff)) { |
62 | /* Inf or NAN. */ | |
63 | ret = (uint64_t)extract32(arg, 31, 1) << 63; | |
64 | ret |= (uint64_t)0x7ff << 52; | |
65 | ret |= (uint64_t)extract32(arg, 0, 23) << 29; | |
66 | } else { | |
67 | /* Normalized operand. */ | |
68 | ret = (uint64_t)extract32(arg, 30, 2) << 62; | |
69 | ret |= ((extract32(arg, 30, 1) ^ 1) * (uint64_t)7) << 59; | |
70 | ret |= (uint64_t)extract32(arg, 0, 30) << 29; | |
71 | } | |
86c0cab1 RH |
72 | } else { |
73 | /* Zero or Denormalized operand. */ | |
74 | ret = (uint64_t)extract32(arg, 31, 1) << 63; | |
75 | if (unlikely(abs_arg != 0)) { | |
c0e6616b PC |
76 | /* |
77 | * Denormalized operand. | |
78 | * Shift fraction so that the msb is in the implicit bit position. | |
79 | * Thus, shift is in the range [1:23]. | |
80 | */ | |
81 | int shift = clz32(abs_arg) - 8; | |
82 | /* | |
83 | * The first 3 terms compute the float64 exponent. We then bias | |
84 | * this result by -1 so that we can swallow the implicit bit below. | |
85 | */ | |
86 | int exp = -126 - shift + 1023 - 1; | |
87 | ||
86c0cab1 | 88 | ret |= (uint64_t)exp << 52; |
c0e6616b | 89 | ret += (uint64_t)abs_arg << (52 - 23 + shift); |
86c0cab1 RH |
90 | } |
91 | } | |
92 | return ret; | |
bd23cd45 BS |
93 | } |
94 | ||
86c0cab1 RH |
95 | /* |
96 | * This is the non-arithmatic conversion that happens e.g. on stores. | |
97 | * In the Power ISA pseudocode, this is called SINGLE. | |
98 | */ | |
99 | uint32_t helper_tosingle(uint64_t arg) | |
bd23cd45 | 100 | { |
86c0cab1 RH |
101 | int exp = extract64(arg, 52, 11); |
102 | uint32_t ret; | |
bd23cd45 | 103 | |
86c0cab1 RH |
104 | if (likely(exp > 896)) { |
105 | /* No denormalization required (includes Inf, NaN). */ | |
106 | ret = extract64(arg, 62, 2) << 30; | |
107 | ret |= extract64(arg, 29, 30); | |
108 | } else { | |
fa9ebf8c DG |
109 | /* |
110 | * Zero or Denormal result. If the exponent is in bounds for | |
111 | * a single-precision denormal result, extract the proper | |
112 | * bits. If the input is not zero, and the exponent is out of | |
113 | * bounds, then the result is undefined; this underflows to | |
114 | * zero. | |
86c0cab1 RH |
115 | */ |
116 | ret = extract64(arg, 63, 1) << 31; | |
117 | if (unlikely(exp >= 874)) { | |
118 | /* Denormal result. */ | |
119 | ret |= ((1ULL << 52) | extract64(arg, 0, 52)) >> (896 + 30 - exp); | |
120 | } | |
121 | } | |
122 | return ret; | |
bd23cd45 BS |
123 | } |
124 | ||
da29cb7b TM |
125 | static inline int ppc_float32_get_unbiased_exp(float32 f) |
126 | { | |
127 | return ((f >> 23) & 0xFF) - 127; | |
128 | } | |
129 | ||
130 | static inline int ppc_float64_get_unbiased_exp(float64 f) | |
131 | { | |
132 | return ((f >> 52) & 0x7FF) - 1023; | |
133 | } | |
134 | ||
0394d7a6 RH |
135 | /* Classify a floating-point number. */ |
136 | enum { | |
137 | is_normal = 1, | |
138 | is_zero = 2, | |
139 | is_denormal = 4, | |
140 | is_inf = 8, | |
141 | is_qnan = 16, | |
142 | is_snan = 32, | |
143 | is_neg = 64, | |
144 | }; | |
145 | ||
146 | #define COMPUTE_CLASS(tp) \ | |
147 | static int tp##_classify(tp arg) \ | |
ffc67420 | 148 | { \ |
0394d7a6 | 149 | int ret = tp##_is_neg(arg) * is_neg; \ |
ffc67420 | 150 | if (unlikely(tp##_is_any_nan(arg))) { \ |
0394d7a6 RH |
151 | float_status dummy = { }; /* snan_bit_is_one = 0 */ \ |
152 | ret |= (tp##_is_signaling_nan(arg, &dummy) \ | |
153 | ? is_snan : is_qnan); \ | |
ffc67420 | 154 | } else if (unlikely(tp##_is_infinity(arg))) { \ |
0394d7a6 RH |
155 | ret |= is_inf; \ |
156 | } else if (tp##_is_zero(arg)) { \ | |
157 | ret |= is_zero; \ | |
158 | } else if (tp##_is_zero_or_denormal(arg)) { \ | |
159 | ret |= is_denormal; \ | |
ffc67420 | 160 | } else { \ |
0394d7a6 | 161 | ret |= is_normal; \ |
ffc67420 | 162 | } \ |
0394d7a6 RH |
163 | return ret; \ |
164 | } | |
165 | ||
166 | COMPUTE_CLASS(float16) | |
167 | COMPUTE_CLASS(float32) | |
168 | COMPUTE_CLASS(float64) | |
169 | COMPUTE_CLASS(float128) | |
170 | ||
171 | static void set_fprf_from_class(CPUPPCState *env, int class) | |
172 | { | |
173 | static const uint8_t fprf[6][2] = { | |
174 | { 0x04, 0x08 }, /* normalized */ | |
175 | { 0x02, 0x12 }, /* zero */ | |
176 | { 0x14, 0x18 }, /* denormalized */ | |
177 | { 0x05, 0x09 }, /* infinity */ | |
178 | { 0x11, 0x11 }, /* qnan */ | |
179 | { 0x00, 0x00 }, /* snan -- flags are undefined */ | |
180 | }; | |
181 | bool isneg = class & is_neg; | |
182 | ||
5c94dd38 | 183 | env->fpscr &= ~FP_FPRF; |
0394d7a6 RH |
184 | env->fpscr |= fprf[ctz32(class)][isneg] << FPSCR_FPRF; |
185 | } | |
186 | ||
187 | #define COMPUTE_FPRF(tp) \ | |
188 | void helper_compute_fprf_##tp(CPUPPCState *env, tp arg) \ | |
189 | { \ | |
190 | set_fprf_from_class(env, tp##_classify(arg)); \ | |
ffc67420 BR |
191 | } |
192 | ||
f566c047 | 193 | COMPUTE_FPRF(float16) |
9aeae8e1 | 194 | COMPUTE_FPRF(float32) |
ffc67420 | 195 | COMPUTE_FPRF(float64) |
07bdd247 | 196 | COMPUTE_FPRF(float128) |
bd23cd45 BS |
197 | |
198 | /* Floating-point invalid operations exception */ | |
13c9115f | 199 | static void finish_invalid_op_excp(CPUPPCState *env, int op, uintptr_t retaddr) |
bd23cd45 | 200 | { |
13c9115f | 201 | /* Update the floating-point invalid operation summary */ |
5c94dd38 | 202 | env->fpscr |= FP_VX; |
13c9115f RH |
203 | /* Update the floating-point exception summary */ |
204 | env->fpscr |= FP_FX; | |
205 | if (fpscr_ve != 0) { | |
206 | /* Update the floating-point enabled exception summary */ | |
5c94dd38 | 207 | env->fpscr |= FP_FEX; |
13c9115f RH |
208 | if (fp_exceptions_enabled(env)) { |
209 | raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, | |
210 | POWERPC_EXCP_FP | op, retaddr); | |
211 | } | |
212 | } | |
213 | } | |
bd23cd45 | 214 | |
13c9115f RH |
215 | static void finish_invalid_op_arith(CPUPPCState *env, int op, |
216 | bool set_fpcc, uintptr_t retaddr) | |
217 | { | |
5c94dd38 | 218 | env->fpscr &= ~(FP_FR | FP_FI); |
13c9115f | 219 | if (fpscr_ve == 0) { |
59800ec8 | 220 | if (set_fpcc) { |
5c94dd38 PC |
221 | env->fpscr &= ~FP_FPCC; |
222 | env->fpscr |= (FP_C | FP_FU); | |
59800ec8 | 223 | } |
13c9115f RH |
224 | } |
225 | finish_invalid_op_excp(env, op, retaddr); | |
226 | } | |
227 | ||
228 | /* Signalling NaN */ | |
229 | static void float_invalid_op_vxsnan(CPUPPCState *env, uintptr_t retaddr) | |
230 | { | |
5c94dd38 | 231 | env->fpscr |= FP_VXSNAN; |
13c9115f RH |
232 | finish_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, retaddr); |
233 | } | |
234 | ||
235 | /* Magnitude subtraction of infinities */ | |
236 | static void float_invalid_op_vxisi(CPUPPCState *env, bool set_fpcc, | |
237 | uintptr_t retaddr) | |
238 | { | |
5c94dd38 | 239 | env->fpscr |= FP_VXISI; |
13c9115f RH |
240 | finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXISI, set_fpcc, retaddr); |
241 | } | |
242 | ||
243 | /* Division of infinity by infinity */ | |
244 | static void float_invalid_op_vxidi(CPUPPCState *env, bool set_fpcc, | |
245 | uintptr_t retaddr) | |
246 | { | |
5c94dd38 | 247 | env->fpscr |= FP_VXIDI; |
13c9115f RH |
248 | finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXIDI, set_fpcc, retaddr); |
249 | } | |
250 | ||
251 | /* Division of zero by zero */ | |
252 | static void float_invalid_op_vxzdz(CPUPPCState *env, bool set_fpcc, | |
253 | uintptr_t retaddr) | |
254 | { | |
5c94dd38 | 255 | env->fpscr |= FP_VXZDZ; |
13c9115f RH |
256 | finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXZDZ, set_fpcc, retaddr); |
257 | } | |
258 | ||
259 | /* Multiplication of zero by infinity */ | |
260 | static void float_invalid_op_vximz(CPUPPCState *env, bool set_fpcc, | |
261 | uintptr_t retaddr) | |
262 | { | |
5c94dd38 | 263 | env->fpscr |= FP_VXIMZ; |
13c9115f RH |
264 | finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXIMZ, set_fpcc, retaddr); |
265 | } | |
266 | ||
267 | /* Square root of a negative number */ | |
268 | static void float_invalid_op_vxsqrt(CPUPPCState *env, bool set_fpcc, | |
269 | uintptr_t retaddr) | |
270 | { | |
5c94dd38 | 271 | env->fpscr |= FP_VXSQRT; |
13c9115f RH |
272 | finish_invalid_op_arith(env, POWERPC_EXCP_FP_VXSQRT, set_fpcc, retaddr); |
273 | } | |
274 | ||
275 | /* Ordered comparison of NaN */ | |
276 | static void float_invalid_op_vxvc(CPUPPCState *env, bool set_fpcc, | |
277 | uintptr_t retaddr) | |
278 | { | |
5c94dd38 | 279 | env->fpscr |= FP_VXVC; |
13c9115f | 280 | if (set_fpcc) { |
5c94dd38 PC |
281 | env->fpscr &= ~FP_FPCC; |
282 | env->fpscr |= (FP_C | FP_FU); | |
bd23cd45 BS |
283 | } |
284 | /* Update the floating-point invalid operation summary */ | |
5c94dd38 | 285 | env->fpscr |= FP_VX; |
bd23cd45 | 286 | /* Update the floating-point exception summary */ |
76247892 | 287 | env->fpscr |= FP_FX; |
13c9115f RH |
288 | /* We must update the target FPR before raising the exception */ |
289 | if (fpscr_ve != 0) { | |
db70b311 | 290 | CPUState *cs = env_cpu(env); |
13c9115f RH |
291 | |
292 | cs->exception_index = POWERPC_EXCP_PROGRAM; | |
293 | env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC; | |
bd23cd45 | 294 | /* Update the floating-point enabled exception summary */ |
5c94dd38 | 295 | env->fpscr |= FP_FEX; |
92eeb004 | 296 | /* Exception is deferred */ |
13c9115f RH |
297 | } |
298 | } | |
299 | ||
300 | /* Invalid conversion */ | |
301 | static void float_invalid_op_vxcvi(CPUPPCState *env, bool set_fpcc, | |
302 | uintptr_t retaddr) | |
303 | { | |
5c94dd38 PC |
304 | env->fpscr |= FP_VXCVI; |
305 | env->fpscr &= ~(FP_FR | FP_FI); | |
13c9115f RH |
306 | if (fpscr_ve == 0) { |
307 | if (set_fpcc) { | |
5c94dd38 PC |
308 | env->fpscr &= ~FP_FPCC; |
309 | env->fpscr |= (FP_C | FP_FU); | |
bd23cd45 BS |
310 | } |
311 | } | |
13c9115f | 312 | finish_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, retaddr); |
bd23cd45 BS |
313 | } |
314 | ||
44f35bd1 | 315 | static inline void float_zero_divide_excp(CPUPPCState *env, uintptr_t raddr) |
bd23cd45 | 316 | { |
5c94dd38 PC |
317 | env->fpscr |= FP_ZX; |
318 | env->fpscr &= ~(FP_FR | FP_FI); | |
bd23cd45 | 319 | /* Update the floating-point exception summary */ |
76247892 | 320 | env->fpscr |= FP_FX; |
bd23cd45 BS |
321 | if (fpscr_ze != 0) { |
322 | /* Update the floating-point enabled exception summary */ | |
5c94dd38 | 323 | env->fpscr |= FP_FEX; |
e82c42b7 | 324 | if (fp_exceptions_enabled(env)) { |
44f35bd1 BH |
325 | raise_exception_err_ra(env, POWERPC_EXCP_PROGRAM, |
326 | POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX, | |
327 | raddr); | |
bd23cd45 BS |
328 | } |
329 | } | |
330 | } | |
331 | ||
8e703949 | 332 | static inline void float_overflow_excp(CPUPPCState *env) |
bd23cd45 | 333 | { |
db70b311 | 334 | CPUState *cs = env_cpu(env); |
27103424 | 335 | |
5c94dd38 | 336 | env->fpscr |= FP_OX; |
bd23cd45 | 337 | /* Update the floating-point exception summary */ |
76247892 | 338 | env->fpscr |= FP_FX; |
bd23cd45 BS |
339 | if (fpscr_oe != 0) { |
340 | /* XXX: should adjust the result */ | |
341 | /* Update the floating-point enabled exception summary */ | |
5c94dd38 | 342 | env->fpscr |= FP_FEX; |
bd23cd45 | 343 | /* We must update the target FPR before raising the exception */ |
27103424 | 344 | cs->exception_index = POWERPC_EXCP_PROGRAM; |
bd23cd45 BS |
345 | env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX; |
346 | } else { | |
5c94dd38 PC |
347 | env->fpscr |= FP_XX; |
348 | env->fpscr |= FP_FI; | |
bd23cd45 BS |
349 | } |
350 | } | |
351 | ||
8e703949 | 352 | static inline void float_underflow_excp(CPUPPCState *env) |
bd23cd45 | 353 | { |
db70b311 | 354 | CPUState *cs = env_cpu(env); |
27103424 | 355 | |
5c94dd38 | 356 | env->fpscr |= FP_UX; |
bd23cd45 | 357 | /* Update the floating-point exception summary */ |
76247892 | 358 | env->fpscr |= FP_FX; |
bd23cd45 BS |
359 | if (fpscr_ue != 0) { |
360 | /* XXX: should adjust the result */ | |
361 | /* Update the floating-point enabled exception summary */ | |
5c94dd38 | 362 | env->fpscr |= FP_FEX; |
bd23cd45 | 363 | /* We must update the target FPR before raising the exception */ |
27103424 | 364 | cs->exception_index = POWERPC_EXCP_PROGRAM; |
bd23cd45 BS |
365 | env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX; |
366 | } | |
367 | } | |
368 | ||
8e703949 | 369 | static inline void float_inexact_excp(CPUPPCState *env) |
bd23cd45 | 370 | { |
db70b311 | 371 | CPUState *cs = env_cpu(env); |
27103424 | 372 | |
5c94dd38 PC |
373 | env->fpscr |= FP_FI; |
374 | env->fpscr |= FP_XX; | |
bd23cd45 | 375 | /* Update the floating-point exception summary */ |
76247892 | 376 | env->fpscr |= FP_FX; |
bd23cd45 BS |
377 | if (fpscr_xe != 0) { |
378 | /* Update the floating-point enabled exception summary */ | |
5c94dd38 | 379 | env->fpscr |= FP_FEX; |
bd23cd45 | 380 | /* We must update the target FPR before raising the exception */ |
27103424 | 381 | cs->exception_index = POWERPC_EXCP_PROGRAM; |
bd23cd45 BS |
382 | env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX; |
383 | } | |
384 | } | |
385 | ||
8e703949 | 386 | void helper_fpscr_clrbit(CPUPPCState *env, uint32_t bit) |
bd23cd45 | 387 | { |
fe43ba97 BL |
388 | uint32_t mask = 1u << bit; |
389 | if (env->fpscr & mask) { | |
390 | ppc_store_fpscr(env, env->fpscr & ~(target_ulong)mask); | |
bd23cd45 BS |
391 | } |
392 | } | |
393 | ||
8e703949 | 394 | void helper_fpscr_setbit(CPUPPCState *env, uint32_t bit) |
bd23cd45 | 395 | { |
fe43ba97 BL |
396 | uint32_t mask = 1u << bit; |
397 | if (!(env->fpscr & mask)) { | |
398 | ppc_store_fpscr(env, env->fpscr | mask); | |
bd23cd45 BS |
399 | } |
400 | } | |
401 | ||
fe43ba97 | 402 | void helper_store_fpscr(CPUPPCState *env, uint64_t val, uint32_t nibbles) |
bd23cd45 | 403 | { |
fe43ba97 | 404 | target_ulong mask = 0; |
bd23cd45 BS |
405 | int i; |
406 | ||
fe43ba97 | 407 | /* TODO: push this extension back to translation time */ |
7d08d856 | 408 | for (i = 0; i < sizeof(target_ulong) * 2; i++) { |
fe43ba97 BL |
409 | if (nibbles & (1 << i)) { |
410 | mask |= (target_ulong) 0xf << (4 * i); | |
bd23cd45 BS |
411 | } |
412 | } | |
fe43ba97 BL |
413 | val = (val & mask) | (env->fpscr & ~mask); |
414 | ppc_store_fpscr(env, val); | |
d6478bc7 FC |
415 | } |
416 | ||
44f35bd1 | 417 | static void do_float_check_status(CPUPPCState *env, uintptr_t raddr) |
bd23cd45 | 418 | { |
db70b311 | 419 | CPUState *cs = env_cpu(env); |
db72c9f2 TG |
420 | int status = get_float_exception_flags(&env->fp_status); |
421 | ||
ae13018d | 422 | if (status & float_flag_overflow) { |
db72c9f2 TG |
423 | float_overflow_excp(env); |
424 | } else if (status & float_flag_underflow) { | |
425 | float_underflow_excp(env); | |
9e430ca3 | 426 | } |
16ce2fff RH |
427 | if (status & float_flag_inexact) { |
428 | float_inexact_excp(env); | |
429 | } else { | |
5c94dd38 | 430 | env->fpscr &= ~FP_FI; /* clear the FPSCR[FI] bit */ |
db72c9f2 TG |
431 | } |
432 | ||
27103424 | 433 | if (cs->exception_index == POWERPC_EXCP_PROGRAM && |
bd23cd45 | 434 | (env->error_code & POWERPC_EXCP_FP)) { |
92eeb004 | 435 | /* Deferred floating-point exception after target FPR update */ |
e82c42b7 | 436 | if (fp_exceptions_enabled(env)) { |
44f35bd1 BH |
437 | raise_exception_err_ra(env, cs->exception_index, |
438 | env->error_code, raddr); | |
bd23cd45 | 439 | } |
bd23cd45 BS |
440 | } |
441 | } | |
442 | ||
44f35bd1 BH |
443 | void helper_float_check_status(CPUPPCState *env) |
444 | { | |
445 | do_float_check_status(env, GETPC()); | |
446 | } | |
447 | ||
8e703949 | 448 | void helper_reset_fpstatus(CPUPPCState *env) |
bd23cd45 BS |
449 | { |
450 | set_float_exception_flags(0, &env->fp_status); | |
451 | } | |
452 | ||
57483867 RH |
453 | static void float_invalid_op_addsub(CPUPPCState *env, bool set_fpcc, |
454 | uintptr_t retaddr, int classes) | |
455 | { | |
456 | if ((classes & ~is_neg) == is_inf) { | |
457 | /* Magnitude subtraction of infinities */ | |
458 | float_invalid_op_vxisi(env, set_fpcc, retaddr); | |
459 | } else if (classes & is_snan) { | |
460 | float_invalid_op_vxsnan(env, retaddr); | |
461 | } | |
462 | } | |
463 | ||
bd23cd45 | 464 | /* fadd - fadd. */ |
ac43cec3 | 465 | float64 helper_fadd(CPUPPCState *env, float64 arg1, float64 arg2) |
bd23cd45 | 466 | { |
ac43cec3 RH |
467 | float64 ret = float64_add(arg1, arg2, &env->fp_status); |
468 | int status = get_float_exception_flags(&env->fp_status); | |
bd23cd45 | 469 | |
ac43cec3 | 470 | if (unlikely(status & float_flag_invalid)) { |
57483867 RH |
471 | float_invalid_op_addsub(env, 1, GETPC(), |
472 | float64_classify(arg1) | | |
473 | float64_classify(arg2)); | |
bd23cd45 BS |
474 | } |
475 | ||
ac43cec3 | 476 | return ret; |
bd23cd45 BS |
477 | } |
478 | ||
479 | /* fsub - fsub. */ | |
ac43cec3 | 480 | float64 helper_fsub(CPUPPCState *env, float64 arg1, float64 arg2) |
bd23cd45 | 481 | { |
ac43cec3 RH |
482 | float64 ret = float64_sub(arg1, arg2, &env->fp_status); |
483 | int status = get_float_exception_flags(&env->fp_status); | |
bd23cd45 | 484 | |
ac43cec3 | 485 | if (unlikely(status & float_flag_invalid)) { |
57483867 RH |
486 | float_invalid_op_addsub(env, 1, GETPC(), |
487 | float64_classify(arg1) | | |
488 | float64_classify(arg2)); | |
bd23cd45 BS |
489 | } |
490 | ||
ac43cec3 | 491 | return ret; |
bd23cd45 BS |
492 | } |
493 | ||
4f0da706 RH |
494 | static void float_invalid_op_mul(CPUPPCState *env, bool set_fprc, |
495 | uintptr_t retaddr, int classes) | |
496 | { | |
497 | if ((classes & (is_zero | is_inf)) == (is_zero | is_inf)) { | |
498 | /* Multiplication of zero by infinity */ | |
499 | float_invalid_op_vximz(env, set_fprc, retaddr); | |
500 | } else if (classes & is_snan) { | |
501 | float_invalid_op_vxsnan(env, retaddr); | |
502 | } | |
503 | } | |
504 | ||
bd23cd45 | 505 | /* fmul - fmul. */ |
79f91633 | 506 | float64 helper_fmul(CPUPPCState *env, float64 arg1, float64 arg2) |
bd23cd45 | 507 | { |
79f91633 RH |
508 | float64 ret = float64_mul(arg1, arg2, &env->fp_status); |
509 | int status = get_float_exception_flags(&env->fp_status); | |
bd23cd45 | 510 | |
79f91633 | 511 | if (unlikely(status & float_flag_invalid)) { |
4f0da706 RH |
512 | float_invalid_op_mul(env, 1, GETPC(), |
513 | float64_classify(arg1) | | |
514 | float64_classify(arg2)); | |
bd23cd45 BS |
515 | } |
516 | ||
79f91633 | 517 | return ret; |
bd23cd45 BS |
518 | } |
519 | ||
fec59ef3 RH |
520 | static void float_invalid_op_div(CPUPPCState *env, bool set_fprc, |
521 | uintptr_t retaddr, int classes) | |
522 | { | |
523 | classes &= ~is_neg; | |
524 | if (classes == is_inf) { | |
525 | /* Division of infinity by infinity */ | |
526 | float_invalid_op_vxidi(env, set_fprc, retaddr); | |
527 | } else if (classes == is_zero) { | |
528 | /* Division of zero by zero */ | |
529 | float_invalid_op_vxzdz(env, set_fprc, retaddr); | |
530 | } else if (classes & is_snan) { | |
531 | float_invalid_op_vxsnan(env, retaddr); | |
532 | } | |
533 | } | |
534 | ||
bd23cd45 | 535 | /* fdiv - fdiv. */ |
ae13018d | 536 | float64 helper_fdiv(CPUPPCState *env, float64 arg1, float64 arg2) |
bd23cd45 | 537 | { |
ae13018d RH |
538 | float64 ret = float64_div(arg1, arg2, &env->fp_status); |
539 | int status = get_float_exception_flags(&env->fp_status); | |
bd23cd45 | 540 | |
ae13018d RH |
541 | if (unlikely(status)) { |
542 | if (status & float_flag_invalid) { | |
fec59ef3 RH |
543 | float_invalid_op_div(env, 1, GETPC(), |
544 | float64_classify(arg1) | | |
545 | float64_classify(arg2)); | |
ae13018d RH |
546 | } |
547 | if (status & float_flag_divbyzero) { | |
548 | float_zero_divide_excp(env, GETPC()); | |
bd23cd45 | 549 | } |
bd23cd45 BS |
550 | } |
551 | ||
ae13018d | 552 | return ret; |
bd23cd45 BS |
553 | } |
554 | ||
a3dec427 RH |
555 | static void float_invalid_cvt(CPUPPCState *env, bool set_fprc, |
556 | uintptr_t retaddr, int class1) | |
557 | { | |
558 | float_invalid_op_vxcvi(env, set_fprc, retaddr); | |
559 | if (class1 & is_snan) { | |
560 | float_invalid_op_vxsnan(env, retaddr); | |
561 | } | |
562 | } | |
bd23cd45 | 563 | |
fab7fe42 | 564 | #define FPU_FCTI(op, cvt, nanval) \ |
a3dec427 | 565 | uint64_t helper_##op(CPUPPCState *env, float64 arg) \ |
fab7fe42 | 566 | { \ |
a3dec427 RH |
567 | uint64_t ret = float64_to_##cvt(arg, &env->fp_status); \ |
568 | int status = get_float_exception_flags(&env->fp_status); \ | |
fab7fe42 | 569 | \ |
a3dec427 RH |
570 | if (unlikely(status)) { \ |
571 | if (status & float_flag_invalid) { \ | |
572 | float_invalid_cvt(env, 1, GETPC(), float64_classify(arg)); \ | |
573 | ret = nanval; \ | |
fab7fe42 | 574 | } \ |
6525aadc | 575 | do_float_check_status(env, GETPC()); \ |
fab7fe42 | 576 | } \ |
a3dec427 RH |
577 | return ret; \ |
578 | } | |
fab7fe42 | 579 | |
7dff9abe TM |
580 | FPU_FCTI(fctiw, int32, 0x80000000U) |
581 | FPU_FCTI(fctiwz, int32_round_to_zero, 0x80000000U) | |
582 | FPU_FCTI(fctiwu, uint32, 0x00000000U) | |
583 | FPU_FCTI(fctiwuz, uint32_round_to_zero, 0x00000000U) | |
7dff9abe TM |
584 | FPU_FCTI(fctid, int64, 0x8000000000000000ULL) |
585 | FPU_FCTI(fctidz, int64_round_to_zero, 0x8000000000000000ULL) | |
586 | FPU_FCTI(fctidu, uint64, 0x0000000000000000ULL) | |
587 | FPU_FCTI(fctiduz, uint64_round_to_zero, 0x0000000000000000ULL) | |
bd23cd45 | 588 | |
28288b48 TM |
589 | #define FPU_FCFI(op, cvtr, is_single) \ |
590 | uint64_t helper_##op(CPUPPCState *env, uint64_t arg) \ | |
591 | { \ | |
592 | CPU_DoubleU farg; \ | |
593 | \ | |
594 | if (is_single) { \ | |
595 | float32 tmp = cvtr(arg, &env->fp_status); \ | |
596 | farg.d = float32_to_float64(tmp, &env->fp_status); \ | |
597 | } else { \ | |
598 | farg.d = cvtr(arg, &env->fp_status); \ | |
599 | } \ | |
6525aadc | 600 | do_float_check_status(env, GETPC()); \ |
28288b48 | 601 | return farg.ll; \ |
bd23cd45 BS |
602 | } |
603 | ||
28288b48 TM |
604 | FPU_FCFI(fcfid, int64_to_float64, 0) |
605 | FPU_FCFI(fcfids, int64_to_float32, 1) | |
606 | FPU_FCFI(fcfidu, uint64_to_float64, 0) | |
607 | FPU_FCFI(fcfidus, uint64_to_float32, 1) | |
bd23cd45 | 608 | |
8e703949 BS |
609 | static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg, |
610 | int rounding_mode) | |
bd23cd45 BS |
611 | { |
612 | CPU_DoubleU farg; | |
63d06e90 | 613 | FloatRoundMode old_rounding_mode = get_float_rounding_mode(&env->fp_status); |
bd23cd45 BS |
614 | |
615 | farg.ll = arg; | |
616 | ||
af39bc8c | 617 | if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) { |
bd23cd45 | 618 | /* sNaN round */ |
13c9115f | 619 | float_invalid_op_vxsnan(env, GETPC()); |
7dff9abe | 620 | farg.ll = arg | 0x0008000000000000ULL; |
bd23cd45 | 621 | } else { |
c7386080 TM |
622 | int inexact = get_float_exception_flags(&env->fp_status) & |
623 | float_flag_inexact; | |
bd23cd45 BS |
624 | set_float_rounding_mode(rounding_mode, &env->fp_status); |
625 | farg.ll = float64_round_to_int(farg.d, &env->fp_status); | |
63d06e90 | 626 | set_float_rounding_mode(old_rounding_mode, &env->fp_status); |
c7386080 TM |
627 | |
628 | /* fri* does not set FPSCR[XX] */ | |
629 | if (!inexact) { | |
630 | env->fp_status.float_exception_flags &= ~float_flag_inexact; | |
631 | } | |
bd23cd45 | 632 | } |
6525aadc | 633 | do_float_check_status(env, GETPC()); |
bd23cd45 BS |
634 | return farg.ll; |
635 | } | |
636 | ||
8e703949 | 637 | uint64_t helper_frin(CPUPPCState *env, uint64_t arg) |
bd23cd45 | 638 | { |
c7386080 | 639 | return do_fri(env, arg, float_round_ties_away); |
bd23cd45 BS |
640 | } |
641 | ||
8e703949 | 642 | uint64_t helper_friz(CPUPPCState *env, uint64_t arg) |
bd23cd45 | 643 | { |
8e703949 | 644 | return do_fri(env, arg, float_round_to_zero); |
bd23cd45 BS |
645 | } |
646 | ||
8e703949 | 647 | uint64_t helper_frip(CPUPPCState *env, uint64_t arg) |
bd23cd45 | 648 | { |
8e703949 | 649 | return do_fri(env, arg, float_round_up); |
bd23cd45 BS |
650 | } |
651 | ||
8e703949 | 652 | uint64_t helper_frim(CPUPPCState *env, uint64_t arg) |
bd23cd45 | 653 | { |
8e703949 | 654 | return do_fri(env, arg, float_round_down); |
bd23cd45 BS |
655 | } |
656 | ||
3e5b26cf ND |
657 | #define FPU_MADDSUB_UPDATE(NAME, TP) \ |
658 | static void NAME(CPUPPCState *env, TP arg1, TP arg2, TP arg3, \ | |
13c9115f | 659 | unsigned int madd_flags, uintptr_t retaddr) \ |
3e5b26cf ND |
660 | { \ |
661 | if (TP##_is_signaling_nan(arg1, &env->fp_status) || \ | |
662 | TP##_is_signaling_nan(arg2, &env->fp_status) || \ | |
663 | TP##_is_signaling_nan(arg3, &env->fp_status)) { \ | |
664 | /* sNaN operation */ \ | |
13c9115f | 665 | float_invalid_op_vxsnan(env, retaddr); \ |
3e5b26cf ND |
666 | } \ |
667 | if ((TP##_is_infinity(arg1) && TP##_is_zero(arg2)) || \ | |
668 | (TP##_is_zero(arg1) && TP##_is_infinity(arg2))) { \ | |
669 | /* Multiplication of zero by infinity */ \ | |
13c9115f | 670 | float_invalid_op_vximz(env, 1, retaddr); \ |
3e5b26cf ND |
671 | } \ |
672 | if ((TP##_is_infinity(arg1) || TP##_is_infinity(arg2)) && \ | |
673 | TP##_is_infinity(arg3)) { \ | |
674 | uint8_t aSign, bSign, cSign; \ | |
675 | \ | |
676 | aSign = TP##_is_neg(arg1); \ | |
677 | bSign = TP##_is_neg(arg2); \ | |
678 | cSign = TP##_is_neg(arg3); \ | |
679 | if (madd_flags & float_muladd_negate_c) { \ | |
680 | cSign ^= 1; \ | |
681 | } \ | |
682 | if (aSign ^ bSign ^ cSign) { \ | |
13c9115f | 683 | float_invalid_op_vxisi(env, 1, retaddr); \ |
3e5b26cf ND |
684 | } \ |
685 | } \ | |
bd23cd45 | 686 | } |
182fe2cf | 687 | FPU_MADDSUB_UPDATE(float32_maddsub_update_excp, float32) |
3e5b26cf | 688 | FPU_MADDSUB_UPDATE(float64_maddsub_update_excp, float64) |
bd23cd45 | 689 | |
992d7e97 ND |
690 | #define FPU_FMADD(op, madd_flags) \ |
691 | uint64_t helper_##op(CPUPPCState *env, uint64_t arg1, \ | |
692 | uint64_t arg2, uint64_t arg3) \ | |
693 | { \ | |
694 | uint32_t flags; \ | |
695 | float64 ret = float64_muladd(arg1, arg2, arg3, madd_flags, \ | |
696 | &env->fp_status); \ | |
697 | flags = get_float_exception_flags(&env->fp_status); \ | |
698 | if (flags) { \ | |
699 | if (flags & float_flag_invalid) { \ | |
700 | float64_maddsub_update_excp(env, arg1, arg2, arg3, \ | |
13c9115f | 701 | madd_flags, GETPC()); \ |
992d7e97 | 702 | } \ |
6525aadc | 703 | do_float_check_status(env, GETPC()); \ |
992d7e97 ND |
704 | } \ |
705 | return ret; \ | |
bd23cd45 BS |
706 | } |
707 | ||
992d7e97 ND |
708 | #define MADD_FLGS 0 |
709 | #define MSUB_FLGS float_muladd_negate_c | |
710 | #define NMADD_FLGS float_muladd_negate_result | |
711 | #define NMSUB_FLGS (float_muladd_negate_c | float_muladd_negate_result) | |
bd23cd45 | 712 | |
992d7e97 ND |
713 | FPU_FMADD(fmadd, MADD_FLGS) |
714 | FPU_FMADD(fnmadd, NMADD_FLGS) | |
715 | FPU_FMADD(fmsub, MSUB_FLGS) | |
716 | FPU_FMADD(fnmsub, NMSUB_FLGS) | |
bd23cd45 BS |
717 | |
718 | /* frsp - frsp. */ | |
8e703949 | 719 | uint64_t helper_frsp(CPUPPCState *env, uint64_t arg) |
bd23cd45 BS |
720 | { |
721 | CPU_DoubleU farg; | |
722 | float32 f32; | |
723 | ||
724 | farg.ll = arg; | |
725 | ||
af39bc8c | 726 | if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) { |
13c9115f | 727 | float_invalid_op_vxsnan(env, GETPC()); |
bd23cd45 BS |
728 | } |
729 | f32 = float64_to_float32(farg.d, &env->fp_status); | |
730 | farg.d = float32_to_float64(f32, &env->fp_status); | |
731 | ||
732 | return farg.ll; | |
733 | } | |
734 | ||
735 | /* fsqrt - fsqrt. */ | |
49ab52ef | 736 | float64 helper_fsqrt(CPUPPCState *env, float64 arg) |
bd23cd45 | 737 | { |
49ab52ef RH |
738 | float64 ret = float64_sqrt(arg, &env->fp_status); |
739 | int status = get_float_exception_flags(&env->fp_status); | |
bd23cd45 | 740 | |
49ab52ef RH |
741 | if (unlikely(status & float_flag_invalid)) { |
742 | if (unlikely(float64_is_any_nan(arg))) { | |
743 | if (unlikely(float64_is_signaling_nan(arg, &env->fp_status))) { | |
744 | /* sNaN square root */ | |
13c9115f | 745 | float_invalid_op_vxsnan(env, GETPC()); |
49ab52ef RH |
746 | } |
747 | } else { | |
748 | /* Square root of a negative nonzero number */ | |
13c9115f | 749 | float_invalid_op_vxsqrt(env, 1, GETPC()); |
bd23cd45 | 750 | } |
bd23cd45 | 751 | } |
49ab52ef RH |
752 | |
753 | return ret; | |
bd23cd45 BS |
754 | } |
755 | ||
756 | /* fre - fre. */ | |
38434717 | 757 | float64 helper_fre(CPUPPCState *env, float64 arg) |
bd23cd45 | 758 | { |
38434717 RH |
759 | /* "Estimate" the reciprocal with actual division. */ |
760 | float64 ret = float64_div(float64_one, arg, &env->fp_status); | |
761 | int status = get_float_exception_flags(&env->fp_status); | |
bd23cd45 | 762 | |
38434717 RH |
763 | if (unlikely(status)) { |
764 | if (status & float_flag_invalid) { | |
765 | if (float64_is_signaling_nan(arg, &env->fp_status)) { | |
766 | /* sNaN reciprocal */ | |
13c9115f | 767 | float_invalid_op_vxsnan(env, GETPC()); |
38434717 RH |
768 | } |
769 | } | |
770 | if (status & float_flag_divbyzero) { | |
771 | float_zero_divide_excp(env, GETPC()); | |
772 | /* For FPSCR.ZE == 0, the result is 1/2. */ | |
773 | ret = float64_set_sign(float64_half, float64_is_neg(arg)); | |
774 | } | |
bd23cd45 | 775 | } |
38434717 RH |
776 | |
777 | return ret; | |
bd23cd45 BS |
778 | } |
779 | ||
780 | /* fres - fres. */ | |
8e703949 | 781 | uint64_t helper_fres(CPUPPCState *env, uint64_t arg) |
bd23cd45 BS |
782 | { |
783 | CPU_DoubleU farg; | |
784 | float32 f32; | |
785 | ||
786 | farg.ll = arg; | |
787 | ||
af39bc8c | 788 | if (unlikely(float64_is_signaling_nan(farg.d, &env->fp_status))) { |
bd23cd45 | 789 | /* sNaN reciprocal */ |
13c9115f | 790 | float_invalid_op_vxsnan(env, GETPC()); |
bd23cd45 BS |
791 | } |
792 | farg.d = float64_div(float64_one, farg.d, &env->fp_status); | |
793 | f32 = float64_to_float32(farg.d, &env->fp_status); | |
794 | farg.d = float32_to_float64(f32, &env->fp_status); | |
795 | ||
796 | return farg.ll; | |
797 | } | |
798 | ||
799 | /* frsqrte - frsqrte. */ | |
38434717 | 800 | float64 helper_frsqrte(CPUPPCState *env, float64 arg) |
bd23cd45 | 801 | { |
38434717 RH |
802 | /* "Estimate" the reciprocal with actual division. */ |
803 | float64 rets = float64_sqrt(arg, &env->fp_status); | |
804 | float64 retd = float64_div(float64_one, rets, &env->fp_status); | |
805 | int status = get_float_exception_flags(&env->fp_status); | |
bd23cd45 | 806 | |
38434717 RH |
807 | if (unlikely(status)) { |
808 | if (status & float_flag_invalid) { | |
809 | if (float64_is_signaling_nan(arg, &env->fp_status)) { | |
810 | /* sNaN reciprocal */ | |
13c9115f | 811 | float_invalid_op_vxsnan(env, GETPC()); |
38434717 RH |
812 | } else { |
813 | /* Square root of a negative nonzero number */ | |
13c9115f | 814 | float_invalid_op_vxsqrt(env, 1, GETPC()); |
38434717 RH |
815 | } |
816 | } | |
817 | if (status & float_flag_divbyzero) { | |
818 | /* Reciprocal of (square root of) zero. */ | |
819 | float_zero_divide_excp(env, GETPC()); | |
bd23cd45 | 820 | } |
bd23cd45 | 821 | } |
b748863a | 822 | |
38434717 | 823 | return retd; |
bd23cd45 BS |
824 | } |
825 | ||
826 | /* fsel - fsel. */ | |
8e703949 BS |
827 | uint64_t helper_fsel(CPUPPCState *env, uint64_t arg1, uint64_t arg2, |
828 | uint64_t arg3) | |
bd23cd45 BS |
829 | { |
830 | CPU_DoubleU farg1; | |
831 | ||
832 | farg1.ll = arg1; | |
833 | ||
834 | if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && | |
835 | !float64_is_any_nan(farg1.d)) { | |
836 | return arg2; | |
837 | } else { | |
838 | return arg3; | |
839 | } | |
840 | } | |
841 | ||
da29cb7b TM |
842 | uint32_t helper_ftdiv(uint64_t fra, uint64_t frb) |
843 | { | |
844 | int fe_flag = 0; | |
845 | int fg_flag = 0; | |
846 | ||
847 | if (unlikely(float64_is_infinity(fra) || | |
848 | float64_is_infinity(frb) || | |
849 | float64_is_zero(frb))) { | |
850 | fe_flag = 1; | |
851 | fg_flag = 1; | |
852 | } else { | |
853 | int e_a = ppc_float64_get_unbiased_exp(fra); | |
854 | int e_b = ppc_float64_get_unbiased_exp(frb); | |
855 | ||
856 | if (unlikely(float64_is_any_nan(fra) || | |
857 | float64_is_any_nan(frb))) { | |
858 | fe_flag = 1; | |
859 | } else if ((e_b <= -1022) || (e_b >= 1021)) { | |
860 | fe_flag = 1; | |
861 | } else if (!float64_is_zero(fra) && | |
862 | (((e_a - e_b) >= 1023) || | |
863 | ((e_a - e_b) <= -1021) || | |
864 | (e_a <= -970))) { | |
865 | fe_flag = 1; | |
866 | } | |
867 | ||
868 | if (unlikely(float64_is_zero_or_denormal(frb))) { | |
869 | /* XB is not zero because of the above check and */ | |
870 | /* so must be denormalized. */ | |
871 | fg_flag = 1; | |
872 | } | |
873 | } | |
874 | ||
875 | return 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0); | |
876 | } | |
6d41d146 TM |
877 | |
878 | uint32_t helper_ftsqrt(uint64_t frb) | |
879 | { | |
880 | int fe_flag = 0; | |
881 | int fg_flag = 0; | |
882 | ||
883 | if (unlikely(float64_is_infinity(frb) || float64_is_zero(frb))) { | |
884 | fe_flag = 1; | |
885 | fg_flag = 1; | |
886 | } else { | |
887 | int e_b = ppc_float64_get_unbiased_exp(frb); | |
888 | ||
889 | if (unlikely(float64_is_any_nan(frb))) { | |
890 | fe_flag = 1; | |
891 | } else if (unlikely(float64_is_zero(frb))) { | |
892 | fe_flag = 1; | |
893 | } else if (unlikely(float64_is_neg(frb))) { | |
894 | fe_flag = 1; | |
fa9ebf8c | 895 | } else if (!float64_is_zero(frb) && (e_b <= (-1022 + 52))) { |
6d41d146 TM |
896 | fe_flag = 1; |
897 | } | |
898 | ||
899 | if (unlikely(float64_is_zero_or_denormal(frb))) { | |
900 | /* XB is not zero because of the above check and */ | |
901 | /* therefore must be denormalized. */ | |
902 | fg_flag = 1; | |
903 | } | |
904 | } | |
905 | ||
906 | return 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0); | |
907 | } | |
da29cb7b | 908 | |
8e703949 BS |
909 | void helper_fcmpu(CPUPPCState *env, uint64_t arg1, uint64_t arg2, |
910 | uint32_t crfD) | |
bd23cd45 BS |
911 | { |
912 | CPU_DoubleU farg1, farg2; | |
913 | uint32_t ret = 0; | |
914 | ||
915 | farg1.ll = arg1; | |
916 | farg2.ll = arg2; | |
917 | ||
918 | if (unlikely(float64_is_any_nan(farg1.d) || | |
919 | float64_is_any_nan(farg2.d))) { | |
920 | ret = 0x01UL; | |
921 | } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) { | |
922 | ret = 0x08UL; | |
923 | } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) { | |
924 | ret = 0x04UL; | |
925 | } else { | |
926 | ret = 0x02UL; | |
927 | } | |
928 | ||
5c94dd38 PC |
929 | env->fpscr &= ~FP_FPCC; |
930 | env->fpscr |= ret << FPSCR_FPCC; | |
bd23cd45 BS |
931 | env->crf[crfD] = ret; |
932 | if (unlikely(ret == 0x01UL | |
af39bc8c AM |
933 | && (float64_is_signaling_nan(farg1.d, &env->fp_status) || |
934 | float64_is_signaling_nan(farg2.d, &env->fp_status)))) { | |
bd23cd45 | 935 | /* sNaN comparison */ |
13c9115f | 936 | float_invalid_op_vxsnan(env, GETPC()); |
bd23cd45 BS |
937 | } |
938 | } | |
939 | ||
8e703949 BS |
940 | void helper_fcmpo(CPUPPCState *env, uint64_t arg1, uint64_t arg2, |
941 | uint32_t crfD) | |
bd23cd45 BS |
942 | { |
943 | CPU_DoubleU farg1, farg2; | |
944 | uint32_t ret = 0; | |
945 | ||
946 | farg1.ll = arg1; | |
947 | farg2.ll = arg2; | |
948 | ||
949 | if (unlikely(float64_is_any_nan(farg1.d) || | |
950 | float64_is_any_nan(farg2.d))) { | |
951 | ret = 0x01UL; | |
952 | } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) { | |
953 | ret = 0x08UL; | |
954 | } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) { | |
955 | ret = 0x04UL; | |
956 | } else { | |
957 | ret = 0x02UL; | |
958 | } | |
959 | ||
5c94dd38 PC |
960 | env->fpscr &= ~FP_FPCC; |
961 | env->fpscr |= ret << FPSCR_FPCC; | |
962 | env->crf[crfD] = (uint32_t) ret; | |
bd23cd45 | 963 | if (unlikely(ret == 0x01UL)) { |
13c9115f | 964 | float_invalid_op_vxvc(env, 1, GETPC()); |
af39bc8c AM |
965 | if (float64_is_signaling_nan(farg1.d, &env->fp_status) || |
966 | float64_is_signaling_nan(farg2.d, &env->fp_status)) { | |
bd23cd45 | 967 | /* sNaN comparison */ |
13c9115f | 968 | float_invalid_op_vxsnan(env, GETPC()); |
bd23cd45 BS |
969 | } |
970 | } | |
971 | } | |
972 | ||
973 | /* Single-precision floating-point conversions */ | |
8e703949 | 974 | static inline uint32_t efscfsi(CPUPPCState *env, uint32_t val) |
bd23cd45 BS |
975 | { |
976 | CPU_FloatU u; | |
977 | ||
978 | u.f = int32_to_float32(val, &env->vec_status); | |
979 | ||
980 | return u.l; | |
981 | } | |
982 | ||
8e703949 | 983 | static inline uint32_t efscfui(CPUPPCState *env, uint32_t val) |
bd23cd45 BS |
984 | { |
985 | CPU_FloatU u; | |
986 | ||
987 | u.f = uint32_to_float32(val, &env->vec_status); | |
988 | ||
989 | return u.l; | |
990 | } | |
991 | ||
8e703949 | 992 | static inline int32_t efsctsi(CPUPPCState *env, uint32_t val) |
bd23cd45 BS |
993 | { |
994 | CPU_FloatU u; | |
995 | ||
996 | u.l = val; | |
997 | /* NaN are not treated the same way IEEE 754 does */ | |
af39bc8c | 998 | if (unlikely(float32_is_quiet_nan(u.f, &env->vec_status))) { |
bd23cd45 BS |
999 | return 0; |
1000 | } | |
1001 | ||
1002 | return float32_to_int32(u.f, &env->vec_status); | |
1003 | } | |
1004 | ||
8e703949 | 1005 | static inline uint32_t efsctui(CPUPPCState *env, uint32_t val) |
bd23cd45 BS |
1006 | { |
1007 | CPU_FloatU u; | |
1008 | ||
1009 | u.l = val; | |
1010 | /* NaN are not treated the same way IEEE 754 does */ | |
af39bc8c | 1011 | if (unlikely(float32_is_quiet_nan(u.f, &env->vec_status))) { |
bd23cd45 BS |
1012 | return 0; |
1013 | } | |
1014 | ||
1015 | return float32_to_uint32(u.f, &env->vec_status); | |
1016 | } | |
1017 | ||
8e703949 | 1018 | static inline uint32_t efsctsiz(CPUPPCState *env, uint32_t val) |
bd23cd45 BS |
1019 | { |
1020 | CPU_FloatU u; | |
1021 | ||
1022 | u.l = val; | |
1023 | /* NaN are not treated the same way IEEE 754 does */ | |
af39bc8c | 1024 | if (unlikely(float32_is_quiet_nan(u.f, &env->vec_status))) { |
bd23cd45 BS |
1025 | return 0; |
1026 | } | |
1027 | ||
1028 | return float32_to_int32_round_to_zero(u.f, &env->vec_status); | |
1029 | } | |
1030 | ||
8e703949 | 1031 | static inline uint32_t efsctuiz(CPUPPCState *env, uint32_t val) |
bd23cd45 BS |
1032 | { |
1033 | CPU_FloatU u; | |
1034 | ||
1035 | u.l = val; | |
1036 | /* NaN are not treated the same way IEEE 754 does */ | |
af39bc8c | 1037 | if (unlikely(float32_is_quiet_nan(u.f, &env->vec_status))) { |
bd23cd45 BS |
1038 | return 0; |
1039 | } | |
1040 | ||
1041 | return float32_to_uint32_round_to_zero(u.f, &env->vec_status); | |
1042 | } | |
1043 | ||
8e703949 | 1044 | static inline uint32_t efscfsf(CPUPPCState *env, uint32_t val) |
bd23cd45 BS |
1045 | { |
1046 | CPU_FloatU u; | |
1047 | float32 tmp; | |
1048 | ||
1049 | u.f = int32_to_float32(val, &env->vec_status); | |
1050 | tmp = int64_to_float32(1ULL << 32, &env->vec_status); | |
1051 | u.f = float32_div(u.f, tmp, &env->vec_status); | |
1052 | ||
1053 | return u.l; | |
1054 | } | |
1055 | ||
8e703949 | 1056 | static inline uint32_t efscfuf(CPUPPCState *env, uint32_t val) |
bd23cd45 BS |
1057 | { |
1058 | CPU_FloatU u; | |
1059 | float32 tmp; | |
1060 | ||
1061 | u.f = uint32_to_float32(val, &env->vec_status); | |
1062 | tmp = uint64_to_float32(1ULL << 32, &env->vec_status); | |
1063 | u.f = float32_div(u.f, tmp, &env->vec_status); | |
1064 | ||
1065 | return u.l; | |
1066 | } | |
1067 | ||
8e703949 | 1068 | static inline uint32_t efsctsf(CPUPPCState *env, uint32_t val) |
bd23cd45 BS |
1069 | { |
1070 | CPU_FloatU u; | |
1071 | float32 tmp; | |
1072 | ||
1073 | u.l = val; | |
1074 | /* NaN are not treated the same way IEEE 754 does */ | |
af39bc8c | 1075 | if (unlikely(float32_is_quiet_nan(u.f, &env->vec_status))) { |
bd23cd45 BS |
1076 | return 0; |
1077 | } | |
1078 | tmp = uint64_to_float32(1ULL << 32, &env->vec_status); | |
1079 | u.f = float32_mul(u.f, tmp, &env->vec_status); | |
1080 | ||
1081 | return float32_to_int32(u.f, &env->vec_status); | |
1082 | } | |
1083 | ||
8e703949 | 1084 | static inline uint32_t efsctuf(CPUPPCState *env, uint32_t val) |
bd23cd45 BS |
1085 | { |
1086 | CPU_FloatU u; | |
1087 | float32 tmp; | |
1088 | ||
1089 | u.l = val; | |
1090 | /* NaN are not treated the same way IEEE 754 does */ | |
af39bc8c | 1091 | if (unlikely(float32_is_quiet_nan(u.f, &env->vec_status))) { |
bd23cd45 BS |
1092 | return 0; |
1093 | } | |
1094 | tmp = uint64_to_float32(1ULL << 32, &env->vec_status); | |
1095 | u.f = float32_mul(u.f, tmp, &env->vec_status); | |
1096 | ||
1097 | return float32_to_uint32(u.f, &env->vec_status); | |
1098 | } | |
1099 | ||
8e703949 BS |
1100 | #define HELPER_SPE_SINGLE_CONV(name) \ |
1101 | uint32_t helper_e##name(CPUPPCState *env, uint32_t val) \ | |
1102 | { \ | |
1103 | return e##name(env, val); \ | |
bd23cd45 BS |
1104 | } |
1105 | /* efscfsi */ | |
1106 | HELPER_SPE_SINGLE_CONV(fscfsi); | |
1107 | /* efscfui */ | |
1108 | HELPER_SPE_SINGLE_CONV(fscfui); | |
1109 | /* efscfuf */ | |
1110 | HELPER_SPE_SINGLE_CONV(fscfuf); | |
1111 | /* efscfsf */ | |
1112 | HELPER_SPE_SINGLE_CONV(fscfsf); | |
1113 | /* efsctsi */ | |
1114 | HELPER_SPE_SINGLE_CONV(fsctsi); | |
1115 | /* efsctui */ | |
1116 | HELPER_SPE_SINGLE_CONV(fsctui); | |
1117 | /* efsctsiz */ | |
1118 | HELPER_SPE_SINGLE_CONV(fsctsiz); | |
1119 | /* efsctuiz */ | |
1120 | HELPER_SPE_SINGLE_CONV(fsctuiz); | |
1121 | /* efsctsf */ | |
1122 | HELPER_SPE_SINGLE_CONV(fsctsf); | |
1123 | /* efsctuf */ | |
1124 | HELPER_SPE_SINGLE_CONV(fsctuf); | |
1125 | ||
8e703949 BS |
1126 | #define HELPER_SPE_VECTOR_CONV(name) \ |
1127 | uint64_t helper_ev##name(CPUPPCState *env, uint64_t val) \ | |
1128 | { \ | |
1129 | return ((uint64_t)e##name(env, val >> 32) << 32) | \ | |
1130 | (uint64_t)e##name(env, val); \ | |
bd23cd45 BS |
1131 | } |
1132 | /* evfscfsi */ | |
1133 | HELPER_SPE_VECTOR_CONV(fscfsi); | |
1134 | /* evfscfui */ | |
1135 | HELPER_SPE_VECTOR_CONV(fscfui); | |
1136 | /* evfscfuf */ | |
1137 | HELPER_SPE_VECTOR_CONV(fscfuf); | |
1138 | /* evfscfsf */ | |
1139 | HELPER_SPE_VECTOR_CONV(fscfsf); | |
1140 | /* evfsctsi */ | |
1141 | HELPER_SPE_VECTOR_CONV(fsctsi); | |
1142 | /* evfsctui */ | |
1143 | HELPER_SPE_VECTOR_CONV(fsctui); | |
1144 | /* evfsctsiz */ | |
1145 | HELPER_SPE_VECTOR_CONV(fsctsiz); | |
1146 | /* evfsctuiz */ | |
1147 | HELPER_SPE_VECTOR_CONV(fsctuiz); | |
1148 | /* evfsctsf */ | |
1149 | HELPER_SPE_VECTOR_CONV(fsctsf); | |
1150 | /* evfsctuf */ | |
1151 | HELPER_SPE_VECTOR_CONV(fsctuf); | |
1152 | ||
1153 | /* Single-precision floating-point arithmetic */ | |
8e703949 | 1154 | static inline uint32_t efsadd(CPUPPCState *env, uint32_t op1, uint32_t op2) |
bd23cd45 BS |
1155 | { |
1156 | CPU_FloatU u1, u2; | |
1157 | ||
1158 | u1.l = op1; | |
1159 | u2.l = op2; | |
1160 | u1.f = float32_add(u1.f, u2.f, &env->vec_status); | |
1161 | return u1.l; | |
1162 | } | |
1163 | ||
8e703949 | 1164 | static inline uint32_t efssub(CPUPPCState *env, uint32_t op1, uint32_t op2) |
bd23cd45 BS |
1165 | { |
1166 | CPU_FloatU u1, u2; | |
1167 | ||
1168 | u1.l = op1; | |
1169 | u2.l = op2; | |
1170 | u1.f = float32_sub(u1.f, u2.f, &env->vec_status); | |
1171 | return u1.l; | |
1172 | } | |
1173 | ||
8e703949 | 1174 | static inline uint32_t efsmul(CPUPPCState *env, uint32_t op1, uint32_t op2) |
bd23cd45 BS |
1175 | { |
1176 | CPU_FloatU u1, u2; | |
1177 | ||
1178 | u1.l = op1; | |
1179 | u2.l = op2; | |
1180 | u1.f = float32_mul(u1.f, u2.f, &env->vec_status); | |
1181 | return u1.l; | |
1182 | } | |
1183 | ||
8e703949 | 1184 | static inline uint32_t efsdiv(CPUPPCState *env, uint32_t op1, uint32_t op2) |
bd23cd45 BS |
1185 | { |
1186 | CPU_FloatU u1, u2; | |
1187 | ||
1188 | u1.l = op1; | |
1189 | u2.l = op2; | |
1190 | u1.f = float32_div(u1.f, u2.f, &env->vec_status); | |
1191 | return u1.l; | |
1192 | } | |
1193 | ||
8e703949 BS |
1194 | #define HELPER_SPE_SINGLE_ARITH(name) \ |
1195 | uint32_t helper_e##name(CPUPPCState *env, uint32_t op1, uint32_t op2) \ | |
1196 | { \ | |
1197 | return e##name(env, op1, op2); \ | |
bd23cd45 BS |
1198 | } |
1199 | /* efsadd */ | |
1200 | HELPER_SPE_SINGLE_ARITH(fsadd); | |
1201 | /* efssub */ | |
1202 | HELPER_SPE_SINGLE_ARITH(fssub); | |
1203 | /* efsmul */ | |
1204 | HELPER_SPE_SINGLE_ARITH(fsmul); | |
1205 | /* efsdiv */ | |
1206 | HELPER_SPE_SINGLE_ARITH(fsdiv); | |
1207 | ||
1208 | #define HELPER_SPE_VECTOR_ARITH(name) \ | |
8e703949 | 1209 | uint64_t helper_ev##name(CPUPPCState *env, uint64_t op1, uint64_t op2) \ |
bd23cd45 | 1210 | { \ |
8e703949 BS |
1211 | return ((uint64_t)e##name(env, op1 >> 32, op2 >> 32) << 32) | \ |
1212 | (uint64_t)e##name(env, op1, op2); \ | |
bd23cd45 BS |
1213 | } |
1214 | /* evfsadd */ | |
1215 | HELPER_SPE_VECTOR_ARITH(fsadd); | |
1216 | /* evfssub */ | |
1217 | HELPER_SPE_VECTOR_ARITH(fssub); | |
1218 | /* evfsmul */ | |
1219 | HELPER_SPE_VECTOR_ARITH(fsmul); | |
1220 | /* evfsdiv */ | |
1221 | HELPER_SPE_VECTOR_ARITH(fsdiv); | |
1222 | ||
1223 | /* Single-precision floating-point comparisons */ | |
8e703949 | 1224 | static inline uint32_t efscmplt(CPUPPCState *env, uint32_t op1, uint32_t op2) |
bd23cd45 BS |
1225 | { |
1226 | CPU_FloatU u1, u2; | |
1227 | ||
1228 | u1.l = op1; | |
1229 | u2.l = op2; | |
1230 | return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0; | |
1231 | } | |
1232 | ||
8e703949 | 1233 | static inline uint32_t efscmpgt(CPUPPCState *env, uint32_t op1, uint32_t op2) |
bd23cd45 BS |
1234 | { |
1235 | CPU_FloatU u1, u2; | |
1236 | ||
1237 | u1.l = op1; | |
1238 | u2.l = op2; | |
1239 | return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4; | |
1240 | } | |
1241 | ||
8e703949 | 1242 | static inline uint32_t efscmpeq(CPUPPCState *env, uint32_t op1, uint32_t op2) |
bd23cd45 BS |
1243 | { |
1244 | CPU_FloatU u1, u2; | |
1245 | ||
1246 | u1.l = op1; | |
1247 | u2.l = op2; | |
1248 | return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0; | |
1249 | } | |
1250 | ||
8e703949 | 1251 | static inline uint32_t efststlt(CPUPPCState *env, uint32_t op1, uint32_t op2) |
bd23cd45 BS |
1252 | { |
1253 | /* XXX: TODO: ignore special values (NaN, infinites, ...) */ | |
8e703949 | 1254 | return efscmplt(env, op1, op2); |
bd23cd45 BS |
1255 | } |
1256 | ||
8e703949 | 1257 | static inline uint32_t efststgt(CPUPPCState *env, uint32_t op1, uint32_t op2) |
bd23cd45 BS |
1258 | { |
1259 | /* XXX: TODO: ignore special values (NaN, infinites, ...) */ | |
8e703949 | 1260 | return efscmpgt(env, op1, op2); |
bd23cd45 BS |
1261 | } |
1262 | ||
8e703949 | 1263 | static inline uint32_t efststeq(CPUPPCState *env, uint32_t op1, uint32_t op2) |
bd23cd45 BS |
1264 | { |
1265 | /* XXX: TODO: ignore special values (NaN, infinites, ...) */ | |
8e703949 | 1266 | return efscmpeq(env, op1, op2); |
bd23cd45 BS |
1267 | } |
1268 | ||
8e703949 BS |
1269 | #define HELPER_SINGLE_SPE_CMP(name) \ |
1270 | uint32_t helper_e##name(CPUPPCState *env, uint32_t op1, uint32_t op2) \ | |
1271 | { \ | |
a575d9ab | 1272 | return e##name(env, op1, op2); \ |
bd23cd45 BS |
1273 | } |
1274 | /* efststlt */ | |
1275 | HELPER_SINGLE_SPE_CMP(fststlt); | |
1276 | /* efststgt */ | |
1277 | HELPER_SINGLE_SPE_CMP(fststgt); | |
1278 | /* efststeq */ | |
1279 | HELPER_SINGLE_SPE_CMP(fststeq); | |
1280 | /* efscmplt */ | |
1281 | HELPER_SINGLE_SPE_CMP(fscmplt); | |
1282 | /* efscmpgt */ | |
1283 | HELPER_SINGLE_SPE_CMP(fscmpgt); | |
1284 | /* efscmpeq */ | |
1285 | HELPER_SINGLE_SPE_CMP(fscmpeq); | |
1286 | ||
1287 | static inline uint32_t evcmp_merge(int t0, int t1) | |
1288 | { | |
1289 | return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1); | |
1290 | } | |
1291 | ||
1292 | #define HELPER_VECTOR_SPE_CMP(name) \ | |
8e703949 | 1293 | uint32_t helper_ev##name(CPUPPCState *env, uint64_t op1, uint64_t op2) \ |
bd23cd45 | 1294 | { \ |
8e703949 BS |
1295 | return evcmp_merge(e##name(env, op1 >> 32, op2 >> 32), \ |
1296 | e##name(env, op1, op2)); \ | |
bd23cd45 BS |
1297 | } |
1298 | /* evfststlt */ | |
1299 | HELPER_VECTOR_SPE_CMP(fststlt); | |
1300 | /* evfststgt */ | |
1301 | HELPER_VECTOR_SPE_CMP(fststgt); | |
1302 | /* evfststeq */ | |
1303 | HELPER_VECTOR_SPE_CMP(fststeq); | |
1304 | /* evfscmplt */ | |
1305 | HELPER_VECTOR_SPE_CMP(fscmplt); | |
1306 | /* evfscmpgt */ | |
1307 | HELPER_VECTOR_SPE_CMP(fscmpgt); | |
1308 | /* evfscmpeq */ | |
1309 | HELPER_VECTOR_SPE_CMP(fscmpeq); | |
1310 | ||
1311 | /* Double-precision floating-point conversion */ | |
8e703949 | 1312 | uint64_t helper_efdcfsi(CPUPPCState *env, uint32_t val) |
bd23cd45 BS |
1313 | { |
1314 | CPU_DoubleU u; | |
1315 | ||
1316 | u.d = int32_to_float64(val, &env->vec_status); | |
1317 | ||
1318 | return u.ll; | |
1319 | } | |
1320 | ||
8e703949 | 1321 | uint64_t helper_efdcfsid(CPUPPCState *env, uint64_t val) |
bd23cd45 BS |
1322 | { |
1323 | CPU_DoubleU u; | |
1324 | ||
1325 | u.d = int64_to_float64(val, &env->vec_status); | |
1326 | ||
1327 | return u.ll; | |
1328 | } | |
1329 | ||
8e703949 | 1330 | uint64_t helper_efdcfui(CPUPPCState *env, uint32_t val) |
bd23cd45 BS |
1331 | { |
1332 | CPU_DoubleU u; | |
1333 | ||
1334 | u.d = uint32_to_float64(val, &env->vec_status); | |
1335 | ||
1336 | return u.ll; | |
1337 | } | |
1338 | ||
8e703949 | 1339 | uint64_t helper_efdcfuid(CPUPPCState *env, uint64_t val) |
bd23cd45 BS |
1340 | { |
1341 | CPU_DoubleU u; | |
1342 | ||
1343 | u.d = uint64_to_float64(val, &env->vec_status); | |
1344 | ||
1345 | return u.ll; | |
1346 | } | |
1347 | ||
8e703949 | 1348 | uint32_t helper_efdctsi(CPUPPCState *env, uint64_t val) |
bd23cd45 BS |
1349 | { |
1350 | CPU_DoubleU u; | |
1351 | ||
1352 | u.ll = val; | |
1353 | /* NaN are not treated the same way IEEE 754 does */ | |
1354 | if (unlikely(float64_is_any_nan(u.d))) { | |
1355 | return 0; | |
1356 | } | |
1357 | ||
1358 | return float64_to_int32(u.d, &env->vec_status); | |
1359 | } | |
1360 | ||
8e703949 | 1361 | uint32_t helper_efdctui(CPUPPCState *env, uint64_t val) |
bd23cd45 BS |
1362 | { |
1363 | CPU_DoubleU u; | |
1364 | ||
1365 | u.ll = val; | |
1366 | /* NaN are not treated the same way IEEE 754 does */ | |
1367 | if (unlikely(float64_is_any_nan(u.d))) { | |
1368 | return 0; | |
1369 | } | |
1370 | ||
1371 | return float64_to_uint32(u.d, &env->vec_status); | |
1372 | } | |
1373 | ||
8e703949 | 1374 | uint32_t helper_efdctsiz(CPUPPCState *env, uint64_t val) |
bd23cd45 BS |
1375 | { |
1376 | CPU_DoubleU u; | |
1377 | ||
1378 | u.ll = val; | |
1379 | /* NaN are not treated the same way IEEE 754 does */ | |
1380 | if (unlikely(float64_is_any_nan(u.d))) { | |
1381 | return 0; | |
1382 | } | |
1383 | ||
1384 | return float64_to_int32_round_to_zero(u.d, &env->vec_status); | |
1385 | } | |
1386 | ||
8e703949 | 1387 | uint64_t helper_efdctsidz(CPUPPCState *env, uint64_t val) |
bd23cd45 BS |
1388 | { |
1389 | CPU_DoubleU u; | |
1390 | ||
1391 | u.ll = val; | |
1392 | /* NaN are not treated the same way IEEE 754 does */ | |
1393 | if (unlikely(float64_is_any_nan(u.d))) { | |
1394 | return 0; | |
1395 | } | |
1396 | ||
1397 | return float64_to_int64_round_to_zero(u.d, &env->vec_status); | |
1398 | } | |
1399 | ||
8e703949 | 1400 | uint32_t helper_efdctuiz(CPUPPCState *env, uint64_t val) |
bd23cd45 BS |
1401 | { |
1402 | CPU_DoubleU u; | |
1403 | ||
1404 | u.ll = val; | |
1405 | /* NaN are not treated the same way IEEE 754 does */ | |
1406 | if (unlikely(float64_is_any_nan(u.d))) { | |
1407 | return 0; | |
1408 | } | |
1409 | ||
1410 | return float64_to_uint32_round_to_zero(u.d, &env->vec_status); | |
1411 | } | |
1412 | ||
8e703949 | 1413 | uint64_t helper_efdctuidz(CPUPPCState *env, uint64_t val) |
bd23cd45 BS |
1414 | { |
1415 | CPU_DoubleU u; | |
1416 | ||
1417 | u.ll = val; | |
1418 | /* NaN are not treated the same way IEEE 754 does */ | |
1419 | if (unlikely(float64_is_any_nan(u.d))) { | |
1420 | return 0; | |
1421 | } | |
1422 | ||
1423 | return float64_to_uint64_round_to_zero(u.d, &env->vec_status); | |
1424 | } | |
1425 | ||
8e703949 | 1426 | uint64_t helper_efdcfsf(CPUPPCState *env, uint32_t val) |
bd23cd45 BS |
1427 | { |
1428 | CPU_DoubleU u; | |
1429 | float64 tmp; | |
1430 | ||
1431 | u.d = int32_to_float64(val, &env->vec_status); | |
1432 | tmp = int64_to_float64(1ULL << 32, &env->vec_status); | |
1433 | u.d = float64_div(u.d, tmp, &env->vec_status); | |
1434 | ||
1435 | return u.ll; | |
1436 | } | |
1437 | ||
8e703949 | 1438 | uint64_t helper_efdcfuf(CPUPPCState *env, uint32_t val) |
bd23cd45 BS |
1439 | { |
1440 | CPU_DoubleU u; | |
1441 | float64 tmp; | |
1442 | ||
1443 | u.d = uint32_to_float64(val, &env->vec_status); | |
1444 | tmp = int64_to_float64(1ULL << 32, &env->vec_status); | |
1445 | u.d = float64_div(u.d, tmp, &env->vec_status); | |
1446 | ||
1447 | return u.ll; | |
1448 | } | |
1449 | ||
8e703949 | 1450 | uint32_t helper_efdctsf(CPUPPCState *env, uint64_t val) |
bd23cd45 BS |
1451 | { |
1452 | CPU_DoubleU u; | |
1453 | float64 tmp; | |
1454 | ||
1455 | u.ll = val; | |
1456 | /* NaN are not treated the same way IEEE 754 does */ | |
1457 | if (unlikely(float64_is_any_nan(u.d))) { | |
1458 | return 0; | |
1459 | } | |
1460 | tmp = uint64_to_float64(1ULL << 32, &env->vec_status); | |
1461 | u.d = float64_mul(u.d, tmp, &env->vec_status); | |
1462 | ||
1463 | return float64_to_int32(u.d, &env->vec_status); | |
1464 | } | |
1465 | ||
8e703949 | 1466 | uint32_t helper_efdctuf(CPUPPCState *env, uint64_t val) |
bd23cd45 BS |
1467 | { |
1468 | CPU_DoubleU u; | |
1469 | float64 tmp; | |
1470 | ||
1471 | u.ll = val; | |
1472 | /* NaN are not treated the same way IEEE 754 does */ | |
1473 | if (unlikely(float64_is_any_nan(u.d))) { | |
1474 | return 0; | |
1475 | } | |
1476 | tmp = uint64_to_float64(1ULL << 32, &env->vec_status); | |
1477 | u.d = float64_mul(u.d, tmp, &env->vec_status); | |
1478 | ||
1479 | return float64_to_uint32(u.d, &env->vec_status); | |
1480 | } | |
1481 | ||
8e703949 | 1482 | uint32_t helper_efscfd(CPUPPCState *env, uint64_t val) |
bd23cd45 BS |
1483 | { |
1484 | CPU_DoubleU u1; | |
1485 | CPU_FloatU u2; | |
1486 | ||
1487 | u1.ll = val; | |
1488 | u2.f = float64_to_float32(u1.d, &env->vec_status); | |
1489 | ||
1490 | return u2.l; | |
1491 | } | |
1492 | ||
8e703949 | 1493 | uint64_t helper_efdcfs(CPUPPCState *env, uint32_t val) |
bd23cd45 BS |
1494 | { |
1495 | CPU_DoubleU u2; | |
1496 | CPU_FloatU u1; | |
1497 | ||
1498 | u1.l = val; | |
1499 | u2.d = float32_to_float64(u1.f, &env->vec_status); | |
1500 | ||
1501 | return u2.ll; | |
1502 | } | |
1503 | ||
1504 | /* Double precision fixed-point arithmetic */ | |
8e703949 | 1505 | uint64_t helper_efdadd(CPUPPCState *env, uint64_t op1, uint64_t op2) |
bd23cd45 BS |
1506 | { |
1507 | CPU_DoubleU u1, u2; | |
1508 | ||
1509 | u1.ll = op1; | |
1510 | u2.ll = op2; | |
1511 | u1.d = float64_add(u1.d, u2.d, &env->vec_status); | |
1512 | return u1.ll; | |
1513 | } | |
1514 | ||
8e703949 | 1515 | uint64_t helper_efdsub(CPUPPCState *env, uint64_t op1, uint64_t op2) |
bd23cd45 BS |
1516 | { |
1517 | CPU_DoubleU u1, u2; | |
1518 | ||
1519 | u1.ll = op1; | |
1520 | u2.ll = op2; | |
1521 | u1.d = float64_sub(u1.d, u2.d, &env->vec_status); | |
1522 | return u1.ll; | |
1523 | } | |
1524 | ||
8e703949 | 1525 | uint64_t helper_efdmul(CPUPPCState *env, uint64_t op1, uint64_t op2) |
bd23cd45 BS |
1526 | { |
1527 | CPU_DoubleU u1, u2; | |
1528 | ||
1529 | u1.ll = op1; | |
1530 | u2.ll = op2; | |
1531 | u1.d = float64_mul(u1.d, u2.d, &env->vec_status); | |
1532 | return u1.ll; | |
1533 | } | |
1534 | ||
8e703949 | 1535 | uint64_t helper_efddiv(CPUPPCState *env, uint64_t op1, uint64_t op2) |
bd23cd45 BS |
1536 | { |
1537 | CPU_DoubleU u1, u2; | |
1538 | ||
1539 | u1.ll = op1; | |
1540 | u2.ll = op2; | |
1541 | u1.d = float64_div(u1.d, u2.d, &env->vec_status); | |
1542 | return u1.ll; | |
1543 | } | |
1544 | ||
1545 | /* Double precision floating point helpers */ | |
8e703949 | 1546 | uint32_t helper_efdtstlt(CPUPPCState *env, uint64_t op1, uint64_t op2) |
bd23cd45 BS |
1547 | { |
1548 | CPU_DoubleU u1, u2; | |
1549 | ||
1550 | u1.ll = op1; | |
1551 | u2.ll = op2; | |
1552 | return float64_lt(u1.d, u2.d, &env->vec_status) ? 4 : 0; | |
1553 | } | |
1554 | ||
8e703949 | 1555 | uint32_t helper_efdtstgt(CPUPPCState *env, uint64_t op1, uint64_t op2) |
bd23cd45 BS |
1556 | { |
1557 | CPU_DoubleU u1, u2; | |
1558 | ||
1559 | u1.ll = op1; | |
1560 | u2.ll = op2; | |
1561 | return float64_le(u1.d, u2.d, &env->vec_status) ? 0 : 4; | |
1562 | } | |
1563 | ||
8e703949 | 1564 | uint32_t helper_efdtsteq(CPUPPCState *env, uint64_t op1, uint64_t op2) |
bd23cd45 BS |
1565 | { |
1566 | CPU_DoubleU u1, u2; | |
1567 | ||
1568 | u1.ll = op1; | |
1569 | u2.ll = op2; | |
1570 | return float64_eq_quiet(u1.d, u2.d, &env->vec_status) ? 4 : 0; | |
1571 | } | |
1572 | ||
8e703949 | 1573 | uint32_t helper_efdcmplt(CPUPPCState *env, uint64_t op1, uint64_t op2) |
bd23cd45 BS |
1574 | { |
1575 | /* XXX: TODO: test special values (NaN, infinites, ...) */ | |
8e703949 | 1576 | return helper_efdtstlt(env, op1, op2); |
bd23cd45 BS |
1577 | } |
1578 | ||
8e703949 | 1579 | uint32_t helper_efdcmpgt(CPUPPCState *env, uint64_t op1, uint64_t op2) |
bd23cd45 BS |
1580 | { |
1581 | /* XXX: TODO: test special values (NaN, infinites, ...) */ | |
8e703949 | 1582 | return helper_efdtstgt(env, op1, op2); |
bd23cd45 BS |
1583 | } |
1584 | ||
8e703949 | 1585 | uint32_t helper_efdcmpeq(CPUPPCState *env, uint64_t op1, uint64_t op2) |
bd23cd45 BS |
1586 | { |
1587 | /* XXX: TODO: test special values (NaN, infinites, ...) */ | |
8e703949 | 1588 | return helper_efdtsteq(env, op1, op2); |
bd23cd45 | 1589 | } |
3c3cbbdc | 1590 | |
3c3cbbdc | 1591 | #define float64_to_float64(x, env) x |
ee6e02c0 TM |
1592 | |
1593 | ||
fa9ebf8c | 1594 | /* |
136fbf65 | 1595 | * VSX_ADD_SUB - VSX floating point add/subtract |
ee6e02c0 TM |
1596 | * name - instruction mnemonic |
1597 | * op - operation (add or sub) | |
1598 | * nels - number of elements (1, 2 or 4) | |
1599 | * tp - type (float32 or float64) | |
bcb7652e | 1600 | * fld - vsr_t field (VsrD(*) or VsrW(*)) |
ee6e02c0 TM |
1601 | * sfprf - set FPRF |
1602 | */ | |
3fd0aadf | 1603 | #define VSX_ADD_SUB(name, op, nels, tp, fld, sfprf, r2sp) \ |
99125c74 MCA |
1604 | void helper_##name(CPUPPCState *env, ppc_vsr_t *xt, \ |
1605 | ppc_vsr_t *xa, ppc_vsr_t *xb) \ | |
ee6e02c0 | 1606 | { \ |
cf3b0334 | 1607 | ppc_vsr_t t = *xt; \ |
ee6e02c0 TM |
1608 | int i; \ |
1609 | \ | |
ee6e02c0 TM |
1610 | helper_reset_fpstatus(env); \ |
1611 | \ | |
1612 | for (i = 0; i < nels; i++) { \ | |
1613 | float_status tstat = env->fp_status; \ | |
1614 | set_float_exception_flags(0, &tstat); \ | |
cf3b0334 | 1615 | t.fld = tp##_##op(xa->fld, xb->fld, &tstat); \ |
ee6e02c0 TM |
1616 | env->fp_status.float_exception_flags |= tstat.float_exception_flags; \ |
1617 | \ | |
1618 | if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ | |
57483867 | 1619 | float_invalid_op_addsub(env, sfprf, GETPC(), \ |
cf3b0334 MCA |
1620 | tp##_classify(xa->fld) | \ |
1621 | tp##_classify(xb->fld)); \ | |
ee6e02c0 TM |
1622 | } \ |
1623 | \ | |
3fd0aadf | 1624 | if (r2sp) { \ |
cf3b0334 | 1625 | t.fld = helper_frsp(env, t.fld); \ |
3fd0aadf TM |
1626 | } \ |
1627 | \ | |
ee6e02c0 | 1628 | if (sfprf) { \ |
cf3b0334 | 1629 | helper_compute_fprf_float64(env, t.fld); \ |
ee6e02c0 TM |
1630 | } \ |
1631 | } \ | |
cf3b0334 | 1632 | *xt = t; \ |
6525aadc | 1633 | do_float_check_status(env, GETPC()); \ |
ee6e02c0 TM |
1634 | } |
1635 | ||
bcb7652e TM |
1636 | VSX_ADD_SUB(xsadddp, add, 1, float64, VsrD(0), 1, 0) |
1637 | VSX_ADD_SUB(xsaddsp, add, 1, float64, VsrD(0), 1, 1) | |
1638 | VSX_ADD_SUB(xvadddp, add, 2, float64, VsrD(i), 0, 0) | |
1639 | VSX_ADD_SUB(xvaddsp, add, 4, float32, VsrW(i), 0, 0) | |
1640 | VSX_ADD_SUB(xssubdp, sub, 1, float64, VsrD(0), 1, 0) | |
1641 | VSX_ADD_SUB(xssubsp, sub, 1, float64, VsrD(0), 1, 1) | |
1642 | VSX_ADD_SUB(xvsubdp, sub, 2, float64, VsrD(i), 0, 0) | |
1643 | VSX_ADD_SUB(xvsubsp, sub, 4, float32, VsrW(i), 0, 0) | |
5e591d88 | 1644 | |
23d0766b MCA |
1645 | void helper_xsaddqp(CPUPPCState *env, uint32_t opcode, |
1646 | ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb) | |
07bdd247 | 1647 | { |
cf3b0334 | 1648 | ppc_vsr_t t = *xt; |
07bdd247 BR |
1649 | float_status tstat; |
1650 | ||
07bdd247 BR |
1651 | helper_reset_fpstatus(env); |
1652 | ||
a8d411ab | 1653 | tstat = env->fp_status; |
07bdd247 | 1654 | if (unlikely(Rc(opcode) != 0)) { |
a8d411ab | 1655 | tstat.float_rounding_mode = float_round_to_odd; |
07bdd247 BR |
1656 | } |
1657 | ||
07bdd247 | 1658 | set_float_exception_flags(0, &tstat); |
cf3b0334 | 1659 | t.f128 = float128_add(xa->f128, xb->f128, &tstat); |
07bdd247 BR |
1660 | env->fp_status.float_exception_flags |= tstat.float_exception_flags; |
1661 | ||
1662 | if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { | |
57483867 | 1663 | float_invalid_op_addsub(env, 1, GETPC(), |
cf3b0334 MCA |
1664 | float128_classify(xa->f128) | |
1665 | float128_classify(xb->f128)); | |
07bdd247 BR |
1666 | } |
1667 | ||
cf3b0334 | 1668 | helper_compute_fprf_float128(env, t.f128); |
07bdd247 | 1669 | |
cf3b0334 | 1670 | *xt = t; |
6525aadc | 1671 | do_float_check_status(env, GETPC()); |
07bdd247 BR |
1672 | } |
1673 | ||
fa9ebf8c DG |
1674 | /* |
1675 | * VSX_MUL - VSX floating point multiply | |
5e591d88 TM |
1676 | * op - instruction mnemonic |
1677 | * nels - number of elements (1, 2 or 4) | |
1678 | * tp - type (float32 or float64) | |
bcb7652e | 1679 | * fld - vsr_t field (VsrD(*) or VsrW(*)) |
5e591d88 TM |
1680 | * sfprf - set FPRF |
1681 | */ | |
ab9408a2 | 1682 | #define VSX_MUL(op, nels, tp, fld, sfprf, r2sp) \ |
99125c74 MCA |
1683 | void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \ |
1684 | ppc_vsr_t *xa, ppc_vsr_t *xb) \ | |
5e591d88 | 1685 | { \ |
cf3b0334 | 1686 | ppc_vsr_t t = *xt; \ |
5e591d88 TM |
1687 | int i; \ |
1688 | \ | |
5e591d88 TM |
1689 | helper_reset_fpstatus(env); \ |
1690 | \ | |
1691 | for (i = 0; i < nels; i++) { \ | |
1692 | float_status tstat = env->fp_status; \ | |
1693 | set_float_exception_flags(0, &tstat); \ | |
cf3b0334 | 1694 | t.fld = tp##_mul(xa->fld, xb->fld, &tstat); \ |
5e591d88 TM |
1695 | env->fp_status.float_exception_flags |= tstat.float_exception_flags; \ |
1696 | \ | |
1697 | if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ | |
4f0da706 | 1698 | float_invalid_op_mul(env, sfprf, GETPC(), \ |
cf3b0334 MCA |
1699 | tp##_classify(xa->fld) | \ |
1700 | tp##_classify(xb->fld)); \ | |
5e591d88 TM |
1701 | } \ |
1702 | \ | |
ab9408a2 | 1703 | if (r2sp) { \ |
cf3b0334 | 1704 | t.fld = helper_frsp(env, t.fld); \ |
ab9408a2 TM |
1705 | } \ |
1706 | \ | |
5e591d88 | 1707 | if (sfprf) { \ |
cf3b0334 | 1708 | helper_compute_fprf_float64(env, t.fld); \ |
5e591d88 TM |
1709 | } \ |
1710 | } \ | |
1711 | \ | |
cf3b0334 | 1712 | *xt = t; \ |
6525aadc | 1713 | do_float_check_status(env, GETPC()); \ |
5e591d88 TM |
1714 | } |
1715 | ||
bcb7652e TM |
1716 | VSX_MUL(xsmuldp, 1, float64, VsrD(0), 1, 0) |
1717 | VSX_MUL(xsmulsp, 1, float64, VsrD(0), 1, 1) | |
1718 | VSX_MUL(xvmuldp, 2, float64, VsrD(i), 0, 0) | |
1719 | VSX_MUL(xvmulsp, 4, float32, VsrW(i), 0, 0) | |
4b98eeef | 1720 | |
23d0766b MCA |
1721 | void helper_xsmulqp(CPUPPCState *env, uint32_t opcode, |
1722 | ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb) | |
a811ec04 | 1723 | { |
cf3b0334 | 1724 | ppc_vsr_t t = *xt; |
a8d411ab | 1725 | float_status tstat; |
a811ec04 | 1726 | |
a8d411ab BR |
1727 | helper_reset_fpstatus(env); |
1728 | tstat = env->fp_status; | |
a811ec04 | 1729 | if (unlikely(Rc(opcode) != 0)) { |
a8d411ab | 1730 | tstat.float_rounding_mode = float_round_to_odd; |
a811ec04 BR |
1731 | } |
1732 | ||
a811ec04 | 1733 | set_float_exception_flags(0, &tstat); |
cf3b0334 | 1734 | t.f128 = float128_mul(xa->f128, xb->f128, &tstat); |
a811ec04 BR |
1735 | env->fp_status.float_exception_flags |= tstat.float_exception_flags; |
1736 | ||
1737 | if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { | |
4f0da706 | 1738 | float_invalid_op_mul(env, 1, GETPC(), |
cf3b0334 MCA |
1739 | float128_classify(xa->f128) | |
1740 | float128_classify(xb->f128)); | |
a811ec04 | 1741 | } |
cf3b0334 | 1742 | helper_compute_fprf_float128(env, t.f128); |
a811ec04 | 1743 | |
cf3b0334 | 1744 | *xt = t; |
6525aadc | 1745 | do_float_check_status(env, GETPC()); |
a811ec04 BR |
1746 | } |
1747 | ||
fa9ebf8c DG |
1748 | /* |
1749 | * VSX_DIV - VSX floating point divide | |
4b98eeef TM |
1750 | * op - instruction mnemonic |
1751 | * nels - number of elements (1, 2 or 4) | |
1752 | * tp - type (float32 or float64) | |
bcb7652e | 1753 | * fld - vsr_t field (VsrD(*) or VsrW(*)) |
4b98eeef TM |
1754 | * sfprf - set FPRF |
1755 | */ | |
b24d0b47 | 1756 | #define VSX_DIV(op, nels, tp, fld, sfprf, r2sp) \ |
99125c74 MCA |
1757 | void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \ |
1758 | ppc_vsr_t *xa, ppc_vsr_t *xb) \ | |
4b98eeef | 1759 | { \ |
cf3b0334 | 1760 | ppc_vsr_t t = *xt; \ |
4b98eeef TM |
1761 | int i; \ |
1762 | \ | |
4b98eeef TM |
1763 | helper_reset_fpstatus(env); \ |
1764 | \ | |
1765 | for (i = 0; i < nels; i++) { \ | |
1766 | float_status tstat = env->fp_status; \ | |
1767 | set_float_exception_flags(0, &tstat); \ | |
cf3b0334 | 1768 | t.fld = tp##_div(xa->fld, xb->fld, &tstat); \ |
4b98eeef TM |
1769 | env->fp_status.float_exception_flags |= tstat.float_exception_flags; \ |
1770 | \ | |
1771 | if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ | |
fec59ef3 | 1772 | float_invalid_op_div(env, sfprf, GETPC(), \ |
cf3b0334 MCA |
1773 | tp##_classify(xa->fld) | \ |
1774 | tp##_classify(xb->fld)); \ | |
ae13018d RH |
1775 | } \ |
1776 | if (unlikely(tstat.float_exception_flags & float_flag_divbyzero)) { \ | |
1777 | float_zero_divide_excp(env, GETPC()); \ | |
4b98eeef TM |
1778 | } \ |
1779 | \ | |
b24d0b47 | 1780 | if (r2sp) { \ |
cf3b0334 | 1781 | t.fld = helper_frsp(env, t.fld); \ |
b24d0b47 TM |
1782 | } \ |
1783 | \ | |
4b98eeef | 1784 | if (sfprf) { \ |
cf3b0334 | 1785 | helper_compute_fprf_float64(env, t.fld); \ |
4b98eeef TM |
1786 | } \ |
1787 | } \ | |
1788 | \ | |
cf3b0334 | 1789 | *xt = t; \ |
6525aadc | 1790 | do_float_check_status(env, GETPC()); \ |
4b98eeef TM |
1791 | } |
1792 | ||
bcb7652e TM |
1793 | VSX_DIV(xsdivdp, 1, float64, VsrD(0), 1, 0) |
1794 | VSX_DIV(xsdivsp, 1, float64, VsrD(0), 1, 1) | |
1795 | VSX_DIV(xvdivdp, 2, float64, VsrD(i), 0, 0) | |
1796 | VSX_DIV(xvdivsp, 4, float32, VsrW(i), 0, 0) | |
2009227f | 1797 | |
23d0766b MCA |
1798 | void helper_xsdivqp(CPUPPCState *env, uint32_t opcode, |
1799 | ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb) | |
314c1163 | 1800 | { |
cf3b0334 | 1801 | ppc_vsr_t t = *xt; |
a8d411ab | 1802 | float_status tstat; |
314c1163 | 1803 | |
a8d411ab BR |
1804 | helper_reset_fpstatus(env); |
1805 | tstat = env->fp_status; | |
314c1163 | 1806 | if (unlikely(Rc(opcode) != 0)) { |
a8d411ab | 1807 | tstat.float_rounding_mode = float_round_to_odd; |
314c1163 BR |
1808 | } |
1809 | ||
314c1163 | 1810 | set_float_exception_flags(0, &tstat); |
cf3b0334 | 1811 | t.f128 = float128_div(xa->f128, xb->f128, &tstat); |
314c1163 BR |
1812 | env->fp_status.float_exception_flags |= tstat.float_exception_flags; |
1813 | ||
1814 | if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { | |
fec59ef3 | 1815 | float_invalid_op_div(env, 1, GETPC(), |
cf3b0334 MCA |
1816 | float128_classify(xa->f128) | |
1817 | float128_classify(xb->f128)); | |
314c1163 | 1818 | } |
ae13018d RH |
1819 | if (unlikely(tstat.float_exception_flags & float_flag_divbyzero)) { |
1820 | float_zero_divide_excp(env, GETPC()); | |
1821 | } | |
314c1163 | 1822 | |
cf3b0334 MCA |
1823 | helper_compute_fprf_float128(env, t.f128); |
1824 | *xt = t; | |
6525aadc | 1825 | do_float_check_status(env, GETPC()); |
314c1163 BR |
1826 | } |
1827 | ||
fa9ebf8c DG |
1828 | /* |
1829 | * VSX_RE - VSX floating point reciprocal estimate | |
2009227f TM |
1830 | * op - instruction mnemonic |
1831 | * nels - number of elements (1, 2 or 4) | |
1832 | * tp - type (float32 or float64) | |
bcb7652e | 1833 | * fld - vsr_t field (VsrD(*) or VsrW(*)) |
2009227f TM |
1834 | * sfprf - set FPRF |
1835 | */ | |
2c0c52ae | 1836 | #define VSX_RE(op, nels, tp, fld, sfprf, r2sp) \ |
75cf84cb | 1837 | void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ |
2009227f | 1838 | { \ |
cf3b0334 | 1839 | ppc_vsr_t t = *xt; \ |
2009227f TM |
1840 | int i; \ |
1841 | \ | |
2009227f TM |
1842 | helper_reset_fpstatus(env); \ |
1843 | \ | |
1844 | for (i = 0; i < nels; i++) { \ | |
cf3b0334 | 1845 | if (unlikely(tp##_is_signaling_nan(xb->fld, &env->fp_status))) { \ |
13c9115f | 1846 | float_invalid_op_vxsnan(env, GETPC()); \ |
2009227f | 1847 | } \ |
cf3b0334 | 1848 | t.fld = tp##_div(tp##_one, xb->fld, &env->fp_status); \ |
2c0c52ae TM |
1849 | \ |
1850 | if (r2sp) { \ | |
cf3b0334 | 1851 | t.fld = helper_frsp(env, t.fld); \ |
2c0c52ae TM |
1852 | } \ |
1853 | \ | |
2009227f | 1854 | if (sfprf) { \ |
cf3b0334 | 1855 | helper_compute_fprf_float64(env, t.fld); \ |
2009227f TM |
1856 | } \ |
1857 | } \ | |
1858 | \ | |
cf3b0334 | 1859 | *xt = t; \ |
6525aadc | 1860 | do_float_check_status(env, GETPC()); \ |
2009227f TM |
1861 | } |
1862 | ||
bcb7652e TM |
1863 | VSX_RE(xsredp, 1, float64, VsrD(0), 1, 0) |
1864 | VSX_RE(xsresp, 1, float64, VsrD(0), 1, 1) | |
1865 | VSX_RE(xvredp, 2, float64, VsrD(i), 0, 0) | |
1866 | VSX_RE(xvresp, 4, float32, VsrW(i), 0, 0) | |
d32404fe | 1867 | |
fa9ebf8c DG |
1868 | /* |
1869 | * VSX_SQRT - VSX floating point square root | |
d32404fe TM |
1870 | * op - instruction mnemonic |
1871 | * nels - number of elements (1, 2 or 4) | |
1872 | * tp - type (float32 or float64) | |
bcb7652e | 1873 | * fld - vsr_t field (VsrD(*) or VsrW(*)) |
d32404fe TM |
1874 | * sfprf - set FPRF |
1875 | */ | |
cea4e574 | 1876 | #define VSX_SQRT(op, nels, tp, fld, sfprf, r2sp) \ |
75cf84cb | 1877 | void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ |
d32404fe | 1878 | { \ |
cf3b0334 | 1879 | ppc_vsr_t t = *xt; \ |
d32404fe TM |
1880 | int i; \ |
1881 | \ | |
d32404fe TM |
1882 | helper_reset_fpstatus(env); \ |
1883 | \ | |
1884 | for (i = 0; i < nels; i++) { \ | |
1885 | float_status tstat = env->fp_status; \ | |
1886 | set_float_exception_flags(0, &tstat); \ | |
cf3b0334 | 1887 | t.fld = tp##_sqrt(xb->fld, &tstat); \ |
d32404fe TM |
1888 | env->fp_status.float_exception_flags |= tstat.float_exception_flags; \ |
1889 | \ | |
1890 | if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ | |
cf3b0334 | 1891 | if (tp##_is_neg(xb->fld) && !tp##_is_zero(xb->fld)) { \ |
13c9115f | 1892 | float_invalid_op_vxsqrt(env, sfprf, GETPC()); \ |
cf3b0334 | 1893 | } else if (tp##_is_signaling_nan(xb->fld, &tstat)) { \ |
13c9115f | 1894 | float_invalid_op_vxsnan(env, GETPC()); \ |
d32404fe TM |
1895 | } \ |
1896 | } \ | |
1897 | \ | |
cea4e574 | 1898 | if (r2sp) { \ |
cf3b0334 | 1899 | t.fld = helper_frsp(env, t.fld); \ |
cea4e574 TM |
1900 | } \ |
1901 | \ | |
d32404fe | 1902 | if (sfprf) { \ |
cf3b0334 | 1903 | helper_compute_fprf_float64(env, t.fld); \ |
d32404fe TM |
1904 | } \ |
1905 | } \ | |
1906 | \ | |
cf3b0334 | 1907 | *xt = t; \ |
6525aadc | 1908 | do_float_check_status(env, GETPC()); \ |
d32404fe TM |
1909 | } |
1910 | ||
bcb7652e TM |
1911 | VSX_SQRT(xssqrtdp, 1, float64, VsrD(0), 1, 0) |
1912 | VSX_SQRT(xssqrtsp, 1, float64, VsrD(0), 1, 1) | |
1913 | VSX_SQRT(xvsqrtdp, 2, float64, VsrD(i), 0, 0) | |
1914 | VSX_SQRT(xvsqrtsp, 4, float32, VsrW(i), 0, 0) | |
d3f9df8f | 1915 | |
fa9ebf8c DG |
1916 | /* |
1917 | *VSX_RSQRTE - VSX floating point reciprocal square root estimate | |
d3f9df8f TM |
1918 | * op - instruction mnemonic |
1919 | * nels - number of elements (1, 2 or 4) | |
1920 | * tp - type (float32 or float64) | |
bcb7652e | 1921 | * fld - vsr_t field (VsrD(*) or VsrW(*)) |
d3f9df8f TM |
1922 | * sfprf - set FPRF |
1923 | */ | |
968e76bc | 1924 | #define VSX_RSQRTE(op, nels, tp, fld, sfprf, r2sp) \ |
75cf84cb | 1925 | void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ |
d3f9df8f | 1926 | { \ |
cf3b0334 | 1927 | ppc_vsr_t t = *xt; \ |
d3f9df8f TM |
1928 | int i; \ |
1929 | \ | |
d3f9df8f TM |
1930 | helper_reset_fpstatus(env); \ |
1931 | \ | |
1932 | for (i = 0; i < nels; i++) { \ | |
1933 | float_status tstat = env->fp_status; \ | |
1934 | set_float_exception_flags(0, &tstat); \ | |
cf3b0334 MCA |
1935 | t.fld = tp##_sqrt(xb->fld, &tstat); \ |
1936 | t.fld = tp##_div(tp##_one, t.fld, &tstat); \ | |
d3f9df8f TM |
1937 | env->fp_status.float_exception_flags |= tstat.float_exception_flags; \ |
1938 | \ | |
1939 | if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ | |
cf3b0334 | 1940 | if (tp##_is_neg(xb->fld) && !tp##_is_zero(xb->fld)) { \ |
13c9115f | 1941 | float_invalid_op_vxsqrt(env, sfprf, GETPC()); \ |
cf3b0334 | 1942 | } else if (tp##_is_signaling_nan(xb->fld, &tstat)) { \ |
13c9115f | 1943 | float_invalid_op_vxsnan(env, GETPC()); \ |
d3f9df8f TM |
1944 | } \ |
1945 | } \ | |
1946 | \ | |
968e76bc | 1947 | if (r2sp) { \ |
cf3b0334 | 1948 | t.fld = helper_frsp(env, t.fld); \ |
968e76bc TM |
1949 | } \ |
1950 | \ | |
d3f9df8f | 1951 | if (sfprf) { \ |
cf3b0334 | 1952 | helper_compute_fprf_float64(env, t.fld); \ |
d3f9df8f TM |
1953 | } \ |
1954 | } \ | |
1955 | \ | |
cf3b0334 | 1956 | *xt = t; \ |
6525aadc | 1957 | do_float_check_status(env, GETPC()); \ |
d3f9df8f TM |
1958 | } |
1959 | ||
bcb7652e TM |
1960 | VSX_RSQRTE(xsrsqrtedp, 1, float64, VsrD(0), 1, 0) |
1961 | VSX_RSQRTE(xsrsqrtesp, 1, float64, VsrD(0), 1, 1) | |
1962 | VSX_RSQRTE(xvrsqrtedp, 2, float64, VsrD(i), 0, 0) | |
1963 | VSX_RSQRTE(xvrsqrtesp, 4, float32, VsrW(i), 0, 0) | |
bc80838f | 1964 | |
fa9ebf8c DG |
1965 | /* |
1966 | * VSX_TDIV - VSX floating point test for divide | |
bc80838f TM |
1967 | * op - instruction mnemonic |
1968 | * nels - number of elements (1, 2 or 4) | |
1969 | * tp - type (float32 or float64) | |
bcb7652e | 1970 | * fld - vsr_t field (VsrD(*) or VsrW(*)) |
bc80838f TM |
1971 | * emin - minimum unbiased exponent |
1972 | * emax - maximum unbiased exponent | |
1973 | * nbits - number of fraction bits | |
1974 | */ | |
1975 | #define VSX_TDIV(op, nels, tp, fld, emin, emax, nbits) \ | |
033e1fcd MCA |
1976 | void helper_##op(CPUPPCState *env, uint32_t opcode, \ |
1977 | ppc_vsr_t *xa, ppc_vsr_t *xb) \ | |
bc80838f | 1978 | { \ |
bc80838f TM |
1979 | int i; \ |
1980 | int fe_flag = 0; \ | |
1981 | int fg_flag = 0; \ | |
1982 | \ | |
bc80838f | 1983 | for (i = 0; i < nels; i++) { \ |
cf3b0334 MCA |
1984 | if (unlikely(tp##_is_infinity(xa->fld) || \ |
1985 | tp##_is_infinity(xb->fld) || \ | |
1986 | tp##_is_zero(xb->fld))) { \ | |
bc80838f TM |
1987 | fe_flag = 1; \ |
1988 | fg_flag = 1; \ | |
1989 | } else { \ | |
cf3b0334 MCA |
1990 | int e_a = ppc_##tp##_get_unbiased_exp(xa->fld); \ |
1991 | int e_b = ppc_##tp##_get_unbiased_exp(xb->fld); \ | |
bc80838f | 1992 | \ |
cf3b0334 MCA |
1993 | if (unlikely(tp##_is_any_nan(xa->fld) || \ |
1994 | tp##_is_any_nan(xb->fld))) { \ | |
bc80838f | 1995 | fe_flag = 1; \ |
fa9ebf8c | 1996 | } else if ((e_b <= emin) || (e_b >= (emax - 2))) { \ |
bc80838f | 1997 | fe_flag = 1; \ |
cf3b0334 | 1998 | } else if (!tp##_is_zero(xa->fld) && \ |
bc80838f | 1999 | (((e_a - e_b) >= emax) || \ |
fa9ebf8c DG |
2000 | ((e_a - e_b) <= (emin + 1)) || \ |
2001 | (e_a <= (emin + nbits)))) { \ | |
bc80838f TM |
2002 | fe_flag = 1; \ |
2003 | } \ | |
2004 | \ | |
cf3b0334 | 2005 | if (unlikely(tp##_is_zero_or_denormal(xb->fld))) { \ |
fa9ebf8c DG |
2006 | /* \ |
2007 | * XB is not zero because of the above check and so \ | |
2008 | * must be denormalized. \ | |
2009 | */ \ | |
bc80838f TM |
2010 | fg_flag = 1; \ |
2011 | } \ | |
2012 | } \ | |
2013 | } \ | |
2014 | \ | |
2015 | env->crf[BF(opcode)] = 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0); \ | |
2016 | } | |
2017 | ||
bcb7652e TM |
2018 | VSX_TDIV(xstdivdp, 1, float64, VsrD(0), -1022, 1023, 52) |
2019 | VSX_TDIV(xvtdivdp, 2, float64, VsrD(i), -1022, 1023, 52) | |
2020 | VSX_TDIV(xvtdivsp, 4, float32, VsrW(i), -126, 127, 23) | |
5cb151ac | 2021 | |
fa9ebf8c DG |
2022 | /* |
2023 | * VSX_TSQRT - VSX floating point test for square root | |
5cb151ac TM |
2024 | * op - instruction mnemonic |
2025 | * nels - number of elements (1, 2 or 4) | |
2026 | * tp - type (float32 or float64) | |
bcb7652e | 2027 | * fld - vsr_t field (VsrD(*) or VsrW(*)) |
5cb151ac TM |
2028 | * emin - minimum unbiased exponent |
2029 | * emax - maximum unbiased exponent | |
2030 | * nbits - number of fraction bits | |
2031 | */ | |
2032 | #define VSX_TSQRT(op, nels, tp, fld, emin, nbits) \ | |
8d830485 | 2033 | void helper_##op(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xb) \ |
5cb151ac | 2034 | { \ |
5cb151ac TM |
2035 | int i; \ |
2036 | int fe_flag = 0; \ | |
2037 | int fg_flag = 0; \ | |
2038 | \ | |
5cb151ac | 2039 | for (i = 0; i < nels; i++) { \ |
cf3b0334 MCA |
2040 | if (unlikely(tp##_is_infinity(xb->fld) || \ |
2041 | tp##_is_zero(xb->fld))) { \ | |
5cb151ac TM |
2042 | fe_flag = 1; \ |
2043 | fg_flag = 1; \ | |
2044 | } else { \ | |
cf3b0334 | 2045 | int e_b = ppc_##tp##_get_unbiased_exp(xb->fld); \ |
5cb151ac | 2046 | \ |
cf3b0334 | 2047 | if (unlikely(tp##_is_any_nan(xb->fld))) { \ |
5cb151ac | 2048 | fe_flag = 1; \ |
cf3b0334 | 2049 | } else if (unlikely(tp##_is_zero(xb->fld))) { \ |
5cb151ac | 2050 | fe_flag = 1; \ |
cf3b0334 | 2051 | } else if (unlikely(tp##_is_neg(xb->fld))) { \ |
5cb151ac | 2052 | fe_flag = 1; \ |
cf3b0334 | 2053 | } else if (!tp##_is_zero(xb->fld) && \ |
fa9ebf8c | 2054 | (e_b <= (emin + nbits))) { \ |
5cb151ac TM |
2055 | fe_flag = 1; \ |
2056 | } \ | |
2057 | \ | |
cf3b0334 | 2058 | if (unlikely(tp##_is_zero_or_denormal(xb->fld))) { \ |
fa9ebf8c DG |
2059 | /* \ |
2060 | * XB is not zero because of the above check and \ | |
2061 | * therefore must be denormalized. \ | |
2062 | */ \ | |
5cb151ac TM |
2063 | fg_flag = 1; \ |
2064 | } \ | |
2065 | } \ | |
2066 | } \ | |
2067 | \ | |
2068 | env->crf[BF(opcode)] = 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0); \ | |
2069 | } | |
2070 | ||
bcb7652e TM |
2071 | VSX_TSQRT(xstsqrtdp, 1, float64, VsrD(0), -1022, 52) |
2072 | VSX_TSQRT(xvtsqrtdp, 2, float64, VsrD(i), -1022, 52) | |
2073 | VSX_TSQRT(xvtsqrtsp, 4, float32, VsrW(i), -126, 23) | |
595c6eef | 2074 | |
fa9ebf8c DG |
2075 | /* |
2076 | * VSX_MADD - VSX floating point muliply/add variations | |
595c6eef TM |
2077 | * op - instruction mnemonic |
2078 | * nels - number of elements (1, 2 or 4) | |
2079 | * tp - type (float32 or float64) | |
bcb7652e | 2080 | * fld - vsr_t field (VsrD(*) or VsrW(*)) |
595c6eef TM |
2081 | * maddflgs - flags for the float*muladd routine that control the |
2082 | * various forms (madd, msub, nmadd, nmsub) | |
595c6eef TM |
2083 | * sfprf - set FPRF |
2084 | */ | |
c9f4e4d8 | 2085 | #define VSX_MADD(op, nels, tp, fld, maddflgs, sfprf, r2sp) \ |
99125c74 | 2086 | void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \ |
c9f4e4d8 | 2087 | ppc_vsr_t *xa, ppc_vsr_t *b, ppc_vsr_t *c) \ |
595c6eef | 2088 | { \ |
c9f4e4d8 | 2089 | ppc_vsr_t t = *xt; \ |
595c6eef TM |
2090 | int i; \ |
2091 | \ | |
595c6eef TM |
2092 | helper_reset_fpstatus(env); \ |
2093 | \ | |
2094 | for (i = 0; i < nels; i++) { \ | |
2095 | float_status tstat = env->fp_status; \ | |
2096 | set_float_exception_flags(0, &tstat); \ | |
f53f81e0 | 2097 | if (r2sp && (tstat.float_rounding_mode == float_round_nearest_even)) {\ |
fa9ebf8c DG |
2098 | /* \ |
2099 | * Avoid double rounding errors by rounding the intermediate \ | |
2100 | * result to odd. \ | |
2101 | */ \ | |
f53f81e0 | 2102 | set_float_rounding_mode(float_round_to_zero, &tstat); \ |
cf3b0334 MCA |
2103 | t.fld = tp##_muladd(xa->fld, b->fld, c->fld, \ |
2104 | maddflgs, &tstat); \ | |
2105 | t.fld |= (get_float_exception_flags(&tstat) & \ | |
2106 | float_flag_inexact) != 0; \ | |
f53f81e0 | 2107 | } else { \ |
cf3b0334 MCA |
2108 | t.fld = tp##_muladd(xa->fld, b->fld, c->fld, \ |
2109 | maddflgs, &tstat); \ | |
f53f81e0 | 2110 | } \ |
595c6eef TM |
2111 | env->fp_status.float_exception_flags |= tstat.float_exception_flags; \ |
2112 | \ | |
2113 | if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \ | |
cf3b0334 | 2114 | tp##_maddsub_update_excp(env, xa->fld, b->fld, \ |
13c9115f | 2115 | c->fld, maddflgs, GETPC()); \ |
595c6eef | 2116 | } \ |
f53f81e0 TM |
2117 | \ |
2118 | if (r2sp) { \ | |
cf3b0334 | 2119 | t.fld = helper_frsp(env, t.fld); \ |
f53f81e0 TM |
2120 | } \ |
2121 | \ | |
595c6eef | 2122 | if (sfprf) { \ |
cf3b0334 | 2123 | helper_compute_fprf_float64(env, t.fld); \ |
595c6eef TM |
2124 | } \ |
2125 | } \ | |
cf3b0334 | 2126 | *xt = t; \ |
6525aadc | 2127 | do_float_check_status(env, GETPC()); \ |
595c6eef TM |
2128 | } |
2129 | ||
c9f4e4d8 MCA |
2130 | VSX_MADD(xsmadddp, 1, float64, VsrD(0), MADD_FLGS, 1, 0) |
2131 | VSX_MADD(xsmsubdp, 1, float64, VsrD(0), MSUB_FLGS, 1, 0) | |
2132 | VSX_MADD(xsnmadddp, 1, float64, VsrD(0), NMADD_FLGS, 1, 0) | |
2133 | VSX_MADD(xsnmsubdp, 1, float64, VsrD(0), NMSUB_FLGS, 1, 0) | |
2134 | VSX_MADD(xsmaddsp, 1, float64, VsrD(0), MADD_FLGS, 1, 1) | |
2135 | VSX_MADD(xsmsubsp, 1, float64, VsrD(0), MSUB_FLGS, 1, 1) | |
2136 | VSX_MADD(xsnmaddsp, 1, float64, VsrD(0), NMADD_FLGS, 1, 1) | |
2137 | VSX_MADD(xsnmsubsp, 1, float64, VsrD(0), NMSUB_FLGS, 1, 1) | |
2138 | ||
2139 | VSX_MADD(xvmadddp, 2, float64, VsrD(i), MADD_FLGS, 0, 0) | |
2140 | VSX_MADD(xvmsubdp, 2, float64, VsrD(i), MSUB_FLGS, 0, 0) | |
2141 | VSX_MADD(xvnmadddp, 2, float64, VsrD(i), NMADD_FLGS, 0, 0) | |
2142 | VSX_MADD(xvnmsubdp, 2, float64, VsrD(i), NMSUB_FLGS, 0, 0) | |
2143 | ||
2144 | VSX_MADD(xvmaddsp, 4, float32, VsrW(i), MADD_FLGS, 0, 0) | |
2145 | VSX_MADD(xvmsubsp, 4, float32, VsrW(i), MSUB_FLGS, 0, 0) | |
2146 | VSX_MADD(xvnmaddsp, 4, float32, VsrW(i), NMADD_FLGS, 0, 0) | |
2147 | VSX_MADD(xvnmsubsp, 4, float32, VsrW(i), NMSUB_FLGS, 0, 0) | |
4f17e9c7 | 2148 | |
fa9ebf8c DG |
2149 | /* |
2150 | * VSX_SCALAR_CMP_DP - VSX scalar floating point compare double precision | |
6d1ff9a7 SD |
2151 | * op - instruction mnemonic |
2152 | * cmp - comparison operation | |
2153 | * exp - expected result of comparison | |
2154 | * svxvc - set VXVC bit | |
2155 | */ | |
2156 | #define VSX_SCALAR_CMP_DP(op, cmp, exp, svxvc) \ | |
99125c74 MCA |
2157 | void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \ |
2158 | ppc_vsr_t *xa, ppc_vsr_t *xb) \ | |
6d1ff9a7 | 2159 | { \ |
cf3b0334 | 2160 | ppc_vsr_t t = *xt; \ |
6d1ff9a7 SD |
2161 | bool vxsnan_flag = false, vxvc_flag = false, vex_flag = false; \ |
2162 | \ | |
cf3b0334 MCA |
2163 | if (float64_is_signaling_nan(xa->VsrD(0), &env->fp_status) || \ |
2164 | float64_is_signaling_nan(xb->VsrD(0), &env->fp_status)) { \ | |
6d1ff9a7 SD |
2165 | vxsnan_flag = true; \ |
2166 | if (fpscr_ve == 0 && svxvc) { \ | |
2167 | vxvc_flag = true; \ | |
2168 | } \ | |
2169 | } else if (svxvc) { \ | |
cf3b0334 MCA |
2170 | vxvc_flag = float64_is_quiet_nan(xa->VsrD(0), &env->fp_status) || \ |
2171 | float64_is_quiet_nan(xb->VsrD(0), &env->fp_status); \ | |
6d1ff9a7 SD |
2172 | } \ |
2173 | if (vxsnan_flag) { \ | |
13c9115f | 2174 | float_invalid_op_vxsnan(env, GETPC()); \ |
6d1ff9a7 SD |
2175 | } \ |
2176 | if (vxvc_flag) { \ | |
13c9115f | 2177 | float_invalid_op_vxvc(env, 0, GETPC()); \ |
6d1ff9a7 SD |
2178 | } \ |
2179 | vex_flag = fpscr_ve && (vxvc_flag || vxsnan_flag); \ | |
2180 | \ | |
2181 | if (!vex_flag) { \ | |
cf3b0334 MCA |
2182 | if (float64_##cmp(xb->VsrD(0), xa->VsrD(0), \ |
2183 | &env->fp_status) == exp) { \ | |
2184 | t.VsrD(0) = -1; \ | |
2185 | t.VsrD(1) = 0; \ | |
6d1ff9a7 | 2186 | } else { \ |
cf3b0334 MCA |
2187 | t.VsrD(0) = 0; \ |
2188 | t.VsrD(1) = 0; \ | |
6d1ff9a7 SD |
2189 | } \ |
2190 | } \ | |
cf3b0334 | 2191 | *xt = t; \ |
6525aadc | 2192 | do_float_check_status(env, GETPC()); \ |
6d1ff9a7 SD |
2193 | } |
2194 | ||
2195 | VSX_SCALAR_CMP_DP(xscmpeqdp, eq, 1, 0) | |
2196 | VSX_SCALAR_CMP_DP(xscmpgedp, le, 1, 1) | |
2197 | VSX_SCALAR_CMP_DP(xscmpgtdp, lt, 1, 1) | |
2198 | VSX_SCALAR_CMP_DP(xscmpnedp, eq, 0, 0) | |
2199 | ||
033e1fcd MCA |
2200 | void helper_xscmpexpdp(CPUPPCState *env, uint32_t opcode, |
2201 | ppc_vsr_t *xa, ppc_vsr_t *xb) | |
3a20d11d | 2202 | { |
3a20d11d BR |
2203 | int64_t exp_a, exp_b; |
2204 | uint32_t cc; | |
2205 | ||
cf3b0334 MCA |
2206 | exp_a = extract64(xa->VsrD(0), 52, 11); |
2207 | exp_b = extract64(xb->VsrD(0), 52, 11); | |
3a20d11d | 2208 | |
cf3b0334 MCA |
2209 | if (unlikely(float64_is_any_nan(xa->VsrD(0)) || |
2210 | float64_is_any_nan(xb->VsrD(0)))) { | |
3a20d11d BR |
2211 | cc = CRF_SO; |
2212 | } else { | |
2213 | if (exp_a < exp_b) { | |
2214 | cc = CRF_LT; | |
2215 | } else if (exp_a > exp_b) { | |
2216 | cc = CRF_GT; | |
2217 | } else { | |
2218 | cc = CRF_EQ; | |
2219 | } | |
2220 | } | |
2221 | ||
5c94dd38 PC |
2222 | env->fpscr &= ~FP_FPCC; |
2223 | env->fpscr |= cc << FPSCR_FPCC; | |
3a20d11d BR |
2224 | env->crf[BF(opcode)] = cc; |
2225 | ||
6525aadc | 2226 | do_float_check_status(env, GETPC()); |
3a20d11d BR |
2227 | } |
2228 | ||
6ae4a57a MCA |
2229 | void helper_xscmpexpqp(CPUPPCState *env, uint32_t opcode, |
2230 | ppc_vsr_t *xa, ppc_vsr_t *xb) | |
3a20d11d | 2231 | { |
3a20d11d BR |
2232 | int64_t exp_a, exp_b; |
2233 | uint32_t cc; | |
2234 | ||
cf3b0334 MCA |
2235 | exp_a = extract64(xa->VsrD(0), 48, 15); |
2236 | exp_b = extract64(xb->VsrD(0), 48, 15); | |
3a20d11d | 2237 | |
cf3b0334 MCA |
2238 | if (unlikely(float128_is_any_nan(xa->f128) || |
2239 | float128_is_any_nan(xb->f128))) { | |
3a20d11d BR |
2240 | cc = CRF_SO; |
2241 | } else { | |
2242 | if (exp_a < exp_b) { | |
2243 | cc = CRF_LT; | |
2244 | } else if (exp_a > exp_b) { | |
2245 | cc = CRF_GT; | |
2246 | } else { | |
2247 | cc = CRF_EQ; | |
2248 | } | |
2249 | } | |
2250 | ||
5c94dd38 PC |
2251 | env->fpscr &= ~FP_FPCC; |
2252 | env->fpscr |= cc << FPSCR_FPCC; | |
3a20d11d BR |
2253 | env->crf[BF(opcode)] = cc; |
2254 | ||
6525aadc | 2255 | do_float_check_status(env, GETPC()); |
3a20d11d BR |
2256 | } |
2257 | ||
132954a8 GM |
2258 | static inline void do_scalar_cmp(CPUPPCState *env, ppc_vsr_t *xa, ppc_vsr_t *xb, |
2259 | int crf_idx, bool ordered) | |
2260 | { | |
2261 | uint32_t cc; | |
2262 | bool vxsnan_flag = false, vxvc_flag = false; | |
2263 | ||
2264 | helper_reset_fpstatus(env); | |
2265 | ||
132954a8 GM |
2266 | switch (float64_compare(xa->VsrD(0), xb->VsrD(0), &env->fp_status)) { |
2267 | case float_relation_less: | |
2268 | cc = CRF_LT; | |
2269 | break; | |
2270 | case float_relation_equal: | |
2271 | cc = CRF_EQ; | |
2272 | break; | |
2273 | case float_relation_greater: | |
2274 | cc = CRF_GT; | |
2275 | break; | |
2276 | case float_relation_unordered: | |
2277 | cc = CRF_SO; | |
bc92c260 GM |
2278 | |
2279 | if (float64_is_signaling_nan(xa->VsrD(0), &env->fp_status) || | |
2280 | float64_is_signaling_nan(xb->VsrD(0), &env->fp_status)) { | |
2281 | vxsnan_flag = true; | |
2282 | if (fpscr_ve == 0 && ordered) { | |
2283 | vxvc_flag = true; | |
2284 | } | |
2285 | } else if (float64_is_quiet_nan(xa->VsrD(0), &env->fp_status) || | |
2286 | float64_is_quiet_nan(xb->VsrD(0), &env->fp_status)) { | |
2287 | if (ordered) { | |
2288 | vxvc_flag = true; | |
2289 | } | |
2290 | } | |
2291 | ||
132954a8 GM |
2292 | break; |
2293 | default: | |
2294 | g_assert_not_reached(); | |
2295 | } | |
2296 | ||
2297 | env->fpscr &= ~FP_FPCC; | |
2298 | env->fpscr |= cc << FPSCR_FPCC; | |
2299 | env->crf[crf_idx] = cc; | |
2300 | ||
91699dbf GM |
2301 | if (vxsnan_flag) { |
2302 | float_invalid_op_vxsnan(env, GETPC()); | |
2303 | } | |
2304 | if (vxvc_flag) { | |
2305 | float_invalid_op_vxvc(env, 0, GETPC()); | |
2306 | } | |
2307 | ||
132954a8 | 2308 | do_float_check_status(env, GETPC()); |
be0a4faf BR |
2309 | } |
2310 | ||
132954a8 GM |
2311 | void helper_xscmpodp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xa, |
2312 | ppc_vsr_t *xb) | |
2313 | { | |
2314 | do_scalar_cmp(env, xa, xb, BF(opcode), true); | |
2315 | } | |
2316 | ||
2317 | void helper_xscmpudp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xa, | |
2318 | ppc_vsr_t *xb) | |
2319 | { | |
2320 | do_scalar_cmp(env, xa, xb, BF(opcode), false); | |
2321 | } | |
2322 | ||
2323 | static inline void do_scalar_cmpq(CPUPPCState *env, ppc_vsr_t *xa, | |
2324 | ppc_vsr_t *xb, int crf_idx, bool ordered) | |
2325 | { | |
2326 | uint32_t cc; | |
2327 | bool vxsnan_flag = false, vxvc_flag = false; | |
2328 | ||
2329 | helper_reset_fpstatus(env); | |
2330 | ||
132954a8 GM |
2331 | switch (float128_compare(xa->f128, xb->f128, &env->fp_status)) { |
2332 | case float_relation_less: | |
2333 | cc = CRF_LT; | |
2334 | break; | |
2335 | case float_relation_equal: | |
2336 | cc = CRF_EQ; | |
2337 | break; | |
2338 | case float_relation_greater: | |
2339 | cc = CRF_GT; | |
2340 | break; | |
2341 | case float_relation_unordered: | |
2342 | cc = CRF_SO; | |
bc92c260 GM |
2343 | |
2344 | if (float128_is_signaling_nan(xa->f128, &env->fp_status) || | |
2345 | float128_is_signaling_nan(xb->f128, &env->fp_status)) { | |
2346 | vxsnan_flag = true; | |
2347 | if (fpscr_ve == 0 && ordered) { | |
2348 | vxvc_flag = true; | |
2349 | } | |
2350 | } else if (float128_is_quiet_nan(xa->f128, &env->fp_status) || | |
2351 | float128_is_quiet_nan(xb->f128, &env->fp_status)) { | |
2352 | if (ordered) { | |
2353 | vxvc_flag = true; | |
2354 | } | |
2355 | } | |
2356 | ||
132954a8 GM |
2357 | break; |
2358 | default: | |
2359 | g_assert_not_reached(); | |
2360 | } | |
2361 | ||
2362 | env->fpscr &= ~FP_FPCC; | |
2363 | env->fpscr |= cc << FPSCR_FPCC; | |
2364 | env->crf[crf_idx] = cc; | |
2365 | ||
91699dbf GM |
2366 | if (vxsnan_flag) { |
2367 | float_invalid_op_vxsnan(env, GETPC()); | |
2368 | } | |
2369 | if (vxvc_flag) { | |
2370 | float_invalid_op_vxvc(env, 0, GETPC()); | |
2371 | } | |
2372 | ||
132954a8 GM |
2373 | do_float_check_status(env, GETPC()); |
2374 | } | |
2375 | ||
2376 | void helper_xscmpoqp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xa, | |
2377 | ppc_vsr_t *xb) | |
2378 | { | |
2379 | do_scalar_cmpq(env, xa, xb, BF(opcode), true); | |
2380 | } | |
2381 | ||
2382 | void helper_xscmpuqp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xa, | |
2383 | ppc_vsr_t *xb) | |
2384 | { | |
2385 | do_scalar_cmpq(env, xa, xb, BF(opcode), false); | |
2386 | } | |
be0a4faf | 2387 | |
fa9ebf8c DG |
2388 | /* |
2389 | * VSX_MAX_MIN - VSX floating point maximum/minimum | |
959e9c9d TM |
2390 | * name - instruction mnemonic |
2391 | * op - operation (max or min) | |
2392 | * nels - number of elements (1, 2 or 4) | |
2393 | * tp - type (float32 or float64) | |
bcb7652e | 2394 | * fld - vsr_t field (VsrD(*) or VsrW(*)) |
959e9c9d TM |
2395 | */ |
2396 | #define VSX_MAX_MIN(name, op, nels, tp, fld) \ | |
99125c74 MCA |
2397 | void helper_##name(CPUPPCState *env, ppc_vsr_t *xt, \ |
2398 | ppc_vsr_t *xa, ppc_vsr_t *xb) \ | |
959e9c9d | 2399 | { \ |
cf3b0334 | 2400 | ppc_vsr_t t = *xt; \ |
959e9c9d TM |
2401 | int i; \ |
2402 | \ | |
959e9c9d | 2403 | for (i = 0; i < nels; i++) { \ |
cf3b0334 MCA |
2404 | t.fld = tp##_##op(xa->fld, xb->fld, &env->fp_status); \ |
2405 | if (unlikely(tp##_is_signaling_nan(xa->fld, &env->fp_status) || \ | |
2406 | tp##_is_signaling_nan(xb->fld, &env->fp_status))) { \ | |
13c9115f | 2407 | float_invalid_op_vxsnan(env, GETPC()); \ |
959e9c9d TM |
2408 | } \ |
2409 | } \ | |
2410 | \ | |
cf3b0334 | 2411 | *xt = t; \ |
6525aadc | 2412 | do_float_check_status(env, GETPC()); \ |
959e9c9d TM |
2413 | } |
2414 | ||
bcb7652e TM |
2415 | VSX_MAX_MIN(xsmaxdp, maxnum, 1, float64, VsrD(0)) |
2416 | VSX_MAX_MIN(xvmaxdp, maxnum, 2, float64, VsrD(i)) | |
2417 | VSX_MAX_MIN(xvmaxsp, maxnum, 4, float32, VsrW(i)) | |
2418 | VSX_MAX_MIN(xsmindp, minnum, 1, float64, VsrD(0)) | |
2419 | VSX_MAX_MIN(xvmindp, minnum, 2, float64, VsrD(i)) | |
2420 | VSX_MAX_MIN(xvminsp, minnum, 4, float32, VsrW(i)) | |
354a6dec | 2421 | |
2770deed | 2422 | #define VSX_MAX_MINC(name, max) \ |
23d0766b MCA |
2423 | void helper_##name(CPUPPCState *env, uint32_t opcode, \ |
2424 | ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb) \ | |
2770deed | 2425 | { \ |
cf3b0334 | 2426 | ppc_vsr_t t = *xt; \ |
2770deed BR |
2427 | bool vxsnan_flag = false, vex_flag = false; \ |
2428 | \ | |
cf3b0334 MCA |
2429 | if (unlikely(float64_is_any_nan(xa->VsrD(0)) || \ |
2430 | float64_is_any_nan(xb->VsrD(0)))) { \ | |
2431 | if (float64_is_signaling_nan(xa->VsrD(0), &env->fp_status) || \ | |
2432 | float64_is_signaling_nan(xb->VsrD(0), &env->fp_status)) { \ | |
2770deed BR |
2433 | vxsnan_flag = true; \ |
2434 | } \ | |
cf3b0334 | 2435 | t.VsrD(0) = xb->VsrD(0); \ |
2770deed | 2436 | } else if ((max && \ |
cf3b0334 | 2437 | !float64_lt(xa->VsrD(0), xb->VsrD(0), &env->fp_status)) || \ |
2770deed | 2438 | (!max && \ |
cf3b0334 MCA |
2439 | float64_lt(xa->VsrD(0), xb->VsrD(0), &env->fp_status))) { \ |
2440 | t.VsrD(0) = xa->VsrD(0); \ | |
2770deed | 2441 | } else { \ |
cf3b0334 | 2442 | t.VsrD(0) = xb->VsrD(0); \ |
2770deed BR |
2443 | } \ |
2444 | \ | |
2445 | vex_flag = fpscr_ve & vxsnan_flag; \ | |
2446 | if (vxsnan_flag) { \ | |
13c9115f | 2447 | float_invalid_op_vxsnan(env, GETPC()); \ |
2770deed BR |
2448 | } \ |
2449 | if (!vex_flag) { \ | |
cf3b0334 | 2450 | *xt = t; \ |
2770deed BR |
2451 | } \ |
2452 | } \ | |
2453 | ||
2454 | VSX_MAX_MINC(xsmaxcdp, 1); | |
2455 | VSX_MAX_MINC(xsmincdp, 0); | |
2456 | ||
d4ccd87e | 2457 | #define VSX_MAX_MINJ(name, max) \ |
23d0766b MCA |
2458 | void helper_##name(CPUPPCState *env, uint32_t opcode, \ |
2459 | ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb) \ | |
d4ccd87e | 2460 | { \ |
cf3b0334 | 2461 | ppc_vsr_t t = *xt; \ |
d4ccd87e BR |
2462 | bool vxsnan_flag = false, vex_flag = false; \ |
2463 | \ | |
cf3b0334 MCA |
2464 | if (unlikely(float64_is_any_nan(xa->VsrD(0)))) { \ |
2465 | if (float64_is_signaling_nan(xa->VsrD(0), &env->fp_status)) { \ | |
d4ccd87e BR |
2466 | vxsnan_flag = true; \ |
2467 | } \ | |
cf3b0334 MCA |
2468 | t.VsrD(0) = xa->VsrD(0); \ |
2469 | } else if (unlikely(float64_is_any_nan(xb->VsrD(0)))) { \ | |
2470 | if (float64_is_signaling_nan(xb->VsrD(0), &env->fp_status)) { \ | |
d4ccd87e BR |
2471 | vxsnan_flag = true; \ |
2472 | } \ | |
cf3b0334 MCA |
2473 | t.VsrD(0) = xb->VsrD(0); \ |
2474 | } else if (float64_is_zero(xa->VsrD(0)) && \ | |
2475 | float64_is_zero(xb->VsrD(0))) { \ | |
d4ccd87e | 2476 | if (max) { \ |
cf3b0334 MCA |
2477 | if (!float64_is_neg(xa->VsrD(0)) || \ |
2478 | !float64_is_neg(xb->VsrD(0))) { \ | |
2479 | t.VsrD(0) = 0ULL; \ | |
d4ccd87e | 2480 | } else { \ |
cf3b0334 | 2481 | t.VsrD(0) = 0x8000000000000000ULL; \ |
d4ccd87e BR |
2482 | } \ |
2483 | } else { \ | |
cf3b0334 MCA |
2484 | if (float64_is_neg(xa->VsrD(0)) || \ |
2485 | float64_is_neg(xb->VsrD(0))) { \ | |
2486 | t.VsrD(0) = 0x8000000000000000ULL; \ | |
d4ccd87e | 2487 | } else { \ |
cf3b0334 | 2488 | t.VsrD(0) = 0ULL; \ |
d4ccd87e BR |
2489 | } \ |
2490 | } \ | |
2491 | } else if ((max && \ | |
cf3b0334 | 2492 | !float64_lt(xa->VsrD(0), xb->VsrD(0), &env->fp_status)) || \ |
d4ccd87e | 2493 | (!max && \ |
cf3b0334 MCA |
2494 | float64_lt(xa->VsrD(0), xb->VsrD(0), &env->fp_status))) { \ |
2495 | t.VsrD(0) = xa->VsrD(0); \ | |
d4ccd87e | 2496 | } else { \ |
cf3b0334 | 2497 | t.VsrD(0) = xb->VsrD(0); \ |
d4ccd87e BR |
2498 | } \ |
2499 | \ | |
2500 | vex_flag = fpscr_ve & vxsnan_flag; \ | |
2501 | if (vxsnan_flag) { \ | |
13c9115f | 2502 | float_invalid_op_vxsnan(env, GETPC()); \ |
d4ccd87e BR |
2503 | } \ |
2504 | if (!vex_flag) { \ | |
cf3b0334 | 2505 | *xt = t; \ |
d4ccd87e BR |
2506 | } \ |
2507 | } \ | |
2508 | ||
2509 | VSX_MAX_MINJ(xsmaxjdp, 1); | |
2510 | VSX_MAX_MINJ(xsminjdp, 0); | |
2511 | ||
fa9ebf8c DG |
2512 | /* |
2513 | * VSX_CMP - VSX floating point compare | |
354a6dec TM |
2514 | * op - instruction mnemonic |
2515 | * nels - number of elements (1, 2 or 4) | |
2516 | * tp - type (float32 or float64) | |
bcb7652e | 2517 | * fld - vsr_t field (VsrD(*) or VsrW(*)) |
354a6dec TM |
2518 | * cmp - comparison operation |
2519 | * svxvc - set VXVC bit | |
6db246f9 | 2520 | * exp - expected result of comparison |
354a6dec | 2521 | */ |
6db246f9 | 2522 | #define VSX_CMP(op, nels, tp, fld, cmp, svxvc, exp) \ |
00084a25 MCA |
2523 | uint32_t helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \ |
2524 | ppc_vsr_t *xa, ppc_vsr_t *xb) \ | |
354a6dec | 2525 | { \ |
cf3b0334 | 2526 | ppc_vsr_t t = *xt; \ |
00084a25 | 2527 | uint32_t crf6 = 0; \ |
354a6dec TM |
2528 | int i; \ |
2529 | int all_true = 1; \ | |
2530 | int all_false = 1; \ | |
2531 | \ | |
354a6dec | 2532 | for (i = 0; i < nels; i++) { \ |
cf3b0334 MCA |
2533 | if (unlikely(tp##_is_any_nan(xa->fld) || \ |
2534 | tp##_is_any_nan(xb->fld))) { \ | |
2535 | if (tp##_is_signaling_nan(xa->fld, &env->fp_status) || \ | |
2536 | tp##_is_signaling_nan(xb->fld, &env->fp_status)) { \ | |
13c9115f | 2537 | float_invalid_op_vxsnan(env, GETPC()); \ |
354a6dec TM |
2538 | } \ |
2539 | if (svxvc) { \ | |
13c9115f | 2540 | float_invalid_op_vxvc(env, 0, GETPC()); \ |
354a6dec | 2541 | } \ |
cf3b0334 | 2542 | t.fld = 0; \ |
354a6dec TM |
2543 | all_true = 0; \ |
2544 | } else { \ | |
cf3b0334 MCA |
2545 | if (tp##_##cmp(xb->fld, xa->fld, &env->fp_status) == exp) { \ |
2546 | t.fld = -1; \ | |
354a6dec TM |
2547 | all_false = 0; \ |
2548 | } else { \ | |
cf3b0334 | 2549 | t.fld = 0; \ |
354a6dec TM |
2550 | all_true = 0; \ |
2551 | } \ | |
2552 | } \ | |
2553 | } \ | |
2554 | \ | |
cf3b0334 | 2555 | *xt = t; \ |
00084a25 MCA |
2556 | crf6 = (all_true ? 0x8 : 0) | (all_false ? 0x2 : 0); \ |
2557 | return crf6; \ | |
2558 | } | |
354a6dec | 2559 | |
6db246f9 SB |
2560 | VSX_CMP(xvcmpeqdp, 2, float64, VsrD(i), eq, 0, 1) |
2561 | VSX_CMP(xvcmpgedp, 2, float64, VsrD(i), le, 1, 1) | |
2562 | VSX_CMP(xvcmpgtdp, 2, float64, VsrD(i), lt, 1, 1) | |
2563 | VSX_CMP(xvcmpnedp, 2, float64, VsrD(i), eq, 0, 0) | |
2564 | VSX_CMP(xvcmpeqsp, 4, float32, VsrW(i), eq, 0, 1) | |
2565 | VSX_CMP(xvcmpgesp, 4, float32, VsrW(i), le, 1, 1) | |
2566 | VSX_CMP(xvcmpgtsp, 4, float32, VsrW(i), lt, 1, 1) | |
2567 | VSX_CMP(xvcmpnesp, 4, float32, VsrW(i), eq, 0, 0) | |
ed8ac568 | 2568 | |
fa9ebf8c DG |
2569 | /* |
2570 | * VSX_CVT_FP_TO_FP - VSX floating point/floating point conversion | |
ed8ac568 TM |
2571 | * op - instruction mnemonic |
2572 | * nels - number of elements (1, 2 or 4) | |
2573 | * stp - source type (float32 or float64) | |
2574 | * ttp - target type (float32 or float64) | |
2575 | * sfld - source vsr_t field | |
2576 | * tfld - target vsr_t field (f32 or f64) | |
2577 | * sfprf - set FPRF | |
2578 | */ | |
2579 | #define VSX_CVT_FP_TO_FP(op, nels, stp, ttp, sfld, tfld, sfprf) \ | |
75cf84cb | 2580 | void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ |
ed8ac568 | 2581 | { \ |
cf3b0334 | 2582 | ppc_vsr_t t = *xt; \ |
ed8ac568 TM |
2583 | int i; \ |
2584 | \ | |
ed8ac568 | 2585 | for (i = 0; i < nels; i++) { \ |
cf3b0334 MCA |
2586 | t.tfld = stp##_to_##ttp(xb->sfld, &env->fp_status); \ |
2587 | if (unlikely(stp##_is_signaling_nan(xb->sfld, \ | |
af39bc8c | 2588 | &env->fp_status))) { \ |
13c9115f | 2589 | float_invalid_op_vxsnan(env, GETPC()); \ |
cf3b0334 | 2590 | t.tfld = ttp##_snan_to_qnan(t.tfld); \ |
ed8ac568 TM |
2591 | } \ |
2592 | if (sfprf) { \ | |
cf3b0334 | 2593 | helper_compute_fprf_##ttp(env, t.tfld); \ |
ed8ac568 TM |
2594 | } \ |
2595 | } \ | |
2596 | \ | |
cf3b0334 | 2597 | *xt = t; \ |
6525aadc | 2598 | do_float_check_status(env, GETPC()); \ |
ed8ac568 TM |
2599 | } |
2600 | ||
6bbad7a9 TM |
2601 | VSX_CVT_FP_TO_FP(xscvdpsp, 1, float64, float32, VsrD(0), VsrW(0), 1) |
2602 | VSX_CVT_FP_TO_FP(xscvspdp, 1, float32, float64, VsrW(0), VsrD(0), 1) | |
fa9ebf8c DG |
2603 | VSX_CVT_FP_TO_FP(xvcvdpsp, 2, float64, float32, VsrD(i), VsrW(2 * i), 0) |
2604 | VSX_CVT_FP_TO_FP(xvcvspdp, 2, float32, float64, VsrW(2 * i), VsrD(i), 0) | |
5177d2ca | 2605 | |
fa9ebf8c DG |
2606 | /* |
2607 | * VSX_CVT_FP_TO_FP_VECTOR - VSX floating point/floating point conversion | |
e5487803 BR |
2608 | * op - instruction mnemonic |
2609 | * nels - number of elements (1, 2 or 4) | |
2610 | * stp - source type (float32 or float64) | |
2611 | * ttp - target type (float32 or float64) | |
2612 | * sfld - source vsr_t field | |
2613 | * tfld - target vsr_t field (f32 or f64) | |
2614 | * sfprf - set FPRF | |
2615 | */ | |
2616 | #define VSX_CVT_FP_TO_FP_VECTOR(op, nels, stp, ttp, sfld, tfld, sfprf) \ | |
99229620 MCA |
2617 | void helper_##op(CPUPPCState *env, uint32_t opcode, \ |
2618 | ppc_vsr_t *xt, ppc_vsr_t *xb) \ | |
e5487803 | 2619 | { \ |
cf3b0334 | 2620 | ppc_vsr_t t = *xt; \ |
e5487803 BR |
2621 | int i; \ |
2622 | \ | |
e5487803 | 2623 | for (i = 0; i < nels; i++) { \ |
cf3b0334 MCA |
2624 | t.tfld = stp##_to_##ttp(xb->sfld, &env->fp_status); \ |
2625 | if (unlikely(stp##_is_signaling_nan(xb->sfld, \ | |
e5487803 | 2626 | &env->fp_status))) { \ |
13c9115f | 2627 | float_invalid_op_vxsnan(env, GETPC()); \ |
cf3b0334 | 2628 | t.tfld = ttp##_snan_to_qnan(t.tfld); \ |
e5487803 BR |
2629 | } \ |
2630 | if (sfprf) { \ | |
cf3b0334 | 2631 | helper_compute_fprf_##ttp(env, t.tfld); \ |
e5487803 BR |
2632 | } \ |
2633 | } \ | |
2634 | \ | |
cf3b0334 | 2635 | *xt = t; \ |
6525aadc | 2636 | do_float_check_status(env, GETPC()); \ |
e5487803 BR |
2637 | } |
2638 | ||
2639 | VSX_CVT_FP_TO_FP_VECTOR(xscvdpqp, 1, float64, float128, VsrD(0), f128, 1) | |
2640 | ||
fa9ebf8c DG |
2641 | /* |
2642 | * VSX_CVT_FP_TO_FP_HP - VSX floating point/floating point conversion | |
f566c047 BR |
2643 | * involving one half precision value |
2644 | * op - instruction mnemonic | |
8b920d8a | 2645 | * nels - number of elements (1, 2 or 4) |
f566c047 BR |
2646 | * stp - source type |
2647 | * ttp - target type | |
2648 | * sfld - source vsr_t field | |
2649 | * tfld - target vsr_t field | |
8b920d8a | 2650 | * sfprf - set FPRF |
f566c047 | 2651 | */ |
8b920d8a | 2652 | #define VSX_CVT_FP_TO_FP_HP(op, nels, stp, ttp, sfld, tfld, sfprf) \ |
75cf84cb | 2653 | void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ |
f566c047 | 2654 | { \ |
cf3b0334 | 2655 | ppc_vsr_t t = { }; \ |
8b920d8a | 2656 | int i; \ |
f566c047 | 2657 | \ |
8b920d8a | 2658 | for (i = 0; i < nels; i++) { \ |
cf3b0334 MCA |
2659 | t.tfld = stp##_to_##ttp(xb->sfld, 1, &env->fp_status); \ |
2660 | if (unlikely(stp##_is_signaling_nan(xb->sfld, \ | |
8b920d8a | 2661 | &env->fp_status))) { \ |
13c9115f | 2662 | float_invalid_op_vxsnan(env, GETPC()); \ |
cf3b0334 | 2663 | t.tfld = ttp##_snan_to_qnan(t.tfld); \ |
8b920d8a ND |
2664 | } \ |
2665 | if (sfprf) { \ | |
cf3b0334 | 2666 | helper_compute_fprf_##ttp(env, t.tfld); \ |
8b920d8a | 2667 | } \ |
f566c047 | 2668 | } \ |
f566c047 | 2669 | \ |
cf3b0334 | 2670 | *xt = t; \ |
6525aadc | 2671 | do_float_check_status(env, GETPC()); \ |
f566c047 BR |
2672 | } |
2673 | ||
8b920d8a ND |
2674 | VSX_CVT_FP_TO_FP_HP(xscvdphp, 1, float64, float16, VsrD(0), VsrH(3), 1) |
2675 | VSX_CVT_FP_TO_FP_HP(xscvhpdp, 1, float16, float64, VsrH(3), VsrD(0), 1) | |
2676 | VSX_CVT_FP_TO_FP_HP(xvcvsphp, 4, float32, float16, VsrW(i), VsrH(2 * i + 1), 0) | |
2677 | VSX_CVT_FP_TO_FP_HP(xvcvhpsp, 4, float16, float32, VsrH(2 * i + 1), VsrW(i), 0) | |
f566c047 | 2678 | |
2a084dad BR |
2679 | /* |
2680 | * xscvqpdp isn't using VSX_CVT_FP_TO_FP() because xscvqpdpo will be | |
2681 | * added to this later. | |
2682 | */ | |
e0d6a362 MCA |
2683 | void helper_xscvqpdp(CPUPPCState *env, uint32_t opcode, |
2684 | ppc_vsr_t *xt, ppc_vsr_t *xb) | |
2a084dad | 2685 | { |
cf3b0334 | 2686 | ppc_vsr_t t = { }; |
a8d411ab | 2687 | float_status tstat; |
2a084dad | 2688 | |
a8d411ab | 2689 | tstat = env->fp_status; |
2a084dad | 2690 | if (unlikely(Rc(opcode) != 0)) { |
a8d411ab | 2691 | tstat.float_rounding_mode = float_round_to_odd; |
2a084dad BR |
2692 | } |
2693 | ||
cf3b0334 | 2694 | t.VsrD(0) = float128_to_float64(xb->f128, &tstat); |
a8d411ab | 2695 | env->fp_status.float_exception_flags |= tstat.float_exception_flags; |
cf3b0334 | 2696 | if (unlikely(float128_is_signaling_nan(xb->f128, &tstat))) { |
13c9115f | 2697 | float_invalid_op_vxsnan(env, GETPC()); |
cf3b0334 | 2698 | t.VsrD(0) = float64_snan_to_qnan(t.VsrD(0)); |
2a084dad | 2699 | } |
cf3b0334 | 2700 | helper_compute_fprf_float64(env, t.VsrD(0)); |
2a084dad | 2701 | |
cf3b0334 | 2702 | *xt = t; |
6525aadc | 2703 | do_float_check_status(env, GETPC()); |
2a084dad BR |
2704 | } |
2705 | ||
7ee19fb9 TM |
2706 | uint64_t helper_xscvdpspn(CPUPPCState *env, uint64_t xb) |
2707 | { | |
fa7d9cb9 | 2708 | uint64_t result, sign, exp, frac; |
e6f1bfb2 | 2709 | |
7ee19fb9 TM |
2710 | float_status tstat = env->fp_status; |
2711 | set_float_exception_flags(0, &tstat); | |
2712 | ||
fa7d9cb9 PC |
2713 | sign = extract64(xb, 63, 1); |
2714 | exp = extract64(xb, 52, 11); | |
2715 | frac = extract64(xb, 0, 52) | 0x10000000000000ULL; | |
2716 | ||
2717 | if (unlikely(exp == 0 && extract64(frac, 0, 52) != 0)) { | |
2718 | /* DP denormal operand. */ | |
2719 | /* Exponent override to DP min exp. */ | |
2720 | exp = 1; | |
2721 | /* Implicit bit override to 0. */ | |
2722 | frac = deposit64(frac, 53, 1, 0); | |
2723 | } | |
2724 | ||
2725 | if (unlikely(exp < 897 && frac != 0)) { | |
2726 | /* SP tiny operand. */ | |
2727 | if (897 - exp > 63) { | |
2728 | frac = 0; | |
2729 | } else { | |
2730 | /* Denormalize until exp = SP min exp. */ | |
2731 | frac >>= (897 - exp); | |
2732 | } | |
2733 | /* Exponent override to SP min exp - 1. */ | |
2734 | exp = 896; | |
2735 | } | |
2736 | ||
2737 | result = sign << 31; | |
2738 | result |= extract64(exp, 10, 1) << 30; | |
2739 | result |= extract64(exp, 0, 7) << 23; | |
2740 | result |= extract64(frac, 29, 23); | |
2741 | ||
e6f1bfb2 PC |
2742 | /* hardware replicates result to both words of the doubleword result. */ |
2743 | return (result << 32) | result; | |
7ee19fb9 TM |
2744 | } |
2745 | ||
2746 | uint64_t helper_xscvspdpn(CPUPPCState *env, uint64_t xb) | |
2747 | { | |
2748 | float_status tstat = env->fp_status; | |
2749 | set_float_exception_flags(0, &tstat); | |
2750 | ||
2751 | return float32_to_float64(xb >> 32, &tstat); | |
2752 | } | |
2753 | ||
fa9ebf8c DG |
2754 | /* |
2755 | * VSX_CVT_FP_TO_INT - VSX floating point to integer conversion | |
5177d2ca TM |
2756 | * op - instruction mnemonic |
2757 | * nels - number of elements (1, 2 or 4) | |
2758 | * stp - source type (float32 or float64) | |
2759 | * ttp - target type (int32, uint32, int64 or uint64) | |
2760 | * sfld - source vsr_t field | |
2761 | * tfld - target vsr_t field | |
5177d2ca TM |
2762 | * rnan - resulting NaN |
2763 | */ | |
d1dec5ef | 2764 | #define VSX_CVT_FP_TO_INT(op, nels, stp, ttp, sfld, tfld, rnan) \ |
75cf84cb | 2765 | void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ |
5177d2ca | 2766 | { \ |
a3dec427 | 2767 | int all_flags = env->fp_status.float_exception_flags, flags; \ |
cf3b0334 | 2768 | ppc_vsr_t t = *xt; \ |
5177d2ca TM |
2769 | int i; \ |
2770 | \ | |
5177d2ca | 2771 | for (i = 0; i < nels; i++) { \ |
a3dec427 | 2772 | env->fp_status.float_exception_flags = 0; \ |
cf3b0334 | 2773 | t.tfld = stp##_to_##ttp##_round_to_zero(xb->sfld, &env->fp_status); \ |
a3dec427 RH |
2774 | flags = env->fp_status.float_exception_flags; \ |
2775 | if (unlikely(flags & float_flag_invalid)) { \ | |
cf3b0334 MCA |
2776 | float_invalid_cvt(env, 0, GETPC(), stp##_classify(xb->sfld)); \ |
2777 | t.tfld = rnan; \ | |
5177d2ca | 2778 | } \ |
a3dec427 | 2779 | all_flags |= flags; \ |
5177d2ca TM |
2780 | } \ |
2781 | \ | |
cf3b0334 | 2782 | *xt = t; \ |
a3dec427 | 2783 | env->fp_status.float_exception_flags = all_flags; \ |
6525aadc | 2784 | do_float_check_status(env, GETPC()); \ |
5177d2ca TM |
2785 | } |
2786 | ||
d1dec5ef | 2787 | VSX_CVT_FP_TO_INT(xscvdpsxds, 1, float64, int64, VsrD(0), VsrD(0), \ |
7dff9abe | 2788 | 0x8000000000000000ULL) |
d1dec5ef TM |
2789 | VSX_CVT_FP_TO_INT(xscvdpsxws, 1, float64, int32, VsrD(0), VsrW(1), \ |
2790 | 0x80000000U) | |
2791 | VSX_CVT_FP_TO_INT(xscvdpuxds, 1, float64, uint64, VsrD(0), VsrD(0), 0ULL) | |
2792 | VSX_CVT_FP_TO_INT(xscvdpuxws, 1, float64, uint32, VsrD(0), VsrW(1), 0U) | |
2793 | VSX_CVT_FP_TO_INT(xvcvdpsxds, 2, float64, int64, VsrD(i), VsrD(i), \ | |
7dff9abe | 2794 | 0x8000000000000000ULL) |
fa9ebf8c | 2795 | VSX_CVT_FP_TO_INT(xvcvdpsxws, 2, float64, int32, VsrD(i), VsrW(2 * i), \ |
7dff9abe | 2796 | 0x80000000U) |
d1dec5ef | 2797 | VSX_CVT_FP_TO_INT(xvcvdpuxds, 2, float64, uint64, VsrD(i), VsrD(i), 0ULL) |
fa9ebf8c DG |
2798 | VSX_CVT_FP_TO_INT(xvcvdpuxws, 2, float64, uint32, VsrD(i), VsrW(2 * i), 0U) |
2799 | VSX_CVT_FP_TO_INT(xvcvspsxds, 2, float32, int64, VsrW(2 * i), VsrD(i), \ | |
d1dec5ef TM |
2800 | 0x8000000000000000ULL) |
2801 | VSX_CVT_FP_TO_INT(xvcvspsxws, 4, float32, int32, VsrW(i), VsrW(i), 0x80000000U) | |
fa9ebf8c | 2802 | VSX_CVT_FP_TO_INT(xvcvspuxds, 2, float32, uint64, VsrW(2 * i), VsrD(i), 0ULL) |
d1dec5ef | 2803 | VSX_CVT_FP_TO_INT(xvcvspuxws, 4, float32, uint32, VsrW(i), VsrW(i), 0U) |
5177d2ca | 2804 | |
fa9ebf8c DG |
2805 | /* |
2806 | * VSX_CVT_FP_TO_INT_VECTOR - VSX floating point to integer conversion | |
05590b92 BR |
2807 | * op - instruction mnemonic |
2808 | * stp - source type (float32 or float64) | |
2809 | * ttp - target type (int32, uint32, int64 or uint64) | |
2810 | * sfld - source vsr_t field | |
2811 | * tfld - target vsr_t field | |
2812 | * rnan - resulting NaN | |
2813 | */ | |
2814 | #define VSX_CVT_FP_TO_INT_VECTOR(op, stp, ttp, sfld, tfld, rnan) \ | |
99229620 MCA |
2815 | void helper_##op(CPUPPCState *env, uint32_t opcode, \ |
2816 | ppc_vsr_t *xt, ppc_vsr_t *xb) \ | |
05590b92 | 2817 | { \ |
cf3b0334 | 2818 | ppc_vsr_t t = { }; \ |
05590b92 | 2819 | \ |
cf3b0334 | 2820 | t.tfld = stp##_to_##ttp##_round_to_zero(xb->sfld, &env->fp_status); \ |
a3dec427 | 2821 | if (env->fp_status.float_exception_flags & float_flag_invalid) { \ |
cf3b0334 MCA |
2822 | float_invalid_cvt(env, 0, GETPC(), stp##_classify(xb->sfld)); \ |
2823 | t.tfld = rnan; \ | |
05590b92 BR |
2824 | } \ |
2825 | \ | |
cf3b0334 | 2826 | *xt = t; \ |
6525aadc | 2827 | do_float_check_status(env, GETPC()); \ |
05590b92 BR |
2828 | } |
2829 | ||
2830 | VSX_CVT_FP_TO_INT_VECTOR(xscvqpsdz, float128, int64, f128, VsrD(0), \ | |
2831 | 0x8000000000000000ULL) | |
2832 | ||
2833 | VSX_CVT_FP_TO_INT_VECTOR(xscvqpswz, float128, int32, f128, VsrD(0), \ | |
2834 | 0xffffffff80000000ULL) | |
e0aee726 BR |
2835 | VSX_CVT_FP_TO_INT_VECTOR(xscvqpudz, float128, uint64, f128, VsrD(0), 0x0ULL) |
2836 | VSX_CVT_FP_TO_INT_VECTOR(xscvqpuwz, float128, uint32, f128, VsrD(0), 0x0ULL) | |
05590b92 | 2837 | |
fa9ebf8c DG |
2838 | /* |
2839 | * VSX_CVT_INT_TO_FP - VSX integer to floating point conversion | |
5177d2ca TM |
2840 | * op - instruction mnemonic |
2841 | * nels - number of elements (1, 2 or 4) | |
2842 | * stp - source type (int32, uint32, int64 or uint64) | |
2843 | * ttp - target type (float32 or float64) | |
2844 | * sfld - source vsr_t field | |
2845 | * tfld - target vsr_t field | |
2846 | * jdef - definition of the j index (i or 2*i) | |
2847 | * sfprf - set FPRF | |
2848 | */ | |
6cd7db3d | 2849 | #define VSX_CVT_INT_TO_FP(op, nels, stp, ttp, sfld, tfld, sfprf, r2sp) \ |
75cf84cb | 2850 | void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ |
5177d2ca | 2851 | { \ |
cf3b0334 | 2852 | ppc_vsr_t t = *xt; \ |
5177d2ca TM |
2853 | int i; \ |
2854 | \ | |
5177d2ca | 2855 | for (i = 0; i < nels; i++) { \ |
cf3b0334 | 2856 | t.tfld = stp##_to_##ttp(xb->sfld, &env->fp_status); \ |
74698350 | 2857 | if (r2sp) { \ |
cf3b0334 | 2858 | t.tfld = helper_frsp(env, t.tfld); \ |
74698350 | 2859 | } \ |
5177d2ca | 2860 | if (sfprf) { \ |
cf3b0334 | 2861 | helper_compute_fprf_float64(env, t.tfld); \ |
5177d2ca TM |
2862 | } \ |
2863 | } \ | |
2864 | \ | |
cf3b0334 | 2865 | *xt = t; \ |
6525aadc | 2866 | do_float_check_status(env, GETPC()); \ |
5177d2ca TM |
2867 | } |
2868 | ||
6cd7db3d TM |
2869 | VSX_CVT_INT_TO_FP(xscvsxddp, 1, int64, float64, VsrD(0), VsrD(0), 1, 0) |
2870 | VSX_CVT_INT_TO_FP(xscvuxddp, 1, uint64, float64, VsrD(0), VsrD(0), 1, 0) | |
2871 | VSX_CVT_INT_TO_FP(xscvsxdsp, 1, int64, float64, VsrD(0), VsrD(0), 1, 1) | |
2872 | VSX_CVT_INT_TO_FP(xscvuxdsp, 1, uint64, float64, VsrD(0), VsrD(0), 1, 1) | |
2873 | VSX_CVT_INT_TO_FP(xvcvsxddp, 2, int64, float64, VsrD(i), VsrD(i), 0, 0) | |
2874 | VSX_CVT_INT_TO_FP(xvcvuxddp, 2, uint64, float64, VsrD(i), VsrD(i), 0, 0) | |
fa9ebf8c DG |
2875 | VSX_CVT_INT_TO_FP(xvcvsxwdp, 2, int32, float64, VsrW(2 * i), VsrD(i), 0, 0) |
2876 | VSX_CVT_INT_TO_FP(xvcvuxwdp, 2, uint64, float64, VsrW(2 * i), VsrD(i), 0, 0) | |
2877 | VSX_CVT_INT_TO_FP(xvcvsxdsp, 2, int64, float32, VsrD(i), VsrW(2 * i), 0, 0) | |
2878 | VSX_CVT_INT_TO_FP(xvcvuxdsp, 2, uint64, float32, VsrD(i), VsrW(2 * i), 0, 0) | |
6cd7db3d TM |
2879 | VSX_CVT_INT_TO_FP(xvcvsxwsp, 4, int32, float32, VsrW(i), VsrW(i), 0, 0) |
2880 | VSX_CVT_INT_TO_FP(xvcvuxwsp, 4, uint32, float32, VsrW(i), VsrW(i), 0, 0) | |
88e33d08 | 2881 | |
fa9ebf8c DG |
2882 | /* |
2883 | * VSX_CVT_INT_TO_FP_VECTOR - VSX integer to floating point conversion | |
48ef23cb BR |
2884 | * op - instruction mnemonic |
2885 | * stp - source type (int32, uint32, int64 or uint64) | |
2886 | * ttp - target type (float32 or float64) | |
2887 | * sfld - source vsr_t field | |
2888 | * tfld - target vsr_t field | |
2889 | */ | |
2890 | #define VSX_CVT_INT_TO_FP_VECTOR(op, stp, ttp, sfld, tfld) \ | |
99229620 MCA |
2891 | void helper_##op(CPUPPCState *env, uint32_t opcode, \ |
2892 | ppc_vsr_t *xt, ppc_vsr_t *xb) \ | |
48ef23cb | 2893 | { \ |
cf3b0334 | 2894 | ppc_vsr_t t = *xt; \ |
48ef23cb | 2895 | \ |
cf3b0334 MCA |
2896 | t.tfld = stp##_to_##ttp(xb->sfld, &env->fp_status); \ |
2897 | helper_compute_fprf_##ttp(env, t.tfld); \ | |
48ef23cb | 2898 | \ |
cf3b0334 | 2899 | *xt = t; \ |
6525aadc | 2900 | do_float_check_status(env, GETPC()); \ |
48ef23cb BR |
2901 | } |
2902 | ||
2903 | VSX_CVT_INT_TO_FP_VECTOR(xscvsdqp, int64, float128, VsrD(0), f128) | |
2904 | VSX_CVT_INT_TO_FP_VECTOR(xscvudqp, uint64, float128, VsrD(0), f128) | |
2905 | ||
fa9ebf8c DG |
2906 | /* |
2907 | * For "use current rounding mode", define a value that will not be | |
2908 | * one of the existing rounding model enums. | |
88e33d08 TM |
2909 | */ |
2910 | #define FLOAT_ROUND_CURRENT (float_round_nearest_even + float_round_down + \ | |
2911 | float_round_up + float_round_to_zero) | |
2912 | ||
fa9ebf8c DG |
2913 | /* |
2914 | * VSX_ROUND - VSX floating point round | |
88e33d08 TM |
2915 | * op - instruction mnemonic |
2916 | * nels - number of elements (1, 2 or 4) | |
2917 | * tp - type (float32 or float64) | |
bcb7652e | 2918 | * fld - vsr_t field (VsrD(*) or VsrW(*)) |
88e33d08 TM |
2919 | * rmode - rounding mode |
2920 | * sfprf - set FPRF | |
2921 | */ | |
2922 | #define VSX_ROUND(op, nels, tp, fld, rmode, sfprf) \ | |
75cf84cb | 2923 | void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \ |
88e33d08 | 2924 | { \ |
cf3b0334 | 2925 | ppc_vsr_t t = *xt; \ |
88e33d08 | 2926 | int i; \ |
63d06e90 | 2927 | FloatRoundMode curr_rounding_mode; \ |
88e33d08 TM |
2928 | \ |
2929 | if (rmode != FLOAT_ROUND_CURRENT) { \ | |
63d06e90 | 2930 | curr_rounding_mode = get_float_rounding_mode(&env->fp_status); \ |
88e33d08 TM |
2931 | set_float_rounding_mode(rmode, &env->fp_status); \ |
2932 | } \ | |
2933 | \ | |
2934 | for (i = 0; i < nels; i++) { \ | |
cf3b0334 | 2935 | if (unlikely(tp##_is_signaling_nan(xb->fld, \ |
af39bc8c | 2936 | &env->fp_status))) { \ |
13c9115f | 2937 | float_invalid_op_vxsnan(env, GETPC()); \ |
cf3b0334 | 2938 | t.fld = tp##_snan_to_qnan(xb->fld); \ |
88e33d08 | 2939 | } else { \ |
cf3b0334 | 2940 | t.fld = tp##_round_to_int(xb->fld, &env->fp_status); \ |
88e33d08 TM |
2941 | } \ |
2942 | if (sfprf) { \ | |
cf3b0334 | 2943 | helper_compute_fprf_float64(env, t.fld); \ |
88e33d08 TM |
2944 | } \ |
2945 | } \ | |
2946 | \ | |
fa9ebf8c DG |
2947 | /* \ |
2948 | * If this is not a "use current rounding mode" instruction, \ | |
88e33d08 | 2949 | * then inhibit setting of the XX bit and restore rounding \ |
fa9ebf8c DG |
2950 | * mode from FPSCR \ |
2951 | */ \ | |
88e33d08 | 2952 | if (rmode != FLOAT_ROUND_CURRENT) { \ |
63d06e90 | 2953 | set_float_rounding_mode(curr_rounding_mode, &env->fp_status); \ |
88e33d08 TM |
2954 | env->fp_status.float_exception_flags &= ~float_flag_inexact; \ |
2955 | } \ | |
2956 | \ | |
cf3b0334 | 2957 | *xt = t; \ |
6525aadc | 2958 | do_float_check_status(env, GETPC()); \ |
88e33d08 TM |
2959 | } |
2960 | ||
158c87e5 | 2961 | VSX_ROUND(xsrdpi, 1, float64, VsrD(0), float_round_ties_away, 1) |
bcb7652e TM |
2962 | VSX_ROUND(xsrdpic, 1, float64, VsrD(0), FLOAT_ROUND_CURRENT, 1) |
2963 | VSX_ROUND(xsrdpim, 1, float64, VsrD(0), float_round_down, 1) | |
2964 | VSX_ROUND(xsrdpip, 1, float64, VsrD(0), float_round_up, 1) | |
2965 | VSX_ROUND(xsrdpiz, 1, float64, VsrD(0), float_round_to_zero, 1) | |
88e33d08 | 2966 | |
158c87e5 | 2967 | VSX_ROUND(xvrdpi, 2, float64, VsrD(i), float_round_ties_away, 0) |
bcb7652e TM |
2968 | VSX_ROUND(xvrdpic, 2, float64, VsrD(i), FLOAT_ROUND_CURRENT, 0) |
2969 | VSX_ROUND(xvrdpim, 2, float64, VsrD(i), float_round_down, 0) | |
2970 | VSX_ROUND(xvrdpip, 2, float64, VsrD(i), float_round_up, 0) | |
2971 | VSX_ROUND(xvrdpiz, 2, float64, VsrD(i), float_round_to_zero, 0) | |
88e33d08 | 2972 | |
158c87e5 | 2973 | VSX_ROUND(xvrspi, 4, float32, VsrW(i), float_round_ties_away, 0) |
bcb7652e TM |
2974 | VSX_ROUND(xvrspic, 4, float32, VsrW(i), FLOAT_ROUND_CURRENT, 0) |
2975 | VSX_ROUND(xvrspim, 4, float32, VsrW(i), float_round_down, 0) | |
2976 | VSX_ROUND(xvrspip, 4, float32, VsrW(i), float_round_up, 0) | |
2977 | VSX_ROUND(xvrspiz, 4, float32, VsrW(i), float_round_to_zero, 0) | |
3d1140bf TM |
2978 | |
2979 | uint64_t helper_xsrsp(CPUPPCState *env, uint64_t xb) | |
2980 | { | |
2981 | helper_reset_fpstatus(env); | |
2982 | ||
2983 | uint64_t xt = helper_frsp(env, xb); | |
2984 | ||
ffc67420 | 2985 | helper_compute_fprf_float64(env, xt); |
6525aadc | 2986 | do_float_check_status(env, GETPC()); |
3d1140bf TM |
2987 | return xt; |
2988 | } | |
234068ab BR |
2989 | |
2990 | #define VSX_XXPERM(op, indexed) \ | |
99125c74 MCA |
2991 | void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \ |
2992 | ppc_vsr_t *xa, ppc_vsr_t *pcv) \ | |
234068ab | 2993 | { \ |
cf3b0334 | 2994 | ppc_vsr_t t = *xt; \ |
234068ab BR |
2995 | int i, idx; \ |
2996 | \ | |
234068ab | 2997 | for (i = 0; i < 16; i++) { \ |
cf3b0334 | 2998 | idx = pcv->VsrB(i) & 0x1F; \ |
234068ab BR |
2999 | if (indexed) { \ |
3000 | idx = 31 - idx; \ | |
3001 | } \ | |
cf3b0334 MCA |
3002 | t.VsrB(i) = (idx <= 15) ? xa->VsrB(idx) \ |
3003 | : xt->VsrB(idx - 16); \ | |
234068ab | 3004 | } \ |
cf3b0334 | 3005 | *xt = t; \ |
234068ab BR |
3006 | } |
3007 | ||
3008 | VSX_XXPERM(xxperm, 0) | |
3009 | VSX_XXPERM(xxpermr, 1) | |
c5969d2e | 3010 | |
75cf84cb | 3011 | void helper_xvxsigsp(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) |
c5969d2e | 3012 | { |
cf3b0334 | 3013 | ppc_vsr_t t = { }; |
c5969d2e ND |
3014 | uint32_t exp, i, fraction; |
3015 | ||
c5969d2e | 3016 | for (i = 0; i < 4; i++) { |
cf3b0334 MCA |
3017 | exp = (xb->VsrW(i) >> 23) & 0xFF; |
3018 | fraction = xb->VsrW(i) & 0x7FFFFF; | |
c5969d2e | 3019 | if (exp != 0 && exp != 255) { |
cf3b0334 | 3020 | t.VsrW(i) = fraction | 0x00800000; |
c5969d2e | 3021 | } else { |
cf3b0334 | 3022 | t.VsrW(i) = fraction; |
c5969d2e ND |
3023 | } |
3024 | } | |
cf3b0334 | 3025 | *xt = t; |
c5969d2e | 3026 | } |
403a884a | 3027 | |
fa9ebf8c DG |
3028 | /* |
3029 | * VSX_TEST_DC - VSX floating point test data class | |
403a884a ND |
3030 | * op - instruction mnemonic |
3031 | * nels - number of elements (1, 2 or 4) | |
3032 | * xbn - VSR register number | |
3033 | * tp - type (float32 or float64) | |
3034 | * fld - vsr_t field (VsrD(*) or VsrW(*)) | |
3035 | * tfld - target vsr_t field (VsrD(*) or VsrW(*)) | |
3036 | * fld_max - target field max | |
78241762 | 3037 | * scrf - set result in CR and FPCC |
403a884a | 3038 | */ |
78241762 | 3039 | #define VSX_TEST_DC(op, nels, xbn, tp, fld, tfld, fld_max, scrf) \ |
403a884a ND |
3040 | void helper_##op(CPUPPCState *env, uint32_t opcode) \ |
3041 | { \ | |
cf3b0334 MCA |
3042 | ppc_vsr_t *xt = &env->vsr[xT(opcode)]; \ |
3043 | ppc_vsr_t *xb = &env->vsr[xbn]; \ | |
3044 | ppc_vsr_t t = { }; \ | |
403a884a | 3045 | uint32_t i, sign, dcmx; \ |
78241762 | 3046 | uint32_t cc, match = 0; \ |
403a884a | 3047 | \ |
78241762 | 3048 | if (!scrf) { \ |
78241762 ND |
3049 | dcmx = DCMX_XV(opcode); \ |
3050 | } else { \ | |
cf3b0334 | 3051 | t = *xt; \ |
78241762 ND |
3052 | dcmx = DCMX(opcode); \ |
3053 | } \ | |
403a884a ND |
3054 | \ |
3055 | for (i = 0; i < nels; i++) { \ | |
cf3b0334 MCA |
3056 | sign = tp##_is_neg(xb->fld); \ |
3057 | if (tp##_is_any_nan(xb->fld)) { \ | |
403a884a | 3058 | match = extract32(dcmx, 6, 1); \ |
cf3b0334 | 3059 | } else if (tp##_is_infinity(xb->fld)) { \ |
403a884a | 3060 | match = extract32(dcmx, 4 + !sign, 1); \ |
cf3b0334 | 3061 | } else if (tp##_is_zero(xb->fld)) { \ |
403a884a | 3062 | match = extract32(dcmx, 2 + !sign, 1); \ |
cf3b0334 | 3063 | } else if (tp##_is_zero_or_denormal(xb->fld)) { \ |
403a884a ND |
3064 | match = extract32(dcmx, 0 + !sign, 1); \ |
3065 | } \ | |
78241762 ND |
3066 | \ |
3067 | if (scrf) { \ | |
3068 | cc = sign << CRF_LT_BIT | match << CRF_EQ_BIT; \ | |
5c94dd38 PC |
3069 | env->fpscr &= ~FP_FPCC; \ |
3070 | env->fpscr |= cc << FPSCR_FPCC; \ | |
78241762 ND |
3071 | env->crf[BF(opcode)] = cc; \ |
3072 | } else { \ | |
cf3b0334 | 3073 | t.tfld = match ? fld_max : 0; \ |
78241762 | 3074 | } \ |
403a884a ND |
3075 | match = 0; \ |
3076 | } \ | |
78241762 | 3077 | if (!scrf) { \ |
cf3b0334 | 3078 | *xt = t; \ |
78241762 | 3079 | } \ |
403a884a ND |
3080 | } |
3081 | ||
78241762 ND |
3082 | VSX_TEST_DC(xvtstdcdp, 2, xB(opcode), float64, VsrD(i), VsrD(i), UINT64_MAX, 0) |
3083 | VSX_TEST_DC(xvtstdcsp, 4, xB(opcode), float32, VsrW(i), VsrW(i), UINT32_MAX, 0) | |
3084 | VSX_TEST_DC(xststdcdp, 1, xB(opcode), float64, VsrD(0), VsrD(0), 0, 1) | |
3085 | VSX_TEST_DC(xststdcqp, 1, (rB(opcode) + 32), float128, f128, VsrD(0), 0, 1) | |
3086 | ||
8d830485 | 3087 | void helper_xststdcsp(CPUPPCState *env, uint32_t opcode, ppc_vsr_t *xb) |
78241762 | 3088 | { |
78241762 ND |
3089 | uint32_t dcmx, sign, exp; |
3090 | uint32_t cc, match = 0, not_sp = 0; | |
3091 | ||
78241762 | 3092 | dcmx = DCMX(opcode); |
cf3b0334 | 3093 | exp = (xb->VsrD(0) >> 52) & 0x7FF; |
78241762 | 3094 | |
cf3b0334 MCA |
3095 | sign = float64_is_neg(xb->VsrD(0)); |
3096 | if (float64_is_any_nan(xb->VsrD(0))) { | |
78241762 | 3097 | match = extract32(dcmx, 6, 1); |
cf3b0334 | 3098 | } else if (float64_is_infinity(xb->VsrD(0))) { |
78241762 | 3099 | match = extract32(dcmx, 4 + !sign, 1); |
cf3b0334 | 3100 | } else if (float64_is_zero(xb->VsrD(0))) { |
78241762 | 3101 | match = extract32(dcmx, 2 + !sign, 1); |
cf3b0334 | 3102 | } else if (float64_is_zero_or_denormal(xb->VsrD(0)) || |
78241762 ND |
3103 | (exp > 0 && exp < 0x381)) { |
3104 | match = extract32(dcmx, 0 + !sign, 1); | |
3105 | } | |
3106 | ||
cf3b0334 | 3107 | not_sp = !float64_eq(xb->VsrD(0), |
78241762 | 3108 | float32_to_float64( |
cf3b0334 | 3109 | float64_to_float32(xb->VsrD(0), &env->fp_status), |
78241762 ND |
3110 | &env->fp_status), &env->fp_status); |
3111 | ||
3112 | cc = sign << CRF_LT_BIT | match << CRF_EQ_BIT | not_sp << CRF_SO_BIT; | |
5c94dd38 PC |
3113 | env->fpscr &= ~FP_FPCC; |
3114 | env->fpscr |= cc << FPSCR_FPCC; | |
78241762 ND |
3115 | env->crf[BF(opcode)] = cc; |
3116 | } | |
be07ad58 | 3117 | |
99229620 MCA |
3118 | void helper_xsrqpi(CPUPPCState *env, uint32_t opcode, |
3119 | ppc_vsr_t *xt, ppc_vsr_t *xb) | |
be07ad58 | 3120 | { |
cf3b0334 | 3121 | ppc_vsr_t t = { }; |
be07ad58 JRZ |
3122 | uint8_t r = Rrm(opcode); |
3123 | uint8_t ex = Rc(opcode); | |
3124 | uint8_t rmc = RMC(opcode); | |
3125 | uint8_t rmode = 0; | |
3126 | float_status tstat; | |
3127 | ||
be07ad58 JRZ |
3128 | helper_reset_fpstatus(env); |
3129 | ||
3130 | if (r == 0 && rmc == 0) { | |
3131 | rmode = float_round_ties_away; | |
3132 | } else if (r == 0 && rmc == 0x3) { | |
3133 | rmode = fpscr_rn; | |
3134 | } else if (r == 1) { | |
3135 | switch (rmc) { | |
3136 | case 0: | |
3137 | rmode = float_round_nearest_even; | |
3138 | break; | |
3139 | case 1: | |
3140 | rmode = float_round_to_zero; | |
3141 | break; | |
3142 | case 2: | |
3143 | rmode = float_round_up; | |
3144 | break; | |
3145 | case 3: | |
3146 | rmode = float_round_down; | |
3147 | break; | |
3148 | default: | |
3149 | abort(); | |
3150 | } | |
3151 | } | |
3152 | ||
3153 | tstat = env->fp_status; | |
3154 | set_float_exception_flags(0, &tstat); | |
3155 | set_float_rounding_mode(rmode, &tstat); | |
cf3b0334 | 3156 | t.f128 = float128_round_to_int(xb->f128, &tstat); |
be07ad58 JRZ |
3157 | env->fp_status.float_exception_flags |= tstat.float_exception_flags; |
3158 | ||
3159 | if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { | |
cf3b0334 | 3160 | if (float128_is_signaling_nan(xb->f128, &tstat)) { |
13c9115f | 3161 | float_invalid_op_vxsnan(env, GETPC()); |
cf3b0334 | 3162 | t.f128 = float128_snan_to_qnan(t.f128); |
be07ad58 JRZ |
3163 | } |
3164 | } | |
3165 | ||
3166 | if (ex == 0 && (tstat.float_exception_flags & float_flag_inexact)) { | |
3167 | env->fp_status.float_exception_flags &= ~float_flag_inexact; | |
3168 | } | |
3169 | ||
cf3b0334 | 3170 | helper_compute_fprf_float128(env, t.f128); |
6525aadc | 3171 | do_float_check_status(env, GETPC()); |
cf3b0334 | 3172 | *xt = t; |
be07ad58 | 3173 | } |
917950d7 | 3174 | |
99229620 MCA |
3175 | void helper_xsrqpxp(CPUPPCState *env, uint32_t opcode, |
3176 | ppc_vsr_t *xt, ppc_vsr_t *xb) | |
917950d7 | 3177 | { |
cf3b0334 | 3178 | ppc_vsr_t t = { }; |
917950d7 JRZ |
3179 | uint8_t r = Rrm(opcode); |
3180 | uint8_t rmc = RMC(opcode); | |
3181 | uint8_t rmode = 0; | |
3182 | floatx80 round_res; | |
3183 | float_status tstat; | |
3184 | ||
917950d7 JRZ |
3185 | helper_reset_fpstatus(env); |
3186 | ||
3187 | if (r == 0 && rmc == 0) { | |
3188 | rmode = float_round_ties_away; | |
3189 | } else if (r == 0 && rmc == 0x3) { | |
3190 | rmode = fpscr_rn; | |
3191 | } else if (r == 1) { | |
3192 | switch (rmc) { | |
3193 | case 0: | |
3194 | rmode = float_round_nearest_even; | |
3195 | break; | |
3196 | case 1: | |
3197 | rmode = float_round_to_zero; | |
3198 | break; | |
3199 | case 2: | |
3200 | rmode = float_round_up; | |
3201 | break; | |
3202 | case 3: | |
3203 | rmode = float_round_down; | |
3204 | break; | |
3205 | default: | |
3206 | abort(); | |
3207 | } | |
3208 | } | |
3209 | ||
3210 | tstat = env->fp_status; | |
3211 | set_float_exception_flags(0, &tstat); | |
3212 | set_float_rounding_mode(rmode, &tstat); | |
cf3b0334 MCA |
3213 | round_res = float128_to_floatx80(xb->f128, &tstat); |
3214 | t.f128 = floatx80_to_float128(round_res, &tstat); | |
917950d7 JRZ |
3215 | env->fp_status.float_exception_flags |= tstat.float_exception_flags; |
3216 | ||
3217 | if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { | |
cf3b0334 | 3218 | if (float128_is_signaling_nan(xb->f128, &tstat)) { |
13c9115f | 3219 | float_invalid_op_vxsnan(env, GETPC()); |
cf3b0334 | 3220 | t.f128 = float128_snan_to_qnan(t.f128); |
917950d7 JRZ |
3221 | } |
3222 | } | |
3223 | ||
cf3b0334 MCA |
3224 | helper_compute_fprf_float128(env, t.f128); |
3225 | *xt = t; | |
6525aadc | 3226 | do_float_check_status(env, GETPC()); |
917950d7 | 3227 | } |
a4a68476 | 3228 | |
99229620 MCA |
3229 | void helper_xssqrtqp(CPUPPCState *env, uint32_t opcode, |
3230 | ppc_vsr_t *xt, ppc_vsr_t *xb) | |
a4a68476 | 3231 | { |
cf3b0334 | 3232 | ppc_vsr_t t = { }; |
a4a68476 JRZ |
3233 | float_status tstat; |
3234 | ||
a4a68476 JRZ |
3235 | helper_reset_fpstatus(env); |
3236 | ||
a8d411ab | 3237 | tstat = env->fp_status; |
a4a68476 | 3238 | if (unlikely(Rc(opcode) != 0)) { |
a8d411ab | 3239 | tstat.float_rounding_mode = float_round_to_odd; |
a4a68476 JRZ |
3240 | } |
3241 | ||
a4a68476 | 3242 | set_float_exception_flags(0, &tstat); |
cf3b0334 | 3243 | t.f128 = float128_sqrt(xb->f128, &tstat); |
a4a68476 JRZ |
3244 | env->fp_status.float_exception_flags |= tstat.float_exception_flags; |
3245 | ||
3246 | if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { | |
cf3b0334 | 3247 | if (float128_is_signaling_nan(xb->f128, &tstat)) { |
13c9115f | 3248 | float_invalid_op_vxsnan(env, GETPC()); |
cf3b0334 MCA |
3249 | t.f128 = float128_snan_to_qnan(xb->f128); |
3250 | } else if (float128_is_quiet_nan(xb->f128, &tstat)) { | |
3251 | t.f128 = xb->f128; | |
3252 | } else if (float128_is_neg(xb->f128) && !float128_is_zero(xb->f128)) { | |
13c9115f | 3253 | float_invalid_op_vxsqrt(env, 1, GETPC()); |
cf3b0334 | 3254 | t.f128 = float128_default_nan(&env->fp_status); |
a4a68476 JRZ |
3255 | } |
3256 | } | |
3257 | ||
cf3b0334 MCA |
3258 | helper_compute_fprf_float128(env, t.f128); |
3259 | *xt = t; | |
6525aadc | 3260 | do_float_check_status(env, GETPC()); |
a4a68476 | 3261 | } |
f6b99afd | 3262 | |
23d0766b MCA |
3263 | void helper_xssubqp(CPUPPCState *env, uint32_t opcode, |
3264 | ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb) | |
f6b99afd | 3265 | { |
cf3b0334 | 3266 | ppc_vsr_t t = *xt; |
f6b99afd JRZ |
3267 | float_status tstat; |
3268 | ||
f6b99afd JRZ |
3269 | helper_reset_fpstatus(env); |
3270 | ||
a8d411ab | 3271 | tstat = env->fp_status; |
f6b99afd | 3272 | if (unlikely(Rc(opcode) != 0)) { |
a8d411ab | 3273 | tstat.float_rounding_mode = float_round_to_odd; |
f6b99afd JRZ |
3274 | } |
3275 | ||
f6b99afd | 3276 | set_float_exception_flags(0, &tstat); |
cf3b0334 | 3277 | t.f128 = float128_sub(xa->f128, xb->f128, &tstat); |
f6b99afd JRZ |
3278 | env->fp_status.float_exception_flags |= tstat.float_exception_flags; |
3279 | ||
3280 | if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { | |
57483867 | 3281 | float_invalid_op_addsub(env, 1, GETPC(), |
cf3b0334 MCA |
3282 | float128_classify(xa->f128) | |
3283 | float128_classify(xb->f128)); | |
f6b99afd JRZ |
3284 | } |
3285 | ||
cf3b0334 MCA |
3286 | helper_compute_fprf_float128(env, t.f128); |
3287 | *xt = t; | |
6525aadc | 3288 | do_float_check_status(env, GETPC()); |
f6b99afd | 3289 | } |