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 | |
parent | 990b3e19013ebd36b3fb9af97aaa67f7bc490c15 (diff) |
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')
-rw-r--r-- | target-alpha/cpu.h | 49 | ||||
-rw-r--r-- | target-alpha/helper.c | 77 | ||||
-rw-r--r-- | target-alpha/op_helper.c | 41 |
3 files changed, 128 insertions, 39 deletions
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h index ca9dfe2458..c0dff4bb87 100644 --- a/target-alpha/cpu.h +++ b/target-alpha/cpu.h @@ -139,6 +139,53 @@ enum { FP_ROUND_DYNAMIC = 0x3, }; +/* FPCR bits */ +#define FPCR_SUM (1ULL << 63) +#define FPCR_INED (1ULL << 62) +#define FPCR_UNFD (1ULL << 61) +#define FPCR_UNDZ (1ULL << 60) +#define FPCR_DYN_SHIFT 58 +#define FPCR_DYN_MASK (3ULL << FPCR_DYN_SHIFT) +#define FPCR_IOV (1ULL << 57) +#define FPCR_INE (1ULL << 56) +#define FPCR_UNF (1ULL << 55) +#define FPCR_OVF (1ULL << 54) +#define FPCR_DZE (1ULL << 53) +#define FPCR_INV (1ULL << 52) +#define FPCR_OVFD (1ULL << 51) +#define FPCR_DZED (1ULL << 50) +#define FPCR_INVD (1ULL << 49) +#define FPCR_DNZ (1ULL << 48) +#define FPCR_DNOD (1ULL << 47) +#define FPCR_STATUS_MASK (FPCR_IOV | FPCR_INE | FPCR_UNF \ + | FPCR_OVF | FPCR_DZE | FPCR_INV) + +/* The silly software trap enables implemented by the kernel emulation. + These are more or less architecturally required, since the real hardware + has read-as-zero bits in the FPCR when the features aren't implemented. + For the purposes of QEMU, we pretend the FPCR can hold everything. */ +#define SWCR_TRAP_ENABLE_INV (1ULL << 1) +#define SWCR_TRAP_ENABLE_DZE (1ULL << 2) +#define SWCR_TRAP_ENABLE_OVF (1ULL << 3) +#define SWCR_TRAP_ENABLE_UNF (1ULL << 4) +#define SWCR_TRAP_ENABLE_INE (1ULL << 5) +#define SWCR_TRAP_ENABLE_DNO (1ULL << 6) +#define SWCR_TRAP_ENABLE_MASK ((1ULL << 7) - (1ULL << 1)) + +#define SWCR_MAP_DMZ (1ULL << 12) +#define SWCR_MAP_UMZ (1ULL << 13) +#define SWCR_MAP_MASK (SWCR_MAP_DMZ | SWCR_MAP_UMZ) + +#define SWCR_STATUS_INV (1ULL << 17) +#define SWCR_STATUS_DZE (1ULL << 18) +#define SWCR_STATUS_OVF (1ULL << 19) +#define SWCR_STATUS_UNF (1ULL << 20) +#define SWCR_STATUS_INE (1ULL << 21) +#define SWCR_STATUS_DNO (1ULL << 22) +#define SWCR_STATUS_MASK ((1ULL << 23) - (1ULL << 17)) + +#define SWCR_MASK (SWCR_TRAP_ENABLE_MASK | SWCR_MAP_MASK | SWCR_STATUS_MASK) + /* Internal processor registers */ /* XXX: TOFIX: most of those registers are implementation dependant */ enum { @@ -436,6 +483,8 @@ int cpu_alpha_handle_mmu_fault (CPUState *env, uint64_t address, int rw, #define cpu_handle_mmu_fault cpu_alpha_handle_mmu_fault void do_interrupt (CPUState *env); +uint64_t cpu_alpha_load_fpcr (CPUState *env); +void cpu_alpha_store_fpcr (CPUState *env, uint64_t val); int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp); int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp); void pal_init (CPUState *env); diff --git a/target-alpha/helper.c b/target-alpha/helper.c index fcd5841e01..a658f9782a 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) diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c index 508272c85d..999a8ab46c 100644 --- a/target-alpha/op_helper.c +++ b/target-alpha/op_helper.c @@ -39,49 +39,12 @@ uint64_t helper_load_pcc (void) uint64_t helper_load_fpcr (void) { - uint64_t ret = 0; -#ifdef CONFIG_SOFTFLOAT - ret |= env->fp_status.float_exception_flags << 52; - if (env->fp_status.float_exception_flags) - ret |= 1ULL << 63; - env->ipr[IPR_EXC_SUM] &= ~0x3E: - env->ipr[IPR_EXC_SUM] |= env->fp_status.float_exception_flags << 1; -#endif - switch (env->fp_status.float_rounding_mode) { - case float_round_nearest_even: - ret |= 2ULL << 58; - break; - case float_round_down: - ret |= 1ULL << 58; - break; - case float_round_up: - ret |= 3ULL << 58; - break; - case float_round_to_zero: - break; - } - return ret; + return cpu_alpha_load_fpcr (env); } void helper_store_fpcr (uint64_t val) { -#ifdef CONFIG_SOFTFLOAT - set_float_exception_flags((val >> 52) & 0x3F, &FP_STATUS); -#endif - switch ((val >> 58) & 3) { - case 0: - set_float_rounding_mode(float_round_to_zero, &FP_STATUS); - break; - case 1: - set_float_rounding_mode(float_round_down, &FP_STATUS); - break; - case 2: - set_float_rounding_mode(float_round_nearest_even, &FP_STATUS); - break; - case 3: - set_float_rounding_mode(float_round_up, &FP_STATUS); - break; - } + cpu_alpha_store_fpcr (env, val); } static spinlock_t intr_cpu_lock = SPIN_LOCK_UNLOCKED; |