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