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