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