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