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