]>
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 | |
5650b549 | 9 | * version 2.1 of the License, or (at your option) any later version. |
1bccec25 BS |
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" |
02c79d78 | 22 | #include "exec/exec-all.h" |
2ef6175a | 23 | #include "exec/helper-proto.h" |
24f91e81 | 24 | #include "fpu/softfloat.h" |
1bccec25 | 25 | |
1bccec25 BS |
26 | #define QT0 (env->qt0) |
27 | #define QT1 (env->qt1) | |
28 | ||
e41716be RH |
29 | static inline float128 f128_in(Int128 i) |
30 | { | |
31 | union { | |
32 | Int128 i; | |
33 | float128 f; | |
34 | } u; | |
35 | ||
36 | u.i = i; | |
37 | return u.f; | |
38 | } | |
39 | ||
40 | static inline Int128 f128_ret(float128 f) | |
41 | { | |
42 | union { | |
43 | Int128 i; | |
44 | float128 f; | |
45 | } u; | |
46 | ||
47 | u.f = f; | |
48 | return u.i; | |
49 | } | |
50 | ||
02c79d78 | 51 | static target_ulong do_check_ieee_exceptions(CPUSPARCState *env, uintptr_t ra) |
44516772 | 52 | { |
7385aed2 RH |
53 | target_ulong status = get_float_exception_flags(&env->fp_status); |
54 | target_ulong fsr = env->fsr; | |
55 | ||
56 | if (unlikely(status)) { | |
57 | /* Keep exception flags clear for next time. */ | |
58 | set_float_exception_flags(0, &env->fp_status); | |
44516772 | 59 | |
44516772 RH |
60 | /* Copy IEEE 754 flags into FSR */ |
61 | if (status & float_flag_invalid) { | |
7385aed2 | 62 | fsr |= FSR_NVC; |
44516772 RH |
63 | } |
64 | if (status & float_flag_overflow) { | |
7385aed2 | 65 | fsr |= FSR_OFC; |
44516772 RH |
66 | } |
67 | if (status & float_flag_underflow) { | |
7385aed2 | 68 | fsr |= FSR_UFC; |
44516772 RH |
69 | } |
70 | if (status & float_flag_divbyzero) { | |
7385aed2 | 71 | fsr |= FSR_DZC; |
44516772 RH |
72 | } |
73 | if (status & float_flag_inexact) { | |
7385aed2 | 74 | fsr |= FSR_NXC; |
44516772 RH |
75 | } |
76 | ||
7385aed2 | 77 | if ((fsr & FSR_CEXC_MASK) & ((fsr & FSR_TEM_MASK) >> 23)) { |
5a59fbce | 78 | CPUState *cs = env_cpu(env); |
02c79d78 | 79 | |
7385aed2 RH |
80 | /* Unmasked exception, generate a trap. Note that while |
81 | the helper is marked as NO_WG, we can get away with | |
82 | writing to cpu state along the exception path, since | |
83 | TCG generated code will never see the write. */ | |
84 | env->fsr = fsr | FSR_FTT_IEEE_EXCP; | |
02c79d78 RH |
85 | cs->exception_index = TT_FP_EXCP; |
86 | cpu_loop_exit_restore(cs, ra); | |
44516772 RH |
87 | } else { |
88 | /* Accumulate exceptions */ | |
7385aed2 | 89 | fsr |= (fsr & FSR_CEXC_MASK) << 5; |
44516772 RH |
90 | } |
91 | } | |
44516772 | 92 | |
7385aed2 | 93 | return fsr; |
44516772 RH |
94 | } |
95 | ||
02c79d78 RH |
96 | target_ulong helper_check_ieee_exceptions(CPUSPARCState *env) |
97 | { | |
98 | return do_check_ieee_exceptions(env, GETPC()); | |
99 | } | |
100 | ||
16bedf89 | 101 | #define F_BINOP(name) \ |
c5f9864e | 102 | float32 helper_f ## name ## s (CPUSPARCState *env, float32 src1, \ |
16bedf89 RH |
103 | float32 src2) \ |
104 | { \ | |
105 | return float32_ ## name (src1, src2, &env->fp_status); \ | |
106 | } \ | |
c5f9864e | 107 | float64 helper_f ## name ## d (CPUSPARCState * env, float64 src1,\ |
16bedf89 RH |
108 | float64 src2) \ |
109 | { \ | |
110 | return float64_ ## name (src1, src2, &env->fp_status); \ | |
111 | } \ | |
112 | Int128 helper_f ## name ## q(CPUSPARCState * env, Int128 src1, \ | |
113 | Int128 src2) \ | |
114 | { \ | |
115 | return f128_ret(float128_ ## name (f128_in(src1), f128_in(src2), \ | |
116 | &env->fp_status)); \ | |
1bccec25 BS |
117 | } |
118 | ||
119 | F_BINOP(add); | |
120 | F_BINOP(sub); | |
121 | F_BINOP(mul); | |
122 | F_BINOP(div); | |
123 | #undef F_BINOP | |
124 | ||
c5f9864e | 125 | float64 helper_fsmuld(CPUSPARCState *env, float32 src1, float32 src2) |
1bccec25 | 126 | { |
7385aed2 RH |
127 | return float64_mul(float32_to_float64(src1, &env->fp_status), |
128 | float32_to_float64(src2, &env->fp_status), | |
129 | &env->fp_status); | |
1bccec25 BS |
130 | } |
131 | ||
c5f9864e | 132 | void helper_fdmulq(CPUSPARCState *env, float64 src1, float64 src2) |
1bccec25 | 133 | { |
03fb8cfc RH |
134 | QT0 = float128_mul(float64_to_float128(src1, &env->fp_status), |
135 | float64_to_float128(src2, &env->fp_status), | |
1bccec25 BS |
136 | &env->fp_status); |
137 | } | |
138 | ||
1bccec25 | 139 | /* Integer to float conversion. */ |
c5f9864e | 140 | float32 helper_fitos(CPUSPARCState *env, int32_t src) |
1bccec25 | 141 | { |
7385aed2 | 142 | return int32_to_float32(src, &env->fp_status); |
1bccec25 BS |
143 | } |
144 | ||
c5f9864e | 145 | float64 helper_fitod(CPUSPARCState *env, int32_t src) |
1bccec25 | 146 | { |
03fb8cfc | 147 | return int32_to_float64(src, &env->fp_status); |
1bccec25 BS |
148 | } |
149 | ||
0b2a61cc | 150 | Int128 helper_fitoq(CPUSPARCState *env, int32_t src) |
1bccec25 | 151 | { |
0b2a61cc | 152 | return f128_ret(int32_to_float128(src, &env->fp_status)); |
1bccec25 BS |
153 | } |
154 | ||
155 | #ifdef TARGET_SPARC64 | |
c5f9864e | 156 | float32 helper_fxtos(CPUSPARCState *env, int64_t src) |
1bccec25 | 157 | { |
7385aed2 | 158 | return int64_to_float32(src, &env->fp_status); |
1bccec25 BS |
159 | } |
160 | ||
c5f9864e | 161 | float64 helper_fxtod(CPUSPARCState *env, int64_t src) |
1bccec25 | 162 | { |
7385aed2 | 163 | return int64_to_float64(src, &env->fp_status); |
1bccec25 BS |
164 | } |
165 | ||
c5f9864e | 166 | void helper_fxtoq(CPUSPARCState *env, int64_t src) |
1bccec25 | 167 | { |
03fb8cfc | 168 | QT0 = int64_to_float128(src, &env->fp_status); |
1bccec25 BS |
169 | } |
170 | #endif | |
1bccec25 BS |
171 | |
172 | /* floating point conversion */ | |
c5f9864e | 173 | float32 helper_fdtos(CPUSPARCState *env, float64 src) |
1bccec25 | 174 | { |
7385aed2 | 175 | return float64_to_float32(src, &env->fp_status); |
1bccec25 BS |
176 | } |
177 | ||
c5f9864e | 178 | float64 helper_fstod(CPUSPARCState *env, float32 src) |
1bccec25 | 179 | { |
7385aed2 | 180 | return float32_to_float64(src, &env->fp_status); |
1bccec25 BS |
181 | } |
182 | ||
d81e3efe | 183 | float32 helper_fqtos(CPUSPARCState *env, Int128 src) |
1bccec25 | 184 | { |
d81e3efe | 185 | return float128_to_float32(f128_in(src), &env->fp_status); |
1bccec25 BS |
186 | } |
187 | ||
0b2a61cc | 188 | Int128 helper_fstoq(CPUSPARCState *env, float32 src) |
1bccec25 | 189 | { |
0b2a61cc | 190 | return f128_ret(float32_to_float128(src, &env->fp_status)); |
1bccec25 BS |
191 | } |
192 | ||
25a5769e | 193 | float64 helper_fqtod(CPUSPARCState *env, Int128 src) |
1bccec25 | 194 | { |
25a5769e | 195 | return float128_to_float64(f128_in(src), &env->fp_status); |
1bccec25 BS |
196 | } |
197 | ||
c5f9864e | 198 | void helper_fdtoq(CPUSPARCState *env, float64 src) |
1bccec25 | 199 | { |
03fb8cfc | 200 | QT0 = float64_to_float128(src, &env->fp_status); |
1bccec25 BS |
201 | } |
202 | ||
203 | /* Float to integer conversion. */ | |
c5f9864e | 204 | int32_t helper_fstoi(CPUSPARCState *env, float32 src) |
1bccec25 | 205 | { |
7385aed2 | 206 | return float32_to_int32_round_to_zero(src, &env->fp_status); |
1bccec25 BS |
207 | } |
208 | ||
c5f9864e | 209 | int32_t helper_fdtoi(CPUSPARCState *env, float64 src) |
1bccec25 | 210 | { |
7385aed2 | 211 | return float64_to_int32_round_to_zero(src, &env->fp_status); |
1bccec25 BS |
212 | } |
213 | ||
d81e3efe | 214 | int32_t helper_fqtoi(CPUSPARCState *env, Int128 src) |
1bccec25 | 215 | { |
d81e3efe | 216 | return float128_to_int32_round_to_zero(f128_in(src), &env->fp_status); |
1bccec25 BS |
217 | } |
218 | ||
219 | #ifdef TARGET_SPARC64 | |
c5f9864e | 220 | int64_t helper_fstox(CPUSPARCState *env, float32 src) |
1bccec25 | 221 | { |
7385aed2 | 222 | return float32_to_int64_round_to_zero(src, &env->fp_status); |
1bccec25 BS |
223 | } |
224 | ||
c5f9864e | 225 | int64_t helper_fdtox(CPUSPARCState *env, float64 src) |
1bccec25 | 226 | { |
7385aed2 | 227 | return float64_to_int64_round_to_zero(src, &env->fp_status); |
1bccec25 BS |
228 | } |
229 | ||
25a5769e | 230 | int64_t helper_fqtox(CPUSPARCState *env, Int128 src) |
1bccec25 | 231 | { |
25a5769e | 232 | return float128_to_int64_round_to_zero(f128_in(src), &env->fp_status); |
1bccec25 BS |
233 | } |
234 | #endif | |
235 | ||
c5f9864e | 236 | float32 helper_fsqrts(CPUSPARCState *env, float32 src) |
1bccec25 | 237 | { |
7385aed2 | 238 | return float32_sqrt(src, &env->fp_status); |
1bccec25 BS |
239 | } |
240 | ||
c5f9864e | 241 | float64 helper_fsqrtd(CPUSPARCState *env, float64 src) |
1bccec25 | 242 | { |
7385aed2 | 243 | return float64_sqrt(src, &env->fp_status); |
1bccec25 BS |
244 | } |
245 | ||
e41716be | 246 | Int128 helper_fsqrtq(CPUSPARCState *env, Int128 src) |
1bccec25 | 247 | { |
e41716be | 248 | return f128_ret(float128_sqrt(f128_in(src), &env->fp_status)); |
1bccec25 BS |
249 | } |
250 | ||
f3ceafad RH |
251 | #define GEN_FCMP(name, size, FS, E) \ |
252 | target_ulong glue(helper_, name) (CPUSPARCState *env, \ | |
253 | Int128 src1, Int128 src2) \ | |
1bccec25 | 254 | { \ |
f3ceafad RH |
255 | float128 reg1 = f128_in(src1); \ |
256 | float128 reg2 = f128_in(src2); \ | |
71bfd65c | 257 | FloatRelation ret; \ |
7385aed2 | 258 | target_ulong fsr; \ |
5acfc832 AJ |
259 | if (E) { \ |
260 | ret = glue(size, _compare)(reg1, reg2, &env->fp_status); \ | |
261 | } else { \ | |
262 | ret = glue(size, _compare_quiet)(reg1, reg2, \ | |
263 | &env->fp_status); \ | |
1bccec25 | 264 | } \ |
02c79d78 | 265 | fsr = do_check_ieee_exceptions(env, GETPC()); \ |
5acfc832 | 266 | switch (ret) { \ |
1bccec25 | 267 | case float_relation_unordered: \ |
7385aed2 RH |
268 | fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \ |
269 | fsr |= FSR_NVA; \ | |
1bccec25 BS |
270 | break; \ |
271 | case float_relation_less: \ | |
7385aed2 RH |
272 | fsr &= ~(FSR_FCC1) << FS; \ |
273 | fsr |= FSR_FCC0 << FS; \ | |
1bccec25 BS |
274 | break; \ |
275 | case float_relation_greater: \ | |
7385aed2 RH |
276 | fsr &= ~(FSR_FCC0) << FS; \ |
277 | fsr |= FSR_FCC1 << FS; \ | |
1bccec25 BS |
278 | break; \ |
279 | default: \ | |
7385aed2 | 280 | fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ |
1bccec25 BS |
281 | break; \ |
282 | } \ | |
7385aed2 | 283 | return fsr; \ |
1bccec25 | 284 | } |
03fb8cfc | 285 | #define GEN_FCMP_T(name, size, FS, E) \ |
7385aed2 | 286 | target_ulong glue(helper_, name)(CPUSPARCState *env, size src1, size src2)\ |
1bccec25 | 287 | { \ |
71bfd65c | 288 | FloatRelation ret; \ |
7385aed2 | 289 | target_ulong fsr; \ |
5acfc832 AJ |
290 | if (E) { \ |
291 | ret = glue(size, _compare)(src1, src2, &env->fp_status); \ | |
292 | } else { \ | |
293 | ret = glue(size, _compare_quiet)(src1, src2, \ | |
294 | &env->fp_status); \ | |
1bccec25 | 295 | } \ |
02c79d78 | 296 | fsr = do_check_ieee_exceptions(env, GETPC()); \ |
5acfc832 | 297 | switch (ret) { \ |
1bccec25 | 298 | case float_relation_unordered: \ |
7385aed2 | 299 | fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \ |
1bccec25 BS |
300 | break; \ |
301 | case float_relation_less: \ | |
7385aed2 RH |
302 | fsr &= ~(FSR_FCC1 << FS); \ |
303 | fsr |= FSR_FCC0 << FS; \ | |
1bccec25 BS |
304 | break; \ |
305 | case float_relation_greater: \ | |
7385aed2 RH |
306 | fsr &= ~(FSR_FCC0 << FS); \ |
307 | fsr |= FSR_FCC1 << FS; \ | |
1bccec25 BS |
308 | break; \ |
309 | default: \ | |
7385aed2 | 310 | fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ |
1bccec25 BS |
311 | break; \ |
312 | } \ | |
7385aed2 | 313 | return fsr; \ |
1bccec25 BS |
314 | } |
315 | ||
03fb8cfc RH |
316 | GEN_FCMP_T(fcmps, float32, 0, 0); |
317 | GEN_FCMP_T(fcmpd, float64, 0, 0); | |
1bccec25 | 318 | |
03fb8cfc RH |
319 | GEN_FCMP_T(fcmpes, float32, 0, 1); |
320 | GEN_FCMP_T(fcmped, float64, 0, 1); | |
1bccec25 | 321 | |
f3ceafad RH |
322 | GEN_FCMP(fcmpq, float128, 0, 0); |
323 | GEN_FCMP(fcmpeq, float128, 0, 1); | |
1bccec25 BS |
324 | |
325 | #ifdef TARGET_SPARC64 | |
03fb8cfc RH |
326 | GEN_FCMP_T(fcmps_fcc1, float32, 22, 0); |
327 | GEN_FCMP_T(fcmpd_fcc1, float64, 22, 0); | |
f3ceafad | 328 | GEN_FCMP(fcmpq_fcc1, float128, 22, 0); |
1bccec25 | 329 | |
03fb8cfc RH |
330 | GEN_FCMP_T(fcmps_fcc2, float32, 24, 0); |
331 | GEN_FCMP_T(fcmpd_fcc2, float64, 24, 0); | |
f3ceafad | 332 | GEN_FCMP(fcmpq_fcc2, float128, 24, 0); |
1bccec25 | 333 | |
03fb8cfc RH |
334 | GEN_FCMP_T(fcmps_fcc3, float32, 26, 0); |
335 | GEN_FCMP_T(fcmpd_fcc3, float64, 26, 0); | |
f3ceafad | 336 | GEN_FCMP(fcmpq_fcc3, float128, 26, 0); |
1bccec25 | 337 | |
03fb8cfc RH |
338 | GEN_FCMP_T(fcmpes_fcc1, float32, 22, 1); |
339 | GEN_FCMP_T(fcmped_fcc1, float64, 22, 1); | |
f3ceafad | 340 | GEN_FCMP(fcmpeq_fcc1, float128, 22, 1); |
1bccec25 | 341 | |
03fb8cfc RH |
342 | GEN_FCMP_T(fcmpes_fcc2, float32, 24, 1); |
343 | GEN_FCMP_T(fcmped_fcc2, float64, 24, 1); | |
f3ceafad | 344 | GEN_FCMP(fcmpeq_fcc2, float128, 24, 1); |
1bccec25 | 345 | |
03fb8cfc RH |
346 | GEN_FCMP_T(fcmpes_fcc3, float32, 26, 1); |
347 | GEN_FCMP_T(fcmped_fcc3, float64, 26, 1); | |
f3ceafad | 348 | GEN_FCMP(fcmpeq_fcc3, float128, 26, 1); |
1bccec25 | 349 | #endif |
03fb8cfc RH |
350 | #undef GEN_FCMP_T |
351 | #undef GEN_FCMP | |
1bccec25 | 352 | |
7385aed2 | 353 | static void set_fsr(CPUSPARCState *env, target_ulong fsr) |
1bccec25 BS |
354 | { |
355 | int rnd_mode; | |
356 | ||
7385aed2 | 357 | switch (fsr & FSR_RD_MASK) { |
1bccec25 BS |
358 | case FSR_RD_NEAREST: |
359 | rnd_mode = float_round_nearest_even; | |
360 | break; | |
361 | default: | |
362 | case FSR_RD_ZERO: | |
363 | rnd_mode = float_round_to_zero; | |
364 | break; | |
365 | case FSR_RD_POS: | |
366 | rnd_mode = float_round_up; | |
367 | break; | |
368 | case FSR_RD_NEG: | |
369 | rnd_mode = float_round_down; | |
370 | break; | |
371 | } | |
372 | set_float_rounding_mode(rnd_mode, &env->fp_status); | |
373 | } | |
374 | ||
da681406 | 375 | void helper_set_fsr(CPUSPARCState *env, target_ulong fsr) |
1bccec25 | 376 | { |
da681406 | 377 | set_fsr(env, fsr); |
1bccec25 | 378 | } |