Commit 27e1259a authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/rth/tags/pull-axp-20150521' into staging



Rewrite fp exceptions

# gpg: Signature made Thu May 21 18:35:52 2015 BST using RSA key ID 4DD0279B
# gpg: Good signature from "Richard Henderson <rth7680@gmail.com>"
# gpg:                 aka "Richard Henderson <rth@redhat.com>"
# gpg:                 aka "Richard Henderson <rth@twiddle.net>"

* remotes/rth/tags/pull-axp-20150521:
  target-alpha: Add vector implementation for CMPBGE
  target-alpha: Rewrite helper_zapnot
  target-alpha: Raise IOV from CVTQL
  target-alpha: Suppress underflow from CVTTQ if DNZ
  target-alpha: Raise EXC_M_INV properly for fp inputs
  target-alpha: Disallow literal operand to 1C.30 to 1C.37
  target-alpha: Implement WH64EN
  target-alpha: Fix integer overflow checking insns
  target-alpha: Fix cvttq vs inf
  target-alpha: Fix cvttq vs large integers
  target-alpha: Raise IOV from CVTTQ
  target-alpha: Set EXC_M_SWC for exceptions from /S insns
  target-alpha: Set fpcr_exc_status even for disabled exceptions
  target-alpha: Tidy FPCR representation
  target-alpha: Set PC correctly for floating-point exceptions
  target-alpha: Forget installed round mode after MT_FPCR
  target-alpha: Rename floating-point subroutines
  target-alpha: Move VAX helpers to a new file

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 9e549d36 32ad48ab
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
obj-$(CONFIG_SOFTMMU) += machine.o
obj-y += translate.o helper.o cpu.o
obj-y += int_helper.o fpu_helper.o sys_helper.o mem_helper.o
obj-y += int_helper.o fpu_helper.o vax_helper.o sys_helper.o mem_helper.o
obj-y += gdbstub.o
+47 −48
Original line number Diff line number Diff line
@@ -150,28 +150,28 @@ enum {
    FP_ROUND_DYNAMIC = 0x3,
};

/* FPCR bits */
#define FPCR_SUM		(1ULL << 63)
#define FPCR_INED		(1ULL << 62)
#define FPCR_UNFD		(1ULL << 61)
#define FPCR_UNDZ		(1ULL << 60)
#define FPCR_DYN_SHIFT		58
#define FPCR_DYN_CHOPPED	(0ULL << FPCR_DYN_SHIFT)
#define FPCR_DYN_MINUS		(1ULL << FPCR_DYN_SHIFT)
#define FPCR_DYN_NORMAL		(2ULL << FPCR_DYN_SHIFT)
#define FPCR_DYN_PLUS		(3ULL << FPCR_DYN_SHIFT)
#define FPCR_DYN_MASK		(3ULL << FPCR_DYN_SHIFT)
#define FPCR_IOV		(1ULL << 57)
#define FPCR_INE		(1ULL << 56)
#define FPCR_UNF		(1ULL << 55)
#define FPCR_OVF		(1ULL << 54)
#define FPCR_DZE		(1ULL << 53)
#define FPCR_INV		(1ULL << 52)
#define FPCR_OVFD		(1ULL << 51)
#define FPCR_DZED		(1ULL << 50)
#define FPCR_INVD		(1ULL << 49)
#define FPCR_DNZ		(1ULL << 48)
#define FPCR_DNOD		(1ULL << 47)
/* FPCR bits -- right-shifted 32 so we can use a uint32_t.  */
#define FPCR_SUM                (1U << (63 - 32))
#define FPCR_INED               (1U << (62 - 32))
#define FPCR_UNFD               (1U << (61 - 32))
#define FPCR_UNDZ               (1U << (60 - 32))
#define FPCR_DYN_SHIFT          (58 - 32)
#define FPCR_DYN_CHOPPED        (0U << FPCR_DYN_SHIFT)
#define FPCR_DYN_MINUS          (1U << FPCR_DYN_SHIFT)
#define FPCR_DYN_NORMAL         (2U << FPCR_DYN_SHIFT)
#define FPCR_DYN_PLUS           (3U << FPCR_DYN_SHIFT)
#define FPCR_DYN_MASK           (3U << FPCR_DYN_SHIFT)
#define FPCR_IOV                (1U << (57 - 32))
#define FPCR_INE                (1U << (56 - 32))
#define FPCR_UNF                (1U << (55 - 32))
#define FPCR_OVF                (1U << (54 - 32))
#define FPCR_DZE                (1U << (53 - 32))
#define FPCR_INV                (1U << (52 - 32))
#define FPCR_OVFD               (1U << (51 - 32))
#define FPCR_DZED               (1U << (50 - 32))
#define FPCR_INVD               (1U << (49 - 32))
#define FPCR_DNZ                (1U << (48 - 32))
#define FPCR_DNOD               (1U << (47 - 32))
#define FPCR_STATUS_MASK        (FPCR_IOV | FPCR_INE | FPCR_UNF \
                                 | FPCR_OVF | FPCR_DZE | FPCR_INV)

@@ -179,25 +179,25 @@ enum {
   These are more or less architecturally required, since the real hardware
   has read-as-zero bits in the FPCR when the features aren't implemented.
   For the purposes of QEMU, we pretend the FPCR can hold everything.  */
#define SWCR_TRAP_ENABLE_INV	(1ULL << 1)
#define SWCR_TRAP_ENABLE_DZE	(1ULL << 2)
#define SWCR_TRAP_ENABLE_OVF	(1ULL << 3)
#define SWCR_TRAP_ENABLE_UNF	(1ULL << 4)
#define SWCR_TRAP_ENABLE_INE	(1ULL << 5)
#define SWCR_TRAP_ENABLE_DNO	(1ULL << 6)
#define SWCR_TRAP_ENABLE_MASK	((1ULL << 7) - (1ULL << 1))

#define SWCR_MAP_DMZ		(1ULL << 12)
#define SWCR_MAP_UMZ		(1ULL << 13)
#define SWCR_TRAP_ENABLE_INV    (1U << 1)
#define SWCR_TRAP_ENABLE_DZE    (1U << 2)
#define SWCR_TRAP_ENABLE_OVF    (1U << 3)
#define SWCR_TRAP_ENABLE_UNF    (1U << 4)
#define SWCR_TRAP_ENABLE_INE    (1U << 5)
#define SWCR_TRAP_ENABLE_DNO    (1U << 6)
#define SWCR_TRAP_ENABLE_MASK   ((1U << 7) - (1U << 1))

#define SWCR_MAP_DMZ            (1U << 12)
#define SWCR_MAP_UMZ            (1U << 13)
#define SWCR_MAP_MASK           (SWCR_MAP_DMZ | SWCR_MAP_UMZ)

#define SWCR_STATUS_INV		(1ULL << 17)
#define SWCR_STATUS_DZE		(1ULL << 18)
#define SWCR_STATUS_OVF		(1ULL << 19)
#define SWCR_STATUS_UNF		(1ULL << 20)
#define SWCR_STATUS_INE		(1ULL << 21)
#define SWCR_STATUS_DNO		(1ULL << 22)
#define SWCR_STATUS_MASK	((1ULL << 23) - (1ULL << 17))
#define SWCR_STATUS_INV         (1U << 17)
#define SWCR_STATUS_DZE         (1U << 18)
#define SWCR_STATUS_OVF         (1U << 19)
#define SWCR_STATUS_UNF         (1U << 20)
#define SWCR_STATUS_INE         (1U << 21)
#define SWCR_STATUS_DNO         (1U << 22)
#define SWCR_STATUS_MASK        ((1U << 23) - (1U << 17))

#define SWCR_MASK  (SWCR_TRAP_ENABLE_MASK | SWCR_MAP_MASK | SWCR_STATUS_MASK)

@@ -238,14 +238,13 @@ struct CPUAlphaState {
    uint64_t lock_addr;
    uint64_t lock_st_addr;
    uint64_t lock_value;

    /* The FPCR, and disassembled portions thereof.  */
    uint32_t fpcr;
    uint32_t fpcr_exc_enable;
    float_status fp_status;
    /* The following fields make up the FPCR, but in FP_STATUS format.  */
    uint8_t fpcr_exc_status;
    uint8_t fpcr_exc_mask;
    uint8_t fpcr_dyn_round;
    uint8_t fpcr_flush_to_zero;
    uint8_t fpcr_dnod;
    uint8_t fpcr_undz;

    /* The Internal Processor Registers.  Some of these we assume always
       exist for use in user-mode.  */
+126 −404
Original line number Diff line number Diff line
@@ -34,57 +34,65 @@ void helper_setflushzero(CPUAlphaState *env, uint32_t val)
    set_flush_to_zero(val, &FP_STATUS);
}

void helper_fp_exc_clear(CPUAlphaState *env)
#define CONVERT_BIT(X, SRC, DST) \
    (SRC > DST ? (X) / (SRC / DST) & (DST) : ((X) & SRC) * (DST / SRC))

static uint32_t soft_to_fpcr_exc(CPUAlphaState *env)
{
    uint8_t exc = get_float_exception_flags(&FP_STATUS);
    uint32_t ret = 0;

    if (unlikely(exc)) {
        set_float_exception_flags(0, &FP_STATUS);
        ret |= CONVERT_BIT(exc, float_flag_invalid, FPCR_INV);
        ret |= CONVERT_BIT(exc, float_flag_divbyzero, FPCR_DZE);
        ret |= CONVERT_BIT(exc, float_flag_overflow, FPCR_OVF);
        ret |= CONVERT_BIT(exc, float_flag_underflow, FPCR_UNF);
        ret |= CONVERT_BIT(exc, float_flag_inexact, FPCR_INE);
    }

uint32_t helper_fp_exc_get(CPUAlphaState *env)
{
    return get_float_exception_flags(&FP_STATUS);
    return ret;
}

static inline void inline_fp_exc_raise(CPUAlphaState *env, uintptr_t retaddr,
                                       uint32_t exc, uint32_t regno)
static void fp_exc_raise1(CPUAlphaState *env, uintptr_t retaddr,
                          uint32_t exc, uint32_t regno, uint32_t hw_exc)
{
    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;
        }
    hw_exc |= CONVERT_BIT(exc, FPCR_INV, EXC_M_INV);
    hw_exc |= CONVERT_BIT(exc, FPCR_DZE, EXC_M_DZE);
    hw_exc |= CONVERT_BIT(exc, FPCR_OVF, EXC_M_FOV);
    hw_exc |= CONVERT_BIT(exc, FPCR_UNF, EXC_M_UNF);
    hw_exc |= CONVERT_BIT(exc, FPCR_INE, EXC_M_INE);
    hw_exc |= CONVERT_BIT(exc, FPCR_IOV, EXC_M_IOV);

    arith_excp(env, retaddr, hw_exc, 1ull << regno);
}
}

/* Raise exceptions for ieee fp insns without software completion.
   In that case there are no exceptions that don't trap; the mask
   doesn't apply.  */
void helper_fp_exc_raise(CPUAlphaState *env, uint32_t exc, uint32_t regno)
void helper_fp_exc_raise(CPUAlphaState *env, uint32_t ignore, uint32_t regno)
{
    inline_fp_exc_raise(env, GETPC(), exc, regno);
    uint32_t exc = env->error_code;
    if (exc) {
        env->fpcr |= exc;
        exc &= ~ignore;
        if (exc) {
            fp_exc_raise1(env, GETPC(), exc, regno, 0);
        }
    }
}

/* Raise exceptions for ieee fp insns with software completion.  */
void helper_fp_exc_raise_s(CPUAlphaState *env, uint32_t exc, uint32_t regno)
void helper_fp_exc_raise_s(CPUAlphaState *env, uint32_t ignore, uint32_t regno)
{
    uint32_t exc = env->error_code & ~ignore;
    if (exc) {
        env->fpcr |= exc;
        exc &= ~ignore;
        if (exc) {
        env->fpcr_exc_status |= exc;
        exc &= ~env->fpcr_exc_mask;
        inline_fp_exc_raise(env, GETPC(), exc, regno);
            exc &= env->fpcr_exc_enable;
            fp_exc_raise1(env, GETPC(), exc, regno, EXC_M_SWC);
        }
    }
}

@@ -96,16 +104,14 @@ void helper_ieee_input(CPUAlphaState *env, uint64_t val)
    uint64_t frac = val & 0xfffffffffffffull;

    if (exp == 0) {
        /* Denormals without DNZ set raise an exception.  */
        if (frac != 0 && !env->fp_status.flush_inputs_to_zero) {
            arith_excp(env, GETPC(), EXC_M_UNF, 0);
        /* Denormals without /S raise an exception.  */
        if (frac != 0) {
            arith_excp(env, GETPC(), EXC_M_INV, 0);
        }
    } else if (exp == 0x7ff) {
        /* Infinity or NaN.  */
        /* ??? 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.  */
        arith_excp(env, GETPC(), frac ? EXC_M_INV : EXC_M_FOV, 0);
        env->fpcr |= FPCR_INV;
        arith_excp(env, GETPC(), EXC_M_INV, 0);
    }
}

@@ -116,273 +122,30 @@ void helper_ieee_input_cmp(CPUAlphaState *env, uint64_t val)
    uint64_t frac = val & 0xfffffffffffffull;

    if (exp == 0) {
        /* Denormals without DNZ set raise an exception.  */
        if (frac != 0 && !env->fp_status.flush_inputs_to_zero) {
            arith_excp(env, GETPC(), EXC_M_UNF, 0);
        /* Denormals without /S raise an exception.  */
        if (frac != 0) {
            arith_excp(env, GETPC(), EXC_M_INV, 0);
        }
    } else if (exp == 0x7ff && frac) {
        /* NaN.  */
        env->fpcr |= FPCR_INV;
        arith_excp(env, GETPC(), EXC_M_INV, 0);
    }
}

/* F floating (VAX) */
static uint64_t float32_to_f(float32 fa)
/* Input handing with software completion.  Trap for denorms, unless DNZ
   is set.  If we try to support DNOD (which none of the produced hardware
   did, AFAICS), we'll need to suppress the trap when FPCR.DNOD is set;
   then the code downstream of that will need to cope with denorms sans
   flush_input_to_zero.  Most of it should work sanely, but there's
   nothing to compare with.  */
void helper_ieee_input_s(CPUAlphaState *env, uint64_t val)
{
    uint64_t r, exp, mant, sig;
    CPU_FloatU a;

    a.f = fa;
    sig = ((uint64_t)a.l & 0x80000000) << 32;
    exp = (a.l >> 23) & 0xff;
    mant = ((uint64_t)a.l & 0x007fffff) << 29;

    if (exp == 255) {
        /* NaN or infinity */
        r = 1; /* VAX dirty zero */
    } else if (exp == 0) {
        if (mant == 0) {
            /* Zero */
            r = 0;
        } else {
            /* Denormalized */
            r = sig | ((exp + 1) << 52) | mant;
    if (unlikely(2 * val - 1 < 0x1fffffffffffffull)
        && !env->fp_status.flush_inputs_to_zero) {
        arith_excp(env, GETPC(), EXC_M_INV | EXC_M_SWC, 0);
    }
    } else {
        if (exp >= 253) {
            /* Overflow */
            r = 1; /* VAX dirty zero */
        } else {
            r = sig | ((exp + 2) << 52);
}
    }

    return r;
}

static float32 f_to_float32(CPUAlphaState *env, uintptr_t retaddr, uint64_t a)
{
    uint32_t exp, mant_sig;
    CPU_FloatU r;

    exp = ((a >> 55) & 0x80) | ((a >> 52) & 0x7f);
    mant_sig = ((a >> 32) & 0x80000000) | ((a >> 29) & 0x007fffff);

    if (unlikely(!exp && mant_sig)) {
        /* Reserved operands / Dirty zero */
        dynamic_excp(env, retaddr, EXCP_OPCDEC, 0);
    }

    if (exp < 3) {
        /* Underflow */
        r.l = 0;
    } else {
        r.l = ((exp - 2) << 23) | mant_sig;
    }

    return r.f;
}

uint32_t helper_f_to_memory(uint64_t a)
{
    uint32_t r;
    r =  (a & 0x00001fffe0000000ull) >> 13;
    r |= (a & 0x07ffe00000000000ull) >> 45;
    r |= (a & 0xc000000000000000ull) >> 48;
    return r;
}

uint64_t helper_memory_to_f(uint32_t a)
{
    uint64_t r;
    r =  ((uint64_t)(a & 0x0000c000)) << 48;
    r |= ((uint64_t)(a & 0x003fffff)) << 45;
    r |= ((uint64_t)(a & 0xffff0000)) << 13;
    if (!(a & 0x00004000)) {
        r |= 0x7ll << 59;
    }
    return r;
}

/* ??? Emulating VAX arithmetic with IEEE arithmetic is wrong.  We should
   either implement VAX arithmetic properly or just signal invalid opcode.  */

uint64_t helper_addf(CPUAlphaState *env, uint64_t a, uint64_t b)
{
    float32 fa, fb, fr;

    fa = f_to_float32(env, GETPC(), a);
    fb = f_to_float32(env, GETPC(), b);
    fr = float32_add(fa, fb, &FP_STATUS);
    return float32_to_f(fr);
}

uint64_t helper_subf(CPUAlphaState *env, uint64_t a, uint64_t b)
{
    float32 fa, fb, fr;

    fa = f_to_float32(env, GETPC(), a);
    fb = f_to_float32(env, GETPC(), b);
    fr = float32_sub(fa, fb, &FP_STATUS);
    return float32_to_f(fr);
}

uint64_t helper_mulf(CPUAlphaState *env, uint64_t a, uint64_t b)
{
    float32 fa, fb, fr;

    fa = f_to_float32(env, GETPC(), a);
    fb = f_to_float32(env, GETPC(), b);
    fr = float32_mul(fa, fb, &FP_STATUS);
    return float32_to_f(fr);
}

uint64_t helper_divf(CPUAlphaState *env, uint64_t a, uint64_t b)
{
    float32 fa, fb, fr;

    fa = f_to_float32(env, GETPC(), a);
    fb = f_to_float32(env, GETPC(), b);
    fr = float32_div(fa, fb, &FP_STATUS);
    return float32_to_f(fr);
}

uint64_t helper_sqrtf(CPUAlphaState *env, uint64_t t)
{
    float32 ft, fr;

    ft = f_to_float32(env, GETPC(), t);
    fr = float32_sqrt(ft, &FP_STATUS);
    return float32_to_f(fr);
}


/* G floating (VAX) */
static uint64_t float64_to_g(float64 fa)
{
    uint64_t r, exp, mant, sig;
    CPU_DoubleU a;

    a.d = fa;
    sig = a.ll & 0x8000000000000000ull;
    exp = (a.ll >> 52) & 0x7ff;
    mant = a.ll & 0x000fffffffffffffull;

    if (exp == 2047) {
        /* NaN or infinity */
        r = 1; /* VAX dirty zero */
    } else if (exp == 0) {
        if (mant == 0) {
            /* Zero */
            r = 0;
        } else {
            /* Denormalized */
            r = sig | ((exp + 1) << 52) | mant;
        }
    } else {
        if (exp >= 2045) {
            /* Overflow */
            r = 1; /* VAX dirty zero */
        } else {
            r = sig | ((exp + 2) << 52);
        }
    }

    return r;
}

static float64 g_to_float64(CPUAlphaState *env, uintptr_t retaddr, uint64_t a)
{
    uint64_t exp, mant_sig;
    CPU_DoubleU r;

    exp = (a >> 52) & 0x7ff;
    mant_sig = a & 0x800fffffffffffffull;

    if (!exp && mant_sig) {
        /* Reserved operands / Dirty zero */
        dynamic_excp(env, retaddr, EXCP_OPCDEC, 0);
    }

    if (exp < 3) {
        /* Underflow */
        r.ll = 0;
    } else {
        r.ll = ((exp - 2) << 52) | mant_sig;
    }

    return r.d;
}

uint64_t helper_g_to_memory(uint64_t a)
{
    uint64_t r;
    r =  (a & 0x000000000000ffffull) << 48;
    r |= (a & 0x00000000ffff0000ull) << 16;
    r |= (a & 0x0000ffff00000000ull) >> 16;
    r |= (a & 0xffff000000000000ull) >> 48;
    return r;
}

uint64_t helper_memory_to_g(uint64_t a)
{
    uint64_t r;
    r =  (a & 0x000000000000ffffull) << 48;
    r |= (a & 0x00000000ffff0000ull) << 16;
    r |= (a & 0x0000ffff00000000ull) >> 16;
    r |= (a & 0xffff000000000000ull) >> 48;
    return r;
}

uint64_t helper_addg(CPUAlphaState *env, uint64_t a, uint64_t b)
{
    float64 fa, fb, fr;

    fa = g_to_float64(env, GETPC(), a);
    fb = g_to_float64(env, GETPC(), b);
    fr = float64_add(fa, fb, &FP_STATUS);
    return float64_to_g(fr);
}

uint64_t helper_subg(CPUAlphaState *env, uint64_t a, uint64_t b)
{
    float64 fa, fb, fr;

    fa = g_to_float64(env, GETPC(), a);
    fb = g_to_float64(env, GETPC(), b);
    fr = float64_sub(fa, fb, &FP_STATUS);
    return float64_to_g(fr);
}

uint64_t helper_mulg(CPUAlphaState *env, uint64_t a, uint64_t b)
{
    float64 fa, fb, fr;

    fa = g_to_float64(env, GETPC(), a);
    fb = g_to_float64(env, GETPC(), b);
    fr = float64_mul(fa, fb, &FP_STATUS);
    return float64_to_g(fr);
}

uint64_t helper_divg(CPUAlphaState *env, uint64_t a, uint64_t b)
{
    float64 fa, fb, fr;

    fa = g_to_float64(env, GETPC(), a);
    fb = g_to_float64(env, GETPC(), b);
    fr = float64_div(fa, fb, &FP_STATUS);
    return float64_to_g(fr);
}

uint64_t helper_sqrtg(CPUAlphaState *env, uint64_t a)
{
    float64 fa, fr;

    fa = g_to_float64(env, GETPC(), a);
    fr = float64_sqrt(fa, &FP_STATUS);
    return float64_to_g(fr);
}


/* S floating (single) */

@@ -447,6 +210,8 @@ uint64_t helper_adds(CPUAlphaState *env, uint64_t a, uint64_t b)
    fa = s_to_float32(a);
    fb = s_to_float32(b);
    fr = float32_add(fa, fb, &FP_STATUS);
    env->error_code = soft_to_fpcr_exc(env);

    return float32_to_s(fr);
}

@@ -457,6 +222,8 @@ uint64_t helper_subs(CPUAlphaState *env, uint64_t a, uint64_t b)
    fa = s_to_float32(a);
    fb = s_to_float32(b);
    fr = float32_sub(fa, fb, &FP_STATUS);
    env->error_code = soft_to_fpcr_exc(env);

    return float32_to_s(fr);
}

@@ -467,6 +234,8 @@ uint64_t helper_muls(CPUAlphaState *env, uint64_t a, uint64_t b)
    fa = s_to_float32(a);
    fb = s_to_float32(b);
    fr = float32_mul(fa, fb, &FP_STATUS);
    env->error_code = soft_to_fpcr_exc(env);

    return float32_to_s(fr);
}

@@ -477,6 +246,8 @@ uint64_t helper_divs(CPUAlphaState *env, uint64_t a, uint64_t b)
    fa = s_to_float32(a);
    fb = s_to_float32(b);
    fr = float32_div(fa, fb, &FP_STATUS);
    env->error_code = soft_to_fpcr_exc(env);

    return float32_to_s(fr);
}

@@ -486,6 +257,8 @@ uint64_t helper_sqrts(CPUAlphaState *env, uint64_t a)

    fa = s_to_float32(a);
    fr = float32_sqrt(fa, &FP_STATUS);
    env->error_code = soft_to_fpcr_exc(env);

    return float32_to_s(fr);
}

@@ -514,6 +287,8 @@ uint64_t helper_addt(CPUAlphaState *env, uint64_t a, uint64_t b)
    fa = t_to_float64(a);
    fb = t_to_float64(b);
    fr = float64_add(fa, fb, &FP_STATUS);
    env->error_code = soft_to_fpcr_exc(env);

    return float64_to_t(fr);
}

@@ -524,6 +299,8 @@ uint64_t helper_subt(CPUAlphaState *env, uint64_t a, uint64_t b)
    fa = t_to_float64(a);
    fb = t_to_float64(b);
    fr = float64_sub(fa, fb, &FP_STATUS);
    env->error_code = soft_to_fpcr_exc(env);

    return float64_to_t(fr);
}

@@ -534,6 +311,8 @@ uint64_t helper_mult(CPUAlphaState *env, uint64_t a, uint64_t b)
    fa = t_to_float64(a);
    fb = t_to_float64(b);
    fr = float64_mul(fa, fb, &FP_STATUS);
    env->error_code = soft_to_fpcr_exc(env);

    return float64_to_t(fr);
}

@@ -544,6 +323,8 @@ uint64_t helper_divt(CPUAlphaState *env, uint64_t a, uint64_t b)
    fa = t_to_float64(a);
    fb = t_to_float64(b);
    fr = float64_div(fa, fb, &FP_STATUS);
    env->error_code = soft_to_fpcr_exc(env);

    return float64_to_t(fr);
}

@@ -553,6 +334,8 @@ uint64_t helper_sqrtt(CPUAlphaState *env, uint64_t a)

    fa = t_to_float64(a);
    fr = float64_sqrt(fa, &FP_STATUS);
    env->error_code = soft_to_fpcr_exc(env);

    return float64_to_t(fr);
}

@@ -560,99 +343,65 @@ uint64_t helper_sqrtt(CPUAlphaState *env, uint64_t a)
uint64_t helper_cmptun(CPUAlphaState *env, uint64_t a, uint64_t b)
{
    float64 fa, fb;
    uint64_t ret = 0;

    fa = t_to_float64(a);
    fb = t_to_float64(b);

    if (float64_unordered_quiet(fa, fb, &FP_STATUS)) {
        return 0x4000000000000000ULL;
    } else {
        return 0;
        ret = 0x4000000000000000ULL;
    }
    env->error_code = soft_to_fpcr_exc(env);

    return ret;
}

uint64_t helper_cmpteq(CPUAlphaState *env, uint64_t a, uint64_t b)
{
    float64 fa, fb;
    uint64_t ret = 0;

    fa = t_to_float64(a);
    fb = t_to_float64(b);

    if (float64_eq_quiet(fa, fb, &FP_STATUS)) {
        return 0x4000000000000000ULL;
    } else {
        return 0;
        ret = 0x4000000000000000ULL;
    }
    env->error_code = soft_to_fpcr_exc(env);

    return ret;
}

uint64_t helper_cmptle(CPUAlphaState *env, uint64_t a, uint64_t b)
{
    float64 fa, fb;
    uint64_t ret = 0;

    fa = t_to_float64(a);
    fb = t_to_float64(b);

    if (float64_le(fa, fb, &FP_STATUS)) {
        return 0x4000000000000000ULL;
    } else {
        return 0;
        ret = 0x4000000000000000ULL;
    }
    env->error_code = soft_to_fpcr_exc(env);

    return ret;
}

uint64_t helper_cmptlt(CPUAlphaState *env, uint64_t a, uint64_t b)
{
    float64 fa, fb;
    uint64_t ret = 0;

    fa = t_to_float64(a);
    fb = t_to_float64(b);

    if (float64_lt(fa, fb, &FP_STATUS)) {
        return 0x4000000000000000ULL;
    } else {
        return 0;
    }
}

uint64_t helper_cmpgeq(CPUAlphaState *env, uint64_t a, uint64_t b)
{
    float64 fa, fb;

    fa = g_to_float64(env, GETPC(), a);
    fb = g_to_float64(env, GETPC(), b);

    if (float64_eq_quiet(fa, fb, &FP_STATUS)) {
        return 0x4000000000000000ULL;
    } else {
        return 0;
        ret = 0x4000000000000000ULL;
    }
}

uint64_t helper_cmpgle(CPUAlphaState *env, uint64_t a, uint64_t b)
{
    float64 fa, fb;
    env->error_code = soft_to_fpcr_exc(env);

    fa = g_to_float64(env, GETPC(), a);
    fb = g_to_float64(env, GETPC(), b);

    if (float64_le(fa, fb, &FP_STATUS)) {
        return 0x4000000000000000ULL;
    } else {
        return 0;
    }
}

uint64_t helper_cmpglt(CPUAlphaState *env, uint64_t a, uint64_t b)
{
    float64 fa, fb;

    fa = g_to_float64(env, GETPC(), a);
    fb = g_to_float64(env, GETPC(), b);

    if (float64_lt(fa, fb, &FP_STATUS)) {
        return 0x4000000000000000ULL;
    } else {
        return 0;
    }
    return ret;
}

/* Floating point format conversion */
@@ -663,6 +412,8 @@ uint64_t helper_cvtts(CPUAlphaState *env, uint64_t a)

    fa = t_to_float64(a);
    fr = float64_to_float32(fa, &FP_STATUS);
    env->error_code = soft_to_fpcr_exc(env);

    return float32_to_s(fr);
}

@@ -673,23 +424,24 @@ uint64_t helper_cvtst(CPUAlphaState *env, uint64_t a)

    fa = s_to_float32(a);
    fr = float32_to_float64(fa, &FP_STATUS);
    env->error_code = soft_to_fpcr_exc(env);

    return float64_to_t(fr);
}

uint64_t helper_cvtqs(CPUAlphaState *env, uint64_t a)
{
    float32 fr = int64_to_float32(a, &FP_STATUS);
    env->error_code = soft_to_fpcr_exc(env);

    return float32_to_s(fr);
}

/* Implement float64 to uint64 conversion without saturation -- we must
   supply the truncated result.  This behaviour is used by the compiler
   to get unsigned conversion for free with the same instruction.

   The VI flag is set when overflow or inexact exceptions should be raised.  */
   to get unsigned conversion for free with the same instruction.  */

static inline uint64_t inline_cvttq(CPUAlphaState *env, uint64_t a,
                                    int roundmode, int VI)
static uint64_t do_cvttq(CPUAlphaState *env, uint64_t a, int roundmode)
{
    uint64_t frac, ret = 0;
    uint32_t exp, sign, exc = 0;
@@ -700,11 +452,11 @@ static inline uint64_t inline_cvttq(CPUAlphaState *env, uint64_t a,
    frac = a & 0xfffffffffffffull;

    if (exp == 0) {
        if (unlikely(frac != 0)) {
        if (unlikely(frac != 0) && !env->fp_status.flush_inputs_to_zero) {
            goto do_underflow;
        }
    } else if (exp == 0x7ff) {
        exc = (frac ? float_flag_invalid : VI ? float_flag_overflow : 0);
        exc = FPCR_INV;
    } else {
        /* Restore implicit bit.  */
        frac |= 0x10000000000000ull;
@@ -713,11 +465,12 @@ static inline uint64_t inline_cvttq(CPUAlphaState *env, uint64_t a,
        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) {
            if (shift < 64) {
                ret = frac << shift;
                if (VI && (ret >> shift) != frac) {
                    exc = float_flag_overflow;
            }
            /* Check for overflow.  Note the special case of -0x1p63.  */
            if (shift >= 11 && a != 0xC3E0000000000000ull) {
                exc = FPCR_IOV | FPCR_INE;
            }
        } else {
            uint64_t round;
@@ -739,7 +492,7 @@ static inline uint64_t inline_cvttq(CPUAlphaState *env, uint64_t a,
            }

            if (round) {
                exc = (VI ? float_flag_inexact : 0);
                exc = FPCR_INE;
                switch (roundmode) {
                case float_round_nearest_even:
                    if (round == (1ull << 63)) {
@@ -764,66 +517,35 @@ static inline uint64_t inline_cvttq(CPUAlphaState *env, uint64_t a,
            ret = -ret;
        }
    }
    if (unlikely(exc)) {
        float_raise(exc, &FP_STATUS);
    }
    env->error_code = exc;

    return ret;
}

uint64_t helper_cvttq(CPUAlphaState *env, uint64_t a)
{
    return inline_cvttq(env, a, FP_STATUS.float_rounding_mode, 1);
    return do_cvttq(env, a, FP_STATUS.float_rounding_mode);
}

uint64_t helper_cvttq_c(CPUAlphaState *env, uint64_t a)
{
    return inline_cvttq(env, a, float_round_to_zero, 0);
}

uint64_t helper_cvttq_svic(CPUAlphaState *env, uint64_t a)
{
    return inline_cvttq(env, a, float_round_to_zero, 1);
    return do_cvttq(env, a, float_round_to_zero);
}

uint64_t helper_cvtqt(CPUAlphaState *env, uint64_t a)
{
    float64 fr = int64_to_float64(a, &FP_STATUS);
    env->error_code = soft_to_fpcr_exc(env);
    return float64_to_t(fr);
}

uint64_t helper_cvtqf(CPUAlphaState *env, uint64_t a)
{
    float32 fr = int64_to_float32(a, &FP_STATUS);
    return float32_to_f(fr);
}

uint64_t helper_cvtgf(CPUAlphaState *env, uint64_t a)
{
    float64 fa;
    float32 fr;

    fa = g_to_float64(env, GETPC(), a);
    fr = float64_to_float32(fa, &FP_STATUS);
    return float32_to_f(fr);
}

uint64_t helper_cvtgq(CPUAlphaState *env, uint64_t a)
{
    float64 fa = g_to_float64(env, GETPC(), a);
    return float64_to_int64_round_to_zero(fa, &FP_STATUS);
}

uint64_t helper_cvtqg(CPUAlphaState *env, uint64_t a)
{
    float64 fr;
    fr = int64_to_float64(a, &FP_STATUS);
    return float64_to_g(fr);
}

void helper_fcvtql_v_input(CPUAlphaState *env, uint64_t val)
uint64_t helper_cvtql(CPUAlphaState *env, uint64_t val)
{
    uint32_t exc = 0;
    if (val != (int32_t)val) {
        arith_excp(env, GETPC(), EXC_M_IOV, 0);
        exc = FPCR_IOV | FPCR_INE;
    }
    env->error_code = exc;

    return ((val & 0xc0000000) << 32) | ((val & 0x3fffffff) << 29);
}
+23 −109

File changed.

Preview size limit exceeded, changes collapsed.

+4 −10

File changed.

Preview size limit exceeded, changes collapsed.

Loading