On Fri, Dec 18, 2009 at 02:09:09PM -0800, Richard Henderson wrote:
> This is a squashed version of the 3 or 4 incremental patches that I
> had sent out for implementing the alpha fpu instruction qualifiers.
> 
> 

First of all, this patch has a lot of coding style issues. I have
reported some of them at the beginning of the file, but stopped at some
point.

My main concern about this patch is that I don't really understand why
the current fp exceptions, the current rounding mode or flush_to_zero 
mode are stored in FP_STATUS. I think it would be better to have 
dedicated variable(s) in the cpu state structure, as it is done in other
emulated architectures. 

For example instead of saving the exception, doing a few fp
instructions, and restoring them, it is better to have a separate
variable that holds the current CPU FPU state (which probably already
exists as (part of) a CPU register), always clear the
FP_STATUS.float_exception_flags variable before an instruction or
sequence of instructions, and copy the bits that needs to be copied back
to the variable holding the CPU FPU state.

That would save a lot of mask and shift operation that is currently done
in your patch, and also a lot of save and restore operations when
executing code.

> commit 572164702dd83955fc8783c85811ec86c3fb6e4a
> Author: Richard Henderson <r...@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 <r...@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);

Coding style.

> +
> +    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;

Coding style. Also the name of the variable "mask" is a bit misleading
for true/false variable.

> +    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;

Does it corresponds to the mode describe above as to be implemented?

> +    }
> +    if (old_rm != rm)
> +        set_float_rounding_mode(rm, &FP_STATUS);

Coding style.

> +    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;

What does this constant corresponds to?

> +    }
> +    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);

coding style

> +}
> +
> +static inline void end_fp_flush_to_zero(uint32_t orig)
> +{
> +    if (orig & 0x10000)

What does this constant corresponds to? I guess it matches the previous
one.

> +        set_flush_to_zero(0, &FP_STATUS);

coding style

> +}
> +
> +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;

Coding style.

> +
> +    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);

Coding style.

> +    }
> +
> +    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;


-- 
Aurelien Jarno                          GPG: 1024D/F1BCDB73
aurel...@aurel32.net                 http://www.aurel32.net


Reply via email to