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