]> git.proxmox.com Git - mirror_qemu.git/blame - target/alpha/fpu_helper.c
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20190927' into...
[mirror_qemu.git] / target / alpha / fpu_helper.c
CommitLineData
4a58aedf
RH
1/*
2 * Helpers for floating point instructions.
3 *
4 * Copyright (c) 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
e2e5e114 20#include "qemu/osdep.h"
4a58aedf 21#include "cpu.h"
63c91552 22#include "exec/exec-all.h"
2ef6175a 23#include "exec/helper-proto.h"
6b4c305c 24#include "fpu/softfloat.h"
4a58aedf
RH
25
26#define FP_STATUS (env->fp_status)
27
28
29void helper_setroundmode(CPUAlphaState *env, uint32_t val)
30{
31 set_float_rounding_mode(val, &FP_STATUS);
32}
33
34void helper_setflushzero(CPUAlphaState *env, uint32_t val)
35{
36 set_flush_to_zero(val, &FP_STATUS);
37}
38
f3d3aad4
RH
39#define CONVERT_BIT(X, SRC, DST) \
40 (SRC > DST ? (X) / (SRC / DST) & (DST) : ((X) & SRC) * (DST / SRC))
4a58aedf 41
f3d3aad4 42static uint32_t soft_to_fpcr_exc(CPUAlphaState *env)
4a58aedf 43{
f3d3aad4
RH
44 uint8_t exc = get_float_exception_flags(&FP_STATUS);
45 uint32_t ret = 0;
46
47 if (unlikely(exc)) {
48 set_float_exception_flags(0, &FP_STATUS);
49 ret |= CONVERT_BIT(exc, float_flag_invalid, FPCR_INV);
50 ret |= CONVERT_BIT(exc, float_flag_divbyzero, FPCR_DZE);
51 ret |= CONVERT_BIT(exc, float_flag_overflow, FPCR_OVF);
52 ret |= CONVERT_BIT(exc, float_flag_underflow, FPCR_UNF);
53 ret |= CONVERT_BIT(exc, float_flag_inexact, FPCR_INE);
54 }
55
56 return ret;
4a58aedf
RH
57}
58
f3d3aad4 59static void fp_exc_raise1(CPUAlphaState *env, uintptr_t retaddr,
f6b6b7b8 60 uint32_t exc, uint32_t regno, uint32_t hw_exc)
4a58aedf 61{
471d4930
RH
62 hw_exc |= CONVERT_BIT(exc, FPCR_INV, EXC_M_INV);
63 hw_exc |= CONVERT_BIT(exc, FPCR_DZE, EXC_M_DZE);
64 hw_exc |= CONVERT_BIT(exc, FPCR_OVF, EXC_M_FOV);
65 hw_exc |= CONVERT_BIT(exc, FPCR_UNF, EXC_M_UNF);
66 hw_exc |= CONVERT_BIT(exc, FPCR_INE, EXC_M_INE);
67 hw_exc |= CONVERT_BIT(exc, FPCR_IOV, EXC_M_IOV);
4a58aedf 68
471d4930 69 arith_excp(env, retaddr, hw_exc, 1ull << regno);
4a58aedf
RH
70}
71
72/* Raise exceptions for ieee fp insns without software completion.
73 In that case there are no exceptions that don't trap; the mask
74 doesn't apply. */
f3d3aad4 75void helper_fp_exc_raise(CPUAlphaState *env, uint32_t ignore, uint32_t regno)
4a58aedf 76{
471d4930
RH
77 uint32_t exc = env->error_code;
78 if (exc) {
79 env->fpcr |= exc;
80 exc &= ~ignore;
81 if (exc) {
f6b6b7b8 82 fp_exc_raise1(env, GETPC(), exc, regno, 0);
471d4930
RH
83 }
84 }
4a58aedf
RH
85}
86
87/* Raise exceptions for ieee fp insns with software completion. */
f3d3aad4 88void helper_fp_exc_raise_s(CPUAlphaState *env, uint32_t ignore, uint32_t regno)
4a58aedf 89{
f3d3aad4 90 uint32_t exc = env->error_code & ~ignore;
4a58aedf 91 if (exc) {
f3d3aad4 92 env->fpcr |= exc;
11bfdbdf 93 exc &= env->fpcr_exc_enable;
21ba8564
RH
94 /*
95 * In system mode, the software handler gets invoked
96 * for any non-ignored exception.
11bfdbdf
RH
97 * In user mode, the kernel's software handler only
98 * delivers a signal if the exception is enabled.
21ba8564 99 */
11bfdbdf 100#ifdef CONFIG_USER_ONLY
21ba8564
RH
101 if (!exc) {
102 return;
471d4930 103 }
21ba8564 104#endif
21ba8564 105 fp_exc_raise1(env, GETPC(), exc, regno, EXC_M_SWC);
4a58aedf
RH
106 }
107}
108
74343409
RH
109/* Input handing without software completion. Trap for all
110 non-finite numbers. */
111void helper_ieee_input(CPUAlphaState *env, uint64_t val)
4a58aedf
RH
112{
113 uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
114 uint64_t frac = val & 0xfffffffffffffull;
115
116 if (exp == 0) {
b99e8069
RH
117 /* Denormals without /S raise an exception. */
118 if (frac != 0) {
119 arith_excp(env, GETPC(), EXC_M_INV, 0);
4a58aedf
RH
120 }
121 } else if (exp == 0x7ff) {
122 /* Infinity or NaN. */
b99e8069
RH
123 env->fpcr |= FPCR_INV;
124 arith_excp(env, GETPC(), EXC_M_INV, 0);
4a58aedf 125 }
4a58aedf
RH
126}
127
128/* Similar, but does not trap for infinities. Used for comparisons. */
74343409 129void helper_ieee_input_cmp(CPUAlphaState *env, uint64_t val)
4a58aedf
RH
130{
131 uint32_t exp = (uint32_t)(val >> 52) & 0x7ff;
132 uint64_t frac = val & 0xfffffffffffffull;
133
134 if (exp == 0) {
b99e8069
RH
135 /* Denormals without /S raise an exception. */
136 if (frac != 0) {
137 arith_excp(env, GETPC(), EXC_M_INV, 0);
4a58aedf
RH
138 }
139 } else if (exp == 0x7ff && frac) {
140 /* NaN. */
b99e8069 141 env->fpcr |= FPCR_INV;
4a58aedf
RH
142 arith_excp(env, GETPC(), EXC_M_INV, 0);
143 }
4a58aedf
RH
144}
145
b99e8069
RH
146/* Input handing with software completion. Trap for denorms, unless DNZ
147 is set. If we try to support DNOD (which none of the produced hardware
148 did, AFAICS), we'll need to suppress the trap when FPCR.DNOD is set;
149 then the code downstream of that will need to cope with denorms sans
150 flush_input_to_zero. Most of it should work sanely, but there's
151 nothing to compare with. */
152void helper_ieee_input_s(CPUAlphaState *env, uint64_t val)
153{
154 if (unlikely(2 * val - 1 < 0x1fffffffffffffull)
155 && !env->fp_status.flush_inputs_to_zero) {
156 arith_excp(env, GETPC(), EXC_M_INV | EXC_M_SWC, 0);
157 }
158}
4a58aedf
RH
159
160/* S floating (single) */
161
162/* Taken from linux/arch/alpha/kernel/traps.c, s_mem_to_reg. */
163static inline uint64_t float32_to_s_int(uint32_t fi)
164{
165 uint32_t frac = fi & 0x7fffff;
166 uint32_t sign = fi >> 31;
167 uint32_t exp_msb = (fi >> 30) & 1;
168 uint32_t exp_low = (fi >> 23) & 0x7f;
169 uint32_t exp;
170
171 exp = (exp_msb << 10) | exp_low;
172 if (exp_msb) {
173 if (exp_low == 0x7f) {
174 exp = 0x7ff;
175 }
176 } else {
177 if (exp_low != 0x00) {
178 exp |= 0x380;
179 }
180 }
181
182 return (((uint64_t)sign << 63)
183 | ((uint64_t)exp << 52)
184 | ((uint64_t)frac << 29));
185}
186
187static inline uint64_t float32_to_s(float32 fa)
188{
189 CPU_FloatU a;
190 a.f = fa;
191 return float32_to_s_int(a.l);
192}
193
194static inline uint32_t s_to_float32_int(uint64_t a)
195{
196 return ((a >> 32) & 0xc0000000) | ((a >> 29) & 0x3fffffff);
197}
198
199static inline float32 s_to_float32(uint64_t a)
200{
201 CPU_FloatU r;
202 r.l = s_to_float32_int(a);
203 return r.f;
204}
205
206uint32_t helper_s_to_memory(uint64_t a)
207{
208 return s_to_float32_int(a);
209}
210
211uint64_t helper_memory_to_s(uint32_t a)
212{
213 return float32_to_s_int(a);
214}
215
216uint64_t helper_adds(CPUAlphaState *env, uint64_t a, uint64_t b)
217{
218 float32 fa, fb, fr;
219
220 fa = s_to_float32(a);
221 fb = s_to_float32(b);
222 fr = float32_add(fa, fb, &FP_STATUS);
f3d3aad4
RH
223 env->error_code = soft_to_fpcr_exc(env);
224
4a58aedf
RH
225 return float32_to_s(fr);
226}
227
228uint64_t helper_subs(CPUAlphaState *env, uint64_t a, uint64_t b)
229{
230 float32 fa, fb, fr;
231
232 fa = s_to_float32(a);
233 fb = s_to_float32(b);
234 fr = float32_sub(fa, fb, &FP_STATUS);
f3d3aad4
RH
235 env->error_code = soft_to_fpcr_exc(env);
236
4a58aedf
RH
237 return float32_to_s(fr);
238}
239
240uint64_t helper_muls(CPUAlphaState *env, uint64_t a, uint64_t b)
241{
242 float32 fa, fb, fr;
243
244 fa = s_to_float32(a);
245 fb = s_to_float32(b);
246 fr = float32_mul(fa, fb, &FP_STATUS);
f3d3aad4
RH
247 env->error_code = soft_to_fpcr_exc(env);
248
4a58aedf
RH
249 return float32_to_s(fr);
250}
251
252uint64_t helper_divs(CPUAlphaState *env, uint64_t a, uint64_t b)
253{
254 float32 fa, fb, fr;
255
256 fa = s_to_float32(a);
257 fb = s_to_float32(b);
258 fr = float32_div(fa, fb, &FP_STATUS);
f3d3aad4
RH
259 env->error_code = soft_to_fpcr_exc(env);
260
4a58aedf
RH
261 return float32_to_s(fr);
262}
263
264uint64_t helper_sqrts(CPUAlphaState *env, uint64_t a)
265{
266 float32 fa, fr;
267
268 fa = s_to_float32(a);
269 fr = float32_sqrt(fa, &FP_STATUS);
f3d3aad4
RH
270 env->error_code = soft_to_fpcr_exc(env);
271
4a58aedf
RH
272 return float32_to_s(fr);
273}
274
275
276/* T floating (double) */
277static inline float64 t_to_float64(uint64_t a)
278{
279 /* Memory format is the same as float64 */
280 CPU_DoubleU r;
281 r.ll = a;
282 return r.d;
283}
284
285static inline uint64_t float64_to_t(float64 fa)
286{
287 /* Memory format is the same as float64 */
288 CPU_DoubleU r;
289 r.d = fa;
290 return r.ll;
291}
292
293uint64_t helper_addt(CPUAlphaState *env, uint64_t a, uint64_t b)
294{
295 float64 fa, fb, fr;
296
297 fa = t_to_float64(a);
298 fb = t_to_float64(b);
299 fr = float64_add(fa, fb, &FP_STATUS);
f3d3aad4
RH
300 env->error_code = soft_to_fpcr_exc(env);
301
4a58aedf
RH
302 return float64_to_t(fr);
303}
304
305uint64_t helper_subt(CPUAlphaState *env, uint64_t a, uint64_t b)
306{
307 float64 fa, fb, fr;
308
309 fa = t_to_float64(a);
310 fb = t_to_float64(b);
311 fr = float64_sub(fa, fb, &FP_STATUS);
f3d3aad4
RH
312 env->error_code = soft_to_fpcr_exc(env);
313
4a58aedf
RH
314 return float64_to_t(fr);
315}
316
317uint64_t helper_mult(CPUAlphaState *env, uint64_t a, uint64_t b)
318{
319 float64 fa, fb, fr;
320
321 fa = t_to_float64(a);
322 fb = t_to_float64(b);
323 fr = float64_mul(fa, fb, &FP_STATUS);
f3d3aad4
RH
324 env->error_code = soft_to_fpcr_exc(env);
325
4a58aedf
RH
326 return float64_to_t(fr);
327}
328
329uint64_t helper_divt(CPUAlphaState *env, uint64_t a, uint64_t b)
330{
331 float64 fa, fb, fr;
332
333 fa = t_to_float64(a);
334 fb = t_to_float64(b);
335 fr = float64_div(fa, fb, &FP_STATUS);
f3d3aad4
RH
336 env->error_code = soft_to_fpcr_exc(env);
337
4a58aedf
RH
338 return float64_to_t(fr);
339}
340
341uint64_t helper_sqrtt(CPUAlphaState *env, uint64_t a)
342{
343 float64 fa, fr;
344
345 fa = t_to_float64(a);
346 fr = float64_sqrt(fa, &FP_STATUS);
f3d3aad4
RH
347 env->error_code = soft_to_fpcr_exc(env);
348
4a58aedf
RH
349 return float64_to_t(fr);
350}
351
352/* Comparisons */
353uint64_t helper_cmptun(CPUAlphaState *env, uint64_t a, uint64_t b)
354{
355 float64 fa, fb;
f3d3aad4 356 uint64_t ret = 0;
4a58aedf
RH
357
358 fa = t_to_float64(a);
359 fb = t_to_float64(b);
360
361 if (float64_unordered_quiet(fa, fb, &FP_STATUS)) {
f3d3aad4 362 ret = 0x4000000000000000ULL;
4a58aedf 363 }
f3d3aad4
RH
364 env->error_code = soft_to_fpcr_exc(env);
365
366 return ret;
4a58aedf
RH
367}
368
369uint64_t helper_cmpteq(CPUAlphaState *env, uint64_t a, uint64_t b)
370{
371 float64 fa, fb;
f3d3aad4 372 uint64_t ret = 0;
4a58aedf
RH
373
374 fa = t_to_float64(a);
375 fb = t_to_float64(b);
376
377 if (float64_eq_quiet(fa, fb, &FP_STATUS)) {
f3d3aad4 378 ret = 0x4000000000000000ULL;
4a58aedf 379 }
f3d3aad4
RH
380 env->error_code = soft_to_fpcr_exc(env);
381
382 return ret;
4a58aedf
RH
383}
384
385uint64_t helper_cmptle(CPUAlphaState *env, uint64_t a, uint64_t b)
386{
387 float64 fa, fb;
f3d3aad4 388 uint64_t ret = 0;
4a58aedf
RH
389
390 fa = t_to_float64(a);
391 fb = t_to_float64(b);
392
393 if (float64_le(fa, fb, &FP_STATUS)) {
f3d3aad4 394 ret = 0x4000000000000000ULL;
4a58aedf 395 }
f3d3aad4
RH
396 env->error_code = soft_to_fpcr_exc(env);
397
398 return ret;
4a58aedf
RH
399}
400
401uint64_t helper_cmptlt(CPUAlphaState *env, uint64_t a, uint64_t b)
402{
403 float64 fa, fb;
f3d3aad4 404 uint64_t ret = 0;
4a58aedf
RH
405
406 fa = t_to_float64(a);
407 fb = t_to_float64(b);
408
409 if (float64_lt(fa, fb, &FP_STATUS)) {
f3d3aad4 410 ret = 0x4000000000000000ULL;
4a58aedf 411 }
f3d3aad4
RH
412 env->error_code = soft_to_fpcr_exc(env);
413
414 return ret;
4a58aedf
RH
415}
416
4a58aedf
RH
417/* Floating point format conversion */
418uint64_t helper_cvtts(CPUAlphaState *env, uint64_t a)
419{
420 float64 fa;
421 float32 fr;
422
423 fa = t_to_float64(a);
424 fr = float64_to_float32(fa, &FP_STATUS);
f3d3aad4
RH
425 env->error_code = soft_to_fpcr_exc(env);
426
4a58aedf
RH
427 return float32_to_s(fr);
428}
429
430uint64_t helper_cvtst(CPUAlphaState *env, uint64_t a)
431{
432 float32 fa;
433 float64 fr;
434
435 fa = s_to_float32(a);
436 fr = float32_to_float64(fa, &FP_STATUS);
f3d3aad4
RH
437 env->error_code = soft_to_fpcr_exc(env);
438
4a58aedf
RH
439 return float64_to_t(fr);
440}
441
442uint64_t helper_cvtqs(CPUAlphaState *env, uint64_t a)
443{
444 float32 fr = int64_to_float32(a, &FP_STATUS);
f3d3aad4
RH
445 env->error_code = soft_to_fpcr_exc(env);
446
4a58aedf
RH
447 return float32_to_s(fr);
448}
449
182f42fd 450/* Implement float64 to uint64_t conversion without saturation -- we must
4a58aedf 451 supply the truncated result. This behaviour is used by the compiler
c24a8a0b 452 to get unsigned conversion for free with the same instruction. */
4a58aedf 453
c24a8a0b 454static uint64_t do_cvttq(CPUAlphaState *env, uint64_t a, int roundmode)
4a58aedf
RH
455{
456 uint64_t frac, ret = 0;
457 uint32_t exp, sign, exc = 0;
458 int shift;
459
460 sign = (a >> 63);
461 exp = (uint32_t)(a >> 52) & 0x7ff;
462 frac = a & 0xfffffffffffffull;
463
464 if (exp == 0) {
4ed069ab 465 if (unlikely(frac != 0) && !env->fp_status.flush_inputs_to_zero) {
4a58aedf
RH
466 goto do_underflow;
467 }
468 } else if (exp == 0x7ff) {
7b4dde83 469 exc = FPCR_INV;
4a58aedf
RH
470 } else {
471 /* Restore implicit bit. */
472 frac |= 0x10000000000000ull;
473
474 shift = exp - 1023 - 52;
475 if (shift >= 0) {
476 /* In this case the number is so large that we must shift
477 the fraction left. There is no rounding to do. */
7f2e4002 478 if (shift < 64) {
4a58aedf 479 ret = frac << shift;
7f2e4002
RH
480 }
481 /* Check for overflow. Note the special case of -0x1p63. */
482 if (shift >= 11 && a != 0xC3E0000000000000ull) {
483 exc = FPCR_IOV | FPCR_INE;
4a58aedf
RH
484 }
485 } else {
486 uint64_t round;
487
488 /* In this case the number is smaller than the fraction as
489 represented by the 52 bit number. Here we must think
490 about rounding the result. Handle this by shifting the
491 fractional part of the number into the high bits of ROUND.
492 This will let us efficiently handle round-to-nearest. */
493 shift = -shift;
494 if (shift < 63) {
495 ret = frac >> shift;
496 round = frac << (64 - shift);
497 } else {
498 /* The exponent is so small we shift out everything.
499 Leave a sticky bit for proper rounding below. */
500 do_underflow:
501 round = 1;
502 }
503
504 if (round) {
c24a8a0b 505 exc = FPCR_INE;
4a58aedf
RH
506 switch (roundmode) {
507 case float_round_nearest_even:
508 if (round == (1ull << 63)) {
509 /* Fraction is exactly 0.5; round to even. */
510 ret += (ret & 1);
511 } else if (round > (1ull << 63)) {
512 ret += 1;
513 }
514 break;
515 case float_round_to_zero:
516 break;
517 case float_round_up:
518 ret += 1 - sign;
519 break;
520 case float_round_down:
521 ret += sign;
522 break;
523 }
524 }
525 }
526 if (sign) {
527 ret = -ret;
528 }
529 }
f3d3aad4 530 env->error_code = exc;
4a58aedf
RH
531
532 return ret;
533}
534
535uint64_t helper_cvttq(CPUAlphaState *env, uint64_t a)
536{
c24a8a0b 537 return do_cvttq(env, a, FP_STATUS.float_rounding_mode);
4a58aedf
RH
538}
539
540uint64_t helper_cvttq_c(CPUAlphaState *env, uint64_t a)
541{
c24a8a0b 542 return do_cvttq(env, a, float_round_to_zero);
4a58aedf
RH
543}
544
545uint64_t helper_cvtqt(CPUAlphaState *env, uint64_t a)
546{
547 float64 fr = int64_to_float64(a, &FP_STATUS);
f3d3aad4 548 env->error_code = soft_to_fpcr_exc(env);
4a58aedf
RH
549 return float64_to_t(fr);
550}
551
57a808b6 552uint64_t helper_cvtql(CPUAlphaState *env, uint64_t val)
e8d8fef4 553{
57a808b6 554 uint32_t exc = 0;
e8d8fef4 555 if (val != (int32_t)val) {
57a808b6 556 exc = FPCR_IOV | FPCR_INE;
e8d8fef4 557 }
57a808b6
RH
558 env->error_code = exc;
559
560 return ((val & 0xc0000000) << 32) | ((val & 0x3fffffff) << 29);
e8d8fef4 561}