]>
Commit | Line | Data |
---|---|---|
1bccec25 BS |
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 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 | ||
db5ebe5f | 20 | #include "qemu/osdep.h" |
1bccec25 | 21 | #include "cpu.h" |
2ef6175a | 22 | #include "exec/helper-proto.h" |
1bccec25 | 23 | |
1bccec25 BS |
24 | #define QT0 (env->qt0) |
25 | #define QT1 (env->qt1) | |
26 | ||
c5f9864e | 27 | static void check_ieee_exceptions(CPUSPARCState *env) |
44516772 RH |
28 | { |
29 | target_ulong status; | |
30 | ||
31 | status = get_float_exception_flags(&env->fp_status); | |
32 | if (status) { | |
33 | /* Copy IEEE 754 flags into FSR */ | |
34 | if (status & float_flag_invalid) { | |
35 | env->fsr |= FSR_NVC; | |
36 | } | |
37 | if (status & float_flag_overflow) { | |
38 | env->fsr |= FSR_OFC; | |
39 | } | |
40 | if (status & float_flag_underflow) { | |
41 | env->fsr |= FSR_UFC; | |
42 | } | |
43 | if (status & float_flag_divbyzero) { | |
44 | env->fsr |= FSR_DZC; | |
45 | } | |
46 | if (status & float_flag_inexact) { | |
47 | env->fsr |= FSR_NXC; | |
48 | } | |
49 | ||
50 | if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23)) { | |
51 | /* Unmasked exception, generate a trap */ | |
52 | env->fsr |= FSR_FTT_IEEE_EXCP; | |
53 | helper_raise_exception(env, TT_FP_EXCP); | |
54 | } else { | |
55 | /* Accumulate exceptions */ | |
56 | env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5; | |
57 | } | |
58 | } | |
59 | } | |
60 | ||
c5f9864e | 61 | static inline void clear_float_exceptions(CPUSPARCState *env) |
44516772 RH |
62 | { |
63 | set_float_exception_flags(0, &env->fp_status); | |
64 | } | |
65 | ||
c5f9864e | 66 | #define F_HELPER(name, p) void helper_f##name##p(CPUSPARCState *env) |
1bccec25 BS |
67 | |
68 | #define F_BINOP(name) \ | |
c5f9864e | 69 | float32 helper_f ## name ## s (CPUSPARCState *env, float32 src1, \ |
2e2f4ade | 70 | float32 src2) \ |
1bccec25 | 71 | { \ |
44516772 RH |
72 | float32 ret; \ |
73 | clear_float_exceptions(env); \ | |
74 | ret = float32_ ## name (src1, src2, &env->fp_status); \ | |
75 | check_ieee_exceptions(env); \ | |
76 | return ret; \ | |
1bccec25 | 77 | } \ |
c5f9864e | 78 | float64 helper_f ## name ## d (CPUSPARCState * env, float64 src1,\ |
03fb8cfc | 79 | float64 src2) \ |
1bccec25 | 80 | { \ |
44516772 RH |
81 | float64 ret; \ |
82 | clear_float_exceptions(env); \ | |
83 | ret = float64_ ## name (src1, src2, &env->fp_status); \ | |
84 | check_ieee_exceptions(env); \ | |
85 | return ret; \ | |
1bccec25 BS |
86 | } \ |
87 | F_HELPER(name, q) \ | |
88 | { \ | |
44516772 | 89 | clear_float_exceptions(env); \ |
1bccec25 | 90 | QT0 = float128_ ## name (QT0, QT1, &env->fp_status); \ |
44516772 | 91 | check_ieee_exceptions(env); \ |
1bccec25 BS |
92 | } |
93 | ||
94 | F_BINOP(add); | |
95 | F_BINOP(sub); | |
96 | F_BINOP(mul); | |
97 | F_BINOP(div); | |
98 | #undef F_BINOP | |
99 | ||
c5f9864e | 100 | float64 helper_fsmuld(CPUSPARCState *env, float32 src1, float32 src2) |
1bccec25 | 101 | { |
44516772 RH |
102 | float64 ret; |
103 | clear_float_exceptions(env); | |
104 | ret = float64_mul(float32_to_float64(src1, &env->fp_status), | |
105 | float32_to_float64(src2, &env->fp_status), | |
106 | &env->fp_status); | |
107 | check_ieee_exceptions(env); | |
108 | return ret; | |
1bccec25 BS |
109 | } |
110 | ||
c5f9864e | 111 | void helper_fdmulq(CPUSPARCState *env, float64 src1, float64 src2) |
1bccec25 | 112 | { |
44516772 | 113 | clear_float_exceptions(env); |
03fb8cfc RH |
114 | QT0 = float128_mul(float64_to_float128(src1, &env->fp_status), |
115 | float64_to_float128(src2, &env->fp_status), | |
1bccec25 | 116 | &env->fp_status); |
44516772 | 117 | check_ieee_exceptions(env); |
1bccec25 BS |
118 | } |
119 | ||
120 | float32 helper_fnegs(float32 src) | |
121 | { | |
122 | return float32_chs(src); | |
123 | } | |
124 | ||
125 | #ifdef TARGET_SPARC64 | |
03fb8cfc | 126 | float64 helper_fnegd(float64 src) |
1bccec25 | 127 | { |
03fb8cfc | 128 | return float64_chs(src); |
1bccec25 BS |
129 | } |
130 | ||
131 | F_HELPER(neg, q) | |
132 | { | |
133 | QT0 = float128_chs(QT1); | |
134 | } | |
135 | #endif | |
136 | ||
137 | /* Integer to float conversion. */ | |
c5f9864e | 138 | float32 helper_fitos(CPUSPARCState *env, int32_t src) |
1bccec25 | 139 | { |
44516772 RH |
140 | /* Inexact error possible converting int to float. */ |
141 | float32 ret; | |
142 | clear_float_exceptions(env); | |
143 | ret = int32_to_float32(src, &env->fp_status); | |
144 | check_ieee_exceptions(env); | |
145 | return ret; | |
1bccec25 BS |
146 | } |
147 | ||
c5f9864e | 148 | float64 helper_fitod(CPUSPARCState *env, int32_t src) |
1bccec25 | 149 | { |
44516772 | 150 | /* No possible exceptions converting int to double. */ |
03fb8cfc | 151 | return int32_to_float64(src, &env->fp_status); |
1bccec25 BS |
152 | } |
153 | ||
c5f9864e | 154 | void helper_fitoq(CPUSPARCState *env, int32_t src) |
1bccec25 | 155 | { |
44516772 | 156 | /* No possible exceptions converting int to long double. */ |
1bccec25 BS |
157 | QT0 = int32_to_float128(src, &env->fp_status); |
158 | } | |
159 | ||
160 | #ifdef TARGET_SPARC64 | |
c5f9864e | 161 | float32 helper_fxtos(CPUSPARCState *env, int64_t src) |
1bccec25 | 162 | { |
44516772 RH |
163 | float32 ret; |
164 | clear_float_exceptions(env); | |
165 | ret = int64_to_float32(src, &env->fp_status); | |
166 | check_ieee_exceptions(env); | |
167 | return ret; | |
1bccec25 BS |
168 | } |
169 | ||
c5f9864e | 170 | float64 helper_fxtod(CPUSPARCState *env, int64_t src) |
1bccec25 | 171 | { |
44516772 RH |
172 | float64 ret; |
173 | clear_float_exceptions(env); | |
174 | ret = int64_to_float64(src, &env->fp_status); | |
175 | check_ieee_exceptions(env); | |
176 | return ret; | |
1bccec25 BS |
177 | } |
178 | ||
c5f9864e | 179 | void helper_fxtoq(CPUSPARCState *env, int64_t src) |
1bccec25 | 180 | { |
44516772 | 181 | /* No possible exceptions converting long long to long double. */ |
03fb8cfc | 182 | QT0 = int64_to_float128(src, &env->fp_status); |
1bccec25 BS |
183 | } |
184 | #endif | |
185 | #undef F_HELPER | |
186 | ||
187 | /* floating point conversion */ | |
c5f9864e | 188 | float32 helper_fdtos(CPUSPARCState *env, float64 src) |
1bccec25 | 189 | { |
44516772 RH |
190 | float32 ret; |
191 | clear_float_exceptions(env); | |
192 | ret = float64_to_float32(src, &env->fp_status); | |
193 | check_ieee_exceptions(env); | |
194 | return ret; | |
1bccec25 BS |
195 | } |
196 | ||
c5f9864e | 197 | float64 helper_fstod(CPUSPARCState *env, float32 src) |
1bccec25 | 198 | { |
44516772 RH |
199 | float64 ret; |
200 | clear_float_exceptions(env); | |
201 | ret = float32_to_float64(src, &env->fp_status); | |
202 | check_ieee_exceptions(env); | |
203 | return ret; | |
1bccec25 BS |
204 | } |
205 | ||
c5f9864e | 206 | float32 helper_fqtos(CPUSPARCState *env) |
1bccec25 | 207 | { |
44516772 RH |
208 | float32 ret; |
209 | clear_float_exceptions(env); | |
210 | ret = float128_to_float32(QT1, &env->fp_status); | |
211 | check_ieee_exceptions(env); | |
212 | return ret; | |
1bccec25 BS |
213 | } |
214 | ||
c5f9864e | 215 | void helper_fstoq(CPUSPARCState *env, float32 src) |
1bccec25 | 216 | { |
44516772 | 217 | clear_float_exceptions(env); |
1bccec25 | 218 | QT0 = float32_to_float128(src, &env->fp_status); |
44516772 | 219 | check_ieee_exceptions(env); |
1bccec25 BS |
220 | } |
221 | ||
c5f9864e | 222 | float64 helper_fqtod(CPUSPARCState *env) |
1bccec25 | 223 | { |
44516772 RH |
224 | float64 ret; |
225 | clear_float_exceptions(env); | |
226 | ret = float128_to_float64(QT1, &env->fp_status); | |
227 | check_ieee_exceptions(env); | |
228 | return ret; | |
1bccec25 BS |
229 | } |
230 | ||
c5f9864e | 231 | void helper_fdtoq(CPUSPARCState *env, float64 src) |
1bccec25 | 232 | { |
44516772 | 233 | clear_float_exceptions(env); |
03fb8cfc | 234 | QT0 = float64_to_float128(src, &env->fp_status); |
44516772 | 235 | check_ieee_exceptions(env); |
1bccec25 BS |
236 | } |
237 | ||
238 | /* Float to integer conversion. */ | |
c5f9864e | 239 | int32_t helper_fstoi(CPUSPARCState *env, float32 src) |
1bccec25 | 240 | { |
44516772 RH |
241 | int32_t ret; |
242 | clear_float_exceptions(env); | |
243 | ret = float32_to_int32_round_to_zero(src, &env->fp_status); | |
244 | check_ieee_exceptions(env); | |
245 | return ret; | |
1bccec25 BS |
246 | } |
247 | ||
c5f9864e | 248 | int32_t helper_fdtoi(CPUSPARCState *env, float64 src) |
1bccec25 | 249 | { |
44516772 RH |
250 | int32_t ret; |
251 | clear_float_exceptions(env); | |
252 | ret = float64_to_int32_round_to_zero(src, &env->fp_status); | |
253 | check_ieee_exceptions(env); | |
254 | return ret; | |
1bccec25 BS |
255 | } |
256 | ||
c5f9864e | 257 | int32_t helper_fqtoi(CPUSPARCState *env) |
1bccec25 | 258 | { |
44516772 RH |
259 | int32_t ret; |
260 | clear_float_exceptions(env); | |
261 | ret = float128_to_int32_round_to_zero(QT1, &env->fp_status); | |
262 | check_ieee_exceptions(env); | |
263 | return ret; | |
1bccec25 BS |
264 | } |
265 | ||
266 | #ifdef TARGET_SPARC64 | |
c5f9864e | 267 | int64_t helper_fstox(CPUSPARCState *env, float32 src) |
1bccec25 | 268 | { |
44516772 RH |
269 | int64_t ret; |
270 | clear_float_exceptions(env); | |
271 | ret = float32_to_int64_round_to_zero(src, &env->fp_status); | |
272 | check_ieee_exceptions(env); | |
273 | return ret; | |
1bccec25 BS |
274 | } |
275 | ||
c5f9864e | 276 | int64_t helper_fdtox(CPUSPARCState *env, float64 src) |
1bccec25 | 277 | { |
44516772 RH |
278 | int64_t ret; |
279 | clear_float_exceptions(env); | |
280 | ret = float64_to_int64_round_to_zero(src, &env->fp_status); | |
281 | check_ieee_exceptions(env); | |
282 | return ret; | |
1bccec25 BS |
283 | } |
284 | ||
c5f9864e | 285 | int64_t helper_fqtox(CPUSPARCState *env) |
1bccec25 | 286 | { |
44516772 RH |
287 | int64_t ret; |
288 | clear_float_exceptions(env); | |
289 | ret = float128_to_int64_round_to_zero(QT1, &env->fp_status); | |
290 | check_ieee_exceptions(env); | |
291 | return ret; | |
1bccec25 BS |
292 | } |
293 | #endif | |
294 | ||
295 | float32 helper_fabss(float32 src) | |
296 | { | |
297 | return float32_abs(src); | |
298 | } | |
299 | ||
300 | #ifdef TARGET_SPARC64 | |
f027c3b1 | 301 | float64 helper_fabsd(float64 src) |
1bccec25 | 302 | { |
03fb8cfc | 303 | return float64_abs(src); |
1bccec25 BS |
304 | } |
305 | ||
c5f9864e | 306 | void helper_fabsq(CPUSPARCState *env) |
1bccec25 BS |
307 | { |
308 | QT0 = float128_abs(QT1); | |
309 | } | |
310 | #endif | |
311 | ||
c5f9864e | 312 | float32 helper_fsqrts(CPUSPARCState *env, float32 src) |
1bccec25 | 313 | { |
44516772 RH |
314 | float32 ret; |
315 | clear_float_exceptions(env); | |
316 | ret = float32_sqrt(src, &env->fp_status); | |
317 | check_ieee_exceptions(env); | |
318 | return ret; | |
1bccec25 BS |
319 | } |
320 | ||
c5f9864e | 321 | float64 helper_fsqrtd(CPUSPARCState *env, float64 src) |
1bccec25 | 322 | { |
44516772 RH |
323 | float64 ret; |
324 | clear_float_exceptions(env); | |
325 | ret = float64_sqrt(src, &env->fp_status); | |
326 | check_ieee_exceptions(env); | |
327 | return ret; | |
1bccec25 BS |
328 | } |
329 | ||
c5f9864e | 330 | void helper_fsqrtq(CPUSPARCState *env) |
1bccec25 | 331 | { |
44516772 | 332 | clear_float_exceptions(env); |
1bccec25 | 333 | QT0 = float128_sqrt(QT1, &env->fp_status); |
44516772 | 334 | check_ieee_exceptions(env); |
1bccec25 BS |
335 | } |
336 | ||
337 | #define GEN_FCMP(name, size, reg1, reg2, FS, E) \ | |
5acfc832 | 338 | void glue(helper_, name) (CPUSPARCState *env) \ |
1bccec25 | 339 | { \ |
5acfc832 AJ |
340 | int ret; \ |
341 | clear_float_exceptions(env); \ | |
342 | if (E) { \ | |
343 | ret = glue(size, _compare)(reg1, reg2, &env->fp_status); \ | |
344 | } else { \ | |
345 | ret = glue(size, _compare_quiet)(reg1, reg2, \ | |
346 | &env->fp_status); \ | |
1bccec25 | 347 | } \ |
5acfc832 AJ |
348 | check_ieee_exceptions(env); \ |
349 | switch (ret) { \ | |
1bccec25 | 350 | case float_relation_unordered: \ |
5acfc832 AJ |
351 | env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \ |
352 | env->fsr |= FSR_NVA; \ | |
1bccec25 BS |
353 | break; \ |
354 | case float_relation_less: \ | |
5acfc832 | 355 | env->fsr &= ~(FSR_FCC1) << FS; \ |
1bccec25 BS |
356 | env->fsr |= FSR_FCC0 << FS; \ |
357 | break; \ | |
358 | case float_relation_greater: \ | |
5acfc832 | 359 | env->fsr &= ~(FSR_FCC0) << FS; \ |
1bccec25 BS |
360 | env->fsr |= FSR_FCC1 << FS; \ |
361 | break; \ | |
362 | default: \ | |
363 | env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ | |
364 | break; \ | |
365 | } \ | |
366 | } | |
03fb8cfc | 367 | #define GEN_FCMP_T(name, size, FS, E) \ |
5acfc832 | 368 | void glue(helper_, name)(CPUSPARCState *env, size src1, size src2) \ |
1bccec25 | 369 | { \ |
5acfc832 AJ |
370 | int ret; \ |
371 | clear_float_exceptions(env); \ | |
372 | if (E) { \ | |
373 | ret = glue(size, _compare)(src1, src2, &env->fp_status); \ | |
374 | } else { \ | |
375 | ret = glue(size, _compare_quiet)(src1, src2, \ | |
376 | &env->fp_status); \ | |
1bccec25 | 377 | } \ |
5acfc832 AJ |
378 | check_ieee_exceptions(env); \ |
379 | switch (ret) { \ | |
1bccec25 | 380 | case float_relation_unordered: \ |
5acfc832 | 381 | env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \ |
1bccec25 BS |
382 | break; \ |
383 | case float_relation_less: \ | |
5acfc832 | 384 | env->fsr &= ~(FSR_FCC1 << FS); \ |
1bccec25 BS |
385 | env->fsr |= FSR_FCC0 << FS; \ |
386 | break; \ | |
387 | case float_relation_greater: \ | |
5acfc832 | 388 | env->fsr &= ~(FSR_FCC0 << FS); \ |
1bccec25 BS |
389 | env->fsr |= FSR_FCC1 << FS; \ |
390 | break; \ | |
391 | default: \ | |
392 | env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ | |
393 | break; \ | |
394 | } \ | |
395 | } | |
396 | ||
03fb8cfc RH |
397 | GEN_FCMP_T(fcmps, float32, 0, 0); |
398 | GEN_FCMP_T(fcmpd, float64, 0, 0); | |
1bccec25 | 399 | |
03fb8cfc RH |
400 | GEN_FCMP_T(fcmpes, float32, 0, 1); |
401 | GEN_FCMP_T(fcmped, float64, 0, 1); | |
1bccec25 BS |
402 | |
403 | GEN_FCMP(fcmpq, float128, QT0, QT1, 0, 0); | |
404 | GEN_FCMP(fcmpeq, float128, QT0, QT1, 0, 1); | |
405 | ||
406 | #ifdef TARGET_SPARC64 | |
03fb8cfc RH |
407 | GEN_FCMP_T(fcmps_fcc1, float32, 22, 0); |
408 | GEN_FCMP_T(fcmpd_fcc1, float64, 22, 0); | |
1bccec25 BS |
409 | GEN_FCMP(fcmpq_fcc1, float128, QT0, QT1, 22, 0); |
410 | ||
03fb8cfc RH |
411 | GEN_FCMP_T(fcmps_fcc2, float32, 24, 0); |
412 | GEN_FCMP_T(fcmpd_fcc2, float64, 24, 0); | |
1bccec25 BS |
413 | GEN_FCMP(fcmpq_fcc2, float128, QT0, QT1, 24, 0); |
414 | ||
03fb8cfc RH |
415 | GEN_FCMP_T(fcmps_fcc3, float32, 26, 0); |
416 | GEN_FCMP_T(fcmpd_fcc3, float64, 26, 0); | |
1bccec25 BS |
417 | GEN_FCMP(fcmpq_fcc3, float128, QT0, QT1, 26, 0); |
418 | ||
03fb8cfc RH |
419 | GEN_FCMP_T(fcmpes_fcc1, float32, 22, 1); |
420 | GEN_FCMP_T(fcmped_fcc1, float64, 22, 1); | |
1bccec25 BS |
421 | GEN_FCMP(fcmpeq_fcc1, float128, QT0, QT1, 22, 1); |
422 | ||
03fb8cfc RH |
423 | GEN_FCMP_T(fcmpes_fcc2, float32, 24, 1); |
424 | GEN_FCMP_T(fcmped_fcc2, float64, 24, 1); | |
1bccec25 BS |
425 | GEN_FCMP(fcmpeq_fcc2, float128, QT0, QT1, 24, 1); |
426 | ||
03fb8cfc RH |
427 | GEN_FCMP_T(fcmpes_fcc3, float32, 26, 1); |
428 | GEN_FCMP_T(fcmped_fcc3, float64, 26, 1); | |
1bccec25 BS |
429 | GEN_FCMP(fcmpeq_fcc3, float128, QT0, QT1, 26, 1); |
430 | #endif | |
03fb8cfc RH |
431 | #undef GEN_FCMP_T |
432 | #undef GEN_FCMP | |
1bccec25 | 433 | |
c5f9864e | 434 | static inline void set_fsr(CPUSPARCState *env) |
1bccec25 BS |
435 | { |
436 | int rnd_mode; | |
437 | ||
438 | switch (env->fsr & FSR_RD_MASK) { | |
439 | case FSR_RD_NEAREST: | |
440 | rnd_mode = float_round_nearest_even; | |
441 | break; | |
442 | default: | |
443 | case FSR_RD_ZERO: | |
444 | rnd_mode = float_round_to_zero; | |
445 | break; | |
446 | case FSR_RD_POS: | |
447 | rnd_mode = float_round_up; | |
448 | break; | |
449 | case FSR_RD_NEG: | |
450 | rnd_mode = float_round_down; | |
451 | break; | |
452 | } | |
453 | set_float_rounding_mode(rnd_mode, &env->fp_status); | |
454 | } | |
455 | ||
c5f9864e | 456 | void helper_ldfsr(CPUSPARCState *env, uint32_t new_fsr) |
1bccec25 BS |
457 | { |
458 | env->fsr = (new_fsr & FSR_LDFSR_MASK) | (env->fsr & FSR_LDFSR_OLDMASK); | |
2e2f4ade | 459 | set_fsr(env); |
1bccec25 BS |
460 | } |
461 | ||
462 | #ifdef TARGET_SPARC64 | |
c5f9864e | 463 | void helper_ldxfsr(CPUSPARCState *env, uint64_t new_fsr) |
1bccec25 BS |
464 | { |
465 | env->fsr = (new_fsr & FSR_LDXFSR_MASK) | (env->fsr & FSR_LDXFSR_OLDMASK); | |
2e2f4ade | 466 | set_fsr(env); |
1bccec25 BS |
467 | } |
468 | #endif |