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