]> Git Repo - qemu.git/blob - target/s390x/fpu_helper.c
s390x/tcg: Fix TEST DATA CLASS instructions
[qemu.git] / target / s390x / fpu_helper.c
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.1 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 "qemu/osdep.h"
22 #include "cpu.h"
23 #include "internal.h"
24 #include "tcg_s390x.h"
25 #include "exec/exec-all.h"
26 #include "exec/cpu_ldst.h"
27 #include "exec/helper-proto.h"
28 #include "fpu/softfloat.h"
29
30 /* #define DEBUG_HELPER */
31 #ifdef DEBUG_HELPER
32 #define HELPER_LOG(x...) qemu_log(x)
33 #else
34 #define HELPER_LOG(x...)
35 #endif
36
37 #define RET128(F) (env->retxl = F.low, F.high)
38
39 #define convert_bit(mask, from, to) \
40     (to < from                      \
41      ? (mask / (from / to)) & to    \
42      : (mask & from) * (to / from))
43
44 /* Should be called after any operation that may raise IEEE exceptions.  */
45 static void handle_exceptions(CPUS390XState *env, uintptr_t retaddr)
46 {
47     unsigned s390_exc, qemu_exc;
48
49     /* Get the exceptions raised by the current operation.  Reset the
50        fpu_status contents so that the next operation has a clean slate.  */
51     qemu_exc = env->fpu_status.float_exception_flags;
52     if (qemu_exc == 0) {
53         return;
54     }
55     env->fpu_status.float_exception_flags = 0;
56
57     /* Convert softfloat exception bits to s390 exception bits.  */
58     s390_exc = 0;
59     s390_exc |= convert_bit(qemu_exc, float_flag_invalid, 0x80);
60     s390_exc |= convert_bit(qemu_exc, float_flag_divbyzero, 0x40);
61     s390_exc |= convert_bit(qemu_exc, float_flag_overflow, 0x20);
62     s390_exc |= convert_bit(qemu_exc, float_flag_underflow, 0x10);
63     s390_exc |= convert_bit(qemu_exc, float_flag_inexact, 0x08);
64
65     /* Install the exceptions that we raised.  */
66     env->fpc |= s390_exc << 16;
67
68     /* Send signals for enabled exceptions.  */
69     s390_exc &= env->fpc >> 24;
70     if (s390_exc) {
71         tcg_s390_data_exception(env, s390_exc, retaddr);
72     }
73 }
74
75 static inline int float_comp_to_cc(CPUS390XState *env, int float_compare)
76 {
77     S390CPU *cpu = s390_env_get_cpu(env);
78
79     switch (float_compare) {
80     case float_relation_equal:
81         return 0;
82     case float_relation_less:
83         return 1;
84     case float_relation_greater:
85         return 2;
86     case float_relation_unordered:
87         return 3;
88     default:
89         cpu_abort(CPU(cpu), "unknown return value for float compare\n");
90     }
91 }
92
93 /* condition codes for unary FP ops */
94 uint32_t set_cc_nz_f32(float32 v)
95 {
96     if (float32_is_any_nan(v)) {
97         return 3;
98     } else if (float32_is_zero(v)) {
99         return 0;
100     } else if (float32_is_neg(v)) {
101         return 1;
102     } else {
103         return 2;
104     }
105 }
106
107 uint32_t set_cc_nz_f64(float64 v)
108 {
109     if (float64_is_any_nan(v)) {
110         return 3;
111     } else if (float64_is_zero(v)) {
112         return 0;
113     } else if (float64_is_neg(v)) {
114         return 1;
115     } else {
116         return 2;
117     }
118 }
119
120 uint32_t set_cc_nz_f128(float128 v)
121 {
122     if (float128_is_any_nan(v)) {
123         return 3;
124     } else if (float128_is_zero(v)) {
125         return 0;
126     } else if (float128_is_neg(v)) {
127         return 1;
128     } else {
129         return 2;
130     }
131 }
132
133 /* 32-bit FP addition */
134 uint64_t HELPER(aeb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
135 {
136     float32 ret = float32_add(f1, f2, &env->fpu_status);
137     handle_exceptions(env, GETPC());
138     return ret;
139 }
140
141 /* 64-bit FP addition */
142 uint64_t HELPER(adb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
143 {
144     float64 ret = float64_add(f1, f2, &env->fpu_status);
145     handle_exceptions(env, GETPC());
146     return ret;
147 }
148
149 /* 128-bit FP addition */
150 uint64_t HELPER(axb)(CPUS390XState *env, uint64_t ah, uint64_t al,
151                      uint64_t bh, uint64_t bl)
152 {
153     float128 ret = float128_add(make_float128(ah, al),
154                                 make_float128(bh, bl),
155                                 &env->fpu_status);
156     handle_exceptions(env, GETPC());
157     return RET128(ret);
158 }
159
160 /* 32-bit FP subtraction */
161 uint64_t HELPER(seb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
162 {
163     float32 ret = float32_sub(f1, f2, &env->fpu_status);
164     handle_exceptions(env, GETPC());
165     return ret;
166 }
167
168 /* 64-bit FP subtraction */
169 uint64_t HELPER(sdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
170 {
171     float64 ret = float64_sub(f1, f2, &env->fpu_status);
172     handle_exceptions(env, GETPC());
173     return ret;
174 }
175
176 /* 128-bit FP subtraction */
177 uint64_t HELPER(sxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
178                      uint64_t bh, uint64_t bl)
179 {
180     float128 ret = float128_sub(make_float128(ah, al),
181                                 make_float128(bh, bl),
182                                 &env->fpu_status);
183     handle_exceptions(env, GETPC());
184     return RET128(ret);
185 }
186
187 /* 32-bit FP division */
188 uint64_t HELPER(deb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
189 {
190     float32 ret = float32_div(f1, f2, &env->fpu_status);
191     handle_exceptions(env, GETPC());
192     return ret;
193 }
194
195 /* 64-bit FP division */
196 uint64_t HELPER(ddb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
197 {
198     float64 ret = float64_div(f1, f2, &env->fpu_status);
199     handle_exceptions(env, GETPC());
200     return ret;
201 }
202
203 /* 128-bit FP division */
204 uint64_t HELPER(dxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
205                      uint64_t bh, uint64_t bl)
206 {
207     float128 ret = float128_div(make_float128(ah, al),
208                                 make_float128(bh, bl),
209                                 &env->fpu_status);
210     handle_exceptions(env, GETPC());
211     return RET128(ret);
212 }
213
214 /* 32-bit FP multiplication */
215 uint64_t HELPER(meeb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
216 {
217     float32 ret = float32_mul(f1, f2, &env->fpu_status);
218     handle_exceptions(env, GETPC());
219     return ret;
220 }
221
222 /* 64-bit FP multiplication */
223 uint64_t HELPER(mdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
224 {
225     float64 ret = float64_mul(f1, f2, &env->fpu_status);
226     handle_exceptions(env, GETPC());
227     return ret;
228 }
229
230 /* 64/32-bit FP multiplication */
231 uint64_t HELPER(mdeb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
232 {
233     float64 ret = float32_to_float64(f2, &env->fpu_status);
234     ret = float64_mul(f1, ret, &env->fpu_status);
235     handle_exceptions(env, GETPC());
236     return ret;
237 }
238
239 /* 128-bit FP multiplication */
240 uint64_t HELPER(mxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
241                      uint64_t bh, uint64_t bl)
242 {
243     float128 ret = float128_mul(make_float128(ah, al),
244                                 make_float128(bh, bl),
245                                 &env->fpu_status);
246     handle_exceptions(env, GETPC());
247     return RET128(ret);
248 }
249
250 /* 128/64-bit FP multiplication */
251 uint64_t HELPER(mxdb)(CPUS390XState *env, uint64_t ah, uint64_t al,
252                       uint64_t f2)
253 {
254     float128 ret = float64_to_float128(f2, &env->fpu_status);
255     ret = float128_mul(make_float128(ah, al), ret, &env->fpu_status);
256     handle_exceptions(env, GETPC());
257     return RET128(ret);
258 }
259
260 /* convert 32-bit float to 64-bit float */
261 uint64_t HELPER(ldeb)(CPUS390XState *env, uint64_t f2)
262 {
263     float64 ret = float32_to_float64(f2, &env->fpu_status);
264     handle_exceptions(env, GETPC());
265     return ret;
266 }
267
268 /* convert 128-bit float to 64-bit float */
269 uint64_t HELPER(ldxb)(CPUS390XState *env, uint64_t ah, uint64_t al)
270 {
271     float64 ret = float128_to_float64(make_float128(ah, al), &env->fpu_status);
272     handle_exceptions(env, GETPC());
273     return ret;
274 }
275
276 /* convert 64-bit float to 128-bit float */
277 uint64_t HELPER(lxdb)(CPUS390XState *env, uint64_t f2)
278 {
279     float128 ret = float64_to_float128(f2, &env->fpu_status);
280     handle_exceptions(env, GETPC());
281     return RET128(ret);
282 }
283
284 /* convert 32-bit float to 128-bit float */
285 uint64_t HELPER(lxeb)(CPUS390XState *env, uint64_t f2)
286 {
287     float128 ret = float32_to_float128(f2, &env->fpu_status);
288     handle_exceptions(env, GETPC());
289     return RET128(ret);
290 }
291
292 /* convert 64-bit float to 32-bit float */
293 uint64_t HELPER(ledb)(CPUS390XState *env, uint64_t f2)
294 {
295     float32 ret = float64_to_float32(f2, &env->fpu_status);
296     handle_exceptions(env, GETPC());
297     return ret;
298 }
299
300 /* convert 128-bit float to 32-bit float */
301 uint64_t HELPER(lexb)(CPUS390XState *env, uint64_t ah, uint64_t al)
302 {
303     float32 ret = float128_to_float32(make_float128(ah, al), &env->fpu_status);
304     handle_exceptions(env, GETPC());
305     return ret;
306 }
307
308 /* 32-bit FP compare */
309 uint32_t HELPER(ceb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
310 {
311     int cmp = float32_compare_quiet(f1, f2, &env->fpu_status);
312     handle_exceptions(env, GETPC());
313     return float_comp_to_cc(env, cmp);
314 }
315
316 /* 64-bit FP compare */
317 uint32_t HELPER(cdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
318 {
319     int cmp = float64_compare_quiet(f1, f2, &env->fpu_status);
320     handle_exceptions(env, GETPC());
321     return float_comp_to_cc(env, cmp);
322 }
323
324 /* 128-bit FP compare */
325 uint32_t HELPER(cxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
326                      uint64_t bh, uint64_t bl)
327 {
328     int cmp = float128_compare_quiet(make_float128(ah, al),
329                                      make_float128(bh, bl),
330                                      &env->fpu_status);
331     handle_exceptions(env, GETPC());
332     return float_comp_to_cc(env, cmp);
333 }
334
335 static int swap_round_mode(CPUS390XState *env, int m3)
336 {
337     int ret = env->fpu_status.float_rounding_mode;
338     switch (m3) {
339     case 0:
340         /* current mode */
341         break;
342     case 1:
343         /* biased round no nearest */
344     case 4:
345         /* round to nearest */
346         set_float_rounding_mode(float_round_nearest_even, &env->fpu_status);
347         break;
348     case 5:
349         /* round to zero */
350         set_float_rounding_mode(float_round_to_zero, &env->fpu_status);
351         break;
352     case 6:
353         /* round to +inf */
354         set_float_rounding_mode(float_round_up, &env->fpu_status);
355         break;
356     case 7:
357         /* round to -inf */
358         set_float_rounding_mode(float_round_down, &env->fpu_status);
359         break;
360     }
361     return ret;
362 }
363
364 /* convert 64-bit int to 32-bit float */
365 uint64_t HELPER(cegb)(CPUS390XState *env, int64_t v2, uint32_t m3)
366 {
367     int hold = swap_round_mode(env, m3);
368     float32 ret = int64_to_float32(v2, &env->fpu_status);
369     set_float_rounding_mode(hold, &env->fpu_status);
370     handle_exceptions(env, GETPC());
371     return ret;
372 }
373
374 /* convert 64-bit int to 64-bit float */
375 uint64_t HELPER(cdgb)(CPUS390XState *env, int64_t v2, uint32_t m3)
376 {
377     int hold = swap_round_mode(env, m3);
378     float64 ret = int64_to_float64(v2, &env->fpu_status);
379     set_float_rounding_mode(hold, &env->fpu_status);
380     handle_exceptions(env, GETPC());
381     return ret;
382 }
383
384 /* convert 64-bit int to 128-bit float */
385 uint64_t HELPER(cxgb)(CPUS390XState *env, int64_t v2, uint32_t m3)
386 {
387     int hold = swap_round_mode(env, m3);
388     float128 ret = int64_to_float128(v2, &env->fpu_status);
389     set_float_rounding_mode(hold, &env->fpu_status);
390     handle_exceptions(env, GETPC());
391     return RET128(ret);
392 }
393
394 /* convert 64-bit uint to 32-bit float */
395 uint64_t HELPER(celgb)(CPUS390XState *env, uint64_t v2, uint32_t m3)
396 {
397     int hold = swap_round_mode(env, m3);
398     float32 ret = uint64_to_float32(v2, &env->fpu_status);
399     set_float_rounding_mode(hold, &env->fpu_status);
400     handle_exceptions(env, GETPC());
401     return ret;
402 }
403
404 /* convert 64-bit uint to 64-bit float */
405 uint64_t HELPER(cdlgb)(CPUS390XState *env, uint64_t v2, uint32_t m3)
406 {
407     int hold = swap_round_mode(env, m3);
408     float64 ret = uint64_to_float64(v2, &env->fpu_status);
409     set_float_rounding_mode(hold, &env->fpu_status);
410     handle_exceptions(env, GETPC());
411     return ret;
412 }
413
414 /* convert 64-bit uint to 128-bit float */
415 uint64_t HELPER(cxlgb)(CPUS390XState *env, uint64_t v2, uint32_t m3)
416 {
417     int hold = swap_round_mode(env, m3);
418     float128 ret = uint64_to_float128(v2, &env->fpu_status);
419     set_float_rounding_mode(hold, &env->fpu_status);
420     handle_exceptions(env, GETPC());
421     return RET128(ret);
422 }
423
424 /* convert 32-bit float to 64-bit int */
425 uint64_t HELPER(cgeb)(CPUS390XState *env, uint64_t v2, uint32_t m3)
426 {
427     int hold = swap_round_mode(env, m3);
428     int64_t ret = float32_to_int64(v2, &env->fpu_status);
429     set_float_rounding_mode(hold, &env->fpu_status);
430     handle_exceptions(env, GETPC());
431     return ret;
432 }
433
434 /* convert 64-bit float to 64-bit int */
435 uint64_t HELPER(cgdb)(CPUS390XState *env, uint64_t v2, uint32_t m3)
436 {
437     int hold = swap_round_mode(env, m3);
438     int64_t ret = float64_to_int64(v2, &env->fpu_status);
439     set_float_rounding_mode(hold, &env->fpu_status);
440     handle_exceptions(env, GETPC());
441     return ret;
442 }
443
444 /* convert 128-bit float to 64-bit int */
445 uint64_t HELPER(cgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m3)
446 {
447     int hold = swap_round_mode(env, m3);
448     float128 v2 = make_float128(h, l);
449     int64_t ret = float128_to_int64(v2, &env->fpu_status);
450     set_float_rounding_mode(hold, &env->fpu_status);
451     handle_exceptions(env, GETPC());
452     return ret;
453 }
454
455 /* convert 32-bit float to 32-bit int */
456 uint64_t HELPER(cfeb)(CPUS390XState *env, uint64_t v2, uint32_t m3)
457 {
458     int hold = swap_round_mode(env, m3);
459     int32_t ret = float32_to_int32(v2, &env->fpu_status);
460     set_float_rounding_mode(hold, &env->fpu_status);
461     handle_exceptions(env, GETPC());
462     return ret;
463 }
464
465 /* convert 64-bit float to 32-bit int */
466 uint64_t HELPER(cfdb)(CPUS390XState *env, uint64_t v2, uint32_t m3)
467 {
468     int hold = swap_round_mode(env, m3);
469     int32_t ret = float64_to_int32(v2, &env->fpu_status);
470     set_float_rounding_mode(hold, &env->fpu_status);
471     handle_exceptions(env, GETPC());
472     return ret;
473 }
474
475 /* convert 128-bit float to 32-bit int */
476 uint64_t HELPER(cfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m3)
477 {
478     int hold = swap_round_mode(env, m3);
479     float128 v2 = make_float128(h, l);
480     int32_t ret = float128_to_int32(v2, &env->fpu_status);
481     set_float_rounding_mode(hold, &env->fpu_status);
482     handle_exceptions(env, GETPC());
483     return ret;
484 }
485
486 /* convert 32-bit float to 64-bit uint */
487 uint64_t HELPER(clgeb)(CPUS390XState *env, uint64_t v2, uint32_t m3)
488 {
489     int hold = swap_round_mode(env, m3);
490     uint64_t ret;
491     v2 = float32_to_float64(v2, &env->fpu_status);
492     ret = float64_to_uint64(v2, &env->fpu_status);
493     set_float_rounding_mode(hold, &env->fpu_status);
494     handle_exceptions(env, GETPC());
495     return ret;
496 }
497
498 /* convert 64-bit float to 64-bit uint */
499 uint64_t HELPER(clgdb)(CPUS390XState *env, uint64_t v2, uint32_t m3)
500 {
501     int hold = swap_round_mode(env, m3);
502     uint64_t ret = float64_to_uint64(v2, &env->fpu_status);
503     set_float_rounding_mode(hold, &env->fpu_status);
504     handle_exceptions(env, GETPC());
505     return ret;
506 }
507
508 /* convert 128-bit float to 64-bit uint */
509 uint64_t HELPER(clgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m3)
510 {
511     int hold = swap_round_mode(env, m3);
512     float128 v2 = make_float128(h, l);
513     /* ??? Not 100% correct.  */
514     uint64_t ret = float128_to_int64(v2, &env->fpu_status);
515     set_float_rounding_mode(hold, &env->fpu_status);
516     handle_exceptions(env, GETPC());
517     return ret;
518 }
519
520 /* convert 32-bit float to 32-bit uint */
521 uint64_t HELPER(clfeb)(CPUS390XState *env, uint64_t v2, uint32_t m3)
522 {
523     int hold = swap_round_mode(env, m3);
524     uint32_t ret = float32_to_uint32(v2, &env->fpu_status);
525     set_float_rounding_mode(hold, &env->fpu_status);
526     handle_exceptions(env, GETPC());
527     return ret;
528 }
529
530 /* convert 64-bit float to 32-bit uint */
531 uint64_t HELPER(clfdb)(CPUS390XState *env, uint64_t v2, uint32_t m3)
532 {
533     int hold = swap_round_mode(env, m3);
534     uint32_t ret = float64_to_uint32(v2, &env->fpu_status);
535     set_float_rounding_mode(hold, &env->fpu_status);
536     handle_exceptions(env, GETPC());
537     return ret;
538 }
539
540 /* convert 128-bit float to 32-bit uint */
541 uint64_t HELPER(clfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m3)
542 {
543     int hold = swap_round_mode(env, m3);
544     float128 v2 = make_float128(h, l);
545     /* Not 100% correct.  */
546     uint32_t ret = float128_to_int64(v2, &env->fpu_status);
547     set_float_rounding_mode(hold, &env->fpu_status);
548     handle_exceptions(env, GETPC());
549     return ret;
550 }
551
552 /* round to integer 32-bit */
553 uint64_t HELPER(fieb)(CPUS390XState *env, uint64_t f2, uint32_t m3)
554 {
555     int hold = swap_round_mode(env, m3);
556     float32 ret = float32_round_to_int(f2, &env->fpu_status);
557     set_float_rounding_mode(hold, &env->fpu_status);
558     handle_exceptions(env, GETPC());
559     return ret;
560 }
561
562 /* round to integer 64-bit */
563 uint64_t HELPER(fidb)(CPUS390XState *env, uint64_t f2, uint32_t m3)
564 {
565     int hold = swap_round_mode(env, m3);
566     float64 ret = float64_round_to_int(f2, &env->fpu_status);
567     set_float_rounding_mode(hold, &env->fpu_status);
568     handle_exceptions(env, GETPC());
569     return ret;
570 }
571
572 /* round to integer 128-bit */
573 uint64_t HELPER(fixb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint32_t m3)
574 {
575     int hold = swap_round_mode(env, m3);
576     float128 ret = float128_round_to_int(make_float128(ah, al),
577                                          &env->fpu_status);
578     set_float_rounding_mode(hold, &env->fpu_status);
579     handle_exceptions(env, GETPC());
580     return RET128(ret);
581 }
582
583 /* 32-bit FP compare and signal */
584 uint32_t HELPER(keb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
585 {
586     int cmp = float32_compare(f1, f2, &env->fpu_status);
587     handle_exceptions(env, GETPC());
588     return float_comp_to_cc(env, cmp);
589 }
590
591 /* 64-bit FP compare and signal */
592 uint32_t HELPER(kdb)(CPUS390XState *env, uint64_t f1, uint64_t f2)
593 {
594     int cmp = float64_compare(f1, f2, &env->fpu_status);
595     handle_exceptions(env, GETPC());
596     return float_comp_to_cc(env, cmp);
597 }
598
599 /* 128-bit FP compare and signal */
600 uint32_t HELPER(kxb)(CPUS390XState *env, uint64_t ah, uint64_t al,
601                      uint64_t bh, uint64_t bl)
602 {
603     int cmp = float128_compare(make_float128(ah, al),
604                                make_float128(bh, bl),
605                                &env->fpu_status);
606     handle_exceptions(env, GETPC());
607     return float_comp_to_cc(env, cmp);
608 }
609
610 /* 32-bit FP multiply and add */
611 uint64_t HELPER(maeb)(CPUS390XState *env, uint64_t f1,
612                       uint64_t f2, uint64_t f3)
613 {
614     float32 ret = float32_muladd(f2, f3, f1, 0, &env->fpu_status);
615     handle_exceptions(env, GETPC());
616     return ret;
617 }
618
619 /* 64-bit FP multiply and add */
620 uint64_t HELPER(madb)(CPUS390XState *env, uint64_t f1,
621                       uint64_t f2, uint64_t f3)
622 {
623     float64 ret = float64_muladd(f2, f3, f1, 0, &env->fpu_status);
624     handle_exceptions(env, GETPC());
625     return ret;
626 }
627
628 /* 32-bit FP multiply and subtract */
629 uint64_t HELPER(mseb)(CPUS390XState *env, uint64_t f1,
630                       uint64_t f2, uint64_t f3)
631 {
632     float32 ret = float32_muladd(f2, f3, f1, float_muladd_negate_c,
633                                  &env->fpu_status);
634     handle_exceptions(env, GETPC());
635     return ret;
636 }
637
638 /* 64-bit FP multiply and subtract */
639 uint64_t HELPER(msdb)(CPUS390XState *env, uint64_t f1,
640                       uint64_t f2, uint64_t f3)
641 {
642     float64 ret = float64_muladd(f2, f3, f1, float_muladd_negate_c,
643                                  &env->fpu_status);
644     handle_exceptions(env, GETPC());
645     return ret;
646 }
647
648 /* The rightmost bit has the number 11. */
649 static inline uint16_t dcmask(int bit, bool neg)
650 {
651     return 1 << (11 - bit - neg);
652 }
653
654 #define DEF_FLOAT_DCMASK(_TYPE) \
655 static uint16_t _TYPE##_dcmask(CPUS390XState *env, _TYPE f1)       \
656 {                                                                  \
657     const bool neg = _TYPE##_is_neg(f1);                           \
658                                                                    \
659     /* Sorted by most common cases - only one class is possible */ \
660     if (_TYPE##_is_normal(f1)) {                                   \
661         return dcmask(2, neg);                                     \
662     } else if (_TYPE##_is_zero(f1)) {                              \
663         return dcmask(0, neg);                                     \
664     } else if (_TYPE##_is_denormal(f1)) {                          \
665         return dcmask(4, neg);                                     \
666     } else if (_TYPE##_is_infinity(f1)) {                          \
667         return dcmask(6, neg);                                     \
668     } else if (_TYPE##_is_quiet_nan(f1, &env->fpu_status)) {       \
669         return dcmask(8, neg);                                     \
670     }                                                              \
671     /* signaling nan, as last remaining case */                    \
672     return dcmask(10, neg);                                        \
673 }
674 DEF_FLOAT_DCMASK(float32)
675 DEF_FLOAT_DCMASK(float64)
676 DEF_FLOAT_DCMASK(float128)
677
678 /* test data class 32-bit */
679 uint32_t HELPER(tceb)(CPUS390XState *env, uint64_t f1, uint64_t m2)
680 {
681     return (m2 & float32_dcmask(env, f1)) != 0;
682 }
683
684 /* test data class 64-bit */
685 uint32_t HELPER(tcdb)(CPUS390XState *env, uint64_t v1, uint64_t m2)
686 {
687     return (m2 & float64_dcmask(env, v1)) != 0;
688 }
689
690 /* test data class 128-bit */
691 uint32_t HELPER(tcxb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint64_t m2)
692 {
693     return (m2 & float128_dcmask(env, make_float128(ah, al))) != 0;
694 }
695
696 /* square root 32-bit */
697 uint64_t HELPER(sqeb)(CPUS390XState *env, uint64_t f2)
698 {
699     float32 ret = float32_sqrt(f2, &env->fpu_status);
700     handle_exceptions(env, GETPC());
701     return ret;
702 }
703
704 /* square root 64-bit */
705 uint64_t HELPER(sqdb)(CPUS390XState *env, uint64_t f2)
706 {
707     float64 ret = float64_sqrt(f2, &env->fpu_status);
708     handle_exceptions(env, GETPC());
709     return ret;
710 }
711
712 /* square root 128-bit */
713 uint64_t HELPER(sqxb)(CPUS390XState *env, uint64_t ah, uint64_t al)
714 {
715     float128 ret = float128_sqrt(make_float128(ah, al), &env->fpu_status);
716     handle_exceptions(env, GETPC());
717     return RET128(ret);
718 }
719
720 static const int fpc_to_rnd[4] = {
721     float_round_nearest_even,
722     float_round_to_zero,
723     float_round_up,
724     float_round_down
725 };
726
727 /* set fpc */
728 void HELPER(sfpc)(CPUS390XState *env, uint64_t fpc)
729 {
730     /* Install everything in the main FPC.  */
731     env->fpc = fpc;
732
733     /* Install the rounding mode in the shadow fpu_status.  */
734     set_float_rounding_mode(fpc_to_rnd[fpc & 3], &env->fpu_status);
735 }
736
737 /* set fpc and signal */
738 void HELPER(sfas)(CPUS390XState *env, uint64_t val)
739 {
740     uint32_t signalling = env->fpc;
741     uint32_t source = val;
742     uint32_t s390_exc;
743
744     /* The contents of the source operand are placed in the FPC register;
745        then the flags in the FPC register are set to the logical OR of the
746        signalling flags and the source flags.  */
747     env->fpc = source | (signalling & 0x00ff0000);
748     set_float_rounding_mode(fpc_to_rnd[source & 3], &env->fpu_status);
749
750     /* If any signalling flag is 1 and the corresponding source mask
751        is also 1, a simulated-iee-exception trap occurs.  */
752     s390_exc = (signalling >> 16) & (source >> 24);
753     if (s390_exc) {
754         tcg_s390_data_exception(env, s390_exc | 3, GETPC());
755     }
756 }
This page took 0.066335 seconds and 4 git commands to generate.