]> git.ipfire.org Git - thirdparty/qemu.git/blob - target/sparc/fop_helper.c
target/sparc: Split cexc and ftt from env->fsr
[thirdparty/qemu.git] / target / sparc / fop_helper.c
1 /*
2 * FPU op helpers
3 *
4 * Copyright (c) 2003-2005 Fabrice Bellard
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.1 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/exec-all.h"
23 #include "exec/helper-proto.h"
24 #include "fpu/softfloat.h"
25
26 static inline float128 f128_in(Int128 i)
27 {
28 union {
29 Int128 i;
30 float128 f;
31 } u;
32
33 u.i = i;
34 return u.f;
35 }
36
37 static inline Int128 f128_ret(float128 f)
38 {
39 union {
40 Int128 i;
41 float128 f;
42 } u;
43
44 u.f = f;
45 return u.i;
46 }
47
48 static void check_ieee_exceptions(CPUSPARCState *env, uintptr_t ra)
49 {
50 target_ulong status = get_float_exception_flags(&env->fp_status);
51 uint32_t cexc = 0;
52
53 if (unlikely(status)) {
54 /* Keep exception flags clear for next time. */
55 set_float_exception_flags(0, &env->fp_status);
56
57 /* Copy IEEE 754 flags into FSR */
58 if (status & float_flag_invalid) {
59 cexc |= FSR_NVC;
60 }
61 if (status & float_flag_overflow) {
62 cexc |= FSR_OFC;
63 }
64 if (status & float_flag_underflow) {
65 cexc |= FSR_UFC;
66 }
67 if (status & float_flag_divbyzero) {
68 cexc |= FSR_DZC;
69 }
70 if (status & float_flag_inexact) {
71 cexc |= FSR_NXC;
72 }
73
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);
78 }
79
80 /* Accumulate exceptions */
81 env->fsr |= cexc << FSR_AEXC_SHIFT;
82 }
83
84 /* No trap, so FTT is cleared. */
85 env->fsr_cexc_ftt = cexc;
86 }
87
88 float32 helper_fadds(CPUSPARCState *env, float32 src1, float32 src2)
89 {
90 float32 ret = float32_add(src1, src2, &env->fp_status);
91 check_ieee_exceptions(env, GETPC());
92 return ret;
93 }
94
95 float32 helper_fsubs(CPUSPARCState *env, float32 src1, float32 src2)
96 {
97 float32 ret = float32_sub(src1, src2, &env->fp_status);
98 check_ieee_exceptions(env, GETPC());
99 return ret;
100 }
101
102 float32 helper_fmuls(CPUSPARCState *env, float32 src1, float32 src2)
103 {
104 float32 ret = float32_mul(src1, src2, &env->fp_status);
105 check_ieee_exceptions(env, GETPC());
106 return ret;
107 }
108
109 float32 helper_fdivs(CPUSPARCState *env, float32 src1, float32 src2)
110 {
111 float32 ret = float32_div(src1, src2, &env->fp_status);
112 check_ieee_exceptions(env, GETPC());
113 return ret;
114 }
115
116 float64 helper_faddd(CPUSPARCState *env, float64 src1, float64 src2)
117 {
118 float64 ret = float64_add(src1, src2, &env->fp_status);
119 check_ieee_exceptions(env, GETPC());
120 return ret;
121 }
122
123 float64 helper_fsubd(CPUSPARCState *env, float64 src1, float64 src2)
124 {
125 float64 ret = float64_sub(src1, src2, &env->fp_status);
126 check_ieee_exceptions(env, GETPC());
127 return ret;
128 }
129
130 float64 helper_fmuld(CPUSPARCState *env, float64 src1, float64 src2)
131 {
132 float64 ret = float64_mul(src1, src2, &env->fp_status);
133 check_ieee_exceptions(env, GETPC());
134 return ret;
135 }
136
137 float64 helper_fdivd(CPUSPARCState *env, float64 src1, float64 src2)
138 {
139 float64 ret = float64_div(src1, src2, &env->fp_status);
140 check_ieee_exceptions(env, GETPC());
141 return ret;
142 }
143
144 Int128 helper_faddq(CPUSPARCState *env, Int128 src1, Int128 src2)
145 {
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);
149 }
150
151 Int128 helper_fsubq(CPUSPARCState *env, Int128 src1, Int128 src2)
152 {
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);
156 }
157
158 Int128 helper_fmulq(CPUSPARCState *env, Int128 src1, Int128 src2)
159 {
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);
163 }
164
165 Int128 helper_fdivq(CPUSPARCState *env, Int128 src1, Int128 src2)
166 {
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);
170 }
171
172 float64 helper_fsmuld(CPUSPARCState *env, float32 src1, float32 src2)
173 {
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;
179 }
180
181 Int128 helper_fdmulq(CPUSPARCState *env, float64 src1, float64 src2)
182 {
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);
188 }
189
190 /* Integer to float conversion. */
191 float32 helper_fitos(CPUSPARCState *env, int32_t src)
192 {
193 float32 ret = int32_to_float32(src, &env->fp_status);
194 check_ieee_exceptions(env, GETPC());
195 return ret;
196 }
197
198 float64 helper_fitod(CPUSPARCState *env, int32_t src)
199 {
200 float64 ret = int32_to_float64(src, &env->fp_status);
201 check_ieee_exceptions(env, GETPC());
202 return ret;
203 }
204
205 Int128 helper_fitoq(CPUSPARCState *env, int32_t src)
206 {
207 float128 ret = int32_to_float128(src, &env->fp_status);
208 check_ieee_exceptions(env, GETPC());
209 return f128_ret(ret);
210 }
211
212 #ifdef TARGET_SPARC64
213 float32 helper_fxtos(CPUSPARCState *env, int64_t src)
214 {
215 float32 ret = int64_to_float32(src, &env->fp_status);
216 check_ieee_exceptions(env, GETPC());
217 return ret;
218 }
219
220 float64 helper_fxtod(CPUSPARCState *env, int64_t src)
221 {
222 float64 ret = int64_to_float64(src, &env->fp_status);
223 check_ieee_exceptions(env, GETPC());
224 return ret;
225 }
226
227 Int128 helper_fxtoq(CPUSPARCState *env, int64_t src)
228 {
229 float128 ret = int64_to_float128(src, &env->fp_status);
230 check_ieee_exceptions(env, GETPC());
231 return f128_ret(ret);
232 }
233 #endif
234
235 /* floating point conversion */
236 float32 helper_fdtos(CPUSPARCState *env, float64 src)
237 {
238 float32 ret = float64_to_float32(src, &env->fp_status);
239 check_ieee_exceptions(env, GETPC());
240 return ret;
241 }
242
243 float64 helper_fstod(CPUSPARCState *env, float32 src)
244 {
245 float64 ret = float32_to_float64(src, &env->fp_status);
246 check_ieee_exceptions(env, GETPC());
247 return ret;
248 }
249
250 float32 helper_fqtos(CPUSPARCState *env, Int128 src)
251 {
252 float32 ret = float128_to_float32(f128_in(src), &env->fp_status);
253 check_ieee_exceptions(env, GETPC());
254 return ret;
255 }
256
257 Int128 helper_fstoq(CPUSPARCState *env, float32 src)
258 {
259 float128 ret = float32_to_float128(src, &env->fp_status);
260 check_ieee_exceptions(env, GETPC());
261 return f128_ret(ret);
262 }
263
264 float64 helper_fqtod(CPUSPARCState *env, Int128 src)
265 {
266 float64 ret = float128_to_float64(f128_in(src), &env->fp_status);
267 check_ieee_exceptions(env, GETPC());
268 return ret;
269 }
270
271 Int128 helper_fdtoq(CPUSPARCState *env, float64 src)
272 {
273 float128 ret = float64_to_float128(src, &env->fp_status);
274 check_ieee_exceptions(env, GETPC());
275 return f128_ret(ret);
276 }
277
278 /* Float to integer conversion. */
279 int32_t helper_fstoi(CPUSPARCState *env, float32 src)
280 {
281 int32_t ret = float32_to_int32_round_to_zero(src, &env->fp_status);
282 check_ieee_exceptions(env, GETPC());
283 return ret;
284 }
285
286 int32_t helper_fdtoi(CPUSPARCState *env, float64 src)
287 {
288 int32_t ret = float64_to_int32_round_to_zero(src, &env->fp_status);
289 check_ieee_exceptions(env, GETPC());
290 return ret;
291 }
292
293 int32_t helper_fqtoi(CPUSPARCState *env, Int128 src)
294 {
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;
299 }
300
301 #ifdef TARGET_SPARC64
302 int64_t helper_fstox(CPUSPARCState *env, float32 src)
303 {
304 int64_t ret = float32_to_int64_round_to_zero(src, &env->fp_status);
305 check_ieee_exceptions(env, GETPC());
306 return ret;
307 }
308
309 int64_t helper_fdtox(CPUSPARCState *env, float64 src)
310 {
311 int64_t ret = float64_to_int64_round_to_zero(src, &env->fp_status);
312 check_ieee_exceptions(env, GETPC());
313 return ret;
314 }
315
316 int64_t helper_fqtox(CPUSPARCState *env, Int128 src)
317 {
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;
322 }
323 #endif
324
325 float32 helper_fsqrts(CPUSPARCState *env, float32 src)
326 {
327 float32 ret = float32_sqrt(src, &env->fp_status);
328 check_ieee_exceptions(env, GETPC());
329 return ret;
330 }
331
332 float64 helper_fsqrtd(CPUSPARCState *env, float64 src)
333 {
334 float64 ret = float64_sqrt(src, &env->fp_status);
335 check_ieee_exceptions(env, GETPC());
336 return ret;
337 }
338
339 Int128 helper_fsqrtq(CPUSPARCState *env, Int128 src)
340 {
341 float128 ret = float128_sqrt(f128_in(src), &env->fp_status);
342 check_ieee_exceptions(env, GETPC());
343 return f128_ret(ret);
344 }
345
346 #define GEN_FCMP(name, size, FS, E) \
347 target_ulong glue(helper_, name) (CPUSPARCState *env, \
348 Int128 src1, Int128 src2) \
349 { \
350 float128 reg1 = f128_in(src1); \
351 float128 reg2 = f128_in(src2); \
352 FloatRelation ret; \
353 target_ulong fsr; \
354 if (E) { \
355 ret = glue(size, _compare)(reg1, reg2, &env->fp_status); \
356 } else { \
357 ret = glue(size, _compare_quiet)(reg1, reg2, \
358 &env->fp_status); \
359 } \
360 check_ieee_exceptions(env, GETPC()); \
361 fsr = env->fsr; \
362 switch (ret) { \
363 case float_relation_unordered: \
364 fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \
365 fsr |= FSR_NVA; \
366 break; \
367 case float_relation_less: \
368 fsr &= ~(FSR_FCC1) << FS; \
369 fsr |= FSR_FCC0 << FS; \
370 break; \
371 case float_relation_greater: \
372 fsr &= ~(FSR_FCC0) << FS; \
373 fsr |= FSR_FCC1 << FS; \
374 break; \
375 default: \
376 fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
377 break; \
378 } \
379 return fsr; \
380 }
381 #define GEN_FCMP_T(name, size, FS, E) \
382 target_ulong glue(helper_, name)(CPUSPARCState *env, size src1, size src2)\
383 { \
384 FloatRelation ret; \
385 target_ulong fsr; \
386 if (E) { \
387 ret = glue(size, _compare)(src1, src2, &env->fp_status); \
388 } else { \
389 ret = glue(size, _compare_quiet)(src1, src2, \
390 &env->fp_status); \
391 } \
392 check_ieee_exceptions(env, GETPC()); \
393 fsr = env->fsr; \
394 switch (ret) { \
395 case float_relation_unordered: \
396 fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \
397 break; \
398 case float_relation_less: \
399 fsr &= ~(FSR_FCC1 << FS); \
400 fsr |= FSR_FCC0 << FS; \
401 break; \
402 case float_relation_greater: \
403 fsr &= ~(FSR_FCC0 << FS); \
404 fsr |= FSR_FCC1 << FS; \
405 break; \
406 default: \
407 fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
408 break; \
409 } \
410 return fsr; \
411 }
412
413 GEN_FCMP_T(fcmps, float32, 0, 0);
414 GEN_FCMP_T(fcmpd, float64, 0, 0);
415
416 GEN_FCMP_T(fcmpes, float32, 0, 1);
417 GEN_FCMP_T(fcmped, float64, 0, 1);
418
419 GEN_FCMP(fcmpq, float128, 0, 0);
420 GEN_FCMP(fcmpeq, float128, 0, 1);
421
422 #ifdef TARGET_SPARC64
423 GEN_FCMP_T(fcmps_fcc1, float32, 22, 0);
424 GEN_FCMP_T(fcmpd_fcc1, float64, 22, 0);
425 GEN_FCMP(fcmpq_fcc1, float128, 22, 0);
426
427 GEN_FCMP_T(fcmps_fcc2, float32, 24, 0);
428 GEN_FCMP_T(fcmpd_fcc2, float64, 24, 0);
429 GEN_FCMP(fcmpq_fcc2, float128, 24, 0);
430
431 GEN_FCMP_T(fcmps_fcc3, float32, 26, 0);
432 GEN_FCMP_T(fcmpd_fcc3, float64, 26, 0);
433 GEN_FCMP(fcmpq_fcc3, float128, 26, 0);
434
435 GEN_FCMP_T(fcmpes_fcc1, float32, 22, 1);
436 GEN_FCMP_T(fcmped_fcc1, float64, 22, 1);
437 GEN_FCMP(fcmpeq_fcc1, float128, 22, 1);
438
439 GEN_FCMP_T(fcmpes_fcc2, float32, 24, 1);
440 GEN_FCMP_T(fcmped_fcc2, float64, 24, 1);
441 GEN_FCMP(fcmpeq_fcc2, float128, 24, 1);
442
443 GEN_FCMP_T(fcmpes_fcc3, float32, 26, 1);
444 GEN_FCMP_T(fcmped_fcc3, float64, 26, 1);
445 GEN_FCMP(fcmpeq_fcc3, float128, 26, 1);
446 #endif
447 #undef GEN_FCMP_T
448 #undef GEN_FCMP
449
450 target_ulong cpu_get_fsr(CPUSPARCState *env)
451 {
452 target_ulong fsr = env->fsr | env->fsr_cexc_ftt;
453
454 /* VER is kept completely separate until re-assembly. */
455 fsr |= env->def.fpu_version;
456
457 return fsr;
458 }
459
460 target_ulong helper_get_fsr(CPUSPARCState *env)
461 {
462 return cpu_get_fsr(env);
463 }
464
465 static void set_fsr_nonsplit(CPUSPARCState *env, target_ulong fsr)
466 {
467 int rnd_mode;
468
469 env->fsr = fsr & ~(FSR_VER_MASK | FSR_CEXC_MASK | FSR_FTT_MASK);
470
471 switch (fsr & FSR_RD_MASK) {
472 case FSR_RD_NEAREST:
473 rnd_mode = float_round_nearest_even;
474 break;
475 default:
476 case FSR_RD_ZERO:
477 rnd_mode = float_round_to_zero;
478 break;
479 case FSR_RD_POS:
480 rnd_mode = float_round_up;
481 break;
482 case FSR_RD_NEG:
483 rnd_mode = float_round_down;
484 break;
485 }
486 set_float_rounding_mode(rnd_mode, &env->fp_status);
487 }
488
489 void cpu_put_fsr(CPUSPARCState *env, target_ulong fsr)
490 {
491 env->fsr_cexc_ftt = fsr & (FSR_CEXC_MASK | FSR_FTT_MASK);
492 set_fsr_nonsplit(env, fsr);
493 }
494
495 void helper_set_fsr_noftt(CPUSPARCState *env, target_ulong fsr)
496 {
497 env->fsr_cexc_ftt &= FSR_FTT_MASK;
498 env->fsr_cexc_ftt |= fsr & FSR_CEXC_MASK;
499 set_fsr_nonsplit(env, fsr);
500 }