qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Richard Henderson <rth@twiddle.net>
To: qemu-devel@nongnu.org
Cc: laurent.desnogues@gmail.com
Subject: [Qemu-devel] [patch] target-alpha: squashed fpu qualifiers patch
Date: Fri, 18 Dec 2009 14:09:09 -0800	[thread overview]
Message-ID: <4B2BFD85.6070702@twiddle.net> (raw)

[-- Attachment #1: Type: text/plain, Size: 142 bytes --]

This is a squashed version of the 3 or 4 incremental patches that I had 
sent out for implementing the alpha fpu instruction qualifiers.


r~

[-- Attachment #2: commit-fpu-qual --]
[-- Type: text/plain, Size: 47063 bytes --]

commit 572164702dd83955fc8783c85811ec86c3fb6e4a
Author: Richard Henderson <rth@twiddle.net>
Date:   Fri Dec 18 10:50:32 2009 -0800

    target-alpha: Implement fp insn qualifiers.
    
    Adds a third constant argument to the fpu helpers, which contain the
    unparsed qualifier bits.  The helper functions use new begin_fp/end_fp
    routines that extract the rounding mode from the qualifier bits, as
    well as raise exceptions for non-finite inputs and outputs also as
    directed by the qualifier bits.
    
    cpu_alpha_load/store_fpcr modified to load/store the majority of the
    bits from env->fpcr.  This because we hadn't been saving a few of the
    fpcr bits in the fp_status field: in particular DNZ.
    
    Re-implement cvttq without saturation of overflow results, to match
    the Alpha specification.
    
    Signed-off-by: Richard Henderson <rth@twiddle.net>

diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index c0dff4b..c1c0470 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -430,9 +430,13 @@ enum {
 };
 
 /* Arithmetic exception */
-enum {
-    EXCP_ARITH_OVERFLOW,
-};
+#define EXC_M_IOV	(1<<16)		/* Integer Overflow */
+#define EXC_M_INE	(1<<15)		/* Inexact result */
+#define EXC_M_UNF	(1<<14)		/* Underflow */
+#define EXC_M_FOV	(1<<13)		/* Overflow */
+#define EXC_M_DZE	(1<<12)		/* Division by zero */
+#define EXC_M_INV	(1<<11)		/* Invalid operation */
+#define EXC_M_SWC	(1<<10)		/* Software completion */
 
 enum {
     IR_V0   = 0,
diff --git a/target-alpha/helper.c b/target-alpha/helper.c
index be7d37b..94821bd 100644
--- a/target-alpha/helper.c
+++ b/target-alpha/helper.c
@@ -27,41 +27,13 @@
 
 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;
-    }
+    uint64_t ret = env->fp_status.float_exception_flags;
+
+    if (ret)
+      ret = FPCR_SUM | (ret << 52);
+
+    ret |= env->fpcr & ~(FPCR_SUM | FPCR_STATUS_MASK);
+
     return ret;
 }
 
@@ -69,6 +41,8 @@ void cpu_alpha_store_fpcr (CPUState *env, uint64_t val)
 {
     int round_mode, mask;
 
+    env->fpcr = val;
+
     set_float_exception_flags((val >> 52) & 0x3F, &env->fp_status);
 
     mask = 0;
@@ -86,6 +60,7 @@ void cpu_alpha_store_fpcr (CPUState *env, uint64_t val)
 
     switch ((val >> FPCR_DYN_SHIFT) & 3) {
     case 0:
+    default:
         round_mode = float_round_to_zero;
         break;
     case 1:
@@ -100,6 +75,11 @@ void cpu_alpha_store_fpcr (CPUState *env, uint64_t val)
         break;
     }
     set_float_rounding_mode(round_mode, &env->fp_status);
+
+    mask = 0;
+    if ((val & (FPCR_UNDZ|FPCR_UNFD)) == (FPCR_UNDZ|FPCR_UNFD))
+        mask = 1;
+    set_flush_to_zero(mask, &env->fp_status);
 }
 
 #if defined(CONFIG_USER_ONLY)
diff --git a/target-alpha/helper.h b/target-alpha/helper.h
index bedd3c0..1521a84 100644
--- a/target-alpha/helper.h
+++ b/target-alpha/helper.h
@@ -41,33 +41,33 @@ DEF_HELPER_1(store_fpcr, void, i64)
 
 DEF_HELPER_1(f_to_memory, i32, i64)
 DEF_HELPER_1(memory_to_f, i64, i32)
-DEF_HELPER_2(addf, i64, i64, i64)
-DEF_HELPER_2(subf, i64, i64, i64)
-DEF_HELPER_2(mulf, i64, i64, i64)
-DEF_HELPER_2(divf, i64, i64, i64)
-DEF_HELPER_1(sqrtf, i64, i64)
+DEF_HELPER_3(addf, i64, i64, i64, i32)
+DEF_HELPER_3(subf, i64, i64, i64, i32)
+DEF_HELPER_3(mulf, i64, i64, i64, i32)
+DEF_HELPER_3(divf, i64, i64, i64, i32)
+DEF_HELPER_2(sqrtf, i64, i64, i32)
 
 DEF_HELPER_1(g_to_memory, i64, i64)
 DEF_HELPER_1(memory_to_g, i64, i64)
-DEF_HELPER_2(addg, i64, i64, i64)
-DEF_HELPER_2(subg, i64, i64, i64)
-DEF_HELPER_2(mulg, i64, i64, i64)
-DEF_HELPER_2(divg, i64, i64, i64)
-DEF_HELPER_1(sqrtg, i64, i64)
+DEF_HELPER_3(addg, i64, i64, i64, i32)
+DEF_HELPER_3(subg, i64, i64, i64, i32)
+DEF_HELPER_3(mulg, i64, i64, i64, i32)
+DEF_HELPER_3(divg, i64, i64, i64, i32)
+DEF_HELPER_2(sqrtg, i64, i64, i32)
 
 DEF_HELPER_1(s_to_memory, i32, i64)
 DEF_HELPER_1(memory_to_s, i64, i32)
-DEF_HELPER_2(adds, i64, i64, i64)
-DEF_HELPER_2(subs, i64, i64, i64)
-DEF_HELPER_2(muls, i64, i64, i64)
-DEF_HELPER_2(divs, i64, i64, i64)
-DEF_HELPER_1(sqrts, i64, i64)
-
-DEF_HELPER_2(addt, i64, i64, i64)
-DEF_HELPER_2(subt, i64, i64, i64)
-DEF_HELPER_2(mult, i64, i64, i64)
-DEF_HELPER_2(divt, i64, i64, i64)
-DEF_HELPER_1(sqrtt, i64, i64)
+DEF_HELPER_3(adds, i64, i64, i64, i32)
+DEF_HELPER_3(subs, i64, i64, i64, i32)
+DEF_HELPER_3(muls, i64, i64, i64, i32)
+DEF_HELPER_3(divs, i64, i64, i64, i32)
+DEF_HELPER_2(sqrts, i64, i64, i32)
+
+DEF_HELPER_3(addt, i64, i64, i64, i32)
+DEF_HELPER_3(subt, i64, i64, i64, i32)
+DEF_HELPER_3(mult, i64, i64, i64, i32)
+DEF_HELPER_3(divt, i64, i64, i64, i32)
+DEF_HELPER_2(sqrtt, i64, i64, i32)
 
 DEF_HELPER_2(cmptun, i64, i64, i64)
 DEF_HELPER_2(cmpteq, i64, i64, i64)
@@ -81,15 +81,15 @@ DEF_HELPER_2(cpys, i64, i64, i64)
 DEF_HELPER_2(cpysn, i64, i64, i64)
 DEF_HELPER_2(cpyse, i64, i64, i64)
 
-DEF_HELPER_1(cvtts, i64, i64)
-DEF_HELPER_1(cvtst, i64, i64)
-DEF_HELPER_1(cvttq, i64, i64)
-DEF_HELPER_1(cvtqs, i64, i64)
-DEF_HELPER_1(cvtqt, i64, i64)
-DEF_HELPER_1(cvtqf, i64, i64)
-DEF_HELPER_1(cvtgf, i64, i64)
-DEF_HELPER_1(cvtgq, i64, i64)
-DEF_HELPER_1(cvtqg, i64, i64)
+DEF_HELPER_2(cvtts, i64, i64, i32)
+DEF_HELPER_2(cvtst, i64, i64, i32)
+DEF_HELPER_2(cvttq, i64, i64, i32)
+DEF_HELPER_2(cvtqs, i64, i64, i32)
+DEF_HELPER_2(cvtqt, i64, i64, i32)
+DEF_HELPER_2(cvtqf, i64, i64, i32)
+DEF_HELPER_2(cvtgf, i64, i64, i32)
+DEF_HELPER_2(cvtgq, i64, i64, i32)
+DEF_HELPER_2(cvtqg, i64, i64, i32)
 DEF_HELPER_1(cvtlq, i64, i64)
 DEF_HELPER_1(cvtql, i64, i64)
 DEF_HELPER_1(cvtqlv, i64, i64)
diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
index b2abf6c..2d1c3d5 100644
--- a/target-alpha/op_helper.c
+++ b/target-alpha/op_helper.c
@@ -24,7 +24,7 @@
 
 /*****************************************************************************/
 /* Exceptions processing helpers */
-void helper_excp (int excp, int error)
+void QEMU_NORETURN helper_excp (int excp, int error)
 {
     env->exception_index = excp;
     env->error_code = error;
@@ -78,7 +78,7 @@ uint64_t helper_addqv (uint64_t op1, uint64_t op2)
     uint64_t tmp = op1;
     op1 += op2;
     if (unlikely((tmp ^ op2 ^ (-1ULL)) & (tmp ^ op1) & (1ULL << 63))) {
-        helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+        helper_excp(EXCP_ARITH, EXC_M_IOV);
     }
     return op1;
 }
@@ -88,7 +88,7 @@ uint64_t helper_addlv (uint64_t op1, uint64_t op2)
     uint64_t tmp = op1;
     op1 = (uint32_t)(op1 + op2);
     if (unlikely((tmp ^ op2 ^ (-1UL)) & (tmp ^ op1) & (1UL << 31))) {
-        helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+        helper_excp(EXCP_ARITH, EXC_M_IOV);
     }
     return op1;
 }
@@ -98,7 +98,7 @@ uint64_t helper_subqv (uint64_t op1, uint64_t op2)
     uint64_t res;
     res = op1 - op2;
     if (unlikely((op1 ^ op2) & (res ^ op1) & (1ULL << 63))) {
-        helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+        helper_excp(EXCP_ARITH, EXC_M_IOV);
     }
     return res;
 }
@@ -108,7 +108,7 @@ uint64_t helper_sublv (uint64_t op1, uint64_t op2)
     uint32_t res;
     res = op1 - op2;
     if (unlikely((op1 ^ op2) & (res ^ op1) & (1UL << 31))) {
-        helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+        helper_excp(EXCP_ARITH, EXC_M_IOV);
     }
     return res;
 }
@@ -118,7 +118,7 @@ uint64_t helper_mullv (uint64_t op1, uint64_t op2)
     int64_t res = (int64_t)op1 * (int64_t)op2;
 
     if (unlikely((int32_t)res != res)) {
-        helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+        helper_excp(EXCP_ARITH, EXC_M_IOV);
     }
     return (int64_t)((int32_t)res);
 }
@@ -130,7 +130,7 @@ uint64_t helper_mulqv (uint64_t op1, uint64_t op2)
     muls64(&tl, &th, op1, op2);
     /* If th != 0 && th != -1, then we had an overflow */
     if (unlikely((th + 1) > 1)) {
-        helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+        helper_excp(EXCP_ARITH, EXC_M_IOV);
     }
     return tl;
 }
@@ -370,8 +370,175 @@ uint64_t helper_unpkbw (uint64_t op1)
 
 /* Floating point helpers */
 
+/* ??? Not implemented is setting EXC_MASK, containing a bitmask of
+   destination registers of instructions that have caused arithmetic
+   traps.  Not needed for userspace emulation, or for complete 
+   emulation of the entire fpu stack within qemu.  But we would need
+   it to invoke a guest kernel's entArith trap handler properly.
+   
+   It would be possible to encode the FP destination register in the
+   QUAL parameter for the FPU helpers below; additional changes would
+   be required for ADD/V et al above.  */
+
+#define QUAL_RM_N	0x080	/* Round mode nearest even */
+#define QUAL_RM_C	0x000	/* Round mode chopped */
+#define QUAL_RM_M	0x040	/* Round mode minus infinity */
+#define QUAL_RM_D	0x0c0	/* Round mode dynamic */
+#define QUAL_RM_MASK	0x0c0
+
+#define QUAL_U		0x100	/* Underflow enable (fp output) */
+#define QUAL_V		0x100	/* Overflow enable (int output) */
+#define QUAL_S		0x400	/* Software completion enable */
+#define QUAL_I		0x200	/* Inexact detection enable */
+
+/* If the floating-point qualifiers specified a rounding mode,
+   set that rounding mode and remember the original mode for
+   resetting at the end of the instruction.  */
+static inline uint32_t begin_fp_roundmode(uint32_t qual)
+{
+    uint32_t rm = FP_STATUS.float_rounding_mode, old_rm = rm;
+
+    switch (qual & QUAL_RM_MASK) {
+    default:
+    case QUAL_RM_N:
+        rm = float_round_nearest_even;
+        break;
+    case QUAL_RM_C:
+        rm = float_round_to_zero;
+        break;
+    case QUAL_RM_M:
+        rm = float_round_down;
+        break;
+    case QUAL_RM_D:
+        return old_rm;
+    }
+    if (old_rm != rm)
+        set_float_rounding_mode(rm, &FP_STATUS);
+    return old_rm;
+}
+
+/* Zero the exception flags so that we can determine if the current
+   instruction raises any exceptions.  Save the old acrued exception
+   status so that we can restore them at the end of the insn.  */
+static inline uint32_t begin_fp_exception(void)
+{
+    uint32_t old_exc = (uint32_t)FP_STATUS.float_exception_flags << 8;
+    set_float_exception_flags(0, &FP_STATUS);
+    return old_exc;
+}
+
+static inline uint32_t begin_fp_flush_to_zero(uint32_t quals)
+{
+    /* If underflow detection is disabled, silently flush to zero.
+       Note that flush-to-zero mode may already be enabled via the FPCR.  */
+    if ((quals & QUAL_U) == 0 && !FP_STATUS.flush_to_zero) {
+        set_flush_to_zero(1, &FP_STATUS);
+        return 0x10000;
+    }
+    return 0;
+}
+
+/* Begin processing an fp operation.  Return a token that should be passed
+   when completing the fp operation.  */
+static uint32_t begin_fp(uint32_t quals)
+{
+    uint32_t ret = 0;
+
+    ret |= begin_fp_roundmode(quals);
+    ret |= begin_fp_flush_to_zero(quals);
+    ret |= begin_fp_exception();
+
+    return ret;
+}
+
+/* End processing an fp operation.  */
+
+static inline void end_fp_roundmode(uint32_t orig)
+{
+    uint32_t rm = FP_STATUS.float_rounding_mode, old_rm = orig & 0xff;
+    if (unlikely(rm != old_rm))
+        set_float_rounding_mode(old_rm, &FP_STATUS);
+}
+
+static inline void end_fp_flush_to_zero(uint32_t orig)
+{
+    if (orig & 0x10000)
+        set_flush_to_zero(0, &FP_STATUS);
+}
+
+static void end_fp_exception(uint32_t quals, uint32_t orig)
+{
+    uint8_t exc = FP_STATUS.float_exception_flags;
+
+    /* If inexact detection is disabled, silently clear it.  */
+    if ((quals & QUAL_I) == 0)
+        exc &= ~float_flag_inexact;
+
+    orig = (orig >> 8) & 0xff;
+    set_float_exception_flags(exc | orig, &FP_STATUS);
+
+    /* Raise an exception as required.  */
+    if (unlikely(exc)) {
+        if (quals & QUAL_S)
+            exc &= ~FP_STATUS.float_exception_mask;
+        if (exc) {
+            uint32_t hw_exc = 0;
+
+            if (exc & float_flag_invalid)
+                hw_exc |= EXC_M_INV;
+            if (exc & float_flag_divbyzero)
+                hw_exc |= EXC_M_DZE;
+            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;
+
+            helper_excp(EXCP_ARITH, hw_exc);
+        }
+    }
+}
+
+static void end_fp(uint32_t quals, uint32_t orig)
+{
+    end_fp_roundmode(orig);
+    end_fp_flush_to_zero(orig);
+    end_fp_exception(quals, orig);
+}
+
+static uint64_t remap_ieee_input(uint32_t quals, uint64_t a)
+{
+    uint64_t frac;
+    uint32_t exp;
+
+    exp = (uint32_t)(a >> 52) & 0x7ff;
+    frac = a & 0xfffffffffffffull;
+
+    if (exp == 0) {
+        if (frac != 0) {
+            /* If DNZ is set, flush denormals to zero on input.  */
+            if (env->fpcr & FPCR_DNZ)
+                a = a & (1ull << 63);
+            /* If software completion not enabled, trap.  */
+            else if ((quals & QUAL_S) == 0)
+                helper_excp(EXCP_ARITH, EXC_M_UNF);
+        }
+    } else if (exp == 0x7ff) {
+        /* Infinity or NaN.  If software completion is not enabled, trap.
+           If /s is enabled, we'll properly signal for SNaN on output.  */
+        /* ??? I'm not sure these exception bit flags are correct.  I do
+           know that the Linux kernel, at least, doesn't rely on them and
+           just emulates the insn to figure out what exception to use.  */
+        if ((quals & QUAL_S) == 0)
+            helper_excp(EXCP_ARITH, frac ? EXC_M_INV : EXC_M_FOV);
+    }
+
+    return a;
+}
+
 /* F floating (VAX) */
-static inline uint64_t float32_to_f(float32 fa)
+static uint64_t float32_to_f(float32 fa)
 {
     uint64_t r, exp, mant, sig;
     CPU_FloatU a;
@@ -404,7 +571,7 @@ static inline uint64_t float32_to_f(float32 fa)
     return r;
 }
 
-static inline float32 f_to_float32(uint64_t a)
+static float32 f_to_float32(uint64_t a)
 {
     uint32_t exp, mant_sig;
     CPU_FloatU r;
@@ -447,58 +614,83 @@ uint64_t helper_memory_to_f (uint32_t a)
     return r;
 }
 
-uint64_t helper_addf (uint64_t a, uint64_t b)
+uint64_t helper_addf (uint64_t a, uint64_t b, uint32_t quals)
 {
     float32 fa, fb, fr;
+    uint32_t token;
 
     fa = f_to_float32(a);
     fb = f_to_float32(b);
+
+    token = begin_fp(quals);
     fr = float32_add(fa, fb, &FP_STATUS);
+    end_fp(quals, token);
+
     return float32_to_f(fr);
 }
 
-uint64_t helper_subf (uint64_t a, uint64_t b)
+uint64_t helper_subf (uint64_t a, uint64_t b, uint32_t quals)
 {
     float32 fa, fb, fr;
+    uint32_t token;
 
     fa = f_to_float32(a);
     fb = f_to_float32(b);
+
+    token = begin_fp(quals);
     fr = float32_sub(fa, fb, &FP_STATUS);
+    end_fp(quals, token);
+
     return float32_to_f(fr);
 }
 
-uint64_t helper_mulf (uint64_t a, uint64_t b)
+uint64_t helper_mulf (uint64_t a, uint64_t b, uint32_t quals)
 {
     float32 fa, fb, fr;
+    uint32_t token;
 
     fa = f_to_float32(a);
     fb = f_to_float32(b);
+
+    token = begin_fp(quals);
     fr = float32_mul(fa, fb, &FP_STATUS);
+    end_fp(quals, token);
+
     return float32_to_f(fr);
 }
 
-uint64_t helper_divf (uint64_t a, uint64_t b)
+uint64_t helper_divf (uint64_t a, uint64_t b, uint32_t quals)
 {
     float32 fa, fb, fr;
+    uint32_t token;
 
     fa = f_to_float32(a);
     fb = f_to_float32(b);
+
+    token = begin_fp(quals);
     fr = float32_div(fa, fb, &FP_STATUS);
+    end_fp(quals, token);
+
     return float32_to_f(fr);
 }
 
-uint64_t helper_sqrtf (uint64_t t)
+uint64_t helper_sqrtf (uint64_t t, uint32_t quals)
 {
     float32 ft, fr;
+    uint32_t token;
 
     ft = f_to_float32(t);
+
+    token = begin_fp(quals);
     fr = float32_sqrt(ft, &FP_STATUS);
+    end_fp(quals, token);
+
     return float32_to_f(fr);
 }
 
 
 /* G floating (VAX) */
-static inline uint64_t float64_to_g(float64 fa)
+static uint64_t float64_to_g(float64 fa)
 {
     uint64_t r, exp, mant, sig;
     CPU_DoubleU a;
@@ -531,7 +723,7 @@ static inline uint64_t float64_to_g(float64 fa)
     return r;
 }
 
-static inline float64 g_to_float64(uint64_t a)
+static float64 g_to_float64(uint64_t a)
 {
     uint64_t exp, mant_sig;
     CPU_DoubleU r;
@@ -574,52 +766,77 @@ uint64_t helper_memory_to_g (uint64_t a)
     return r;
 }
 
-uint64_t helper_addg (uint64_t a, uint64_t b)
+uint64_t helper_addg (uint64_t a, uint64_t b, uint32_t quals)
 {
     float64 fa, fb, fr;
+    uint32_t token;
 
     fa = g_to_float64(a);
     fb = g_to_float64(b);
+
+    token = begin_fp(quals);
     fr = float64_add(fa, fb, &FP_STATUS);
+    end_fp(quals, token);
+
     return float64_to_g(fr);
 }
 
-uint64_t helper_subg (uint64_t a, uint64_t b)
+uint64_t helper_subg (uint64_t a, uint64_t b, uint32_t quals)
 {
     float64 fa, fb, fr;
+    uint32_t token;
 
     fa = g_to_float64(a);
     fb = g_to_float64(b);
+
+    token = begin_fp(quals);
     fr = float64_sub(fa, fb, &FP_STATUS);
+    end_fp(quals, token);
+
     return float64_to_g(fr);
 }
 
-uint64_t helper_mulg (uint64_t a, uint64_t b)
+uint64_t helper_mulg (uint64_t a, uint64_t b, uint32_t quals)
 {
     float64 fa, fb, fr;
-
+    uint32_t token;
+    
     fa = g_to_float64(a);
     fb = g_to_float64(b);
+
+    token = begin_fp(quals);
     fr = float64_mul(fa, fb, &FP_STATUS);
+    end_fp(quals, token);
+
     return float64_to_g(fr);
 }
 
-uint64_t helper_divg (uint64_t a, uint64_t b)
+uint64_t helper_divg (uint64_t a, uint64_t b, uint32_t quals)
 {
     float64 fa, fb, fr;
+    uint32_t token;
 
     fa = g_to_float64(a);
     fb = g_to_float64(b);
+
+    token = begin_fp(quals);
     fr = float64_div(fa, fb, &FP_STATUS);
+    end_fp(quals, token);
+
     return float64_to_g(fr);
 }
 
-uint64_t helper_sqrtg (uint64_t a)
+uint64_t helper_sqrtg (uint64_t a, uint32_t quals)
 {
     float64 fa, fr;
+    uint32_t token;
 
     fa = g_to_float64(a);
+
+    token = begin_fp(quals);
     fr = float64_sqrt(fa, &FP_STATUS);
+    end_fp(quals, token);
+
     return float64_to_g(fr);
 }
 
@@ -627,7 +844,7 @@ uint64_t helper_sqrtg (uint64_t a)
 /* S floating (single) */
 
 /* Taken from linux/arch/alpha/kernel/traps.c, s_mem_to_reg.  */
-static inline uint64_t float32_to_s_int(uint32_t fi)
+static uint64_t float32_to_s_int(uint32_t fi)
 {
     uint32_t frac = fi & 0x7fffff;
     uint32_t sign = fi >> 31;
@@ -649,7 +866,7 @@ static inline uint64_t float32_to_s_int(uint32_t fi)
             | ((uint64_t)frac << 29));
 }
 
-static inline uint64_t float32_to_s(float32 fa)
+static uint64_t float32_to_s(float32 fa)
 {
     CPU_FloatU a;
     a.f = fa;
@@ -678,52 +895,77 @@ uint64_t helper_memory_to_s (uint32_t a)
     return float32_to_s_int(a);
 }
 
-uint64_t helper_adds (uint64_t a, uint64_t b)
+static float32 input_s(uint32_t quals, uint64_t a)
+{
+    return s_to_float32(remap_ieee_input(quals, a));
+}
+
+uint64_t helper_adds (uint64_t a, uint64_t b, uint32_t quals)
 {
     float32 fa, fb, fr;
+    uint32_t token;
 
-    fa = s_to_float32(a);
-    fb = s_to_float32(b);
+    token = begin_fp(quals);
+    fa = input_s(quals, a);
+    fb = input_s(quals, b);
     fr = float32_add(fa, fb, &FP_STATUS);
+    end_fp(quals, token);
+
     return float32_to_s(fr);
 }
 
-uint64_t helper_subs (uint64_t a, uint64_t b)
+uint64_t helper_subs (uint64_t a, uint64_t b, uint32_t quals)
 {
     float32 fa, fb, fr;
+    uint32_t token;
 
-    fa = s_to_float32(a);
-    fb = s_to_float32(b);
+    token = begin_fp(quals);
+    fa = input_s(quals, a);
+    fb = input_s(quals, b);
     fr = float32_sub(fa, fb, &FP_STATUS);
+    end_fp(quals, token);
+
     return float32_to_s(fr);
 }
 
-uint64_t helper_muls (uint64_t a, uint64_t b)
+uint64_t helper_muls (uint64_t a, uint64_t b, uint32_t quals)
 {
     float32 fa, fb, fr;
+    uint32_t token;
 
-    fa = s_to_float32(a);
-    fb = s_to_float32(b);
+    token = begin_fp(quals);
+    fa = input_s(quals, a);
+    fb = input_s(quals, b);
     fr = float32_mul(fa, fb, &FP_STATUS);
+    end_fp(quals, token);
+
     return float32_to_s(fr);
 }
 
-uint64_t helper_divs (uint64_t a, uint64_t b)
+uint64_t helper_divs (uint64_t a, uint64_t b, uint32_t quals)
 {
     float32 fa, fb, fr;
+    uint32_t token;
 
-    fa = s_to_float32(a);
-    fb = s_to_float32(b);
+    token = begin_fp(quals);
+    fa = input_s(quals, a);
+    fb = input_s(quals, b);
     fr = float32_div(fa, fb, &FP_STATUS);
+    end_fp(quals, token);
+
     return float32_to_s(fr);
 }
 
-uint64_t helper_sqrts (uint64_t a)
+uint64_t helper_sqrts (uint64_t a, uint32_t quals)
 {
     float32 fa, fr;
+    uint32_t token;
 
-    fa = s_to_float32(a);
+    token = begin_fp(quals);
+    fa = input_s(quals, a);
     fr = float32_sqrt(fa, &FP_STATUS);
+    end_fp(quals, token);
+
     return float32_to_s(fr);
 }
 
@@ -745,52 +987,78 @@ static inline uint64_t float64_to_t(float64 fa)
     return r.ll;
 }
 
-uint64_t helper_addt (uint64_t a, uint64_t b)
+/* Raise any exceptions needed for using F, given the insn qualifiers.  */
+static float64 input_t(uint32_t quals, uint64_t a)
+{
+    return t_to_float64(remap_ieee_input(quals, a));
+}
+
+uint64_t helper_addt (uint64_t a, uint64_t b, uint32_t quals)
 {
     float64 fa, fb, fr;
+    uint32_t token;
 
-    fa = t_to_float64(a);
-    fb = t_to_float64(b);
+    token = begin_fp(quals);
+    fa = input_t(quals, a);
+    fb = input_t(quals, b);
     fr = float64_add(fa, fb, &FP_STATUS);
+    end_fp(quals, token);
+
     return float64_to_t(fr);
 }
 
-uint64_t helper_subt (uint64_t a, uint64_t b)
+uint64_t helper_subt (uint64_t a, uint64_t b, uint32_t quals)
 {
     float64 fa, fb, fr;
+    uint32_t token;
 
-    fa = t_to_float64(a);
-    fb = t_to_float64(b);
+    token = begin_fp(quals);
+    fa = input_t(quals, a);
+    fb = input_t(quals, b);
     fr = float64_sub(fa, fb, &FP_STATUS);
+    end_fp(quals, token);
+    
     return float64_to_t(fr);
 }
 
-uint64_t helper_mult (uint64_t a, uint64_t b)
+uint64_t helper_mult (uint64_t a, uint64_t b, uint32_t quals)
 {
     float64 fa, fb, fr;
+    uint32_t token;
 
-    fa = t_to_float64(a);
-    fb = t_to_float64(b);
+    token = begin_fp(quals);
+    fa = input_t(quals, a);
+    fb = input_t(quals, b);
     fr = float64_mul(fa, fb, &FP_STATUS);
+    end_fp(quals, token);
+
     return float64_to_t(fr);
 }
 
-uint64_t helper_divt (uint64_t a, uint64_t b)
+uint64_t helper_divt (uint64_t a, uint64_t b, uint32_t quals)
 {
     float64 fa, fb, fr;
+    uint32_t token;
 
-    fa = t_to_float64(a);
-    fb = t_to_float64(b);
+    token = begin_fp(quals);
+    fa = input_t(quals, a);
+    fb = input_t(quals, b);
     fr = float64_div(fa, fb, &FP_STATUS);
+    end_fp(quals, token);
+
     return float64_to_t(fr);
 }
 
-uint64_t helper_sqrtt (uint64_t a)
+uint64_t helper_sqrtt (uint64_t a, uint32_t quals)
 {
     float64 fa, fr;
+    uint32_t token;
 
-    fa = t_to_float64(a);
+    token = begin_fp(quals);
+    fa = input_t(quals, a);
     fr = float64_sqrt(fa, &FP_STATUS);
+    end_fp(quals, token);
+
     return float64_to_t(fr);
 }
 
@@ -813,6 +1081,8 @@ uint64_t helper_cpyse(uint64_t a, uint64_t b)
 
 
 /* Comparisons */
+/* ??? Software completion qualifier missing.  */
+
 uint64_t helper_cmptun (uint64_t a, uint64_t b)
 {
     float64 fa, fb;
@@ -905,70 +1175,218 @@ uint64_t helper_cmpglt(uint64_t a, uint64_t b)
 }
 
 /* Floating point format conversion */
-uint64_t helper_cvtts (uint64_t a)
+uint64_t helper_cvtts (uint64_t a, uint32_t quals)
 {
     float64 fa;
     float32 fr;
+    uint32_t token;
 
-    fa = t_to_float64(a);
+    token = begin_fp(quals);
+    fa = input_t(quals, a);
     fr = float64_to_float32(fa, &FP_STATUS);
+    end_fp(quals, token);
+
     return float32_to_s(fr);
 }
 
-uint64_t helper_cvtst (uint64_t a)
+uint64_t helper_cvtst (uint64_t a, uint32_t quals)
 {
     float32 fa;
     float64 fr;
+    uint32_t token;
 
-    fa = s_to_float32(a);
+    token = begin_fp(quals);
+    fa = input_s(quals, a);
     fr = float32_to_float64(fa, &FP_STATUS);
+    end_fp(quals, token);
+
     return float64_to_t(fr);
 }
 
-uint64_t helper_cvtqs (uint64_t a)
+uint64_t helper_cvtqs (uint64_t a, uint32_t quals)
 {
-    float32 fr = int64_to_float32(a, &FP_STATUS);
+    float32 fr;
+    uint32_t token;
+
+    token = begin_fp(quals);
+    fr = int64_to_float32(a, &FP_STATUS);
+    end_fp(quals, token);
+
     return float32_to_s(fr);
 }
 
-uint64_t helper_cvttq (uint64_t a)
+/* Implement float64 to uint64 conversion without overflow enabled.
+   In this mode we must supply the truncated result.  This behaviour
+   is used by the compiler to get unsigned conversion for free with
+   the same instruction.  */
+
+static uint64_t cvttq_internal(uint64_t a)
 {
-    float64 fa = t_to_float64(a);
-    return float64_to_int64_round_to_zero(fa, &FP_STATUS);
+    uint64_t frac, ret = 0;
+    uint32_t exp, sign, exc = 0;
+    int shift;
+
+    sign = (a >> 63);
+    exp = (uint32_t)(a >> 52) & 0x7ff;
+    frac = a & 0xfffffffffffffull;
+
+    if (exp == 0) {
+        if (unlikely(frac != 0))
+            goto do_underflow;
+    } else if (exp == 0x7ff) {
+        if (frac == 0)
+            exc = float_flag_overflow;
+        else
+            exc = float_flag_invalid;
+    } else {
+        /* Restore implicit bit.  */
+        frac |= 0x10000000000000ull;
+
+        /* Note that neither overflow exceptions nor inexact exceptions
+           are desired.  This lets us streamline the checks quite a bit.  */
+        shift = exp - 1023 - 52;
+        if (shift >= 0) {
+            /* In this case the number is so large that we must shift
+               the fraction left.  There is no rounding to do.  */
+            if (shift < 63) {
+                ret = frac << shift;
+                if ((ret >> shift) != frac)
+                    exc = float_flag_overflow;
+            }
+        } else {
+            uint64_t round;
+
+            /* In this case the number is smaller than the fraction as
+               represented by the 52 bit number.  Here we must think 
+               about rounding the result.  Handle this by shifting the
+               fractional part of the number into the high bits of ROUND.
+               This will let us efficiently handle round-to-nearest.  */
+            shift = -shift;
+            if (shift < 63) {
+                ret = frac >> shift;
+                round = frac << (64 - shift);
+            } else {
+                /* The exponent is so small we shift out everything.
+                   Leave a sticky bit for proper rounding below.  */
+            do_underflow:
+                round = 1;
+            }
+
+            if (round) {
+                exc = float_flag_inexact;
+                switch (FP_STATUS.float_rounding_mode) {
+                case float_round_nearest_even:
+                    if (round == (1ull << 63)) {
+                        /* Fraction is exactly 0.5; round to even.  */
+                        ret += (ret & 1);
+                    } else if (round > (1ull << 63)) {
+                        ret += 1;
+                    }
+                    break;
+                case float_round_to_zero:
+                    break;
+                case float_round_up:
+                    if (!sign)
+                        ret += 1;
+                    break;
+                case float_round_down:
+                    if (sign)
+                        ret += 1;
+                    break;
+                }
+            }
+        }
+        if (sign)
+            ret = -ret;
+    }
+    if (unlikely(exc))
+        float_raise(exc, &FP_STATUS);
+
+    return ret;
+}
+
+uint64_t helper_cvttq (uint64_t a, uint32_t quals)
+{
+    uint64_t ret;
+    uint32_t token;
+
+    /* ??? There's an arugument to be made that when /S is enabled, we
+       should provide the standard IEEE saturated result, instead of
+       the truncated result that we *must* provide when /V is disabled.
+       However, that's not how either the Tru64 or Linux completion
+       handlers actually work, and GCC knows it.  */
+
+    token = begin_fp(quals);
+    a = remap_ieee_input(quals, a);
+    ret = cvttq_internal(a);
+    end_fp(quals, token);
+
+    return ret;
 }
 
-uint64_t helper_cvtqt (uint64_t a)
+uint64_t helper_cvtqt (uint64_t a, uint32_t quals)
 {
-    float64 fr = int64_to_float64(a, &FP_STATUS);
+    float64 fr;
+    uint32_t token;
+
+    token = begin_fp(quals);
+    fr = int64_to_float64(a, &FP_STATUS);
+    end_fp(quals, token);
+
     return float64_to_t(fr);
 }
 
-uint64_t helper_cvtqf (uint64_t a)
+uint64_t helper_cvtqf (uint64_t a, uint32_t quals)
 {
-    float32 fr = int64_to_float32(a, &FP_STATUS);
+    float32 fr;
+    uint32_t token;
+
+    token = begin_fp(quals);
+    fr = int64_to_float32(a, &FP_STATUS);
+    end_fp(quals, token);
+
     return float32_to_f(fr);
 }
 
-uint64_t helper_cvtgf (uint64_t a)
+uint64_t helper_cvtgf (uint64_t a, uint32_t quals)
 {
     float64 fa;
     float32 fr;
+    uint32_t token;
 
     fa = g_to_float64(a);
+
+    token = begin_fp(quals);
     fr = float64_to_float32(fa, &FP_STATUS);
+    end_fp(quals, token);
+
     return float32_to_f(fr);
 }
 
-uint64_t helper_cvtgq (uint64_t a)
+uint64_t helper_cvtgq (uint64_t a, uint32_t quals)
 {
-    float64 fa = g_to_float64(a);
-    return float64_to_int64_round_to_zero(fa, &FP_STATUS);
+    float64 fa;
+    uint64_t ret;
+    uint32_t token;
+
+    fa = g_to_float64(a);
+
+    token = begin_fp(quals);
+    ret = float64_to_int64(fa, &FP_STATUS);
+    end_fp(quals, token);
+
+    return ret;
 }
 
-uint64_t helper_cvtqg (uint64_t a)
+uint64_t helper_cvtqg (uint64_t a, uint32_t quals)
 {
     float64 fr;
+    uint32_t token;
+
+    token = begin_fp(quals);
     fr = int64_to_float64(a, &FP_STATUS);
+    end_fp(quals, token);
+
     return float64_to_g(fr);
 }
 
@@ -979,35 +1397,24 @@ uint64_t helper_cvtlq (uint64_t a)
     return (lo & 0x3FFFFFFF) | (hi & 0xc0000000);
 }
 
-static inline uint64_t __helper_cvtql(uint64_t a, int s, int v)
-{
-    uint64_t r;
-
-    r = ((uint64_t)(a & 0xC0000000)) << 32;
-    r |= ((uint64_t)(a & 0x7FFFFFFF)) << 29;
-
-    if (v && (int64_t)((int32_t)r) != (int64_t)r) {
-        helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
-    }
-    if (s) {
-        /* TODO */
-    }
-    return r;
-}
-
 uint64_t helper_cvtql (uint64_t a)
 {
-    return __helper_cvtql(a, 0, 0);
+    return ((a & 0xC0000000) << 32) | ((a & 0x7FFFFFFF) << 29);
 }
 
 uint64_t helper_cvtqlv (uint64_t a)
 {
-    return __helper_cvtql(a, 0, 1);
+    if ((int32_t)a != (int64_t)a)
+        helper_excp(EXCP_ARITH, EXC_M_IOV);
+    return helper_cvtql(a);
 }
 
 uint64_t helper_cvtqlsv (uint64_t a)
 {
-    return __helper_cvtql(a, 1, 1);
+    /* ??? I'm pretty sure there's nothing that /sv needs to do that /v
+       doesn't do.  The only thing I can think is that /sv is a valid
+       instruction merely for completeness in the ISA.  */
+    return helper_cvtqlv(a);
 }
 
 /* PALcode support special instructions */
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index 45cb697..e0ca0ed 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -442,81 +442,79 @@ static void gen_fcmov(TCGCond inv_cond, int ra, int rb, int rc)
     gen_set_label(l1);
 }
 
-#define FARITH2(name)                                       \
-static inline void glue(gen_f, name)(int rb, int rc)        \
-{                                                           \
-    if (unlikely(rc == 31))                                 \
-      return;                                               \
-                                                            \
-    if (rb != 31)                                           \
-        gen_helper_ ## name (cpu_fir[rc], cpu_fir[rb]);    \
-    else {                                                  \
-        TCGv tmp = tcg_const_i64(0);                        \
-        gen_helper_ ## name (cpu_fir[rc], tmp);            \
-        tcg_temp_free(tmp);                                 \
-    }                                                       \
+#define FARITH2(name)                                   \
+static inline void glue(gen_f, name)(int rb, int rc)    \
+{                                                       \
+    if (unlikely(rc == 31))                             \
+      return;                                           \
+                                                        \
+    if (rb != 31)                                       \
+        gen_helper_ ## name (cpu_fir[rc], cpu_fir[rb]); \
+    else {                                              \
+        TCGv tmp = tcg_const_i64(0);                    \
+        gen_helper_ ## name (cpu_fir[rc], tmp);         \
+        tcg_temp_free(tmp);                             \
+    }                                                   \
 }
-FARITH2(sqrts)
-FARITH2(sqrtf)
-FARITH2(sqrtg)
-FARITH2(sqrtt)
-FARITH2(cvtgf)
-FARITH2(cvtgq)
-FARITH2(cvtqf)
-FARITH2(cvtqg)
-FARITH2(cvtst)
-FARITH2(cvtts)
-FARITH2(cvttq)
-FARITH2(cvtqs)
-FARITH2(cvtqt)
 FARITH2(cvtlq)
 FARITH2(cvtql)
 FARITH2(cvtqlv)
 FARITH2(cvtqlsv)
 
-#define FARITH3(name)                                                     \
-static inline void glue(gen_f, name)(int ra, int rb, int rc)              \
-{                                                                         \
-    if (unlikely(rc == 31))                                               \
-        return;                                                           \
-                                                                          \
-    if (ra != 31) {                                                       \
-        if (rb != 31)                                                     \
-            gen_helper_ ## name (cpu_fir[rc], cpu_fir[ra], cpu_fir[rb]);  \
-        else {                                                            \
-            TCGv tmp = tcg_const_i64(0);                                  \
-            gen_helper_ ## name (cpu_fir[rc], cpu_fir[ra], tmp);          \
-            tcg_temp_free(tmp);                                           \
-        }                                                                 \
-    } else {                                                              \
-        TCGv tmp = tcg_const_i64(0);                                      \
-        if (rb != 31)                                                     \
-            gen_helper_ ## name (cpu_fir[rc], tmp, cpu_fir[rb]);          \
-        else                                                              \
-            gen_helper_ ## name (cpu_fir[rc], tmp, tmp);                   \
-        tcg_temp_free(tmp);                                               \
-    }                                                                     \
+#define QFARITH2(name)                                          \
+static inline void glue(gen_f, name)(int rb, int rc, int opc)   \
+{                                                               \
+    TCGv_i32 quals;                                             \
+    if (unlikely(rc == 31))                                     \
+      return;                                                   \
+    quals = tcg_const_i32(opc & ~0x3f);                         \
+    if (rb != 31)                                               \
+        gen_helper_ ## name (cpu_fir[rc], cpu_fir[rb], quals);  \
+    else {                                                      \
+        TCGv tmp = tcg_const_i64(0);                            \
+        gen_helper_ ## name (cpu_fir[rc], tmp, quals);          \
+        tcg_temp_free(tmp);                                     \
+    }                                                           \
+    tcg_temp_free_i32(quals);                                   \
+}
+QFARITH2(sqrts)
+QFARITH2(sqrtf)
+QFARITH2(sqrtg)
+QFARITH2(sqrtt)
+QFARITH2(cvtgf)
+QFARITH2(cvtgq)
+QFARITH2(cvtqf)
+QFARITH2(cvtqg)
+QFARITH2(cvtst)
+QFARITH2(cvtts)
+QFARITH2(cvttq)
+QFARITH2(cvtqs)
+QFARITH2(cvtqt)
+
+#define FARITH3(name)                                           \
+static inline void glue(gen_f, name)(int ra, int rb, int rc)    \
+{                                                               \
+    TCGv zero, ta, tb;                                          \
+    if (unlikely(rc == 31))                                     \
+        return;                                                 \
+    ta = cpu_fir[ra];                                           \
+    tb = cpu_fir[rb];                                           \
+    if (unlikely(ra == 31)) {                                   \
+        zero = tcg_const_i64(0);                                \
+        ta = zero;                                              \
+    }                                                           \
+    if (unlikely(rb == 31)) {                                   \
+        if (ra != 31)                                           \
+            zero = tcg_const_i64(0);                            \
+        tb = zero;                                              \
+    }                                                           \
+    gen_helper_ ## name (cpu_fir[rc], ta, tb);                  \
+    if (ra == 31 || rb == 31)                                   \
+        tcg_temp_free(zero);                                    \
 }
-
-FARITH3(addf)
-FARITH3(subf)
-FARITH3(mulf)
-FARITH3(divf)
-FARITH3(addg)
-FARITH3(subg)
-FARITH3(mulg)
-FARITH3(divg)
 FARITH3(cmpgeq)
 FARITH3(cmpglt)
 FARITH3(cmpgle)
-FARITH3(adds)
-FARITH3(subs)
-FARITH3(muls)
-FARITH3(divs)
-FARITH3(addt)
-FARITH3(subt)
-FARITH3(mult)
-FARITH3(divt)
 FARITH3(cmptun)
 FARITH3(cmpteq)
 FARITH3(cmptlt)
@@ -525,6 +523,47 @@ FARITH3(cpys)
 FARITH3(cpysn)
 FARITH3(cpyse)
 
+#define QFARITH3(name)                                                  \
+static inline void glue(gen_f, name)(int ra, int rb, int rc, int opc)   \
+{                                                                       \
+    TCGv zero, ta, tb;                                                  \
+    TCGv_i32 quals;                                                     \
+    if (unlikely(rc == 31))                                             \
+        return;                                                         \
+    ta = cpu_fir[ra];                                                   \
+    tb = cpu_fir[rb];                                                   \
+    if (unlikely(ra == 31)) {                                           \
+        zero = tcg_const_i64(0);                                        \
+        ta = zero;                                                      \
+    }                                                                   \
+    if (unlikely(rb == 31)) {                                           \
+        if (ra != 31)                                                   \
+            zero = tcg_const_i64(0);                                    \
+        tb = zero;                                                      \
+    }                                                                   \
+    quals = tcg_const_i32(opc & ~0x3f);                                 \
+    gen_helper_ ## name (cpu_fir[rc], ta, tb, quals);                   \
+    tcg_temp_free_i32(quals);                                           \
+    if (ra == 31 || rb == 31)                                           \
+        tcg_temp_free(zero);                                            \
+}
+QFARITH3(addf)
+QFARITH3(subf)
+QFARITH3(mulf)
+QFARITH3(divf)
+QFARITH3(addg)
+QFARITH3(subg)
+QFARITH3(mulg)
+QFARITH3(divg)
+QFARITH3(adds)
+QFARITH3(subs)
+QFARITH3(muls)
+QFARITH3(divs)
+QFARITH3(addt)
+QFARITH3(subt)
+QFARITH3(mult)
+QFARITH3(divt)
+
 static inline uint64_t zapnot_mask(uint8_t lit)
 {
     uint64_t mask = 0;
@@ -1607,7 +1646,7 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn)
         }
         break;
     case 0x14:
-        switch (fpfn) { /* f11 & 0x3F */
+        switch (fpfn) { /* fn11 & 0x3F */
         case 0x04:
             /* ITOFS */
             if (!(ctx->amask & AMASK_FIX))
@@ -1626,13 +1665,13 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn)
             /* SQRTF */
             if (!(ctx->amask & AMASK_FIX))
                 goto invalid_opc;
-            gen_fsqrtf(rb, rc);
+            gen_fsqrtf(rb, rc, fn11);
             break;
         case 0x0B:
             /* SQRTS */
             if (!(ctx->amask & AMASK_FIX))
                 goto invalid_opc;
-            gen_fsqrts(rb, rc);
+            gen_fsqrts(rb, rc, fn11);
             break;
         case 0x14:
             /* ITOFF */
@@ -1663,13 +1702,13 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn)
             /* SQRTG */
             if (!(ctx->amask & AMASK_FIX))
                 goto invalid_opc;
-            gen_fsqrtg(rb, rc);
+            gen_fsqrtg(rb, rc, fn11);
             break;
         case 0x02B:
             /* SQRTT */
             if (!(ctx->amask & AMASK_FIX))
                 goto invalid_opc;
-            gen_fsqrtt(rb, rc);
+            gen_fsqrtt(rb, rc, fn11);
             break;
         default:
             goto invalid_opc;
@@ -1677,47 +1716,42 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn)
         break;
     case 0x15:
         /* VAX floating point */
-        /* XXX: rounding mode and trap are ignored (!) */
-        switch (fpfn) { /* f11 & 0x3F */
+        switch (fpfn) { /* fn11 & 0x3F */
         case 0x00:
             /* ADDF */
-            gen_faddf(ra, rb, rc);
+            gen_faddf(ra, rb, rc, fn11);
             break;
         case 0x01:
             /* SUBF */
-            gen_fsubf(ra, rb, rc);
+            gen_fsubf(ra, rb, rc, fn11);
             break;
         case 0x02:
             /* MULF */
-            gen_fmulf(ra, rb, rc);
+            gen_fmulf(ra, rb, rc, fn11);
             break;
         case 0x03:
             /* DIVF */
-            gen_fdivf(ra, rb, rc);
+            gen_fdivf(ra, rb, rc, fn11);
             break;
         case 0x1E:
             /* CVTDG */
-#if 0 // TODO
-            gen_fcvtdg(rb, rc);
-#else
+            /* TODO */
             goto invalid_opc;
-#endif
-            break;
         case 0x20:
             /* ADDG */
-            gen_faddg(ra, rb, rc);
+            gen_faddg(ra, rb, rc, fn11);
             break;
         case 0x21:
             /* SUBG */
-            gen_fsubg(ra, rb, rc);
+            gen_fsubg(ra, rb, rc, fn11);
             break;
         case 0x22:
             /* MULG */
-            gen_fmulg(ra, rb, rc);
+            gen_fmulg(ra, rb, rc, fn11);
             break;
         case 0x23:
             /* DIVG */
-            gen_fdivg(ra, rb, rc);
+            gen_fdivg(ra, rb, rc, fn11);
             break;
         case 0x25:
             /* CMPGEQ */
@@ -1733,27 +1767,23 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn)
             break;
         case 0x2C:
             /* CVTGF */
-            gen_fcvtgf(rb, rc);
+            gen_fcvtgf(rb, rc, fn11);
             break;
         case 0x2D:
             /* CVTGD */
-#if 0 // TODO
-            gen_fcvtgd(rb, rc);
-#else
+            /* TODO */
             goto invalid_opc;
-#endif
-            break;
         case 0x2F:
             /* CVTGQ */
-            gen_fcvtgq(rb, rc);
+            gen_fcvtgq(rb, rc, fn11);
             break;
         case 0x3C:
             /* CVTQF */
-            gen_fcvtqf(rb, rc);
+            gen_fcvtqf(rb, rc, fn11);
             break;
         case 0x3E:
             /* CVTQG */
-            gen_fcvtqg(rb, rc);
+            gen_fcvtqg(rb, rc, fn11);
             break;
         default:
             goto invalid_opc;
@@ -1761,39 +1791,38 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn)
         break;
     case 0x16:
         /* IEEE floating-point */
-        /* XXX: rounding mode and traps are ignored (!) */
-        switch (fpfn) { /* f11 & 0x3F */
+        switch (fpfn) { /* fn11 & 0x3F */
         case 0x00:
             /* ADDS */
-            gen_fadds(ra, rb, rc);
+            gen_fadds(ra, rb, rc, fn11);
             break;
         case 0x01:
             /* SUBS */
-            gen_fsubs(ra, rb, rc);
+            gen_fsubs(ra, rb, rc, fn11);
             break;
         case 0x02:
             /* MULS */
-            gen_fmuls(ra, rb, rc);
+            gen_fmuls(ra, rb, rc, fn11);
             break;
         case 0x03:
             /* DIVS */
-            gen_fdivs(ra, rb, rc);
+            gen_fdivs(ra, rb, rc, fn11);
             break;
         case 0x20:
             /* ADDT */
-            gen_faddt(ra, rb, rc);
+            gen_faddt(ra, rb, rc, fn11);
             break;
         case 0x21:
             /* SUBT */
-            gen_fsubt(ra, rb, rc);
+            gen_fsubt(ra, rb, rc, fn11);
             break;
         case 0x22:
             /* MULT */
-            gen_fmult(ra, rb, rc);
+            gen_fmult(ra, rb, rc, fn11);
             break;
         case 0x23:
             /* DIVT */
-            gen_fdivt(ra, rb, rc);
+            gen_fdivt(ra, rb, rc, fn11);
             break;
         case 0x24:
             /* CMPTUN */
@@ -1812,26 +1841,25 @@ static inline int translate_one(DisasContext *ctx, uint32_t insn)
             gen_fcmptle(ra, rb, rc);
             break;
         case 0x2C:
-            /* XXX: incorrect */
             if (fn11 == 0x2AC || fn11 == 0x6AC) {
                 /* CVTST */
-                gen_fcvtst(rb, rc);
+                gen_fcvtst(rb, rc, fn11);
             } else {
                 /* CVTTS */
-                gen_fcvtts(rb, rc);
+                gen_fcvtts(rb, rc, fn11);
             }
             break;
         case 0x2F:
             /* CVTTQ */
-            gen_fcvttq(rb, rc);
+            gen_fcvttq(rb, rc, fn11);
             break;
         case 0x3C:
             /* CVTQS */
-            gen_fcvtqs(rb, rc);
+            gen_fcvtqs(rb, rc, fn11);
             break;
         case 0x3E:
             /* CVTQT */
-            gen_fcvtqt(rb, rc);
+            gen_fcvtqt(rb, rc, fn11);
             break;
         default:
             goto invalid_opc;

             reply	other threads:[~2009-12-18 22:09 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20091228201020.GD5695@hall.aurel32.net>
2009-12-18 22:09 ` Richard Henderson [this message]
2010-01-04 22:46   ` [Qemu-devel] [PATCH 0/6] target-alpha: fpu qualifiers, round 2 Richard Henderson
2009-12-31 19:54     ` [Qemu-devel] [PATCH 1/6] target-alpha: Fix gdb access to fpcr and unique Richard Henderson
2009-12-31 20:41     ` [Qemu-devel] [PATCH 2/6] target-alpha: Split up FPCR value into separate fields Richard Henderson
2010-01-04 19:19     ` [Qemu-devel] [PATCH 3/6] target-alpha: Reduce internal processor registers for user-mode Richard Henderson
2010-01-06  9:55       ` Tristan Gingold
2010-01-06 16:29         ` Richard Henderson
2010-01-06 17:04           ` Andreas Färber
2010-01-07 11:54             ` Tristan Gingold
2010-01-07 20:13               ` Andreas Färber
2010-01-04 19:24     ` [Qemu-devel] [PATCH 4/6] target-alpha: Clean up arithmetic traps Richard Henderson
2010-01-04 19:25     ` [Qemu-devel] [PATCH 5/6] target-alpha: Mark helper_excp as NORETURN Richard Henderson
2010-01-04 22:27     ` [Qemu-devel] [PATCH 6/6] target-alpha: Implement IEEE FP qualifiers Richard Henderson
2010-01-26 16:35     ` [Qemu-devel] [PATCH 0/6] target-alpha: fpu qualifiers, round 2 Richard Henderson
2010-02-09 18:47     ` Richard Henderson
2010-02-23 22:58     ` Aurelien Jarno
2010-02-24 11:24       ` Richard Henderson
2010-02-28 16:49         ` Aurelien Jarno

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4B2BFD85.6070702@twiddle.net \
    --to=rth@twiddle.net \
    --cc=laurent.desnogues@gmail.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).