]>
Commit | Line | Data |
---|---|---|
4a58aedf RH |
1 | /* |
2 | * Helpers for floating point instructions. | |
3 | * | |
4 | * Copyright (c) 2007 Jocelyn Mayer | |
5 | * | |
6 | * This library is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU Lesser General Public | |
8 | * License as published by the Free Software Foundation; either | |
9 | * version 2 of the License, or (at your option) any later version. | |
10 | * | |
11 | * This library is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * Lesser General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU Lesser General Public | |
17 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. | |
18 | */ | |
19 | ||
e2e5e114 | 20 | #include "qemu/osdep.h" |
4a58aedf | 21 | #include "cpu.h" |
2ef6175a | 22 | #include "exec/helper-proto.h" |
6b4c305c | 23 | #include "fpu/softfloat.h" |
4a58aedf RH |
24 | |
25 | #define FP_STATUS (env->fp_status) | |
26 | ||
27 | ||
28 | void helper_setroundmode(CPUAlphaState *env, uint32_t val) | |
29 | { | |
30 | set_float_rounding_mode(val, &FP_STATUS); | |
31 | } | |
32 | ||
33 | void helper_setflushzero(CPUAlphaState *env, uint32_t val) | |
34 | { | |
35 | set_flush_to_zero(val, &FP_STATUS); | |
36 | } | |
37 | ||
f3d3aad4 RH |
38 | #define CONVERT_BIT(X, SRC, DST) \ |
39 | (SRC > DST ? (X) / (SRC / DST) & (DST) : ((X) & SRC) * (DST / SRC)) | |
4a58aedf | 40 | |
f3d3aad4 | 41 | static uint32_t soft_to_fpcr_exc(CPUAlphaState *env) |
4a58aedf | 42 | { |
f3d3aad4 RH |
43 | uint8_t exc = get_float_exception_flags(&FP_STATUS); |
44 | uint32_t ret = 0; | |
45 | ||
46 | if (unlikely(exc)) { | |
47 | set_float_exception_flags(0, &FP_STATUS); | |
48 | ret |= CONVERT_BIT(exc, float_flag_invalid, FPCR_INV); | |
49 | ret |= CONVERT_BIT(exc, float_flag_divbyzero, FPCR_DZE); | |
50 | ret |= CONVERT_BIT(exc, float_flag_overflow, FPCR_OVF); | |
51 | ret |= CONVERT_BIT(exc, float_flag_underflow, FPCR_UNF); | |
52 | ret |= CONVERT_BIT(exc, float_flag_inexact, FPCR_INE); | |
53 | } | |
54 | ||
55 | return ret; | |
4a58aedf RH |
56 | } |
57 | ||
f3d3aad4 | 58 | static void fp_exc_raise1(CPUAlphaState *env, uintptr_t retaddr, |
f6b6b7b8 | 59 | uint32_t exc, uint32_t regno, uint32_t hw_exc) |
4a58aedf | 60 | { |
471d4930 RH |
61 | hw_exc |= CONVERT_BIT(exc, FPCR_INV, EXC_M_INV); |
62 | hw_exc |= CONVERT_BIT(exc, FPCR_DZE, EXC_M_DZE); | |
63 | hw_exc |= CONVERT_BIT(exc, FPCR_OVF, EXC_M_FOV); | |
64 | hw_exc |= CONVERT_BIT(exc, FPCR_UNF, EXC_M_UNF); | |
65 | hw_exc |= CONVERT_BIT(exc, FPCR_INE, EXC_M_INE); | |
66 | hw_exc |= CONVERT_BIT(exc, FPCR_IOV, EXC_M_IOV); | |
4a58aedf | 67 | |
471d4930 | 68 | arith_excp(env, retaddr, hw_exc, 1ull << regno); |
4a58aedf RH |
69 | } |
70 | ||
71 | /* Raise exceptions for ieee fp insns without software completion. | |
72 | In that case there are no exceptions that don't trap; the mask | |
73 | doesn't apply. */ | |
f3d3aad4 | 74 | void helper_fp_exc_raise(CPUAlphaState *env, uint32_t ignore, uint32_t regno) |
4a58aedf | 75 | { |
471d4930 RH |
76 | uint32_t exc = env->error_code; |
77 | if (exc) { | |
78 | env->fpcr |= exc; | |
79 | exc &= ~ignore; | |
80 | if (exc) { | |
f6b6b7b8 | 81 | fp_exc_raise1(env, GETPC(), exc, regno, 0); |
471d4930 RH |
82 | } |
83 | } | |
4a58aedf RH |
84 | } |
85 | ||
86 | /* Raise exceptions for ieee fp insns with software completion. */ | |
f3d3aad4 | 87 | void helper_fp_exc_raise_s(CPUAlphaState *env, uint32_t ignore, uint32_t regno) |
4a58aedf | 88 | { |
f3d3aad4 | 89 | uint32_t exc = env->error_code & ~ignore; |
4a58aedf | 90 | if (exc) { |
f3d3aad4 | 91 | env->fpcr |= exc; |
471d4930 RH |
92 | exc &= ~ignore; |
93 | if (exc) { | |
94 | exc &= env->fpcr_exc_enable; | |
f6b6b7b8 | 95 | fp_exc_raise1(env, GETPC(), exc, regno, EXC_M_SWC); |
471d4930 | 96 | } |
4a58aedf RH |
97 | } |
98 | } | |
99 | ||
74343409 RH |
100 | /* Input handing without software completion. Trap for all |
101 | non-finite numbers. */ | |
102 | void helper_ieee_input(CPUAlphaState *env, uint64_t val) | |
4a58aedf RH |
103 | { |
104 | uint32_t exp = (uint32_t)(val >> 52) & 0x7ff; | |
105 | uint64_t frac = val & 0xfffffffffffffull; | |
106 | ||
107 | if (exp == 0) { | |
b99e8069 RH |
108 | /* Denormals without /S raise an exception. */ |
109 | if (frac != 0) { | |
110 | arith_excp(env, GETPC(), EXC_M_INV, 0); | |
4a58aedf RH |
111 | } |
112 | } else if (exp == 0x7ff) { | |
113 | /* Infinity or NaN. */ | |
b99e8069 RH |
114 | env->fpcr |= FPCR_INV; |
115 | arith_excp(env, GETPC(), EXC_M_INV, 0); | |
4a58aedf | 116 | } |
4a58aedf RH |
117 | } |
118 | ||
119 | /* Similar, but does not trap for infinities. Used for comparisons. */ | |
74343409 | 120 | void helper_ieee_input_cmp(CPUAlphaState *env, uint64_t val) |
4a58aedf RH |
121 | { |
122 | uint32_t exp = (uint32_t)(val >> 52) & 0x7ff; | |
123 | uint64_t frac = val & 0xfffffffffffffull; | |
124 | ||
125 | if (exp == 0) { | |
b99e8069 RH |
126 | /* Denormals without /S raise an exception. */ |
127 | if (frac != 0) { | |
128 | arith_excp(env, GETPC(), EXC_M_INV, 0); | |
4a58aedf RH |
129 | } |
130 | } else if (exp == 0x7ff && frac) { | |
131 | /* NaN. */ | |
b99e8069 | 132 | env->fpcr |= FPCR_INV; |
4a58aedf RH |
133 | arith_excp(env, GETPC(), EXC_M_INV, 0); |
134 | } | |
4a58aedf RH |
135 | } |
136 | ||
b99e8069 RH |
137 | /* Input handing with software completion. Trap for denorms, unless DNZ |
138 | is set. If we try to support DNOD (which none of the produced hardware | |
139 | did, AFAICS), we'll need to suppress the trap when FPCR.DNOD is set; | |
140 | then the code downstream of that will need to cope with denorms sans | |
141 | flush_input_to_zero. Most of it should work sanely, but there's | |
142 | nothing to compare with. */ | |
143 | void helper_ieee_input_s(CPUAlphaState *env, uint64_t val) | |
144 | { | |
145 | if (unlikely(2 * val - 1 < 0x1fffffffffffffull) | |
146 | && !env->fp_status.flush_inputs_to_zero) { | |
147 | arith_excp(env, GETPC(), EXC_M_INV | EXC_M_SWC, 0); | |
148 | } | |
149 | } | |
4a58aedf RH |
150 | |
151 | /* S floating (single) */ | |
152 | ||
153 | /* Taken from linux/arch/alpha/kernel/traps.c, s_mem_to_reg. */ | |
154 | static inline uint64_t float32_to_s_int(uint32_t fi) | |
155 | { | |
156 | uint32_t frac = fi & 0x7fffff; | |
157 | uint32_t sign = fi >> 31; | |
158 | uint32_t exp_msb = (fi >> 30) & 1; | |
159 | uint32_t exp_low = (fi >> 23) & 0x7f; | |
160 | uint32_t exp; | |
161 | ||
162 | exp = (exp_msb << 10) | exp_low; | |
163 | if (exp_msb) { | |
164 | if (exp_low == 0x7f) { | |
165 | exp = 0x7ff; | |
166 | } | |
167 | } else { | |
168 | if (exp_low != 0x00) { | |
169 | exp |= 0x380; | |
170 | } | |
171 | } | |
172 | ||
173 | return (((uint64_t)sign << 63) | |
174 | | ((uint64_t)exp << 52) | |
175 | | ((uint64_t)frac << 29)); | |
176 | } | |
177 | ||
178 | static inline uint64_t float32_to_s(float32 fa) | |
179 | { | |
180 | CPU_FloatU a; | |
181 | a.f = fa; | |
182 | return float32_to_s_int(a.l); | |
183 | } | |
184 | ||
185 | static inline uint32_t s_to_float32_int(uint64_t a) | |
186 | { | |
187 | return ((a >> 32) & 0xc0000000) | ((a >> 29) & 0x3fffffff); | |
188 | } | |
189 | ||
190 | static inline float32 s_to_float32(uint64_t a) | |
191 | { | |
192 | CPU_FloatU r; | |
193 | r.l = s_to_float32_int(a); | |
194 | return r.f; | |
195 | } | |
196 | ||
197 | uint32_t helper_s_to_memory(uint64_t a) | |
198 | { | |
199 | return s_to_float32_int(a); | |
200 | } | |
201 | ||
202 | uint64_t helper_memory_to_s(uint32_t a) | |
203 | { | |
204 | return float32_to_s_int(a); | |
205 | } | |
206 | ||
207 | uint64_t helper_adds(CPUAlphaState *env, uint64_t a, uint64_t b) | |
208 | { | |
209 | float32 fa, fb, fr; | |
210 | ||
211 | fa = s_to_float32(a); | |
212 | fb = s_to_float32(b); | |
213 | fr = float32_add(fa, fb, &FP_STATUS); | |
f3d3aad4 RH |
214 | env->error_code = soft_to_fpcr_exc(env); |
215 | ||
4a58aedf RH |
216 | return float32_to_s(fr); |
217 | } | |
218 | ||
219 | uint64_t helper_subs(CPUAlphaState *env, uint64_t a, uint64_t b) | |
220 | { | |
221 | float32 fa, fb, fr; | |
222 | ||
223 | fa = s_to_float32(a); | |
224 | fb = s_to_float32(b); | |
225 | fr = float32_sub(fa, fb, &FP_STATUS); | |
f3d3aad4 RH |
226 | env->error_code = soft_to_fpcr_exc(env); |
227 | ||
4a58aedf RH |
228 | return float32_to_s(fr); |
229 | } | |
230 | ||
231 | uint64_t helper_muls(CPUAlphaState *env, uint64_t a, uint64_t b) | |
232 | { | |
233 | float32 fa, fb, fr; | |
234 | ||
235 | fa = s_to_float32(a); | |
236 | fb = s_to_float32(b); | |
237 | fr = float32_mul(fa, fb, &FP_STATUS); | |
f3d3aad4 RH |
238 | env->error_code = soft_to_fpcr_exc(env); |
239 | ||
4a58aedf RH |
240 | return float32_to_s(fr); |
241 | } | |
242 | ||
243 | uint64_t helper_divs(CPUAlphaState *env, uint64_t a, uint64_t b) | |
244 | { | |
245 | float32 fa, fb, fr; | |
246 | ||
247 | fa = s_to_float32(a); | |
248 | fb = s_to_float32(b); | |
249 | fr = float32_div(fa, fb, &FP_STATUS); | |
f3d3aad4 RH |
250 | env->error_code = soft_to_fpcr_exc(env); |
251 | ||
4a58aedf RH |
252 | return float32_to_s(fr); |
253 | } | |
254 | ||
255 | uint64_t helper_sqrts(CPUAlphaState *env, uint64_t a) | |
256 | { | |
257 | float32 fa, fr; | |
258 | ||
259 | fa = s_to_float32(a); | |
260 | fr = float32_sqrt(fa, &FP_STATUS); | |
f3d3aad4 RH |
261 | env->error_code = soft_to_fpcr_exc(env); |
262 | ||
4a58aedf RH |
263 | return float32_to_s(fr); |
264 | } | |
265 | ||
266 | ||
267 | /* T floating (double) */ | |
268 | static inline float64 t_to_float64(uint64_t a) | |
269 | { | |
270 | /* Memory format is the same as float64 */ | |
271 | CPU_DoubleU r; | |
272 | r.ll = a; | |
273 | return r.d; | |
274 | } | |
275 | ||
276 | static inline uint64_t float64_to_t(float64 fa) | |
277 | { | |
278 | /* Memory format is the same as float64 */ | |
279 | CPU_DoubleU r; | |
280 | r.d = fa; | |
281 | return r.ll; | |
282 | } | |
283 | ||
284 | uint64_t helper_addt(CPUAlphaState *env, uint64_t a, uint64_t b) | |
285 | { | |
286 | float64 fa, fb, fr; | |
287 | ||
288 | fa = t_to_float64(a); | |
289 | fb = t_to_float64(b); | |
290 | fr = float64_add(fa, fb, &FP_STATUS); | |
f3d3aad4 RH |
291 | env->error_code = soft_to_fpcr_exc(env); |
292 | ||
4a58aedf RH |
293 | return float64_to_t(fr); |
294 | } | |
295 | ||
296 | uint64_t helper_subt(CPUAlphaState *env, uint64_t a, uint64_t b) | |
297 | { | |
298 | float64 fa, fb, fr; | |
299 | ||
300 | fa = t_to_float64(a); | |
301 | fb = t_to_float64(b); | |
302 | fr = float64_sub(fa, fb, &FP_STATUS); | |
f3d3aad4 RH |
303 | env->error_code = soft_to_fpcr_exc(env); |
304 | ||
4a58aedf RH |
305 | return float64_to_t(fr); |
306 | } | |
307 | ||
308 | uint64_t helper_mult(CPUAlphaState *env, uint64_t a, uint64_t b) | |
309 | { | |
310 | float64 fa, fb, fr; | |
311 | ||
312 | fa = t_to_float64(a); | |
313 | fb = t_to_float64(b); | |
314 | fr = float64_mul(fa, fb, &FP_STATUS); | |
f3d3aad4 RH |
315 | env->error_code = soft_to_fpcr_exc(env); |
316 | ||
4a58aedf RH |
317 | return float64_to_t(fr); |
318 | } | |
319 | ||
320 | uint64_t helper_divt(CPUAlphaState *env, uint64_t a, uint64_t b) | |
321 | { | |
322 | float64 fa, fb, fr; | |
323 | ||
324 | fa = t_to_float64(a); | |
325 | fb = t_to_float64(b); | |
326 | fr = float64_div(fa, fb, &FP_STATUS); | |
f3d3aad4 RH |
327 | env->error_code = soft_to_fpcr_exc(env); |
328 | ||
4a58aedf RH |
329 | return float64_to_t(fr); |
330 | } | |
331 | ||
332 | uint64_t helper_sqrtt(CPUAlphaState *env, uint64_t a) | |
333 | { | |
334 | float64 fa, fr; | |
335 | ||
336 | fa = t_to_float64(a); | |
337 | fr = float64_sqrt(fa, &FP_STATUS); | |
f3d3aad4 RH |
338 | env->error_code = soft_to_fpcr_exc(env); |
339 | ||
4a58aedf RH |
340 | return float64_to_t(fr); |
341 | } | |
342 | ||
343 | /* Comparisons */ | |
344 | uint64_t helper_cmptun(CPUAlphaState *env, uint64_t a, uint64_t b) | |
345 | { | |
346 | float64 fa, fb; | |
f3d3aad4 | 347 | uint64_t ret = 0; |
4a58aedf RH |
348 | |
349 | fa = t_to_float64(a); | |
350 | fb = t_to_float64(b); | |
351 | ||
352 | if (float64_unordered_quiet(fa, fb, &FP_STATUS)) { | |
f3d3aad4 | 353 | ret = 0x4000000000000000ULL; |
4a58aedf | 354 | } |
f3d3aad4 RH |
355 | env->error_code = soft_to_fpcr_exc(env); |
356 | ||
357 | return ret; | |
4a58aedf RH |
358 | } |
359 | ||
360 | uint64_t helper_cmpteq(CPUAlphaState *env, uint64_t a, uint64_t b) | |
361 | { | |
362 | float64 fa, fb; | |
f3d3aad4 | 363 | uint64_t ret = 0; |
4a58aedf RH |
364 | |
365 | fa = t_to_float64(a); | |
366 | fb = t_to_float64(b); | |
367 | ||
368 | if (float64_eq_quiet(fa, fb, &FP_STATUS)) { | |
f3d3aad4 | 369 | ret = 0x4000000000000000ULL; |
4a58aedf | 370 | } |
f3d3aad4 RH |
371 | env->error_code = soft_to_fpcr_exc(env); |
372 | ||
373 | return ret; | |
4a58aedf RH |
374 | } |
375 | ||
376 | uint64_t helper_cmptle(CPUAlphaState *env, uint64_t a, uint64_t b) | |
377 | { | |
378 | float64 fa, fb; | |
f3d3aad4 | 379 | uint64_t ret = 0; |
4a58aedf RH |
380 | |
381 | fa = t_to_float64(a); | |
382 | fb = t_to_float64(b); | |
383 | ||
384 | if (float64_le(fa, fb, &FP_STATUS)) { | |
f3d3aad4 | 385 | ret = 0x4000000000000000ULL; |
4a58aedf | 386 | } |
f3d3aad4 RH |
387 | env->error_code = soft_to_fpcr_exc(env); |
388 | ||
389 | return ret; | |
4a58aedf RH |
390 | } |
391 | ||
392 | uint64_t helper_cmptlt(CPUAlphaState *env, uint64_t a, uint64_t b) | |
393 | { | |
394 | float64 fa, fb; | |
f3d3aad4 | 395 | uint64_t ret = 0; |
4a58aedf RH |
396 | |
397 | fa = t_to_float64(a); | |
398 | fb = t_to_float64(b); | |
399 | ||
400 | if (float64_lt(fa, fb, &FP_STATUS)) { | |
f3d3aad4 | 401 | ret = 0x4000000000000000ULL; |
4a58aedf | 402 | } |
f3d3aad4 RH |
403 | env->error_code = soft_to_fpcr_exc(env); |
404 | ||
405 | return ret; | |
4a58aedf RH |
406 | } |
407 | ||
4a58aedf RH |
408 | /* Floating point format conversion */ |
409 | uint64_t helper_cvtts(CPUAlphaState *env, uint64_t a) | |
410 | { | |
411 | float64 fa; | |
412 | float32 fr; | |
413 | ||
414 | fa = t_to_float64(a); | |
415 | fr = float64_to_float32(fa, &FP_STATUS); | |
f3d3aad4 RH |
416 | env->error_code = soft_to_fpcr_exc(env); |
417 | ||
4a58aedf RH |
418 | return float32_to_s(fr); |
419 | } | |
420 | ||
421 | uint64_t helper_cvtst(CPUAlphaState *env, uint64_t a) | |
422 | { | |
423 | float32 fa; | |
424 | float64 fr; | |
425 | ||
426 | fa = s_to_float32(a); | |
427 | fr = float32_to_float64(fa, &FP_STATUS); | |
f3d3aad4 RH |
428 | env->error_code = soft_to_fpcr_exc(env); |
429 | ||
4a58aedf RH |
430 | return float64_to_t(fr); |
431 | } | |
432 | ||
433 | uint64_t helper_cvtqs(CPUAlphaState *env, uint64_t a) | |
434 | { | |
435 | float32 fr = int64_to_float32(a, &FP_STATUS); | |
f3d3aad4 RH |
436 | env->error_code = soft_to_fpcr_exc(env); |
437 | ||
4a58aedf RH |
438 | return float32_to_s(fr); |
439 | } | |
440 | ||
182f42fd | 441 | /* Implement float64 to uint64_t conversion without saturation -- we must |
4a58aedf | 442 | supply the truncated result. This behaviour is used by the compiler |
c24a8a0b | 443 | to get unsigned conversion for free with the same instruction. */ |
4a58aedf | 444 | |
c24a8a0b | 445 | static uint64_t do_cvttq(CPUAlphaState *env, uint64_t a, int roundmode) |
4a58aedf RH |
446 | { |
447 | uint64_t frac, ret = 0; | |
448 | uint32_t exp, sign, exc = 0; | |
449 | int shift; | |
450 | ||
451 | sign = (a >> 63); | |
452 | exp = (uint32_t)(a >> 52) & 0x7ff; | |
453 | frac = a & 0xfffffffffffffull; | |
454 | ||
455 | if (exp == 0) { | |
4ed069ab | 456 | if (unlikely(frac != 0) && !env->fp_status.flush_inputs_to_zero) { |
4a58aedf RH |
457 | goto do_underflow; |
458 | } | |
459 | } else if (exp == 0x7ff) { | |
7b4dde83 | 460 | exc = FPCR_INV; |
4a58aedf RH |
461 | } else { |
462 | /* Restore implicit bit. */ | |
463 | frac |= 0x10000000000000ull; | |
464 | ||
465 | shift = exp - 1023 - 52; | |
466 | if (shift >= 0) { | |
467 | /* In this case the number is so large that we must shift | |
468 | the fraction left. There is no rounding to do. */ | |
7f2e4002 | 469 | if (shift < 64) { |
4a58aedf | 470 | ret = frac << shift; |
7f2e4002 RH |
471 | } |
472 | /* Check for overflow. Note the special case of -0x1p63. */ | |
473 | if (shift >= 11 && a != 0xC3E0000000000000ull) { | |
474 | exc = FPCR_IOV | FPCR_INE; | |
4a58aedf RH |
475 | } |
476 | } else { | |
477 | uint64_t round; | |
478 | ||
479 | /* In this case the number is smaller than the fraction as | |
480 | represented by the 52 bit number. Here we must think | |
481 | about rounding the result. Handle this by shifting the | |
482 | fractional part of the number into the high bits of ROUND. | |
483 | This will let us efficiently handle round-to-nearest. */ | |
484 | shift = -shift; | |
485 | if (shift < 63) { | |
486 | ret = frac >> shift; | |
487 | round = frac << (64 - shift); | |
488 | } else { | |
489 | /* The exponent is so small we shift out everything. | |
490 | Leave a sticky bit for proper rounding below. */ | |
491 | do_underflow: | |
492 | round = 1; | |
493 | } | |
494 | ||
495 | if (round) { | |
c24a8a0b | 496 | exc = FPCR_INE; |
4a58aedf RH |
497 | switch (roundmode) { |
498 | case float_round_nearest_even: | |
499 | if (round == (1ull << 63)) { | |
500 | /* Fraction is exactly 0.5; round to even. */ | |
501 | ret += (ret & 1); | |
502 | } else if (round > (1ull << 63)) { | |
503 | ret += 1; | |
504 | } | |
505 | break; | |
506 | case float_round_to_zero: | |
507 | break; | |
508 | case float_round_up: | |
509 | ret += 1 - sign; | |
510 | break; | |
511 | case float_round_down: | |
512 | ret += sign; | |
513 | break; | |
514 | } | |
515 | } | |
516 | } | |
517 | if (sign) { | |
518 | ret = -ret; | |
519 | } | |
520 | } | |
f3d3aad4 | 521 | env->error_code = exc; |
4a58aedf RH |
522 | |
523 | return ret; | |
524 | } | |
525 | ||
526 | uint64_t helper_cvttq(CPUAlphaState *env, uint64_t a) | |
527 | { | |
c24a8a0b | 528 | return do_cvttq(env, a, FP_STATUS.float_rounding_mode); |
4a58aedf RH |
529 | } |
530 | ||
531 | uint64_t helper_cvttq_c(CPUAlphaState *env, uint64_t a) | |
532 | { | |
c24a8a0b | 533 | return do_cvttq(env, a, float_round_to_zero); |
4a58aedf RH |
534 | } |
535 | ||
536 | uint64_t helper_cvtqt(CPUAlphaState *env, uint64_t a) | |
537 | { | |
538 | float64 fr = int64_to_float64(a, &FP_STATUS); | |
f3d3aad4 | 539 | env->error_code = soft_to_fpcr_exc(env); |
4a58aedf RH |
540 | return float64_to_t(fr); |
541 | } | |
542 | ||
57a808b6 | 543 | uint64_t helper_cvtql(CPUAlphaState *env, uint64_t val) |
e8d8fef4 | 544 | { |
57a808b6 | 545 | uint32_t exc = 0; |
e8d8fef4 | 546 | if (val != (int32_t)val) { |
57a808b6 | 547 | exc = FPCR_IOV | FPCR_INE; |
e8d8fef4 | 548 | } |
57a808b6 RH |
549 | env->error_code = exc; |
550 | ||
551 | return ((val & 0xc0000000) << 32) | ((val & 0x3fffffff) << 29); | |
e8d8fef4 | 552 | } |