]>
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 | |
10 | * version 2 of the License, or (at your option) any later version. | |
11 | * | |
12 | * This library is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
18 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. | |
19 | */ | |
20 | ||
21 | #include "cpu.h" | |
22 | #include "dyngen-exec.h" | |
23 | #include "helper.h" | |
24 | ||
25 | #if !defined(CONFIG_USER_ONLY) | |
26 | #include "softmmu_exec.h" | |
27 | #endif | |
28 | ||
29 | /* #define DEBUG_HELPER */ | |
30 | #ifdef DEBUG_HELPER | |
31 | #define HELPER_LOG(x...) qemu_log(x) | |
32 | #else | |
33 | #define HELPER_LOG(x...) | |
34 | #endif | |
35 | ||
36 | static inline int float_comp_to_cc(int float_compare) | |
37 | { | |
38 | switch (float_compare) { | |
39 | case float_relation_equal: | |
40 | return 0; | |
41 | case float_relation_less: | |
42 | return 1; | |
43 | case float_relation_greater: | |
44 | return 2; | |
45 | case float_relation_unordered: | |
46 | return 3; | |
47 | default: | |
48 | cpu_abort(env, "unknown return value for float compare\n"); | |
49 | } | |
50 | } | |
51 | ||
52 | /* condition codes for binary FP ops */ | |
53 | uint32_t set_cc_f32(float32 v1, float32 v2) | |
54 | { | |
55 | return float_comp_to_cc(float32_compare_quiet(v1, v2, &env->fpu_status)); | |
56 | } | |
57 | ||
58 | uint32_t set_cc_f64(float64 v1, float64 v2) | |
59 | { | |
60 | return float_comp_to_cc(float64_compare_quiet(v1, v2, &env->fpu_status)); | |
61 | } | |
62 | ||
63 | /* condition codes for unary FP ops */ | |
64 | uint32_t set_cc_nz_f32(float32 v) | |
65 | { | |
66 | if (float32_is_any_nan(v)) { | |
67 | return 3; | |
68 | } else if (float32_is_zero(v)) { | |
69 | return 0; | |
70 | } else if (float32_is_neg(v)) { | |
71 | return 1; | |
72 | } else { | |
73 | return 2; | |
74 | } | |
75 | } | |
76 | ||
77 | uint32_t set_cc_nz_f64(float64 v) | |
78 | { | |
79 | if (float64_is_any_nan(v)) { | |
80 | return 3; | |
81 | } else if (float64_is_zero(v)) { | |
82 | return 0; | |
83 | } else if (float64_is_neg(v)) { | |
84 | return 1; | |
85 | } else { | |
86 | return 2; | |
87 | } | |
88 | } | |
89 | ||
90 | static uint32_t set_cc_nz_f128(float128 v) | |
91 | { | |
92 | if (float128_is_any_nan(v)) { | |
93 | return 3; | |
94 | } else if (float128_is_zero(v)) { | |
95 | return 0; | |
96 | } else if (float128_is_neg(v)) { | |
97 | return 1; | |
98 | } else { | |
99 | return 2; | |
100 | } | |
101 | } | |
102 | ||
103 | /* convert 32-bit int to 64-bit float */ | |
104 | void HELPER(cdfbr)(uint32_t f1, int32_t v2) | |
105 | { | |
106 | HELPER_LOG("%s: converting %d to f%d\n", __func__, v2, f1); | |
107 | env->fregs[f1].d = int32_to_float64(v2, &env->fpu_status); | |
108 | } | |
109 | ||
110 | /* convert 32-bit int to 128-bit float */ | |
111 | void HELPER(cxfbr)(uint32_t f1, int32_t v2) | |
112 | { | |
113 | CPU_QuadU v1; | |
114 | ||
115 | v1.q = int32_to_float128(v2, &env->fpu_status); | |
116 | env->fregs[f1].ll = v1.ll.upper; | |
117 | env->fregs[f1 + 2].ll = v1.ll.lower; | |
118 | } | |
119 | ||
120 | /* convert 64-bit int to 32-bit float */ | |
121 | void HELPER(cegbr)(uint32_t f1, int64_t v2) | |
122 | { | |
123 | HELPER_LOG("%s: converting %ld to f%d\n", __func__, v2, f1); | |
124 | env->fregs[f1].l.upper = int64_to_float32(v2, &env->fpu_status); | |
125 | } | |
126 | ||
127 | /* convert 64-bit int to 64-bit float */ | |
128 | void HELPER(cdgbr)(uint32_t f1, int64_t v2) | |
129 | { | |
130 | HELPER_LOG("%s: converting %ld to f%d\n", __func__, v2, f1); | |
131 | env->fregs[f1].d = int64_to_float64(v2, &env->fpu_status); | |
132 | } | |
133 | ||
134 | /* convert 64-bit int to 128-bit float */ | |
135 | void HELPER(cxgbr)(uint32_t f1, int64_t v2) | |
136 | { | |
137 | CPU_QuadU x1; | |
138 | ||
139 | x1.q = int64_to_float128(v2, &env->fpu_status); | |
140 | HELPER_LOG("%s: converted %ld to 0x%lx and 0x%lx\n", __func__, v2, | |
141 | x1.ll.upper, x1.ll.lower); | |
142 | env->fregs[f1].ll = x1.ll.upper; | |
143 | env->fregs[f1 + 2].ll = x1.ll.lower; | |
144 | } | |
145 | ||
146 | /* convert 32-bit int to 32-bit float */ | |
147 | void HELPER(cefbr)(uint32_t f1, int32_t v2) | |
148 | { | |
149 | env->fregs[f1].l.upper = int32_to_float32(v2, &env->fpu_status); | |
150 | HELPER_LOG("%s: converting %d to 0x%d in f%d\n", __func__, v2, | |
151 | env->fregs[f1].l.upper, f1); | |
152 | } | |
153 | ||
154 | /* 32-bit FP addition RR */ | |
155 | uint32_t HELPER(aebr)(uint32_t f1, uint32_t f2) | |
156 | { | |
157 | env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper, | |
158 | env->fregs[f2].l.upper, | |
159 | &env->fpu_status); | |
160 | HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __func__, | |
161 | env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1); | |
162 | ||
163 | return set_cc_nz_f32(env->fregs[f1].l.upper); | |
164 | } | |
165 | ||
166 | /* 64-bit FP addition RR */ | |
167 | uint32_t HELPER(adbr)(uint32_t f1, uint32_t f2) | |
168 | { | |
169 | env->fregs[f1].d = float64_add(env->fregs[f1].d, env->fregs[f2].d, | |
170 | &env->fpu_status); | |
171 | HELPER_LOG("%s: adding 0x%ld resulting in 0x%ld in f%d\n", __func__, | |
172 | env->fregs[f2].d, env->fregs[f1].d, f1); | |
173 | ||
174 | return set_cc_nz_f64(env->fregs[f1].d); | |
175 | } | |
176 | ||
177 | /* 32-bit FP subtraction RR */ | |
178 | uint32_t HELPER(sebr)(uint32_t f1, uint32_t f2) | |
179 | { | |
180 | env->fregs[f1].l.upper = float32_sub(env->fregs[f1].l.upper, | |
181 | env->fregs[f2].l.upper, | |
182 | &env->fpu_status); | |
183 | HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __func__, | |
184 | env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1); | |
185 | ||
186 | return set_cc_nz_f32(env->fregs[f1].l.upper); | |
187 | } | |
188 | ||
189 | /* 64-bit FP subtraction RR */ | |
190 | uint32_t HELPER(sdbr)(uint32_t f1, uint32_t f2) | |
191 | { | |
192 | env->fregs[f1].d = float64_sub(env->fregs[f1].d, env->fregs[f2].d, | |
193 | &env->fpu_status); | |
194 | HELPER_LOG("%s: subtracting 0x%ld resulting in 0x%ld in f%d\n", | |
195 | __func__, env->fregs[f2].d, env->fregs[f1].d, f1); | |
196 | ||
197 | return set_cc_nz_f64(env->fregs[f1].d); | |
198 | } | |
199 | ||
200 | /* 32-bit FP division RR */ | |
201 | void HELPER(debr)(uint32_t f1, uint32_t f2) | |
202 | { | |
203 | env->fregs[f1].l.upper = float32_div(env->fregs[f1].l.upper, | |
204 | env->fregs[f2].l.upper, | |
205 | &env->fpu_status); | |
206 | } | |
207 | ||
208 | /* 128-bit FP division RR */ | |
209 | void HELPER(dxbr)(uint32_t f1, uint32_t f2) | |
210 | { | |
211 | CPU_QuadU v1; | |
212 | CPU_QuadU v2; | |
213 | CPU_QuadU res; | |
214 | ||
215 | v1.ll.upper = env->fregs[f1].ll; | |
216 | v1.ll.lower = env->fregs[f1 + 2].ll; | |
217 | v2.ll.upper = env->fregs[f2].ll; | |
218 | v2.ll.lower = env->fregs[f2 + 2].ll; | |
219 | res.q = float128_div(v1.q, v2.q, &env->fpu_status); | |
220 | env->fregs[f1].ll = res.ll.upper; | |
221 | env->fregs[f1 + 2].ll = res.ll.lower; | |
222 | } | |
223 | ||
224 | /* 64-bit FP multiplication RR */ | |
225 | void HELPER(mdbr)(uint32_t f1, uint32_t f2) | |
226 | { | |
227 | env->fregs[f1].d = float64_mul(env->fregs[f1].d, env->fregs[f2].d, | |
228 | &env->fpu_status); | |
229 | } | |
230 | ||
231 | /* 128-bit FP multiplication RR */ | |
232 | void HELPER(mxbr)(uint32_t f1, uint32_t f2) | |
233 | { | |
234 | CPU_QuadU v1; | |
235 | CPU_QuadU v2; | |
236 | CPU_QuadU res; | |
237 | ||
238 | v1.ll.upper = env->fregs[f1].ll; | |
239 | v1.ll.lower = env->fregs[f1 + 2].ll; | |
240 | v2.ll.upper = env->fregs[f2].ll; | |
241 | v2.ll.lower = env->fregs[f2 + 2].ll; | |
242 | res.q = float128_mul(v1.q, v2.q, &env->fpu_status); | |
243 | env->fregs[f1].ll = res.ll.upper; | |
244 | env->fregs[f1 + 2].ll = res.ll.lower; | |
245 | } | |
246 | ||
247 | /* convert 32-bit float to 64-bit float */ | |
248 | void HELPER(ldebr)(uint32_t r1, uint32_t r2) | |
249 | { | |
250 | env->fregs[r1].d = float32_to_float64(env->fregs[r2].l.upper, | |
251 | &env->fpu_status); | |
252 | } | |
253 | ||
254 | /* convert 128-bit float to 64-bit float */ | |
255 | void HELPER(ldxbr)(uint32_t f1, uint32_t f2) | |
256 | { | |
257 | CPU_QuadU x2; | |
258 | ||
259 | x2.ll.upper = env->fregs[f2].ll; | |
260 | x2.ll.lower = env->fregs[f2 + 2].ll; | |
261 | env->fregs[f1].d = float128_to_float64(x2.q, &env->fpu_status); | |
262 | HELPER_LOG("%s: to 0x%ld\n", __func__, env->fregs[f1].d); | |
263 | } | |
264 | ||
265 | /* convert 64-bit float to 128-bit float */ | |
266 | void HELPER(lxdbr)(uint32_t f1, uint32_t f2) | |
267 | { | |
268 | CPU_QuadU res; | |
269 | ||
270 | res.q = float64_to_float128(env->fregs[f2].d, &env->fpu_status); | |
271 | env->fregs[f1].ll = res.ll.upper; | |
272 | env->fregs[f1 + 2].ll = res.ll.lower; | |
273 | } | |
274 | ||
275 | /* convert 64-bit float to 32-bit float */ | |
276 | void HELPER(ledbr)(uint32_t f1, uint32_t f2) | |
277 | { | |
278 | float64 d2 = env->fregs[f2].d; | |
279 | ||
280 | env->fregs[f1].l.upper = float64_to_float32(d2, &env->fpu_status); | |
281 | } | |
282 | ||
283 | /* convert 128-bit float to 32-bit float */ | |
284 | void HELPER(lexbr)(uint32_t f1, uint32_t f2) | |
285 | { | |
286 | CPU_QuadU x2; | |
287 | ||
288 | x2.ll.upper = env->fregs[f2].ll; | |
289 | x2.ll.lower = env->fregs[f2 + 2].ll; | |
290 | env->fregs[f1].l.upper = float128_to_float32(x2.q, &env->fpu_status); | |
291 | HELPER_LOG("%s: to 0x%d\n", __func__, env->fregs[f1].l.upper); | |
292 | } | |
293 | ||
294 | /* absolute value of 32-bit float */ | |
295 | uint32_t HELPER(lpebr)(uint32_t f1, uint32_t f2) | |
296 | { | |
297 | float32 v1; | |
298 | float32 v2 = env->fregs[f2].d; | |
299 | ||
300 | v1 = float32_abs(v2); | |
301 | env->fregs[f1].d = v1; | |
302 | return set_cc_nz_f32(v1); | |
303 | } | |
304 | ||
305 | /* absolute value of 64-bit float */ | |
306 | uint32_t HELPER(lpdbr)(uint32_t f1, uint32_t f2) | |
307 | { | |
308 | float64 v1; | |
309 | float64 v2 = env->fregs[f2].d; | |
310 | ||
311 | v1 = float64_abs(v2); | |
312 | env->fregs[f1].d = v1; | |
313 | return set_cc_nz_f64(v1); | |
314 | } | |
315 | ||
316 | /* absolute value of 128-bit float */ | |
317 | uint32_t HELPER(lpxbr)(uint32_t f1, uint32_t f2) | |
318 | { | |
319 | CPU_QuadU v1; | |
320 | CPU_QuadU v2; | |
321 | ||
322 | v2.ll.upper = env->fregs[f2].ll; | |
323 | v2.ll.lower = env->fregs[f2 + 2].ll; | |
324 | v1.q = float128_abs(v2.q); | |
325 | env->fregs[f1].ll = v1.ll.upper; | |
326 | env->fregs[f1 + 2].ll = v1.ll.lower; | |
327 | return set_cc_nz_f128(v1.q); | |
328 | } | |
329 | ||
330 | /* load and test 64-bit float */ | |
331 | uint32_t HELPER(ltdbr)(uint32_t f1, uint32_t f2) | |
332 | { | |
333 | env->fregs[f1].d = env->fregs[f2].d; | |
334 | return set_cc_nz_f64(env->fregs[f1].d); | |
335 | } | |
336 | ||
337 | /* load and test 32-bit float */ | |
338 | uint32_t HELPER(ltebr)(uint32_t f1, uint32_t f2) | |
339 | { | |
340 | env->fregs[f1].l.upper = env->fregs[f2].l.upper; | |
341 | return set_cc_nz_f32(env->fregs[f1].l.upper); | |
342 | } | |
343 | ||
344 | /* load and test 128-bit float */ | |
345 | uint32_t HELPER(ltxbr)(uint32_t f1, uint32_t f2) | |
346 | { | |
347 | CPU_QuadU x; | |
348 | ||
349 | x.ll.upper = env->fregs[f2].ll; | |
350 | x.ll.lower = env->fregs[f2 + 2].ll; | |
351 | env->fregs[f1].ll = x.ll.upper; | |
352 | env->fregs[f1 + 2].ll = x.ll.lower; | |
353 | return set_cc_nz_f128(x.q); | |
354 | } | |
355 | ||
356 | /* load complement of 32-bit float */ | |
357 | uint32_t HELPER(lcebr)(uint32_t f1, uint32_t f2) | |
358 | { | |
359 | env->fregs[f1].l.upper = float32_chs(env->fregs[f2].l.upper); | |
360 | ||
361 | return set_cc_nz_f32(env->fregs[f1].l.upper); | |
362 | } | |
363 | ||
364 | /* load complement of 64-bit float */ | |
365 | uint32_t HELPER(lcdbr)(uint32_t f1, uint32_t f2) | |
366 | { | |
367 | env->fregs[f1].d = float64_chs(env->fregs[f2].d); | |
368 | ||
369 | return set_cc_nz_f64(env->fregs[f1].d); | |
370 | } | |
371 | ||
372 | /* load complement of 128-bit float */ | |
373 | uint32_t HELPER(lcxbr)(uint32_t f1, uint32_t f2) | |
374 | { | |
375 | CPU_QuadU x1, x2; | |
376 | ||
377 | x2.ll.upper = env->fregs[f2].ll; | |
378 | x2.ll.lower = env->fregs[f2 + 2].ll; | |
379 | x1.q = float128_chs(x2.q); | |
380 | env->fregs[f1].ll = x1.ll.upper; | |
381 | env->fregs[f1 + 2].ll = x1.ll.lower; | |
382 | return set_cc_nz_f128(x1.q); | |
383 | } | |
384 | ||
385 | /* 32-bit FP addition RM */ | |
386 | void HELPER(aeb)(uint32_t f1, uint32_t val) | |
387 | { | |
388 | float32 v1 = env->fregs[f1].l.upper; | |
389 | CPU_FloatU v2; | |
390 | ||
391 | v2.l = val; | |
392 | HELPER_LOG("%s: adding 0x%d from f%d and 0x%d\n", __func__, | |
393 | v1, f1, v2.f); | |
394 | env->fregs[f1].l.upper = float32_add(v1, v2.f, &env->fpu_status); | |
395 | } | |
396 | ||
397 | /* 32-bit FP division RM */ | |
398 | void HELPER(deb)(uint32_t f1, uint32_t val) | |
399 | { | |
400 | float32 v1 = env->fregs[f1].l.upper; | |
401 | CPU_FloatU v2; | |
402 | ||
403 | v2.l = val; | |
404 | HELPER_LOG("%s: dividing 0x%d from f%d by 0x%d\n", __func__, | |
405 | v1, f1, v2.f); | |
406 | env->fregs[f1].l.upper = float32_div(v1, v2.f, &env->fpu_status); | |
407 | } | |
408 | ||
409 | /* 32-bit FP multiplication RM */ | |
410 | void HELPER(meeb)(uint32_t f1, uint32_t val) | |
411 | { | |
412 | float32 v1 = env->fregs[f1].l.upper; | |
413 | CPU_FloatU v2; | |
414 | ||
415 | v2.l = val; | |
416 | HELPER_LOG("%s: multiplying 0x%d from f%d and 0x%d\n", __func__, | |
417 | v1, f1, v2.f); | |
418 | env->fregs[f1].l.upper = float32_mul(v1, v2.f, &env->fpu_status); | |
419 | } | |
420 | ||
421 | /* 32-bit FP compare RR */ | |
422 | uint32_t HELPER(cebr)(uint32_t f1, uint32_t f2) | |
423 | { | |
424 | float32 v1 = env->fregs[f1].l.upper; | |
425 | float32 v2 = env->fregs[f2].l.upper; | |
426 | ||
427 | HELPER_LOG("%s: comparing 0x%d from f%d and 0x%d\n", __func__, | |
428 | v1, f1, v2); | |
429 | return set_cc_f32(v1, v2); | |
430 | } | |
431 | ||
432 | /* 64-bit FP compare RR */ | |
433 | uint32_t HELPER(cdbr)(uint32_t f1, uint32_t f2) | |
434 | { | |
435 | float64 v1 = env->fregs[f1].d; | |
436 | float64 v2 = env->fregs[f2].d; | |
437 | ||
438 | HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%ld\n", __func__, | |
439 | v1, f1, v2); | |
440 | return set_cc_f64(v1, v2); | |
441 | } | |
442 | ||
443 | /* 128-bit FP compare RR */ | |
444 | uint32_t HELPER(cxbr)(uint32_t f1, uint32_t f2) | |
445 | { | |
446 | CPU_QuadU v1; | |
447 | CPU_QuadU v2; | |
448 | ||
449 | v1.ll.upper = env->fregs[f1].ll; | |
450 | v1.ll.lower = env->fregs[f1 + 2].ll; | |
451 | v2.ll.upper = env->fregs[f2].ll; | |
452 | v2.ll.lower = env->fregs[f2 + 2].ll; | |
453 | ||
454 | return float_comp_to_cc(float128_compare_quiet(v1.q, v2.q, | |
455 | &env->fpu_status)); | |
456 | } | |
457 | ||
458 | /* 64-bit FP compare RM */ | |
459 | uint32_t HELPER(cdb)(uint32_t f1, uint64_t a2) | |
460 | { | |
461 | float64 v1 = env->fregs[f1].d; | |
462 | CPU_DoubleU v2; | |
463 | ||
464 | v2.ll = ldq(a2); | |
465 | HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%lx\n", __func__, v1, | |
466 | f1, v2.d); | |
467 | return set_cc_f64(v1, v2.d); | |
468 | } | |
469 | ||
470 | /* 64-bit FP addition RM */ | |
471 | uint32_t HELPER(adb)(uint32_t f1, uint64_t a2) | |
472 | { | |
473 | float64 v1 = env->fregs[f1].d; | |
474 | CPU_DoubleU v2; | |
475 | ||
476 | v2.ll = ldq(a2); | |
477 | HELPER_LOG("%s: adding 0x%lx from f%d and 0x%lx\n", __func__, | |
478 | v1, f1, v2.d); | |
479 | env->fregs[f1].d = v1 = float64_add(v1, v2.d, &env->fpu_status); | |
480 | return set_cc_nz_f64(v1); | |
481 | } | |
482 | ||
483 | /* 32-bit FP subtraction RM */ | |
484 | void HELPER(seb)(uint32_t f1, uint32_t val) | |
485 | { | |
486 | float32 v1 = env->fregs[f1].l.upper; | |
487 | CPU_FloatU v2; | |
488 | ||
489 | v2.l = val; | |
490 | env->fregs[f1].l.upper = float32_sub(v1, v2.f, &env->fpu_status); | |
491 | } | |
492 | ||
493 | /* 64-bit FP subtraction RM */ | |
494 | uint32_t HELPER(sdb)(uint32_t f1, uint64_t a2) | |
495 | { | |
496 | float64 v1 = env->fregs[f1].d; | |
497 | CPU_DoubleU v2; | |
498 | ||
499 | v2.ll = ldq(a2); | |
500 | env->fregs[f1].d = v1 = float64_sub(v1, v2.d, &env->fpu_status); | |
501 | return set_cc_nz_f64(v1); | |
502 | } | |
503 | ||
504 | /* 64-bit FP multiplication RM */ | |
505 | void HELPER(mdb)(uint32_t f1, uint64_t a2) | |
506 | { | |
507 | float64 v1 = env->fregs[f1].d; | |
508 | CPU_DoubleU v2; | |
509 | ||
510 | v2.ll = ldq(a2); | |
511 | HELPER_LOG("%s: multiplying 0x%lx from f%d and 0x%ld\n", __func__, | |
512 | v1, f1, v2.d); | |
513 | env->fregs[f1].d = float64_mul(v1, v2.d, &env->fpu_status); | |
514 | } | |
515 | ||
516 | /* 64-bit FP division RM */ | |
517 | void HELPER(ddb)(uint32_t f1, uint64_t a2) | |
518 | { | |
519 | float64 v1 = env->fregs[f1].d; | |
520 | CPU_DoubleU v2; | |
521 | ||
522 | v2.ll = ldq(a2); | |
523 | HELPER_LOG("%s: dividing 0x%lx from f%d by 0x%ld\n", __func__, | |
524 | v1, f1, v2.d); | |
525 | env->fregs[f1].d = float64_div(v1, v2.d, &env->fpu_status); | |
526 | } | |
527 | ||
528 | static void set_round_mode(int m3) | |
529 | { | |
530 | switch (m3) { | |
531 | case 0: | |
532 | /* current mode */ | |
533 | break; | |
534 | case 1: | |
535 | /* biased round no nearest */ | |
536 | case 4: | |
537 | /* round to nearest */ | |
538 | set_float_rounding_mode(float_round_nearest_even, &env->fpu_status); | |
539 | break; | |
540 | case 5: | |
541 | /* round to zero */ | |
542 | set_float_rounding_mode(float_round_to_zero, &env->fpu_status); | |
543 | break; | |
544 | case 6: | |
545 | /* round to +inf */ | |
546 | set_float_rounding_mode(float_round_up, &env->fpu_status); | |
547 | break; | |
548 | case 7: | |
549 | /* round to -inf */ | |
550 | set_float_rounding_mode(float_round_down, &env->fpu_status); | |
551 | break; | |
552 | } | |
553 | } | |
554 | ||
555 | /* convert 32-bit float to 64-bit int */ | |
556 | uint32_t HELPER(cgebr)(uint32_t r1, uint32_t f2, uint32_t m3) | |
557 | { | |
558 | float32 v2 = env->fregs[f2].l.upper; | |
559 | ||
560 | set_round_mode(m3); | |
561 | env->regs[r1] = float32_to_int64(v2, &env->fpu_status); | |
562 | return set_cc_nz_f32(v2); | |
563 | } | |
564 | ||
565 | /* convert 64-bit float to 64-bit int */ | |
566 | uint32_t HELPER(cgdbr)(uint32_t r1, uint32_t f2, uint32_t m3) | |
567 | { | |
568 | float64 v2 = env->fregs[f2].d; | |
569 | ||
570 | set_round_mode(m3); | |
571 | env->regs[r1] = float64_to_int64(v2, &env->fpu_status); | |
572 | return set_cc_nz_f64(v2); | |
573 | } | |
574 | ||
575 | /* convert 128-bit float to 64-bit int */ | |
576 | uint32_t HELPER(cgxbr)(uint32_t r1, uint32_t f2, uint32_t m3) | |
577 | { | |
578 | CPU_QuadU v2; | |
579 | ||
580 | v2.ll.upper = env->fregs[f2].ll; | |
581 | v2.ll.lower = env->fregs[f2 + 2].ll; | |
582 | set_round_mode(m3); | |
583 | env->regs[r1] = float128_to_int64(v2.q, &env->fpu_status); | |
584 | if (float128_is_any_nan(v2.q)) { | |
585 | return 3; | |
586 | } else if (float128_is_zero(v2.q)) { | |
587 | return 0; | |
588 | } else if (float128_is_neg(v2.q)) { | |
589 | return 1; | |
590 | } else { | |
591 | return 2; | |
592 | } | |
593 | } | |
594 | ||
595 | /* convert 32-bit float to 32-bit int */ | |
596 | uint32_t HELPER(cfebr)(uint32_t r1, uint32_t f2, uint32_t m3) | |
597 | { | |
598 | float32 v2 = env->fregs[f2].l.upper; | |
599 | ||
600 | set_round_mode(m3); | |
601 | env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | | |
602 | float32_to_int32(v2, &env->fpu_status); | |
603 | return set_cc_nz_f32(v2); | |
604 | } | |
605 | ||
606 | /* convert 64-bit float to 32-bit int */ | |
607 | uint32_t HELPER(cfdbr)(uint32_t r1, uint32_t f2, uint32_t m3) | |
608 | { | |
609 | float64 v2 = env->fregs[f2].d; | |
610 | ||
611 | set_round_mode(m3); | |
612 | env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | | |
613 | float64_to_int32(v2, &env->fpu_status); | |
614 | return set_cc_nz_f64(v2); | |
615 | } | |
616 | ||
617 | /* convert 128-bit float to 32-bit int */ | |
618 | uint32_t HELPER(cfxbr)(uint32_t r1, uint32_t f2, uint32_t m3) | |
619 | { | |
620 | CPU_QuadU v2; | |
621 | ||
622 | v2.ll.upper = env->fregs[f2].ll; | |
623 | v2.ll.lower = env->fregs[f2 + 2].ll; | |
624 | env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | | |
625 | float128_to_int32(v2.q, &env->fpu_status); | |
626 | return set_cc_nz_f128(v2.q); | |
627 | } | |
628 | ||
629 | /* load 32-bit FP zero */ | |
630 | void HELPER(lzer)(uint32_t f1) | |
631 | { | |
632 | env->fregs[f1].l.upper = float32_zero; | |
633 | } | |
634 | ||
635 | /* load 64-bit FP zero */ | |
636 | void HELPER(lzdr)(uint32_t f1) | |
637 | { | |
638 | env->fregs[f1].d = float64_zero; | |
639 | } | |
640 | ||
641 | /* load 128-bit FP zero */ | |
642 | void HELPER(lzxr)(uint32_t f1) | |
643 | { | |
644 | CPU_QuadU x; | |
645 | ||
646 | x.q = float64_to_float128(float64_zero, &env->fpu_status); | |
647 | env->fregs[f1].ll = x.ll.upper; | |
648 | env->fregs[f1 + 1].ll = x.ll.lower; | |
649 | } | |
650 | ||
651 | /* 128-bit FP subtraction RR */ | |
652 | uint32_t HELPER(sxbr)(uint32_t f1, uint32_t f2) | |
653 | { | |
654 | CPU_QuadU v1; | |
655 | CPU_QuadU v2; | |
656 | CPU_QuadU res; | |
657 | ||
658 | v1.ll.upper = env->fregs[f1].ll; | |
659 | v1.ll.lower = env->fregs[f1 + 2].ll; | |
660 | v2.ll.upper = env->fregs[f2].ll; | |
661 | v2.ll.lower = env->fregs[f2 + 2].ll; | |
662 | res.q = float128_sub(v1.q, v2.q, &env->fpu_status); | |
663 | env->fregs[f1].ll = res.ll.upper; | |
664 | env->fregs[f1 + 2].ll = res.ll.lower; | |
665 | return set_cc_nz_f128(res.q); | |
666 | } | |
667 | ||
668 | /* 128-bit FP addition RR */ | |
669 | uint32_t HELPER(axbr)(uint32_t f1, uint32_t f2) | |
670 | { | |
671 | CPU_QuadU v1; | |
672 | CPU_QuadU v2; | |
673 | CPU_QuadU res; | |
674 | ||
675 | v1.ll.upper = env->fregs[f1].ll; | |
676 | v1.ll.lower = env->fregs[f1 + 2].ll; | |
677 | v2.ll.upper = env->fregs[f2].ll; | |
678 | v2.ll.lower = env->fregs[f2 + 2].ll; | |
679 | res.q = float128_add(v1.q, v2.q, &env->fpu_status); | |
680 | env->fregs[f1].ll = res.ll.upper; | |
681 | env->fregs[f1 + 2].ll = res.ll.lower; | |
682 | return set_cc_nz_f128(res.q); | |
683 | } | |
684 | ||
685 | /* 32-bit FP multiplication RR */ | |
686 | void HELPER(meebr)(uint32_t f1, uint32_t f2) | |
687 | { | |
688 | env->fregs[f1].l.upper = float32_mul(env->fregs[f1].l.upper, | |
689 | env->fregs[f2].l.upper, | |
690 | &env->fpu_status); | |
691 | } | |
692 | ||
693 | /* 64-bit FP division RR */ | |
694 | void HELPER(ddbr)(uint32_t f1, uint32_t f2) | |
695 | { | |
696 | env->fregs[f1].d = float64_div(env->fregs[f1].d, env->fregs[f2].d, | |
697 | &env->fpu_status); | |
698 | } | |
699 | ||
700 | /* 64-bit FP multiply and add RM */ | |
701 | void HELPER(madb)(uint32_t f1, uint64_t a2, uint32_t f3) | |
702 | { | |
703 | CPU_DoubleU v2; | |
704 | ||
705 | HELPER_LOG("%s: f1 %d a2 0x%lx f3 %d\n", __func__, f1, a2, f3); | |
706 | v2.ll = ldq(a2); | |
707 | env->fregs[f1].d = float64_add(env->fregs[f1].d, | |
708 | float64_mul(v2.d, env->fregs[f3].d, | |
709 | &env->fpu_status), | |
710 | &env->fpu_status); | |
711 | } | |
712 | ||
713 | /* 64-bit FP multiply and add RR */ | |
714 | void HELPER(madbr)(uint32_t f1, uint32_t f3, uint32_t f2) | |
715 | { | |
716 | HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __func__, f1, f2, f3); | |
717 | env->fregs[f1].d = float64_add(float64_mul(env->fregs[f2].d, | |
718 | env->fregs[f3].d, | |
719 | &env->fpu_status), | |
720 | env->fregs[f1].d, &env->fpu_status); | |
721 | } | |
722 | ||
723 | /* 64-bit FP multiply and subtract RR */ | |
724 | void HELPER(msdbr)(uint32_t f1, uint32_t f3, uint32_t f2) | |
725 | { | |
726 | HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __func__, f1, f2, f3); | |
727 | env->fregs[f1].d = float64_sub(float64_mul(env->fregs[f2].d, | |
728 | env->fregs[f3].d, | |
729 | &env->fpu_status), | |
730 | env->fregs[f1].d, &env->fpu_status); | |
731 | } | |
732 | ||
733 | /* 32-bit FP multiply and add RR */ | |
734 | void HELPER(maebr)(uint32_t f1, uint32_t f3, uint32_t f2) | |
735 | { | |
736 | env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper, | |
737 | float32_mul(env->fregs[f2].l.upper, | |
738 | env->fregs[f3].l.upper, | |
739 | &env->fpu_status), | |
740 | &env->fpu_status); | |
741 | } | |
742 | ||
743 | /* convert 32-bit float to 64-bit float */ | |
744 | void HELPER(ldeb)(uint32_t f1, uint64_t a2) | |
745 | { | |
746 | uint32_t v2; | |
747 | ||
748 | v2 = ldl(a2); | |
749 | env->fregs[f1].d = float32_to_float64(v2, | |
750 | &env->fpu_status); | |
751 | } | |
752 | ||
753 | /* convert 64-bit float to 128-bit float */ | |
754 | void HELPER(lxdb)(uint32_t f1, uint64_t a2) | |
755 | { | |
756 | CPU_DoubleU v2; | |
757 | CPU_QuadU v1; | |
758 | ||
759 | v2.ll = ldq(a2); | |
760 | v1.q = float64_to_float128(v2.d, &env->fpu_status); | |
761 | env->fregs[f1].ll = v1.ll.upper; | |
762 | env->fregs[f1 + 2].ll = v1.ll.lower; | |
763 | } | |
764 | ||
765 | /* test data class 32-bit */ | |
766 | uint32_t HELPER(tceb)(uint32_t f1, uint64_t m2) | |
767 | { | |
768 | float32 v1 = env->fregs[f1].l.upper; | |
769 | int neg = float32_is_neg(v1); | |
770 | uint32_t cc = 0; | |
771 | ||
772 | HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __func__, (long)v1, m2, neg); | |
773 | if ((float32_is_zero(v1) && (m2 & (1 << (11-neg)))) || | |
774 | (float32_is_infinity(v1) && (m2 & (1 << (5-neg)))) || | |
775 | (float32_is_any_nan(v1) && (m2 & (1 << (3-neg)))) || | |
776 | (float32_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) { | |
777 | cc = 1; | |
778 | } else if (m2 & (1 << (9-neg))) { | |
779 | /* assume normalized number */ | |
780 | cc = 1; | |
781 | } | |
782 | ||
783 | /* FIXME: denormalized? */ | |
784 | return cc; | |
785 | } | |
786 | ||
787 | /* test data class 64-bit */ | |
788 | uint32_t HELPER(tcdb)(uint32_t f1, uint64_t m2) | |
789 | { | |
790 | float64 v1 = env->fregs[f1].d; | |
791 | int neg = float64_is_neg(v1); | |
792 | uint32_t cc = 0; | |
793 | ||
794 | HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __func__, v1, m2, neg); | |
795 | if ((float64_is_zero(v1) && (m2 & (1 << (11-neg)))) || | |
796 | (float64_is_infinity(v1) && (m2 & (1 << (5-neg)))) || | |
797 | (float64_is_any_nan(v1) && (m2 & (1 << (3-neg)))) || | |
798 | (float64_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) { | |
799 | cc = 1; | |
800 | } else if (m2 & (1 << (9-neg))) { | |
801 | /* assume normalized number */ | |
802 | cc = 1; | |
803 | } | |
804 | /* FIXME: denormalized? */ | |
805 | return cc; | |
806 | } | |
807 | ||
808 | /* test data class 128-bit */ | |
809 | uint32_t HELPER(tcxb)(uint32_t f1, uint64_t m2) | |
810 | { | |
811 | CPU_QuadU v1; | |
812 | uint32_t cc = 0; | |
813 | int neg; | |
814 | ||
815 | v1.ll.upper = env->fregs[f1].ll; | |
816 | v1.ll.lower = env->fregs[f1 + 2].ll; | |
817 | ||
818 | neg = float128_is_neg(v1.q); | |
819 | if ((float128_is_zero(v1.q) && (m2 & (1 << (11-neg)))) || | |
820 | (float128_is_infinity(v1.q) && (m2 & (1 << (5-neg)))) || | |
821 | (float128_is_any_nan(v1.q) && (m2 & (1 << (3-neg)))) || | |
822 | (float128_is_signaling_nan(v1.q) && (m2 & (1 << (1-neg))))) { | |
823 | cc = 1; | |
824 | } else if (m2 & (1 << (9-neg))) { | |
825 | /* assume normalized number */ | |
826 | cc = 1; | |
827 | } | |
828 | /* FIXME: denormalized? */ | |
829 | return cc; | |
830 | } | |
831 | ||
832 | /* square root 64-bit RR */ | |
833 | void HELPER(sqdbr)(uint32_t f1, uint32_t f2) | |
834 | { | |
835 | env->fregs[f1].d = float64_sqrt(env->fregs[f2].d, &env->fpu_status); | |
836 | } |