mirror of
https://github.com/autc04/Retro68.git
synced 2024-12-03 10:49:58 +00:00
596 lines
12 KiB
C
596 lines
12 KiB
C
|
/* This is a stripped down version of floatlib.c. It supplies only those
|
|||
|
functions which exist in libgcc, but for which there is not assembly
|
|||
|
language versions in m68k/lb1sf68.S.
|
|||
|
|
|||
|
It also includes simplistic support for extended floats (by working in
|
|||
|
double precision). You must compile this file again with -DEXTFLOAT
|
|||
|
to get this support. */
|
|||
|
|
|||
|
/*
|
|||
|
** gnulib support for software floating point.
|
|||
|
** Copyright (C) 1991 by Pipeline Associates, Inc. All rights reserved.
|
|||
|
** Permission is granted to do *anything* you want with this file,
|
|||
|
** commercial or otherwise, provided this message remains intact. So there!
|
|||
|
** I would appreciate receiving any updates/patches/changes that anyone
|
|||
|
** makes, and am willing to be the repository for said changes (am I
|
|||
|
** making a big mistake?).
|
|||
|
**
|
|||
|
** Pat Wood
|
|||
|
** Pipeline Associates, Inc.
|
|||
|
** pipeline!phw@motown.com or
|
|||
|
** sun!pipeline!phw or
|
|||
|
** uunet!motown!pipeline!phw
|
|||
|
**
|
|||
|
** 05/01/91 -- V1.0 -- first release to gcc mailing lists
|
|||
|
** 05/04/91 -- V1.1 -- added float and double prototypes and return values
|
|||
|
** -- fixed problems with adding and subtracting zero
|
|||
|
** -- fixed rounding in truncdfsf2
|
|||
|
** -- fixed SWAP define and tested on 386
|
|||
|
*/
|
|||
|
|
|||
|
/*
|
|||
|
** The following are routines that replace the gnulib soft floating point
|
|||
|
** routines that are called automatically when -msoft-float is selected.
|
|||
|
** The support single and double precision IEEE format, with provisions
|
|||
|
** for byte-swapped machines (tested on 386). Some of the double-precision
|
|||
|
** routines work at full precision, but most of the hard ones simply punt
|
|||
|
** and call the single precision routines, producing a loss of accuracy.
|
|||
|
** long long support is not assumed or included.
|
|||
|
** Overall accuracy is close to IEEE (actually 68882) for single-precision
|
|||
|
** arithmetic. I think there may still be a 1 in 1000 chance of a bit
|
|||
|
** being rounded the wrong way during a multiply. I'm not fussy enough to
|
|||
|
** bother with it, but if anyone is, knock yourself out.
|
|||
|
**
|
|||
|
** Efficiency has only been addressed where it was obvious that something
|
|||
|
** would make a big difference. Anyone who wants to do this right for
|
|||
|
** best speed should go in and rewrite in assembler.
|
|||
|
**
|
|||
|
** I have tested this only on a 68030 workstation and 386/ix integrated
|
|||
|
** in with -msoft-float.
|
|||
|
*/
|
|||
|
|
|||
|
/* the following deal with IEEE single-precision numbers */
|
|||
|
#define EXCESS 126L
|
|||
|
#define SIGNBIT 0x80000000L
|
|||
|
#define HIDDEN (1L << 23L)
|
|||
|
#define SIGN(fp) ((fp) & SIGNBIT)
|
|||
|
#define EXP(fp) (((fp) >> 23L) & 0xFF)
|
|||
|
#define MANT(fp) (((fp) & 0x7FFFFFL) | HIDDEN)
|
|||
|
#define PACK(s,e,m) ((s) | ((e) << 23L) | (m))
|
|||
|
|
|||
|
/* the following deal with IEEE double-precision numbers */
|
|||
|
#define EXCESSD 1022L
|
|||
|
#define HIDDEND (1L << 20L)
|
|||
|
#define EXPDBITS 11
|
|||
|
#define EXPDMASK 0x7FFL
|
|||
|
#define EXPD(fp) (((fp.l.upper) >> 20L) & 0x7FFL)
|
|||
|
#define SIGND(fp) ((fp.l.upper) & SIGNBIT)
|
|||
|
#define MANTD(fp) (((((fp.l.upper) & 0xFFFFF) | HIDDEND) << 10) | \
|
|||
|
(fp.l.lower >> 22))
|
|||
|
#define MANTDMASK 0xFFFFFL /* mask of upper part */
|
|||
|
|
|||
|
/* the following deal with IEEE extended-precision numbers */
|
|||
|
#define EXCESSX 16382L
|
|||
|
#define HIDDENX (1L << 31L)
|
|||
|
#define EXPXBITS 15
|
|||
|
#define EXPXMASK 0x7FFF
|
|||
|
#define EXPX(fp) (((fp.l.upper) >> 16) & EXPXMASK)
|
|||
|
#define SIGNX(fp) ((fp.l.upper) & SIGNBIT)
|
|||
|
#define MANTXMASK 0x7FFFFFFFL /* mask of upper part */
|
|||
|
|
|||
|
union double_long
|
|||
|
{
|
|||
|
double d;
|
|||
|
struct {
|
|||
|
long upper;
|
|||
|
unsigned long lower;
|
|||
|
} l;
|
|||
|
};
|
|||
|
|
|||
|
union float_long {
|
|||
|
float f;
|
|||
|
long l;
|
|||
|
};
|
|||
|
|
|||
|
union long_double_long
|
|||
|
{
|
|||
|
long double ld;
|
|||
|
struct
|
|||
|
{
|
|||
|
long upper;
|
|||
|
unsigned long middle;
|
|||
|
unsigned long lower;
|
|||
|
} l;
|
|||
|
};
|
|||
|
|
|||
|
#ifndef EXTFLOAT
|
|||
|
|
|||
|
int
|
|||
|
__unordsf2(float a, float b)
|
|||
|
{
|
|||
|
union float_long fl;
|
|||
|
|
|||
|
fl.f = a;
|
|||
|
if (EXP(fl.l) == EXP(~0u) && (MANT(fl.l) & ~HIDDEN) != 0)
|
|||
|
return 1;
|
|||
|
fl.f = b;
|
|||
|
if (EXP(fl.l) == EXP(~0u) && (MANT(fl.l) & ~HIDDEN) != 0)
|
|||
|
return 1;
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
int
|
|||
|
__unorddf2(double a, double b)
|
|||
|
{
|
|||
|
union double_long dl;
|
|||
|
|
|||
|
dl.d = a;
|
|||
|
if (EXPD(dl) == EXPDMASK
|
|||
|
&& ((dl.l.upper & MANTDMASK) != 0 || dl.l.lower != 0))
|
|||
|
return 1;
|
|||
|
dl.d = b;
|
|||
|
if (EXPD(dl) == EXPDMASK
|
|||
|
&& ((dl.l.upper & MANTDMASK) != 0 || dl.l.lower != 0))
|
|||
|
return 1;
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
/* convert unsigned int to double */
|
|||
|
double
|
|||
|
__floatunsidf (unsigned long a1)
|
|||
|
{
|
|||
|
long exp = 32 + EXCESSD;
|
|||
|
union double_long dl;
|
|||
|
|
|||
|
if (!a1)
|
|||
|
{
|
|||
|
dl.l.upper = dl.l.lower = 0;
|
|||
|
return dl.d;
|
|||
|
}
|
|||
|
|
|||
|
while (a1 < 0x2000000L)
|
|||
|
{
|
|||
|
a1 <<= 4;
|
|||
|
exp -= 4;
|
|||
|
}
|
|||
|
|
|||
|
while (a1 < 0x80000000L)
|
|||
|
{
|
|||
|
a1 <<= 1;
|
|||
|
exp--;
|
|||
|
}
|
|||
|
|
|||
|
/* pack up and go home */
|
|||
|
dl.l.upper = exp << 20L;
|
|||
|
dl.l.upper |= (a1 >> 11L) & ~HIDDEND;
|
|||
|
dl.l.lower = a1 << 21L;
|
|||
|
|
|||
|
return dl.d;
|
|||
|
}
|
|||
|
|
|||
|
/* convert int to double */
|
|||
|
double
|
|||
|
__floatsidf (long a1)
|
|||
|
{
|
|||
|
long sign = 0, exp = 31 + EXCESSD;
|
|||
|
union double_long dl;
|
|||
|
|
|||
|
if (!a1)
|
|||
|
{
|
|||
|
dl.l.upper = dl.l.lower = 0;
|
|||
|
return dl.d;
|
|||
|
}
|
|||
|
|
|||
|
if (a1 < 0)
|
|||
|
{
|
|||
|
sign = SIGNBIT;
|
|||
|
a1 = (long)-(unsigned long)a1;
|
|||
|
if (a1 < 0)
|
|||
|
{
|
|||
|
dl.l.upper = SIGNBIT | ((32 + EXCESSD) << 20L);
|
|||
|
dl.l.lower = 0;
|
|||
|
return dl.d;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
while (a1 < 0x1000000L)
|
|||
|
{
|
|||
|
a1 <<= 4;
|
|||
|
exp -= 4;
|
|||
|
}
|
|||
|
|
|||
|
while (a1 < 0x40000000L)
|
|||
|
{
|
|||
|
a1 <<= 1;
|
|||
|
exp--;
|
|||
|
}
|
|||
|
|
|||
|
/* pack up and go home */
|
|||
|
dl.l.upper = sign;
|
|||
|
dl.l.upper |= exp << 20L;
|
|||
|
dl.l.upper |= (a1 >> 10L) & ~HIDDEND;
|
|||
|
dl.l.lower = a1 << 22L;
|
|||
|
|
|||
|
return dl.d;
|
|||
|
}
|
|||
|
|
|||
|
/* convert unsigned int to float */
|
|||
|
float
|
|||
|
__floatunsisf (unsigned long l)
|
|||
|
{
|
|||
|
double foo = __floatunsidf (l);
|
|||
|
return foo;
|
|||
|
}
|
|||
|
|
|||
|
/* convert int to float */
|
|||
|
float
|
|||
|
__floatsisf (long l)
|
|||
|
{
|
|||
|
double foo = __floatsidf (l);
|
|||
|
return foo;
|
|||
|
}
|
|||
|
|
|||
|
/* convert float to double */
|
|||
|
double
|
|||
|
__extendsfdf2 (float a1)
|
|||
|
{
|
|||
|
register union float_long fl1;
|
|||
|
register union double_long dl;
|
|||
|
register long exp;
|
|||
|
register long mant;
|
|||
|
|
|||
|
fl1.f = a1;
|
|||
|
|
|||
|
dl.l.upper = SIGN (fl1.l);
|
|||
|
if ((fl1.l & ~SIGNBIT) == 0)
|
|||
|
{
|
|||
|
dl.l.lower = 0;
|
|||
|
return dl.d;
|
|||
|
}
|
|||
|
|
|||
|
exp = EXP(fl1.l);
|
|||
|
mant = MANT (fl1.l) & ~HIDDEN;
|
|||
|
if (exp == 0)
|
|||
|
{
|
|||
|
/* Denormal. */
|
|||
|
exp = 1;
|
|||
|
while (!(mant & HIDDEN))
|
|||
|
{
|
|||
|
mant <<= 1;
|
|||
|
exp--;
|
|||
|
}
|
|||
|
mant &= ~HIDDEN;
|
|||
|
}
|
|||
|
exp = exp - EXCESS + EXCESSD;
|
|||
|
dl.l.upper |= exp << 20;
|
|||
|
dl.l.upper |= mant >> 3;
|
|||
|
dl.l.lower = mant << 29;
|
|||
|
|
|||
|
return dl.d;
|
|||
|
}
|
|||
|
|
|||
|
/* convert double to float */
|
|||
|
float
|
|||
|
__truncdfsf2 (double a1)
|
|||
|
{
|
|||
|
register long exp;
|
|||
|
register long mant;
|
|||
|
register union float_long fl;
|
|||
|
register union double_long dl1;
|
|||
|
int sticky;
|
|||
|
int shift;
|
|||
|
|
|||
|
dl1.d = a1;
|
|||
|
|
|||
|
if ((dl1.l.upper & ~SIGNBIT) == 0 && !dl1.l.lower)
|
|||
|
{
|
|||
|
fl.l = SIGND(dl1);
|
|||
|
return fl.f;
|
|||
|
}
|
|||
|
|
|||
|
exp = EXPD (dl1) - EXCESSD + EXCESS;
|
|||
|
|
|||
|
sticky = dl1.l.lower & ((1 << 22) - 1);
|
|||
|
mant = MANTD (dl1);
|
|||
|
/* shift double mantissa 6 bits so we can round */
|
|||
|
sticky |= mant & ((1 << 6) - 1);
|
|||
|
mant >>= 6;
|
|||
|
|
|||
|
/* Check for underflow and denormals. */
|
|||
|
if (exp <= 0)
|
|||
|
{
|
|||
|
if (exp < -24)
|
|||
|
{
|
|||
|
sticky |= mant;
|
|||
|
mant = 0;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
sticky |= mant & ((1 << (1 - exp)) - 1);
|
|||
|
mant >>= 1 - exp;
|
|||
|
}
|
|||
|
exp = 0;
|
|||
|
}
|
|||
|
|
|||
|
/* now round */
|
|||
|
shift = 1;
|
|||
|
if ((mant & 1) && (sticky || (mant & 2)))
|
|||
|
{
|
|||
|
int rounding = exp ? 2 : 1;
|
|||
|
|
|||
|
mant += 1;
|
|||
|
|
|||
|
/* did the round overflow? */
|
|||
|
if (mant >= (HIDDEN << rounding))
|
|||
|
{
|
|||
|
exp++;
|
|||
|
shift = rounding;
|
|||
|
}
|
|||
|
}
|
|||
|
/* shift down */
|
|||
|
mant >>= shift;
|
|||
|
|
|||
|
mant &= ~HIDDEN;
|
|||
|
|
|||
|
/* pack up and go home */
|
|||
|
fl.l = PACK (SIGND (dl1), exp, mant);
|
|||
|
return (fl.f);
|
|||
|
}
|
|||
|
|
|||
|
/* convert double to int */
|
|||
|
long
|
|||
|
__fixdfsi (double a1)
|
|||
|
{
|
|||
|
register union double_long dl1;
|
|||
|
register long exp;
|
|||
|
register long l;
|
|||
|
|
|||
|
dl1.d = a1;
|
|||
|
|
|||
|
if (!dl1.l.upper && !dl1.l.lower)
|
|||
|
return 0;
|
|||
|
|
|||
|
exp = EXPD (dl1) - EXCESSD - 31;
|
|||
|
l = MANTD (dl1);
|
|||
|
|
|||
|
if (exp > 0)
|
|||
|
{
|
|||
|
/* Return largest integer. */
|
|||
|
return SIGND (dl1) ? 0x80000000L : 0x7fffffffL;
|
|||
|
}
|
|||
|
|
|||
|
if (exp <= -32)
|
|||
|
return 0;
|
|||
|
|
|||
|
/* shift down until exp = 0 */
|
|||
|
if (exp < 0)
|
|||
|
l >>= -exp;
|
|||
|
|
|||
|
return (SIGND (dl1) ? -l : l);
|
|||
|
}
|
|||
|
|
|||
|
/* convert float to int */
|
|||
|
long
|
|||
|
__fixsfsi (float a1)
|
|||
|
{
|
|||
|
double foo = a1;
|
|||
|
return __fixdfsi (foo);
|
|||
|
}
|
|||
|
|
|||
|
#else /* EXTFLOAT */
|
|||
|
|
|||
|
/* We do not need these routines for coldfire, as it has no extended
|
|||
|
float format. */
|
|||
|
#if !defined (__mcoldfire__)
|
|||
|
|
|||
|
/* Primitive extended precision floating point support.
|
|||
|
|
|||
|
We assume all numbers are normalized, don't do any rounding, etc. */
|
|||
|
|
|||
|
/* Prototypes for the above in case we use them. */
|
|||
|
double __floatunsidf (unsigned long);
|
|||
|
double __floatsidf (long);
|
|||
|
float __floatsisf (long);
|
|||
|
double __extendsfdf2 (float);
|
|||
|
float __truncdfsf2 (double);
|
|||
|
long __fixdfsi (double);
|
|||
|
long __fixsfsi (float);
|
|||
|
|
|||
|
int
|
|||
|
__unordxf2(long double a, long double b)
|
|||
|
{
|
|||
|
union long_double_long ldl;
|
|||
|
|
|||
|
ldl.ld = a;
|
|||
|
if (EXPX(ldl) == EXPXMASK
|
|||
|
&& ((ldl.l.middle & MANTXMASK) != 0 || ldl.l.lower != 0))
|
|||
|
return 1;
|
|||
|
ldl.ld = b;
|
|||
|
if (EXPX(ldl) == EXPXMASK
|
|||
|
&& ((ldl.l.middle & MANTXMASK) != 0 || ldl.l.lower != 0))
|
|||
|
return 1;
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
/* convert double to long double */
|
|||
|
long double
|
|||
|
__extenddfxf2 (double d)
|
|||
|
{
|
|||
|
register union double_long dl;
|
|||
|
register union long_double_long ldl;
|
|||
|
register long exp;
|
|||
|
|
|||
|
dl.d = d;
|
|||
|
/*printf ("dfxf in: %g\n", d);*/
|
|||
|
|
|||
|
ldl.l.upper = SIGND (dl);
|
|||
|
if ((dl.l.upper & ~SIGNBIT) == 0 && !dl.l.lower)
|
|||
|
{
|
|||
|
ldl.l.middle = 0;
|
|||
|
ldl.l.lower = 0;
|
|||
|
return ldl.ld;
|
|||
|
}
|
|||
|
|
|||
|
exp = EXPD (dl) - EXCESSD + EXCESSX;
|
|||
|
ldl.l.upper |= exp << 16;
|
|||
|
ldl.l.middle = HIDDENX;
|
|||
|
/* 31-20: # mantissa bits in ldl.l.middle - # mantissa bits in dl.l.upper */
|
|||
|
ldl.l.middle |= (dl.l.upper & MANTDMASK) << (31 - 20);
|
|||
|
/* 1+20: explicit-integer-bit + # mantissa bits in dl.l.upper */
|
|||
|
ldl.l.middle |= dl.l.lower >> (1 + 20);
|
|||
|
/* 32 - 21: # bits of dl.l.lower in ldl.l.middle */
|
|||
|
ldl.l.lower = dl.l.lower << (32 - 21);
|
|||
|
|
|||
|
/*printf ("dfxf out: %s\n", dumpxf (ldl.ld));*/
|
|||
|
return ldl.ld;
|
|||
|
}
|
|||
|
|
|||
|
/* convert long double to double */
|
|||
|
double
|
|||
|
__truncxfdf2 (long double ld)
|
|||
|
{
|
|||
|
register long exp;
|
|||
|
register union double_long dl;
|
|||
|
register union long_double_long ldl;
|
|||
|
|
|||
|
ldl.ld = ld;
|
|||
|
/*printf ("xfdf in: %s\n", dumpxf (ld));*/
|
|||
|
|
|||
|
dl.l.upper = SIGNX (ldl);
|
|||
|
if ((ldl.l.upper & ~SIGNBIT) == 0 && !ldl.l.middle && !ldl.l.lower)
|
|||
|
{
|
|||
|
dl.l.lower = 0;
|
|||
|
return dl.d;
|
|||
|
}
|
|||
|
|
|||
|
exp = EXPX (ldl) - EXCESSX + EXCESSD;
|
|||
|
/* ??? quick and dirty: keep `exp' sane */
|
|||
|
if (exp >= EXPDMASK)
|
|||
|
exp = EXPDMASK - 1;
|
|||
|
dl.l.upper |= exp << (32 - (EXPDBITS + 1));
|
|||
|
/* +1-1: add one for sign bit, but take one off for explicit-integer-bit */
|
|||
|
dl.l.upper |= (ldl.l.middle & MANTXMASK) >> (EXPDBITS + 1 - 1);
|
|||
|
dl.l.lower = (ldl.l.middle & MANTXMASK) << (32 - (EXPDBITS + 1 - 1));
|
|||
|
dl.l.lower |= ldl.l.lower >> (EXPDBITS + 1 - 1);
|
|||
|
|
|||
|
/*printf ("xfdf out: %g\n", dl.d);*/
|
|||
|
return dl.d;
|
|||
|
}
|
|||
|
|
|||
|
/* convert a float to a long double */
|
|||
|
long double
|
|||
|
__extendsfxf2 (float f)
|
|||
|
{
|
|||
|
long double foo = __extenddfxf2 (__extendsfdf2 (f));
|
|||
|
return foo;
|
|||
|
}
|
|||
|
|
|||
|
/* convert a long double to a float */
|
|||
|
float
|
|||
|
__truncxfsf2 (long double ld)
|
|||
|
{
|
|||
|
float foo = __truncdfsf2 (__truncxfdf2 (ld));
|
|||
|
return foo;
|
|||
|
}
|
|||
|
|
|||
|
/* convert an int to a long double */
|
|||
|
long double
|
|||
|
__floatsixf (long l)
|
|||
|
{
|
|||
|
double foo = __floatsidf (l);
|
|||
|
return foo;
|
|||
|
}
|
|||
|
|
|||
|
/* convert an unsigned int to a long double */
|
|||
|
long double
|
|||
|
__floatunsixf (unsigned long l)
|
|||
|
{
|
|||
|
double foo = __floatunsidf (l);
|
|||
|
return foo;
|
|||
|
}
|
|||
|
|
|||
|
/* convert a long double to an int */
|
|||
|
long
|
|||
|
__fixxfsi (long double ld)
|
|||
|
{
|
|||
|
long foo = __fixdfsi ((double) ld);
|
|||
|
return foo;
|
|||
|
}
|
|||
|
|
|||
|
/* The remaining provide crude math support by working in double precision. */
|
|||
|
|
|||
|
long double
|
|||
|
__addxf3 (long double x1, long double x2)
|
|||
|
{
|
|||
|
return (double) x1 + (double) x2;
|
|||
|
}
|
|||
|
|
|||
|
long double
|
|||
|
__subxf3 (long double x1, long double x2)
|
|||
|
{
|
|||
|
return (double) x1 - (double) x2;
|
|||
|
}
|
|||
|
|
|||
|
long double
|
|||
|
__mulxf3 (long double x1, long double x2)
|
|||
|
{
|
|||
|
return (double) x1 * (double) x2;
|
|||
|
}
|
|||
|
|
|||
|
long double
|
|||
|
__divxf3 (long double x1, long double x2)
|
|||
|
{
|
|||
|
return (double) x1 / (double) x2;
|
|||
|
}
|
|||
|
|
|||
|
long double
|
|||
|
__negxf2 (long double x1)
|
|||
|
{
|
|||
|
return - (double) x1;
|
|||
|
}
|
|||
|
|
|||
|
long
|
|||
|
__cmpxf2 (long double x1, long double x2)
|
|||
|
{
|
|||
|
return __cmpdf2 ((double) x1, (double) x2);
|
|||
|
}
|
|||
|
|
|||
|
long
|
|||
|
__eqxf2 (long double x1, long double x2)
|
|||
|
{
|
|||
|
return __cmpdf2 ((double) x1, (double) x2);
|
|||
|
}
|
|||
|
|
|||
|
long
|
|||
|
__nexf2 (long double x1, long double x2)
|
|||
|
{
|
|||
|
return __cmpdf2 ((double) x1, (double) x2);
|
|||
|
}
|
|||
|
|
|||
|
long
|
|||
|
__ltxf2 (long double x1, long double x2)
|
|||
|
{
|
|||
|
return __cmpdf2 ((double) x1, (double) x2);
|
|||
|
}
|
|||
|
|
|||
|
long
|
|||
|
__lexf2 (long double x1, long double x2)
|
|||
|
{
|
|||
|
return __cmpdf2 ((double) x1, (double) x2);
|
|||
|
}
|
|||
|
|
|||
|
long
|
|||
|
__gtxf2 (long double x1, long double x2)
|
|||
|
{
|
|||
|
return __cmpdf2 ((double) x1, (double) x2);
|
|||
|
}
|
|||
|
|
|||
|
long
|
|||
|
__gexf2 (long double x1, long double x2)
|
|||
|
{
|
|||
|
return __cmpdf2 ((double) x1, (double) x2);
|
|||
|
}
|
|||
|
|
|||
|
#endif /* !__mcoldfire__ */
|
|||
|
#endif /* EXTFLOAT */
|