Revision f24518b5 target-alpha/op_helper.c
b/target-alpha/op_helper.c | ||
---|---|---|
370 | 370 |
|
371 | 371 |
/* Floating point helpers */ |
372 | 372 |
|
373 |
void helper_setroundmode (uint32_t val) |
|
374 |
{ |
|
375 |
set_float_rounding_mode(val, &FP_STATUS); |
|
376 |
} |
|
377 |
|
|
378 |
void helper_setflushzero (uint32_t val) |
|
379 |
{ |
|
380 |
set_flush_to_zero(val, &FP_STATUS); |
|
381 |
} |
|
382 |
|
|
383 |
void helper_fp_exc_clear (void) |
|
384 |
{ |
|
385 |
set_float_exception_flags(0, &FP_STATUS); |
|
386 |
} |
|
387 |
|
|
388 |
uint32_t helper_fp_exc_get (void) |
|
389 |
{ |
|
390 |
return get_float_exception_flags(&FP_STATUS); |
|
391 |
} |
|
392 |
|
|
393 |
/* Raise exceptions for ieee fp insns without software completion. |
|
394 |
In that case there are no exceptions that don't trap; the mask |
|
395 |
doesn't apply. */ |
|
396 |
void helper_fp_exc_raise(uint32_t exc, uint32_t regno) |
|
397 |
{ |
|
398 |
if (exc) { |
|
399 |
uint32_t hw_exc = 0; |
|
400 |
|
|
401 |
env->ipr[IPR_EXC_MASK] |= 1ull << regno; |
|
402 |
|
|
403 |
if (exc & float_flag_invalid) { |
|
404 |
hw_exc |= EXC_M_INV; |
|
405 |
} |
|
406 |
if (exc & float_flag_divbyzero) { |
|
407 |
hw_exc |= EXC_M_DZE; |
|
408 |
} |
|
409 |
if (exc & float_flag_overflow) { |
|
410 |
hw_exc |= EXC_M_FOV; |
|
411 |
} |
|
412 |
if (exc & float_flag_underflow) { |
|
413 |
hw_exc |= EXC_M_UNF; |
|
414 |
} |
|
415 |
if (exc & float_flag_inexact) { |
|
416 |
hw_exc |= EXC_M_INE; |
|
417 |
} |
|
418 |
helper_excp(EXCP_ARITH, hw_exc); |
|
419 |
} |
|
420 |
} |
|
421 |
|
|
422 |
/* Raise exceptions for ieee fp insns with software completion. */ |
|
423 |
void helper_fp_exc_raise_s(uint32_t exc, uint32_t regno) |
|
424 |
{ |
|
425 |
if (exc) { |
|
426 |
env->fpcr_exc_status |= exc; |
|
427 |
|
|
428 |
exc &= ~env->fpcr_exc_mask; |
|
429 |
if (exc) { |
|
430 |
helper_fp_exc_raise(exc, regno); |
|
431 |
} |
|
432 |
} |
|
433 |
} |
|
434 |
|
|
435 |
/* Input remapping without software completion. Handle denormal-map-to-zero |
|
436 |
and trap for all other non-finite numbers. */ |
|
437 |
uint64_t helper_ieee_input(uint64_t val) |
|
438 |
{ |
|
439 |
uint32_t exp = (uint32_t)(val >> 52) & 0x7ff; |
|
440 |
uint64_t frac = val & 0xfffffffffffffull; |
|
441 |
|
|
442 |
if (exp == 0) { |
|
443 |
if (frac != 0) { |
|
444 |
/* If DNZ is set flush denormals to zero on input. */ |
|
445 |
if (env->fpcr_dnz) { |
|
446 |
val &= 1ull << 63; |
|
447 |
} else { |
|
448 |
helper_excp(EXCP_ARITH, EXC_M_UNF); |
|
449 |
} |
|
450 |
} |
|
451 |
} else if (exp == 0x7ff) { |
|
452 |
/* Infinity or NaN. */ |
|
453 |
/* ??? I'm not sure these exception bit flags are correct. I do |
|
454 |
know that the Linux kernel, at least, doesn't rely on them and |
|
455 |
just emulates the insn to figure out what exception to use. */ |
|
456 |
helper_excp(EXCP_ARITH, frac ? EXC_M_INV : EXC_M_FOV); |
|
457 |
} |
|
458 |
return val; |
|
459 |
} |
|
460 |
|
|
461 |
/* Similar, but does not trap for infinities. Used for comparisons. */ |
|
462 |
uint64_t helper_ieee_input_cmp(uint64_t val) |
|
463 |
{ |
|
464 |
uint32_t exp = (uint32_t)(val >> 52) & 0x7ff; |
|
465 |
uint64_t frac = val & 0xfffffffffffffull; |
|
466 |
|
|
467 |
if (exp == 0) { |
|
468 |
if (frac != 0) { |
|
469 |
/* If DNZ is set flush denormals to zero on input. */ |
|
470 |
if (env->fpcr_dnz) { |
|
471 |
val &= 1ull << 63; |
|
472 |
} else { |
|
473 |
helper_excp(EXCP_ARITH, EXC_M_UNF); |
|
474 |
} |
|
475 |
} |
|
476 |
} else if (exp == 0x7ff && frac) { |
|
477 |
/* NaN. */ |
|
478 |
helper_excp(EXCP_ARITH, EXC_M_INV); |
|
479 |
} |
|
480 |
return val; |
|
481 |
} |
|
482 |
|
|
483 |
/* Input remapping with software completion enabled. All we have to do |
|
484 |
is handle denormal-map-to-zero; all other inputs get exceptions as |
|
485 |
needed from the actual operation. */ |
|
486 |
uint64_t helper_ieee_input_s(uint64_t val) |
|
487 |
{ |
|
488 |
if (env->fpcr_dnz) { |
|
489 |
uint32_t exp = (uint32_t)(val >> 52) & 0x7ff; |
|
490 |
if (exp == 0) { |
|
491 |
val &= 1ull << 63; |
|
492 |
} |
|
493 |
} |
|
494 |
return val; |
|
495 |
} |
|
496 |
|
|
373 | 497 |
/* F floating (VAX) */ |
374 | 498 |
static inline uint64_t float32_to_f(float32 fa) |
375 | 499 |
{ |
... | ... | |
447 | 571 |
return r; |
448 | 572 |
} |
449 | 573 |
|
574 |
/* ??? Emulating VAX arithmetic with IEEE arithmetic is wrong. We should |
|
575 |
either implement VAX arithmetic properly or just signal invalid opcode. */ |
|
576 |
|
|
450 | 577 |
uint64_t helper_addf (uint64_t a, uint64_t b) |
451 | 578 |
{ |
452 | 579 |
float32 fa, fb, fr; |
... | ... | |
931 | 1058 |
return float32_to_s(fr); |
932 | 1059 |
} |
933 | 1060 |
|
934 |
uint64_t helper_cvttq (uint64_t a) |
|
1061 |
/* Implement float64 to uint64 conversion without saturation -- we must |
|
1062 |
supply the truncated result. This behaviour is used by the compiler |
|
1063 |
to get unsigned conversion for free with the same instruction. |
|
1064 |
|
|
1065 |
The VI flag is set when overflow or inexact exceptions should be raised. */ |
|
1066 |
|
|
1067 |
static inline uint64_t helper_cvttq_internal(uint64_t a, int roundmode, int VI) |
|
935 | 1068 |
{ |
936 |
float64 fa = t_to_float64(a); |
|
937 |
return float64_to_int64_round_to_zero(fa, &FP_STATUS); |
|
1069 |
uint64_t frac, ret = 0; |
|
1070 |
uint32_t exp, sign, exc = 0; |
|
1071 |
int shift; |
|
1072 |
|
|
1073 |
sign = (a >> 63); |
|
1074 |
exp = (uint32_t)(a >> 52) & 0x7ff; |
|
1075 |
frac = a & 0xfffffffffffffull; |
|
1076 |
|
|
1077 |
if (exp == 0) { |
|
1078 |
if (unlikely(frac != 0)) { |
|
1079 |
goto do_underflow; |
|
1080 |
} |
|
1081 |
} else if (exp == 0x7ff) { |
|
1082 |
exc = (frac ? float_flag_invalid : VI ? float_flag_overflow : 0); |
|
1083 |
} else { |
|
1084 |
/* Restore implicit bit. */ |
|
1085 |
frac |= 0x10000000000000ull; |
|
1086 |
|
|
1087 |
shift = exp - 1023 - 52; |
|
1088 |
if (shift >= 0) { |
|
1089 |
/* In this case the number is so large that we must shift |
|
1090 |
the fraction left. There is no rounding to do. */ |
|
1091 |
if (shift < 63) { |
|
1092 |
ret = frac << shift; |
|
1093 |
if (VI && (ret >> shift) != frac) { |
|
1094 |
exc = float_flag_overflow; |
|
1095 |
} |
|
1096 |
} |
|
1097 |
} else { |
|
1098 |
uint64_t round; |
|
1099 |
|
|
1100 |
/* In this case the number is smaller than the fraction as |
|
1101 |
represented by the 52 bit number. Here we must think |
|
1102 |
about rounding the result. Handle this by shifting the |
|
1103 |
fractional part of the number into the high bits of ROUND. |
|
1104 |
This will let us efficiently handle round-to-nearest. */ |
|
1105 |
shift = -shift; |
|
1106 |
if (shift < 63) { |
|
1107 |
ret = frac >> shift; |
|
1108 |
round = frac << (64 - shift); |
|
1109 |
} else { |
|
1110 |
/* The exponent is so small we shift out everything. |
|
1111 |
Leave a sticky bit for proper rounding below. */ |
|
1112 |
do_underflow: |
|
1113 |
round = 1; |
|
1114 |
} |
|
1115 |
|
|
1116 |
if (round) { |
|
1117 |
exc = (VI ? float_flag_inexact : 0); |
|
1118 |
switch (roundmode) { |
|
1119 |
case float_round_nearest_even: |
|
1120 |
if (round == (1ull << 63)) { |
|
1121 |
/* Fraction is exactly 0.5; round to even. */ |
|
1122 |
ret += (ret & 1); |
|
1123 |
} else if (round > (1ull << 63)) { |
|
1124 |
ret += 1; |
|
1125 |
} |
|
1126 |
break; |
|
1127 |
case float_round_to_zero: |
|
1128 |
break; |
|
1129 |
case float_round_up: |
|
1130 |
ret += 1 - sign; |
|
1131 |
break; |
|
1132 |
case float_round_down: |
|
1133 |
ret += sign; |
|
1134 |
break; |
|
1135 |
} |
|
1136 |
} |
|
1137 |
} |
|
1138 |
if (sign) { |
|
1139 |
ret = -ret; |
|
1140 |
} |
|
1141 |
} |
|
1142 |
if (unlikely(exc)) { |
|
1143 |
float_raise(exc, &FP_STATUS); |
|
1144 |
} |
|
1145 |
|
|
1146 |
return ret; |
|
1147 |
} |
|
1148 |
|
|
1149 |
uint64_t helper_cvttq(uint64_t a) |
|
1150 |
{ |
|
1151 |
return helper_cvttq_internal(a, FP_STATUS.float_rounding_mode, 1); |
|
1152 |
} |
|
1153 |
|
|
1154 |
uint64_t helper_cvttq_c(uint64_t a) |
|
1155 |
{ |
|
1156 |
return helper_cvttq_internal(a, float_round_to_zero, 0); |
|
1157 |
} |
|
1158 |
|
|
1159 |
uint64_t helper_cvttq_svic(uint64_t a) |
|
1160 |
{ |
|
1161 |
return helper_cvttq_internal(a, float_round_to_zero, 1); |
|
938 | 1162 |
} |
939 | 1163 |
|
940 | 1164 |
uint64_t helper_cvtqt (uint64_t a) |
... | ... | |
979 | 1203 |
return (lo & 0x3FFFFFFF) | (hi & 0xc0000000); |
980 | 1204 |
} |
981 | 1205 |
|
982 |
static inline uint64_t __helper_cvtql(uint64_t a, int s, int v) |
|
983 |
{ |
|
984 |
uint64_t r; |
|
985 |
|
|
986 |
r = ((uint64_t)(a & 0xC0000000)) << 32; |
|
987 |
r |= ((uint64_t)(a & 0x7FFFFFFF)) << 29; |
|
988 |
|
|
989 |
if (v && (int64_t)((int32_t)r) != (int64_t)r) { |
|
990 |
helper_excp(EXCP_ARITH, EXC_M_IOV); |
|
991 |
} |
|
992 |
if (s) { |
|
993 |
/* TODO */ |
|
994 |
} |
|
995 |
return r; |
|
996 |
} |
|
997 |
|
|
998 | 1206 |
uint64_t helper_cvtql (uint64_t a) |
999 | 1207 |
{ |
1000 |
return __helper_cvtql(a, 0, 0);
|
|
1208 |
return ((a & 0xC0000000) << 32) | ((a & 0x7FFFFFFF) << 29);
|
|
1001 | 1209 |
} |
1002 | 1210 |
|
1003 |
uint64_t helper_cvtqlv (uint64_t a) |
|
1211 |
uint64_t helper_cvtql_v (uint64_t a)
|
|
1004 | 1212 |
{ |
1005 |
return __helper_cvtql(a, 0, 1); |
|
1213 |
if ((int32_t)a != (int64_t)a) |
|
1214 |
helper_excp(EXCP_ARITH, EXC_M_IOV); |
|
1215 |
return helper_cvtql(a); |
|
1006 | 1216 |
} |
1007 | 1217 |
|
1008 |
uint64_t helper_cvtqlsv (uint64_t a) |
|
1218 |
uint64_t helper_cvtql_sv (uint64_t a)
|
|
1009 | 1219 |
{ |
1010 |
return __helper_cvtql(a, 1, 1); |
|
1220 |
/* ??? I'm pretty sure there's nothing that /sv needs to do that /v |
|
1221 |
doesn't do. The only thing I can think is that /sv is a valid |
|
1222 |
instruction merely for completeness in the ISA. */ |
|
1223 |
return helper_cvtql_v(a); |
|
1011 | 1224 |
} |
1012 | 1225 |
|
1013 | 1226 |
/* PALcode support special instructions */ |
Also available in: Unified diff