diff options
author | Richard Henderson <rth@twiddle.net> | 2009-12-09 15:56:29 -0800 |
---|---|---|
committer | Aurelien Jarno <aurelien@aurel32.net> | 2009-12-13 20:32:36 +0100 |
commit | ba0e276db4b51bd2255a5d5ff8902c70d32ade40 (patch) | |
tree | 7366b9dcf6b064f59e4879bc517906c3af5fbdb2 /target-alpha/helper.c | |
parent | 990b3e19013ebd36b3fb9af97aaa67f7bc490c15 (diff) | |
download | qemu-ba0e276db4b51bd2255a5d5ff8902c70d32ade40.zip qemu-ba0e276db4b51bd2255a5d5ff8902c70d32ade40.tar.gz qemu-ba0e276db4b51bd2255a5d5ff8902c70d32ade40.tar.bz2 |
target-alpha: Fixes for alpha-linux syscalls.
1. Add correct definitions of error numbers.
2. Implement SYS_osf_sigprocmask
3. Implement SYS_osf_get/setsysinfo for IEEE_FP_CONTROL.
This last requires exposing the FPCR value to do_syscall.
Since this value is actually split up into the float_status,
expose routines from helper.c to access it.
Finally, also add a float_exception_mask field to float_status.
We don't actually use it to control delivery of exceptions to
the emulator yet, but simply hold the value that we placed there
when loading/storing the FPCR.
Signed-off-by: Richard Henderson <rth@twiddle.net>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
Diffstat (limited to 'target-alpha/helper.c')
-rw-r--r-- | target-alpha/helper.c | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/target-alpha/helper.c b/target-alpha/helper.c index fcd5841..a658f97 100644 --- a/target-alpha/helper.c +++ b/target-alpha/helper.c @@ -23,6 +23,83 @@ #include "cpu.h" #include "exec-all.h" +#include "softfloat.h" + +uint64_t cpu_alpha_load_fpcr (CPUState *env) +{ + uint64_t ret = 0; + int flags, mask; + + flags = env->fp_status.float_exception_flags; + ret |= (uint64_t) flags << 52; + if (flags) + ret |= FPCR_SUM; + env->ipr[IPR_EXC_SUM] &= ~0x3E; + env->ipr[IPR_EXC_SUM] |= flags << 1; + + mask = env->fp_status.float_exception_mask; + if (mask & float_flag_invalid) + ret |= FPCR_INVD; + if (mask & float_flag_divbyzero) + ret |= FPCR_DZED; + if (mask & float_flag_overflow) + ret |= FPCR_OVFD; + if (mask & float_flag_underflow) + ret |= FPCR_UNFD; + if (mask & float_flag_inexact) + ret |= FPCR_INED; + + switch (env->fp_status.float_rounding_mode) { + case float_round_nearest_even: + ret |= 2ULL << FPCR_DYN_SHIFT; + break; + case float_round_down: + ret |= 1ULL << FPCR_DYN_SHIFT; + break; + case float_round_up: + ret |= 3ULL << FPCR_DYN_SHIFT; + break; + case float_round_to_zero: + break; + } + return ret; +} + +void cpu_alpha_store_fpcr (CPUState *env, uint64_t val) +{ + int round_mode, mask; + + set_float_exception_flags((val >> 52) & 0x3F, &env->fp_status); + + mask = 0; + if (val & FPCR_INVD) + mask |= float_flag_invalid; + if (val & FPCR_DZED) + mask |= float_flag_divbyzero; + if (val & FPCR_OVFD) + mask |= float_flag_overflow; + if (val & FPCR_UNFD) + mask |= float_flag_underflow; + if (val & FPCR_INED) + mask |= float_flag_inexact; + env->fp_status.float_exception_mask = mask; + + switch ((val >> FPCR_DYN_SHIFT) & 3) { + case 0: + round_mode = float_round_to_zero; + break; + case 1: + round_mode = float_round_down; + break; + case 2: + round_mode = float_round_nearest_even; + break; + case 3: + round_mode = float_round_up; + break; + } + set_float_rounding_mode(round_mode, &env->fp_status); +} #if defined(CONFIG_USER_ONLY) |