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