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