Ejemplo n.º 1
0
static float32 propagateFloat32NaN( float32 a, float32 b )
{
    flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
	
    aIsNaN = float32_is_nan( a );
    aIsSignalingNaN = float32_is_signaling_nan( a );
    bIsNaN = float32_is_nan( b );
    bIsSignalingNaN = float32_is_signaling_nan( b );
    a |= 0x00400000;
    b |= 0x00400000;
    if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
    if ( aIsSignalingNaN ) {
        if ( bIsSignalingNaN ) goto returnLargerSignificand;
        return bIsNaN ? b : a;
    }
    else if ( aIsNaN ) {
        if ( bIsSignalingNaN | ! bIsNaN ) return a;
	returnLargerSignificand:
        if ( (bits32) ( a<<1 ) < (bits32) ( b<<1 ) ) return b;
        if ( (bits32) ( b<<1 ) < (bits32) ( a<<1 ) ) return a;
        return ( a < b ) ? a : b;
    }
    else {
        return b;
    }
	
}
Ejemplo n.º 2
0
BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::FCOM_SINGLE_REAL(bxInstruction_c *i)
{
  BX_CPU_THIS_PTR prepareFPU(i);

  int pop_stack = i->nnn() & 1, rc;

  RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
  float32 load_reg = read_virtual_dword(i->seg(), RMAddr(i));

  BX_CPU_THIS_PTR FPU_update_last_instruction(i);

  clear_C1();

  if (IS_TAG_EMPTY(0))
  {
      FPU_exception(FPU_EX_Stack_Underflow);
      setcc(FPU_SW_C0|FPU_SW_C2|FPU_SW_C3);

      if(BX_CPU_THIS_PTR the_i387.is_IA_masked())
      {
          if (pop_stack)
              BX_CPU_THIS_PTR the_i387.FPU_pop();
      }
      BX_NEXT_INSTR(i);
  }

  float_status_t status =
      FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word());

  floatx80 a = BX_READ_FPU_REG(0);

  if (floatx80_is_nan(a) || floatx80_is_unsupported(a) || float32_is_nan(load_reg)) {
    rc = float_relation_unordered;
    float_raise(status, float_flag_invalid);
  }
  else {
    rc = floatx80_compare(a, float32_to_floatx80(load_reg, status), status);
  }
  setcc(status_word_flags_fpu_compare(rc));

  if (! FPU_exception(status.float_exception_flags)) {
     if (pop_stack)
         BX_CPU_THIS_PTR the_i387.FPU_pop();
  }

  BX_NEXT_INSTR(i);
}
Ejemplo n.º 3
0
/* This instruction sets the flags N, Z, C, V in the FPSR. */
static unsigned int PerformComparison(const unsigned int opcode)
{
    FPA11 *fpa11 = GET_FPA11();
    unsigned int Fn = getFn(opcode), Fm = getFm(opcode);
    int e_flag = opcode & 0x400000;    /* 1 if CxFE */
    int n_flag = opcode & 0x200000;    /* 1 if CNxx */
    unsigned int flags = 0;

#ifdef CONFIG_FPE_NWFPE_XP
    floatx80 rFn, rFm;

    /* Check for unordered condition and convert all operands to 80-bit
       format.
       ?? Might be some mileage in avoiding this conversion if possible.
       Eg, if both operands are 32-bit, detect this and do a 32-bit
       comparison (cheaper than an 80-bit one).  */
    switch (fpa11->fType[Fn]) {
    case typeSingle:
        //printk("single.\n");
        if (float32_is_nan(fpa11->fpreg[Fn].fSingle))
            goto unordered;
        rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
        break;

    case typeDouble:
        //printk("double.\n");
        if (float64_is_nan(fpa11->fpreg[Fn].fDouble))
            goto unordered;
        rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
        break;

    case typeExtended:
        //printk("extended.\n");
        if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended))
            goto unordered;
        rFn = fpa11->fpreg[Fn].fExtended;
        break;

    default:
        return 0;
    }

    if (CONSTANT_FM(opcode)) {
        //printk("Fm is a constant: #%d.\n",Fm);
        rFm = getExtendedConstant(Fm);
        if (floatx80_is_nan(rFm))
            goto unordered;
    } else {
        //printk("Fm = r%d which contains a ",Fm);
        switch (fpa11->fType[Fm]) {
        case typeSingle:
            //printk("single.\n");
            if (float32_is_nan(fpa11->fpreg[Fm].fSingle))
                goto unordered;
            rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle);
            break;

        case typeDouble:
            //printk("double.\n");
            if (float64_is_nan(fpa11->fpreg[Fm].fDouble))
                goto unordered;
            rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble);
            break;

        case typeExtended:
            //printk("extended.\n");
            if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended))
                goto unordered;
            rFm = fpa11->fpreg[Fm].fExtended;
            break;

        default:
            return 0;
        }
    }

    if (n_flag)
        rFm.high ^= 0x8000;

    /* test for less than condition */
    if (floatx80_lt(rFn, rFm))
        flags |= CC_NEGATIVE;

    /* test for equal condition */
    if (floatx80_eq(rFn, rFm))
        flags |= CC_ZERO;

    /* test for greater than or equal condition */
    if (floatx80_lt(rFm, rFn))
        flags |= CC_CARRY;

#else
    if (CONSTANT_FM(opcode)) {
        /* Fm is a constant.  Do the comparison in whatever precision
           Fn happens to be stored in.  */
        if (fpa11->fType[Fn] == typeSingle) {
            float32 rFm = getSingleConstant(Fm);
            float32 rFn = fpa11->fpreg[Fn].fSingle;

            if (float32_is_nan(rFn))
                goto unordered;

            if (n_flag)
                rFm ^= 0x80000000;

            /* test for less than condition */
            if (float32_lt_nocheck(rFn, rFm))
                flags |= CC_NEGATIVE;

            /* test for equal condition */
            if (float32_eq_nocheck(rFn, rFm))
                flags |= CC_ZERO;

            /* test for greater than or equal condition */
            if (float32_lt_nocheck(rFm, rFn))
                flags |= CC_CARRY;
        } else {
            float64 rFm = getDoubleConstant(Fm);
            float64 rFn = fpa11->fpreg[Fn].fDouble;

            if (float64_is_nan(rFn))
                goto unordered;

            if (n_flag)
                rFm ^= 0x8000000000000000ULL;

            /* test for less than condition */
            if (float64_lt_nocheck(rFn, rFm))
                flags |= CC_NEGATIVE;

            /* test for equal condition */
            if (float64_eq_nocheck(rFn, rFm))
                flags |= CC_ZERO;

            /* test for greater than or equal condition */
            if (float64_lt_nocheck(rFm, rFn))
                flags |= CC_CARRY;
        }
    } else {
        /* Both operands are in registers.  */
        if (fpa11->fType[Fn] == typeSingle
            && fpa11->fType[Fm] == typeSingle) {
            float32 rFm = fpa11->fpreg[Fm].fSingle;
            float32 rFn = fpa11->fpreg[Fn].fSingle;

            if (float32_is_nan(rFn)
                || float32_is_nan(rFm))
                goto unordered;

            if (n_flag)
                rFm ^= 0x80000000;

            /* test for less than condition */
            if (float32_lt_nocheck(rFn, rFm))
                flags |= CC_NEGATIVE;

            /* test for equal condition */
            if (float32_eq_nocheck(rFn, rFm))
                flags |= CC_ZERO;

            /* test for greater than or equal condition */
            if (float32_lt_nocheck(rFm, rFn))
                flags |= CC_CARRY;
        } else {
            /* Promote 32-bit operand to 64 bits.  */
            float64 rFm, rFn;

            rFm = (fpa11->fType[Fm] == typeSingle) ?
                float32_to_float64(fpa11->fpreg[Fm].fSingle)
                : fpa11->fpreg[Fm].fDouble;

            rFn = (fpa11->fType[Fn] == typeSingle) ?
                float32_to_float64(fpa11->fpreg[Fn].fSingle)
                : fpa11->fpreg[Fn].fDouble;

            if (float64_is_nan(rFn)
                || float64_is_nan(rFm))
                goto unordered;

            if (n_flag)
                rFm ^= 0x8000000000000000ULL;

            /* test for less than condition */
            if (float64_lt_nocheck(rFn, rFm))
                flags |= CC_NEGATIVE;

            /* test for equal condition */
            if (float64_eq_nocheck(rFn, rFm))
                flags |= CC_ZERO;

            /* test for greater than or equal condition */
            if (float64_lt_nocheck(rFm, rFn))
                flags |= CC_CARRY;
        }
    }

#endif

    writeConditionCodes(flags);

    return 1;

      unordered:
    /* ?? The FPA data sheet is pretty vague about this, in particular
       about whether the non-E comparisons can ever raise exceptions.
       This implementation is based on a combination of what it says in
       the data sheet, observation of how the Acorn emulator actually
       behaves (and how programs expect it to) and guesswork.  */
    flags |= CC_OVERFLOW;
    flags &= ~(CC_ZERO | CC_NEGATIVE);

    if (BIT_AC & readFPSR())
        flags |= CC_CARRY;

    if (e_flag)
        float_raise(float_flag_invalid);

    writeConditionCodes(flags);
    return 1;
}