summaryrefslogtreecommitdiff
path: root/ANDROID_3.4.5/arch/m68k/math-emu/fp_arith.c
diff options
context:
space:
mode:
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.c701
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;
-}
-