Exemplo n.º 1
0
unsigned int EmulateCPRT(const unsigned int opcode)
{

    if (opcode & 0x800000) {
        /* This is some variant of a comparison (PerformComparison
           will sort out which one).  Since most of the other CPRT
           instructions are oddball cases of some sort or other it
           makes sense to pull this out into a fast path.  */
        return PerformComparison(opcode);
    }

    /* Hint to GCC that we'd like a jump table rather than a load of CMPs */
    switch ((opcode & 0x700000) >> 20) {
    case FLT_CODE >> 20:
        return PerformFLT(opcode);
        break;
    case FIX_CODE >> 20:
        return PerformFIX(opcode);
        break;

    case WFS_CODE >> 20:
        writeFPSR(readRegister(getRd(opcode)));
        break;
    case RFS_CODE >> 20:
        writeRegister(getRd(opcode), readFPSR());
        break;

    default:
        return 0;
    }

    return 1;
}
Exemplo n.º 2
0
void float_raise(signed char flags)
{
	register unsigned int fpsr, cumulativeTraps;

#ifdef CONFIG_DEBUG_USER
	printk(KERN_DEBUG
	       "NWFPE: %s[%d] takes exception %08x at %p from %08lx\n",
	       current->comm, current->pid, flags,
	       __builtin_return_address(0), GET_USERREG()[15]);
#endif

	/* Keep SoftFloat exception flags up to date.  */
	float_exception_flags |= flags;

	/* Read fpsr and initialize the cumulativeTraps.  */
	fpsr = readFPSR();
	cumulativeTraps = 0;

	/* For each type of exception, the cumulative trap exception bit is only
	   set if the corresponding trap enable bit is not set.  */
	if ((!(fpsr & BIT_IXE)) && (flags & BIT_IXC))
		cumulativeTraps |= BIT_IXC;
	if ((!(fpsr & BIT_UFE)) && (flags & BIT_UFC))
		cumulativeTraps |= BIT_UFC;
	if ((!(fpsr & BIT_OFE)) && (flags & BIT_OFC))
		cumulativeTraps |= BIT_OFC;
	if ((!(fpsr & BIT_DZE)) && (flags & BIT_DZC))
		cumulativeTraps |= BIT_DZC;
	if ((!(fpsr & BIT_IOE)) && (flags & BIT_IOC))
		cumulativeTraps |= BIT_IOC;

	/* Set the cumulative exceptions flags.  */
	if (cumulativeTraps)
		writeFPSR(fpsr | cumulativeTraps);

	/* Raise an exception if necessary.  */
	if (fpsr & (flags << 16))
		fp_send_sig(SIGFPE, current, 1);
}
Exemplo 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;
}