root / target-ppc / fpu_helper.c @ fab7fe42
History | View | Annotate | Download (104.3 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 |
int set_fpcc)
|
111 |
{ |
112 |
uint64_t ret = 0;
|
113 |
int ve;
|
114 |
|
115 |
ve = fpscr_ve; |
116 |
switch (op) {
|
117 |
case POWERPC_EXCP_FP_VXSNAN:
|
118 |
env->fpscr |= 1 << FPSCR_VXSNAN;
|
119 |
break;
|
120 |
case POWERPC_EXCP_FP_VXSOFT:
|
121 |
env->fpscr |= 1 << FPSCR_VXSOFT;
|
122 |
break;
|
123 |
case POWERPC_EXCP_FP_VXISI:
|
124 |
/* Magnitude subtraction of infinities */
|
125 |
env->fpscr |= 1 << FPSCR_VXISI;
|
126 |
goto update_arith;
|
127 |
case POWERPC_EXCP_FP_VXIDI:
|
128 |
/* Division of infinity by infinity */
|
129 |
env->fpscr |= 1 << FPSCR_VXIDI;
|
130 |
goto update_arith;
|
131 |
case POWERPC_EXCP_FP_VXZDZ:
|
132 |
/* Division of zero by zero */
|
133 |
env->fpscr |= 1 << FPSCR_VXZDZ;
|
134 |
goto update_arith;
|
135 |
case POWERPC_EXCP_FP_VXIMZ:
|
136 |
/* Multiplication of zero by infinity */
|
137 |
env->fpscr |= 1 << FPSCR_VXIMZ;
|
138 |
goto update_arith;
|
139 |
case POWERPC_EXCP_FP_VXVC:
|
140 |
/* Ordered comparison of NaN */
|
141 |
env->fpscr |= 1 << FPSCR_VXVC;
|
142 |
if (set_fpcc) {
|
143 |
env->fpscr &= ~(0xF << FPSCR_FPCC);
|
144 |
env->fpscr |= 0x11 << FPSCR_FPCC;
|
145 |
} |
146 |
/* We must update the target FPR before raising the exception */
|
147 |
if (ve != 0) { |
148 |
env->exception_index = POWERPC_EXCP_PROGRAM; |
149 |
env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC; |
150 |
/* Update the floating-point enabled exception summary */
|
151 |
env->fpscr |= 1 << FPSCR_FEX;
|
152 |
/* Exception is differed */
|
153 |
ve = 0;
|
154 |
} |
155 |
break;
|
156 |
case POWERPC_EXCP_FP_VXSQRT:
|
157 |
/* Square root of a negative number */
|
158 |
env->fpscr |= 1 << FPSCR_VXSQRT;
|
159 |
update_arith:
|
160 |
env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); |
161 |
if (ve == 0) { |
162 |
/* Set the result to quiet NaN */
|
163 |
ret = 0x7FF8000000000000ULL;
|
164 |
if (set_fpcc) {
|
165 |
env->fpscr &= ~(0xF << FPSCR_FPCC);
|
166 |
env->fpscr |= 0x11 << FPSCR_FPCC;
|
167 |
} |
168 |
} |
169 |
break;
|
170 |
case POWERPC_EXCP_FP_VXCVI:
|
171 |
/* Invalid conversion */
|
172 |
env->fpscr |= 1 << FPSCR_VXCVI;
|
173 |
env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); |
174 |
if (ve == 0) { |
175 |
/* Set the result to quiet NaN */
|
176 |
ret = 0x7FF8000000000000ULL;
|
177 |
if (set_fpcc) {
|
178 |
env->fpscr &= ~(0xF << FPSCR_FPCC);
|
179 |
env->fpscr |= 0x11 << FPSCR_FPCC;
|
180 |
} |
181 |
} |
182 |
break;
|
183 |
} |
184 |
/* Update the floating-point invalid operation summary */
|
185 |
env->fpscr |= 1 << FPSCR_VX;
|
186 |
/* Update the floating-point exception summary */
|
187 |
env->fpscr |= 1 << FPSCR_FX;
|
188 |
if (ve != 0) { |
189 |
/* Update the floating-point enabled exception summary */
|
190 |
env->fpscr |= 1 << FPSCR_FEX;
|
191 |
if (msr_fe0 != 0 || msr_fe1 != 0) { |
192 |
helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, |
193 |
POWERPC_EXCP_FP | op); |
194 |
} |
195 |
} |
196 |
return ret;
|
197 |
} |
198 |
|
199 |
static inline void float_zero_divide_excp(CPUPPCState *env) |
200 |
{ |
201 |
env->fpscr |= 1 << FPSCR_ZX;
|
202 |
env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI)); |
203 |
/* Update the floating-point exception summary */
|
204 |
env->fpscr |= 1 << FPSCR_FX;
|
205 |
if (fpscr_ze != 0) { |
206 |
/* Update the floating-point enabled exception summary */
|
207 |
env->fpscr |= 1 << FPSCR_FEX;
|
208 |
if (msr_fe0 != 0 || msr_fe1 != 0) { |
209 |
helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM, |
210 |
POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX); |
211 |
} |
212 |
} |
213 |
} |
214 |
|
215 |
static inline void float_overflow_excp(CPUPPCState *env) |
216 |
{ |
217 |
env->fpscr |= 1 << FPSCR_OX;
|
218 |
/* Update the floating-point exception summary */
|
219 |
env->fpscr |= 1 << FPSCR_FX;
|
220 |
if (fpscr_oe != 0) { |
221 |
/* XXX: should adjust the result */
|
222 |
/* Update the floating-point enabled exception summary */
|
223 |
env->fpscr |= 1 << FPSCR_FEX;
|
224 |
/* We must update the target FPR before raising the exception */
|
225 |
env->exception_index = POWERPC_EXCP_PROGRAM; |
226 |
env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX; |
227 |
} else {
|
228 |
env->fpscr |= 1 << FPSCR_XX;
|
229 |
env->fpscr |= 1 << FPSCR_FI;
|
230 |
} |
231 |
} |
232 |
|
233 |
static inline void float_underflow_excp(CPUPPCState *env) |
234 |
{ |
235 |
env->fpscr |= 1 << FPSCR_UX;
|
236 |
/* Update the floating-point exception summary */
|
237 |
env->fpscr |= 1 << FPSCR_FX;
|
238 |
if (fpscr_ue != 0) { |
239 |
/* XXX: should adjust the result */
|
240 |
/* Update the floating-point enabled exception summary */
|
241 |
env->fpscr |= 1 << FPSCR_FEX;
|
242 |
/* We must update the target FPR before raising the exception */
|
243 |
env->exception_index = POWERPC_EXCP_PROGRAM; |
244 |
env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX; |
245 |
} |
246 |
} |
247 |
|
248 |
static inline void float_inexact_excp(CPUPPCState *env) |
249 |
{ |
250 |
env->fpscr |= 1 << FPSCR_XX;
|
251 |
/* Update the floating-point exception summary */
|
252 |
env->fpscr |= 1 << FPSCR_FX;
|
253 |
if (fpscr_xe != 0) { |
254 |
/* Update the floating-point enabled exception summary */
|
255 |
env->fpscr |= 1 << FPSCR_FEX;
|
256 |
/* We must update the target FPR before raising the exception */
|
257 |
env->exception_index = POWERPC_EXCP_PROGRAM; |
258 |
env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX; |
259 |
} |
260 |
} |
261 |
|
262 |
static inline void fpscr_set_rounding_mode(CPUPPCState *env) |
263 |
{ |
264 |
int rnd_type;
|
265 |
|
266 |
/* Set rounding mode */
|
267 |
switch (fpscr_rn) {
|
268 |
case 0: |
269 |
/* Best approximation (round to nearest) */
|
270 |
rnd_type = float_round_nearest_even; |
271 |
break;
|
272 |
case 1: |
273 |
/* Smaller magnitude (round toward zero) */
|
274 |
rnd_type = float_round_to_zero; |
275 |
break;
|
276 |
case 2: |
277 |
/* Round toward +infinite */
|
278 |
rnd_type = float_round_up; |
279 |
break;
|
280 |
default:
|
281 |
case 3: |
282 |
/* Round toward -infinite */
|
283 |
rnd_type = float_round_down; |
284 |
break;
|
285 |
} |
286 |
set_float_rounding_mode(rnd_type, &env->fp_status); |
287 |
} |
288 |
|
289 |
void helper_fpscr_clrbit(CPUPPCState *env, uint32_t bit)
|
290 |
{ |
291 |
int prev;
|
292 |
|
293 |
prev = (env->fpscr >> bit) & 1;
|
294 |
env->fpscr &= ~(1 << bit);
|
295 |
if (prev == 1) { |
296 |
switch (bit) {
|
297 |
case FPSCR_RN1:
|
298 |
case FPSCR_RN:
|
299 |
fpscr_set_rounding_mode(env); |
300 |
break;
|
301 |
default:
|
302 |
break;
|
303 |
} |
304 |
} |
305 |
} |
306 |
|
307 |
void helper_fpscr_setbit(CPUPPCState *env, uint32_t bit)
|
308 |
{ |
309 |
int prev;
|
310 |
|
311 |
prev = (env->fpscr >> bit) & 1;
|
312 |
env->fpscr |= 1 << bit;
|
313 |
if (prev == 0) { |
314 |
switch (bit) {
|
315 |
case FPSCR_VX:
|
316 |
env->fpscr |= 1 << FPSCR_FX;
|
317 |
if (fpscr_ve) {
|
318 |
goto raise_ve;
|
319 |
} |
320 |
break;
|
321 |
case FPSCR_OX:
|
322 |
env->fpscr |= 1 << FPSCR_FX;
|
323 |
if (fpscr_oe) {
|
324 |
goto raise_oe;
|
325 |
} |
326 |
break;
|
327 |
case FPSCR_UX:
|
328 |
env->fpscr |= 1 << FPSCR_FX;
|
329 |
if (fpscr_ue) {
|
330 |
goto raise_ue;
|
331 |
} |
332 |
break;
|
333 |
case FPSCR_ZX:
|
334 |
env->fpscr |= 1 << FPSCR_FX;
|
335 |
if (fpscr_ze) {
|
336 |
goto raise_ze;
|
337 |
} |
338 |
break;
|
339 |
case FPSCR_XX:
|
340 |
env->fpscr |= 1 << FPSCR_FX;
|
341 |
if (fpscr_xe) {
|
342 |
goto raise_xe;
|
343 |
} |
344 |
break;
|
345 |
case FPSCR_VXSNAN:
|
346 |
case FPSCR_VXISI:
|
347 |
case FPSCR_VXIDI:
|
348 |
case FPSCR_VXZDZ:
|
349 |
case FPSCR_VXIMZ:
|
350 |
case FPSCR_VXVC:
|
351 |
case FPSCR_VXSOFT:
|
352 |
case FPSCR_VXSQRT:
|
353 |
case FPSCR_VXCVI:
|
354 |
env->fpscr |= 1 << FPSCR_VX;
|
355 |
env->fpscr |= 1 << FPSCR_FX;
|
356 |
if (fpscr_ve != 0) { |
357 |
goto raise_ve;
|
358 |
} |
359 |
break;
|
360 |
case FPSCR_VE:
|
361 |
if (fpscr_vx != 0) { |
362 |
raise_ve:
|
363 |
env->error_code = POWERPC_EXCP_FP; |
364 |
if (fpscr_vxsnan) {
|
365 |
env->error_code |= POWERPC_EXCP_FP_VXSNAN; |
366 |
} |
367 |
if (fpscr_vxisi) {
|
368 |
env->error_code |= POWERPC_EXCP_FP_VXISI; |
369 |
} |
370 |
if (fpscr_vxidi) {
|
371 |
env->error_code |= POWERPC_EXCP_FP_VXIDI; |
372 |
} |
373 |
if (fpscr_vxzdz) {
|
374 |
env->error_code |= POWERPC_EXCP_FP_VXZDZ; |
375 |
} |
376 |
if (fpscr_vximz) {
|
377 |
env->error_code |= POWERPC_EXCP_FP_VXIMZ; |
378 |
} |
379 |
if (fpscr_vxvc) {
|
380 |
env->error_code |= POWERPC_EXCP_FP_VXVC; |
381 |
} |
382 |
if (fpscr_vxsoft) {
|
383 |
env->error_code |= POWERPC_EXCP_FP_VXSOFT; |
384 |
} |
385 |
if (fpscr_vxsqrt) {
|
386 |
env->error_code |= POWERPC_EXCP_FP_VXSQRT; |
387 |
} |
388 |
if (fpscr_vxcvi) {
|
389 |
env->error_code |= POWERPC_EXCP_FP_VXCVI; |
390 |
} |
391 |
goto raise_excp;
|
392 |
} |
393 |
break;
|
394 |
case FPSCR_OE:
|
395 |
if (fpscr_ox != 0) { |
396 |
raise_oe:
|
397 |
env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX; |
398 |
goto raise_excp;
|
399 |
} |
400 |
break;
|
401 |
case FPSCR_UE:
|
402 |
if (fpscr_ux != 0) { |
403 |
raise_ue:
|
404 |
env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX; |
405 |
goto raise_excp;
|
406 |
} |
407 |
break;
|
408 |
case FPSCR_ZE:
|
409 |
if (fpscr_zx != 0) { |
410 |
raise_ze:
|
411 |
env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX; |
412 |
goto raise_excp;
|
413 |
} |
414 |
break;
|
415 |
case FPSCR_XE:
|
416 |
if (fpscr_xx != 0) { |
417 |
raise_xe:
|
418 |
env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX; |
419 |
goto raise_excp;
|
420 |
} |
421 |
break;
|
422 |
case FPSCR_RN1:
|
423 |
case FPSCR_RN:
|
424 |
fpscr_set_rounding_mode(env); |
425 |
break;
|
426 |
default:
|
427 |
break;
|
428 |
raise_excp:
|
429 |
/* Update the floating-point enabled exception summary */
|
430 |
env->fpscr |= 1 << FPSCR_FEX;
|
431 |
/* We have to update Rc1 before raising the exception */
|
432 |
env->exception_index = POWERPC_EXCP_PROGRAM; |
433 |
break;
|
434 |
} |
435 |
} |
436 |
} |
437 |
|
438 |
void helper_store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask)
|
439 |
{ |
440 |
target_ulong prev, new; |
441 |
int i;
|
442 |
|
443 |
prev = env->fpscr; |
444 |
new = (target_ulong)arg; |
445 |
new &= ~0x60000000LL;
|
446 |
new |= prev & 0x60000000LL;
|
447 |
for (i = 0; i < sizeof(target_ulong) * 2; i++) { |
448 |
if (mask & (1 << i)) { |
449 |
env->fpscr &= ~(0xFLL << (4 * i)); |
450 |
env->fpscr |= new & (0xFLL << (4 * i)); |
451 |
} |
452 |
} |
453 |
/* Update VX and FEX */
|
454 |
if (fpscr_ix != 0) { |
455 |
env->fpscr |= 1 << FPSCR_VX;
|
456 |
} else {
|
457 |
env->fpscr &= ~(1 << FPSCR_VX);
|
458 |
} |
459 |
if ((fpscr_ex & fpscr_eex) != 0) { |
460 |
env->fpscr |= 1 << FPSCR_FEX;
|
461 |
env->exception_index = POWERPC_EXCP_PROGRAM; |
462 |
/* XXX: we should compute it properly */
|
463 |
env->error_code = POWERPC_EXCP_FP; |
464 |
} else {
|
465 |
env->fpscr &= ~(1 << FPSCR_FEX);
|
466 |
} |
467 |
fpscr_set_rounding_mode(env); |
468 |
} |
469 |
|
470 |
void store_fpscr(CPUPPCState *env, uint64_t arg, uint32_t mask)
|
471 |
{ |
472 |
helper_store_fpscr(env, arg, mask); |
473 |
} |
474 |
|
475 |
void helper_float_check_status(CPUPPCState *env)
|
476 |
{ |
477 |
int status = get_float_exception_flags(&env->fp_status);
|
478 |
|
479 |
if (status & float_flag_divbyzero) {
|
480 |
float_zero_divide_excp(env); |
481 |
} else if (status & float_flag_overflow) { |
482 |
float_overflow_excp(env); |
483 |
} else if (status & float_flag_underflow) { |
484 |
float_underflow_excp(env); |
485 |
} else if (status & float_flag_inexact) { |
486 |
float_inexact_excp(env); |
487 |
} |
488 |
|
489 |
if (env->exception_index == POWERPC_EXCP_PROGRAM &&
|
490 |
(env->error_code & POWERPC_EXCP_FP)) { |
491 |
/* Differred floating-point exception after target FPR update */
|
492 |
if (msr_fe0 != 0 || msr_fe1 != 0) { |
493 |
helper_raise_exception_err(env, env->exception_index, |
494 |
env->error_code); |
495 |
} |
496 |
} |
497 |
} |
498 |
|
499 |
void helper_reset_fpstatus(CPUPPCState *env)
|
500 |
{ |
501 |
set_float_exception_flags(0, &env->fp_status);
|
502 |
} |
503 |
|
504 |
/* fadd - fadd. */
|
505 |
uint64_t helper_fadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2) |
506 |
{ |
507 |
CPU_DoubleU farg1, farg2; |
508 |
|
509 |
farg1.ll = arg1; |
510 |
farg2.ll = arg2; |
511 |
|
512 |
if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
|
513 |
float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) { |
514 |
/* Magnitude subtraction of infinities */
|
515 |
farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
|
516 |
} else {
|
517 |
if (unlikely(float64_is_signaling_nan(farg1.d) ||
|
518 |
float64_is_signaling_nan(farg2.d))) { |
519 |
/* sNaN addition */
|
520 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
|
521 |
} |
522 |
farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status); |
523 |
} |
524 |
|
525 |
return farg1.ll;
|
526 |
} |
527 |
|
528 |
/* fsub - fsub. */
|
529 |
uint64_t helper_fsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2) |
530 |
{ |
531 |
CPU_DoubleU farg1, farg2; |
532 |
|
533 |
farg1.ll = arg1; |
534 |
farg2.ll = arg2; |
535 |
|
536 |
if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
|
537 |
float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) { |
538 |
/* Magnitude subtraction of infinities */
|
539 |
farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
|
540 |
} else {
|
541 |
if (unlikely(float64_is_signaling_nan(farg1.d) ||
|
542 |
float64_is_signaling_nan(farg2.d))) { |
543 |
/* sNaN subtraction */
|
544 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
|
545 |
} |
546 |
farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status); |
547 |
} |
548 |
|
549 |
return farg1.ll;
|
550 |
} |
551 |
|
552 |
/* fmul - fmul. */
|
553 |
uint64_t helper_fmul(CPUPPCState *env, uint64_t arg1, uint64_t arg2) |
554 |
{ |
555 |
CPU_DoubleU farg1, farg2; |
556 |
|
557 |
farg1.ll = arg1; |
558 |
farg2.ll = arg2; |
559 |
|
560 |
if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
|
561 |
(float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { |
562 |
/* Multiplication of zero by infinity */
|
563 |
farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
|
564 |
} else {
|
565 |
if (unlikely(float64_is_signaling_nan(farg1.d) ||
|
566 |
float64_is_signaling_nan(farg2.d))) { |
567 |
/* sNaN multiplication */
|
568 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
|
569 |
} |
570 |
farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status); |
571 |
} |
572 |
|
573 |
return farg1.ll;
|
574 |
} |
575 |
|
576 |
/* fdiv - fdiv. */
|
577 |
uint64_t helper_fdiv(CPUPPCState *env, uint64_t arg1, uint64_t arg2) |
578 |
{ |
579 |
CPU_DoubleU farg1, farg2; |
580 |
|
581 |
farg1.ll = arg1; |
582 |
farg2.ll = arg2; |
583 |
|
584 |
if (unlikely(float64_is_infinity(farg1.d) &&
|
585 |
float64_is_infinity(farg2.d))) { |
586 |
/* Division of infinity by infinity */
|
587 |
farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, 1);
|
588 |
} else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) { |
589 |
/* Division of zero by zero */
|
590 |
farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, 1);
|
591 |
} else {
|
592 |
if (unlikely(float64_is_signaling_nan(farg1.d) ||
|
593 |
float64_is_signaling_nan(farg2.d))) { |
594 |
/* sNaN division */
|
595 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
|
596 |
} |
597 |
farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status); |
598 |
} |
599 |
|
600 |
return farg1.ll;
|
601 |
} |
602 |
|
603 |
|
604 |
#define FPU_FCTI(op, cvt, nanval) \
|
605 |
uint64_t helper_##op(CPUPPCState *env, uint64_t arg) \ |
606 |
{ \ |
607 |
CPU_DoubleU farg; \ |
608 |
\ |
609 |
farg.ll = arg; \ |
610 |
farg.ll = float64_to_##cvt(farg.d, &env->fp_status); \ |
611 |
\ |
612 |
if (unlikely(env->fp_status.float_exception_flags)) { \
|
613 |
if (float64_is_any_nan(arg)) { \
|
614 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1); \
|
615 |
if (float64_is_signaling_nan(arg)) { \
|
616 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1); \
|
617 |
} \ |
618 |
farg.ll = nanval; \ |
619 |
} else if (env->fp_status.float_exception_flags & \ |
620 |
float_flag_invalid) { \ |
621 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1); \
|
622 |
} \ |
623 |
helper_float_check_status(env); \ |
624 |
} \ |
625 |
return farg.ll; \
|
626 |
} |
627 |
|
628 |
FPU_FCTI(fctiw, int32, 0x80000000)
|
629 |
FPU_FCTI(fctiwz, int32_round_to_zero, 0x80000000)
|
630 |
FPU_FCTI(fctiwu, uint32, 0x00000000)
|
631 |
FPU_FCTI(fctiwuz, uint32_round_to_zero, 0x00000000)
|
632 |
#if defined(TARGET_PPC64)
|
633 |
FPU_FCTI(fctid, int64, 0x8000000000000000)
|
634 |
FPU_FCTI(fctidz, int64_round_to_zero, 0x8000000000000000)
|
635 |
FPU_FCTI(fctidu, uint64, 0x0000000000000000)
|
636 |
FPU_FCTI(fctiduz, uint64_round_to_zero, 0x0000000000000000)
|
637 |
#endif
|
638 |
|
639 |
#if defined(TARGET_PPC64)
|
640 |
/* fcfid - fcfid. */
|
641 |
uint64_t helper_fcfid(CPUPPCState *env, uint64_t arg) |
642 |
{ |
643 |
CPU_DoubleU farg; |
644 |
|
645 |
farg.d = int64_to_float64(arg, &env->fp_status); |
646 |
return farg.ll;
|
647 |
} |
648 |
|
649 |
|
650 |
|
651 |
#endif
|
652 |
|
653 |
static inline uint64_t do_fri(CPUPPCState *env, uint64_t arg, |
654 |
int rounding_mode)
|
655 |
{ |
656 |
CPU_DoubleU farg; |
657 |
|
658 |
farg.ll = arg; |
659 |
|
660 |
if (unlikely(float64_is_signaling_nan(farg.d))) {
|
661 |
/* sNaN round */
|
662 |
farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN | |
663 |
POWERPC_EXCP_FP_VXCVI, 1);
|
664 |
} else if (unlikely(float64_is_quiet_nan(farg.d) || |
665 |
float64_is_infinity(farg.d))) { |
666 |
/* qNan / infinity round */
|
667 |
farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 1);
|
668 |
} else {
|
669 |
set_float_rounding_mode(rounding_mode, &env->fp_status); |
670 |
farg.ll = float64_round_to_int(farg.d, &env->fp_status); |
671 |
/* Restore rounding mode from FPSCR */
|
672 |
fpscr_set_rounding_mode(env); |
673 |
} |
674 |
return farg.ll;
|
675 |
} |
676 |
|
677 |
uint64_t helper_frin(CPUPPCState *env, uint64_t arg) |
678 |
{ |
679 |
return do_fri(env, arg, float_round_nearest_even);
|
680 |
} |
681 |
|
682 |
uint64_t helper_friz(CPUPPCState *env, uint64_t arg) |
683 |
{ |
684 |
return do_fri(env, arg, float_round_to_zero);
|
685 |
} |
686 |
|
687 |
uint64_t helper_frip(CPUPPCState *env, uint64_t arg) |
688 |
{ |
689 |
return do_fri(env, arg, float_round_up);
|
690 |
} |
691 |
|
692 |
uint64_t helper_frim(CPUPPCState *env, uint64_t arg) |
693 |
{ |
694 |
return do_fri(env, arg, float_round_down);
|
695 |
} |
696 |
|
697 |
/* fmadd - fmadd. */
|
698 |
uint64_t helper_fmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2, |
699 |
uint64_t arg3) |
700 |
{ |
701 |
CPU_DoubleU farg1, farg2, farg3; |
702 |
|
703 |
farg1.ll = arg1; |
704 |
farg2.ll = arg2; |
705 |
farg3.ll = arg3; |
706 |
|
707 |
if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
|
708 |
(float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { |
709 |
/* Multiplication of zero by infinity */
|
710 |
farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
|
711 |
} else {
|
712 |
if (unlikely(float64_is_signaling_nan(farg1.d) ||
|
713 |
float64_is_signaling_nan(farg2.d) || |
714 |
float64_is_signaling_nan(farg3.d))) { |
715 |
/* sNaN operation */
|
716 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
|
717 |
} |
718 |
/* This is the way the PowerPC specification defines it */
|
719 |
float128 ft0_128, ft1_128; |
720 |
|
721 |
ft0_128 = float64_to_float128(farg1.d, &env->fp_status); |
722 |
ft1_128 = float64_to_float128(farg2.d, &env->fp_status); |
723 |
ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); |
724 |
if (unlikely(float128_is_infinity(ft0_128) &&
|
725 |
float64_is_infinity(farg3.d) && |
726 |
float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) { |
727 |
/* Magnitude subtraction of infinities */
|
728 |
farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
|
729 |
} else {
|
730 |
ft1_128 = float64_to_float128(farg3.d, &env->fp_status); |
731 |
ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status); |
732 |
farg1.d = float128_to_float64(ft0_128, &env->fp_status); |
733 |
} |
734 |
} |
735 |
|
736 |
return farg1.ll;
|
737 |
} |
738 |
|
739 |
/* fmsub - fmsub. */
|
740 |
uint64_t helper_fmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2, |
741 |
uint64_t arg3) |
742 |
{ |
743 |
CPU_DoubleU farg1, farg2, farg3; |
744 |
|
745 |
farg1.ll = arg1; |
746 |
farg2.ll = arg2; |
747 |
farg3.ll = arg3; |
748 |
|
749 |
if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
|
750 |
(float64_is_zero(farg1.d) && |
751 |
float64_is_infinity(farg2.d)))) { |
752 |
/* Multiplication of zero by infinity */
|
753 |
farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
|
754 |
} else {
|
755 |
if (unlikely(float64_is_signaling_nan(farg1.d) ||
|
756 |
float64_is_signaling_nan(farg2.d) || |
757 |
float64_is_signaling_nan(farg3.d))) { |
758 |
/* sNaN operation */
|
759 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
|
760 |
} |
761 |
/* This is the way the PowerPC specification defines it */
|
762 |
float128 ft0_128, ft1_128; |
763 |
|
764 |
ft0_128 = float64_to_float128(farg1.d, &env->fp_status); |
765 |
ft1_128 = float64_to_float128(farg2.d, &env->fp_status); |
766 |
ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); |
767 |
if (unlikely(float128_is_infinity(ft0_128) &&
|
768 |
float64_is_infinity(farg3.d) && |
769 |
float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) { |
770 |
/* Magnitude subtraction of infinities */
|
771 |
farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
|
772 |
} else {
|
773 |
ft1_128 = float64_to_float128(farg3.d, &env->fp_status); |
774 |
ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status); |
775 |
farg1.d = float128_to_float64(ft0_128, &env->fp_status); |
776 |
} |
777 |
} |
778 |
return farg1.ll;
|
779 |
} |
780 |
|
781 |
/* fnmadd - fnmadd. */
|
782 |
uint64_t helper_fnmadd(CPUPPCState *env, uint64_t arg1, uint64_t arg2, |
783 |
uint64_t arg3) |
784 |
{ |
785 |
CPU_DoubleU farg1, farg2, farg3; |
786 |
|
787 |
farg1.ll = arg1; |
788 |
farg2.ll = arg2; |
789 |
farg3.ll = arg3; |
790 |
|
791 |
if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
|
792 |
(float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) { |
793 |
/* Multiplication of zero by infinity */
|
794 |
farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
|
795 |
} else {
|
796 |
if (unlikely(float64_is_signaling_nan(farg1.d) ||
|
797 |
float64_is_signaling_nan(farg2.d) || |
798 |
float64_is_signaling_nan(farg3.d))) { |
799 |
/* sNaN operation */
|
800 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
|
801 |
} |
802 |
/* This is the way the PowerPC specification defines it */
|
803 |
float128 ft0_128, ft1_128; |
804 |
|
805 |
ft0_128 = float64_to_float128(farg1.d, &env->fp_status); |
806 |
ft1_128 = float64_to_float128(farg2.d, &env->fp_status); |
807 |
ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); |
808 |
if (unlikely(float128_is_infinity(ft0_128) &&
|
809 |
float64_is_infinity(farg3.d) && |
810 |
float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) { |
811 |
/* Magnitude subtraction of infinities */
|
812 |
farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
|
813 |
} else {
|
814 |
ft1_128 = float64_to_float128(farg3.d, &env->fp_status); |
815 |
ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status); |
816 |
farg1.d = float128_to_float64(ft0_128, &env->fp_status); |
817 |
} |
818 |
if (likely(!float64_is_any_nan(farg1.d))) {
|
819 |
farg1.d = float64_chs(farg1.d); |
820 |
} |
821 |
} |
822 |
return farg1.ll;
|
823 |
} |
824 |
|
825 |
/* fnmsub - fnmsub. */
|
826 |
uint64_t helper_fnmsub(CPUPPCState *env, uint64_t arg1, uint64_t arg2, |
827 |
uint64_t arg3) |
828 |
{ |
829 |
CPU_DoubleU farg1, farg2, farg3; |
830 |
|
831 |
farg1.ll = arg1; |
832 |
farg2.ll = arg2; |
833 |
farg3.ll = arg3; |
834 |
|
835 |
if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
|
836 |
(float64_is_zero(farg1.d) && |
837 |
float64_is_infinity(farg2.d)))) { |
838 |
/* Multiplication of zero by infinity */
|
839 |
farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, 1);
|
840 |
} else {
|
841 |
if (unlikely(float64_is_signaling_nan(farg1.d) ||
|
842 |
float64_is_signaling_nan(farg2.d) || |
843 |
float64_is_signaling_nan(farg3.d))) { |
844 |
/* sNaN operation */
|
845 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
|
846 |
} |
847 |
/* This is the way the PowerPC specification defines it */
|
848 |
float128 ft0_128, ft1_128; |
849 |
|
850 |
ft0_128 = float64_to_float128(farg1.d, &env->fp_status); |
851 |
ft1_128 = float64_to_float128(farg2.d, &env->fp_status); |
852 |
ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status); |
853 |
if (unlikely(float128_is_infinity(ft0_128) &&
|
854 |
float64_is_infinity(farg3.d) && |
855 |
float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) { |
856 |
/* Magnitude subtraction of infinities */
|
857 |
farg1.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, 1);
|
858 |
} else {
|
859 |
ft1_128 = float64_to_float128(farg3.d, &env->fp_status); |
860 |
ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status); |
861 |
farg1.d = float128_to_float64(ft0_128, &env->fp_status); |
862 |
} |
863 |
if (likely(!float64_is_any_nan(farg1.d))) {
|
864 |
farg1.d = float64_chs(farg1.d); |
865 |
} |
866 |
} |
867 |
return farg1.ll;
|
868 |
} |
869 |
|
870 |
/* frsp - frsp. */
|
871 |
uint64_t helper_frsp(CPUPPCState *env, uint64_t arg) |
872 |
{ |
873 |
CPU_DoubleU farg; |
874 |
float32 f32; |
875 |
|
876 |
farg.ll = arg; |
877 |
|
878 |
if (unlikely(float64_is_signaling_nan(farg.d))) {
|
879 |
/* sNaN square root */
|
880 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
|
881 |
} |
882 |
f32 = float64_to_float32(farg.d, &env->fp_status); |
883 |
farg.d = float32_to_float64(f32, &env->fp_status); |
884 |
|
885 |
return farg.ll;
|
886 |
} |
887 |
|
888 |
/* fsqrt - fsqrt. */
|
889 |
uint64_t helper_fsqrt(CPUPPCState *env, uint64_t arg) |
890 |
{ |
891 |
CPU_DoubleU farg; |
892 |
|
893 |
farg.ll = arg; |
894 |
|
895 |
if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
|
896 |
/* Square root of a negative nonzero number */
|
897 |
farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1);
|
898 |
} else {
|
899 |
if (unlikely(float64_is_signaling_nan(farg.d))) {
|
900 |
/* sNaN square root */
|
901 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
|
902 |
} |
903 |
farg.d = float64_sqrt(farg.d, &env->fp_status); |
904 |
} |
905 |
return farg.ll;
|
906 |
} |
907 |
|
908 |
/* fre - fre. */
|
909 |
uint64_t helper_fre(CPUPPCState *env, uint64_t arg) |
910 |
{ |
911 |
CPU_DoubleU farg; |
912 |
|
913 |
farg.ll = arg; |
914 |
|
915 |
if (unlikely(float64_is_signaling_nan(farg.d))) {
|
916 |
/* sNaN reciprocal */
|
917 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
|
918 |
} |
919 |
farg.d = float64_div(float64_one, farg.d, &env->fp_status); |
920 |
return farg.d;
|
921 |
} |
922 |
|
923 |
/* fres - fres. */
|
924 |
uint64_t helper_fres(CPUPPCState *env, uint64_t arg) |
925 |
{ |
926 |
CPU_DoubleU farg; |
927 |
float32 f32; |
928 |
|
929 |
farg.ll = arg; |
930 |
|
931 |
if (unlikely(float64_is_signaling_nan(farg.d))) {
|
932 |
/* sNaN reciprocal */
|
933 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
|
934 |
} |
935 |
farg.d = float64_div(float64_one, farg.d, &env->fp_status); |
936 |
f32 = float64_to_float32(farg.d, &env->fp_status); |
937 |
farg.d = float32_to_float64(f32, &env->fp_status); |
938 |
|
939 |
return farg.ll;
|
940 |
} |
941 |
|
942 |
/* frsqrte - frsqrte. */
|
943 |
uint64_t helper_frsqrte(CPUPPCState *env, uint64_t arg) |
944 |
{ |
945 |
CPU_DoubleU farg; |
946 |
float32 f32; |
947 |
|
948 |
farg.ll = arg; |
949 |
|
950 |
if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
|
951 |
/* Reciprocal square root of a negative nonzero number */
|
952 |
farg.ll = fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, 1);
|
953 |
} else {
|
954 |
if (unlikely(float64_is_signaling_nan(farg.d))) {
|
955 |
/* sNaN reciprocal square root */
|
956 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
|
957 |
} |
958 |
farg.d = float64_sqrt(farg.d, &env->fp_status); |
959 |
farg.d = float64_div(float64_one, farg.d, &env->fp_status); |
960 |
f32 = float64_to_float32(farg.d, &env->fp_status); |
961 |
farg.d = float32_to_float64(f32, &env->fp_status); |
962 |
} |
963 |
return farg.ll;
|
964 |
} |
965 |
|
966 |
/* fsel - fsel. */
|
967 |
uint64_t helper_fsel(CPUPPCState *env, uint64_t arg1, uint64_t arg2, |
968 |
uint64_t arg3) |
969 |
{ |
970 |
CPU_DoubleU farg1; |
971 |
|
972 |
farg1.ll = arg1; |
973 |
|
974 |
if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) &&
|
975 |
!float64_is_any_nan(farg1.d)) { |
976 |
return arg2;
|
977 |
} else {
|
978 |
return arg3;
|
979 |
} |
980 |
} |
981 |
|
982 |
void helper_fcmpu(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
|
983 |
uint32_t crfD) |
984 |
{ |
985 |
CPU_DoubleU farg1, farg2; |
986 |
uint32_t ret = 0;
|
987 |
|
988 |
farg1.ll = arg1; |
989 |
farg2.ll = arg2; |
990 |
|
991 |
if (unlikely(float64_is_any_nan(farg1.d) ||
|
992 |
float64_is_any_nan(farg2.d))) { |
993 |
ret = 0x01UL;
|
994 |
} else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) { |
995 |
ret = 0x08UL;
|
996 |
} else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) { |
997 |
ret = 0x04UL;
|
998 |
} else {
|
999 |
ret = 0x02UL;
|
1000 |
} |
1001 |
|
1002 |
env->fpscr &= ~(0x0F << FPSCR_FPRF);
|
1003 |
env->fpscr |= ret << FPSCR_FPRF; |
1004 |
env->crf[crfD] = ret; |
1005 |
if (unlikely(ret == 0x01UL |
1006 |
&& (float64_is_signaling_nan(farg1.d) || |
1007 |
float64_is_signaling_nan(farg2.d)))) { |
1008 |
/* sNaN comparison */
|
1009 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 1);
|
1010 |
} |
1011 |
} |
1012 |
|
1013 |
void helper_fcmpo(CPUPPCState *env, uint64_t arg1, uint64_t arg2,
|
1014 |
uint32_t crfD) |
1015 |
{ |
1016 |
CPU_DoubleU farg1, farg2; |
1017 |
uint32_t ret = 0;
|
1018 |
|
1019 |
farg1.ll = arg1; |
1020 |
farg2.ll = arg2; |
1021 |
|
1022 |
if (unlikely(float64_is_any_nan(farg1.d) ||
|
1023 |
float64_is_any_nan(farg2.d))) { |
1024 |
ret = 0x01UL;
|
1025 |
} else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) { |
1026 |
ret = 0x08UL;
|
1027 |
} else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) { |
1028 |
ret = 0x04UL;
|
1029 |
} else {
|
1030 |
ret = 0x02UL;
|
1031 |
} |
1032 |
|
1033 |
env->fpscr &= ~(0x0F << FPSCR_FPRF);
|
1034 |
env->fpscr |= ret << FPSCR_FPRF; |
1035 |
env->crf[crfD] = ret; |
1036 |
if (unlikely(ret == 0x01UL)) { |
1037 |
if (float64_is_signaling_nan(farg1.d) ||
|
1038 |
float64_is_signaling_nan(farg2.d)) { |
1039 |
/* sNaN comparison */
|
1040 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN | |
1041 |
POWERPC_EXCP_FP_VXVC, 1);
|
1042 |
} else {
|
1043 |
/* qNaN comparison */
|
1044 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 1);
|
1045 |
} |
1046 |
} |
1047 |
} |
1048 |
|
1049 |
/* Single-precision floating-point conversions */
|
1050 |
static inline uint32_t efscfsi(CPUPPCState *env, uint32_t val) |
1051 |
{ |
1052 |
CPU_FloatU u; |
1053 |
|
1054 |
u.f = int32_to_float32(val, &env->vec_status); |
1055 |
|
1056 |
return u.l;
|
1057 |
} |
1058 |
|
1059 |
static inline uint32_t efscfui(CPUPPCState *env, uint32_t val) |
1060 |
{ |
1061 |
CPU_FloatU u; |
1062 |
|
1063 |
u.f = uint32_to_float32(val, &env->vec_status); |
1064 |
|
1065 |
return u.l;
|
1066 |
} |
1067 |
|
1068 |
static inline int32_t efsctsi(CPUPPCState *env, uint32_t val) |
1069 |
{ |
1070 |
CPU_FloatU u; |
1071 |
|
1072 |
u.l = val; |
1073 |
/* NaN are not treated the same way IEEE 754 does */
|
1074 |
if (unlikely(float32_is_quiet_nan(u.f))) {
|
1075 |
return 0; |
1076 |
} |
1077 |
|
1078 |
return float32_to_int32(u.f, &env->vec_status);
|
1079 |
} |
1080 |
|
1081 |
static inline uint32_t efsctui(CPUPPCState *env, uint32_t val) |
1082 |
{ |
1083 |
CPU_FloatU u; |
1084 |
|
1085 |
u.l = val; |
1086 |
/* NaN are not treated the same way IEEE 754 does */
|
1087 |
if (unlikely(float32_is_quiet_nan(u.f))) {
|
1088 |
return 0; |
1089 |
} |
1090 |
|
1091 |
return float32_to_uint32(u.f, &env->vec_status);
|
1092 |
} |
1093 |
|
1094 |
static inline uint32_t efsctsiz(CPUPPCState *env, uint32_t val) |
1095 |
{ |
1096 |
CPU_FloatU u; |
1097 |
|
1098 |
u.l = val; |
1099 |
/* NaN are not treated the same way IEEE 754 does */
|
1100 |
if (unlikely(float32_is_quiet_nan(u.f))) {
|
1101 |
return 0; |
1102 |
} |
1103 |
|
1104 |
return float32_to_int32_round_to_zero(u.f, &env->vec_status);
|
1105 |
} |
1106 |
|
1107 |
static inline uint32_t efsctuiz(CPUPPCState *env, uint32_t val) |
1108 |
{ |
1109 |
CPU_FloatU u; |
1110 |
|
1111 |
u.l = val; |
1112 |
/* NaN are not treated the same way IEEE 754 does */
|
1113 |
if (unlikely(float32_is_quiet_nan(u.f))) {
|
1114 |
return 0; |
1115 |
} |
1116 |
|
1117 |
return float32_to_uint32_round_to_zero(u.f, &env->vec_status);
|
1118 |
} |
1119 |
|
1120 |
static inline uint32_t efscfsf(CPUPPCState *env, uint32_t val) |
1121 |
{ |
1122 |
CPU_FloatU u; |
1123 |
float32 tmp; |
1124 |
|
1125 |
u.f = int32_to_float32(val, &env->vec_status); |
1126 |
tmp = int64_to_float32(1ULL << 32, &env->vec_status); |
1127 |
u.f = float32_div(u.f, tmp, &env->vec_status); |
1128 |
|
1129 |
return u.l;
|
1130 |
} |
1131 |
|
1132 |
static inline uint32_t efscfuf(CPUPPCState *env, uint32_t val) |
1133 |
{ |
1134 |
CPU_FloatU u; |
1135 |
float32 tmp; |
1136 |
|
1137 |
u.f = uint32_to_float32(val, &env->vec_status); |
1138 |
tmp = uint64_to_float32(1ULL << 32, &env->vec_status); |
1139 |
u.f = float32_div(u.f, tmp, &env->vec_status); |
1140 |
|
1141 |
return u.l;
|
1142 |
} |
1143 |
|
1144 |
static inline uint32_t efsctsf(CPUPPCState *env, uint32_t val) |
1145 |
{ |
1146 |
CPU_FloatU u; |
1147 |
float32 tmp; |
1148 |
|
1149 |
u.l = val; |
1150 |
/* NaN are not treated the same way IEEE 754 does */
|
1151 |
if (unlikely(float32_is_quiet_nan(u.f))) {
|
1152 |
return 0; |
1153 |
} |
1154 |
tmp = uint64_to_float32(1ULL << 32, &env->vec_status); |
1155 |
u.f = float32_mul(u.f, tmp, &env->vec_status); |
1156 |
|
1157 |
return float32_to_int32(u.f, &env->vec_status);
|
1158 |
} |
1159 |
|
1160 |
static inline uint32_t efsctuf(CPUPPCState *env, uint32_t val) |
1161 |
{ |
1162 |
CPU_FloatU u; |
1163 |
float32 tmp; |
1164 |
|
1165 |
u.l = val; |
1166 |
/* NaN are not treated the same way IEEE 754 does */
|
1167 |
if (unlikely(float32_is_quiet_nan(u.f))) {
|
1168 |
return 0; |
1169 |
} |
1170 |
tmp = uint64_to_float32(1ULL << 32, &env->vec_status); |
1171 |
u.f = float32_mul(u.f, tmp, &env->vec_status); |
1172 |
|
1173 |
return float32_to_uint32(u.f, &env->vec_status);
|
1174 |
} |
1175 |
|
1176 |
#define HELPER_SPE_SINGLE_CONV(name) \
|
1177 |
uint32_t helper_e##name(CPUPPCState *env, uint32_t val) \ |
1178 |
{ \ |
1179 |
return e##name(env, val); \ |
1180 |
} |
1181 |
/* efscfsi */
|
1182 |
HELPER_SPE_SINGLE_CONV(fscfsi); |
1183 |
/* efscfui */
|
1184 |
HELPER_SPE_SINGLE_CONV(fscfui); |
1185 |
/* efscfuf */
|
1186 |
HELPER_SPE_SINGLE_CONV(fscfuf); |
1187 |
/* efscfsf */
|
1188 |
HELPER_SPE_SINGLE_CONV(fscfsf); |
1189 |
/* efsctsi */
|
1190 |
HELPER_SPE_SINGLE_CONV(fsctsi); |
1191 |
/* efsctui */
|
1192 |
HELPER_SPE_SINGLE_CONV(fsctui); |
1193 |
/* efsctsiz */
|
1194 |
HELPER_SPE_SINGLE_CONV(fsctsiz); |
1195 |
/* efsctuiz */
|
1196 |
HELPER_SPE_SINGLE_CONV(fsctuiz); |
1197 |
/* efsctsf */
|
1198 |
HELPER_SPE_SINGLE_CONV(fsctsf); |
1199 |
/* efsctuf */
|
1200 |
HELPER_SPE_SINGLE_CONV(fsctuf); |
1201 |
|
1202 |
#define HELPER_SPE_VECTOR_CONV(name) \
|
1203 |
uint64_t helper_ev##name(CPUPPCState *env, uint64_t val) \ |
1204 |
{ \ |
1205 |
return ((uint64_t)e##name(env, val >> 32) << 32) | \ |
1206 |
(uint64_t)e##name(env, val); \ |
1207 |
} |
1208 |
/* evfscfsi */
|
1209 |
HELPER_SPE_VECTOR_CONV(fscfsi); |
1210 |
/* evfscfui */
|
1211 |
HELPER_SPE_VECTOR_CONV(fscfui); |
1212 |
/* evfscfuf */
|
1213 |
HELPER_SPE_VECTOR_CONV(fscfuf); |
1214 |
/* evfscfsf */
|
1215 |
HELPER_SPE_VECTOR_CONV(fscfsf); |
1216 |
/* evfsctsi */
|
1217 |
HELPER_SPE_VECTOR_CONV(fsctsi); |
1218 |
/* evfsctui */
|
1219 |
HELPER_SPE_VECTOR_CONV(fsctui); |
1220 |
/* evfsctsiz */
|
1221 |
HELPER_SPE_VECTOR_CONV(fsctsiz); |
1222 |
/* evfsctuiz */
|
1223 |
HELPER_SPE_VECTOR_CONV(fsctuiz); |
1224 |
/* evfsctsf */
|
1225 |
HELPER_SPE_VECTOR_CONV(fsctsf); |
1226 |
/* evfsctuf */
|
1227 |
HELPER_SPE_VECTOR_CONV(fsctuf); |
1228 |
|
1229 |
/* Single-precision floating-point arithmetic */
|
1230 |
static inline uint32_t efsadd(CPUPPCState *env, uint32_t op1, uint32_t op2) |
1231 |
{ |
1232 |
CPU_FloatU u1, u2; |
1233 |
|
1234 |
u1.l = op1; |
1235 |
u2.l = op2; |
1236 |
u1.f = float32_add(u1.f, u2.f, &env->vec_status); |
1237 |
return u1.l;
|
1238 |
} |
1239 |
|
1240 |
static inline uint32_t efssub(CPUPPCState *env, uint32_t op1, uint32_t op2) |
1241 |
{ |
1242 |
CPU_FloatU u1, u2; |
1243 |
|
1244 |
u1.l = op1; |
1245 |
u2.l = op2; |
1246 |
u1.f = float32_sub(u1.f, u2.f, &env->vec_status); |
1247 |
return u1.l;
|
1248 |
} |
1249 |
|
1250 |
static inline uint32_t efsmul(CPUPPCState *env, uint32_t op1, uint32_t op2) |
1251 |
{ |
1252 |
CPU_FloatU u1, u2; |
1253 |
|
1254 |
u1.l = op1; |
1255 |
u2.l = op2; |
1256 |
u1.f = float32_mul(u1.f, u2.f, &env->vec_status); |
1257 |
return u1.l;
|
1258 |
} |
1259 |
|
1260 |
static inline uint32_t efsdiv(CPUPPCState *env, uint32_t op1, uint32_t op2) |
1261 |
{ |
1262 |
CPU_FloatU u1, u2; |
1263 |
|
1264 |
u1.l = op1; |
1265 |
u2.l = op2; |
1266 |
u1.f = float32_div(u1.f, u2.f, &env->vec_status); |
1267 |
return u1.l;
|
1268 |
} |
1269 |
|
1270 |
#define HELPER_SPE_SINGLE_ARITH(name) \
|
1271 |
uint32_t helper_e##name(CPUPPCState *env, uint32_t op1, uint32_t op2) \ |
1272 |
{ \ |
1273 |
return e##name(env, op1, op2); \ |
1274 |
} |
1275 |
/* efsadd */
|
1276 |
HELPER_SPE_SINGLE_ARITH(fsadd); |
1277 |
/* efssub */
|
1278 |
HELPER_SPE_SINGLE_ARITH(fssub); |
1279 |
/* efsmul */
|
1280 |
HELPER_SPE_SINGLE_ARITH(fsmul); |
1281 |
/* efsdiv */
|
1282 |
HELPER_SPE_SINGLE_ARITH(fsdiv); |
1283 |
|
1284 |
#define HELPER_SPE_VECTOR_ARITH(name) \
|
1285 |
uint64_t helper_ev##name(CPUPPCState *env, uint64_t op1, uint64_t op2) \ |
1286 |
{ \ |
1287 |
return ((uint64_t)e##name(env, op1 >> 32, op2 >> 32) << 32) | \ |
1288 |
(uint64_t)e##name(env, op1, op2); \ |
1289 |
} |
1290 |
/* evfsadd */
|
1291 |
HELPER_SPE_VECTOR_ARITH(fsadd); |
1292 |
/* evfssub */
|
1293 |
HELPER_SPE_VECTOR_ARITH(fssub); |
1294 |
/* evfsmul */
|
1295 |
HELPER_SPE_VECTOR_ARITH(fsmul); |
1296 |
/* evfsdiv */
|
1297 |
HELPER_SPE_VECTOR_ARITH(fsdiv); |
1298 |
|
1299 |
/* Single-precision floating-point comparisons */
|
1300 |
static inline uint32_t efscmplt(CPUPPCState *env, uint32_t op1, uint32_t op2) |
1301 |
{ |
1302 |
CPU_FloatU u1, u2; |
1303 |
|
1304 |
u1.l = op1; |
1305 |
u2.l = op2; |
1306 |
return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0; |
1307 |
} |
1308 |
|
1309 |
static inline uint32_t efscmpgt(CPUPPCState *env, uint32_t op1, uint32_t op2) |
1310 |
{ |
1311 |
CPU_FloatU u1, u2; |
1312 |
|
1313 |
u1.l = op1; |
1314 |
u2.l = op2; |
1315 |
return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4; |
1316 |
} |
1317 |
|
1318 |
static inline uint32_t efscmpeq(CPUPPCState *env, uint32_t op1, uint32_t op2) |
1319 |
{ |
1320 |
CPU_FloatU u1, u2; |
1321 |
|
1322 |
u1.l = op1; |
1323 |
u2.l = op2; |
1324 |
return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0; |
1325 |
} |
1326 |
|
1327 |
static inline uint32_t efststlt(CPUPPCState *env, uint32_t op1, uint32_t op2) |
1328 |
{ |
1329 |
/* XXX: TODO: ignore special values (NaN, infinites, ...) */
|
1330 |
return efscmplt(env, op1, op2);
|
1331 |
} |
1332 |
|
1333 |
static inline uint32_t efststgt(CPUPPCState *env, uint32_t op1, uint32_t op2) |
1334 |
{ |
1335 |
/* XXX: TODO: ignore special values (NaN, infinites, ...) */
|
1336 |
return efscmpgt(env, op1, op2);
|
1337 |
} |
1338 |
|
1339 |
static inline uint32_t efststeq(CPUPPCState *env, uint32_t op1, uint32_t op2) |
1340 |
{ |
1341 |
/* XXX: TODO: ignore special values (NaN, infinites, ...) */
|
1342 |
return efscmpeq(env, op1, op2);
|
1343 |
} |
1344 |
|
1345 |
#define HELPER_SINGLE_SPE_CMP(name) \
|
1346 |
uint32_t helper_e##name(CPUPPCState *env, uint32_t op1, uint32_t op2) \ |
1347 |
{ \ |
1348 |
return e##name(env, op1, op2) << 2; \ |
1349 |
} |
1350 |
/* efststlt */
|
1351 |
HELPER_SINGLE_SPE_CMP(fststlt); |
1352 |
/* efststgt */
|
1353 |
HELPER_SINGLE_SPE_CMP(fststgt); |
1354 |
/* efststeq */
|
1355 |
HELPER_SINGLE_SPE_CMP(fststeq); |
1356 |
/* efscmplt */
|
1357 |
HELPER_SINGLE_SPE_CMP(fscmplt); |
1358 |
/* efscmpgt */
|
1359 |
HELPER_SINGLE_SPE_CMP(fscmpgt); |
1360 |
/* efscmpeq */
|
1361 |
HELPER_SINGLE_SPE_CMP(fscmpeq); |
1362 |
|
1363 |
static inline uint32_t evcmp_merge(int t0, int t1) |
1364 |
{ |
1365 |
return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1); |
1366 |
} |
1367 |
|
1368 |
#define HELPER_VECTOR_SPE_CMP(name) \
|
1369 |
uint32_t helper_ev##name(CPUPPCState *env, uint64_t op1, uint64_t op2) \ |
1370 |
{ \ |
1371 |
return evcmp_merge(e##name(env, op1 >> 32, op2 >> 32), \ |
1372 |
e##name(env, op1, op2)); \ |
1373 |
} |
1374 |
/* evfststlt */
|
1375 |
HELPER_VECTOR_SPE_CMP(fststlt); |
1376 |
/* evfststgt */
|
1377 |
HELPER_VECTOR_SPE_CMP(fststgt); |
1378 |
/* evfststeq */
|
1379 |
HELPER_VECTOR_SPE_CMP(fststeq); |
1380 |
/* evfscmplt */
|
1381 |
HELPER_VECTOR_SPE_CMP(fscmplt); |
1382 |
/* evfscmpgt */
|
1383 |
HELPER_VECTOR_SPE_CMP(fscmpgt); |
1384 |
/* evfscmpeq */
|
1385 |
HELPER_VECTOR_SPE_CMP(fscmpeq); |
1386 |
|
1387 |
/* Double-precision floating-point conversion */
|
1388 |
uint64_t helper_efdcfsi(CPUPPCState *env, uint32_t val) |
1389 |
{ |
1390 |
CPU_DoubleU u; |
1391 |
|
1392 |
u.d = int32_to_float64(val, &env->vec_status); |
1393 |
|
1394 |
return u.ll;
|
1395 |
} |
1396 |
|
1397 |
uint64_t helper_efdcfsid(CPUPPCState *env, uint64_t val) |
1398 |
{ |
1399 |
CPU_DoubleU u; |
1400 |
|
1401 |
u.d = int64_to_float64(val, &env->vec_status); |
1402 |
|
1403 |
return u.ll;
|
1404 |
} |
1405 |
|
1406 |
uint64_t helper_efdcfui(CPUPPCState *env, uint32_t val) |
1407 |
{ |
1408 |
CPU_DoubleU u; |
1409 |
|
1410 |
u.d = uint32_to_float64(val, &env->vec_status); |
1411 |
|
1412 |
return u.ll;
|
1413 |
} |
1414 |
|
1415 |
uint64_t helper_efdcfuid(CPUPPCState *env, uint64_t val) |
1416 |
{ |
1417 |
CPU_DoubleU u; |
1418 |
|
1419 |
u.d = uint64_to_float64(val, &env->vec_status); |
1420 |
|
1421 |
return u.ll;
|
1422 |
} |
1423 |
|
1424 |
uint32_t helper_efdctsi(CPUPPCState *env, uint64_t val) |
1425 |
{ |
1426 |
CPU_DoubleU u; |
1427 |
|
1428 |
u.ll = val; |
1429 |
/* NaN are not treated the same way IEEE 754 does */
|
1430 |
if (unlikely(float64_is_any_nan(u.d))) {
|
1431 |
return 0; |
1432 |
} |
1433 |
|
1434 |
return float64_to_int32(u.d, &env->vec_status);
|
1435 |
} |
1436 |
|
1437 |
uint32_t helper_efdctui(CPUPPCState *env, uint64_t val) |
1438 |
{ |
1439 |
CPU_DoubleU u; |
1440 |
|
1441 |
u.ll = val; |
1442 |
/* NaN are not treated the same way IEEE 754 does */
|
1443 |
if (unlikely(float64_is_any_nan(u.d))) {
|
1444 |
return 0; |
1445 |
} |
1446 |
|
1447 |
return float64_to_uint32(u.d, &env->vec_status);
|
1448 |
} |
1449 |
|
1450 |
uint32_t helper_efdctsiz(CPUPPCState *env, uint64_t val) |
1451 |
{ |
1452 |
CPU_DoubleU u; |
1453 |
|
1454 |
u.ll = val; |
1455 |
/* NaN are not treated the same way IEEE 754 does */
|
1456 |
if (unlikely(float64_is_any_nan(u.d))) {
|
1457 |
return 0; |
1458 |
} |
1459 |
|
1460 |
return float64_to_int32_round_to_zero(u.d, &env->vec_status);
|
1461 |
} |
1462 |
|
1463 |
uint64_t helper_efdctsidz(CPUPPCState *env, uint64_t val) |
1464 |
{ |
1465 |
CPU_DoubleU u; |
1466 |
|
1467 |
u.ll = val; |
1468 |
/* NaN are not treated the same way IEEE 754 does */
|
1469 |
if (unlikely(float64_is_any_nan(u.d))) {
|
1470 |
return 0; |
1471 |
} |
1472 |
|
1473 |
return float64_to_int64_round_to_zero(u.d, &env->vec_status);
|
1474 |
} |
1475 |
|
1476 |
uint32_t helper_efdctuiz(CPUPPCState *env, uint64_t val) |
1477 |
{ |
1478 |
CPU_DoubleU u; |
1479 |
|
1480 |
u.ll = val; |
1481 |
/* NaN are not treated the same way IEEE 754 does */
|
1482 |
if (unlikely(float64_is_any_nan(u.d))) {
|
1483 |
return 0; |
1484 |
} |
1485 |
|
1486 |
return float64_to_uint32_round_to_zero(u.d, &env->vec_status);
|
1487 |
} |
1488 |
|
1489 |
uint64_t helper_efdctuidz(CPUPPCState *env, uint64_t val) |
1490 |
{ |
1491 |
CPU_DoubleU u; |
1492 |
|
1493 |
u.ll = val; |
1494 |
/* NaN are not treated the same way IEEE 754 does */
|
1495 |
if (unlikely(float64_is_any_nan(u.d))) {
|
1496 |
return 0; |
1497 |
} |
1498 |
|
1499 |
return float64_to_uint64_round_to_zero(u.d, &env->vec_status);
|
1500 |
} |
1501 |
|
1502 |
uint64_t helper_efdcfsf(CPUPPCState *env, uint32_t val) |
1503 |
{ |
1504 |
CPU_DoubleU u; |
1505 |
float64 tmp; |
1506 |
|
1507 |
u.d = int32_to_float64(val, &env->vec_status); |
1508 |
tmp = int64_to_float64(1ULL << 32, &env->vec_status); |
1509 |
u.d = float64_div(u.d, tmp, &env->vec_status); |
1510 |
|
1511 |
return u.ll;
|
1512 |
} |
1513 |
|
1514 |
uint64_t helper_efdcfuf(CPUPPCState *env, uint32_t val) |
1515 |
{ |
1516 |
CPU_DoubleU u; |
1517 |
float64 tmp; |
1518 |
|
1519 |
u.d = uint32_to_float64(val, &env->vec_status); |
1520 |
tmp = int64_to_float64(1ULL << 32, &env->vec_status); |
1521 |
u.d = float64_div(u.d, tmp, &env->vec_status); |
1522 |
|
1523 |
return u.ll;
|
1524 |
} |
1525 |
|
1526 |
uint32_t helper_efdctsf(CPUPPCState *env, uint64_t val) |
1527 |
{ |
1528 |
CPU_DoubleU u; |
1529 |
float64 tmp; |
1530 |
|
1531 |
u.ll = val; |
1532 |
/* NaN are not treated the same way IEEE 754 does */
|
1533 |
if (unlikely(float64_is_any_nan(u.d))) {
|
1534 |
return 0; |
1535 |
} |
1536 |
tmp = uint64_to_float64(1ULL << 32, &env->vec_status); |
1537 |
u.d = float64_mul(u.d, tmp, &env->vec_status); |
1538 |
|
1539 |
return float64_to_int32(u.d, &env->vec_status);
|
1540 |
} |
1541 |
|
1542 |
uint32_t helper_efdctuf(CPUPPCState *env, uint64_t val) |
1543 |
{ |
1544 |
CPU_DoubleU u; |
1545 |
float64 tmp; |
1546 |
|
1547 |
u.ll = val; |
1548 |
/* NaN are not treated the same way IEEE 754 does */
|
1549 |
if (unlikely(float64_is_any_nan(u.d))) {
|
1550 |
return 0; |
1551 |
} |
1552 |
tmp = uint64_to_float64(1ULL << 32, &env->vec_status); |
1553 |
u.d = float64_mul(u.d, tmp, &env->vec_status); |
1554 |
|
1555 |
return float64_to_uint32(u.d, &env->vec_status);
|
1556 |
} |
1557 |
|
1558 |
uint32_t helper_efscfd(CPUPPCState *env, uint64_t val) |
1559 |
{ |
1560 |
CPU_DoubleU u1; |
1561 |
CPU_FloatU u2; |
1562 |
|
1563 |
u1.ll = val; |
1564 |
u2.f = float64_to_float32(u1.d, &env->vec_status); |
1565 |
|
1566 |
return u2.l;
|
1567 |
} |
1568 |
|
1569 |
uint64_t helper_efdcfs(CPUPPCState *env, uint32_t val) |
1570 |
{ |
1571 |
CPU_DoubleU u2; |
1572 |
CPU_FloatU u1; |
1573 |
|
1574 |
u1.l = val; |
1575 |
u2.d = float32_to_float64(u1.f, &env->vec_status); |
1576 |
|
1577 |
return u2.ll;
|
1578 |
} |
1579 |
|
1580 |
/* Double precision fixed-point arithmetic */
|
1581 |
uint64_t helper_efdadd(CPUPPCState *env, uint64_t op1, uint64_t op2) |
1582 |
{ |
1583 |
CPU_DoubleU u1, u2; |
1584 |
|
1585 |
u1.ll = op1; |
1586 |
u2.ll = op2; |
1587 |
u1.d = float64_add(u1.d, u2.d, &env->vec_status); |
1588 |
return u1.ll;
|
1589 |
} |
1590 |
|
1591 |
uint64_t helper_efdsub(CPUPPCState *env, uint64_t op1, uint64_t op2) |
1592 |
{ |
1593 |
CPU_DoubleU u1, u2; |
1594 |
|
1595 |
u1.ll = op1; |
1596 |
u2.ll = op2; |
1597 |
u1.d = float64_sub(u1.d, u2.d, &env->vec_status); |
1598 |
return u1.ll;
|
1599 |
} |
1600 |
|
1601 |
uint64_t helper_efdmul(CPUPPCState *env, uint64_t op1, uint64_t op2) |
1602 |
{ |
1603 |
CPU_DoubleU u1, u2; |
1604 |
|
1605 |
u1.ll = op1; |
1606 |
u2.ll = op2; |
1607 |
u1.d = float64_mul(u1.d, u2.d, &env->vec_status); |
1608 |
return u1.ll;
|
1609 |
} |
1610 |
|
1611 |
uint64_t helper_efddiv(CPUPPCState *env, uint64_t op1, uint64_t op2) |
1612 |
{ |
1613 |
CPU_DoubleU u1, u2; |
1614 |
|
1615 |
u1.ll = op1; |
1616 |
u2.ll = op2; |
1617 |
u1.d = float64_div(u1.d, u2.d, &env->vec_status); |
1618 |
return u1.ll;
|
1619 |
} |
1620 |
|
1621 |
/* Double precision floating point helpers */
|
1622 |
uint32_t helper_efdtstlt(CPUPPCState *env, uint64_t op1, uint64_t op2) |
1623 |
{ |
1624 |
CPU_DoubleU u1, u2; |
1625 |
|
1626 |
u1.ll = op1; |
1627 |
u2.ll = op2; |
1628 |
return float64_lt(u1.d, u2.d, &env->vec_status) ? 4 : 0; |
1629 |
} |
1630 |
|
1631 |
uint32_t helper_efdtstgt(CPUPPCState *env, uint64_t op1, uint64_t op2) |
1632 |
{ |
1633 |
CPU_DoubleU u1, u2; |
1634 |
|
1635 |
u1.ll = op1; |
1636 |
u2.ll = op2; |
1637 |
return float64_le(u1.d, u2.d, &env->vec_status) ? 0 : 4; |
1638 |
} |
1639 |
|
1640 |
uint32_t helper_efdtsteq(CPUPPCState *env, uint64_t op1, uint64_t op2) |
1641 |
{ |
1642 |
CPU_DoubleU u1, u2; |
1643 |
|
1644 |
u1.ll = op1; |
1645 |
u2.ll = op2; |
1646 |
return float64_eq_quiet(u1.d, u2.d, &env->vec_status) ? 4 : 0; |
1647 |
} |
1648 |
|
1649 |
uint32_t helper_efdcmplt(CPUPPCState *env, uint64_t op1, uint64_t op2) |
1650 |
{ |
1651 |
/* XXX: TODO: test special values (NaN, infinites, ...) */
|
1652 |
return helper_efdtstlt(env, op1, op2);
|
1653 |
} |
1654 |
|
1655 |
uint32_t helper_efdcmpgt(CPUPPCState *env, uint64_t op1, uint64_t op2) |
1656 |
{ |
1657 |
/* XXX: TODO: test special values (NaN, infinites, ...) */
|
1658 |
return helper_efdtstgt(env, op1, op2);
|
1659 |
} |
1660 |
|
1661 |
uint32_t helper_efdcmpeq(CPUPPCState *env, uint64_t op1, uint64_t op2) |
1662 |
{ |
1663 |
/* XXX: TODO: test special values (NaN, infinites, ...) */
|
1664 |
return helper_efdtsteq(env, op1, op2);
|
1665 |
} |
1666 |
|
1667 |
#define DECODE_SPLIT(opcode, shift1, nb1, shift2, nb2) \
|
1668 |
(((((opcode) >> (shift1)) & ((1 << (nb1)) - 1)) << nb2) | \ |
1669 |
(((opcode) >> (shift2)) & ((1 << (nb2)) - 1))) |
1670 |
|
1671 |
#define xT(opcode) DECODE_SPLIT(opcode, 0, 1, 21, 5) |
1672 |
#define xA(opcode) DECODE_SPLIT(opcode, 2, 1, 16, 5) |
1673 |
#define xB(opcode) DECODE_SPLIT(opcode, 1, 1, 11, 5) |
1674 |
#define xC(opcode) DECODE_SPLIT(opcode, 3, 1, 6, 5) |
1675 |
#define BF(opcode) (((opcode) >> (31-8)) & 7) |
1676 |
|
1677 |
typedef union _ppc_vsr_t { |
1678 |
uint64_t u64[2];
|
1679 |
uint32_t u32[4];
|
1680 |
float32 f32[4];
|
1681 |
float64 f64[2];
|
1682 |
} ppc_vsr_t; |
1683 |
|
1684 |
static void getVSR(int n, ppc_vsr_t *vsr, CPUPPCState *env) |
1685 |
{ |
1686 |
if (n < 32) { |
1687 |
vsr->f64[0] = env->fpr[n];
|
1688 |
vsr->u64[1] = env->vsr[n];
|
1689 |
} else {
|
1690 |
vsr->u64[0] = env->avr[n-32].u64[0]; |
1691 |
vsr->u64[1] = env->avr[n-32].u64[1]; |
1692 |
} |
1693 |
} |
1694 |
|
1695 |
static void putVSR(int n, ppc_vsr_t *vsr, CPUPPCState *env) |
1696 |
{ |
1697 |
if (n < 32) { |
1698 |
env->fpr[n] = vsr->f64[0];
|
1699 |
env->vsr[n] = vsr->u64[1];
|
1700 |
} else {
|
1701 |
env->avr[n-32].u64[0] = vsr->u64[0]; |
1702 |
env->avr[n-32].u64[1] = vsr->u64[1]; |
1703 |
} |
1704 |
} |
1705 |
|
1706 |
#define float64_to_float64(x, env) x
|
1707 |
|
1708 |
|
1709 |
/* VSX_ADD_SUB - VSX floating point add/subract
|
1710 |
* name - instruction mnemonic
|
1711 |
* op - operation (add or sub)
|
1712 |
* nels - number of elements (1, 2 or 4)
|
1713 |
* tp - type (float32 or float64)
|
1714 |
* fld - vsr_t field (f32 or f64)
|
1715 |
* sfprf - set FPRF
|
1716 |
*/
|
1717 |
#define VSX_ADD_SUB(name, op, nels, tp, fld, sfprf, r2sp) \
|
1718 |
void helper_##name(CPUPPCState *env, uint32_t opcode) \ |
1719 |
{ \ |
1720 |
ppc_vsr_t xt, xa, xb; \ |
1721 |
int i; \
|
1722 |
\ |
1723 |
getVSR(xA(opcode), &xa, env); \ |
1724 |
getVSR(xB(opcode), &xb, env); \ |
1725 |
getVSR(xT(opcode), &xt, env); \ |
1726 |
helper_reset_fpstatus(env); \ |
1727 |
\ |
1728 |
for (i = 0; i < nels; i++) { \ |
1729 |
float_status tstat = env->fp_status; \ |
1730 |
set_float_exception_flags(0, &tstat); \
|
1731 |
xt.fld[i] = tp##_##op(xa.fld[i], xb.fld[i], &tstat); \ |
1732 |
env->fp_status.float_exception_flags |= tstat.float_exception_flags; \ |
1733 |
\ |
1734 |
if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
|
1735 |
if (tp##_is_infinity(xa.fld[i]) && tp##_is_infinity(xb.fld[i])) {\ |
1736 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf); \ |
1737 |
} else if (tp##_is_signaling_nan(xa.fld[i]) || \ |
1738 |
tp##_is_signaling_nan(xb.fld[i])) { \ |
1739 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ |
1740 |
} \ |
1741 |
} \ |
1742 |
\ |
1743 |
if (r2sp) { \
|
1744 |
xt.fld[i] = helper_frsp(env, xt.fld[i]); \ |
1745 |
} \ |
1746 |
\ |
1747 |
if (sfprf) { \
|
1748 |
helper_compute_fprf(env, xt.fld[i], sfprf); \ |
1749 |
} \ |
1750 |
} \ |
1751 |
putVSR(xT(opcode), &xt, env); \ |
1752 |
helper_float_check_status(env); \ |
1753 |
} |
1754 |
|
1755 |
VSX_ADD_SUB(xsadddp, add, 1, float64, f64, 1, 0) |
1756 |
VSX_ADD_SUB(xsaddsp, add, 1, float64, f64, 1, 1) |
1757 |
VSX_ADD_SUB(xvadddp, add, 2, float64, f64, 0, 0) |
1758 |
VSX_ADD_SUB(xvaddsp, add, 4, float32, f32, 0, 0) |
1759 |
VSX_ADD_SUB(xssubdp, sub, 1, float64, f64, 1, 0) |
1760 |
VSX_ADD_SUB(xssubsp, sub, 1, float64, f64, 1, 1) |
1761 |
VSX_ADD_SUB(xvsubdp, sub, 2, float64, f64, 0, 0) |
1762 |
VSX_ADD_SUB(xvsubsp, sub, 4, float32, f32, 0, 0) |
1763 |
|
1764 |
/* VSX_MUL - VSX floating point multiply
|
1765 |
* op - instruction mnemonic
|
1766 |
* nels - number of elements (1, 2 or 4)
|
1767 |
* tp - type (float32 or float64)
|
1768 |
* fld - vsr_t field (f32 or f64)
|
1769 |
* sfprf - set FPRF
|
1770 |
*/
|
1771 |
#define VSX_MUL(op, nels, tp, fld, sfprf, r2sp) \
|
1772 |
void helper_##op(CPUPPCState *env, uint32_t opcode) \ |
1773 |
{ \ |
1774 |
ppc_vsr_t xt, xa, xb; \ |
1775 |
int i; \
|
1776 |
\ |
1777 |
getVSR(xA(opcode), &xa, env); \ |
1778 |
getVSR(xB(opcode), &xb, env); \ |
1779 |
getVSR(xT(opcode), &xt, env); \ |
1780 |
helper_reset_fpstatus(env); \ |
1781 |
\ |
1782 |
for (i = 0; i < nels; i++) { \ |
1783 |
float_status tstat = env->fp_status; \ |
1784 |
set_float_exception_flags(0, &tstat); \
|
1785 |
xt.fld[i] = tp##_mul(xa.fld[i], xb.fld[i], &tstat); \ |
1786 |
env->fp_status.float_exception_flags |= tstat.float_exception_flags; \ |
1787 |
\ |
1788 |
if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
|
1789 |
if ((tp##_is_infinity(xa.fld[i]) && tp##_is_zero(xb.fld[i])) || \ |
1790 |
(tp##_is_infinity(xb.fld[i]) && tp##_is_zero(xa.fld[i]))) { \ |
1791 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIMZ, sfprf); \ |
1792 |
} else if (tp##_is_signaling_nan(xa.fld[i]) || \ |
1793 |
tp##_is_signaling_nan(xb.fld[i])) { \ |
1794 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ |
1795 |
} \ |
1796 |
} \ |
1797 |
\ |
1798 |
if (r2sp) { \
|
1799 |
xt.fld[i] = helper_frsp(env, xt.fld[i]); \ |
1800 |
} \ |
1801 |
\ |
1802 |
if (sfprf) { \
|
1803 |
helper_compute_fprf(env, xt.fld[i], sfprf); \ |
1804 |
} \ |
1805 |
} \ |
1806 |
\ |
1807 |
putVSR(xT(opcode), &xt, env); \ |
1808 |
helper_float_check_status(env); \ |
1809 |
} |
1810 |
|
1811 |
VSX_MUL(xsmuldp, 1, float64, f64, 1, 0) |
1812 |
VSX_MUL(xsmulsp, 1, float64, f64, 1, 1) |
1813 |
VSX_MUL(xvmuldp, 2, float64, f64, 0, 0) |
1814 |
VSX_MUL(xvmulsp, 4, float32, f32, 0, 0) |
1815 |
|
1816 |
/* VSX_DIV - VSX floating point divide
|
1817 |
* op - instruction mnemonic
|
1818 |
* nels - number of elements (1, 2 or 4)
|
1819 |
* tp - type (float32 or float64)
|
1820 |
* fld - vsr_t field (f32 or f64)
|
1821 |
* sfprf - set FPRF
|
1822 |
*/
|
1823 |
#define VSX_DIV(op, nels, tp, fld, sfprf, r2sp) \
|
1824 |
void helper_##op(CPUPPCState *env, uint32_t opcode) \ |
1825 |
{ \ |
1826 |
ppc_vsr_t xt, xa, xb; \ |
1827 |
int i; \
|
1828 |
\ |
1829 |
getVSR(xA(opcode), &xa, env); \ |
1830 |
getVSR(xB(opcode), &xb, env); \ |
1831 |
getVSR(xT(opcode), &xt, env); \ |
1832 |
helper_reset_fpstatus(env); \ |
1833 |
\ |
1834 |
for (i = 0; i < nels; i++) { \ |
1835 |
float_status tstat = env->fp_status; \ |
1836 |
set_float_exception_flags(0, &tstat); \
|
1837 |
xt.fld[i] = tp##_div(xa.fld[i], xb.fld[i], &tstat); \ |
1838 |
env->fp_status.float_exception_flags |= tstat.float_exception_flags; \ |
1839 |
\ |
1840 |
if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
|
1841 |
if (tp##_is_infinity(xa.fld[i]) && tp##_is_infinity(xb.fld[i])) { \ |
1842 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXIDI, sfprf); \ |
1843 |
} else if (tp##_is_zero(xa.fld[i]) && \ |
1844 |
tp##_is_zero(xb.fld[i])) { \ |
1845 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXZDZ, sfprf); \ |
1846 |
} else if (tp##_is_signaling_nan(xa.fld[i]) || \ |
1847 |
tp##_is_signaling_nan(xb.fld[i])) { \ |
1848 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ |
1849 |
} \ |
1850 |
} \ |
1851 |
\ |
1852 |
if (r2sp) { \
|
1853 |
xt.fld[i] = helper_frsp(env, xt.fld[i]); \ |
1854 |
} \ |
1855 |
\ |
1856 |
if (sfprf) { \
|
1857 |
helper_compute_fprf(env, xt.fld[i], sfprf); \ |
1858 |
} \ |
1859 |
} \ |
1860 |
\ |
1861 |
putVSR(xT(opcode), &xt, env); \ |
1862 |
helper_float_check_status(env); \ |
1863 |
} |
1864 |
|
1865 |
VSX_DIV(xsdivdp, 1, float64, f64, 1, 0) |
1866 |
VSX_DIV(xsdivsp, 1, float64, f64, 1, 1) |
1867 |
VSX_DIV(xvdivdp, 2, float64, f64, 0, 0) |
1868 |
VSX_DIV(xvdivsp, 4, float32, f32, 0, 0) |
1869 |
|
1870 |
/* VSX_RE - VSX floating point reciprocal estimate
|
1871 |
* op - instruction mnemonic
|
1872 |
* nels - number of elements (1, 2 or 4)
|
1873 |
* tp - type (float32 or float64)
|
1874 |
* fld - vsr_t field (f32 or f64)
|
1875 |
* sfprf - set FPRF
|
1876 |
*/
|
1877 |
#define VSX_RE(op, nels, tp, fld, sfprf, r2sp) \
|
1878 |
void helper_##op(CPUPPCState *env, uint32_t opcode) \ |
1879 |
{ \ |
1880 |
ppc_vsr_t xt, xb; \ |
1881 |
int i; \
|
1882 |
\ |
1883 |
getVSR(xB(opcode), &xb, env); \ |
1884 |
getVSR(xT(opcode), &xt, env); \ |
1885 |
helper_reset_fpstatus(env); \ |
1886 |
\ |
1887 |
for (i = 0; i < nels; i++) { \ |
1888 |
if (unlikely(tp##_is_signaling_nan(xb.fld[i]))) { \ |
1889 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ |
1890 |
} \ |
1891 |
xt.fld[i] = tp##_div(tp##_one, xb.fld[i], &env->fp_status); \ |
1892 |
\ |
1893 |
if (r2sp) { \
|
1894 |
xt.fld[i] = helper_frsp(env, xt.fld[i]); \ |
1895 |
} \ |
1896 |
\ |
1897 |
if (sfprf) { \
|
1898 |
helper_compute_fprf(env, xt.fld[0], sfprf); \
|
1899 |
} \ |
1900 |
} \ |
1901 |
\ |
1902 |
putVSR(xT(opcode), &xt, env); \ |
1903 |
helper_float_check_status(env); \ |
1904 |
} |
1905 |
|
1906 |
VSX_RE(xsredp, 1, float64, f64, 1, 0) |
1907 |
VSX_RE(xsresp, 1, float64, f64, 1, 1) |
1908 |
VSX_RE(xvredp, 2, float64, f64, 0, 0) |
1909 |
VSX_RE(xvresp, 4, float32, f32, 0, 0) |
1910 |
|
1911 |
/* VSX_SQRT - VSX floating point square root
|
1912 |
* op - instruction mnemonic
|
1913 |
* nels - number of elements (1, 2 or 4)
|
1914 |
* tp - type (float32 or float64)
|
1915 |
* fld - vsr_t field (f32 or f64)
|
1916 |
* sfprf - set FPRF
|
1917 |
*/
|
1918 |
#define VSX_SQRT(op, nels, tp, fld, sfprf, r2sp) \
|
1919 |
void helper_##op(CPUPPCState *env, uint32_t opcode) \ |
1920 |
{ \ |
1921 |
ppc_vsr_t xt, xb; \ |
1922 |
int i; \
|
1923 |
\ |
1924 |
getVSR(xB(opcode), &xb, env); \ |
1925 |
getVSR(xT(opcode), &xt, env); \ |
1926 |
helper_reset_fpstatus(env); \ |
1927 |
\ |
1928 |
for (i = 0; i < nels; i++) { \ |
1929 |
float_status tstat = env->fp_status; \ |
1930 |
set_float_exception_flags(0, &tstat); \
|
1931 |
xt.fld[i] = tp##_sqrt(xb.fld[i], &tstat); \ |
1932 |
env->fp_status.float_exception_flags |= tstat.float_exception_flags; \ |
1933 |
\ |
1934 |
if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
|
1935 |
if (tp##_is_neg(xb.fld[i]) && !tp##_is_zero(xb.fld[i])) { \ |
1936 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf); \ |
1937 |
} else if (tp##_is_signaling_nan(xb.fld[i])) { \ |
1938 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ |
1939 |
} \ |
1940 |
} \ |
1941 |
\ |
1942 |
if (r2sp) { \
|
1943 |
xt.fld[i] = helper_frsp(env, xt.fld[i]); \ |
1944 |
} \ |
1945 |
\ |
1946 |
if (sfprf) { \
|
1947 |
helper_compute_fprf(env, xt.fld[i], sfprf); \ |
1948 |
} \ |
1949 |
} \ |
1950 |
\ |
1951 |
putVSR(xT(opcode), &xt, env); \ |
1952 |
helper_float_check_status(env); \ |
1953 |
} |
1954 |
|
1955 |
VSX_SQRT(xssqrtdp, 1, float64, f64, 1, 0) |
1956 |
VSX_SQRT(xssqrtsp, 1, float64, f64, 1, 1) |
1957 |
VSX_SQRT(xvsqrtdp, 2, float64, f64, 0, 0) |
1958 |
VSX_SQRT(xvsqrtsp, 4, float32, f32, 0, 0) |
1959 |
|
1960 |
/* VSX_RSQRTE - VSX floating point reciprocal square root estimate
|
1961 |
* op - instruction mnemonic
|
1962 |
* nels - number of elements (1, 2 or 4)
|
1963 |
* tp - type (float32 or float64)
|
1964 |
* fld - vsr_t field (f32 or f64)
|
1965 |
* sfprf - set FPRF
|
1966 |
*/
|
1967 |
#define VSX_RSQRTE(op, nels, tp, fld, sfprf, r2sp) \
|
1968 |
void helper_##op(CPUPPCState *env, uint32_t opcode) \ |
1969 |
{ \ |
1970 |
ppc_vsr_t xt, xb; \ |
1971 |
int i; \
|
1972 |
\ |
1973 |
getVSR(xB(opcode), &xb, env); \ |
1974 |
getVSR(xT(opcode), &xt, env); \ |
1975 |
helper_reset_fpstatus(env); \ |
1976 |
\ |
1977 |
for (i = 0; i < nels; i++) { \ |
1978 |
float_status tstat = env->fp_status; \ |
1979 |
set_float_exception_flags(0, &tstat); \
|
1980 |
xt.fld[i] = tp##_sqrt(xb.fld[i], &tstat); \ |
1981 |
xt.fld[i] = tp##_div(tp##_one, xt.fld[i], &tstat); \ |
1982 |
env->fp_status.float_exception_flags |= tstat.float_exception_flags; \ |
1983 |
\ |
1984 |
if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
|
1985 |
if (tp##_is_neg(xb.fld[i]) && !tp##_is_zero(xb.fld[i])) { \ |
1986 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSQRT, sfprf); \ |
1987 |
} else if (tp##_is_signaling_nan(xb.fld[i])) { \ |
1988 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ |
1989 |
} \ |
1990 |
} \ |
1991 |
\ |
1992 |
if (r2sp) { \
|
1993 |
xt.fld[i] = helper_frsp(env, xt.fld[i]); \ |
1994 |
} \ |
1995 |
\ |
1996 |
if (sfprf) { \
|
1997 |
helper_compute_fprf(env, xt.fld[i], sfprf); \ |
1998 |
} \ |
1999 |
} \ |
2000 |
\ |
2001 |
putVSR(xT(opcode), &xt, env); \ |
2002 |
helper_float_check_status(env); \ |
2003 |
} |
2004 |
|
2005 |
VSX_RSQRTE(xsrsqrtedp, 1, float64, f64, 1, 0) |
2006 |
VSX_RSQRTE(xsrsqrtesp, 1, float64, f64, 1, 1) |
2007 |
VSX_RSQRTE(xvrsqrtedp, 2, float64, f64, 0, 0) |
2008 |
VSX_RSQRTE(xvrsqrtesp, 4, float32, f32, 0, 0) |
2009 |
|
2010 |
static inline int ppc_float32_get_unbiased_exp(float32 f) |
2011 |
{ |
2012 |
return ((f >> 23) & 0xFF) - 127; |
2013 |
} |
2014 |
|
2015 |
static inline int ppc_float64_get_unbiased_exp(float64 f) |
2016 |
{ |
2017 |
return ((f >> 52) & 0x7FF) - 1023; |
2018 |
} |
2019 |
|
2020 |
/* VSX_TDIV - VSX floating point test for divide
|
2021 |
* op - instruction mnemonic
|
2022 |
* nels - number of elements (1, 2 or 4)
|
2023 |
* tp - type (float32 or float64)
|
2024 |
* fld - vsr_t field (f32 or f64)
|
2025 |
* emin - minimum unbiased exponent
|
2026 |
* emax - maximum unbiased exponent
|
2027 |
* nbits - number of fraction bits
|
2028 |
*/
|
2029 |
#define VSX_TDIV(op, nels, tp, fld, emin, emax, nbits) \
|
2030 |
void helper_##op(CPUPPCState *env, uint32_t opcode) \ |
2031 |
{ \ |
2032 |
ppc_vsr_t xa, xb; \ |
2033 |
int i; \
|
2034 |
int fe_flag = 0; \ |
2035 |
int fg_flag = 0; \ |
2036 |
\ |
2037 |
getVSR(xA(opcode), &xa, env); \ |
2038 |
getVSR(xB(opcode), &xb, env); \ |
2039 |
\ |
2040 |
for (i = 0; i < nels; i++) { \ |
2041 |
if (unlikely(tp##_is_infinity(xa.fld[i]) || \ |
2042 |
tp##_is_infinity(xb.fld[i]) || \ |
2043 |
tp##_is_zero(xb.fld[i]))) { \ |
2044 |
fe_flag = 1; \
|
2045 |
fg_flag = 1; \
|
2046 |
} else { \
|
2047 |
int e_a = ppc_##tp##_get_unbiased_exp(xa.fld[i]); \ |
2048 |
int e_b = ppc_##tp##_get_unbiased_exp(xb.fld[i]); \ |
2049 |
\ |
2050 |
if (unlikely(tp##_is_any_nan(xa.fld[i]) || \ |
2051 |
tp##_is_any_nan(xb.fld[i]))) { \ |
2052 |
fe_flag = 1; \
|
2053 |
} else if ((e_b <= emin) || (e_b >= (emax-2))) { \ |
2054 |
fe_flag = 1; \
|
2055 |
} else if (!tp##_is_zero(xa.fld[i]) && \ |
2056 |
(((e_a - e_b) >= emax) || \ |
2057 |
((e_a - e_b) <= (emin+1)) || \
|
2058 |
(e_a <= (emin+nbits)))) { \ |
2059 |
fe_flag = 1; \
|
2060 |
} \ |
2061 |
\ |
2062 |
if (unlikely(tp##_is_zero_or_denormal(xb.fld[i]))) { \ |
2063 |
/* XB is not zero because of the above check and */ \
|
2064 |
/* so must be denormalized. */ \
|
2065 |
fg_flag = 1; \
|
2066 |
} \ |
2067 |
} \ |
2068 |
} \ |
2069 |
\ |
2070 |
env->crf[BF(opcode)] = 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0); \ |
2071 |
} |
2072 |
|
2073 |
VSX_TDIV(xstdivdp, 1, float64, f64, -1022, 1023, 52) |
2074 |
VSX_TDIV(xvtdivdp, 2, float64, f64, -1022, 1023, 52) |
2075 |
VSX_TDIV(xvtdivsp, 4, float32, f32, -126, 127, 23) |
2076 |
|
2077 |
/* VSX_TSQRT - VSX floating point test for square root
|
2078 |
* op - instruction mnemonic
|
2079 |
* nels - number of elements (1, 2 or 4)
|
2080 |
* tp - type (float32 or float64)
|
2081 |
* fld - vsr_t field (f32 or f64)
|
2082 |
* emin - minimum unbiased exponent
|
2083 |
* emax - maximum unbiased exponent
|
2084 |
* nbits - number of fraction bits
|
2085 |
*/
|
2086 |
#define VSX_TSQRT(op, nels, tp, fld, emin, nbits) \
|
2087 |
void helper_##op(CPUPPCState *env, uint32_t opcode) \ |
2088 |
{ \ |
2089 |
ppc_vsr_t xa, xb; \ |
2090 |
int i; \
|
2091 |
int fe_flag = 0; \ |
2092 |
int fg_flag = 0; \ |
2093 |
\ |
2094 |
getVSR(xA(opcode), &xa, env); \ |
2095 |
getVSR(xB(opcode), &xb, env); \ |
2096 |
\ |
2097 |
for (i = 0; i < nels; i++) { \ |
2098 |
if (unlikely(tp##_is_infinity(xb.fld[i]) || \ |
2099 |
tp##_is_zero(xb.fld[i]))) { \ |
2100 |
fe_flag = 1; \
|
2101 |
fg_flag = 1; \
|
2102 |
} else { \
|
2103 |
int e_b = ppc_##tp##_get_unbiased_exp(xb.fld[i]); \ |
2104 |
\ |
2105 |
if (unlikely(tp##_is_any_nan(xb.fld[i]))) { \ |
2106 |
fe_flag = 1; \
|
2107 |
} else if (unlikely(tp##_is_zero(xb.fld[i]))) { \ |
2108 |
fe_flag = 1; \
|
2109 |
} else if (unlikely(tp##_is_neg(xb.fld[i]))) { \ |
2110 |
fe_flag = 1; \
|
2111 |
} else if (!tp##_is_zero(xb.fld[i]) && \ |
2112 |
(e_b <= (emin+nbits))) { \ |
2113 |
fe_flag = 1; \
|
2114 |
} \ |
2115 |
\ |
2116 |
if (unlikely(tp##_is_zero_or_denormal(xb.fld[i]))) { \ |
2117 |
/* XB is not zero because of the above check and */ \
|
2118 |
/* therefore must be denormalized. */ \
|
2119 |
fg_flag = 1; \
|
2120 |
} \ |
2121 |
} \ |
2122 |
} \ |
2123 |
\ |
2124 |
env->crf[BF(opcode)] = 0x8 | (fg_flag ? 4 : 0) | (fe_flag ? 2 : 0); \ |
2125 |
} |
2126 |
|
2127 |
VSX_TSQRT(xstsqrtdp, 1, float64, f64, -1022, 52) |
2128 |
VSX_TSQRT(xvtsqrtdp, 2, float64, f64, -1022, 52) |
2129 |
VSX_TSQRT(xvtsqrtsp, 4, float32, f32, -126, 23) |
2130 |
|
2131 |
/* VSX_MADD - VSX floating point muliply/add variations
|
2132 |
* op - instruction mnemonic
|
2133 |
* nels - number of elements (1, 2 or 4)
|
2134 |
* tp - type (float32 or float64)
|
2135 |
* fld - vsr_t field (f32 or f64)
|
2136 |
* maddflgs - flags for the float*muladd routine that control the
|
2137 |
* various forms (madd, msub, nmadd, nmsub)
|
2138 |
* afrm - A form (1=A, 0=M)
|
2139 |
* sfprf - set FPRF
|
2140 |
*/
|
2141 |
#define VSX_MADD(op, nels, tp, fld, maddflgs, afrm, sfprf, r2sp) \
|
2142 |
void helper_##op(CPUPPCState *env, uint32_t opcode) \ |
2143 |
{ \ |
2144 |
ppc_vsr_t xt_in, xa, xb, xt_out; \ |
2145 |
ppc_vsr_t *b, *c; \ |
2146 |
int i; \
|
2147 |
\ |
2148 |
if (afrm) { /* AxB + T */ \ |
2149 |
b = &xb; \ |
2150 |
c = &xt_in; \ |
2151 |
} else { /* AxT + B */ \ |
2152 |
b = &xt_in; \ |
2153 |
c = &xb; \ |
2154 |
} \ |
2155 |
\ |
2156 |
getVSR(xA(opcode), &xa, env); \ |
2157 |
getVSR(xB(opcode), &xb, env); \ |
2158 |
getVSR(xT(opcode), &xt_in, env); \ |
2159 |
\ |
2160 |
xt_out = xt_in; \ |
2161 |
\ |
2162 |
helper_reset_fpstatus(env); \ |
2163 |
\ |
2164 |
for (i = 0; i < nels; i++) { \ |
2165 |
float_status tstat = env->fp_status; \ |
2166 |
set_float_exception_flags(0, &tstat); \
|
2167 |
if (r2sp && (tstat.float_rounding_mode == float_round_nearest_even)) {\
|
2168 |
/* Avoid double rounding errors by rounding the intermediate */ \
|
2169 |
/* result to odd. */ \
|
2170 |
set_float_rounding_mode(float_round_to_zero, &tstat); \ |
2171 |
xt_out.fld[i] = tp##_muladd(xa.fld[i], b->fld[i], c->fld[i], \ |
2172 |
maddflgs, &tstat); \ |
2173 |
xt_out.fld[i] |= (get_float_exception_flags(&tstat) & \ |
2174 |
float_flag_inexact) != 0; \
|
2175 |
} else { \
|
2176 |
xt_out.fld[i] = tp##_muladd(xa.fld[i], b->fld[i], c->fld[i], \ |
2177 |
maddflgs, &tstat); \ |
2178 |
} \ |
2179 |
env->fp_status.float_exception_flags |= tstat.float_exception_flags; \ |
2180 |
\ |
2181 |
if (unlikely(tstat.float_exception_flags & float_flag_invalid)) { \
|
2182 |
if (tp##_is_signaling_nan(xa.fld[i]) || \ |
2183 |
tp##_is_signaling_nan(b->fld[i]) || \ |
2184 |
tp##_is_signaling_nan(c->fld[i])) { \ |
2185 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, sfprf); \ |
2186 |
tstat.float_exception_flags &= ~float_flag_invalid; \ |
2187 |
} \ |
2188 |
if ((tp##_is_infinity(xa.fld[i]) && tp##_is_zero(b->fld[i])) || \ |
2189 |
(tp##_is_zero(xa.fld[i]) && tp##_is_infinity(b->fld[i]))) { \ |
2190 |
xt_out.fld[i] = float64_to_##tp(fload_invalid_op_excp(env, \ |
2191 |
POWERPC_EXCP_FP_VXIMZ, sfprf), &env->fp_status); \ |
2192 |
tstat.float_exception_flags &= ~float_flag_invalid; \ |
2193 |
} \ |
2194 |
if ((tstat.float_exception_flags & float_flag_invalid) && \
|
2195 |
((tp##_is_infinity(xa.fld[i]) || \ |
2196 |
tp##_is_infinity(b->fld[i])) && \ |
2197 |
tp##_is_infinity(c->fld[i]))) { \ |
2198 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXISI, sfprf); \ |
2199 |
} \ |
2200 |
} \ |
2201 |
\ |
2202 |
if (r2sp) { \
|
2203 |
xt_out.fld[i] = helper_frsp(env, xt_out.fld[i]); \ |
2204 |
} \ |
2205 |
\ |
2206 |
if (sfprf) { \
|
2207 |
helper_compute_fprf(env, xt_out.fld[i], sfprf); \ |
2208 |
} \ |
2209 |
} \ |
2210 |
putVSR(xT(opcode), &xt_out, env); \ |
2211 |
helper_float_check_status(env); \ |
2212 |
} |
2213 |
|
2214 |
#define MADD_FLGS 0 |
2215 |
#define MSUB_FLGS float_muladd_negate_c
|
2216 |
#define NMADD_FLGS float_muladd_negate_result
|
2217 |
#define NMSUB_FLGS (float_muladd_negate_c | float_muladd_negate_result)
|
2218 |
|
2219 |
VSX_MADD(xsmaddadp, 1, float64, f64, MADD_FLGS, 1, 1, 0) |
2220 |
VSX_MADD(xsmaddmdp, 1, float64, f64, MADD_FLGS, 0, 1, 0) |
2221 |
VSX_MADD(xsmsubadp, 1, float64, f64, MSUB_FLGS, 1, 1, 0) |
2222 |
VSX_MADD(xsmsubmdp, 1, float64, f64, MSUB_FLGS, 0, 1, 0) |
2223 |
VSX_MADD(xsnmaddadp, 1, float64, f64, NMADD_FLGS, 1, 1, 0) |
2224 |
VSX_MADD(xsnmaddmdp, 1, float64, f64, NMADD_FLGS, 0, 1, 0) |
2225 |
VSX_MADD(xsnmsubadp, 1, float64, f64, NMSUB_FLGS, 1, 1, 0) |
2226 |
VSX_MADD(xsnmsubmdp, 1, float64, f64, NMSUB_FLGS, 0, 1, 0) |
2227 |
|
2228 |
VSX_MADD(xsmaddasp, 1, float64, f64, MADD_FLGS, 1, 1, 1) |
2229 |
VSX_MADD(xsmaddmsp, 1, float64, f64, MADD_FLGS, 0, 1, 1) |
2230 |
VSX_MADD(xsmsubasp, 1, float64, f64, MSUB_FLGS, 1, 1, 1) |
2231 |
VSX_MADD(xsmsubmsp, 1, float64, f64, MSUB_FLGS, 0, 1, 1) |
2232 |
VSX_MADD(xsnmaddasp, 1, float64, f64, NMADD_FLGS, 1, 1, 1) |
2233 |
VSX_MADD(xsnmaddmsp, 1, float64, f64, NMADD_FLGS, 0, 1, 1) |
2234 |
VSX_MADD(xsnmsubasp, 1, float64, f64, NMSUB_FLGS, 1, 1, 1) |
2235 |
VSX_MADD(xsnmsubmsp, 1, float64, f64, NMSUB_FLGS, 0, 1, 1) |
2236 |
|
2237 |
VSX_MADD(xvmaddadp, 2, float64, f64, MADD_FLGS, 1, 0, 0) |
2238 |
VSX_MADD(xvmaddmdp, 2, float64, f64, MADD_FLGS, 0, 0, 0) |
2239 |
VSX_MADD(xvmsubadp, 2, float64, f64, MSUB_FLGS, 1, 0, 0) |
2240 |
VSX_MADD(xvmsubmdp, 2, float64, f64, MSUB_FLGS, 0, 0, 0) |
2241 |
VSX_MADD(xvnmaddadp, 2, float64, f64, NMADD_FLGS, 1, 0, 0) |
2242 |
VSX_MADD(xvnmaddmdp, 2, float64, f64, NMADD_FLGS, 0, 0, 0) |
2243 |
VSX_MADD(xvnmsubadp, 2, float64, f64, NMSUB_FLGS, 1, 0, 0) |
2244 |
VSX_MADD(xvnmsubmdp, 2, float64, f64, NMSUB_FLGS, 0, 0, 0) |
2245 |
|
2246 |
VSX_MADD(xvmaddasp, 4, float32, f32, MADD_FLGS, 1, 0, 0) |
2247 |
VSX_MADD(xvmaddmsp, 4, float32, f32, MADD_FLGS, 0, 0, 0) |
2248 |
VSX_MADD(xvmsubasp, 4, float32, f32, MSUB_FLGS, 1, 0, 0) |
2249 |
VSX_MADD(xvmsubmsp, 4, float32, f32, MSUB_FLGS, 0, 0, 0) |
2250 |
VSX_MADD(xvnmaddasp, 4, float32, f32, NMADD_FLGS, 1, 0, 0) |
2251 |
VSX_MADD(xvnmaddmsp, 4, float32, f32, NMADD_FLGS, 0, 0, 0) |
2252 |
VSX_MADD(xvnmsubasp, 4, float32, f32, NMSUB_FLGS, 1, 0, 0) |
2253 |
VSX_MADD(xvnmsubmsp, 4, float32, f32, NMSUB_FLGS, 0, 0, 0) |
2254 |
|
2255 |
#define VSX_SCALAR_CMP(op, ordered) \
|
2256 |
void helper_##op(CPUPPCState *env, uint32_t opcode) \ |
2257 |
{ \ |
2258 |
ppc_vsr_t xa, xb; \ |
2259 |
uint32_t cc = 0; \
|
2260 |
\ |
2261 |
getVSR(xA(opcode), &xa, env); \ |
2262 |
getVSR(xB(opcode), &xb, env); \ |
2263 |
\ |
2264 |
if (unlikely(float64_is_any_nan(xa.f64[0]) || \ |
2265 |
float64_is_any_nan(xb.f64[0]))) { \
|
2266 |
if (float64_is_signaling_nan(xa.f64[0]) || \ |
2267 |
float64_is_signaling_nan(xb.f64[0])) { \
|
2268 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
|
2269 |
} \ |
2270 |
if (ordered) { \
|
2271 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0); \
|
2272 |
} \ |
2273 |
cc = 1; \
|
2274 |
} else { \
|
2275 |
if (float64_lt(xa.f64[0], xb.f64[0], &env->fp_status)) { \ |
2276 |
cc = 8; \
|
2277 |
} else if (!float64_le(xa.f64[0], xb.f64[0], &env->fp_status)) { \ |
2278 |
cc = 4; \
|
2279 |
} else { \
|
2280 |
cc = 2; \
|
2281 |
} \ |
2282 |
} \ |
2283 |
\ |
2284 |
env->fpscr &= ~(0x0F << FPSCR_FPRF); \
|
2285 |
env->fpscr |= cc << FPSCR_FPRF; \ |
2286 |
env->crf[BF(opcode)] = cc; \ |
2287 |
\ |
2288 |
helper_float_check_status(env); \ |
2289 |
} |
2290 |
|
2291 |
VSX_SCALAR_CMP(xscmpodp, 1)
|
2292 |
VSX_SCALAR_CMP(xscmpudp, 0)
|
2293 |
|
2294 |
#define float64_snan_to_qnan(x) ((x) | 0x0008000000000000ul) |
2295 |
#define float32_snan_to_qnan(x) ((x) | 0x00400000) |
2296 |
|
2297 |
/* VSX_MAX_MIN - VSX floating point maximum/minimum
|
2298 |
* name - instruction mnemonic
|
2299 |
* op - operation (max or min)
|
2300 |
* nels - number of elements (1, 2 or 4)
|
2301 |
* tp - type (float32 or float64)
|
2302 |
* fld - vsr_t field (f32 or f64)
|
2303 |
*/
|
2304 |
#define VSX_MAX_MIN(name, op, nels, tp, fld) \
|
2305 |
void helper_##name(CPUPPCState *env, uint32_t opcode) \ |
2306 |
{ \ |
2307 |
ppc_vsr_t xt, xa, xb; \ |
2308 |
int i; \
|
2309 |
\ |
2310 |
getVSR(xA(opcode), &xa, env); \ |
2311 |
getVSR(xB(opcode), &xb, env); \ |
2312 |
getVSR(xT(opcode), &xt, env); \ |
2313 |
\ |
2314 |
for (i = 0; i < nels; i++) { \ |
2315 |
xt.fld[i] = tp##_##op(xa.fld[i], xb.fld[i], &env->fp_status); \ |
2316 |
if (unlikely(tp##_is_signaling_nan(xa.fld[i]) || \ |
2317 |
tp##_is_signaling_nan(xb.fld[i]))) { \ |
2318 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
|
2319 |
} \ |
2320 |
} \ |
2321 |
\ |
2322 |
putVSR(xT(opcode), &xt, env); \ |
2323 |
helper_float_check_status(env); \ |
2324 |
} |
2325 |
|
2326 |
VSX_MAX_MIN(xsmaxdp, maxnum, 1, float64, f64)
|
2327 |
VSX_MAX_MIN(xvmaxdp, maxnum, 2, float64, f64)
|
2328 |
VSX_MAX_MIN(xvmaxsp, maxnum, 4, float32, f32)
|
2329 |
VSX_MAX_MIN(xsmindp, minnum, 1, float64, f64)
|
2330 |
VSX_MAX_MIN(xvmindp, minnum, 2, float64, f64)
|
2331 |
VSX_MAX_MIN(xvminsp, minnum, 4, float32, f32)
|
2332 |
|
2333 |
/* VSX_CMP - VSX floating point compare
|
2334 |
* op - instruction mnemonic
|
2335 |
* nels - number of elements (1, 2 or 4)
|
2336 |
* tp - type (float32 or float64)
|
2337 |
* fld - vsr_t field (f32 or f64)
|
2338 |
* cmp - comparison operation
|
2339 |
* svxvc - set VXVC bit
|
2340 |
*/
|
2341 |
#define VSX_CMP(op, nels, tp, fld, cmp, svxvc) \
|
2342 |
void helper_##op(CPUPPCState *env, uint32_t opcode) \ |
2343 |
{ \ |
2344 |
ppc_vsr_t xt, xa, xb; \ |
2345 |
int i; \
|
2346 |
int all_true = 1; \ |
2347 |
int all_false = 1; \ |
2348 |
\ |
2349 |
getVSR(xA(opcode), &xa, env); \ |
2350 |
getVSR(xB(opcode), &xb, env); \ |
2351 |
getVSR(xT(opcode), &xt, env); \ |
2352 |
\ |
2353 |
for (i = 0; i < nels; i++) { \ |
2354 |
if (unlikely(tp##_is_any_nan(xa.fld[i]) || \ |
2355 |
tp##_is_any_nan(xb.fld[i]))) { \ |
2356 |
if (tp##_is_signaling_nan(xa.fld[i]) || \ |
2357 |
tp##_is_signaling_nan(xb.fld[i])) { \ |
2358 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
|
2359 |
} \ |
2360 |
if (svxvc) { \
|
2361 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXVC, 0); \
|
2362 |
} \ |
2363 |
xt.fld[i] = 0; \
|
2364 |
all_true = 0; \
|
2365 |
} else { \
|
2366 |
if (tp##_##cmp(xb.fld[i], xa.fld[i], &env->fp_status) == 1) { \ |
2367 |
xt.fld[i] = -1; \
|
2368 |
all_false = 0; \
|
2369 |
} else { \
|
2370 |
xt.fld[i] = 0; \
|
2371 |
all_true = 0; \
|
2372 |
} \ |
2373 |
} \ |
2374 |
} \ |
2375 |
\ |
2376 |
putVSR(xT(opcode), &xt, env); \ |
2377 |
if ((opcode >> (31-21)) & 1) { \ |
2378 |
env->crf[6] = (all_true ? 0x8 : 0) | (all_false ? 0x2 : 0); \ |
2379 |
} \ |
2380 |
helper_float_check_status(env); \ |
2381 |
} |
2382 |
|
2383 |
VSX_CMP(xvcmpeqdp, 2, float64, f64, eq, 0) |
2384 |
VSX_CMP(xvcmpgedp, 2, float64, f64, le, 1) |
2385 |
VSX_CMP(xvcmpgtdp, 2, float64, f64, lt, 1) |
2386 |
VSX_CMP(xvcmpeqsp, 4, float32, f32, eq, 0) |
2387 |
VSX_CMP(xvcmpgesp, 4, float32, f32, le, 1) |
2388 |
VSX_CMP(xvcmpgtsp, 4, float32, f32, lt, 1) |
2389 |
|
2390 |
#if defined(HOST_WORDS_BIGENDIAN)
|
2391 |
#define JOFFSET 0 |
2392 |
#else
|
2393 |
#define JOFFSET 1 |
2394 |
#endif
|
2395 |
|
2396 |
/* VSX_CVT_FP_TO_FP - VSX floating point/floating point conversion
|
2397 |
* op - instruction mnemonic
|
2398 |
* nels - number of elements (1, 2 or 4)
|
2399 |
* stp - source type (float32 or float64)
|
2400 |
* ttp - target type (float32 or float64)
|
2401 |
* sfld - source vsr_t field
|
2402 |
* tfld - target vsr_t field (f32 or f64)
|
2403 |
* sfprf - set FPRF
|
2404 |
*/
|
2405 |
#define VSX_CVT_FP_TO_FP(op, nels, stp, ttp, sfld, tfld, sfprf) \
|
2406 |
void helper_##op(CPUPPCState *env, uint32_t opcode) \ |
2407 |
{ \ |
2408 |
ppc_vsr_t xt, xb; \ |
2409 |
int i; \
|
2410 |
\ |
2411 |
getVSR(xB(opcode), &xb, env); \ |
2412 |
getVSR(xT(opcode), &xt, env); \ |
2413 |
\ |
2414 |
for (i = 0; i < nels; i++) { \ |
2415 |
int j = 2*i + JOFFSET; \ |
2416 |
xt.tfld = stp##_to_##ttp(xb.sfld, &env->fp_status); \ |
2417 |
if (unlikely(stp##_is_signaling_nan(xb.sfld))) { \ |
2418 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
|
2419 |
xt.tfld = ttp##_snan_to_qnan(xt.tfld); \ |
2420 |
} \ |
2421 |
if (sfprf) { \
|
2422 |
helper_compute_fprf(env, ttp##_to_float64(xt.tfld, \ |
2423 |
&env->fp_status), sfprf); \ |
2424 |
} \ |
2425 |
} \ |
2426 |
\ |
2427 |
putVSR(xT(opcode), &xt, env); \ |
2428 |
helper_float_check_status(env); \ |
2429 |
} |
2430 |
|
2431 |
VSX_CVT_FP_TO_FP(xscvdpsp, 1, float64, float32, f64[i], f32[j], 1) |
2432 |
VSX_CVT_FP_TO_FP(xscvspdp, 1, float32, float64, f32[j], f64[i], 1) |
2433 |
VSX_CVT_FP_TO_FP(xvcvdpsp, 2, float64, float32, f64[i], f32[j], 0) |
2434 |
VSX_CVT_FP_TO_FP(xvcvspdp, 2, float32, float64, f32[j], f64[i], 0) |
2435 |
|
2436 |
uint64_t helper_xscvdpspn(CPUPPCState *env, uint64_t xb) |
2437 |
{ |
2438 |
float_status tstat = env->fp_status; |
2439 |
set_float_exception_flags(0, &tstat);
|
2440 |
|
2441 |
return (uint64_t)float64_to_float32(xb, &tstat) << 32; |
2442 |
} |
2443 |
|
2444 |
uint64_t helper_xscvspdpn(CPUPPCState *env, uint64_t xb) |
2445 |
{ |
2446 |
float_status tstat = env->fp_status; |
2447 |
set_float_exception_flags(0, &tstat);
|
2448 |
|
2449 |
return float32_to_float64(xb >> 32, &tstat); |
2450 |
} |
2451 |
|
2452 |
/* VSX_CVT_FP_TO_INT - VSX floating point to integer conversion
|
2453 |
* op - instruction mnemonic
|
2454 |
* nels - number of elements (1, 2 or 4)
|
2455 |
* stp - source type (float32 or float64)
|
2456 |
* ttp - target type (int32, uint32, int64 or uint64)
|
2457 |
* sfld - source vsr_t field
|
2458 |
* tfld - target vsr_t field
|
2459 |
* jdef - definition of the j index (i or 2*i)
|
2460 |
* rnan - resulting NaN
|
2461 |
*/
|
2462 |
#define VSX_CVT_FP_TO_INT(op, nels, stp, ttp, sfld, tfld, jdef, rnan) \
|
2463 |
void helper_##op(CPUPPCState *env, uint32_t opcode) \ |
2464 |
{ \ |
2465 |
ppc_vsr_t xt, xb; \ |
2466 |
int i; \
|
2467 |
\ |
2468 |
getVSR(xB(opcode), &xb, env); \ |
2469 |
getVSR(xT(opcode), &xt, env); \ |
2470 |
\ |
2471 |
for (i = 0; i < nels; i++) { \ |
2472 |
int j = jdef; \
|
2473 |
if (unlikely(stp##_is_any_nan(xb.sfld))) { \ |
2474 |
if (stp##_is_signaling_nan(xb.sfld)) { \ |
2475 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
|
2476 |
} \ |
2477 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0); \
|
2478 |
xt.tfld = rnan; \ |
2479 |
} else { \
|
2480 |
xt.tfld = stp##_to_##ttp(xb.sfld, &env->fp_status); \ |
2481 |
if (env->fp_status.float_exception_flags & float_flag_invalid) { \
|
2482 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXCVI, 0); \
|
2483 |
} \ |
2484 |
} \ |
2485 |
} \ |
2486 |
\ |
2487 |
putVSR(xT(opcode), &xt, env); \ |
2488 |
helper_float_check_status(env); \ |
2489 |
} |
2490 |
|
2491 |
VSX_CVT_FP_TO_INT(xscvdpsxds, 1, float64, int64, f64[j], u64[i], i, \
|
2492 |
0x8000000000000000ul)
|
2493 |
VSX_CVT_FP_TO_INT(xscvdpsxws, 1, float64, int32, f64[i], u32[j], \
|
2494 |
2*i + JOFFSET, 0x80000000l) |
2495 |
VSX_CVT_FP_TO_INT(xscvdpuxds, 1, float64, uint64, f64[j], u64[i], i, 0ul) |
2496 |
VSX_CVT_FP_TO_INT(xscvdpuxws, 1, float64, uint32, f64[i], u32[j], \
|
2497 |
2*i + JOFFSET, 0) |
2498 |
VSX_CVT_FP_TO_INT(xvcvdpsxds, 2, float64, int64, f64[j], u64[i], i, \
|
2499 |
0x8000000000000000ul)
|
2500 |
VSX_CVT_FP_TO_INT(xvcvdpsxws, 2, float64, int32, f64[i], u32[j], \
|
2501 |
2*i + JOFFSET, 0x80000000l) |
2502 |
VSX_CVT_FP_TO_INT(xvcvdpuxds, 2, float64, uint64, f64[j], u64[i], i, 0ul) |
2503 |
VSX_CVT_FP_TO_INT(xvcvdpuxws, 2, float64, uint32, f64[i], u32[j], \
|
2504 |
2*i + JOFFSET, 0) |
2505 |
VSX_CVT_FP_TO_INT(xvcvspsxds, 2, float32, int64, f32[j], u64[i], \
|
2506 |
2*i + JOFFSET, 0x8000000000000000ul) |
2507 |
VSX_CVT_FP_TO_INT(xvcvspsxws, 4, float32, int32, f32[j], u32[j], i, \
|
2508 |
0x80000000l)
|
2509 |
VSX_CVT_FP_TO_INT(xvcvspuxds, 2, float32, uint64, f32[j], u64[i], \
|
2510 |
2*i + JOFFSET, 0ul) |
2511 |
VSX_CVT_FP_TO_INT(xvcvspuxws, 4, float32, uint32, f32[j], u32[i], i, 0) |
2512 |
|
2513 |
/* VSX_CVT_INT_TO_FP - VSX integer to floating point conversion
|
2514 |
* op - instruction mnemonic
|
2515 |
* nels - number of elements (1, 2 or 4)
|
2516 |
* stp - source type (int32, uint32, int64 or uint64)
|
2517 |
* ttp - target type (float32 or float64)
|
2518 |
* sfld - source vsr_t field
|
2519 |
* tfld - target vsr_t field
|
2520 |
* jdef - definition of the j index (i or 2*i)
|
2521 |
* sfprf - set FPRF
|
2522 |
*/
|
2523 |
#define VSX_CVT_INT_TO_FP(op, nels, stp, ttp, sfld, tfld, jdef, sfprf, r2sp) \
|
2524 |
void helper_##op(CPUPPCState *env, uint32_t opcode) \ |
2525 |
{ \ |
2526 |
ppc_vsr_t xt, xb; \ |
2527 |
int i; \
|
2528 |
\ |
2529 |
getVSR(xB(opcode), &xb, env); \ |
2530 |
getVSR(xT(opcode), &xt, env); \ |
2531 |
\ |
2532 |
for (i = 0; i < nels; i++) { \ |
2533 |
int j = jdef; \
|
2534 |
xt.tfld = stp##_to_##ttp(xb.sfld, &env->fp_status); \ |
2535 |
if (r2sp) { \
|
2536 |
xt.tfld = helper_frsp(env, xt.tfld); \ |
2537 |
} \ |
2538 |
if (sfprf) { \
|
2539 |
helper_compute_fprf(env, xt.tfld, sfprf); \ |
2540 |
} \ |
2541 |
} \ |
2542 |
\ |
2543 |
putVSR(xT(opcode), &xt, env); \ |
2544 |
helper_float_check_status(env); \ |
2545 |
} |
2546 |
|
2547 |
VSX_CVT_INT_TO_FP(xscvsxddp, 1, int64, float64, u64[j], f64[i], i, 1, 0) |
2548 |
VSX_CVT_INT_TO_FP(xscvuxddp, 1, uint64, float64, u64[j], f64[i], i, 1, 0) |
2549 |
VSX_CVT_INT_TO_FP(xscvsxdsp, 1, int64, float64, u64[j], f64[i], i, 1, 1) |
2550 |
VSX_CVT_INT_TO_FP(xscvuxdsp, 1, uint64, float64, u64[j], f64[i], i, 1, 1) |
2551 |
VSX_CVT_INT_TO_FP(xvcvsxddp, 2, int64, float64, u64[j], f64[i], i, 0, 0) |
2552 |
VSX_CVT_INT_TO_FP(xvcvuxddp, 2, uint64, float64, u64[j], f64[i], i, 0, 0) |
2553 |
VSX_CVT_INT_TO_FP(xvcvsxwdp, 2, int32, float64, u32[j], f64[i], \
|
2554 |
2*i + JOFFSET, 0, 0) |
2555 |
VSX_CVT_INT_TO_FP(xvcvuxwdp, 2, uint64, float64, u32[j], f64[i], \
|
2556 |
2*i + JOFFSET, 0, 0) |
2557 |
VSX_CVT_INT_TO_FP(xvcvsxdsp, 2, int64, float32, u64[i], f32[j], \
|
2558 |
2*i + JOFFSET, 0, 0) |
2559 |
VSX_CVT_INT_TO_FP(xvcvuxdsp, 2, uint64, float32, u64[i], f32[j], \
|
2560 |
2*i + JOFFSET, 0, 0) |
2561 |
VSX_CVT_INT_TO_FP(xvcvsxwsp, 4, int32, float32, u32[j], f32[i], i, 0, 0) |
2562 |
VSX_CVT_INT_TO_FP(xvcvuxwsp, 4, uint32, float32, u32[j], f32[i], i, 0, 0) |
2563 |
|
2564 |
/* For "use current rounding mode", define a value that will not be one of
|
2565 |
* the existing rounding model enums.
|
2566 |
*/
|
2567 |
#define FLOAT_ROUND_CURRENT (float_round_nearest_even + float_round_down + \
|
2568 |
float_round_up + float_round_to_zero) |
2569 |
|
2570 |
/* VSX_ROUND - VSX floating point round
|
2571 |
* op - instruction mnemonic
|
2572 |
* nels - number of elements (1, 2 or 4)
|
2573 |
* tp - type (float32 or float64)
|
2574 |
* fld - vsr_t field (f32 or f64)
|
2575 |
* rmode - rounding mode
|
2576 |
* sfprf - set FPRF
|
2577 |
*/
|
2578 |
#define VSX_ROUND(op, nels, tp, fld, rmode, sfprf) \
|
2579 |
void helper_##op(CPUPPCState *env, uint32_t opcode) \ |
2580 |
{ \ |
2581 |
ppc_vsr_t xt, xb; \ |
2582 |
int i; \
|
2583 |
getVSR(xB(opcode), &xb, env); \ |
2584 |
getVSR(xT(opcode), &xt, env); \ |
2585 |
\ |
2586 |
if (rmode != FLOAT_ROUND_CURRENT) { \
|
2587 |
set_float_rounding_mode(rmode, &env->fp_status); \ |
2588 |
} \ |
2589 |
\ |
2590 |
for (i = 0; i < nels; i++) { \ |
2591 |
if (unlikely(tp##_is_signaling_nan(xb.fld[i]))) { \ |
2592 |
fload_invalid_op_excp(env, POWERPC_EXCP_FP_VXSNAN, 0); \
|
2593 |
xt.fld[i] = tp##_snan_to_qnan(xb.fld[i]); \ |
2594 |
} else { \
|
2595 |
xt.fld[i] = tp##_round_to_int(xb.fld[i], &env->fp_status); \ |
2596 |
} \ |
2597 |
if (sfprf) { \
|
2598 |
helper_compute_fprf(env, xt.fld[i], sfprf); \ |
2599 |
} \ |
2600 |
} \ |
2601 |
\ |
2602 |
/* If this is not a "use current rounding mode" instruction, \
|
2603 |
* then inhibit setting of the XX bit and restore rounding \
|
2604 |
* mode from FPSCR */ \
|
2605 |
if (rmode != FLOAT_ROUND_CURRENT) { \
|
2606 |
fpscr_set_rounding_mode(env); \ |
2607 |
env->fp_status.float_exception_flags &= ~float_flag_inexact; \ |
2608 |
} \ |
2609 |
\ |
2610 |
putVSR(xT(opcode), &xt, env); \ |
2611 |
helper_float_check_status(env); \ |
2612 |
} |
2613 |
|
2614 |
VSX_ROUND(xsrdpi, 1, float64, f64, float_round_nearest_even, 1) |
2615 |
VSX_ROUND(xsrdpic, 1, float64, f64, FLOAT_ROUND_CURRENT, 1) |
2616 |
VSX_ROUND(xsrdpim, 1, float64, f64, float_round_down, 1) |
2617 |
VSX_ROUND(xsrdpip, 1, float64, f64, float_round_up, 1) |
2618 |
VSX_ROUND(xsrdpiz, 1, float64, f64, float_round_to_zero, 1) |
2619 |
|
2620 |
VSX_ROUND(xvrdpi, 2, float64, f64, float_round_nearest_even, 0) |
2621 |
VSX_ROUND(xvrdpic, 2, float64, f64, FLOAT_ROUND_CURRENT, 0) |
2622 |
VSX_ROUND(xvrdpim, 2, float64, f64, float_round_down, 0) |
2623 |
VSX_ROUND(xvrdpip, 2, float64, f64, float_round_up, 0) |
2624 |
VSX_ROUND(xvrdpiz, 2, float64, f64, float_round_to_zero, 0) |
2625 |
|
2626 |
VSX_ROUND(xvrspi, 4, float32, f32, float_round_nearest_even, 0) |
2627 |
VSX_ROUND(xvrspic, 4, float32, f32, FLOAT_ROUND_CURRENT, 0) |
2628 |
VSX_ROUND(xvrspim, 4, float32, f32, float_round_down, 0) |
2629 |
VSX_ROUND(xvrspip, 4, float32, f32, float_round_up, 0) |
2630 |
VSX_ROUND(xvrspiz, 4, float32, f32, float_round_to_zero, 0) |
2631 |
|
2632 |
uint64_t helper_xsrsp(CPUPPCState *env, uint64_t xb) |
2633 |
{ |
2634 |
helper_reset_fpstatus(env); |
2635 |
|
2636 |
uint64_t xt = helper_frsp(env, xb); |
2637 |
|
2638 |
helper_compute_fprf(env, xt, 1);
|
2639 |
helper_float_check_status(env); |
2640 |
return xt;
|
2641 |
} |