~ahs3/+junk/cq-qemu

« back to all changes in this revision

Viewing changes to target-sparc/fop_helper.c

  • Committer: Al Stone
  • Date: 2012-02-09 01:17:20 UTC
  • Revision ID: albert.stone@canonical.com-20120209011720-tztl7ik3qayz80p4
first commit to bzr for qemu

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 "helper.h"
 
22
 
 
23
#define QT0 (env->qt0)
 
24
#define QT1 (env->qt1)
 
25
 
 
26
static void check_ieee_exceptions(CPUState *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(CPUState *env)
 
61
{
 
62
    set_float_exception_flags(0, &env->fp_status);
 
63
}
 
64
 
 
65
#define F_HELPER(name, p) void helper_f##name##p(CPUState *env)
 
66
 
 
67
#define F_BINOP(name)                                           \
 
68
    float32 helper_f ## name ## s (CPUState *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 (CPUState * 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(CPUState *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(CPUState *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(CPUState *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(CPUState *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(CPUState *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(CPUState *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(CPUState *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(CPUState *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(CPUState *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(CPUState *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(CPUState *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(CPUState *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(CPUState *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(CPUState *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(CPUState *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(CPUState *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(CPUState *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(CPUState *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(CPUState *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(CPUState *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(CPUState *env)
 
306
{
 
307
    QT0 = float128_abs(QT1);
 
308
}
 
309
#endif
 
310
 
 
311
float32 helper_fsqrts(CPUState *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(CPUState *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(CPUState *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) (CPUState *env)                            \
 
338
    {                                                                   \
 
339
        env->fsr &= FSR_FTT_NMASK;                                      \
 
340
        if (E && (glue(size, _is_any_nan)(reg1) ||                      \
 
341
                  glue(size, _is_any_nan)(reg2)) &&                     \
 
342
            (env->fsr & FSR_NVM)) {                                     \
 
343
            env->fsr |= FSR_NVC;                                        \
 
344
            env->fsr |= FSR_FTT_IEEE_EXCP;                              \
 
345
            helper_raise_exception(env, TT_FP_EXCP);                    \
 
346
        }                                                               \
 
347
        switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) {   \
 
348
        case float_relation_unordered:                                  \
 
349
            if ((env->fsr & FSR_NVM)) {                                 \
 
350
                env->fsr |= FSR_NVC;                                    \
 
351
                env->fsr |= FSR_FTT_IEEE_EXCP;                          \
 
352
                helper_raise_exception(env, TT_FP_EXCP);                \
 
353
            } else {                                                    \
 
354
                env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);             \
 
355
                env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS;                \
 
356
                env->fsr |= FSR_NVA;                                    \
 
357
            }                                                           \
 
358
            break;                                                      \
 
359
        case float_relation_less:                                       \
 
360
            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
 
361
            env->fsr |= FSR_FCC0 << FS;                                 \
 
362
            break;                                                      \
 
363
        case float_relation_greater:                                    \
 
364
            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
 
365
            env->fsr |= FSR_FCC1 << FS;                                 \
 
366
            break;                                                      \
 
367
        default:                                                        \
 
368
            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
 
369
            break;                                                      \
 
370
        }                                                               \
 
371
    }
 
372
#define GEN_FCMP_T(name, size, FS, E)                                   \
 
373
    void glue(helper_, name)(CPUState *env, size src1, size src2)       \
 
374
    {                                                                   \
 
375
        env->fsr &= FSR_FTT_NMASK;                                      \
 
376
        if (E && (glue(size, _is_any_nan)(src1) ||                      \
 
377
                  glue(size, _is_any_nan)(src2)) &&                     \
 
378
            (env->fsr & FSR_NVM)) {                                     \
 
379
            env->fsr |= FSR_NVC;                                        \
 
380
            env->fsr |= FSR_FTT_IEEE_EXCP;                              \
 
381
            helper_raise_exception(env, TT_FP_EXCP);                    \
 
382
        }                                                               \
 
383
        switch (glue(size, _compare) (src1, src2, &env->fp_status)) {   \
 
384
        case float_relation_unordered:                                  \
 
385
            if ((env->fsr & FSR_NVM)) {                                 \
 
386
                env->fsr |= FSR_NVC;                                    \
 
387
                env->fsr |= FSR_FTT_IEEE_EXCP;                          \
 
388
                helper_raise_exception(env, TT_FP_EXCP);                \
 
389
            } else {                                                    \
 
390
                env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);             \
 
391
                env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS;                \
 
392
                env->fsr |= FSR_NVA;                                    \
 
393
            }                                                           \
 
394
            break;                                                      \
 
395
        case float_relation_less:                                       \
 
396
            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
 
397
            env->fsr |= FSR_FCC0 << FS;                                 \
 
398
            break;                                                      \
 
399
        case float_relation_greater:                                    \
 
400
            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
 
401
            env->fsr |= FSR_FCC1 << FS;                                 \
 
402
            break;                                                      \
 
403
        default:                                                        \
 
404
            env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                 \
 
405
            break;                                                      \
 
406
        }                                                               \
 
407
    }
 
408
 
 
409
GEN_FCMP_T(fcmps, float32, 0, 0);
 
410
GEN_FCMP_T(fcmpd, float64, 0, 0);
 
411
 
 
412
GEN_FCMP_T(fcmpes, float32, 0, 1);
 
413
GEN_FCMP_T(fcmped, float64, 0, 1);
 
414
 
 
415
GEN_FCMP(fcmpq, float128, QT0, QT1, 0, 0);
 
416
GEN_FCMP(fcmpeq, float128, QT0, QT1, 0, 1);
 
417
 
 
418
#ifdef TARGET_SPARC64
 
419
GEN_FCMP_T(fcmps_fcc1, float32, 22, 0);
 
420
GEN_FCMP_T(fcmpd_fcc1, float64, 22, 0);
 
421
GEN_FCMP(fcmpq_fcc1, float128, QT0, QT1, 22, 0);
 
422
 
 
423
GEN_FCMP_T(fcmps_fcc2, float32, 24, 0);
 
424
GEN_FCMP_T(fcmpd_fcc2, float64, 24, 0);
 
425
GEN_FCMP(fcmpq_fcc2, float128, QT0, QT1, 24, 0);
 
426
 
 
427
GEN_FCMP_T(fcmps_fcc3, float32, 26, 0);
 
428
GEN_FCMP_T(fcmpd_fcc3, float64, 26, 0);
 
429
GEN_FCMP(fcmpq_fcc3, float128, QT0, QT1, 26, 0);
 
430
 
 
431
GEN_FCMP_T(fcmpes_fcc1, float32, 22, 1);
 
432
GEN_FCMP_T(fcmped_fcc1, float64, 22, 1);
 
433
GEN_FCMP(fcmpeq_fcc1, float128, QT0, QT1, 22, 1);
 
434
 
 
435
GEN_FCMP_T(fcmpes_fcc2, float32, 24, 1);
 
436
GEN_FCMP_T(fcmped_fcc2, float64, 24, 1);
 
437
GEN_FCMP(fcmpeq_fcc2, float128, QT0, QT1, 24, 1);
 
438
 
 
439
GEN_FCMP_T(fcmpes_fcc3, float32, 26, 1);
 
440
GEN_FCMP_T(fcmped_fcc3, float64, 26, 1);
 
441
GEN_FCMP(fcmpeq_fcc3, float128, QT0, QT1, 26, 1);
 
442
#endif
 
443
#undef GEN_FCMP_T
 
444
#undef GEN_FCMP
 
445
 
 
446
static inline void set_fsr(CPUState *env)
 
447
{
 
448
    int rnd_mode;
 
449
 
 
450
    switch (env->fsr & FSR_RD_MASK) {
 
451
    case FSR_RD_NEAREST:
 
452
        rnd_mode = float_round_nearest_even;
 
453
        break;
 
454
    default:
 
455
    case FSR_RD_ZERO:
 
456
        rnd_mode = float_round_to_zero;
 
457
        break;
 
458
    case FSR_RD_POS:
 
459
        rnd_mode = float_round_up;
 
460
        break;
 
461
    case FSR_RD_NEG:
 
462
        rnd_mode = float_round_down;
 
463
        break;
 
464
    }
 
465
    set_float_rounding_mode(rnd_mode, &env->fp_status);
 
466
}
 
467
 
 
468
void helper_ldfsr(CPUState *env, uint32_t new_fsr)
 
469
{
 
470
    env->fsr = (new_fsr & FSR_LDFSR_MASK) | (env->fsr & FSR_LDFSR_OLDMASK);
 
471
    set_fsr(env);
 
472
}
 
473
 
 
474
#ifdef TARGET_SPARC64
 
475
void helper_ldxfsr(CPUState *env, uint64_t new_fsr)
 
476
{
 
477
    env->fsr = (new_fsr & FSR_LDXFSR_MASK) | (env->fsr & FSR_LDXFSR_OLDMASK);
 
478
    set_fsr(env);
 
479
}
 
480
#endif