target-alpha: Tidy FPCR representation

Store the fpcr as the hardware represents it.  Convert the softfpu
representation of exceptions into the fpcr representation.

Signed-off-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
Richard Henderson 2014-08-08 12:17:07 -10:00
parent ba9c5de5f2
commit f3d3aad4a9
5 changed files with 158 additions and 242 deletions

View File

@ -150,54 +150,54 @@ enum {
FP_ROUND_DYNAMIC = 0x3, FP_ROUND_DYNAMIC = 0x3,
}; };
/* FPCR bits */ /* FPCR bits -- right-shifted 32 so we can use a uint32_t. */
#define FPCR_SUM (1ULL << 63) #define FPCR_SUM (1U << (63 - 32))
#define FPCR_INED (1ULL << 62) #define FPCR_INED (1U << (62 - 32))
#define FPCR_UNFD (1ULL << 61) #define FPCR_UNFD (1U << (61 - 32))
#define FPCR_UNDZ (1ULL << 60) #define FPCR_UNDZ (1U << (60 - 32))
#define FPCR_DYN_SHIFT 58 #define FPCR_DYN_SHIFT (58 - 32)
#define FPCR_DYN_CHOPPED (0ULL << FPCR_DYN_SHIFT) #define FPCR_DYN_CHOPPED (0U << FPCR_DYN_SHIFT)
#define FPCR_DYN_MINUS (1ULL << FPCR_DYN_SHIFT) #define FPCR_DYN_MINUS (1U << FPCR_DYN_SHIFT)
#define FPCR_DYN_NORMAL (2ULL << FPCR_DYN_SHIFT) #define FPCR_DYN_NORMAL (2U << FPCR_DYN_SHIFT)
#define FPCR_DYN_PLUS (3ULL << FPCR_DYN_SHIFT) #define FPCR_DYN_PLUS (3U << FPCR_DYN_SHIFT)
#define FPCR_DYN_MASK (3ULL << FPCR_DYN_SHIFT) #define FPCR_DYN_MASK (3U << FPCR_DYN_SHIFT)
#define FPCR_IOV (1ULL << 57) #define FPCR_IOV (1U << (57 - 32))
#define FPCR_INE (1ULL << 56) #define FPCR_INE (1U << (56 - 32))
#define FPCR_UNF (1ULL << 55) #define FPCR_UNF (1U << (55 - 32))
#define FPCR_OVF (1ULL << 54) #define FPCR_OVF (1U << (54 - 32))
#define FPCR_DZE (1ULL << 53) #define FPCR_DZE (1U << (53 - 32))
#define FPCR_INV (1ULL << 52) #define FPCR_INV (1U << (52 - 32))
#define FPCR_OVFD (1ULL << 51) #define FPCR_OVFD (1U << (51 - 32))
#define FPCR_DZED (1ULL << 50) #define FPCR_DZED (1U << (50 - 32))
#define FPCR_INVD (1ULL << 49) #define FPCR_INVD (1U << (49 - 32))
#define FPCR_DNZ (1ULL << 48) #define FPCR_DNZ (1U << (48 - 32))
#define FPCR_DNOD (1ULL << 47) #define FPCR_DNOD (1U << (47 - 32))
#define FPCR_STATUS_MASK (FPCR_IOV | FPCR_INE | FPCR_UNF \ #define FPCR_STATUS_MASK (FPCR_IOV | FPCR_INE | FPCR_UNF \
| FPCR_OVF | FPCR_DZE | FPCR_INV) | FPCR_OVF | FPCR_DZE | FPCR_INV)
/* The silly software trap enables implemented by the kernel emulation. /* The silly software trap enables implemented by the kernel emulation.
These are more or less architecturally required, since the real hardware 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. 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. */ For the purposes of QEMU, we pretend the FPCR can hold everything. */
#define SWCR_TRAP_ENABLE_INV (1ULL << 1) #define SWCR_TRAP_ENABLE_INV (1U << 1)
#define SWCR_TRAP_ENABLE_DZE (1ULL << 2) #define SWCR_TRAP_ENABLE_DZE (1U << 2)
#define SWCR_TRAP_ENABLE_OVF (1ULL << 3) #define SWCR_TRAP_ENABLE_OVF (1U << 3)
#define SWCR_TRAP_ENABLE_UNF (1ULL << 4) #define SWCR_TRAP_ENABLE_UNF (1U << 4)
#define SWCR_TRAP_ENABLE_INE (1ULL << 5) #define SWCR_TRAP_ENABLE_INE (1U << 5)
#define SWCR_TRAP_ENABLE_DNO (1ULL << 6) #define SWCR_TRAP_ENABLE_DNO (1U << 6)
#define SWCR_TRAP_ENABLE_MASK ((1ULL << 7) - (1ULL << 1)) #define SWCR_TRAP_ENABLE_MASK ((1U << 7) - (1U << 1))
#define SWCR_MAP_DMZ (1ULL << 12) #define SWCR_MAP_DMZ (1U << 12)
#define SWCR_MAP_UMZ (1ULL << 13) #define SWCR_MAP_UMZ (1U << 13)
#define SWCR_MAP_MASK (SWCR_MAP_DMZ | SWCR_MAP_UMZ) #define SWCR_MAP_MASK (SWCR_MAP_DMZ | SWCR_MAP_UMZ)
#define SWCR_STATUS_INV (1ULL << 17) #define SWCR_STATUS_INV (1U << 17)
#define SWCR_STATUS_DZE (1ULL << 18) #define SWCR_STATUS_DZE (1U << 18)
#define SWCR_STATUS_OVF (1ULL << 19) #define SWCR_STATUS_OVF (1U << 19)
#define SWCR_STATUS_UNF (1ULL << 20) #define SWCR_STATUS_UNF (1U << 20)
#define SWCR_STATUS_INE (1ULL << 21) #define SWCR_STATUS_INE (1U << 21)
#define SWCR_STATUS_DNO (1ULL << 22) #define SWCR_STATUS_DNO (1U << 22)
#define SWCR_STATUS_MASK ((1ULL << 23) - (1ULL << 17)) #define SWCR_STATUS_MASK ((1U << 23) - (1U << 17))
#define SWCR_MASK (SWCR_TRAP_ENABLE_MASK | SWCR_MAP_MASK | SWCR_STATUS_MASK) #define SWCR_MASK (SWCR_TRAP_ENABLE_MASK | SWCR_MAP_MASK | SWCR_STATUS_MASK)
@ -238,14 +238,13 @@ struct CPUAlphaState {
uint64_t lock_addr; uint64_t lock_addr;
uint64_t lock_st_addr; uint64_t lock_st_addr;
uint64_t lock_value; uint64_t lock_value;
/* The FPCR, and disassembled portions thereof. */
uint32_t fpcr;
uint32_t fpcr_exc_enable;
float_status fp_status; float_status fp_status;
/* The following fields make up the FPCR, but in FP_STATUS format. */
uint8_t fpcr_exc_status;
uint8_t fpcr_exc_mask;
uint8_t fpcr_dyn_round; uint8_t fpcr_dyn_round;
uint8_t fpcr_flush_to_zero; uint8_t fpcr_flush_to_zero;
uint8_t fpcr_dnod;
uint8_t fpcr_undz;
/* The Internal Processor Registers. Some of these we assume always /* The Internal Processor Registers. Some of these we assume always
exist for use in user-mode. */ exist for use in user-mode. */

View File

@ -34,37 +34,38 @@ void helper_setflushzero(CPUAlphaState *env, uint32_t val)
set_flush_to_zero(val, &FP_STATUS); set_flush_to_zero(val, &FP_STATUS);
} }
void helper_fp_exc_clear(CPUAlphaState *env) #define CONVERT_BIT(X, SRC, DST) \
(SRC > DST ? (X) / (SRC / DST) & (DST) : ((X) & SRC) * (DST / SRC))
static uint32_t soft_to_fpcr_exc(CPUAlphaState *env)
{ {
set_float_exception_flags(0, &FP_STATUS); uint8_t exc = get_float_exception_flags(&FP_STATUS);
uint32_t ret = 0;
if (unlikely(exc)) {
set_float_exception_flags(0, &FP_STATUS);
ret |= CONVERT_BIT(exc, float_flag_invalid, FPCR_INV);
ret |= CONVERT_BIT(exc, float_flag_divbyzero, FPCR_DZE);
ret |= CONVERT_BIT(exc, float_flag_overflow, FPCR_OVF);
ret |= CONVERT_BIT(exc, float_flag_underflow, FPCR_UNF);
ret |= CONVERT_BIT(exc, float_flag_inexact, FPCR_INE);
}
return ret;
} }
uint32_t helper_fp_exc_get(CPUAlphaState *env) static void fp_exc_raise1(CPUAlphaState *env, uintptr_t retaddr,
{ uint32_t exc, uint32_t regno)
return get_float_exception_flags(&FP_STATUS);
}
static inline void inline_fp_exc_raise(CPUAlphaState *env, uintptr_t retaddr,
uint32_t exc, uint32_t regno)
{ {
if (exc) { if (exc) {
uint32_t hw_exc = 0; uint32_t hw_exc = 0;
if (exc & float_flag_invalid) { hw_exc |= CONVERT_BIT(exc, FPCR_INV, EXC_M_INV);
hw_exc |= EXC_M_INV; hw_exc |= CONVERT_BIT(exc, FPCR_DZE, EXC_M_DZE);
} hw_exc |= CONVERT_BIT(exc, FPCR_OVF, EXC_M_FOV);
if (exc & float_flag_divbyzero) { hw_exc |= CONVERT_BIT(exc, FPCR_UNF, EXC_M_UNF);
hw_exc |= EXC_M_DZE; hw_exc |= CONVERT_BIT(exc, FPCR_INE, EXC_M_INE);
} hw_exc |= CONVERT_BIT(exc, FPCR_IOV, EXC_M_IOV);
if (exc & float_flag_overflow) {
hw_exc |= EXC_M_FOV;
}
if (exc & float_flag_underflow) {
hw_exc |= EXC_M_UNF;
}
if (exc & float_flag_inexact) {
hw_exc |= EXC_M_INE;
}
arith_excp(env, retaddr, hw_exc, 1ull << regno); arith_excp(env, retaddr, hw_exc, 1ull << regno);
} }
@ -73,18 +74,20 @@ static inline void inline_fp_exc_raise(CPUAlphaState *env, uintptr_t retaddr,
/* Raise exceptions for ieee fp insns without software completion. /* Raise exceptions for ieee fp insns without software completion.
In that case there are no exceptions that don't trap; the mask In that case there are no exceptions that don't trap; the mask
doesn't apply. */ doesn't apply. */
void helper_fp_exc_raise(CPUAlphaState *env, uint32_t exc, uint32_t regno) void helper_fp_exc_raise(CPUAlphaState *env, uint32_t ignore, uint32_t regno)
{ {
inline_fp_exc_raise(env, GETPC(), exc, regno); uint32_t exc = env->error_code & ~ignore;
fp_exc_raise1(env, GETPC(), exc, regno);
} }
/* Raise exceptions for ieee fp insns with software completion. */ /* Raise exceptions for ieee fp insns with software completion. */
void helper_fp_exc_raise_s(CPUAlphaState *env, uint32_t exc, uint32_t regno) void helper_fp_exc_raise_s(CPUAlphaState *env, uint32_t ignore, uint32_t regno)
{ {
uint32_t exc = env->error_code & ~ignore;
if (exc) { if (exc) {
env->fpcr_exc_status |= exc; env->fpcr |= exc;
exc &= ~env->fpcr_exc_mask; exc &= env->fpcr_exc_enable;
inline_fp_exc_raise(env, GETPC(), exc, regno); fp_exc_raise1(env, GETPC(), exc, regno);
} }
} }
@ -190,6 +193,8 @@ uint64_t helper_adds(CPUAlphaState *env, uint64_t a, uint64_t b)
fa = s_to_float32(a); fa = s_to_float32(a);
fb = s_to_float32(b); fb = s_to_float32(b);
fr = float32_add(fa, fb, &FP_STATUS); fr = float32_add(fa, fb, &FP_STATUS);
env->error_code = soft_to_fpcr_exc(env);
return float32_to_s(fr); return float32_to_s(fr);
} }
@ -200,6 +205,8 @@ uint64_t helper_subs(CPUAlphaState *env, uint64_t a, uint64_t b)
fa = s_to_float32(a); fa = s_to_float32(a);
fb = s_to_float32(b); fb = s_to_float32(b);
fr = float32_sub(fa, fb, &FP_STATUS); fr = float32_sub(fa, fb, &FP_STATUS);
env->error_code = soft_to_fpcr_exc(env);
return float32_to_s(fr); return float32_to_s(fr);
} }
@ -210,6 +217,8 @@ uint64_t helper_muls(CPUAlphaState *env, uint64_t a, uint64_t b)
fa = s_to_float32(a); fa = s_to_float32(a);
fb = s_to_float32(b); fb = s_to_float32(b);
fr = float32_mul(fa, fb, &FP_STATUS); fr = float32_mul(fa, fb, &FP_STATUS);
env->error_code = soft_to_fpcr_exc(env);
return float32_to_s(fr); return float32_to_s(fr);
} }
@ -220,6 +229,8 @@ uint64_t helper_divs(CPUAlphaState *env, uint64_t a, uint64_t b)
fa = s_to_float32(a); fa = s_to_float32(a);
fb = s_to_float32(b); fb = s_to_float32(b);
fr = float32_div(fa, fb, &FP_STATUS); fr = float32_div(fa, fb, &FP_STATUS);
env->error_code = soft_to_fpcr_exc(env);
return float32_to_s(fr); return float32_to_s(fr);
} }
@ -229,6 +240,8 @@ uint64_t helper_sqrts(CPUAlphaState *env, uint64_t a)
fa = s_to_float32(a); fa = s_to_float32(a);
fr = float32_sqrt(fa, &FP_STATUS); fr = float32_sqrt(fa, &FP_STATUS);
env->error_code = soft_to_fpcr_exc(env);
return float32_to_s(fr); return float32_to_s(fr);
} }
@ -257,6 +270,8 @@ uint64_t helper_addt(CPUAlphaState *env, uint64_t a, uint64_t b)
fa = t_to_float64(a); fa = t_to_float64(a);
fb = t_to_float64(b); fb = t_to_float64(b);
fr = float64_add(fa, fb, &FP_STATUS); fr = float64_add(fa, fb, &FP_STATUS);
env->error_code = soft_to_fpcr_exc(env);
return float64_to_t(fr); return float64_to_t(fr);
} }
@ -267,6 +282,8 @@ uint64_t helper_subt(CPUAlphaState *env, uint64_t a, uint64_t b)
fa = t_to_float64(a); fa = t_to_float64(a);
fb = t_to_float64(b); fb = t_to_float64(b);
fr = float64_sub(fa, fb, &FP_STATUS); fr = float64_sub(fa, fb, &FP_STATUS);
env->error_code = soft_to_fpcr_exc(env);
return float64_to_t(fr); return float64_to_t(fr);
} }
@ -277,6 +294,8 @@ uint64_t helper_mult(CPUAlphaState *env, uint64_t a, uint64_t b)
fa = t_to_float64(a); fa = t_to_float64(a);
fb = t_to_float64(b); fb = t_to_float64(b);
fr = float64_mul(fa, fb, &FP_STATUS); fr = float64_mul(fa, fb, &FP_STATUS);
env->error_code = soft_to_fpcr_exc(env);
return float64_to_t(fr); return float64_to_t(fr);
} }
@ -287,6 +306,8 @@ uint64_t helper_divt(CPUAlphaState *env, uint64_t a, uint64_t b)
fa = t_to_float64(a); fa = t_to_float64(a);
fb = t_to_float64(b); fb = t_to_float64(b);
fr = float64_div(fa, fb, &FP_STATUS); fr = float64_div(fa, fb, &FP_STATUS);
env->error_code = soft_to_fpcr_exc(env);
return float64_to_t(fr); return float64_to_t(fr);
} }
@ -296,6 +317,8 @@ uint64_t helper_sqrtt(CPUAlphaState *env, uint64_t a)
fa = t_to_float64(a); fa = t_to_float64(a);
fr = float64_sqrt(fa, &FP_STATUS); fr = float64_sqrt(fa, &FP_STATUS);
env->error_code = soft_to_fpcr_exc(env);
return float64_to_t(fr); return float64_to_t(fr);
} }
@ -303,57 +326,65 @@ uint64_t helper_sqrtt(CPUAlphaState *env, uint64_t a)
uint64_t helper_cmptun(CPUAlphaState *env, uint64_t a, uint64_t b) uint64_t helper_cmptun(CPUAlphaState *env, uint64_t a, uint64_t b)
{ {
float64 fa, fb; float64 fa, fb;
uint64_t ret = 0;
fa = t_to_float64(a); fa = t_to_float64(a);
fb = t_to_float64(b); fb = t_to_float64(b);
if (float64_unordered_quiet(fa, fb, &FP_STATUS)) { if (float64_unordered_quiet(fa, fb, &FP_STATUS)) {
return 0x4000000000000000ULL; ret = 0x4000000000000000ULL;
} else {
return 0;
} }
env->error_code = soft_to_fpcr_exc(env);
return ret;
} }
uint64_t helper_cmpteq(CPUAlphaState *env, uint64_t a, uint64_t b) uint64_t helper_cmpteq(CPUAlphaState *env, uint64_t a, uint64_t b)
{ {
float64 fa, fb; float64 fa, fb;
uint64_t ret = 0;
fa = t_to_float64(a); fa = t_to_float64(a);
fb = t_to_float64(b); fb = t_to_float64(b);
if (float64_eq_quiet(fa, fb, &FP_STATUS)) { if (float64_eq_quiet(fa, fb, &FP_STATUS)) {
return 0x4000000000000000ULL; ret = 0x4000000000000000ULL;
} else {
return 0;
} }
env->error_code = soft_to_fpcr_exc(env);
return ret;
} }
uint64_t helper_cmptle(CPUAlphaState *env, uint64_t a, uint64_t b) uint64_t helper_cmptle(CPUAlphaState *env, uint64_t a, uint64_t b)
{ {
float64 fa, fb; float64 fa, fb;
uint64_t ret = 0;
fa = t_to_float64(a); fa = t_to_float64(a);
fb = t_to_float64(b); fb = t_to_float64(b);
if (float64_le(fa, fb, &FP_STATUS)) { if (float64_le(fa, fb, &FP_STATUS)) {
return 0x4000000000000000ULL; ret = 0x4000000000000000ULL;
} else {
return 0;
} }
env->error_code = soft_to_fpcr_exc(env);
return ret;
} }
uint64_t helper_cmptlt(CPUAlphaState *env, uint64_t a, uint64_t b) uint64_t helper_cmptlt(CPUAlphaState *env, uint64_t a, uint64_t b)
{ {
float64 fa, fb; float64 fa, fb;
uint64_t ret = 0;
fa = t_to_float64(a); fa = t_to_float64(a);
fb = t_to_float64(b); fb = t_to_float64(b);
if (float64_lt(fa, fb, &FP_STATUS)) { if (float64_lt(fa, fb, &FP_STATUS)) {
return 0x4000000000000000ULL; ret = 0x4000000000000000ULL;
} else {
return 0;
} }
env->error_code = soft_to_fpcr_exc(env);
return ret;
} }
/* Floating point format conversion */ /* Floating point format conversion */
@ -364,6 +395,8 @@ uint64_t helper_cvtts(CPUAlphaState *env, uint64_t a)
fa = t_to_float64(a); fa = t_to_float64(a);
fr = float64_to_float32(fa, &FP_STATUS); fr = float64_to_float32(fa, &FP_STATUS);
env->error_code = soft_to_fpcr_exc(env);
return float32_to_s(fr); return float32_to_s(fr);
} }
@ -374,12 +407,16 @@ uint64_t helper_cvtst(CPUAlphaState *env, uint64_t a)
fa = s_to_float32(a); fa = s_to_float32(a);
fr = float32_to_float64(fa, &FP_STATUS); fr = float32_to_float64(fa, &FP_STATUS);
env->error_code = soft_to_fpcr_exc(env);
return float64_to_t(fr); return float64_to_t(fr);
} }
uint64_t helper_cvtqs(CPUAlphaState *env, uint64_t a) uint64_t helper_cvtqs(CPUAlphaState *env, uint64_t a)
{ {
float32 fr = int64_to_float32(a, &FP_STATUS); float32 fr = int64_to_float32(a, &FP_STATUS);
env->error_code = soft_to_fpcr_exc(env);
return float32_to_s(fr); return float32_to_s(fr);
} }
@ -405,7 +442,7 @@ static inline uint64_t inline_cvttq(CPUAlphaState *env, uint64_t a,
goto do_underflow; goto do_underflow;
} }
} else if (exp == 0x7ff) { } else if (exp == 0x7ff) {
exc = (frac ? float_flag_invalid : VI ? float_flag_overflow : 0); exc = (frac ? FPCR_INV : VI ? FPCR_OVF : 0);
} else { } else {
/* Restore implicit bit. */ /* Restore implicit bit. */
frac |= 0x10000000000000ull; frac |= 0x10000000000000ull;
@ -417,7 +454,7 @@ static inline uint64_t inline_cvttq(CPUAlphaState *env, uint64_t a,
if (shift < 63) { if (shift < 63) {
ret = frac << shift; ret = frac << shift;
if (VI && (ret >> shift) != frac) { if (VI && (ret >> shift) != frac) {
exc = float_flag_overflow; exc = FPCR_OVF;
} }
} }
} else { } else {
@ -440,7 +477,7 @@ static inline uint64_t inline_cvttq(CPUAlphaState *env, uint64_t a,
} }
if (round) { if (round) {
exc = (VI ? float_flag_inexact : 0); exc = (VI ? FPCR_INE : 0);
switch (roundmode) { switch (roundmode) {
case float_round_nearest_even: case float_round_nearest_even:
if (round == (1ull << 63)) { if (round == (1ull << 63)) {
@ -465,9 +502,7 @@ static inline uint64_t inline_cvttq(CPUAlphaState *env, uint64_t a,
ret = -ret; ret = -ret;
} }
} }
if (unlikely(exc)) { env->error_code = exc;
float_raise(exc, &FP_STATUS);
}
return ret; return ret;
} }
@ -490,6 +525,7 @@ uint64_t helper_cvttq_svic(CPUAlphaState *env, uint64_t a)
uint64_t helper_cvtqt(CPUAlphaState *env, uint64_t a) uint64_t helper_cvtqt(CPUAlphaState *env, uint64_t a)
{ {
float64 fr = int64_to_float64(a, &FP_STATUS); float64 fr = int64_to_float64(a, &FP_STATUS);
env->error_code = soft_to_fpcr_exc(env);
return float64_to_t(fr); return float64_to_t(fr);
} }

View File

@ -25,136 +25,48 @@
#include "fpu/softfloat.h" #include "fpu/softfloat.h"
#include "exec/helper-proto.h" #include "exec/helper-proto.h"
#define CONVERT_BIT(X, SRC, DST) \
(SRC > DST ? (X) / (SRC / DST) & (DST) : ((X) & SRC) * (DST / SRC))
uint64_t cpu_alpha_load_fpcr (CPUAlphaState *env) uint64_t cpu_alpha_load_fpcr (CPUAlphaState *env)
{ {
uint64_t r = 0; return (uint64_t)env->fpcr << 32;
uint8_t t;
t = env->fpcr_exc_status;
if (t) {
r = FPCR_SUM;
if (t & float_flag_invalid) {
r |= FPCR_INV;
}
if (t & float_flag_divbyzero) {
r |= FPCR_DZE;
}
if (t & float_flag_overflow) {
r |= FPCR_OVF;
}
if (t & float_flag_underflow) {
r |= FPCR_UNF;
}
if (t & float_flag_inexact) {
r |= FPCR_INE;
}
}
t = env->fpcr_exc_mask;
if (t & float_flag_invalid) {
r |= FPCR_INVD;
}
if (t & float_flag_divbyzero) {
r |= FPCR_DZED;
}
if (t & float_flag_overflow) {
r |= FPCR_OVFD;
}
if (t & float_flag_underflow) {
r |= FPCR_UNFD;
}
if (t & float_flag_inexact) {
r |= FPCR_INED;
}
switch (env->fpcr_dyn_round) {
case float_round_nearest_even:
r |= FPCR_DYN_NORMAL;
break;
case float_round_down:
r |= FPCR_DYN_MINUS;
break;
case float_round_up:
r |= FPCR_DYN_PLUS;
break;
case float_round_to_zero:
r |= FPCR_DYN_CHOPPED;
break;
}
if (env->fp_status.flush_inputs_to_zero) {
r |= FPCR_DNZ;
}
if (env->fpcr_dnod) {
r |= FPCR_DNOD;
}
if (env->fpcr_undz) {
r |= FPCR_UNDZ;
}
return r;
} }
void cpu_alpha_store_fpcr (CPUAlphaState *env, uint64_t val) void cpu_alpha_store_fpcr (CPUAlphaState *env, uint64_t val)
{ {
uint8_t t; uint32_t fpcr = val >> 32;
uint32_t t = 0;
t = 0; t |= CONVERT_BIT(fpcr, FPCR_INED, FPCR_INE);
if (val & FPCR_INV) { t |= CONVERT_BIT(fpcr, FPCR_UNFD, FPCR_UNF);
t |= float_flag_invalid; t |= CONVERT_BIT(fpcr, FPCR_OVFD, FPCR_OVF);
} t |= CONVERT_BIT(fpcr, FPCR_DZED, FPCR_DZE);
if (val & FPCR_DZE) { t |= CONVERT_BIT(fpcr, FPCR_INVD, FPCR_INV);
t |= float_flag_divbyzero;
}
if (val & FPCR_OVF) {
t |= float_flag_overflow;
}
if (val & FPCR_UNF) {
t |= float_flag_underflow;
}
if (val & FPCR_INE) {
t |= float_flag_inexact;
}
env->fpcr_exc_status = t;
t = 0; env->fpcr = fpcr;
if (val & FPCR_INVD) { env->fpcr_exc_enable = ~t & FPCR_STATUS_MASK;
t |= float_flag_invalid;
}
if (val & FPCR_DZED) {
t |= float_flag_divbyzero;
}
if (val & FPCR_OVFD) {
t |= float_flag_overflow;
}
if (val & FPCR_UNFD) {
t |= float_flag_underflow;
}
if (val & FPCR_INED) {
t |= float_flag_inexact;
}
env->fpcr_exc_mask = t;
switch (val & FPCR_DYN_MASK) { switch (fpcr & FPCR_DYN_MASK) {
case FPCR_DYN_NORMAL:
default:
t = float_round_nearest_even;
break;
case FPCR_DYN_CHOPPED: case FPCR_DYN_CHOPPED:
t = float_round_to_zero; t = float_round_to_zero;
break; break;
case FPCR_DYN_MINUS: case FPCR_DYN_MINUS:
t = float_round_down; t = float_round_down;
break; break;
case FPCR_DYN_NORMAL:
t = float_round_nearest_even;
break;
case FPCR_DYN_PLUS: case FPCR_DYN_PLUS:
t = float_round_up; t = float_round_up;
break; break;
} }
env->fpcr_dyn_round = t; env->fpcr_dyn_round = t;
env->fpcr_dnod = (val & FPCR_DNOD) != 0; env->fpcr_flush_to_zero = (fpcr & FPCR_UNFD) && (fpcr & FPCR_UNDZ);
env->fpcr_undz = (val & FPCR_UNDZ) != 0; env->fp_status.flush_inputs_to_zero = (fpcr & FPCR_DNZ) != 0;
env->fpcr_flush_to_zero = env->fpcr_dnod & env->fpcr_undz;
env->fp_status.flush_inputs_to_zero = (val & FPCR_DNZ) != 0;
} }
uint64_t helper_load_fpcr(CPUAlphaState *env) uint64_t helper_load_fpcr(CPUAlphaState *env)

View File

@ -87,8 +87,6 @@ DEF_HELPER_FLAGS_2(cvttq_svic, TCG_CALL_NO_RWG, i64, env, i64)
DEF_HELPER_FLAGS_2(setroundmode, TCG_CALL_NO_RWG, void, env, i32) DEF_HELPER_FLAGS_2(setroundmode, TCG_CALL_NO_RWG, void, env, i32)
DEF_HELPER_FLAGS_2(setflushzero, TCG_CALL_NO_RWG, void, env, i32) DEF_HELPER_FLAGS_2(setflushzero, TCG_CALL_NO_RWG, void, env, i32)
DEF_HELPER_FLAGS_1(fp_exc_clear, TCG_CALL_NO_RWG, void, env)
DEF_HELPER_FLAGS_1(fp_exc_get, TCG_CALL_NO_RWG_SE, i32, env)
DEF_HELPER_FLAGS_3(fp_exc_raise, TCG_CALL_NO_WG, void, env, i32, i32) DEF_HELPER_FLAGS_3(fp_exc_raise, TCG_CALL_NO_WG, void, env, i32, i32)
DEF_HELPER_FLAGS_3(fp_exc_raise_s, TCG_CALL_NO_WG, void, env, i32, i32) DEF_HELPER_FLAGS_3(fp_exc_raise_s, TCG_CALL_NO_WG, void, env, i32, i32)

View File

@ -663,18 +663,6 @@ static TCGv gen_ieee_input(DisasContext *ctx, int reg, int fn11, int is_cmp)
return val; return val;
} }
static void gen_fp_exc_clear(void)
{
#if defined(CONFIG_SOFTFLOAT_INLINE)
TCGv_i32 zero = tcg_const_i32(0);
tcg_gen_st8_i32(zero, cpu_env,
offsetof(CPUAlphaState, fp_status.float_exception_flags));
tcg_temp_free_i32(zero);
#else
gen_helper_fp_exc_clear(cpu_env);
#endif
}
static void gen_fp_exc_raise_ignore(int rc, int fn11, int ignore) static void gen_fp_exc_raise_ignore(int rc, int fn11, int ignore)
{ {
/* ??? We ought to be able to do something with imprecise exceptions. /* ??? We ought to be able to do something with imprecise exceptions.
@ -682,20 +670,9 @@ static void gen_fp_exc_raise_ignore(int rc, int fn11, int ignore)
TB and do not generate the code to signal the exception; end the TB TB and do not generate the code to signal the exception; end the TB
when an exception is forced to arrive, either by consumption of a when an exception is forced to arrive, either by consumption of a
register value or TRAPB or EXCB. */ register value or TRAPB or EXCB. */
TCGv_i32 exc = tcg_temp_new_i32(); TCGv_i32 ign = tcg_const_i32(ignore);
TCGv_i32 reg; TCGv_i32 reg;
#if defined(CONFIG_SOFTFLOAT_INLINE)
tcg_gen_ld8u_i32(exc, cpu_env,
offsetof(CPUAlphaState, fp_status.float_exception_flags));
#else
gen_helper_fp_exc_get(exc, cpu_env);
#endif
if (ignore) {
tcg_gen_andi_i32(exc, exc, ~ignore);
}
/* ??? Pass in the regno of the destination so that the helper can /* ??? Pass in the regno of the destination so that the helper can
set EXC_MASK, which contains a bitmask of destination registers set EXC_MASK, which contains a bitmask of destination registers
that have caused arithmetic traps. A simple userspace emulation that have caused arithmetic traps. A simple userspace emulation
@ -704,18 +681,18 @@ static void gen_fp_exc_raise_ignore(int rc, int fn11, int ignore)
reg = tcg_const_i32(rc + 32); reg = tcg_const_i32(rc + 32);
if (fn11 & QUAL_S) { if (fn11 & QUAL_S) {
gen_helper_fp_exc_raise_s(cpu_env, exc, reg); gen_helper_fp_exc_raise_s(cpu_env, ign, reg);
} else { } else {
gen_helper_fp_exc_raise(cpu_env, exc, reg); gen_helper_fp_exc_raise(cpu_env, ign, reg);
} }
tcg_temp_free_i32(reg); tcg_temp_free_i32(reg);
tcg_temp_free_i32(exc); tcg_temp_free_i32(ign);
} }
static inline void gen_fp_exc_raise(int rc, int fn11) static inline void gen_fp_exc_raise(int rc, int fn11)
{ {
gen_fp_exc_raise_ignore(rc, fn11, fn11 & QUAL_I ? 0 : float_flag_inexact); gen_fp_exc_raise_ignore(rc, fn11, fn11 & QUAL_I ? 0 : FPCR_INE);
} }
static void gen_cvtlq(TCGv vc, TCGv vb) static void gen_cvtlq(TCGv vc, TCGv vb)
@ -754,7 +731,6 @@ static void gen_ieee_arith2(DisasContext *ctx,
gen_qual_roundmode(ctx, fn11); gen_qual_roundmode(ctx, fn11);
gen_qual_flushzero(ctx, fn11); gen_qual_flushzero(ctx, fn11);
gen_fp_exc_clear();
vb = gen_ieee_input(ctx, rb, fn11, 0); vb = gen_ieee_input(ctx, rb, fn11, 0);
helper(dest_fpr(ctx, rc), cpu_env, vb); helper(dest_fpr(ctx, rc), cpu_env, vb);
@ -779,7 +755,6 @@ static void gen_cvttq(DisasContext *ctx, int rb, int rc, int fn11)
int ignore = 0; int ignore = 0;
/* No need to set flushzero, since we have an integer output. */ /* No need to set flushzero, since we have an integer output. */
gen_fp_exc_clear();
vb = gen_ieee_input(ctx, rb, fn11, 0); vb = gen_ieee_input(ctx, rb, fn11, 0);
vc = dest_fpr(ctx, rc); vc = dest_fpr(ctx, rc);
@ -791,7 +766,7 @@ static void gen_cvttq(DisasContext *ctx, int rb, int rc, int fn11)
break; break;
case QUAL_V | QUAL_RM_C: case QUAL_V | QUAL_RM_C:
case QUAL_S | QUAL_V | QUAL_RM_C: case QUAL_S | QUAL_V | QUAL_RM_C:
ignore = float_flag_inexact; ignore = FPCR_INE;
/* FALLTHRU */ /* FALLTHRU */
case QUAL_S | QUAL_V | QUAL_I | QUAL_RM_C: case QUAL_S | QUAL_V | QUAL_I | QUAL_RM_C:
gen_helper_cvttq_svic(vc, cpu_env, vb); gen_helper_cvttq_svic(vc, cpu_env, vb);
@ -799,8 +774,8 @@ static void gen_cvttq(DisasContext *ctx, int rb, int rc, int fn11)
default: default:
gen_qual_roundmode(ctx, fn11); gen_qual_roundmode(ctx, fn11);
gen_helper_cvttq(vc, cpu_env, vb); gen_helper_cvttq(vc, cpu_env, vb);
ignore |= (fn11 & QUAL_V ? 0 : float_flag_overflow); ignore |= (fn11 & QUAL_V ? 0 : FPCR_IOV);
ignore |= (fn11 & QUAL_I ? 0 : float_flag_inexact); ignore |= (fn11 & QUAL_I ? 0 : FPCR_INE);
break; break;
} }
@ -821,7 +796,6 @@ static void gen_ieee_intcvt(DisasContext *ctx,
is inexact. Thus we only need to worry about exceptions when is inexact. Thus we only need to worry about exceptions when
inexact handling is requested. */ inexact handling is requested. */
if (fn11 & QUAL_I) { if (fn11 & QUAL_I) {
gen_fp_exc_clear();
helper(vc, cpu_env, vb); helper(vc, cpu_env, vb);
gen_fp_exc_raise(rc, fn11); gen_fp_exc_raise(rc, fn11);
} else { } else {
@ -864,7 +838,6 @@ static void gen_ieee_arith3(DisasContext *ctx,
gen_qual_roundmode(ctx, fn11); gen_qual_roundmode(ctx, fn11);
gen_qual_flushzero(ctx, fn11); gen_qual_flushzero(ctx, fn11);
gen_fp_exc_clear();
va = gen_ieee_input(ctx, ra, fn11, 0); va = gen_ieee_input(ctx, ra, fn11, 0);
vb = gen_ieee_input(ctx, rb, fn11, 0); vb = gen_ieee_input(ctx, rb, fn11, 0);
@ -895,8 +868,6 @@ static void gen_ieee_compare(DisasContext *ctx,
{ {
TCGv va, vb, vc; TCGv va, vb, vc;
gen_fp_exc_clear();
va = gen_ieee_input(ctx, ra, fn11, 1); va = gen_ieee_input(ctx, ra, fn11, 1);
vb = gen_ieee_input(ctx, rb, fn11, 1); vb = gen_ieee_input(ctx, rb, fn11, 1);
vc = dest_fpr(ctx, rc); vc = dest_fpr(ctx, rc);