aboutsummaryrefslogtreecommitdiff
path: root/target-alpha
diff options
context:
space:
mode:
authorRichard Henderson <rth@twiddle.net>2009-12-09 15:56:29 -0800
committerAurelien Jarno <aurelien@aurel32.net>2009-12-13 20:32:36 +0100
commitba0e276db4b51bd2255a5d5ff8902c70d32ade40 (patch)
tree7366b9dcf6b064f59e4879bc517906c3af5fbdb2 /target-alpha
parent990b3e19013ebd36b3fb9af97aaa67f7bc490c15 (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.h49
-rw-r--r--target-alpha/helper.c77
-rw-r--r--target-alpha/op_helper.c41
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;