Statistics
| Branch: | Revision:

root / target-s390x / fpu_helper.c @ f08a5c31

History | View | Annotate | Download (20.4 kB)

1
/*
2
 *  S/390 FPU helper routines
3
 *
4
 *  Copyright (c) 2009 Ulrich Hecht
5
 *  Copyright (c) 2009 Alexander Graf
6
 *
7
 * This library is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2 of the License, or (at your option) any later version.
11
 *
12
 * This library is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19
 */
20

    
21
#include "cpu.h"
22
#include "helper.h"
23

    
24
#if !defined(CONFIG_USER_ONLY)
25
#include "exec/softmmu_exec.h"
26
#endif
27

    
28
/* #define DEBUG_HELPER */
29
#ifdef DEBUG_HELPER
30
#define HELPER_LOG(x...) qemu_log(x)
31
#else
32
#define HELPER_LOG(x...)
33
#endif
34

    
35
#define RET128(F) (env->retxl = F.low, F.high)
36

    
37
#define convert_bit(mask, from, to) \
38
    (to < from                      \
39
     ? (mask / (from / to)) & to    \
40
     : (mask & from) * (to / from))
41

    
42
static void ieee_exception(CPUS390XState *env, uint32_t dxc, uintptr_t retaddr)
43
{
44
    /* Install the DXC code.  */
45
    env->fpc = (env->fpc & ~0xff00) | (dxc << 8);
46
    /* Trap.  */
47
    runtime_exception(env, PGM_DATA, retaddr);
48
}
49

    
50
/* Should be called after any operation that may raise IEEE exceptions.  */
51
static void handle_exceptions(CPUS390XState *env, uintptr_t retaddr)
52
{
53
    unsigned s390_exc, qemu_exc;
54

    
55
    /* Get the exceptions raised by the current operation.  Reset the
56
       fpu_status contents so that the next operation has a clean slate.  */
57
    qemu_exc = env->fpu_status.float_exception_flags;
58
    if (qemu_exc == 0) {
59
        return;
60
    }
61
    env->fpu_status.float_exception_flags = 0;
62

    
63
    /* Convert softfloat exception bits to s390 exception bits.  */
64
    s390_exc = 0;
65
    s390_exc |= convert_bit(qemu_exc, float_flag_invalid, 0x80);
66
    s390_exc |= convert_bit(qemu_exc, float_flag_divbyzero, 0x40);
67
    s390_exc |= convert_bit(qemu_exc, float_flag_overflow, 0x20);
68
    s390_exc |= convert_bit(qemu_exc, float_flag_underflow, 0x10);
69
    s390_exc |= convert_bit(qemu_exc, float_flag_inexact, 0x08);
70

    
71
    /* Install the exceptions that we raised.  */
72
    env->fpc |= s390_exc << 16;
73

    
74
    /* Send signals for enabled exceptions.  */
75
    s390_exc &= env->fpc >> 24;
76
    if (s390_exc) {
77
        ieee_exception(env, s390_exc, retaddr);
78
    }
79
}
80

    
81
static inline int float_comp_to_cc(CPUS390XState *env, int float_compare)
82
{
83
    switch (float_compare) {
84
    case float_relation_equal:
85
        return 0;
86
    case float_relation_less:
87
        return 1;
88
    case float_relation_greater:
89
        return 2;
90
    case float_relation_unordered:
91
        return 3;
92
    default:
93
        cpu_abort(env, "unknown return value for float compare\n");
94
    }
95
}
96

    
97
/* condition codes for unary FP ops */
98
uint32_t set_cc_nz_f32(float32 v)
99
{
100
    if (float32_is_any_nan(v)) {
101
        return 3;
102
    } else if (float32_is_zero(v)) {
103
        return 0;
104
    } else if (float32_is_neg(v)) {
105
        return 1;
106
    } else {
107
        return 2;
108
    }
109
}
110

    
111
uint32_t set_cc_nz_f64(float64 v)
112
{
113
    if (float64_is_any_nan(v)) {
114
        return 3;
115
    } else if (float64_is_zero(v)) {
116
        return 0;
117
    } else if (float64_is_neg(v)) {
118
        return 1;
119
    } else {
120
        return 2;
121
    }
122
}
123

    
124
uint32_t set_cc_nz_f128(float128 v)
125
{
126
    if (float128_is_any_nan(v)) {
127
        return 3;
128
    } else if (float128_is_zero(v)) {
129
        return 0;
130
    } else if (float128_is_neg(v)) {
131
        return 1;
132
    } else {
133
        return 2;
134
    }
135
}
136

    
137
/* convert 32-bit int to 64-bit float */
138
void HELPER(cdfbr)(CPUS390XState *env, uint32_t f1, int32_t v2)
139
{
140
    HELPER_LOG("%s: converting %d to f%d\n", __func__, v2, f1);
141
    env->fregs[f1].d = int32_to_float64(v2, &env->fpu_status);
142
}
143

    
144
/* convert 32-bit int to 128-bit float */
145
void HELPER(cxfbr)(CPUS390XState *env, uint32_t f1, int32_t v2)
146
{
147
    CPU_QuadU v1;
148

    
149
    v1.q = int32_to_float128(v2, &env->fpu_status);
150
    env->fregs[f1].ll = v1.ll.upper;
151
    env->fregs[f1 + 2].ll = v1.ll.lower;
152
}
153

    
154
/* convert 64-bit int to 32-bit float */
155
void HELPER(cegbr)(CPUS390XState *env, uint32_t f1, int64_t v2)
156
{
157
    HELPER_LOG("%s: converting %ld to f%d\n", __func__, v2, f1);
158
    env->fregs[f1].l.upper = int64_to_float32(v2, &env->fpu_status);
159
}
160

    
161
/* convert 64-bit int to 64-bit float */
162
void HELPER(cdgbr)(CPUS390XState *env, uint32_t f1, int64_t v2)
163
{
164
    HELPER_LOG("%s: converting %ld to f%d\n", __func__, v2, f1);
165
    env->fregs[f1].d = int64_to_float64(v2, &env->fpu_status);
166
}
167

    
168
/* convert 64-bit int to 128-bit float */
169
void HELPER(cxgbr)(CPUS390XState *env, uint32_t f1, int64_t v2)
170
{
171
    CPU_QuadU x1;
172

    
173
    x1.q = int64_to_float128(v2, &env->fpu_status);
174
    HELPER_LOG("%s: converted %ld to 0x%lx and 0x%lx\n", __func__, v2,
175
               x1.ll.upper, x1.ll.lower);
176
    env->fregs[f1].ll = x1.ll.upper;
177
    env->fregs[f1 + 2].ll = x1.ll.lower;
178
}
179

    
180
/* convert 32-bit int to 32-bit float */
181
void HELPER(cefbr)(CPUS390XState *env, uint32_t f1, int32_t v2)
182
{
183
    env->fregs[f1].l.upper = int32_to_float32(v2, &env->fpu_status);
184
    HELPER_LOG("%s: converting %d to 0x%d in f%d\n", __func__, v2,
185
               env->fregs[f1].l.upper, f1);
186
}
187

    
188
/* 32-bit FP addition */
189
uint64_t HELPER(aeb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
190
{
191
    float32 ret = float32_add(f1, f2, &env->fpu_status);
192
    handle_exceptions(env, GETPC());
193
    return ret;
194
}
195

    
196
/* 64-bit FP addition */
197
uint64_t HELPER(adb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
198
{
199
    float64 ret = float64_add(f1, f2, &env->fpu_status);
200
    handle_exceptions(env, GETPC());
201
    return ret;
202
}
203

    
204
/* 128-bit FP addition */
205
uint64_t HELPER(axb)(CPUS390XState *env, uint64_t ah, uint64_t al,
206
                     uint64_t bh, uint64_t bl)
207
{
208
    float128 ret = float128_add(make_float128(ah, al),
209
                                make_float128(bh, bl),
210
                                &env->fpu_status);
211
    handle_exceptions(env, GETPC());
212
    return RET128(ret);
213
}
214

    
215
/* 32-bit FP subtraction */
216
uint64_t HELPER(seb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
217
{
218
    float32 ret = float32_sub(f1, f2, &env->fpu_status);
219
    handle_exceptions(env, GETPC());
220
    return ret;
221
}
222

    
223
/* 64-bit FP subtraction */
224
uint64_t HELPER(sdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
225
{
226
    float64 ret = float64_sub(f1, f2, &env->fpu_status);
227
    handle_exceptions(env, GETPC());
228
    return ret;
229
}
230

    
231
/* 128-bit FP subtraction */
232
uint64_t HELPER(sxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
233
                     uint64_t bh, uint64_t bl)
234
{
235
    float128 ret = float128_sub(make_float128(ah, al),
236
                                make_float128(bh, bl),
237
                                &env->fpu_status);
238
    handle_exceptions(env, GETPC());
239
    return RET128(ret);
240
}
241

    
242
/* 32-bit FP division */
243
uint64_t HELPER(deb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
244
{
245
    float32 ret = float32_div(f1, f2, &env->fpu_status);
246
    handle_exceptions(env, GETPC());
247
    return ret;
248
}
249

    
250
/* 64-bit FP division */
251
uint64_t HELPER(ddb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
252
{
253
    float64 ret = float64_div(f1, f2, &env->fpu_status);
254
    handle_exceptions(env, GETPC());
255
    return ret;
256
}
257

    
258
/* 128-bit FP division */
259
uint64_t HELPER(dxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
260
                     uint64_t bh, uint64_t bl)
261
{
262
    float128 ret = float128_div(make_float128(ah, al),
263
                                make_float128(bh, bl),
264
                                &env->fpu_status);
265
    handle_exceptions(env, GETPC());
266
    return RET128(ret);
267
}
268

    
269
/* 64-bit FP multiplication RR */
270
void HELPER(mdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
271
{
272
    env->fregs[f1].d = float64_mul(env->fregs[f1].d, env->fregs[f2].d,
273
                                   &env->fpu_status);
274
}
275

    
276
/* 128-bit FP multiplication RR */
277
void HELPER(mxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
278
{
279
    CPU_QuadU v1;
280
    CPU_QuadU v2;
281
    CPU_QuadU res;
282

    
283
    v1.ll.upper = env->fregs[f1].ll;
284
    v1.ll.lower = env->fregs[f1 + 2].ll;
285
    v2.ll.upper = env->fregs[f2].ll;
286
    v2.ll.lower = env->fregs[f2 + 2].ll;
287
    res.q = float128_mul(v1.q, v2.q, &env->fpu_status);
288
    env->fregs[f1].ll = res.ll.upper;
289
    env->fregs[f1 + 2].ll = res.ll.lower;
290
}
291

    
292
/* convert 32-bit float to 64-bit float */
293
uint64_t HELPER(ldeb)(CPUS390XState *env, uint64_t f2)
294
{
295
    float64 ret = float32_to_float64(f2, &env->fpu_status);
296
    handle_exceptions(env, GETPC());
297
    return ret;
298
}
299

    
300
/* convert 128-bit float to 64-bit float */
301
uint64_t HELPER(ldxb)(CPUS390XState *env, uint64_t ah, uint64_t al)
302
{
303
    float64 ret = float128_to_float64(make_float128(ah, al), &env->fpu_status);
304
    handle_exceptions(env, GETPC());
305
    return ret;
306
}
307

    
308
/* convert 64-bit float to 128-bit float */
309
uint64_t HELPER(lxdb)(CPUS390XState *env, uint64_t f2)
310
{
311
    float128 ret = float64_to_float128(f2, &env->fpu_status);
312
    handle_exceptions(env, GETPC());
313
    return RET128(ret);
314
}
315

    
316
/* convert 32-bit float to 128-bit float */
317
uint64_t HELPER(lxeb)(CPUS390XState *env, uint64_t f2)
318
{
319
    float128 ret = float32_to_float128(f2, &env->fpu_status);
320
    handle_exceptions(env, GETPC());
321
    return RET128(ret);
322
}
323

    
324
/* convert 64-bit float to 32-bit float */
325
uint64_t HELPER(ledb)(CPUS390XState *env, uint64_t f2)
326
{
327
    float32 ret = float64_to_float32(f2, &env->fpu_status);
328
    handle_exceptions(env, GETPC());
329
    return ret;
330
}
331

    
332
/* convert 128-bit float to 32-bit float */
333
uint64_t HELPER(lexb)(CPUS390XState *env, uint64_t ah, uint64_t al)
334
{
335
    float32 ret = float128_to_float32(make_float128(ah, al), &env->fpu_status);
336
    handle_exceptions(env, GETPC());
337
    return ret;
338
}
339

    
340
/* absolute value of 32-bit float */
341
uint32_t HELPER(lpebr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
342
{
343
    float32 v1;
344
    float32 v2 = env->fregs[f2].d;
345

    
346
    v1 = float32_abs(v2);
347
    env->fregs[f1].d = v1;
348
    return set_cc_nz_f32(v1);
349
}
350

    
351
/* absolute value of 64-bit float */
352
uint32_t HELPER(lpdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
353
{
354
    float64 v1;
355
    float64 v2 = env->fregs[f2].d;
356

    
357
    v1 = float64_abs(v2);
358
    env->fregs[f1].d = v1;
359
    return set_cc_nz_f64(v1);
360
}
361

    
362
/* absolute value of 128-bit float */
363
uint32_t HELPER(lpxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
364
{
365
    CPU_QuadU v1;
366
    CPU_QuadU v2;
367

    
368
    v2.ll.upper = env->fregs[f2].ll;
369
    v2.ll.lower = env->fregs[f2 + 2].ll;
370
    v1.q = float128_abs(v2.q);
371
    env->fregs[f1].ll = v1.ll.upper;
372
    env->fregs[f1 + 2].ll = v1.ll.lower;
373
    return set_cc_nz_f128(v1.q);
374
}
375

    
376
/* load complement of 32-bit float */
377
uint32_t HELPER(lcebr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
378
{
379
    env->fregs[f1].l.upper = float32_chs(env->fregs[f2].l.upper);
380

    
381
    return set_cc_nz_f32(env->fregs[f1].l.upper);
382
}
383

    
384
/* load complement of 64-bit float */
385
uint32_t HELPER(lcdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
386
{
387
    env->fregs[f1].d = float64_chs(env->fregs[f2].d);
388

    
389
    return set_cc_nz_f64(env->fregs[f1].d);
390
}
391

    
392
/* load complement of 128-bit float */
393
uint32_t HELPER(lcxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
394
{
395
    CPU_QuadU x1, x2;
396

    
397
    x2.ll.upper = env->fregs[f2].ll;
398
    x2.ll.lower = env->fregs[f2 + 2].ll;
399
    x1.q = float128_chs(x2.q);
400
    env->fregs[f1].ll = x1.ll.upper;
401
    env->fregs[f1 + 2].ll = x1.ll.lower;
402
    return set_cc_nz_f128(x1.q);
403
}
404

    
405
/* 32-bit FP multiplication RM */
406
void HELPER(meeb)(CPUS390XState *env, uint32_t f1, uint32_t val)
407
{
408
    float32 v1 = env->fregs[f1].l.upper;
409
    CPU_FloatU v2;
410

    
411
    v2.l = val;
412
    HELPER_LOG("%s: multiplying 0x%d from f%d and 0x%d\n", __func__,
413
               v1, f1, v2.f);
414
    env->fregs[f1].l.upper = float32_mul(v1, v2.f, &env->fpu_status);
415
}
416

    
417
/* 32-bit FP compare */
418
uint32_t HELPER(ceb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
419
{
420
    int cmp = float32_compare_quiet(f1, f2, &env->fpu_status);
421
    handle_exceptions(env, GETPC());
422
    return float_comp_to_cc(env, cmp);
423
}
424

    
425
/* 64-bit FP compare */
426
uint32_t HELPER(cdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
427
{
428
    int cmp = float64_compare_quiet(f1, f2, &env->fpu_status);
429
    handle_exceptions(env, GETPC());
430
    return float_comp_to_cc(env, cmp);
431
}
432

    
433
/* 128-bit FP compare */
434
uint32_t HELPER(cxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
435
                     uint64_t bh, uint64_t bl)
436
{
437
    int cmp = float128_compare_quiet(make_float128(ah, al),
438
                                     make_float128(bh, bl),
439
                                     &env->fpu_status);
440
    handle_exceptions(env, GETPC());
441
    return float_comp_to_cc(env, cmp);
442
}
443

    
444
/* 64-bit FP multiplication RM */
445
void HELPER(mdb)(CPUS390XState *env, uint32_t f1, uint64_t a2)
446
{
447
    float64 v1 = env->fregs[f1].d;
448
    CPU_DoubleU v2;
449

    
450
    v2.ll = cpu_ldq_data(env, a2);
451
    HELPER_LOG("%s: multiplying 0x%lx from f%d and 0x%ld\n", __func__,
452
               v1, f1, v2.d);
453
    env->fregs[f1].d = float64_mul(v1, v2.d, &env->fpu_status);
454
}
455

    
456
static void set_round_mode(CPUS390XState *env, int m3)
457
{
458
    switch (m3) {
459
    case 0:
460
        /* current mode */
461
        break;
462
    case 1:
463
        /* biased round no nearest */
464
    case 4:
465
        /* round to nearest */
466
        set_float_rounding_mode(float_round_nearest_even, &env->fpu_status);
467
        break;
468
    case 5:
469
        /* round to zero */
470
        set_float_rounding_mode(float_round_to_zero, &env->fpu_status);
471
        break;
472
    case 6:
473
        /* round to +inf */
474
        set_float_rounding_mode(float_round_up, &env->fpu_status);
475
        break;
476
    case 7:
477
        /* round to -inf */
478
        set_float_rounding_mode(float_round_down, &env->fpu_status);
479
        break;
480
    }
481
}
482

    
483
/* convert 32-bit float to 64-bit int */
484
uint32_t HELPER(cgebr)(CPUS390XState *env, uint32_t r1, uint32_t f2,
485
                       uint32_t m3)
486
{
487
    float32 v2 = env->fregs[f2].l.upper;
488

    
489
    set_round_mode(env, m3);
490
    env->regs[r1] = float32_to_int64(v2, &env->fpu_status);
491
    return set_cc_nz_f32(v2);
492
}
493

    
494
/* convert 64-bit float to 64-bit int */
495
uint32_t HELPER(cgdbr)(CPUS390XState *env, uint32_t r1, uint32_t f2,
496
                       uint32_t m3)
497
{
498
    float64 v2 = env->fregs[f2].d;
499

    
500
    set_round_mode(env, m3);
501
    env->regs[r1] = float64_to_int64(v2, &env->fpu_status);
502
    return set_cc_nz_f64(v2);
503
}
504

    
505
/* convert 128-bit float to 64-bit int */
506
uint32_t HELPER(cgxbr)(CPUS390XState *env, uint32_t r1, uint32_t f2,
507
                       uint32_t m3)
508
{
509
    CPU_QuadU v2;
510

    
511
    v2.ll.upper = env->fregs[f2].ll;
512
    v2.ll.lower = env->fregs[f2 + 2].ll;
513
    set_round_mode(env, m3);
514
    env->regs[r1] = float128_to_int64(v2.q, &env->fpu_status);
515
    if (float128_is_any_nan(v2.q)) {
516
        return 3;
517
    } else if (float128_is_zero(v2.q)) {
518
        return 0;
519
    } else if (float128_is_neg(v2.q)) {
520
        return 1;
521
    } else {
522
        return 2;
523
    }
524
}
525

    
526
/* convert 32-bit float to 32-bit int */
527
uint32_t HELPER(cfebr)(CPUS390XState *env, uint32_t r1, uint32_t f2,
528
                       uint32_t m3)
529
{
530
    float32 v2 = env->fregs[f2].l.upper;
531

    
532
    set_round_mode(env, m3);
533
    env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
534
        float32_to_int32(v2, &env->fpu_status);
535
    return set_cc_nz_f32(v2);
536
}
537

    
538
/* convert 64-bit float to 32-bit int */
539
uint32_t HELPER(cfdbr)(CPUS390XState *env, uint32_t r1, uint32_t f2,
540
                       uint32_t m3)
541
{
542
    float64 v2 = env->fregs[f2].d;
543

    
544
    set_round_mode(env, m3);
545
    env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
546
        float64_to_int32(v2, &env->fpu_status);
547
    return set_cc_nz_f64(v2);
548
}
549

    
550
/* convert 128-bit float to 32-bit int */
551
uint32_t HELPER(cfxbr)(CPUS390XState *env, uint32_t r1, uint32_t f2,
552
                       uint32_t m3)
553
{
554
    CPU_QuadU v2;
555

    
556
    v2.ll.upper = env->fregs[f2].ll;
557
    v2.ll.lower = env->fregs[f2 + 2].ll;
558
    env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) |
559
        float128_to_int32(v2.q, &env->fpu_status);
560
    return set_cc_nz_f128(v2.q);
561
}
562

    
563
/* load 32-bit FP zero */
564
void HELPER(lzer)(CPUS390XState *env, uint32_t f1)
565
{
566
    env->fregs[f1].l.upper = float32_zero;
567
}
568

    
569
/* load 64-bit FP zero */
570
void HELPER(lzdr)(CPUS390XState *env, uint32_t f1)
571
{
572
    env->fregs[f1].d = float64_zero;
573
}
574

    
575
/* load 128-bit FP zero */
576
void HELPER(lzxr)(CPUS390XState *env, uint32_t f1)
577
{
578
    CPU_QuadU x;
579

    
580
    x.q = float64_to_float128(float64_zero, &env->fpu_status);
581
    env->fregs[f1].ll = x.ll.upper;
582
    env->fregs[f1 + 1].ll = x.ll.lower;
583
}
584

    
585
/* 32-bit FP multiplication RR */
586
void HELPER(meebr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
587
{
588
    env->fregs[f1].l.upper = float32_mul(env->fregs[f1].l.upper,
589
                                         env->fregs[f2].l.upper,
590
                                         &env->fpu_status);
591
}
592

    
593
/* 64-bit FP multiply and add RM */
594
void HELPER(madb)(CPUS390XState *env, uint32_t f1, uint64_t a2, uint32_t f3)
595
{
596
    CPU_DoubleU v2;
597

    
598
    HELPER_LOG("%s: f1 %d a2 0x%lx f3 %d\n", __func__, f1, a2, f3);
599
    v2.ll = cpu_ldq_data(env, a2);
600
    env->fregs[f1].d = float64_add(env->fregs[f1].d,
601
                                   float64_mul(v2.d, env->fregs[f3].d,
602
                                               &env->fpu_status),
603
                                   &env->fpu_status);
604
}
605

    
606
/* 64-bit FP multiply and add RR */
607
void HELPER(madbr)(CPUS390XState *env, uint32_t f1, uint32_t f3, uint32_t f2)
608
{
609
    HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __func__, f1, f2, f3);
610
    env->fregs[f1].d = float64_add(float64_mul(env->fregs[f2].d,
611
                                               env->fregs[f3].d,
612
                                               &env->fpu_status),
613
                                   env->fregs[f1].d, &env->fpu_status);
614
}
615

    
616
/* 64-bit FP multiply and subtract RR */
617
void HELPER(msdbr)(CPUS390XState *env, uint32_t f1, uint32_t f3, uint32_t f2)
618
{
619
    HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __func__, f1, f2, f3);
620
    env->fregs[f1].d = float64_sub(float64_mul(env->fregs[f2].d,
621
                                               env->fregs[f3].d,
622
                                               &env->fpu_status),
623
                                   env->fregs[f1].d, &env->fpu_status);
624
}
625

    
626
/* 32-bit FP multiply and add RR */
627
void HELPER(maebr)(CPUS390XState *env, uint32_t f1, uint32_t f3, uint32_t f2)
628
{
629
    env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper,
630
                                         float32_mul(env->fregs[f2].l.upper,
631
                                                     env->fregs[f3].l.upper,
632
                                                     &env->fpu_status),
633
                                         &env->fpu_status);
634
}
635

    
636
/* test data class 32-bit */
637
uint32_t HELPER(tceb)(CPUS390XState *env, uint32_t f1, uint64_t m2)
638
{
639
    float32 v1 = env->fregs[f1].l.upper;
640
    int neg = float32_is_neg(v1);
641
    uint32_t cc = 0;
642

    
643
    HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __func__, (long)v1, m2, neg);
644
    if ((float32_is_zero(v1) && (m2 & (1 << (11-neg)))) ||
645
        (float32_is_infinity(v1) && (m2 & (1 << (5-neg)))) ||
646
        (float32_is_any_nan(v1) && (m2 & (1 << (3-neg)))) ||
647
        (float32_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) {
648
        cc = 1;
649
    } else if (m2 & (1 << (9-neg))) {
650
        /* assume normalized number */
651
        cc = 1;
652
    }
653

    
654
    /* FIXME: denormalized? */
655
    return cc;
656
}
657

    
658
/* test data class 64-bit */
659
uint32_t HELPER(tcdb)(CPUS390XState *env, uint32_t f1, uint64_t m2)
660
{
661
    float64 v1 = env->fregs[f1].d;
662
    int neg = float64_is_neg(v1);
663
    uint32_t cc = 0;
664

    
665
    HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __func__, v1, m2, neg);
666
    if ((float64_is_zero(v1) && (m2 & (1 << (11-neg)))) ||
667
        (float64_is_infinity(v1) && (m2 & (1 << (5-neg)))) ||
668
        (float64_is_any_nan(v1) && (m2 & (1 << (3-neg)))) ||
669
        (float64_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) {
670
        cc = 1;
671
    } else if (m2 & (1 << (9-neg))) {
672
        /* assume normalized number */
673
        cc = 1;
674
    }
675
    /* FIXME: denormalized? */
676
    return cc;
677
}
678

    
679
/* test data class 128-bit */
680
uint32_t HELPER(tcxb)(CPUS390XState *env, uint32_t f1, uint64_t m2)
681
{
682
    CPU_QuadU v1;
683
    uint32_t cc = 0;
684
    int neg;
685

    
686
    v1.ll.upper = env->fregs[f1].ll;
687
    v1.ll.lower = env->fregs[f1 + 2].ll;
688

    
689
    neg = float128_is_neg(v1.q);
690
    if ((float128_is_zero(v1.q) && (m2 & (1 << (11-neg)))) ||
691
        (float128_is_infinity(v1.q) && (m2 & (1 << (5-neg)))) ||
692
        (float128_is_any_nan(v1.q) && (m2 & (1 << (3-neg)))) ||
693
        (float128_is_signaling_nan(v1.q) && (m2 & (1 << (1-neg))))) {
694
        cc = 1;
695
    } else if (m2 & (1 << (9-neg))) {
696
        /* assume normalized number */
697
        cc = 1;
698
    }
699
    /* FIXME: denormalized? */
700
    return cc;
701
}
702

    
703
/* square root 64-bit RR */
704
void HELPER(sqdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)
705
{
706
    env->fregs[f1].d = float64_sqrt(env->fregs[f2].d, &env->fpu_status);
707
}