Merge tag 'v9.0.0-rc3'
[qemu/ar7.git] / target / sparc / fop_helper.c
blob1205a599ef435881a86b3862c5623d93f4272aac
1 /*
2 * FPU op helpers
4 * Copyright (c) 2003-2005 Fabrice Bellard
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.1 of the License, or (at your option) any later version.
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.
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/>.
20 #include "qemu/osdep.h"
21 #include "cpu.h"
22 #include "exec/exec-all.h"
23 #include "exec/helper-proto.h"
24 #include "fpu/softfloat.h"
26 static inline float128 f128_in(Int128 i)
28 union {
29 Int128 i;
30 float128 f;
31 } u;
33 u.i = i;
34 return u.f;
37 static inline Int128 f128_ret(float128 f)
39 union {
40 Int128 i;
41 float128 f;
42 } u;
44 u.f = f;
45 return u.i;
48 static void check_ieee_exceptions(CPUSPARCState *env, uintptr_t ra)
50 target_ulong status = get_float_exception_flags(&env->fp_status);
51 uint32_t cexc = 0;
53 if (unlikely(status)) {
54 /* Keep exception flags clear for next time. */
55 set_float_exception_flags(0, &env->fp_status);
57 /* Copy IEEE 754 flags into FSR */
58 if (status & float_flag_invalid) {
59 cexc |= FSR_NVC;
61 if (status & float_flag_overflow) {
62 cexc |= FSR_OFC;
64 if (status & float_flag_underflow) {
65 cexc |= FSR_UFC;
67 if (status & float_flag_divbyzero) {
68 cexc |= FSR_DZC;
70 if (status & float_flag_inexact) {
71 cexc |= FSR_NXC;
74 if (cexc & (env->fsr >> FSR_TEM_SHIFT)) {
75 /* Unmasked exception, generate an IEEE trap. */
76 env->fsr_cexc_ftt = cexc | FSR_FTT_IEEE_EXCP;
77 cpu_raise_exception_ra(env, TT_FP_EXCP, ra);
80 /* Accumulate exceptions */
81 env->fsr |= cexc << FSR_AEXC_SHIFT;
84 /* No trap, so FTT is cleared. */
85 env->fsr_cexc_ftt = cexc;
88 float32 helper_fadds(CPUSPARCState *env, float32 src1, float32 src2)
90 float32 ret = float32_add(src1, src2, &env->fp_status);
91 check_ieee_exceptions(env, GETPC());
92 return ret;
95 float32 helper_fsubs(CPUSPARCState *env, float32 src1, float32 src2)
97 float32 ret = float32_sub(src1, src2, &env->fp_status);
98 check_ieee_exceptions(env, GETPC());
99 return ret;
102 float32 helper_fmuls(CPUSPARCState *env, float32 src1, float32 src2)
104 float32 ret = float32_mul(src1, src2, &env->fp_status);
105 check_ieee_exceptions(env, GETPC());
106 return ret;
109 float32 helper_fdivs(CPUSPARCState *env, float32 src1, float32 src2)
111 float32 ret = float32_div(src1, src2, &env->fp_status);
112 check_ieee_exceptions(env, GETPC());
113 return ret;
116 float64 helper_faddd(CPUSPARCState *env, float64 src1, float64 src2)
118 float64 ret = float64_add(src1, src2, &env->fp_status);
119 check_ieee_exceptions(env, GETPC());
120 return ret;
123 float64 helper_fsubd(CPUSPARCState *env, float64 src1, float64 src2)
125 float64 ret = float64_sub(src1, src2, &env->fp_status);
126 check_ieee_exceptions(env, GETPC());
127 return ret;
130 float64 helper_fmuld(CPUSPARCState *env, float64 src1, float64 src2)
132 float64 ret = float64_mul(src1, src2, &env->fp_status);
133 check_ieee_exceptions(env, GETPC());
134 return ret;
137 float64 helper_fdivd(CPUSPARCState *env, float64 src1, float64 src2)
139 float64 ret = float64_div(src1, src2, &env->fp_status);
140 check_ieee_exceptions(env, GETPC());
141 return ret;
144 Int128 helper_faddq(CPUSPARCState *env, Int128 src1, Int128 src2)
146 float128 ret = float128_add(f128_in(src1), f128_in(src2), &env->fp_status);
147 check_ieee_exceptions(env, GETPC());
148 return f128_ret(ret);
151 Int128 helper_fsubq(CPUSPARCState *env, Int128 src1, Int128 src2)
153 float128 ret = float128_sub(f128_in(src1), f128_in(src2), &env->fp_status);
154 check_ieee_exceptions(env, GETPC());
155 return f128_ret(ret);
158 Int128 helper_fmulq(CPUSPARCState *env, Int128 src1, Int128 src2)
160 float128 ret = float128_mul(f128_in(src1), f128_in(src2), &env->fp_status);
161 check_ieee_exceptions(env, GETPC());
162 return f128_ret(ret);
165 Int128 helper_fdivq(CPUSPARCState *env, Int128 src1, Int128 src2)
167 float128 ret = float128_div(f128_in(src1), f128_in(src2), &env->fp_status);
168 check_ieee_exceptions(env, GETPC());
169 return f128_ret(ret);
172 float64 helper_fsmuld(CPUSPARCState *env, float32 src1, float32 src2)
174 float64 ret = float64_mul(float32_to_float64(src1, &env->fp_status),
175 float32_to_float64(src2, &env->fp_status),
176 &env->fp_status);
177 check_ieee_exceptions(env, GETPC());
178 return ret;
181 Int128 helper_fdmulq(CPUSPARCState *env, float64 src1, float64 src2)
183 float128 ret = float128_mul(float64_to_float128(src1, &env->fp_status),
184 float64_to_float128(src2, &env->fp_status),
185 &env->fp_status);
186 check_ieee_exceptions(env, GETPC());
187 return f128_ret(ret);
190 /* Integer to float conversion. */
191 float32 helper_fitos(CPUSPARCState *env, int32_t src)
193 float32 ret = int32_to_float32(src, &env->fp_status);
194 check_ieee_exceptions(env, GETPC());
195 return ret;
198 float64 helper_fitod(CPUSPARCState *env, int32_t src)
200 float64 ret = int32_to_float64(src, &env->fp_status);
201 check_ieee_exceptions(env, GETPC());
202 return ret;
205 Int128 helper_fitoq(CPUSPARCState *env, int32_t src)
207 float128 ret = int32_to_float128(src, &env->fp_status);
208 check_ieee_exceptions(env, GETPC());
209 return f128_ret(ret);
212 #ifdef TARGET_SPARC64
213 float32 helper_fxtos(CPUSPARCState *env, int64_t src)
215 float32 ret = int64_to_float32(src, &env->fp_status);
216 check_ieee_exceptions(env, GETPC());
217 return ret;
220 float64 helper_fxtod(CPUSPARCState *env, int64_t src)
222 float64 ret = int64_to_float64(src, &env->fp_status);
223 check_ieee_exceptions(env, GETPC());
224 return ret;
227 Int128 helper_fxtoq(CPUSPARCState *env, int64_t src)
229 float128 ret = int64_to_float128(src, &env->fp_status);
230 check_ieee_exceptions(env, GETPC());
231 return f128_ret(ret);
233 #endif
235 /* floating point conversion */
236 float32 helper_fdtos(CPUSPARCState *env, float64 src)
238 float32 ret = float64_to_float32(src, &env->fp_status);
239 check_ieee_exceptions(env, GETPC());
240 return ret;
243 float64 helper_fstod(CPUSPARCState *env, float32 src)
245 float64 ret = float32_to_float64(src, &env->fp_status);
246 check_ieee_exceptions(env, GETPC());
247 return ret;
250 float32 helper_fqtos(CPUSPARCState *env, Int128 src)
252 float32 ret = float128_to_float32(f128_in(src), &env->fp_status);
253 check_ieee_exceptions(env, GETPC());
254 return ret;
257 Int128 helper_fstoq(CPUSPARCState *env, float32 src)
259 float128 ret = float32_to_float128(src, &env->fp_status);
260 check_ieee_exceptions(env, GETPC());
261 return f128_ret(ret);
264 float64 helper_fqtod(CPUSPARCState *env, Int128 src)
266 float64 ret = float128_to_float64(f128_in(src), &env->fp_status);
267 check_ieee_exceptions(env, GETPC());
268 return ret;
271 Int128 helper_fdtoq(CPUSPARCState *env, float64 src)
273 float128 ret = float64_to_float128(src, &env->fp_status);
274 check_ieee_exceptions(env, GETPC());
275 return f128_ret(ret);
278 /* Float to integer conversion. */
279 int32_t helper_fstoi(CPUSPARCState *env, float32 src)
281 int32_t ret = float32_to_int32_round_to_zero(src, &env->fp_status);
282 check_ieee_exceptions(env, GETPC());
283 return ret;
286 int32_t helper_fdtoi(CPUSPARCState *env, float64 src)
288 int32_t ret = float64_to_int32_round_to_zero(src, &env->fp_status);
289 check_ieee_exceptions(env, GETPC());
290 return ret;
293 int32_t helper_fqtoi(CPUSPARCState *env, Int128 src)
295 int32_t ret = float128_to_int32_round_to_zero(f128_in(src),
296 &env->fp_status);
297 check_ieee_exceptions(env, GETPC());
298 return ret;
301 #ifdef TARGET_SPARC64
302 int64_t helper_fstox(CPUSPARCState *env, float32 src)
304 int64_t ret = float32_to_int64_round_to_zero(src, &env->fp_status);
305 check_ieee_exceptions(env, GETPC());
306 return ret;
309 int64_t helper_fdtox(CPUSPARCState *env, float64 src)
311 int64_t ret = float64_to_int64_round_to_zero(src, &env->fp_status);
312 check_ieee_exceptions(env, GETPC());
313 return ret;
316 int64_t helper_fqtox(CPUSPARCState *env, Int128 src)
318 int64_t ret = float128_to_int64_round_to_zero(f128_in(src),
319 &env->fp_status);
320 check_ieee_exceptions(env, GETPC());
321 return ret;
323 #endif
325 float32 helper_fsqrts(CPUSPARCState *env, float32 src)
327 float32 ret = float32_sqrt(src, &env->fp_status);
328 check_ieee_exceptions(env, GETPC());
329 return ret;
332 float64 helper_fsqrtd(CPUSPARCState *env, float64 src)
334 float64 ret = float64_sqrt(src, &env->fp_status);
335 check_ieee_exceptions(env, GETPC());
336 return ret;
339 Int128 helper_fsqrtq(CPUSPARCState *env, Int128 src)
341 float128 ret = float128_sqrt(f128_in(src), &env->fp_status);
342 check_ieee_exceptions(env, GETPC());
343 return f128_ret(ret);
346 static uint32_t finish_fcmp(CPUSPARCState *env, FloatRelation r, uintptr_t ra)
348 check_ieee_exceptions(env, ra);
351 * FCC values:
352 * 0 =
353 * 1 <
354 * 2 >
355 * 3 unordered
357 switch (r) {
358 case float_relation_equal:
359 return 0;
360 case float_relation_less:
361 return 1;
362 case float_relation_greater:
363 return 2;
364 case float_relation_unordered:
365 env->fsr |= FSR_NVA;
366 return 3;
368 g_assert_not_reached();
371 uint32_t helper_fcmps(CPUSPARCState *env, float32 src1, float32 src2)
373 FloatRelation r = float32_compare_quiet(src1, src2, &env->fp_status);
374 return finish_fcmp(env, r, GETPC());
377 uint32_t helper_fcmpes(CPUSPARCState *env, float32 src1, float32 src2)
379 FloatRelation r = float32_compare(src1, src2, &env->fp_status);
380 return finish_fcmp(env, r, GETPC());
383 uint32_t helper_fcmpd(CPUSPARCState *env, float64 src1, float64 src2)
385 FloatRelation r = float64_compare_quiet(src1, src2, &env->fp_status);
386 return finish_fcmp(env, r, GETPC());
389 uint32_t helper_fcmped(CPUSPARCState *env, float64 src1, float64 src2)
391 FloatRelation r = float64_compare(src1, src2, &env->fp_status);
392 return finish_fcmp(env, r, GETPC());
395 uint32_t helper_fcmpq(CPUSPARCState *env, Int128 src1, Int128 src2)
397 FloatRelation r = float128_compare_quiet(f128_in(src1), f128_in(src2),
398 &env->fp_status);
399 return finish_fcmp(env, r, GETPC());
402 uint32_t helper_fcmpeq(CPUSPARCState *env, Int128 src1, Int128 src2)
404 FloatRelation r = float128_compare(f128_in(src1), f128_in(src2),
405 &env->fp_status);
406 return finish_fcmp(env, r, GETPC());
409 target_ulong cpu_get_fsr(CPUSPARCState *env)
411 target_ulong fsr = env->fsr | env->fsr_cexc_ftt;
413 fsr |= env->fcc[0] << FSR_FCC0_SHIFT;
414 #ifdef TARGET_SPARC64
415 fsr |= (uint64_t)env->fcc[1] << FSR_FCC1_SHIFT;
416 fsr |= (uint64_t)env->fcc[2] << FSR_FCC2_SHIFT;
417 fsr |= (uint64_t)env->fcc[3] << FSR_FCC3_SHIFT;
418 #endif
420 /* VER is kept completely separate until re-assembly. */
421 fsr |= env->def.fpu_version;
423 return fsr;
426 target_ulong helper_get_fsr(CPUSPARCState *env)
428 return cpu_get_fsr(env);
431 static void set_fsr_nonsplit(CPUSPARCState *env, target_ulong fsr)
433 int rnd_mode;
435 env->fsr = fsr & (FSR_RD_MASK | FSR_TEM_MASK | FSR_AEXC_MASK);
437 switch (fsr & FSR_RD_MASK) {
438 case FSR_RD_NEAREST:
439 rnd_mode = float_round_nearest_even;
440 break;
441 default:
442 case FSR_RD_ZERO:
443 rnd_mode = float_round_to_zero;
444 break;
445 case FSR_RD_POS:
446 rnd_mode = float_round_up;
447 break;
448 case FSR_RD_NEG:
449 rnd_mode = float_round_down;
450 break;
452 set_float_rounding_mode(rnd_mode, &env->fp_status);
455 void cpu_put_fsr(CPUSPARCState *env, target_ulong fsr)
457 env->fsr_cexc_ftt = fsr & (FSR_CEXC_MASK | FSR_FTT_MASK);
459 env->fcc[0] = extract32(fsr, FSR_FCC0_SHIFT, 2);
460 #ifdef TARGET_SPARC64
461 env->fcc[1] = extract64(fsr, FSR_FCC1_SHIFT, 2);
462 env->fcc[2] = extract64(fsr, FSR_FCC2_SHIFT, 2);
463 env->fcc[3] = extract64(fsr, FSR_FCC3_SHIFT, 2);
464 #endif
466 set_fsr_nonsplit(env, fsr);
469 void helper_set_fsr_nofcc_noftt(CPUSPARCState *env, uint32_t fsr)
471 env->fsr_cexc_ftt &= FSR_FTT_MASK;
472 env->fsr_cexc_ftt |= fsr & FSR_CEXC_MASK;
473 set_fsr_nonsplit(env, fsr);