diff options
Diffstat (limited to 'ANDROID_3.4.5/arch/m68k/math-emu/fp_arith.c')
-rw-r--r-- | ANDROID_3.4.5/arch/m68k/math-emu/fp_arith.c | 701 |
1 files changed, 0 insertions, 701 deletions
diff --git a/ANDROID_3.4.5/arch/m68k/math-emu/fp_arith.c b/ANDROID_3.4.5/arch/m68k/math-emu/fp_arith.c deleted file mode 100644 index 08f286db..00000000 --- a/ANDROID_3.4.5/arch/m68k/math-emu/fp_arith.c +++ /dev/null @@ -1,701 +0,0 @@ -/* - - fp_arith.c: floating-point math routines for the Linux-m68k - floating point emulator. - - Copyright (c) 1998-1999 David Huggins-Daines. - - Somewhat based on the AlphaLinux floating point emulator, by David - Mosberger-Tang. - - You may copy, modify, and redistribute this file under the terms of - the GNU General Public License, version 2, or any later version, at - your convenience. - */ - -#include "fp_emu.h" -#include "multi_arith.h" -#include "fp_arith.h" - -const struct fp_ext fp_QNaN = -{ - .exp = 0x7fff, - .mant = { .m64 = ~0 } -}; - -const struct fp_ext fp_Inf = -{ - .exp = 0x7fff, -}; - -/* let's start with the easy ones */ - -struct fp_ext * -fp_fabs(struct fp_ext *dest, struct fp_ext *src) -{ - dprint(PINSTR, "fabs\n"); - - fp_monadic_check(dest, src); - - dest->sign = 0; - - return dest; -} - -struct fp_ext * -fp_fneg(struct fp_ext *dest, struct fp_ext *src) -{ - dprint(PINSTR, "fneg\n"); - - fp_monadic_check(dest, src); - - dest->sign = !dest->sign; - - return dest; -} - -/* Now, the slightly harder ones */ - -/* fp_fadd: Implements the kernel of the FADD, FSADD, FDADD, FSUB, - FDSUB, and FCMP instructions. */ - -struct fp_ext * -fp_fadd(struct fp_ext *dest, struct fp_ext *src) -{ - int diff; - - dprint(PINSTR, "fadd\n"); - - fp_dyadic_check(dest, src); - - if (IS_INF(dest)) { - /* infinity - infinity == NaN */ - if (IS_INF(src) && (src->sign != dest->sign)) - fp_set_nan(dest); - return dest; - } - if (IS_INF(src)) { - fp_copy_ext(dest, src); - return dest; - } - - if (IS_ZERO(dest)) { - if (IS_ZERO(src)) { - if (src->sign != dest->sign) { - if (FPDATA->rnd == FPCR_ROUND_RM) - dest->sign = 1; - else - dest->sign = 0; - } - } else - fp_copy_ext(dest, src); - return dest; - } - - dest->lowmant = src->lowmant = 0; - - if ((diff = dest->exp - src->exp) > 0) - fp_denormalize(src, diff); - else if ((diff = -diff) > 0) - fp_denormalize(dest, diff); - - if (dest->sign == src->sign) { - if (fp_addmant(dest, src)) - if (!fp_addcarry(dest)) - return dest; - } else { - if (dest->mant.m64 < src->mant.m64) { - fp_submant(dest, src, dest); - dest->sign = !dest->sign; - } else - fp_submant(dest, dest, src); - } - - return dest; -} - -/* fp_fsub: Implements the kernel of the FSUB, FSSUB, and FDSUB - instructions. - - Remember that the arguments are in assembler-syntax order! */ - -struct fp_ext * -fp_fsub(struct fp_ext *dest, struct fp_ext *src) -{ - dprint(PINSTR, "fsub "); - - src->sign = !src->sign; - return fp_fadd(dest, src); -} - - -struct fp_ext * -fp_fcmp(struct fp_ext *dest, struct fp_ext *src) -{ - dprint(PINSTR, "fcmp "); - - FPDATA->temp[1] = *dest; - src->sign = !src->sign; - return fp_fadd(&FPDATA->temp[1], src); -} - -struct fp_ext * -fp_ftst(struct fp_ext *dest, struct fp_ext *src) -{ - dprint(PINSTR, "ftst\n"); - - (void)dest; - - return src; -} - -struct fp_ext * -fp_fmul(struct fp_ext *dest, struct fp_ext *src) -{ - union fp_mant128 temp; - int exp; - - dprint(PINSTR, "fmul\n"); - - fp_dyadic_check(dest, src); - - /* calculate the correct sign now, as it's necessary for infinities */ - dest->sign = src->sign ^ dest->sign; - - /* Handle infinities */ - if (IS_INF(dest)) { - if (IS_ZERO(src)) - fp_set_nan(dest); - return dest; - } - if (IS_INF(src)) { - if (IS_ZERO(dest)) - fp_set_nan(dest); - else - fp_copy_ext(dest, src); - return dest; - } - - /* Of course, as we all know, zero * anything = zero. You may - not have known that it might be a positive or negative - zero... */ - if (IS_ZERO(dest) || IS_ZERO(src)) { - dest->exp = 0; - dest->mant.m64 = 0; - dest->lowmant = 0; - - return dest; - } - - exp = dest->exp + src->exp - 0x3ffe; - - /* shift up the mantissa for denormalized numbers, - so that the highest bit is set, this makes the - shift of the result below easier */ - if ((long)dest->mant.m32[0] >= 0) - exp -= fp_overnormalize(dest); - if ((long)src->mant.m32[0] >= 0) - exp -= fp_overnormalize(src); - - /* now, do a 64-bit multiply with expansion */ - fp_multiplymant(&temp, dest, src); - - /* normalize it back to 64 bits and stuff it back into the - destination struct */ - if ((long)temp.m32[0] > 0) { - exp--; - fp_putmant128(dest, &temp, 1); - } else - fp_putmant128(dest, &temp, 0); - - if (exp >= 0x7fff) { - fp_set_ovrflw(dest); - return dest; - } - dest->exp = exp; - if (exp < 0) { - fp_set_sr(FPSR_EXC_UNFL); - fp_denormalize(dest, -exp); - } - - return dest; -} - -/* fp_fdiv: Implements the "kernel" of the FDIV, FSDIV, FDDIV and - FSGLDIV instructions. - - Note that the order of the operands is counter-intuitive: instead - of src / dest, the result is actually dest / src. */ - -struct fp_ext * -fp_fdiv(struct fp_ext *dest, struct fp_ext *src) -{ - union fp_mant128 temp; - int exp; - - dprint(PINSTR, "fdiv\n"); - - fp_dyadic_check(dest, src); - - /* calculate the correct sign now, as it's necessary for infinities */ - dest->sign = src->sign ^ dest->sign; - - /* Handle infinities */ - if (IS_INF(dest)) { - /* infinity / infinity = NaN (quiet, as always) */ - if (IS_INF(src)) - fp_set_nan(dest); - /* infinity / anything else = infinity (with approprate sign) */ - return dest; - } - if (IS_INF(src)) { - /* anything / infinity = zero (with appropriate sign) */ - dest->exp = 0; - dest->mant.m64 = 0; - dest->lowmant = 0; - - return dest; - } - - /* zeroes */ - if (IS_ZERO(dest)) { - /* zero / zero = NaN */ - if (IS_ZERO(src)) - fp_set_nan(dest); - /* zero / anything else = zero */ - return dest; - } - if (IS_ZERO(src)) { - /* anything / zero = infinity (with appropriate sign) */ - fp_set_sr(FPSR_EXC_DZ); - dest->exp = 0x7fff; - dest->mant.m64 = 0; - - return dest; - } - - exp = dest->exp - src->exp + 0x3fff; - - /* shift up the mantissa for denormalized numbers, - so that the highest bit is set, this makes lots - of things below easier */ - if ((long)dest->mant.m32[0] >= 0) - exp -= fp_overnormalize(dest); - if ((long)src->mant.m32[0] >= 0) - exp -= fp_overnormalize(src); - - /* now, do the 64-bit divide */ - fp_dividemant(&temp, dest, src); - - /* normalize it back to 64 bits and stuff it back into the - destination struct */ - if (!temp.m32[0]) { - exp--; - fp_putmant128(dest, &temp, 32); - } else - fp_putmant128(dest, &temp, 31); - - if (exp >= 0x7fff) { - fp_set_ovrflw(dest); - return dest; - } - dest->exp = exp; - if (exp < 0) { - fp_set_sr(FPSR_EXC_UNFL); - fp_denormalize(dest, -exp); - } - - return dest; -} - -struct fp_ext * -fp_fsglmul(struct fp_ext *dest, struct fp_ext *src) -{ - int exp; - - dprint(PINSTR, "fsglmul\n"); - - fp_dyadic_check(dest, src); - - /* calculate the correct sign now, as it's necessary for infinities */ - dest->sign = src->sign ^ dest->sign; - - /* Handle infinities */ - if (IS_INF(dest)) { - if (IS_ZERO(src)) - fp_set_nan(dest); - return dest; - } - if (IS_INF(src)) { - if (IS_ZERO(dest)) - fp_set_nan(dest); - else - fp_copy_ext(dest, src); - return dest; - } - - /* Of course, as we all know, zero * anything = zero. You may - not have known that it might be a positive or negative - zero... */ - if (IS_ZERO(dest) || IS_ZERO(src)) { - dest->exp = 0; - dest->mant.m64 = 0; - dest->lowmant = 0; - - return dest; - } - - exp = dest->exp + src->exp - 0x3ffe; - - /* do a 32-bit multiply */ - fp_mul64(dest->mant.m32[0], dest->mant.m32[1], - dest->mant.m32[0] & 0xffffff00, - src->mant.m32[0] & 0xffffff00); - - if (exp >= 0x7fff) { - fp_set_ovrflw(dest); - return dest; - } - dest->exp = exp; - if (exp < 0) { - fp_set_sr(FPSR_EXC_UNFL); - fp_denormalize(dest, -exp); - } - - return dest; -} - -struct fp_ext * -fp_fsgldiv(struct fp_ext *dest, struct fp_ext *src) -{ - int exp; - unsigned long quot, rem; - - dprint(PINSTR, "fsgldiv\n"); - - fp_dyadic_check(dest, src); - - /* calculate the correct sign now, as it's necessary for infinities */ - dest->sign = src->sign ^ dest->sign; - - /* Handle infinities */ - if (IS_INF(dest)) { - /* infinity / infinity = NaN (quiet, as always) */ - if (IS_INF(src)) - fp_set_nan(dest); - /* infinity / anything else = infinity (with approprate sign) */ - return dest; - } - if (IS_INF(src)) { - /* anything / infinity = zero (with appropriate sign) */ - dest->exp = 0; - dest->mant.m64 = 0; - dest->lowmant = 0; - - return dest; - } - - /* zeroes */ - if (IS_ZERO(dest)) { - /* zero / zero = NaN */ - if (IS_ZERO(src)) - fp_set_nan(dest); - /* zero / anything else = zero */ - return dest; - } - if (IS_ZERO(src)) { - /* anything / zero = infinity (with appropriate sign) */ - fp_set_sr(FPSR_EXC_DZ); - dest->exp = 0x7fff; - dest->mant.m64 = 0; - - return dest; - } - - exp = dest->exp - src->exp + 0x3fff; - - dest->mant.m32[0] &= 0xffffff00; - src->mant.m32[0] &= 0xffffff00; - - /* do the 32-bit divide */ - if (dest->mant.m32[0] >= src->mant.m32[0]) { - fp_sub64(dest->mant, src->mant); - fp_div64(quot, rem, dest->mant.m32[0], 0, src->mant.m32[0]); - dest->mant.m32[0] = 0x80000000 | (quot >> 1); - dest->mant.m32[1] = (quot & 1) | rem; /* only for rounding */ - } else { - fp_div64(quot, rem, dest->mant.m32[0], 0, src->mant.m32[0]); - dest->mant.m32[0] = quot; - dest->mant.m32[1] = rem; /* only for rounding */ - exp--; - } - - if (exp >= 0x7fff) { - fp_set_ovrflw(dest); - return dest; - } - dest->exp = exp; - if (exp < 0) { - fp_set_sr(FPSR_EXC_UNFL); - fp_denormalize(dest, -exp); - } - - return dest; -} - -/* fp_roundint: Internal rounding function for use by several of these - emulated instructions. - - This one rounds off the fractional part using the rounding mode - specified. */ - -static void fp_roundint(struct fp_ext *dest, int mode) -{ - union fp_mant64 oldmant; - unsigned long mask; - - if (!fp_normalize_ext(dest)) - return; - - /* infinities and zeroes */ - if (IS_INF(dest) || IS_ZERO(dest)) - return; - - /* first truncate the lower bits */ - oldmant = dest->mant; - switch (dest->exp) { - case 0 ... 0x3ffe: - dest->mant.m64 = 0; - break; - case 0x3fff ... 0x401e: - dest->mant.m32[0] &= 0xffffffffU << (0x401e - dest->exp); - dest->mant.m32[1] = 0; - if (oldmant.m64 == dest->mant.m64) - return; - break; - case 0x401f ... 0x403e: - dest->mant.m32[1] &= 0xffffffffU << (0x403e - dest->exp); - if (oldmant.m32[1] == dest->mant.m32[1]) - return; - break; - default: - return; - } - fp_set_sr(FPSR_EXC_INEX2); - - /* We might want to normalize upwards here... however, since - we know that this is only called on the output of fp_fdiv, - or with the input to fp_fint or fp_fintrz, and the inputs - to all these functions are either normal or denormalized - (no subnormals allowed!), there's really no need. - - In the case of fp_fdiv, observe that 0x80000000 / 0xffff = - 0xffff8000, and the same holds for 128-bit / 64-bit. (i.e. the - smallest possible normal dividend and the largest possible normal - divisor will still produce a normal quotient, therefore, (normal - << 64) / normal is normal in all cases) */ - - switch (mode) { - case FPCR_ROUND_RN: - switch (dest->exp) { - case 0 ... 0x3ffd: - return; - case 0x3ffe: - /* As noted above, the input is always normal, so the - guard bit (bit 63) is always set. therefore, the - only case in which we will NOT round to 1.0 is when - the input is exactly 0.5. */ - if (oldmant.m64 == (1ULL << 63)) - return; - break; - case 0x3fff ... 0x401d: - mask = 1 << (0x401d - dest->exp); - if (!(oldmant.m32[0] & mask)) - return; - if (oldmant.m32[0] & (mask << 1)) - break; - if (!(oldmant.m32[0] << (dest->exp - 0x3ffd)) && - !oldmant.m32[1]) - return; - break; - case 0x401e: - if (!(oldmant.m32[1] >= 0)) - return; - if (oldmant.m32[0] & 1) - break; - if (!(oldmant.m32[1] << 1)) - return; - break; - case 0x401f ... 0x403d: - mask = 1 << (0x403d - dest->exp); - if (!(oldmant.m32[1] & mask)) - return; - if (oldmant.m32[1] & (mask << 1)) - break; - if (!(oldmant.m32[1] << (dest->exp - 0x401d))) - return; - break; - default: - return; - } - break; - case FPCR_ROUND_RZ: - return; - default: - if (dest->sign ^ (mode - FPCR_ROUND_RM)) - break; - return; - } - - switch (dest->exp) { - case 0 ... 0x3ffe: - dest->exp = 0x3fff; - dest->mant.m64 = 1ULL << 63; - break; - case 0x3fff ... 0x401e: - mask = 1 << (0x401e - dest->exp); - if (dest->mant.m32[0] += mask) - break; - dest->mant.m32[0] = 0x80000000; - dest->exp++; - break; - case 0x401f ... 0x403e: - mask = 1 << (0x403e - dest->exp); - if (dest->mant.m32[1] += mask) - break; - if (dest->mant.m32[0] += 1) - break; - dest->mant.m32[0] = 0x80000000; - dest->exp++; - break; - } -} - -/* modrem_kernel: Implementation of the FREM and FMOD instructions - (which are exactly the same, except for the rounding used on the - intermediate value) */ - -static struct fp_ext * -modrem_kernel(struct fp_ext *dest, struct fp_ext *src, int mode) -{ - struct fp_ext tmp; - - fp_dyadic_check(dest, src); - - /* Infinities and zeros */ - if (IS_INF(dest) || IS_ZERO(src)) { - fp_set_nan(dest); - return dest; - } - if (IS_ZERO(dest) || IS_INF(src)) - return dest; - - /* FIXME: there is almost certainly a smarter way to do this */ - fp_copy_ext(&tmp, dest); - fp_fdiv(&tmp, src); /* NOTE: src might be modified */ - fp_roundint(&tmp, mode); - fp_fmul(&tmp, src); - fp_fsub(dest, &tmp); - - /* set the quotient byte */ - fp_set_quotient((dest->mant.m64 & 0x7f) | (dest->sign << 7)); - return dest; -} - -/* fp_fmod: Implements the kernel of the FMOD instruction. - - Again, the argument order is backwards. The result, as defined in - the Motorola manuals, is: - - fmod(src,dest) = (dest - (src * floor(dest / src))) */ - -struct fp_ext * -fp_fmod(struct fp_ext *dest, struct fp_ext *src) -{ - dprint(PINSTR, "fmod\n"); - return modrem_kernel(dest, src, FPCR_ROUND_RZ); -} - -/* fp_frem: Implements the kernel of the FREM instruction. - - frem(src,dest) = (dest - (src * round(dest / src))) - */ - -struct fp_ext * -fp_frem(struct fp_ext *dest, struct fp_ext *src) -{ - dprint(PINSTR, "frem\n"); - return modrem_kernel(dest, src, FPCR_ROUND_RN); -} - -struct fp_ext * -fp_fint(struct fp_ext *dest, struct fp_ext *src) -{ - dprint(PINSTR, "fint\n"); - - fp_copy_ext(dest, src); - - fp_roundint(dest, FPDATA->rnd); - - return dest; -} - -struct fp_ext * -fp_fintrz(struct fp_ext *dest, struct fp_ext *src) -{ - dprint(PINSTR, "fintrz\n"); - - fp_copy_ext(dest, src); - - fp_roundint(dest, FPCR_ROUND_RZ); - - return dest; -} - -struct fp_ext * -fp_fscale(struct fp_ext *dest, struct fp_ext *src) -{ - int scale, oldround; - - dprint(PINSTR, "fscale\n"); - - fp_dyadic_check(dest, src); - - /* Infinities */ - if (IS_INF(src)) { - fp_set_nan(dest); - return dest; - } - if (IS_INF(dest)) - return dest; - - /* zeroes */ - if (IS_ZERO(src) || IS_ZERO(dest)) - return dest; - - /* Source exponent out of range */ - if (src->exp >= 0x400c) { - fp_set_ovrflw(dest); - return dest; - } - - /* src must be rounded with round to zero. */ - oldround = FPDATA->rnd; - FPDATA->rnd = FPCR_ROUND_RZ; - scale = fp_conv_ext2long(src); - FPDATA->rnd = oldround; - - /* new exponent */ - scale += dest->exp; - - if (scale >= 0x7fff) { - fp_set_ovrflw(dest); - } else if (scale <= 0) { - fp_set_sr(FPSR_EXC_UNFL); - fp_denormalize(dest, -scale); - } else - dest->exp = scale; - - return dest; -} - |