]>
Commit | Line | Data |
---|---|---|
e72ca652 BS |
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 | |
41c6a6dd | 10 | * version 2.1 of the License, or (at your option) any later version. |
e72ca652 BS |
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 | ||
9615495a | 21 | #include "qemu/osdep.h" |
e72ca652 | 22 | #include "cpu.h" |
4e58b838 | 23 | #include "internal.h" |
bbf6ea3b | 24 | #include "tcg_s390x.h" |
63c91552 | 25 | #include "exec/exec-all.h" |
f08b6170 | 26 | #include "exec/cpu_ldst.h" |
2ef6175a | 27 | #include "exec/helper-proto.h" |
24f91e81 | 28 | #include "fpu/softfloat.h" |
e72ca652 | 29 | |
e72ca652 BS |
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 | ||
587626f8 RH |
37 | #define RET128(F) (env->retxl = F.low, F.high) |
38 | ||
4b70fc54 DH |
39 | uint8_t s390_softfloat_exc_to_ieee(unsigned int exc) |
40 | { | |
41 | uint8_t s390_exc = 0; | |
42 | ||
43 | s390_exc |= (exc & float_flag_invalid) ? S390_IEEE_MASK_INVALID : 0; | |
44 | s390_exc |= (exc & float_flag_divbyzero) ? S390_IEEE_MASK_DIVBYZERO : 0; | |
45 | s390_exc |= (exc & float_flag_overflow) ? S390_IEEE_MASK_OVERFLOW : 0; | |
46 | s390_exc |= (exc & float_flag_underflow) ? S390_IEEE_MASK_UNDERFLOW : 0; | |
47 | s390_exc |= (exc & float_flag_inexact) ? S390_IEEE_MASK_INEXACT : 0; | |
48 | ||
49 | return s390_exc; | |
50 | } | |
587626f8 | 51 | |
587626f8 | 52 | /* Should be called after any operation that may raise IEEE exceptions. */ |
cf97f9ff | 53 | static void handle_exceptions(CPUS390XState *env, bool XxC, uintptr_t retaddr) |
587626f8 RH |
54 | { |
55 | unsigned s390_exc, qemu_exc; | |
56 | ||
57 | /* Get the exceptions raised by the current operation. Reset the | |
58 | fpu_status contents so that the next operation has a clean slate. */ | |
59 | qemu_exc = env->fpu_status.float_exception_flags; | |
60 | if (qemu_exc == 0) { | |
61 | return; | |
62 | } | |
63 | env->fpu_status.float_exception_flags = 0; | |
4b70fc54 | 64 | s390_exc = s390_softfloat_exc_to_ieee(qemu_exc); |
587626f8 | 65 | |
6d6ad1d1 DH |
66 | /* |
67 | * IEEE-Underflow exception recognition exists if a tininess condition | |
68 | * (underflow) exists and | |
69 | * - The mask bit in the FPC is zero and the result is inexact | |
70 | * - The mask bit in the FPC is one | |
71 | * So tininess conditions that are not inexact don't trigger any | |
72 | * underflow action in case the mask bit is not one. | |
73 | */ | |
74 | if (!(s390_exc & S390_IEEE_MASK_INEXACT) && | |
75 | !((env->fpc >> 24) & S390_IEEE_MASK_UNDERFLOW)) { | |
76 | s390_exc &= ~S390_IEEE_MASK_UNDERFLOW; | |
77 | } | |
78 | ||
fcb9e9f2 DH |
79 | /* |
80 | * FIXME: | |
81 | * 1. Right now, all inexact conditions are inidicated as | |
82 | * "truncated" (0) and never as "incremented" (1) in the DXC. | |
83 | * 2. Only traps due to invalid/divbyzero are suppressing. Other traps | |
84 | * are completing, meaning the target register has to be written! | |
85 | * This, however will mean that we have to write the register before | |
86 | * triggering the trap - impossible right now. | |
87 | */ | |
587626f8 | 88 | |
fcb9e9f2 DH |
89 | /* |
90 | * invalid/divbyzero cannot coexist with other conditions. | |
91 | * overflow/underflow however can coexist with inexact, we have to | |
92 | * handle it separatly. | |
93 | */ | |
94 | if (s390_exc & ~S390_IEEE_MASK_INEXACT) { | |
95 | if (s390_exc & ~S390_IEEE_MASK_INEXACT & env->fpc >> 24) { | |
96 | /* trap condition - inexact reported along */ | |
97 | tcg_s390_data_exception(env, s390_exc, retaddr); | |
98 | } | |
99 | /* nontrap condition - inexact handled differently */ | |
100 | env->fpc |= (s390_exc & ~S390_IEEE_MASK_INEXACT) << 16; | |
101 | } | |
102 | ||
103 | /* inexact handling */ | |
cf97f9ff | 104 | if (s390_exc & S390_IEEE_MASK_INEXACT && !XxC) { |
fcb9e9f2 DH |
105 | /* trap condition - overflow/underflow _not_ reported along */ |
106 | if (s390_exc & S390_IEEE_MASK_INEXACT & env->fpc >> 24) { | |
107 | tcg_s390_data_exception(env, s390_exc & S390_IEEE_MASK_INEXACT, | |
108 | retaddr); | |
109 | } | |
110 | /* nontrap condition */ | |
111 | env->fpc |= (s390_exc & S390_IEEE_MASK_INEXACT) << 16; | |
587626f8 RH |
112 | } |
113 | } | |
114 | ||
71bfd65c | 115 | int float_comp_to_cc(CPUS390XState *env, FloatRelation float_compare) |
e72ca652 BS |
116 | { |
117 | switch (float_compare) { | |
118 | case float_relation_equal: | |
119 | return 0; | |
120 | case float_relation_less: | |
121 | return 1; | |
122 | case float_relation_greater: | |
123 | return 2; | |
124 | case float_relation_unordered: | |
125 | return 3; | |
126 | default: | |
dc79e928 | 127 | cpu_abort(env_cpu(env), "unknown return value for float compare\n"); |
e72ca652 BS |
128 | } |
129 | } | |
130 | ||
e72ca652 BS |
131 | /* condition codes for unary FP ops */ |
132 | uint32_t set_cc_nz_f32(float32 v) | |
133 | { | |
134 | if (float32_is_any_nan(v)) { | |
135 | return 3; | |
136 | } else if (float32_is_zero(v)) { | |
137 | return 0; | |
138 | } else if (float32_is_neg(v)) { | |
139 | return 1; | |
140 | } else { | |
141 | return 2; | |
142 | } | |
143 | } | |
144 | ||
145 | uint32_t set_cc_nz_f64(float64 v) | |
146 | { | |
147 | if (float64_is_any_nan(v)) { | |
148 | return 3; | |
149 | } else if (float64_is_zero(v)) { | |
150 | return 0; | |
151 | } else if (float64_is_neg(v)) { | |
152 | return 1; | |
153 | } else { | |
154 | return 2; | |
155 | } | |
156 | } | |
157 | ||
587626f8 | 158 | uint32_t set_cc_nz_f128(float128 v) |
e72ca652 BS |
159 | { |
160 | if (float128_is_any_nan(v)) { | |
161 | return 3; | |
162 | } else if (float128_is_zero(v)) { | |
163 | return 0; | |
164 | } else if (float128_is_neg(v)) { | |
165 | return 1; | |
166 | } else { | |
167 | return 2; | |
168 | } | |
169 | } | |
170 | ||
dce0a58f DH |
171 | static inline uint8_t round_from_m34(uint32_t m34) |
172 | { | |
173 | return extract32(m34, 0, 4); | |
174 | } | |
175 | ||
176 | static inline bool xxc_from_m34(uint32_t m34) | |
177 | { | |
178 | /* XxC is bit 1 of m4 */ | |
179 | return extract32(m34, 4 + 3 - 1, 1); | |
180 | } | |
181 | ||
587626f8 RH |
182 | /* 32-bit FP addition */ |
183 | uint64_t HELPER(aeb)(CPUS390XState *env, uint64_t f1, uint64_t f2) | |
e72ca652 | 184 | { |
587626f8 | 185 | float32 ret = float32_add(f1, f2, &env->fpu_status); |
cf97f9ff | 186 | handle_exceptions(env, false, GETPC()); |
587626f8 | 187 | return ret; |
e72ca652 BS |
188 | } |
189 | ||
587626f8 RH |
190 | /* 64-bit FP addition */ |
191 | uint64_t HELPER(adb)(CPUS390XState *env, uint64_t f1, uint64_t f2) | |
e72ca652 | 192 | { |
587626f8 | 193 | float64 ret = float64_add(f1, f2, &env->fpu_status); |
cf97f9ff | 194 | handle_exceptions(env, false, GETPC()); |
587626f8 RH |
195 | return ret; |
196 | } | |
e72ca652 | 197 | |
587626f8 RH |
198 | /* 128-bit FP addition */ |
199 | uint64_t HELPER(axb)(CPUS390XState *env, uint64_t ah, uint64_t al, | |
200 | uint64_t bh, uint64_t bl) | |
201 | { | |
202 | float128 ret = float128_add(make_float128(ah, al), | |
203 | make_float128(bh, bl), | |
204 | &env->fpu_status); | |
cf97f9ff | 205 | handle_exceptions(env, false, GETPC()); |
587626f8 | 206 | return RET128(ret); |
e72ca652 BS |
207 | } |
208 | ||
1a800a2d RH |
209 | /* 32-bit FP subtraction */ |
210 | uint64_t HELPER(seb)(CPUS390XState *env, uint64_t f1, uint64_t f2) | |
e72ca652 | 211 | { |
1a800a2d | 212 | float32 ret = float32_sub(f1, f2, &env->fpu_status); |
cf97f9ff | 213 | handle_exceptions(env, false, GETPC()); |
1a800a2d | 214 | return ret; |
e72ca652 BS |
215 | } |
216 | ||
1a800a2d RH |
217 | /* 64-bit FP subtraction */ |
218 | uint64_t HELPER(sdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) | |
e72ca652 | 219 | { |
1a800a2d | 220 | float64 ret = float64_sub(f1, f2, &env->fpu_status); |
cf97f9ff | 221 | handle_exceptions(env, false, GETPC()); |
1a800a2d RH |
222 | return ret; |
223 | } | |
e72ca652 | 224 | |
1a800a2d RH |
225 | /* 128-bit FP subtraction */ |
226 | uint64_t HELPER(sxb)(CPUS390XState *env, uint64_t ah, uint64_t al, | |
227 | uint64_t bh, uint64_t bl) | |
228 | { | |
229 | float128 ret = float128_sub(make_float128(ah, al), | |
230 | make_float128(bh, bl), | |
231 | &env->fpu_status); | |
cf97f9ff | 232 | handle_exceptions(env, false, GETPC()); |
1a800a2d | 233 | return RET128(ret); |
e72ca652 BS |
234 | } |
235 | ||
f08a5c31 RH |
236 | /* 32-bit FP division */ |
237 | uint64_t HELPER(deb)(CPUS390XState *env, uint64_t f1, uint64_t f2) | |
e72ca652 | 238 | { |
f08a5c31 | 239 | float32 ret = float32_div(f1, f2, &env->fpu_status); |
cf97f9ff | 240 | handle_exceptions(env, false, GETPC()); |
f08a5c31 | 241 | return ret; |
e72ca652 BS |
242 | } |
243 | ||
f08a5c31 RH |
244 | /* 64-bit FP division */ |
245 | uint64_t HELPER(ddb)(CPUS390XState *env, uint64_t f1, uint64_t f2) | |
e72ca652 | 246 | { |
f08a5c31 | 247 | float64 ret = float64_div(f1, f2, &env->fpu_status); |
cf97f9ff | 248 | handle_exceptions(env, false, GETPC()); |
f08a5c31 RH |
249 | return ret; |
250 | } | |
e72ca652 | 251 | |
f08a5c31 RH |
252 | /* 128-bit FP division */ |
253 | uint64_t HELPER(dxb)(CPUS390XState *env, uint64_t ah, uint64_t al, | |
254 | uint64_t bh, uint64_t bl) | |
255 | { | |
256 | float128 ret = float128_div(make_float128(ah, al), | |
257 | make_float128(bh, bl), | |
258 | &env->fpu_status); | |
cf97f9ff | 259 | handle_exceptions(env, false, GETPC()); |
f08a5c31 | 260 | return RET128(ret); |
e72ca652 BS |
261 | } |
262 | ||
83b00736 RH |
263 | /* 32-bit FP multiplication */ |
264 | uint64_t HELPER(meeb)(CPUS390XState *env, uint64_t f1, uint64_t f2) | |
e72ca652 | 265 | { |
83b00736 | 266 | float32 ret = float32_mul(f1, f2, &env->fpu_status); |
cf97f9ff | 267 | handle_exceptions(env, false, GETPC()); |
83b00736 | 268 | return ret; |
e72ca652 BS |
269 | } |
270 | ||
83b00736 RH |
271 | /* 64-bit FP multiplication */ |
272 | uint64_t HELPER(mdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) | |
e72ca652 | 273 | { |
83b00736 | 274 | float64 ret = float64_mul(f1, f2, &env->fpu_status); |
cf97f9ff | 275 | handle_exceptions(env, false, GETPC()); |
83b00736 RH |
276 | return ret; |
277 | } | |
e72ca652 | 278 | |
83b00736 RH |
279 | /* 64/32-bit FP multiplication */ |
280 | uint64_t HELPER(mdeb)(CPUS390XState *env, uint64_t f1, uint64_t f2) | |
281 | { | |
282 | float64 ret = float32_to_float64(f2, &env->fpu_status); | |
283 | ret = float64_mul(f1, ret, &env->fpu_status); | |
cf97f9ff | 284 | handle_exceptions(env, false, GETPC()); |
83b00736 RH |
285 | return ret; |
286 | } | |
287 | ||
288 | /* 128-bit FP multiplication */ | |
289 | uint64_t HELPER(mxb)(CPUS390XState *env, uint64_t ah, uint64_t al, | |
290 | uint64_t bh, uint64_t bl) | |
291 | { | |
292 | float128 ret = float128_mul(make_float128(ah, al), | |
293 | make_float128(bh, bl), | |
294 | &env->fpu_status); | |
cf97f9ff | 295 | handle_exceptions(env, false, GETPC()); |
83b00736 RH |
296 | return RET128(ret); |
297 | } | |
298 | ||
299 | /* 128/64-bit FP multiplication */ | |
300 | uint64_t HELPER(mxdb)(CPUS390XState *env, uint64_t ah, uint64_t al, | |
301 | uint64_t f2) | |
302 | { | |
303 | float128 ret = float64_to_float128(f2, &env->fpu_status); | |
304 | ret = float128_mul(make_float128(ah, al), ret, &env->fpu_status); | |
cf97f9ff | 305 | handle_exceptions(env, false, GETPC()); |
83b00736 | 306 | return RET128(ret); |
e72ca652 BS |
307 | } |
308 | ||
309 | /* convert 32-bit float to 64-bit float */ | |
587626f8 | 310 | uint64_t HELPER(ldeb)(CPUS390XState *env, uint64_t f2) |
e72ca652 | 311 | { |
587626f8 | 312 | float64 ret = float32_to_float64(f2, &env->fpu_status); |
cf97f9ff | 313 | handle_exceptions(env, false, GETPC()); |
d0cfecb5 | 314 | return ret; |
e72ca652 BS |
315 | } |
316 | ||
317 | /* convert 128-bit float to 64-bit float */ | |
bdcfcd44 DH |
318 | uint64_t HELPER(ldxb)(CPUS390XState *env, uint64_t ah, uint64_t al, |
319 | uint32_t m34) | |
e72ca652 | 320 | { |
bdcfcd44 | 321 | int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); |
587626f8 | 322 | float64 ret = float128_to_float64(make_float128(ah, al), &env->fpu_status); |
bdcfcd44 DH |
323 | |
324 | s390_restore_bfp_rounding_mode(env, old_mode); | |
325 | handle_exceptions(env, xxc_from_m34(m34), GETPC()); | |
d0cfecb5 | 326 | return ret; |
e72ca652 BS |
327 | } |
328 | ||
329 | /* convert 64-bit float to 128-bit float */ | |
587626f8 | 330 | uint64_t HELPER(lxdb)(CPUS390XState *env, uint64_t f2) |
e72ca652 | 331 | { |
587626f8 | 332 | float128 ret = float64_to_float128(f2, &env->fpu_status); |
cf97f9ff | 333 | handle_exceptions(env, false, GETPC()); |
d0cfecb5 | 334 | return RET128(ret); |
587626f8 | 335 | } |
e72ca652 | 336 | |
587626f8 RH |
337 | /* convert 32-bit float to 128-bit float */ |
338 | uint64_t HELPER(lxeb)(CPUS390XState *env, uint64_t f2) | |
339 | { | |
340 | float128 ret = float32_to_float128(f2, &env->fpu_status); | |
cf97f9ff | 341 | handle_exceptions(env, false, GETPC()); |
d0cfecb5 | 342 | return RET128(ret); |
e72ca652 BS |
343 | } |
344 | ||
345 | /* convert 64-bit float to 32-bit float */ | |
bdcfcd44 | 346 | uint64_t HELPER(ledb)(CPUS390XState *env, uint64_t f2, uint32_t m34) |
e72ca652 | 347 | { |
bdcfcd44 | 348 | int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); |
587626f8 | 349 | float32 ret = float64_to_float32(f2, &env->fpu_status); |
bdcfcd44 DH |
350 | |
351 | s390_restore_bfp_rounding_mode(env, old_mode); | |
352 | handle_exceptions(env, xxc_from_m34(m34), GETPC()); | |
d0cfecb5 | 353 | return ret; |
e72ca652 BS |
354 | } |
355 | ||
356 | /* convert 128-bit float to 32-bit float */ | |
bdcfcd44 DH |
357 | uint64_t HELPER(lexb)(CPUS390XState *env, uint64_t ah, uint64_t al, |
358 | uint32_t m34) | |
e72ca652 | 359 | { |
bdcfcd44 | 360 | int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); |
587626f8 | 361 | float32 ret = float128_to_float32(make_float128(ah, al), &env->fpu_status); |
bdcfcd44 DH |
362 | |
363 | s390_restore_bfp_rounding_mode(env, old_mode); | |
364 | handle_exceptions(env, xxc_from_m34(m34), GETPC()); | |
d0cfecb5 | 365 | return ret; |
e72ca652 BS |
366 | } |
367 | ||
587626f8 RH |
368 | /* 32-bit FP compare */ |
369 | uint32_t HELPER(ceb)(CPUS390XState *env, uint64_t f1, uint64_t f2) | |
e72ca652 | 370 | { |
71bfd65c | 371 | FloatRelation cmp = float32_compare_quiet(f1, f2, &env->fpu_status); |
cf97f9ff | 372 | handle_exceptions(env, false, GETPC()); |
587626f8 | 373 | return float_comp_to_cc(env, cmp); |
e72ca652 BS |
374 | } |
375 | ||
587626f8 RH |
376 | /* 64-bit FP compare */ |
377 | uint32_t HELPER(cdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) | |
e72ca652 | 378 | { |
71bfd65c | 379 | FloatRelation cmp = float64_compare_quiet(f1, f2, &env->fpu_status); |
cf97f9ff | 380 | handle_exceptions(env, false, GETPC()); |
587626f8 | 381 | return float_comp_to_cc(env, cmp); |
e72ca652 BS |
382 | } |
383 | ||
587626f8 RH |
384 | /* 128-bit FP compare */ |
385 | uint32_t HELPER(cxb)(CPUS390XState *env, uint64_t ah, uint64_t al, | |
386 | uint64_t bh, uint64_t bl) | |
e72ca652 | 387 | { |
71bfd65c RH |
388 | FloatRelation cmp = float128_compare_quiet(make_float128(ah, al), |
389 | make_float128(bh, bl), | |
390 | &env->fpu_status); | |
cf97f9ff | 391 | handle_exceptions(env, false, GETPC()); |
587626f8 | 392 | return float_comp_to_cc(env, cmp); |
e72ca652 BS |
393 | } |
394 | ||
c0ee7015 | 395 | int s390_swap_bfp_rounding_mode(CPUS390XState *env, int m3) |
e72ca652 | 396 | { |
68c8bd93 | 397 | int ret = env->fpu_status.float_rounding_mode; |
b12b103e | 398 | |
e72ca652 BS |
399 | switch (m3) { |
400 | case 0: | |
401 | /* current mode */ | |
402 | break; | |
403 | case 1: | |
b12b103e DH |
404 | /* round to nearest with ties away from 0 */ |
405 | set_float_rounding_mode(float_round_ties_away, &env->fpu_status); | |
406 | break; | |
407 | case 3: | |
408 | /* round to prepare for shorter precision */ | |
409 | set_float_rounding_mode(float_round_to_odd, &env->fpu_status); | |
410 | break; | |
e72ca652 | 411 | case 4: |
b12b103e | 412 | /* round to nearest with ties to even */ |
e72ca652 BS |
413 | set_float_rounding_mode(float_round_nearest_even, &env->fpu_status); |
414 | break; | |
415 | case 5: | |
416 | /* round to zero */ | |
417 | set_float_rounding_mode(float_round_to_zero, &env->fpu_status); | |
418 | break; | |
419 | case 6: | |
420 | /* round to +inf */ | |
421 | set_float_rounding_mode(float_round_up, &env->fpu_status); | |
422 | break; | |
423 | case 7: | |
424 | /* round to -inf */ | |
425 | set_float_rounding_mode(float_round_down, &env->fpu_status); | |
426 | break; | |
b12b103e DH |
427 | default: |
428 | g_assert_not_reached(); | |
e72ca652 | 429 | } |
68c8bd93 | 430 | return ret; |
e72ca652 BS |
431 | } |
432 | ||
c0ee7015 DH |
433 | void s390_restore_bfp_rounding_mode(CPUS390XState *env, int old_mode) |
434 | { | |
435 | set_float_rounding_mode(old_mode, &env->fpu_status); | |
436 | } | |
437 | ||
683bb9a8 | 438 | /* convert 64-bit int to 32-bit float */ |
dce0a58f | 439 | uint64_t HELPER(cegb)(CPUS390XState *env, int64_t v2, uint32_t m34) |
683bb9a8 | 440 | { |
dce0a58f | 441 | int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); |
683bb9a8 | 442 | float32 ret = int64_to_float32(v2, &env->fpu_status); |
c0ee7015 DH |
443 | |
444 | s390_restore_bfp_rounding_mode(env, old_mode); | |
dce0a58f | 445 | handle_exceptions(env, xxc_from_m34(m34), GETPC()); |
683bb9a8 RH |
446 | return ret; |
447 | } | |
448 | ||
449 | /* convert 64-bit int to 64-bit float */ | |
dce0a58f | 450 | uint64_t HELPER(cdgb)(CPUS390XState *env, int64_t v2, uint32_t m34) |
683bb9a8 | 451 | { |
dce0a58f | 452 | int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); |
683bb9a8 | 453 | float64 ret = int64_to_float64(v2, &env->fpu_status); |
c0ee7015 DH |
454 | |
455 | s390_restore_bfp_rounding_mode(env, old_mode); | |
dce0a58f | 456 | handle_exceptions(env, xxc_from_m34(m34), GETPC()); |
683bb9a8 RH |
457 | return ret; |
458 | } | |
459 | ||
460 | /* convert 64-bit int to 128-bit float */ | |
dce0a58f | 461 | uint64_t HELPER(cxgb)(CPUS390XState *env, int64_t v2, uint32_t m34) |
683bb9a8 | 462 | { |
dce0a58f | 463 | int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); |
683bb9a8 | 464 | float128 ret = int64_to_float128(v2, &env->fpu_status); |
c0ee7015 DH |
465 | |
466 | s390_restore_bfp_rounding_mode(env, old_mode); | |
dce0a58f | 467 | handle_exceptions(env, xxc_from_m34(m34), GETPC()); |
2112bf1b RH |
468 | return RET128(ret); |
469 | } | |
470 | ||
471 | /* convert 64-bit uint to 32-bit float */ | |
dce0a58f | 472 | uint64_t HELPER(celgb)(CPUS390XState *env, uint64_t v2, uint32_t m34) |
2112bf1b | 473 | { |
dce0a58f | 474 | int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); |
2112bf1b | 475 | float32 ret = uint64_to_float32(v2, &env->fpu_status); |
c0ee7015 DH |
476 | |
477 | s390_restore_bfp_rounding_mode(env, old_mode); | |
dce0a58f | 478 | handle_exceptions(env, xxc_from_m34(m34), GETPC()); |
2112bf1b RH |
479 | return ret; |
480 | } | |
481 | ||
482 | /* convert 64-bit uint to 64-bit float */ | |
dce0a58f | 483 | uint64_t HELPER(cdlgb)(CPUS390XState *env, uint64_t v2, uint32_t m34) |
2112bf1b | 484 | { |
dce0a58f | 485 | int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); |
2112bf1b | 486 | float64 ret = uint64_to_float64(v2, &env->fpu_status); |
c0ee7015 DH |
487 | |
488 | s390_restore_bfp_rounding_mode(env, old_mode); | |
dce0a58f | 489 | handle_exceptions(env, xxc_from_m34(m34), GETPC()); |
2112bf1b RH |
490 | return ret; |
491 | } | |
492 | ||
493 | /* convert 64-bit uint to 128-bit float */ | |
dce0a58f | 494 | uint64_t HELPER(cxlgb)(CPUS390XState *env, uint64_t v2, uint32_t m34) |
2112bf1b | 495 | { |
dce0a58f | 496 | int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); |
d2d9feac | 497 | float128 ret = uint64_to_float128(v2, &env->fpu_status); |
c0ee7015 DH |
498 | |
499 | s390_restore_bfp_rounding_mode(env, old_mode); | |
dce0a58f | 500 | handle_exceptions(env, xxc_from_m34(m34), GETPC()); |
683bb9a8 RH |
501 | return RET128(ret); |
502 | } | |
503 | ||
e72ca652 | 504 | /* convert 32-bit float to 64-bit int */ |
dce0a58f | 505 | uint64_t HELPER(cgeb)(CPUS390XState *env, uint64_t v2, uint32_t m34) |
e72ca652 | 506 | { |
dce0a58f | 507 | int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); |
68c8bd93 | 508 | int64_t ret = float32_to_int64(v2, &env->fpu_status); |
c0ee7015 DH |
509 | |
510 | s390_restore_bfp_rounding_mode(env, old_mode); | |
dce0a58f | 511 | handle_exceptions(env, xxc_from_m34(m34), GETPC()); |
68c8bd93 | 512 | return ret; |
e72ca652 BS |
513 | } |
514 | ||
515 | /* convert 64-bit float to 64-bit int */ | |
dce0a58f | 516 | uint64_t HELPER(cgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34) |
e72ca652 | 517 | { |
dce0a58f | 518 | int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); |
68c8bd93 | 519 | int64_t ret = float64_to_int64(v2, &env->fpu_status); |
c0ee7015 DH |
520 | |
521 | s390_restore_bfp_rounding_mode(env, old_mode); | |
dce0a58f | 522 | handle_exceptions(env, xxc_from_m34(m34), GETPC()); |
68c8bd93 | 523 | return ret; |
e72ca652 BS |
524 | } |
525 | ||
526 | /* convert 128-bit float to 64-bit int */ | |
dce0a58f | 527 | uint64_t HELPER(cgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34) |
e72ca652 | 528 | { |
dce0a58f | 529 | int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); |
68c8bd93 RH |
530 | float128 v2 = make_float128(h, l); |
531 | int64_t ret = float128_to_int64(v2, &env->fpu_status); | |
c0ee7015 DH |
532 | |
533 | s390_restore_bfp_rounding_mode(env, old_mode); | |
dce0a58f | 534 | handle_exceptions(env, xxc_from_m34(m34), GETPC()); |
68c8bd93 | 535 | return ret; |
e72ca652 BS |
536 | } |
537 | ||
538 | /* convert 32-bit float to 32-bit int */ | |
dce0a58f | 539 | uint64_t HELPER(cfeb)(CPUS390XState *env, uint64_t v2, uint32_t m34) |
e72ca652 | 540 | { |
dce0a58f | 541 | int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); |
68c8bd93 | 542 | int32_t ret = float32_to_int32(v2, &env->fpu_status); |
c0ee7015 DH |
543 | |
544 | s390_restore_bfp_rounding_mode(env, old_mode); | |
dce0a58f | 545 | handle_exceptions(env, xxc_from_m34(m34), GETPC()); |
68c8bd93 | 546 | return ret; |
e72ca652 BS |
547 | } |
548 | ||
549 | /* convert 64-bit float to 32-bit int */ | |
dce0a58f | 550 | uint64_t HELPER(cfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34) |
e72ca652 | 551 | { |
dce0a58f | 552 | int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); |
68c8bd93 | 553 | int32_t ret = float64_to_int32(v2, &env->fpu_status); |
c0ee7015 DH |
554 | |
555 | s390_restore_bfp_rounding_mode(env, old_mode); | |
dce0a58f | 556 | handle_exceptions(env, xxc_from_m34(m34), GETPC()); |
68c8bd93 | 557 | return ret; |
e72ca652 BS |
558 | } |
559 | ||
560 | /* convert 128-bit float to 32-bit int */ | |
dce0a58f | 561 | uint64_t HELPER(cfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34) |
e72ca652 | 562 | { |
dce0a58f | 563 | int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); |
68c8bd93 RH |
564 | float128 v2 = make_float128(h, l); |
565 | int32_t ret = float128_to_int32(v2, &env->fpu_status); | |
c0ee7015 DH |
566 | |
567 | s390_restore_bfp_rounding_mode(env, old_mode); | |
dce0a58f | 568 | handle_exceptions(env, xxc_from_m34(m34), GETPC()); |
68c8bd93 | 569 | return ret; |
e72ca652 BS |
570 | } |
571 | ||
6ac1b45f | 572 | /* convert 32-bit float to 64-bit uint */ |
dce0a58f | 573 | uint64_t HELPER(clgeb)(CPUS390XState *env, uint64_t v2, uint32_t m34) |
6ac1b45f | 574 | { |
dce0a58f | 575 | int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); |
6ac1b45f | 576 | uint64_t ret; |
c0ee7015 | 577 | |
6ac1b45f RH |
578 | v2 = float32_to_float64(v2, &env->fpu_status); |
579 | ret = float64_to_uint64(v2, &env->fpu_status); | |
c0ee7015 | 580 | s390_restore_bfp_rounding_mode(env, old_mode); |
dce0a58f | 581 | handle_exceptions(env, xxc_from_m34(m34), GETPC()); |
6ac1b45f RH |
582 | return ret; |
583 | } | |
584 | ||
585 | /* convert 64-bit float to 64-bit uint */ | |
dce0a58f | 586 | uint64_t HELPER(clgdb)(CPUS390XState *env, uint64_t v2, uint32_t m34) |
6ac1b45f | 587 | { |
dce0a58f | 588 | int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); |
6ac1b45f | 589 | uint64_t ret = float64_to_uint64(v2, &env->fpu_status); |
c0ee7015 DH |
590 | |
591 | s390_restore_bfp_rounding_mode(env, old_mode); | |
dce0a58f | 592 | handle_exceptions(env, xxc_from_m34(m34), GETPC()); |
6ac1b45f RH |
593 | return ret; |
594 | } | |
595 | ||
596 | /* convert 128-bit float to 64-bit uint */ | |
dce0a58f | 597 | uint64_t HELPER(clgxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34) |
6ac1b45f | 598 | { |
dce0a58f | 599 | int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); |
3af471f9 | 600 | uint64_t ret = float128_to_uint64(make_float128(h, l), &env->fpu_status); |
c0ee7015 DH |
601 | |
602 | s390_restore_bfp_rounding_mode(env, old_mode); | |
dce0a58f | 603 | handle_exceptions(env, xxc_from_m34(m34), GETPC()); |
6ac1b45f RH |
604 | return ret; |
605 | } | |
606 | ||
607 | /* convert 32-bit float to 32-bit uint */ | |
dce0a58f | 608 | uint64_t HELPER(clfeb)(CPUS390XState *env, uint64_t v2, uint32_t m34) |
6ac1b45f | 609 | { |
dce0a58f | 610 | int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); |
6ac1b45f | 611 | uint32_t ret = float32_to_uint32(v2, &env->fpu_status); |
c0ee7015 DH |
612 | |
613 | s390_restore_bfp_rounding_mode(env, old_mode); | |
dce0a58f | 614 | handle_exceptions(env, xxc_from_m34(m34), GETPC()); |
6ac1b45f RH |
615 | return ret; |
616 | } | |
617 | ||
618 | /* convert 64-bit float to 32-bit uint */ | |
dce0a58f | 619 | uint64_t HELPER(clfdb)(CPUS390XState *env, uint64_t v2, uint32_t m34) |
6ac1b45f | 620 | { |
dce0a58f | 621 | int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); |
6ac1b45f | 622 | uint32_t ret = float64_to_uint32(v2, &env->fpu_status); |
c0ee7015 DH |
623 | |
624 | s390_restore_bfp_rounding_mode(env, old_mode); | |
dce0a58f | 625 | handle_exceptions(env, xxc_from_m34(m34), GETPC()); |
6ac1b45f RH |
626 | return ret; |
627 | } | |
628 | ||
629 | /* convert 128-bit float to 32-bit uint */ | |
dce0a58f | 630 | uint64_t HELPER(clfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m34) |
6ac1b45f | 631 | { |
dce0a58f | 632 | int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); |
3af471f9 | 633 | uint32_t ret = float128_to_uint32(make_float128(h, l), &env->fpu_status); |
c0ee7015 DH |
634 | |
635 | s390_restore_bfp_rounding_mode(env, old_mode); | |
dce0a58f | 636 | handle_exceptions(env, xxc_from_m34(m34), GETPC()); |
6ac1b45f RH |
637 | return ret; |
638 | } | |
639 | ||
ed0bcece | 640 | /* round to integer 32-bit */ |
dce0a58f | 641 | uint64_t HELPER(fieb)(CPUS390XState *env, uint64_t f2, uint32_t m34) |
ed0bcece | 642 | { |
dce0a58f | 643 | int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); |
ed0bcece | 644 | float32 ret = float32_round_to_int(f2, &env->fpu_status); |
c0ee7015 DH |
645 | |
646 | s390_restore_bfp_rounding_mode(env, old_mode); | |
dce0a58f | 647 | handle_exceptions(env, xxc_from_m34(m34), GETPC()); |
ed0bcece AJ |
648 | return ret; |
649 | } | |
650 | ||
651 | /* round to integer 64-bit */ | |
dce0a58f | 652 | uint64_t HELPER(fidb)(CPUS390XState *env, uint64_t f2, uint32_t m34) |
ed0bcece | 653 | { |
dce0a58f | 654 | int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); |
ed0bcece | 655 | float64 ret = float64_round_to_int(f2, &env->fpu_status); |
c0ee7015 DH |
656 | |
657 | s390_restore_bfp_rounding_mode(env, old_mode); | |
dce0a58f | 658 | handle_exceptions(env, xxc_from_m34(m34), GETPC()); |
ed0bcece AJ |
659 | return ret; |
660 | } | |
661 | ||
662 | /* round to integer 128-bit */ | |
dce0a58f DH |
663 | uint64_t HELPER(fixb)(CPUS390XState *env, uint64_t ah, uint64_t al, |
664 | uint32_t m34) | |
ed0bcece | 665 | { |
dce0a58f | 666 | int old_mode = s390_swap_bfp_rounding_mode(env, round_from_m34(m34)); |
ed0bcece AJ |
667 | float128 ret = float128_round_to_int(make_float128(ah, al), |
668 | &env->fpu_status); | |
cf97f9ff | 669 | |
c0ee7015 | 670 | s390_restore_bfp_rounding_mode(env, old_mode); |
dce0a58f | 671 | handle_exceptions(env, xxc_from_m34(m34), GETPC()); |
ed0bcece AJ |
672 | return RET128(ret); |
673 | } | |
674 | ||
9c8be598 AJ |
675 | /* 32-bit FP compare and signal */ |
676 | uint32_t HELPER(keb)(CPUS390XState *env, uint64_t f1, uint64_t f2) | |
677 | { | |
71bfd65c | 678 | FloatRelation cmp = float32_compare(f1, f2, &env->fpu_status); |
cf97f9ff | 679 | handle_exceptions(env, false, GETPC()); |
9c8be598 AJ |
680 | return float_comp_to_cc(env, cmp); |
681 | } | |
682 | ||
683 | /* 64-bit FP compare and signal */ | |
684 | uint32_t HELPER(kdb)(CPUS390XState *env, uint64_t f1, uint64_t f2) | |
685 | { | |
71bfd65c | 686 | FloatRelation cmp = float64_compare(f1, f2, &env->fpu_status); |
cf97f9ff | 687 | handle_exceptions(env, false, GETPC()); |
9c8be598 AJ |
688 | return float_comp_to_cc(env, cmp); |
689 | } | |
690 | ||
691 | /* 128-bit FP compare and signal */ | |
692 | uint32_t HELPER(kxb)(CPUS390XState *env, uint64_t ah, uint64_t al, | |
693 | uint64_t bh, uint64_t bl) | |
694 | { | |
71bfd65c RH |
695 | FloatRelation cmp = float128_compare(make_float128(ah, al), |
696 | make_float128(bh, bl), | |
697 | &env->fpu_status); | |
cf97f9ff | 698 | handle_exceptions(env, false, GETPC()); |
9c8be598 AJ |
699 | return float_comp_to_cc(env, cmp); |
700 | } | |
701 | ||
722bfec3 RH |
702 | /* 32-bit FP multiply and add */ |
703 | uint64_t HELPER(maeb)(CPUS390XState *env, uint64_t f1, | |
704 | uint64_t f2, uint64_t f3) | |
e72ca652 | 705 | { |
722bfec3 | 706 | float32 ret = float32_muladd(f2, f3, f1, 0, &env->fpu_status); |
cf97f9ff | 707 | handle_exceptions(env, false, GETPC()); |
722bfec3 | 708 | return ret; |
e72ca652 BS |
709 | } |
710 | ||
722bfec3 RH |
711 | /* 64-bit FP multiply and add */ |
712 | uint64_t HELPER(madb)(CPUS390XState *env, uint64_t f1, | |
713 | uint64_t f2, uint64_t f3) | |
e72ca652 | 714 | { |
722bfec3 | 715 | float64 ret = float64_muladd(f2, f3, f1, 0, &env->fpu_status); |
cf97f9ff | 716 | handle_exceptions(env, false, GETPC()); |
722bfec3 | 717 | return ret; |
e72ca652 BS |
718 | } |
719 | ||
722bfec3 RH |
720 | /* 32-bit FP multiply and subtract */ |
721 | uint64_t HELPER(mseb)(CPUS390XState *env, uint64_t f1, | |
722 | uint64_t f2, uint64_t f3) | |
e72ca652 | 723 | { |
722bfec3 RH |
724 | float32 ret = float32_muladd(f2, f3, f1, float_muladd_negate_c, |
725 | &env->fpu_status); | |
cf97f9ff | 726 | handle_exceptions(env, false, GETPC()); |
722bfec3 | 727 | return ret; |
e72ca652 BS |
728 | } |
729 | ||
722bfec3 RH |
730 | /* 64-bit FP multiply and subtract */ |
731 | uint64_t HELPER(msdb)(CPUS390XState *env, uint64_t f1, | |
732 | uint64_t f2, uint64_t f3) | |
e72ca652 | 733 | { |
722bfec3 RH |
734 | float64 ret = float64_muladd(f2, f3, f1, float_muladd_negate_c, |
735 | &env->fpu_status); | |
cf97f9ff | 736 | handle_exceptions(env, false, GETPC()); |
722bfec3 | 737 | return ret; |
e72ca652 BS |
738 | } |
739 | ||
fc7cc951 DH |
740 | /* The rightmost bit has the number 11. */ |
741 | static inline uint16_t dcmask(int bit, bool neg) | |
742 | { | |
743 | return 1 << (11 - bit - neg); | |
744 | } | |
745 | ||
746 | #define DEF_FLOAT_DCMASK(_TYPE) \ | |
aae65009 | 747 | uint16_t _TYPE##_dcmask(CPUS390XState *env, _TYPE f1) \ |
fc7cc951 DH |
748 | { \ |
749 | const bool neg = _TYPE##_is_neg(f1); \ | |
750 | \ | |
751 | /* Sorted by most common cases - only one class is possible */ \ | |
752 | if (_TYPE##_is_normal(f1)) { \ | |
753 | return dcmask(2, neg); \ | |
754 | } else if (_TYPE##_is_zero(f1)) { \ | |
755 | return dcmask(0, neg); \ | |
756 | } else if (_TYPE##_is_denormal(f1)) { \ | |
757 | return dcmask(4, neg); \ | |
758 | } else if (_TYPE##_is_infinity(f1)) { \ | |
759 | return dcmask(6, neg); \ | |
760 | } else if (_TYPE##_is_quiet_nan(f1, &env->fpu_status)) { \ | |
761 | return dcmask(8, neg); \ | |
762 | } \ | |
763 | /* signaling nan, as last remaining case */ \ | |
764 | return dcmask(10, neg); \ | |
765 | } | |
766 | DEF_FLOAT_DCMASK(float32) | |
767 | DEF_FLOAT_DCMASK(float64) | |
768 | DEF_FLOAT_DCMASK(float128) | |
769 | ||
e72ca652 | 770 | /* test data class 32-bit */ |
af39bc8c | 771 | uint32_t HELPER(tceb)(CPUS390XState *env, uint64_t f1, uint64_t m2) |
e72ca652 | 772 | { |
fc7cc951 | 773 | return (m2 & float32_dcmask(env, f1)) != 0; |
e72ca652 BS |
774 | } |
775 | ||
776 | /* test data class 64-bit */ | |
af39bc8c | 777 | uint32_t HELPER(tcdb)(CPUS390XState *env, uint64_t v1, uint64_t m2) |
e72ca652 | 778 | { |
fc7cc951 | 779 | return (m2 & float64_dcmask(env, v1)) != 0; |
e72ca652 BS |
780 | } |
781 | ||
782 | /* test data class 128-bit */ | |
fc7cc951 DH |
783 | uint32_t HELPER(tcxb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint64_t m2) |
784 | { | |
785 | return (m2 & float128_dcmask(env, make_float128(ah, al))) != 0; | |
e72ca652 BS |
786 | } |
787 | ||
16d7b2a4 RH |
788 | /* square root 32-bit */ |
789 | uint64_t HELPER(sqeb)(CPUS390XState *env, uint64_t f2) | |
e72ca652 | 790 | { |
16d7b2a4 | 791 | float32 ret = float32_sqrt(f2, &env->fpu_status); |
cf97f9ff | 792 | handle_exceptions(env, false, GETPC()); |
16d7b2a4 RH |
793 | return ret; |
794 | } | |
795 | ||
796 | /* square root 64-bit */ | |
797 | uint64_t HELPER(sqdb)(CPUS390XState *env, uint64_t f2) | |
798 | { | |
799 | float64 ret = float64_sqrt(f2, &env->fpu_status); | |
cf97f9ff | 800 | handle_exceptions(env, false, GETPC()); |
16d7b2a4 RH |
801 | return ret; |
802 | } | |
803 | ||
804 | /* square root 128-bit */ | |
805 | uint64_t HELPER(sqxb)(CPUS390XState *env, uint64_t ah, uint64_t al) | |
806 | { | |
807 | float128 ret = float128_sqrt(make_float128(ah, al), &env->fpu_status); | |
cf97f9ff | 808 | handle_exceptions(env, false, GETPC()); |
16d7b2a4 | 809 | return RET128(ret); |
e72ca652 | 810 | } |
8379bfdb | 811 | |
2aea83c6 | 812 | static const int fpc_to_rnd[8] = { |
411edc22 RH |
813 | float_round_nearest_even, |
814 | float_round_to_zero, | |
815 | float_round_up, | |
2aea83c6 DH |
816 | float_round_down, |
817 | -1, | |
818 | -1, | |
819 | -1, | |
820 | float_round_to_odd, | |
411edc22 RH |
821 | }; |
822 | ||
8379bfdb RH |
823 | /* set fpc */ |
824 | void HELPER(sfpc)(CPUS390XState *env, uint64_t fpc) | |
825 | { | |
2aea83c6 DH |
826 | if (fpc_to_rnd[fpc & 0x7] == -1 || fpc & 0x03030088u || |
827 | (!s390_has_feat(S390_FEAT_FLOATING_POINT_EXT) && fpc & 0x4)) { | |
1e36aee6 | 828 | tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC()); |
2aea83c6 DH |
829 | } |
830 | ||
8379bfdb RH |
831 | /* Install everything in the main FPC. */ |
832 | env->fpc = fpc; | |
833 | ||
834 | /* Install the rounding mode in the shadow fpu_status. */ | |
2aea83c6 | 835 | set_float_rounding_mode(fpc_to_rnd[fpc & 0x7], &env->fpu_status); |
411edc22 RH |
836 | } |
837 | ||
838 | /* set fpc and signal */ | |
f66a0ecf | 839 | void HELPER(sfas)(CPUS390XState *env, uint64_t fpc) |
411edc22 RH |
840 | { |
841 | uint32_t signalling = env->fpc; | |
411edc22 RH |
842 | uint32_t s390_exc; |
843 | ||
2aea83c6 DH |
844 | if (fpc_to_rnd[fpc & 0x7] == -1 || fpc & 0x03030088u || |
845 | (!s390_has_feat(S390_FEAT_FLOATING_POINT_EXT) && fpc & 0x4)) { | |
1e36aee6 | 846 | tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC()); |
2aea83c6 DH |
847 | } |
848 | ||
f66a0ecf DH |
849 | /* |
850 | * FPC is set to the FPC operand with a bitwise OR of the signalling | |
851 | * flags. | |
852 | */ | |
853 | env->fpc = fpc | (signalling & 0x00ff0000); | |
2aea83c6 | 854 | set_float_rounding_mode(fpc_to_rnd[fpc & 0x7], &env->fpu_status); |
411edc22 | 855 | |
f66a0ecf DH |
856 | /* |
857 | * If any signaling flag is enabled in the new FPC mask, a | |
858 | * simulated-iee-exception exception occurs. | |
859 | */ | |
860 | s390_exc = (signalling >> 16) & (fpc >> 24); | |
411edc22 | 861 | if (s390_exc) { |
8772bbe4 DH |
862 | if (s390_exc & S390_IEEE_MASK_INVALID) { |
863 | s390_exc = S390_IEEE_MASK_INVALID; | |
864 | } else if (s390_exc & S390_IEEE_MASK_DIVBYZERO) { | |
865 | s390_exc = S390_IEEE_MASK_DIVBYZERO; | |
866 | } else if (s390_exc & S390_IEEE_MASK_OVERFLOW) { | |
867 | s390_exc &= (S390_IEEE_MASK_OVERFLOW | S390_IEEE_MASK_INEXACT); | |
868 | } else if (s390_exc & S390_IEEE_MASK_UNDERFLOW) { | |
869 | s390_exc &= (S390_IEEE_MASK_UNDERFLOW | S390_IEEE_MASK_INEXACT); | |
870 | } else if (s390_exc & S390_IEEE_MASK_INEXACT) { | |
871 | s390_exc = S390_IEEE_MASK_INEXACT; | |
872 | } else if (s390_exc & S390_IEEE_MASK_QUANTUM) { | |
873 | s390_exc = S390_IEEE_MASK_QUANTUM; | |
874 | } | |
bbf6ea3b | 875 | tcg_s390_data_exception(env, s390_exc | 3, GETPC()); |
411edc22 | 876 | } |
8379bfdb | 877 | } |
b9c737f5 DH |
878 | |
879 | /* set bfp rounding mode */ | |
880 | void HELPER(srnm)(CPUS390XState *env, uint64_t rnd) | |
881 | { | |
882 | if (rnd > 0x7 || fpc_to_rnd[rnd & 0x7] == -1) { | |
1e36aee6 | 883 | tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC()); |
b9c737f5 DH |
884 | } |
885 | ||
886 | env->fpc = deposit32(env->fpc, 0, 3, rnd); | |
887 | set_float_rounding_mode(fpc_to_rnd[rnd & 0x7], &env->fpu_status); | |
888 | } |