root / target-ppc / fpu_helper.c @ e0ff466c
History | View | Annotate | Download (48.5 kB)
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 |
*/
|
19 |
#include "cpu.h" |
20 |
#include "helper.h" |
21 |
|
22 |
/*****************************************************************************/
|
23 |
/* Floating point operations helpers */
|
24 |
uint64_t helper_float32_to_float64(CPUPPCState *env, uint32_t arg) |
25 |
{ |
26 |
CPU_FloatU f; |
27 |
CPU_DoubleU d; |
28 |
|
29 |
f.l = arg; |
30 |
d.d = float32_to_float64(f.f, &env->fp_status); |
31 |
return d.ll;
|
32 |
} |
33 |
|
34 |
uint32_t helper_float64_to_float32(CPUPPCState *env, uint64_t arg) |
35 |
{ |
36 |
CPU_FloatU f; |
37 |
CPU_DoubleU d; |
38 |
|
39 |
d.ll = arg; |
40 |
f.f = float64_to_float32(d.d, &env->fp_status); |
41 |
return f.l;
|
42 |
} |
43 |
|
44 |
static inline int isden(float64 d) |
45 |
{ |
46 |
CPU_DoubleU u; |
47 |
|
48 |
u.d = d; |
49 |
|
50 |
return ((u.ll >> 52) & 0x7FF) == 0; |
51 |
} |
52 |
|
53 |
uint32_t helper_compute_fprf(CPUPPCState *env, uint64_t arg, uint32_t set_fprf) |
54 |
{ |
55 |
CPU_DoubleU farg; |
56 |
int isneg;
|
57 |
int ret;
|
58 |
|
59 |
farg.ll = arg; |
60 |
isneg = float64_is_neg(farg.d); |
61 |
if (unlikely(float64_is_any_nan(farg.d))) {
|
62 |
if (float64_is_signaling_nan(farg.d)) {
|
63 |
/* Signaling NaN: flags are undefined */
|
64 |
ret = 0x00;
|
65 |
} else {
|
66 |
/* Quiet NaN */
|
67 |
ret = 0x11;
|
68 |
} |
69 |
} else if (unlikely(float64_is_infinity(farg.d))) { |
70 |
/* +/- infinity */
|
71 |
if (isneg) {
|
72 |
ret = 0x09;
|
73 |
} else {
|
74 |
ret = 0x05;
|
75 |
} |
76 |
} else {
|
77 |
if (float64_is_zero(farg.d)) {
|
78 |
/* +/- zero */
|
79 |
if (isneg) {
|
80 |
ret = 0x12;
|
81 |
} else {
|
82 |
ret = 0x02;
|
83 |
} |
84 |
} else {
|
85 |
if (isden(farg.d)) {
|
86 |
/* Denormalized numbers */
|
87 |
ret = 0x10;
|
88 |
} else {
|
89 |
/* Normalized numbers */
|
90 |
ret = 0x00;
|
91 |
} |
92 |
if (isneg) {
|
93 |
ret |= 0x08;
|
94 |
} else {
|
95 |
ret |= 0x04;
|
96 |
} |
97 |
} |
98 |
} |
99 |
if (set_fprf) {
|
100 |
/* We update FPSCR_FPRF */
|
101 |
env->fpscr &= ~(0x1F << FPSCR_FPRF);
|
102 |
env->fpscr |= ret << FPSCR_FPRF; |
103 |
} |
104 |
/* We just need fpcc to update Rc1 */
|
105 |
return ret & 0xF; |
106 |
} |
107 |
|
108 |
/* Floating-point invalid operations exception */
|
109 |
static inline uint64_t fload_invalid_op_excp(CPUPPCState *env, int op) |
110 |
{ |
111 |
uint64_t ret = 0;
|
112 |
int ve;
|
113 |
|
114 |
ve = fpscr_ve; |
115 |
switch (op) {
|
116 |
case POWERPC_EXCP_FP_VXSNAN:
|
117 |
env->fpscr |= 1 << FPSCR_VXSNAN;
|
118 |
break;
|
119 |
case POWERPC_EXCP_FP_VXSOFT:
|
120 |
env->fpscr |= 1 << FPSCR_VXSOFT;
|
121 |
break;
|
122 |
case POWERPC_EXCP_FP_VXISI:
|
123 |
/* Magnitude subtraction of infinities */
|
124 |
env->fpscr |= 1 << FPSCR_VXISI;
|
125 |
goto update_arith;
|
126 |
case POWERPC_EXCP_FP_VXIDI:
|
127 |
/* Division of infinity by infinity */
|
128 |
env->fpscr |= 1 << FPSCR_VXIDI;
|
129 |
goto update_arith;
|
130 |
case POWERPC_EXCP_FP_VXZDZ:
|
131 |
/* Division of zero by zero */
|
132 |
env->fpscr |= 1 << FPSCR_VXZDZ;
|
133 |
goto update_arith;
|
134 |
case POWERPC_EXCP_FP_VXIMZ:
|
135 |
/* Multiplication of zero by infinity */
|
136 |
env->fpscr |= 1 << FPSCR_VXIMZ;
|
137 |
goto update_arith;
|
138 |
case POWERPC_EXCP_FP_VXVC:
|
139 |
/* Ordered comparison of NaN */
|
140 |
env->fpscr |= 1 << FPSCR_VXVC;
|
141 |
env->fpscr &= ~(0xF << FPSCR_FPCC);
|
142 |
env->fpscr |= 0x11 << FPSCR_FPCC;
|
143 |
/* We must update the target FPR before raising the exception */
|
144 |
if (ve != 0) { |
145 |
env->exception_index = POWERPC_EXCP_PROGRAM; |
146 |
env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC; |
147 |
/* Update the floating-point enabled exception summary */
|
148 |
env->fpscr |= 1 << FPSCR_FEX;
|
149 |
/* Exception is differed */
|
150 |
ve = 0;
|
151 |
} |
152 |
break;
|
153 |
case POWERPC_EXCP_FP_VXSQRT:
|
154 |
/* Square root of a negative number */
|
155 |
env->fpscr |= 1 << FPSCR_VXSQRT;
|
156 |
update_arith:
|
157 |
env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); |
158 |
if (ve == 0) { |
159 |
/* Set the result to quiet NaN */
|
160 |
ret = 0x7FF8000000000000ULL;
|
161 |
env->fpscr &= ~(0xF << FPSCR_FPCC);
|
162 |
env->fpscr |= 0x11 << FPSCR_FPCC;
|
163 |
} |
164 |
break;
|
165 |
case POWERPC_EXCP_FP_VXCVI:
|
166 |
/* Invalid conversion */
|
167 |
env->fpscr |= 1 << FPSCR_VXCVI;
|
168 |
env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); |
169 |
if (ve == 0) { |
170 |
/* Set the result to quiet NaN */
|
171 |
ret = 0x7FF8000000000000ULL;
|
172 |
env->fpscr &= ~(0xF << FPSCR_FPCC);
|
173 |
env->fpscr |= 0x11 << FPSCR_FPCC;
|
174 |
} |
175 |
break;
|
176 |
} |
177 |
/* Update the floating-point invalid operation summary */
|
178 |
env->fpscr |= 1 << FPSCR_VX;
|
179 |
/* Update the floating-point exception summary */
|
180 |
env->fpscr |= 1 << FPSCR_FX;
|
181 |
if (ve != 0) { |
182 |
/* Update the floating-point enabled exception summary */
|
183 |
env->fpscr |= 1 << FPSCR_FEX;
|
184 |
if (msr_fe0 != 0 || msr_fe1 != 0) { |
185 |
helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, |
186 |
POWERPC_EXCP_FP | op); |
187 |
} |
188 |
} |
189 |
return ret;
|
190 |
} |
191 |
|
192 |
static inline void float_zero_divide_excp(CPUPPCState *env) |
193 |
{ |
194 |
env->fpscr |= 1 << FPSCR_ZX;
|
195 |
env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); |
196 |
/* Update the floating-point exception summary */
|
197 |
env->fpscr |= 1 << FPSCR_FX;
|
198 |
if (fpscr_ze != 0) { |
199 |
/* Update the floating-point enabled exception summary */
|
200 |
env->fpscr |= 1 << FPSCR_FEX;
|
201 |
if (msr_fe0 != 0 || msr_fe1 != 0) { |
202 |
helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, |
203 |
POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX); |
204 |
} |
205 |
} |
206 |
} |
207 |
|
208 |
static inline void float_overflow_excp(CPUPPCState *env) |
209 |
{ |
210 |
env->fpscr |= 1 << FPSCR_OX;
|
211 |
/* Update the floating-point exception summary */
|
212 |
env->fpscr |= 1 << FPSCR_FX;
|
213 |
if (fpscr_oe != 0) { |
214 |
/* XXX: should adjust the result */
|
215 |
/* Update the floating-point enabled exception summary */
|
216 |
env->fpscr |= 1 << FPSCR_FEX;
|
217 |
/* We must update the target FPR before raising the exception */
|
218 |
env->exception_index = POWERPC_EXCP_PROGRAM; |
219 |
env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX; |
220 |
} else {
|
221 |
env->fpscr |= 1 << FPSCR_XX;
|
222 |
env->fpscr |= 1 << FPSCR_FI;
|
223 |
} |
224 |
} |
225 |
|
226 |
static inline void float_underflow_excp(CPUPPCState *env) |
227 |
{ |
228 |
env->fpscr |= 1 << FPSCR_UX;
|
229 |
/* Update the floating-point exception summary */
|
230 |
env->fpscr |= 1 << FPSCR_FX;
|
231 |
if (fpscr_ue != 0) { |
232 |
/* XXX: should adjust the result */
|
233 |
/* Update the floating-point enabled exception summary */
|
234 |
env->fpscr |= 1 << FPSCR_FEX;
|
235 |
/* We must update the target FPR before raising the exception */
|
236 |
env->exception_index = POWERPC_EXCP_PROGRAM; |
237 |
env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX; |
238 |
} |
239 |
} |
240 |
|
241 |
static inline void float_inexact_excp(CPUPPCState *env) |
242 |
{ |
243 |
env->fpscr |= 1 << FPSCR_XX;
|
244 |
/* Update the floating-point exception summary */
|
245 |
env->fpscr |= 1 << FPSCR_FX;
|
246 |
if (fpscr_xe != 0) { |
247 |
/* Update the floating-point enabled exception summary */
|
248 |
env->fpscr |= 1 << FPSCR_FEX;
|
249 |
/* We must update the target FPR before raising the exception */
|
250 |
env->exception_index = POWERPC_EXCP_PROGRAM; |
251 |
env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX; |
252 |
} |
253 |
} |
254 |
|
255 |
static inline void fpscr_set_rounding_mode(CPUPPCState *env) |
256 |
{ |
257 |
int rnd_type;
|
258 |
|
259 |
/* Set rounding mode */
|
260 |
switch (fpscr_rn) {
|
261 |
case 0: |
262 |
/* Best approximation (round to nearest) */
|
263 |
rnd_type = float_round_nearest_even; |
264 |
break;
|
265 |
case 1: |
266 |
/* Smaller magnitude (round toward zero) */
|
267 |
rnd_type = float_round_to_zero; |
268 |
break;
|
269 |
case 2: |
270 |
/* Round toward +infinite */
|
271 |
rnd_type = float_round_up; |
272 |
break;
|
273 |
default:
|
274 |
case 3: |
275 |
/* Round toward -infinite */
|
276 |
rnd_type = float_round_down; |
277 |
break;
|
278 |
} |
279 |
set_float_rounding_mode(rnd_type, &env->fp_status); |
280 |
} |
281 |
|
282 |
void helper_fpscr_clrbit(CPUPPCState *env, uint32_t bit)
|
283 |
{ |
284 |
int prev;
|
285 |
|
286 |
prev = (env->fpscr >> bit) & 1;
|
287 |
env->fpscr &= ~(1 << bit);
|
288 |
if (prev == 1) { |
289 |
switch (bit) {
|
290 |
case FPSCR_RN1:
|
291 |
case FPSCR_RN:
|
292 |
fpscr_set_rounding_mode(env); |
293 |
break;
|
294 |
default:
|
295 |
break;
|
296 |
} |
297 |
} |
298 |
} |
299 |
|
300 |
void helper_fpscr_setbit(CPUPPCState *env, uint32_t bit)
|
301 |
{ |
302 |
int prev;
|
303 |
|
304 |
prev = (env->fpscr >> bit) & 1;
|
305 |
env->fpscr |= 1 << bit;
|
306 |
if (prev == 0) { |
307 |
switch (bit) {
|
308 |
case FPSCR_VX:
|
309 |
env->fpscr |= 1 << FPSCR_FX;
|
310 |
if (fpscr_ve) {
|
311 |
goto raise_ve;
|
312 |
} |
313 |
break;
|
314 |
case FPSCR_OX:
|
315 |
env->fpscr |= 1 << FPSCR_FX;
|
316 |
if (fpscr_oe) {
|
317 |
goto raise_oe;
|
318 |
} |
319 |
break;
|
320 |
case FPSCR_UX:
|
321 |
env->fpscr |= 1 << FPSCR_FX;
|
322 |
if (fpscr_ue) {
|
323 |
goto raise_ue;
|
324 |
} |
325 |
break;
|
326 |
case FPSCR_ZX:
|
327 |
env->fpscr |= 1 << FPSCR_FX;
|
328 |
if (fpscr_ze) {
|
329 |
goto raise_ze;
|
330 |
} |
331 |
break;
|
332 |
case FPSCR_XX:
|
333 |
env->fpscr |= 1 << FPSCR_FX;
|
334 |
if (fpscr_xe) {
|
335 |
goto raise_xe;
|
336 |
} |
337 |
break;
|
338 |
case FPSCR_VXSNAN:
|
339 |
case FPSCR_VXISI:
|
340 |
case FPSCR_VXIDI:
|
341 |
case FPSCR_VXZDZ:
|
342 |
case FPSCR_VXIMZ:
|
343 |
case FPSCR_VXVC:
|
344 |
case FPSCR_VXSOFT:
|
345 |
case FPSCR_VXSQRT:
|
346 |
case FPSCR_VXCVI:
|
347 |
env->fpscr |= 1 << FPSCR_VX;
|
348 |
env->fpscr |= 1 << FPSCR_FX;
|
349 |
if (fpscr_ve != 0) { |
350 |
goto raise_ve;
|
351 |
} |
352 |
break;
|
353 |
case FPSCR_VE:
|
354 |
if (fpscr_vx != 0) { |
355 |
raise_ve:
|
356 |
env->error_code = POWERPC_EXCP_FP; |
357 |
if (fpscr_vxsnan) {
|
358 |
env->error_code |= POWERPC_EXCP_FP_VXSNAN; |
359 |
} |
360 |
if (fpscr_vxisi) {
|
361 |
env->error_code |= POWERPC_EXCP_FP_VXISI; |
362 |
} |
363 |
if (fpscr_vxidi) {
|
364 |
env->error_code |= POWERPC_EXCP_FP_VXIDI; |
365 |
} |
366 |
if (fpscr_vxzdz) {
|
367 |
env->error_code |= POWERPC_EXCP_FP_VXZDZ; |
368 |
} |
369 |
if (fpscr_vximz) {
|
370 |
env->error_code |= POWERPC_EXCP_FP_VXIMZ; |
371 |
} |
372 |
if (fpscr_vxvc) {
|
373 |
env->error_code |= POWERPC_EXCP_FP_VXVC; |
374 |
} |
375 |
if (fpscr_vxsoft) {
|
376 |
env->error_code |= POWERPC_EXCP_FP_VXSOFT; |
377 |
} |
378 |
if (fpscr_vxsqrt) {
|
379 |
env->error_code |= POWERPC_EXCP_FP_VXSQRT; |
380 |
} |
381 |
if (fpscr_vxcvi) {
|
382 |
env->error_code |= POWERPC_EXCP_FP_VXCVI; |
383 |
} |
384 |
goto raise_excp;
|
385 |
} |
386 |
break;
|
387 |
case FPSCR_OE:
|
388 |
if (fpscr_ox != 0) { |
389 |
raise_oe:
|
390 |
env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX; |
391 |
goto raise_excp;
|
392 |
} |
393 |
break;
|
394 |
case FPSCR_UE:
|
395 |
if (fpscr_ux != 0) { |
396 |
raise_ue:
|
397 |
env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX; |
398 |
goto raise_excp;
|
399 |
} |
400 |
break;
|
401 |
case FPSCR_ZE:
|
402 |
if (fpscr_zx != 0) { |
403 |
raise_ze:
|
404 |
env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX; |
405 |
goto raise_excp;
|
406 |
} |
407 |
break;
|
408 |
case FPSCR_XE:
|
409 |
if (fpscr_xx != 0) { |
410 |
raise_xe:
|
411 |
env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX; |
412 |
goto raise_excp;
|
413 |
} |
414 |
break;
|
415 |
case FPSCR_RN1:
|
416 |
case FPSCR_RN:
|
417 |
fpscr_set_rounding_mode(env); |
418 |
break;
|
419 |
default:
|
420 |
break;
|
421 |
raise_excp:
|
422 |
/* Update the floating-point enabled exception summary */
|
423 |
env->fpscr |= 1 << FPSCR_FEX;
|
424 |
/* We have to update Rc1 before raising the exception */
|
425 |
env->exception_index = POWERPC_EXCP_PROGRAM; |
426 |
break;
|
427 |
} |
428 |
} |
429 |
} |
430 |
|
431 |
void helper_store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask)
|
432 |
{ |
433 |
target_ulong prev, new; |
434 |
int i;
|
435 |
|
436 |
prev = env->fpscr; |
437 |
new = (target_ulong)arg; |
438 |
new &= ~0x60000000LL;
|
439 |
new |= prev & 0x60000000LL;
|
440 |
for (i = 0; i < sizeof(target_ulong) * 2; i++) { |
441 |
if (mask & (1 << i)) { |
442 |
env->fpscr &= ~(0xFLL << (4 * i)); |
443 |
env->fpscr |= new & (0xFLL << (4 * i)); |
444 |
} |
445 |
} |
446 |
/* Update VX and FEX */
|
447 |
if (fpscr_ix != 0) { |
448 |
env->fpscr |= 1 << FPSCR_VX;
|
449 |
} else {
|
450 |
env->fpscr &= ~(1 << FPSCR_VX);
|
451 |
} |
452 |
if ((fpscr_ex & fpscr_eex) != 0) { |
453 |
env->fpscr |= 1 << FPSCR_FEX;
|
454 |
env->exception_index = POWERPC_EXCP_PROGRAM; |
455 |
/* XXX: we should compute it properly */
|
456 |
env->error_code = POWERPC_EXCP_FP; |
457 |
} else {
|
458 |
env->fpscr &= ~(1 << FPSCR_FEX);
|
459 |
} |
460 |
fpscr_set_rounding_mode(env); |
461 |
} |
462 |
|
463 |
void store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask)
|
464 |
{ |
465 |
helper_store_fpscr(env, arg, mask); |
466 |
} |
467 |
|
468 |
void helper_float_check_status(CPUPPCState *env)
|
469 |
{ |
470 |
int status = get_float_exception_flags(&env->fp_status);
|
471 |
|
472 |
if (status & float_flag_divbyzero) {
|
473 |
float_zero_divide_excp(env); |
474 |
} else if (status & float_flag_overflow) { |
475 |
float_overflow_excp(env); |
476 |
} else if (status & float_flag_underflow) { |
477 |
float_underflow_excp(env); |
478 |
} else if (status & float_flag_inexact) { |
479 |
float_inexact_excp(env); |
480 |
} |
481 |
|
482 |
if (env->exception_index == POWERPC_EXCP_PROGRAM &&
|
483 |
(env->error_code & POWERPC_EXCP_FP)) { |
484 |
/* Differred floating-point exception after target FPR update */
|
485 |
if (msr_fe0 != 0 || msr_fe1 != 0) { |
486 |
helper_raise_exception_err(env, env->exception_index, |
487 |
env->error_code); |
488 |
} |
489 |
} |
490 |
} |
491 |
|
492 |
void helper_reset_fpstatus(CPUPPCState *env)
|
493 |
{ |
494 |
set_float_exception_flags(0, &env->fp_status);
|
495 |
} |
496 |
|
497 |
/* fadd - fadd. */
|
498 |
uint64_t helper_fadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2) |
499 |
{ |
500 |
CPU_DoubleU farg1, farg2; |
501 |
|
502 |
farg1.ll = arg1; |
503 |
farg2.ll = arg2; |
504 |
|
505 |
if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
|
506 |
float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) { |
507 |
/* Magnitude subtraction of infinities */
|
508 |
farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI); |
509 |
} else {
|
510 |
if (unlikely(float64_is_signaling_nan(farg1.d) ||
|
511 |
float64_is_signaling_nan(farg2.d))) { |
512 |
/* sNaN addition */
|
513 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN); |
514 |
} |
515 |
farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status); |
516 |
} |
517 |
|
518 |
return farg1.ll;
|
519 |
} |
520 |
|
521 |
/* fsub - fsub. */
|
522 |
uint64_t helper_fsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2) |
523 |
{ |
524 |
CPU_DoubleU farg1, farg2; |
525 |
|
526 |
farg1.ll = arg1; |
527 |
farg2.ll = arg2; |
528 |
|
529 |
if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
|
530 |
float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) { |
531 |
/* Magnitude subtraction of infinities */
|
532 |
farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI); |
533 |
} else {
|
534 |
if (unlikely(float64_is_signaling_nan(farg1.d) ||
|
535 |
float64_is_signaling_nan(farg2.d))) { |
536 |
/* sNaN subtraction */
|
537 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN); |
538 |
} |
539 |
farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status); |
540 |
} |
541 |
|
542 |
return farg1.ll;
|
543 |
} |
544 |
|
545 |
/* fmul - fmul. */
|
546 |
uint64_t helper_fmul(CPUPPCState *env, uint64_t arg1, uint64_t arg2) |
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_zero(farg2.d)) ||
|
554 |
(float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { |
555 |
/* Multiplication of zero by infinity */
|
556 |
farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ); |
557 |
} else {
|
558 |
if (unlikely(float64_is_signaling_nan(farg1.d) ||
|
559 |
float64_is_signaling_nan(farg2.d))) { |
560 |
/* sNaN multiplication */
|
561 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN); |
562 |
} |
563 |
farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status); |
564 |
} |
565 |
|
566 |
return farg1.ll;
|
567 |
} |
568 |
|
569 |
/* fdiv - fdiv. */
|
570 |
uint64_t helper_fdiv(CPUPPCState *env, uint64_t arg1, uint64_t arg2) |
571 |
{ |
572 |
CPU_DoubleU farg1, farg2; |
573 |
|
574 |
farg1.ll = arg1; |
575 |
farg2.ll = arg2; |
576 |
|
577 |
if (unlikely(float64_is_infinity(farg1.d) &&
|
578 |
float64_is_infinity(farg2.d))) { |
579 |
/* Division of infinity by infinity */
|
580 |
farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI); |
581 |
} else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) { |
582 |
/* Division of zero by zero */
|
583 |
farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ); |
584 |
} else {
|
585 |
if (unlikely(float64_is_signaling_nan(farg1.d) ||
|
586 |
float64_is_signaling_nan(farg2.d))) { |
587 |
/* sNaN division */
|
588 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN); |
589 |
} |
590 |
farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status); |
591 |
} |
592 |
|
593 |
return farg1.ll;
|
594 |
} |
595 |
|
596 |
/* fctiw - fctiw. */
|
597 |
uint64_t helper_fctiw(CPUPPCState *env, uint64_t arg) |
598 |
{ |
599 |
CPU_DoubleU farg; |
600 |
|
601 |
farg.ll = arg; |
602 |
|
603 |
if (unlikely(float64_is_signaling_nan(farg.d))) {
|
604 |
/* sNaN conversion */
|
605 |
farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN | |
606 |
POWERPC_EXCP_FP_VXCVI); |
607 |
} else if (unlikely(float64_is_quiet_nan(farg.d) || |
608 |
float64_is_infinity(farg.d))) { |
609 |
/* qNan / infinity conversion */
|
610 |
farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI); |
611 |
} else {
|
612 |
farg.ll = float64_to_int32(farg.d, &env->fp_status); |
613 |
/* XXX: higher bits are not supposed to be significant.
|
614 |
* to make tests easier, return the same as a real PowerPC 750
|
615 |
*/
|
616 |
farg.ll |= 0xFFF80000ULL << 32; |
617 |
} |
618 |
return farg.ll;
|
619 |
} |
620 |
|
621 |
/* fctiwz - fctiwz. */
|
622 |
uint64_t helper_fctiwz(CPUPPCState *env, uint64_t arg) |
623 |
{ |
624 |
CPU_DoubleU farg; |
625 |
|
626 |
farg.ll = arg; |
627 |
|
628 |
if (unlikely(float64_is_signaling_nan(farg.d))) {
|
629 |
/* sNaN conversion */
|
630 |
farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN | |
631 |
POWERPC_EXCP_FP_VXCVI); |
632 |
} else if (unlikely(float64_is_quiet_nan(farg.d) || |
633 |
float64_is_infinity(farg.d))) { |
634 |
/* qNan / infinity conversion */
|
635 |
farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI); |
636 |
} else {
|
637 |
farg.ll = float64_to_int32_round_to_zero(farg.d, &env->fp_status); |
638 |
/* XXX: higher bits are not supposed to be significant.
|
639 |
* to make tests easier, return the same as a real PowerPC 750
|
640 |
*/
|
641 |
farg.ll |= 0xFFF80000ULL << 32; |
642 |
} |
643 |
return farg.ll;
|
644 |
} |
645 |
|
646 |
#if defined(TARGET_PPC64)
|
647 |
/* fcfid - fcfid. */
|
648 |
uint64_t helper_fcfid(CPUPPCState *env, uint64_t arg) |
649 |
{ |
650 |
CPU_DoubleU farg; |
651 |
|
652 |
farg.d = int64_to_float64(arg, &env->fp_status); |
653 |
return farg.ll;
|
654 |
} |
655 |
|
656 |
/* fctid - fctid. */
|
657 |
uint64_t helper_fctid(CPUPPCState *env, uint64_t arg) |
658 |
{ |
659 |
CPU_DoubleU farg; |
660 |
|
661 |
farg.ll = arg; |
662 |
|
663 |
if (unlikely(float64_is_signaling_nan(farg.d))) {
|
664 |
/* sNaN conversion */
|
665 |
farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN | |
666 |
POWERPC_EXCP_FP_VXCVI); |
667 |
} else if (unlikely(float64_is_quiet_nan(farg.d) || |
668 |
float64_is_infinity(farg.d))) { |
669 |
/* qNan / infinity conversion */
|
670 |
farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI); |
671 |
} else {
|
672 |
farg.ll = float64_to_int64(farg.d, &env->fp_status); |
673 |
} |
674 |
return farg.ll;
|
675 |
} |
676 |
|
677 |
/* fctidz - fctidz. */
|
678 |
uint64_t helper_fctidz(CPUPPCState *env, uint64_t arg) |
679 |
{ |
680 |
CPU_DoubleU farg; |
681 |
|
682 |
farg.ll = arg; |
683 |
|
684 |
if (unlikely(float64_is_signaling_nan(farg.d))) {
|
685 |
/* sNaN conversion */
|
686 |
farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN | |
687 |
POWERPC_EXCP_FP_VXCVI); |
688 |
} else if (unlikely(float64_is_quiet_nan(farg.d) || |
689 |
float64_is_infinity(farg.d))) { |
690 |
/* qNan / infinity conversion */
|
691 |
farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI); |
692 |
} else {
|
693 |
farg.ll = float64_to_int64_round_to_zero(farg.d, &env->fp_status); |
694 |
} |
695 |
return farg.ll;
|
696 |
} |
697 |
|
698 |
#endif
|
699 |
|
700 |
static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg, |
701 |
int rounding_mode)
|
702 |
{ |
703 |
CPU_DoubleU farg; |
704 |
|
705 |
farg.ll = arg; |
706 |
|
707 |
if (unlikely(float64_is_signaling_nan(farg.d))) {
|
708 |
/* sNaN round */
|
709 |
farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN | |
710 |
POWERPC_EXCP_FP_VXCVI); |
711 |
} else if (unlikely(float64_is_quiet_nan(farg.d) || |
712 |
float64_is_infinity(farg.d))) { |
713 |
/* qNan / infinity round */
|
714 |
farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI); |
715 |
} else {
|
716 |
set_float_rounding_mode(rounding_mode, &env->fp_status); |
717 |
farg.ll = float64_round_to_int(farg.d, &env->fp_status); |
718 |
/* Restore rounding mode from FPSCR */
|
719 |
fpscr_set_rounding_mode(env); |
720 |
} |
721 |
return farg.ll;
|
722 |
} |
723 |
|
724 |
uint64_t helper_frin(CPUPPCState *env, uint64_t arg) |
725 |
{ |
726 |
return do_fri(env, arg, float_round_nearest_even);
|
727 |
} |
728 |
|
729 |
uint64_t helper_friz(CPUPPCState *env, uint64_t arg) |
730 |
{ |
731 |
return do_fri(env, arg, float_round_to_zero);
|
732 |
} |
733 |
|
734 |
uint64_t helper_frip(CPUPPCState *env, uint64_t arg) |
735 |
{ |
736 |
return do_fri(env, arg, float_round_up);
|
737 |
} |
738 |
|
739 |
uint64_t helper_frim(CPUPPCState *env, uint64_t arg) |
740 |
{ |
741 |
return do_fri(env, arg, float_round_down);
|
742 |
} |
743 |
|
744 |
/* fmadd - fmadd. */
|
745 |
uint64_t helper_fmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2, |
746 |
uint64_t arg3) |
747 |
{ |
748 |
CPU_DoubleU farg1, farg2, farg3; |
749 |
|
750 |
farg1.ll = arg1; |
751 |
farg2.ll = arg2; |
752 |
farg3.ll = arg3; |
753 |
|
754 |
if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
|
755 |
(float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { |
756 |
/* Multiplication of zero by infinity */
|
757 |
farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ); |
758 |
} else {
|
759 |
if (unlikely(float64_is_signaling_nan(farg1.d) ||
|
760 |
float64_is_signaling_nan(farg2.d) || |
761 |
float64_is_signaling_nan(farg3.d))) { |
762 |
/* sNaN operation */
|
763 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN); |
764 |
} |
765 |
/* This is the way the PowerPC specification defines it */
|
766 |
float128 ft0_128, ft1_128; |
767 |
|
768 |
ft0_128 = float64_to_float128(farg1.d, &env->fp_status); |
769 |
ft1_128 = float64_to_float128(farg2.d, &env->fp_status); |
770 |
ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); |
771 |
if (unlikely(float128_is_infinity(ft0_128) &&
|
772 |
float64_is_infinity(farg3.d) && |
773 |
float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) { |
774 |
/* Magnitude subtraction of infinities */
|
775 |
farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI); |
776 |
} else {
|
777 |
ft1_128 = float64_to_float128(farg3.d, &env->fp_status); |
778 |
ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status); |
779 |
farg1.d = float128_to_float64(ft0_128, &env->fp_status); |
780 |
} |
781 |
} |
782 |
|
783 |
return farg1.ll;
|
784 |
} |
785 |
|
786 |
/* fmsub - fmsub. */
|
787 |
uint64_t helper_fmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2, |
788 |
uint64_t arg3) |
789 |
{ |
790 |
CPU_DoubleU farg1, farg2, farg3; |
791 |
|
792 |
farg1.ll = arg1; |
793 |
farg2.ll = arg2; |
794 |
farg3.ll = arg3; |
795 |
|
796 |
if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
|
797 |
(float64_is_zero(farg1.d) && |
798 |
float64_is_infinity(farg2.d)))) { |
799 |
/* Multiplication of zero by infinity */
|
800 |
farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ); |
801 |
} else {
|
802 |
if (unlikely(float64_is_signaling_nan(farg1.d) ||
|
803 |
float64_is_signaling_nan(farg2.d) || |
804 |
float64_is_signaling_nan(farg3.d))) { |
805 |
/* sNaN operation */
|
806 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN); |
807 |
} |
808 |
/* This is the way the PowerPC specification defines it */
|
809 |
float128 ft0_128, ft1_128; |
810 |
|
811 |
ft0_128 = float64_to_float128(farg1.d, &env->fp_status); |
812 |
ft1_128 = float64_to_float128(farg2.d, &env->fp_status); |
813 |
ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); |
814 |
if (unlikely(float128_is_infinity(ft0_128) &&
|
815 |
float64_is_infinity(farg3.d) && |
816 |
float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) { |
817 |
/* Magnitude subtraction of infinities */
|
818 |
farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI); |
819 |
} else {
|
820 |
ft1_128 = float64_to_float128(farg3.d, &env->fp_status); |
821 |
ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status); |
822 |
farg1.d = float128_to_float64(ft0_128, &env->fp_status); |
823 |
} |
824 |
} |
825 |
return farg1.ll;
|
826 |
} |
827 |
|
828 |
/* fnmadd - fnmadd. */
|
829 |
uint64_t helper_fnmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2, |
830 |
uint64_t arg3) |
831 |
{ |
832 |
CPU_DoubleU farg1, farg2, farg3; |
833 |
|
834 |
farg1.ll = arg1; |
835 |
farg2.ll = arg2; |
836 |
farg3.ll = arg3; |
837 |
|
838 |
if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
|
839 |
(float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { |
840 |
/* Multiplication of zero by infinity */
|
841 |
farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ); |
842 |
} else {
|
843 |
if (unlikely(float64_is_signaling_nan(farg1.d) ||
|
844 |
float64_is_signaling_nan(farg2.d) || |
845 |
float64_is_signaling_nan(farg3.d))) { |
846 |
/* sNaN operation */
|
847 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN); |
848 |
} |
849 |
/* This is the way the PowerPC specification defines it */
|
850 |
float128 ft0_128, ft1_128; |
851 |
|
852 |
ft0_128 = float64_to_float128(farg1.d, &env->fp_status); |
853 |
ft1_128 = float64_to_float128(farg2.d, &env->fp_status); |
854 |
ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); |
855 |
if (unlikely(float128_is_infinity(ft0_128) &&
|
856 |
float64_is_infinity(farg3.d) && |
857 |
float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) { |
858 |
/* Magnitude subtraction of infinities */
|
859 |
farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI); |
860 |
} else {
|
861 |
ft1_128 = float64_to_float128(farg3.d, &env->fp_status); |
862 |
ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status); |
863 |
farg1.d = float128_to_float64(ft0_128, &env->fp_status); |
864 |
} |
865 |
if (likely(!float64_is_any_nan(farg1.d))) {
|
866 |
farg1.d = float64_chs(farg1.d); |
867 |
} |
868 |
} |
869 |
return farg1.ll;
|
870 |
} |
871 |
|
872 |
/* fnmsub - fnmsub. */
|
873 |
uint64_t helper_fnmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2, |
874 |
uint64_t arg3) |
875 |
{ |
876 |
CPU_DoubleU farg1, farg2, farg3; |
877 |
|
878 |
farg1.ll = arg1; |
879 |
farg2.ll = arg2; |
880 |
farg3.ll = arg3; |
881 |
|
882 |
if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
|
883 |
(float64_is_zero(farg1.d) && |
884 |
float64_is_infinity(farg2.d)))) { |
885 |
/* Multiplication of zero by infinity */
|
886 |
farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ); |
887 |
} else {
|
888 |
if (unlikely(float64_is_signaling_nan(farg1.d) ||
|
889 |
float64_is_signaling_nan(farg2.d) || |
890 |
float64_is_signaling_nan(farg3.d))) { |
891 |
/* sNaN operation */
|
892 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN); |
893 |
} |
894 |
/* This is the way the PowerPC specification defines it */
|
895 |
float128 ft0_128, ft1_128; |
896 |
|
897 |
ft0_128 = float64_to_float128(farg1.d, &env->fp_status); |
898 |
ft1_128 = float64_to_float128(farg2.d, &env->fp_status); |
899 |
ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); |
900 |
if (unlikely(float128_is_infinity(ft0_128) &&
|
901 |
float64_is_infinity(farg3.d) && |
902 |
float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) { |
903 |
/* Magnitude subtraction of infinities */
|
904 |
farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI); |
905 |
} else {
|
906 |
ft1_128 = float64_to_float128(farg3.d, &env->fp_status); |
907 |
ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status); |
908 |
farg1.d = float128_to_float64(ft0_128, &env->fp_status); |
909 |
} |
910 |
if (likely(!float64_is_any_nan(farg1.d))) {
|
911 |
farg1.d = float64_chs(farg1.d); |
912 |
} |
913 |
} |
914 |
return farg1.ll;
|
915 |
} |
916 |
|
917 |
/* frsp - frsp. */
|
918 |
uint64_t helper_frsp(CPUPPCState *env, uint64_t arg) |
919 |
{ |
920 |
CPU_DoubleU farg; |
921 |
float32 f32; |
922 |
|
923 |
farg.ll = arg; |
924 |
|
925 |
if (unlikely(float64_is_signaling_nan(farg.d))) {
|
926 |
/* sNaN square root */
|
927 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN); |
928 |
} |
929 |
f32 = float64_to_float32(farg.d, &env->fp_status); |
930 |
farg.d = float32_to_float64(f32, &env->fp_status); |
931 |
|
932 |
return farg.ll;
|
933 |
} |
934 |
|
935 |
/* fsqrt - fsqrt. */
|
936 |
uint64_t helper_fsqrt(CPUPPCState *env, uint64_t arg) |
937 |
{ |
938 |
CPU_DoubleU farg; |
939 |
|
940 |
farg.ll = arg; |
941 |
|
942 |
if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
|
943 |
/* Square root of a negative nonzero number */
|
944 |
farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT); |
945 |
} else {
|
946 |
if (unlikely(float64_is_signaling_nan(farg.d))) {
|
947 |
/* sNaN square root */
|
948 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN); |
949 |
} |
950 |
farg.d = float64_sqrt(farg.d, &env->fp_status); |
951 |
} |
952 |
return farg.ll;
|
953 |
} |
954 |
|
955 |
/* fre - fre. */
|
956 |
uint64_t helper_fre(CPUPPCState *env, uint64_t arg) |
957 |
{ |
958 |
CPU_DoubleU farg; |
959 |
|
960 |
farg.ll = arg; |
961 |
|
962 |
if (unlikely(float64_is_signaling_nan(farg.d))) {
|
963 |
/* sNaN reciprocal */
|
964 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN); |
965 |
} |
966 |
farg.d = float64_div(float64_one, farg.d, &env->fp_status); |
967 |
return farg.d;
|
968 |
} |
969 |
|
970 |
/* fres - fres. */
|
971 |
uint64_t helper_fres(CPUPPCState *env, uint64_t arg) |
972 |
{ |
973 |
CPU_DoubleU farg; |
974 |
float32 f32; |
975 |
|
976 |
farg.ll = arg; |
977 |
|
978 |
if (unlikely(float64_is_signaling_nan(farg.d))) {
|
979 |
/* sNaN reciprocal */
|
980 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN); |
981 |
} |
982 |
farg.d = float64_div(float64_one, farg.d, &env->fp_status); |
983 |
f32 = float64_to_float32(farg.d, &env->fp_status); |
984 |
farg.d = float32_to_float64(f32, &env->fp_status); |
985 |
|
986 |
return farg.ll;
|
987 |
} |
988 |
|
989 |
/* frsqrte - frsqrte. */
|
990 |
uint64_t helper_frsqrte(CPUPPCState *env, uint64_t arg) |
991 |
{ |
992 |
CPU_DoubleU farg; |
993 |
float32 f32; |
994 |
|
995 |
farg.ll = arg; |
996 |
|
997 |
if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
|
998 |
/* Reciprocal square root of a negative nonzero number */
|
999 |
farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT); |
1000 |
} else {
|
1001 |
if (unlikely(float64_is_signaling_nan(farg.d))) {
|
1002 |
/* sNaN reciprocal square root */
|
1003 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN); |
1004 |
} |
1005 |
farg.d = float64_sqrt(farg.d, &env->fp_status); |
1006 |
farg.d = float64_div(float64_one, farg.d, &env->fp_status); |
1007 |
f32 = float64_to_float32(farg.d, &env->fp_status); |
1008 |
farg.d = float32_to_float64(f32, &env->fp_status); |
1009 |
} |
1010 |
return farg.ll;
|
1011 |
} |
1012 |
|
1013 |
/* fsel - fsel. */
|
1014 |
uint64_t helper_fsel(CPUPPCState *env, uint64_t arg1, uint64_t arg2, |
1015 |
uint64_t arg3) |
1016 |
{ |
1017 |
CPU_DoubleU farg1; |
1018 |
|
1019 |
farg1.ll = arg1; |
1020 |
|
1021 |
if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) &&
|
1022 |
!float64_is_any_nan(farg1.d)) { |
1023 |
return arg2;
|
1024 |
} else {
|
1025 |
return arg3;
|
1026 |
} |
1027 |
} |
1028 |
|
1029 |
void helper_fcmpu(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
|
1030 |
uint32_t crfD) |
1031 |
{ |
1032 |
CPU_DoubleU farg1, farg2; |
1033 |
uint32_t ret = 0;
|
1034 |
|
1035 |
farg1.ll = arg1; |
1036 |
farg2.ll = arg2; |
1037 |
|
1038 |
if (unlikely(float64_is_any_nan(farg1.d) ||
|
1039 |
float64_is_any_nan(farg2.d))) { |
1040 |
ret = 0x01UL;
|
1041 |
} else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) { |
1042 |
ret = 0x08UL;
|
1043 |
} else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) { |
1044 |
ret = 0x04UL;
|
1045 |
} else {
|
1046 |
ret = 0x02UL;
|
1047 |
} |
1048 |
|
1049 |
env->fpscr &= ~(0x0F << FPSCR_FPRF);
|
1050 |
env->fpscr |= ret << FPSCR_FPRF; |
1051 |
env->crf[crfD] = ret; |
1052 |
if (unlikely(ret == 0x01UL |
1053 |
&& (float64_is_signaling_nan(farg1.d) || |
1054 |
float64_is_signaling_nan(farg2.d)))) { |
1055 |
/* sNaN comparison */
|
1056 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN); |
1057 |
} |
1058 |
} |
1059 |
|
1060 |
void helper_fcmpo(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
|
1061 |
uint32_t crfD) |
1062 |
{ |
1063 |
CPU_DoubleU farg1, farg2; |
1064 |
uint32_t ret = 0;
|
1065 |
|
1066 |
farg1.ll = arg1; |
1067 |
farg2.ll = arg2; |
1068 |
|
1069 |
if (unlikely(float64_is_any_nan(farg1.d) ||
|
1070 |
float64_is_any_nan(farg2.d))) { |
1071 |
ret = 0x01UL;
|
1072 |
} else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) { |
1073 |
ret = 0x08UL;
|
1074 |
} else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) { |
1075 |
ret = 0x04UL;
|
1076 |
} else {
|
1077 |
ret = 0x02UL;
|
1078 |
} |
1079 |
|
1080 |
env->fpscr &= ~(0x0F << FPSCR_FPRF);
|
1081 |
env->fpscr |= ret << FPSCR_FPRF; |
1082 |
env->crf[crfD] = ret; |
1083 |
if (unlikely(ret == 0x01UL)) { |
1084 |
if (float64_is_signaling_nan(farg1.d) ||
|
1085 |
float64_is_signaling_nan(farg2.d)) { |
1086 |
/* sNaN comparison */
|
1087 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN | |
1088 |
POWERPC_EXCP_FP_VXVC); |
1089 |
} else {
|
1090 |
/* qNaN comparison */
|
1091 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC); |
1092 |
} |
1093 |
} |
1094 |
} |
1095 |
|
1096 |
/* Single-precision floating-point conversions */
|
1097 |
static inline uint32_t efscfsi(CPUPPCState *env, uint32_t val) |
1098 |
{ |
1099 |
CPU_FloatU u; |
1100 |
|
1101 |
u.f = int32_to_float32(val, &env->vec_status); |
1102 |
|
1103 |
return u.l;
|
1104 |
} |
1105 |
|
1106 |
static inline uint32_t efscfui(CPUPPCState *env, uint32_t val) |
1107 |
{ |
1108 |
CPU_FloatU u; |
1109 |
|
1110 |
u.f = uint32_to_float32(val, &env->vec_status); |
1111 |
|
1112 |
return u.l;
|
1113 |
} |
1114 |
|
1115 |
static inline int32_t efsctsi(CPUPPCState *env, uint32_t val) |
1116 |
{ |
1117 |
CPU_FloatU u; |
1118 |
|
1119 |
u.l = val; |
1120 |
/* NaN are not treated the same way IEEE 754 does */
|
1121 |
if (unlikely(float32_is_quiet_nan(u.f))) {
|
1122 |
return 0; |
1123 |
} |
1124 |
|
1125 |
return float32_to_int32(u.f, &env->vec_status);
|
1126 |
} |
1127 |
|
1128 |
static inline uint32_t efsctui(CPUPPCState *env, uint32_t val) |
1129 |
{ |
1130 |
CPU_FloatU u; |
1131 |
|
1132 |
u.l = val; |
1133 |
/* NaN are not treated the same way IEEE 754 does */
|
1134 |
if (unlikely(float32_is_quiet_nan(u.f))) {
|
1135 |
return 0; |
1136 |
} |
1137 |
|
1138 |
return float32_to_uint32(u.f, &env->vec_status);
|
1139 |
} |
1140 |
|
1141 |
static inline uint32_t efsctsiz(CPUPPCState *env, uint32_t val) |
1142 |
{ |
1143 |
CPU_FloatU u; |
1144 |
|
1145 |
u.l = val; |
1146 |
/* NaN are not treated the same way IEEE 754 does */
|
1147 |
if (unlikely(float32_is_quiet_nan(u.f))) {
|
1148 |
return 0; |
1149 |
} |
1150 |
|
1151 |
return float32_to_int32_round_to_zero(u.f, &env->vec_status);
|
1152 |
} |
1153 |
|
1154 |
static inline uint32_t efsctuiz(CPUPPCState *env, uint32_t val) |
1155 |
{ |
1156 |
CPU_FloatU u; |
1157 |
|
1158 |
u.l = val; |
1159 |
/* NaN are not treated the same way IEEE 754 does */
|
1160 |
if (unlikely(float32_is_quiet_nan(u.f))) {
|
1161 |
return 0; |
1162 |
} |
1163 |
|
1164 |
return float32_to_uint32_round_to_zero(u.f, &env->vec_status);
|
1165 |
} |
1166 |
|
1167 |
static inline uint32_t efscfsf(CPUPPCState *env, uint32_t val) |
1168 |
{ |
1169 |
CPU_FloatU u; |
1170 |
float32 tmp; |
1171 |
|
1172 |
u.f = int32_to_float32(val, &env->vec_status); |
1173 |
tmp = int64_to_float32(1ULL << 32, &env->vec_status); |
1174 |
u.f = float32_div(u.f, tmp, &env->vec_status); |
1175 |
|
1176 |
return u.l;
|
1177 |
} |
1178 |
|
1179 |
static inline uint32_t efscfuf(CPUPPCState *env, uint32_t val) |
1180 |
{ |
1181 |
CPU_FloatU u; |
1182 |
float32 tmp; |
1183 |
|
1184 |
u.f = uint32_to_float32(val, &env->vec_status); |
1185 |
tmp = uint64_to_float32(1ULL << 32, &env->vec_status); |
1186 |
u.f = float32_div(u.f, tmp, &env->vec_status); |
1187 |
|
1188 |
return u.l;
|
1189 |
} |
1190 |
|
1191 |
static inline uint32_t efsctsf(CPUPPCState *env, uint32_t val) |
1192 |
{ |
1193 |
CPU_FloatU u; |
1194 |
float32 tmp; |
1195 |
|
1196 |
u.l = val; |
1197 |
/* NaN are not treated the same way IEEE 754 does */
|
1198 |
if (unlikely(float32_is_quiet_nan(u.f))) {
|
1199 |
return 0; |
1200 |
} |
1201 |
tmp = uint64_to_float32(1ULL << 32, &env->vec_status); |
1202 |
u.f = float32_mul(u.f, tmp, &env->vec_status); |
1203 |
|
1204 |
return float32_to_int32(u.f, &env->vec_status);
|
1205 |
} |
1206 |
|
1207 |
static inline uint32_t efsctuf(CPUPPCState *env, uint32_t val) |
1208 |
{ |
1209 |
CPU_FloatU u; |
1210 |
float32 tmp; |
1211 |
|
1212 |
u.l = val; |
1213 |
/* NaN are not treated the same way IEEE 754 does */
|
1214 |
if (unlikely(float32_is_quiet_nan(u.f))) {
|
1215 |
return 0; |
1216 |
} |
1217 |
tmp = uint64_to_float32(1ULL << 32, &env->vec_status); |
1218 |
u.f = float32_mul(u.f, tmp, &env->vec_status); |
1219 |
|
1220 |
return float32_to_uint32(u.f, &env->vec_status);
|
1221 |
} |
1222 |
|
1223 |
#define HELPER_SPE_SINGLE_CONV(name) \
|
1224 |
uint32_t helper_e##name(CPUPPCState *env, uint32_t val) \ |
1225 |
{ \ |
1226 |
return e##name(env, val); \ |
1227 |
} |
1228 |
/* efscfsi */
|
1229 |
HELPER_SPE_SINGLE_CONV(fscfsi); |
1230 |
/* efscfui */
|
1231 |
HELPER_SPE_SINGLE_CONV(fscfui); |
1232 |
/* efscfuf */
|
1233 |
HELPER_SPE_SINGLE_CONV(fscfuf); |
1234 |
/* efscfsf */
|
1235 |
HELPER_SPE_SINGLE_CONV(fscfsf); |
1236 |
/* efsctsi */
|
1237 |
HELPER_SPE_SINGLE_CONV(fsctsi); |
1238 |
/* efsctui */
|
1239 |
HELPER_SPE_SINGLE_CONV(fsctui); |
1240 |
/* efsctsiz */
|
1241 |
HELPER_SPE_SINGLE_CONV(fsctsiz); |
1242 |
/* efsctuiz */
|
1243 |
HELPER_SPE_SINGLE_CONV(fsctuiz); |
1244 |
/* efsctsf */
|
1245 |
HELPER_SPE_SINGLE_CONV(fsctsf); |
1246 |
/* efsctuf */
|
1247 |
HELPER_SPE_SINGLE_CONV(fsctuf); |
1248 |
|
1249 |
#define HELPER_SPE_VECTOR_CONV(name) \
|
1250 |
uint64_t helper_ev##name(CPUPPCState *env, uint64_t val) \ |
1251 |
{ \ |
1252 |
return ((uint64_t)e##name(env, val >> 32) << 32) | \ |
1253 |
(uint64_t)e##name(env, val); \ |
1254 |
} |
1255 |
/* evfscfsi */
|
1256 |
HELPER_SPE_VECTOR_CONV(fscfsi); |
1257 |
/* evfscfui */
|
1258 |
HELPER_SPE_VECTOR_CONV(fscfui); |
1259 |
/* evfscfuf */
|
1260 |
HELPER_SPE_VECTOR_CONV(fscfuf); |
1261 |
/* evfscfsf */
|
1262 |
HELPER_SPE_VECTOR_CONV(fscfsf); |
1263 |
/* evfsctsi */
|
1264 |
HELPER_SPE_VECTOR_CONV(fsctsi); |
1265 |
/* evfsctui */
|
1266 |
HELPER_SPE_VECTOR_CONV(fsctui); |
1267 |
/* evfsctsiz */
|
1268 |
HELPER_SPE_VECTOR_CONV(fsctsiz); |
1269 |
/* evfsctuiz */
|
1270 |
HELPER_SPE_VECTOR_CONV(fsctuiz); |
1271 |
/* evfsctsf */
|
1272 |
HELPER_SPE_VECTOR_CONV(fsctsf); |
1273 |
/* evfsctuf */
|
1274 |
HELPER_SPE_VECTOR_CONV(fsctuf); |
1275 |
|
1276 |
/* Single-precision floating-point arithmetic */
|
1277 |
static inline uint32_t efsadd(CPUPPCState *env, uint32_t op1, uint32_t op2) |
1278 |
{ |
1279 |
CPU_FloatU u1, u2; |
1280 |
|
1281 |
u1.l = op1; |
1282 |
u2.l = op2; |
1283 |
u1.f = float32_add(u1.f, u2.f, &env->vec_status); |
1284 |
return u1.l;
|
1285 |
} |
1286 |
|
1287 |
static inline uint32_t efssub(CPUPPCState *env, uint32_t op1, uint32_t op2) |
1288 |
{ |
1289 |
CPU_FloatU u1, u2; |
1290 |
|
1291 |
u1.l = op1; |
1292 |
u2.l = op2; |
1293 |
u1.f = float32_sub(u1.f, u2.f, &env->vec_status); |
1294 |
return u1.l;
|
1295 |
} |
1296 |
|
1297 |
static inline uint32_t efsmul(CPUPPCState *env, uint32_t op1, uint32_t op2) |
1298 |
{ |
1299 |
CPU_FloatU u1, u2; |
1300 |
|
1301 |
u1.l = op1; |
1302 |
u2.l = op2; |
1303 |
u1.f = float32_mul(u1.f, u2.f, &env->vec_status); |
1304 |
return u1.l;
|
1305 |
} |
1306 |
|
1307 |
static inline uint32_t efsdiv(CPUPPCState *env, uint32_t op1, uint32_t op2) |
1308 |
{ |
1309 |
CPU_FloatU u1, u2; |
1310 |
|
1311 |
u1.l = op1; |
1312 |
u2.l = op2; |
1313 |
u1.f = float32_div(u1.f, u2.f, &env->vec_status); |
1314 |
return u1.l;
|
1315 |
} |
1316 |
|
1317 |
#define HELPER_SPE_SINGLE_ARITH(name) \
|
1318 |
uint32_t helper_e##name(CPUPPCState *env, uint32_t op1, uint32_t op2) \ |
1319 |
{ \ |
1320 |
return e##name(env, op1, op2); \ |
1321 |
} |
1322 |
/* efsadd */
|
1323 |
HELPER_SPE_SINGLE_ARITH(fsadd); |
1324 |
/* efssub */
|
1325 |
HELPER_SPE_SINGLE_ARITH(fssub); |
1326 |
/* efsmul */
|
1327 |
HELPER_SPE_SINGLE_ARITH(fsmul); |
1328 |
/* efsdiv */
|
1329 |
HELPER_SPE_SINGLE_ARITH(fsdiv); |
1330 |
|
1331 |
#define HELPER_SPE_VECTOR_ARITH(name) \
|
1332 |
uint64_t helper_ev##name(CPUPPCState *env, uint64_t op1, uint64_t op2) \ |
1333 |
{ \ |
1334 |
return ((uint64_t)e##name(env, op1 >> 32, op2 >> 32) << 32) | \ |
1335 |
(uint64_t)e##name(env, op1, op2); \ |
1336 |
} |
1337 |
/* evfsadd */
|
1338 |
HELPER_SPE_VECTOR_ARITH(fsadd); |
1339 |
/* evfssub */
|
1340 |
HELPER_SPE_VECTOR_ARITH(fssub); |
1341 |
/* evfsmul */
|
1342 |
HELPER_SPE_VECTOR_ARITH(fsmul); |
1343 |
/* evfsdiv */
|
1344 |
HELPER_SPE_VECTOR_ARITH(fsdiv); |
1345 |
|
1346 |
/* Single-precision floating-point comparisons */
|
1347 |
static inline uint32_t efscmplt(CPUPPCState *env, uint32_t op1, uint32_t op2) |
1348 |
{ |
1349 |
CPU_FloatU u1, u2; |
1350 |
|
1351 |
u1.l = op1; |
1352 |
u2.l = op2; |
1353 |
return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0; |
1354 |
} |
1355 |
|
1356 |
static inline uint32_t efscmpgt(CPUPPCState *env, uint32_t op1, uint32_t op2) |
1357 |
{ |
1358 |
CPU_FloatU u1, u2; |
1359 |
|
1360 |
u1.l = op1; |
1361 |
u2.l = op2; |
1362 |
return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4; |
1363 |
} |
1364 |
|
1365 |
static inline uint32_t efscmpeq(CPUPPCState *env, uint32_t op1, uint32_t op2) |
1366 |
{ |
1367 |
CPU_FloatU u1, u2; |
1368 |
|
1369 |
u1.l = op1; |
1370 |
u2.l = op2; |
1371 |
return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0; |
1372 |
} |
1373 |
|
1374 |
static inline uint32_t efststlt(CPUPPCState *env, uint32_t op1, uint32_t op2) |
1375 |
{ |
1376 |
/* XXX: TODO: ignore special values (NaN, infinites, ...) */
|
1377 |
return efscmplt(env, op1, op2);
|
1378 |
} |
1379 |
|
1380 |
static inline uint32_t efststgt(CPUPPCState *env, uint32_t op1, uint32_t op2) |
1381 |
{ |
1382 |
/* XXX: TODO: ignore special values (NaN, infinites, ...) */
|
1383 |
return efscmpgt(env, op1, op2);
|
1384 |
} |
1385 |
|
1386 |
static inline uint32_t efststeq(CPUPPCState *env, uint32_t op1, uint32_t op2) |
1387 |
{ |
1388 |
/* XXX: TODO: ignore special values (NaN, infinites, ...) */
|
1389 |
return efscmpeq(env, op1, op2);
|
1390 |
} |
1391 |
|
1392 |
#define HELPER_SINGLE_SPE_CMP(name) \
|
1393 |
uint32_t helper_e##name(CPUPPCState *env, uint32_t op1, uint32_t op2) \ |
1394 |
{ \ |
1395 |
return e##name(env, op1, op2) << 2; \ |
1396 |
} |
1397 |
/* efststlt */
|
1398 |
HELPER_SINGLE_SPE_CMP(fststlt); |
1399 |
/* efststgt */
|
1400 |
HELPER_SINGLE_SPE_CMP(fststgt); |
1401 |
/* efststeq */
|
1402 |
HELPER_SINGLE_SPE_CMP(fststeq); |
1403 |
/* efscmplt */
|
1404 |
HELPER_SINGLE_SPE_CMP(fscmplt); |
1405 |
/* efscmpgt */
|
1406 |
HELPER_SINGLE_SPE_CMP(fscmpgt); |
1407 |
/* efscmpeq */
|
1408 |
HELPER_SINGLE_SPE_CMP(fscmpeq); |
1409 |
|
1410 |
static inline uint32_t evcmp_merge(int t0, int t1) |
1411 |
{ |
1412 |
return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1); |
1413 |
} |
1414 |
|
1415 |
#define HELPER_VECTOR_SPE_CMP(name) \
|
1416 |
uint32_t helper_ev##name(CPUPPCState *env, uint64_t op1, uint64_t op2) \ |
1417 |
{ \ |
1418 |
return evcmp_merge(e##name(env, op1 >> 32, op2 >> 32), \ |
1419 |
e##name(env, op1, op2)); \ |
1420 |
} |
1421 |
/* evfststlt */
|
1422 |
HELPER_VECTOR_SPE_CMP(fststlt); |
1423 |
/* evfststgt */
|
1424 |
HELPER_VECTOR_SPE_CMP(fststgt); |
1425 |
/* evfststeq */
|
1426 |
HELPER_VECTOR_SPE_CMP(fststeq); |
1427 |
/* evfscmplt */
|
1428 |
HELPER_VECTOR_SPE_CMP(fscmplt); |
1429 |
/* evfscmpgt */
|
1430 |
HELPER_VECTOR_SPE_CMP(fscmpgt); |
1431 |
/* evfscmpeq */
|
1432 |
HELPER_VECTOR_SPE_CMP(fscmpeq); |
1433 |
|
1434 |
/* Double-precision floating-point conversion */
|
1435 |
uint64_t helper_efdcfsi(CPUPPCState *env, uint32_t val) |
1436 |
{ |
1437 |
CPU_DoubleU u; |
1438 |
|
1439 |
u.d = int32_to_float64(val, &env->vec_status); |
1440 |
|
1441 |
return u.ll;
|
1442 |
} |
1443 |
|
1444 |
uint64_t helper_efdcfsid(CPUPPCState *env, uint64_t val) |
1445 |
{ |
1446 |
CPU_DoubleU u; |
1447 |
|
1448 |
u.d = int64_to_float64(val, &env->vec_status); |
1449 |
|
1450 |
return u.ll;
|
1451 |
} |
1452 |
|
1453 |
uint64_t helper_efdcfui(CPUPPCState *env, uint32_t val) |
1454 |
{ |
1455 |
CPU_DoubleU u; |
1456 |
|
1457 |
u.d = uint32_to_float64(val, &env->vec_status); |
1458 |
|
1459 |
return u.ll;
|
1460 |
} |
1461 |
|
1462 |
uint64_t helper_efdcfuid(CPUPPCState *env, uint64_t val) |
1463 |
{ |
1464 |
CPU_DoubleU u; |
1465 |
|
1466 |
u.d = uint64_to_float64(val, &env->vec_status); |
1467 |
|
1468 |
return u.ll;
|
1469 |
} |
1470 |
|
1471 |
uint32_t helper_efdctsi(CPUPPCState *env, uint64_t val) |
1472 |
{ |
1473 |
CPU_DoubleU u; |
1474 |
|
1475 |
u.ll = val; |
1476 |
/* NaN are not treated the same way IEEE 754 does */
|
1477 |
if (unlikely(float64_is_any_nan(u.d))) {
|
1478 |
return 0; |
1479 |
} |
1480 |
|
1481 |
return float64_to_int32(u.d, &env->vec_status);
|
1482 |
} |
1483 |
|
1484 |
uint32_t helper_efdctui(CPUPPCState *env, uint64_t val) |
1485 |
{ |
1486 |
CPU_DoubleU u; |
1487 |
|
1488 |
u.ll = val; |
1489 |
/* NaN are not treated the same way IEEE 754 does */
|
1490 |
if (unlikely(float64_is_any_nan(u.d))) {
|
1491 |
return 0; |
1492 |
} |
1493 |
|
1494 |
return float64_to_uint32(u.d, &env->vec_status);
|
1495 |
} |
1496 |
|
1497 |
uint32_t helper_efdctsiz(CPUPPCState *env, uint64_t val) |
1498 |
{ |
1499 |
CPU_DoubleU u; |
1500 |
|
1501 |
u.ll = val; |
1502 |
/* NaN are not treated the same way IEEE 754 does */
|
1503 |
if (unlikely(float64_is_any_nan(u.d))) {
|
1504 |
return 0; |
1505 |
} |
1506 |
|
1507 |
return float64_to_int32_round_to_zero(u.d, &env->vec_status);
|
1508 |
} |
1509 |
|
1510 |
uint64_t helper_efdctsidz(CPUPPCState *env, uint64_t val) |
1511 |
{ |
1512 |
CPU_DoubleU u; |
1513 |
|
1514 |
u.ll = val; |
1515 |
/* NaN are not treated the same way IEEE 754 does */
|
1516 |
if (unlikely(float64_is_any_nan(u.d))) {
|
1517 |
return 0; |
1518 |
} |
1519 |
|
1520 |
return float64_to_int64_round_to_zero(u.d, &env->vec_status);
|
1521 |
} |
1522 |
|
1523 |
uint32_t helper_efdctuiz(CPUPPCState *env, uint64_t val) |
1524 |
{ |
1525 |
CPU_DoubleU u; |
1526 |
|
1527 |
u.ll = val; |
1528 |
/* NaN are not treated the same way IEEE 754 does */
|
1529 |
if (unlikely(float64_is_any_nan(u.d))) {
|
1530 |
return 0; |
1531 |
} |
1532 |
|
1533 |
return float64_to_uint32_round_to_zero(u.d, &env->vec_status);
|
1534 |
} |
1535 |
|
1536 |
uint64_t helper_efdctuidz(CPUPPCState *env, uint64_t val) |
1537 |
{ |
1538 |
CPU_DoubleU u; |
1539 |
|
1540 |
u.ll = val; |
1541 |
/* NaN are not treated the same way IEEE 754 does */
|
1542 |
if (unlikely(float64_is_any_nan(u.d))) {
|
1543 |
return 0; |
1544 |
} |
1545 |
|
1546 |
return float64_to_uint64_round_to_zero(u.d, &env->vec_status);
|
1547 |
} |
1548 |
|
1549 |
uint64_t helper_efdcfsf(CPUPPCState *env, uint32_t val) |
1550 |
{ |
1551 |
CPU_DoubleU u; |
1552 |
float64 tmp; |
1553 |
|
1554 |
u.d = int32_to_float64(val, &env->vec_status); |
1555 |
tmp = int64_to_float64(1ULL << 32, &env->vec_status); |
1556 |
u.d = float64_div(u.d, tmp, &env->vec_status); |
1557 |
|
1558 |
return u.ll;
|
1559 |
} |
1560 |
|
1561 |
uint64_t helper_efdcfuf(CPUPPCState *env, uint32_t val) |
1562 |
{ |
1563 |
CPU_DoubleU u; |
1564 |
float64 tmp; |
1565 |
|
1566 |
u.d = uint32_to_float64(val, &env->vec_status); |
1567 |
tmp = int64_to_float64(1ULL << 32, &env->vec_status); |
1568 |
u.d = float64_div(u.d, tmp, &env->vec_status); |
1569 |
|
1570 |
return u.ll;
|
1571 |
} |
1572 |
|
1573 |
uint32_t helper_efdctsf(CPUPPCState *env, uint64_t val) |
1574 |
{ |
1575 |
CPU_DoubleU u; |
1576 |
float64 tmp; |
1577 |
|
1578 |
u.ll = val; |
1579 |
/* NaN are not treated the same way IEEE 754 does */
|
1580 |
if (unlikely(float64_is_any_nan(u.d))) {
|
1581 |
return 0; |
1582 |
} |
1583 |
tmp = uint64_to_float64(1ULL << 32, &env->vec_status); |
1584 |
u.d = float64_mul(u.d, tmp, &env->vec_status); |
1585 |
|
1586 |
return float64_to_int32(u.d, &env->vec_status);
|
1587 |
} |
1588 |
|
1589 |
uint32_t helper_efdctuf(CPUPPCState *env, uint64_t val) |
1590 |
{ |
1591 |
CPU_DoubleU u; |
1592 |
float64 tmp; |
1593 |
|
1594 |
u.ll = val; |
1595 |
/* NaN are not treated the same way IEEE 754 does */
|
1596 |
if (unlikely(float64_is_any_nan(u.d))) {
|
1597 |
return 0; |
1598 |
} |
1599 |
tmp = uint64_to_float64(1ULL << 32, &env->vec_status); |
1600 |
u.d = float64_mul(u.d, tmp, &env->vec_status); |
1601 |
|
1602 |
return float64_to_uint32(u.d, &env->vec_status);
|
1603 |
} |
1604 |
|
1605 |
uint32_t helper_efscfd(CPUPPCState *env, uint64_t val) |
1606 |
{ |
1607 |
CPU_DoubleU u1; |
1608 |
CPU_FloatU u2; |
1609 |
|
1610 |
u1.ll = val; |
1611 |
u2.f = float64_to_float32(u1.d, &env->vec_status); |
1612 |
|
1613 |
return u2.l;
|
1614 |
} |
1615 |
|
1616 |
uint64_t helper_efdcfs(CPUPPCState *env, uint32_t val) |
1617 |
{ |
1618 |
CPU_DoubleU u2; |
1619 |
CPU_FloatU u1; |
1620 |
|
1621 |
u1.l = val; |
1622 |
u2.d = float32_to_float64(u1.f, &env->vec_status); |
1623 |
|
1624 |
return u2.ll;
|
1625 |
} |
1626 |
|
1627 |
/* Double precision fixed-point arithmetic */
|
1628 |
uint64_t helper_efdadd(CPUPPCState *env, uint64_t op1, uint64_t op2) |
1629 |
{ |
1630 |
CPU_DoubleU u1, u2; |
1631 |
|
1632 |
u1.ll = op1; |
1633 |
u2.ll = op2; |
1634 |
u1.d = float64_add(u1.d, u2.d, &env->vec_status); |
1635 |
return u1.ll;
|
1636 |
} |
1637 |
|
1638 |
uint64_t helper_efdsub(CPUPPCState *env, uint64_t op1, uint64_t op2) |
1639 |
{ |
1640 |
CPU_DoubleU u1, u2; |
1641 |
|
1642 |
u1.ll = op1; |
1643 |
u2.ll = op2; |
1644 |
u1.d = float64_sub(u1.d, u2.d, &env->vec_status); |
1645 |
return u1.ll;
|
1646 |
} |
1647 |
|
1648 |
uint64_t helper_efdmul(CPUPPCState *env, uint64_t op1, uint64_t op2) |
1649 |
{ |
1650 |
CPU_DoubleU u1, u2; |
1651 |
|
1652 |
u1.ll = op1; |
1653 |
u2.ll = op2; |
1654 |
u1.d = float64_mul(u1.d, u2.d, &env->vec_status); |
1655 |
return u1.ll;
|
1656 |
} |
1657 |
|
1658 |
uint64_t helper_efddiv(CPUPPCState *env, uint64_t op1, uint64_t op2) |
1659 |
{ |
1660 |
CPU_DoubleU u1, u2; |
1661 |
|
1662 |
u1.ll = op1; |
1663 |
u2.ll = op2; |
1664 |
u1.d = float64_div(u1.d, u2.d, &env->vec_status); |
1665 |
return u1.ll;
|
1666 |
} |
1667 |
|
1668 |
/* Double precision floating point helpers */
|
1669 |
uint32_t helper_efdtstlt(CPUPPCState *env, uint64_t op1, uint64_t op2) |
1670 |
{ |
1671 |
CPU_DoubleU u1, u2; |
1672 |
|
1673 |
u1.ll = op1; |
1674 |
u2.ll = op2; |
1675 |
return float64_lt(u1.d, u2.d, &env->vec_status) ? 4 : 0; |
1676 |
} |
1677 |
|
1678 |
uint32_t helper_efdtstgt(CPUPPCState *env, uint64_t op1, uint64_t op2) |
1679 |
{ |
1680 |
CPU_DoubleU u1, u2; |
1681 |
|
1682 |
u1.ll = op1; |
1683 |
u2.ll = op2; |
1684 |
return float64_le(u1.d, u2.d, &env->vec_status) ? 0 : 4; |
1685 |
} |
1686 |
|
1687 |
uint32_t helper_efdtsteq(CPUPPCState *env, uint64_t op1, uint64_t op2) |
1688 |
{ |
1689 |
CPU_DoubleU u1, u2; |
1690 |
|
1691 |
u1.ll = op1; |
1692 |
u2.ll = op2; |
1693 |
return float64_eq_quiet(u1.d, u2.d, &env->vec_status) ? 4 : 0; |
1694 |
} |
1695 |
|
1696 |
uint32_t helper_efdcmplt(CPUPPCState *env, uint64_t op1, uint64_t op2) |
1697 |
{ |
1698 |
/* XXX: TODO: test special values (NaN, infinites, ...) */
|
1699 |
return helper_efdtstlt(env, op1, op2);
|
1700 |
} |
1701 |
|
1702 |
uint32_t helper_efdcmpgt(CPUPPCState *env, uint64_t op1, uint64_t op2) |
1703 |
{ |
1704 |
/* XXX: TODO: test special values (NaN, infinites, ...) */
|
1705 |
return helper_efdtstgt(env, op1, op2);
|
1706 |
} |
1707 |
|
1708 |
uint32_t helper_efdcmpeq(CPUPPCState *env, uint64_t op1, uint64_t op2) |
1709 |
{ |
1710 |
/* XXX: TODO: test special values (NaN, infinites, ...) */
|
1711 |
return helper_efdtsteq(env, op1, op2);
|
1712 |
} |