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