use the generic soft float code

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1333 c046a42c-6fe2-441c-8c8c-71466251a162
master
bellard 2005-03-13 16:55:58 +00:00
parent 158142c2c2
commit 2049521883
15 changed files with 84 additions and 5011 deletions

View File

@ -1,120 +0,0 @@
/*
-------------------------------------------------------------------------------
The macro `BITS64' can be defined to indicate that 64-bit integer types are
supported by the compiler.
-------------------------------------------------------------------------------
*/
#define BITS64
/*
-------------------------------------------------------------------------------
Each of the following `typedef's defines the most convenient type that holds
integers of at least as many bits as specified. For example, `uint8' should
be the most convenient type that can hold unsigned integers of as many as
8 bits. The `flag' type must be able to hold either a 0 or 1. For most
implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed
to the same as `int'.
-------------------------------------------------------------------------------
*/
typedef char flag;
typedef unsigned char uint8;
typedef signed char int8;
typedef int uint16;
typedef int int16;
typedef unsigned int uint32;
typedef signed int int32;
#ifdef BITS64
typedef unsigned long long int bits64;
typedef signed long long int sbits64;
#endif
/*
-------------------------------------------------------------------------------
Each of the following `typedef's defines a type that holds integers
of _exactly_ the number of bits specified. For instance, for most
implementation of C, `bits16' and `sbits16' should be `typedef'ed to
`unsigned short int' and `signed short int' (or `short int'), respectively.
-------------------------------------------------------------------------------
*/
typedef unsigned char bits8;
typedef signed char sbits8;
typedef unsigned short int bits16;
typedef signed short int sbits16;
typedef unsigned int bits32;
typedef signed int sbits32;
#ifdef BITS64
typedef unsigned long long int uint64;
typedef signed long long int int64;
#endif
#ifdef BITS64
/*
-------------------------------------------------------------------------------
The `LIT64' macro takes as its argument a textual integer literal and if
necessary ``marks'' the literal as having a 64-bit integer type. For
example, the Gnu C Compiler (`gcc') requires that 64-bit literals be
appended with the letters `LL' standing for `long long', which is `gcc's
name for the 64-bit integer type. Some compilers may allow `LIT64' to be
defined as the identity macro: `#define LIT64( a ) a'.
-------------------------------------------------------------------------------
*/
#define LIT64( a ) a##LL
#endif
/*
-------------------------------------------------------------------------------
The macro `INLINE' can be used before functions that should be inlined. If
a compiler does not support explicit inlining, this macro should be defined
to be `static'.
-------------------------------------------------------------------------------
*/
#define INLINE extern __inline__
/* For use as a GCC soft-float library we need some special function names. */
#ifdef __LIBFLOAT__
/* Some 32-bit ops can be mapped straight across by just changing the name. */
#define float32_add __addsf3
#define float32_sub __subsf3
#define float32_mul __mulsf3
#define float32_div __divsf3
#define int32_to_float32 __floatsisf
#define float32_to_int32_round_to_zero __fixsfsi
#define float32_to_uint32_round_to_zero __fixunssfsi
/* These ones go through the glue code. To avoid namespace pollution
we rename the internal functions too. */
#define float32_eq ___float32_eq
#define float32_le ___float32_le
#define float32_lt ___float32_lt
/* All the 64-bit ops have to go through the glue, so we pull the same
trick. */
#define float64_add ___float64_add
#define float64_sub ___float64_sub
#define float64_mul ___float64_mul
#define float64_div ___float64_div
#define int32_to_float64 ___int32_to_float64
#define float64_to_int32_round_to_zero ___float64_to_int32_round_to_zero
#define float64_to_uint32_round_to_zero ___float64_to_uint32_round_to_zero
#define float64_to_float32 ___float64_to_float32
#define float32_to_float64 ___float32_to_float64
#define float64_eq ___float64_eq
#define float64_le ___float64_le
#define float64_lt ___float64_lt
#if 0
#define float64_add __adddf3
#define float64_sub __subdf3
#define float64_mul __muldf3
#define float64_div __divdf3
#define int32_to_float64 __floatsidf
#define float64_to_int32_round_to_zero __fixdfsi
#define float64_to_uint32_round_to_zero __fixunsdfsi
#define float64_to_float32 __truncdfsf2
#define float32_to_float64 __extendsfdf2
#endif
#endif

View File

@ -53,7 +53,7 @@ unsigned int DoubleCPDO(const unsigned int opcode)
switch (fpa11->fType[Fm])
{
case typeSingle:
rFm = float32_to_float64(fpa11->fpreg[Fm].fSingle);
rFm = float32_to_float64(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status);
break;
case typeDouble:
@ -79,7 +79,7 @@ unsigned int DoubleCPDO(const unsigned int opcode)
switch (fpa11->fType[Fn])
{
case typeSingle:
rFn = float32_to_float64(fpa11->fpreg[Fn].fSingle);
rFn = float32_to_float64(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
break;
case typeDouble:
@ -96,30 +96,30 @@ unsigned int DoubleCPDO(const unsigned int opcode)
{
/* dyadic opcodes */
case ADF_CODE:
fpa11->fpreg[Fd].fDouble = float64_add(rFn,rFm);
fpa11->fpreg[Fd].fDouble = float64_add(rFn,rFm, &fpa11->fp_status);
break;
case MUF_CODE:
case FML_CODE:
fpa11->fpreg[Fd].fDouble = float64_mul(rFn,rFm);
fpa11->fpreg[Fd].fDouble = float64_mul(rFn,rFm, &fpa11->fp_status);
break;
case SUF_CODE:
fpa11->fpreg[Fd].fDouble = float64_sub(rFn,rFm);
fpa11->fpreg[Fd].fDouble = float64_sub(rFn,rFm, &fpa11->fp_status);
break;
case RSF_CODE:
fpa11->fpreg[Fd].fDouble = float64_sub(rFm,rFn);
fpa11->fpreg[Fd].fDouble = float64_sub(rFm,rFn, &fpa11->fp_status);
break;
case DVF_CODE:
case FDV_CODE:
fpa11->fpreg[Fd].fDouble = float64_div(rFn,rFm);
fpa11->fpreg[Fd].fDouble = float64_div(rFn,rFm, &fpa11->fp_status);
break;
case RDF_CODE:
case FRD_CODE:
fpa11->fpreg[Fd].fDouble = float64_div(rFm,rFn);
fpa11->fpreg[Fd].fDouble = float64_div(rFm,rFn, &fpa11->fp_status);
break;
#if 0
@ -133,7 +133,7 @@ unsigned int DoubleCPDO(const unsigned int opcode)
#endif
case RMF_CODE:
fpa11->fpreg[Fd].fDouble = float64_rem(rFn,rFm);
fpa11->fpreg[Fd].fDouble = float64_rem(rFn,rFm, &fpa11->fp_status);
break;
#if 0
@ -173,11 +173,11 @@ unsigned int DoubleCPDO(const unsigned int opcode)
case RND_CODE:
case URD_CODE:
fpa11->fpreg[Fd].fDouble = float64_round_to_int(rFm);
fpa11->fpreg[Fd].fDouble = float64_round_to_int(rFm, &fpa11->fp_status);
break;
case SQT_CODE:
fpa11->fpreg[Fd].fDouble = float64_sqrt(rFm);
fpa11->fpreg[Fd].fDouble = float64_sqrt(rFm, &fpa11->fp_status);
break;
#if 0

View File

@ -53,11 +53,11 @@ unsigned int ExtendedCPDO(const unsigned int opcode)
switch (fpa11->fType[Fm])
{
case typeSingle:
rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle);
rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status);
break;
case typeDouble:
rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble);
rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status);
break;
case typeExtended:
@ -74,11 +74,11 @@ unsigned int ExtendedCPDO(const unsigned int opcode)
switch (fpa11->fType[Fn])
{
case typeSingle:
rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
break;
case typeDouble:
rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
break;
case typeExtended:
@ -94,30 +94,30 @@ unsigned int ExtendedCPDO(const unsigned int opcode)
{
/* dyadic opcodes */
case ADF_CODE:
fpa11->fpreg[Fd].fExtended = floatx80_add(rFn,rFm);
fpa11->fpreg[Fd].fExtended = floatx80_add(rFn,rFm, &fpa11->fp_status);
break;
case MUF_CODE:
case FML_CODE:
fpa11->fpreg[Fd].fExtended = floatx80_mul(rFn,rFm);
fpa11->fpreg[Fd].fExtended = floatx80_mul(rFn,rFm, &fpa11->fp_status);
break;
case SUF_CODE:
fpa11->fpreg[Fd].fExtended = floatx80_sub(rFn,rFm);
fpa11->fpreg[Fd].fExtended = floatx80_sub(rFn,rFm, &fpa11->fp_status);
break;
case RSF_CODE:
fpa11->fpreg[Fd].fExtended = floatx80_sub(rFm,rFn);
fpa11->fpreg[Fd].fExtended = floatx80_sub(rFm,rFn, &fpa11->fp_status);
break;
case DVF_CODE:
case FDV_CODE:
fpa11->fpreg[Fd].fExtended = floatx80_div(rFn,rFm);
fpa11->fpreg[Fd].fExtended = floatx80_div(rFn,rFm, &fpa11->fp_status);
break;
case RDF_CODE:
case FRD_CODE:
fpa11->fpreg[Fd].fExtended = floatx80_div(rFm,rFn);
fpa11->fpreg[Fd].fExtended = floatx80_div(rFm,rFn, &fpa11->fp_status);
break;
#if 0
@ -131,7 +131,7 @@ unsigned int ExtendedCPDO(const unsigned int opcode)
#endif
case RMF_CODE:
fpa11->fpreg[Fd].fExtended = floatx80_rem(rFn,rFm);
fpa11->fpreg[Fd].fExtended = floatx80_rem(rFn,rFm, &fpa11->fp_status);
break;
#if 0
@ -157,11 +157,11 @@ unsigned int ExtendedCPDO(const unsigned int opcode)
case RND_CODE:
case URD_CODE:
fpa11->fpreg[Fd].fExtended = floatx80_round_to_int(rFm);
fpa11->fpreg[Fd].fExtended = floatx80_round_to_int(rFm, &fpa11->fp_status);
break;
case SQT_CODE:
fpa11->fpreg[Fd].fExtended = floatx80_sqrt(rFm);
fpa11->fpreg[Fd].fExtended = floatx80_sqrt(rFm, &fpa11->fp_status);
break;
#if 0

View File

@ -61,74 +61,79 @@ void resetFPA11(void)
void SetRoundingMode(const unsigned int opcode)
{
#if MAINTAIN_FPCR
int rounding_mode;
FPA11 *fpa11 = GET_FPA11();
#if MAINTAIN_FPCR
fpa11->fpcr &= ~MASK_ROUNDING_MODE;
#endif
switch (opcode & MASK_ROUNDING_MODE)
{
default:
case ROUND_TO_NEAREST:
float_rounding_mode = float_round_nearest_even;
rounding_mode = float_round_nearest_even;
#if MAINTAIN_FPCR
fpa11->fpcr |= ROUND_TO_NEAREST;
#endif
break;
case ROUND_TO_PLUS_INFINITY:
float_rounding_mode = float_round_up;
rounding_mode = float_round_up;
#if MAINTAIN_FPCR
fpa11->fpcr |= ROUND_TO_PLUS_INFINITY;
#endif
break;
case ROUND_TO_MINUS_INFINITY:
float_rounding_mode = float_round_down;
rounding_mode = float_round_down;
#if MAINTAIN_FPCR
fpa11->fpcr |= ROUND_TO_MINUS_INFINITY;
#endif
break;
case ROUND_TO_ZERO:
float_rounding_mode = float_round_to_zero;
rounding_mode = float_round_to_zero;
#if MAINTAIN_FPCR
fpa11->fpcr |= ROUND_TO_ZERO;
#endif
break;
}
set_float_rounding_mode(rounding_mode, &fpa11->fp_status);
}
void SetRoundingPrecision(const unsigned int opcode)
{
#if MAINTAIN_FPCR
int rounding_precision;
FPA11 *fpa11 = GET_FPA11();
#if MAINTAIN_FPCR
fpa11->fpcr &= ~MASK_ROUNDING_PRECISION;
#endif
switch (opcode & MASK_ROUNDING_PRECISION)
{
case ROUND_SINGLE:
floatx80_rounding_precision = 32;
rounding_precision = 32;
#if MAINTAIN_FPCR
fpa11->fpcr |= ROUND_SINGLE;
#endif
break;
case ROUND_DOUBLE:
floatx80_rounding_precision = 64;
rounding_precision = 64;
#if MAINTAIN_FPCR
fpa11->fpcr |= ROUND_DOUBLE;
#endif
break;
case ROUND_EXTENDED:
floatx80_rounding_precision = 80;
rounding_precision = 80;
#if MAINTAIN_FPCR
fpa11->fpcr |= ROUND_EXTENDED;
#endif
break;
default: floatx80_rounding_precision = 80;
default: rounding_precision = 80;
}
set_floatx80_rounding_precision(rounding_precision, &fpa11->fp_status);
}
/* Emulate the instruction in the opcode. */

View File

@ -83,6 +83,7 @@ typedef struct tagFPA11 {
so we can use it to detect whether this
instance of the emulator needs to be
initialised. */
float_status fp_status; /* QEMU float emulator status */
} FPA11;
extern FPA11* qemufpa;

View File

@ -80,10 +80,10 @@ unsigned int EmulateCPDO(const unsigned int opcode)
{
if (typeDouble == nType)
fpa11->fpreg[Fd].fSingle =
float64_to_float32(fpa11->fpreg[Fd].fDouble);
float64_to_float32(fpa11->fpreg[Fd].fDouble, &fpa11->fp_status);
else
fpa11->fpreg[Fd].fSingle =
floatx80_to_float32(fpa11->fpreg[Fd].fExtended);
floatx80_to_float32(fpa11->fpreg[Fd].fExtended, &fpa11->fp_status);
}
break;
@ -91,10 +91,10 @@ unsigned int EmulateCPDO(const unsigned int opcode)
{
if (typeSingle == nType)
fpa11->fpreg[Fd].fDouble =
float32_to_float64(fpa11->fpreg[Fd].fSingle);
float32_to_float64(fpa11->fpreg[Fd].fSingle, &fpa11->fp_status);
else
fpa11->fpreg[Fd].fDouble =
floatx80_to_float64(fpa11->fpreg[Fd].fExtended);
floatx80_to_float64(fpa11->fpreg[Fd].fExtended, &fpa11->fp_status);
}
break;
@ -102,10 +102,10 @@ unsigned int EmulateCPDO(const unsigned int opcode)
{
if (typeSingle == nType)
fpa11->fpreg[Fd].fExtended =
float32_to_floatx80(fpa11->fpreg[Fd].fSingle);
float32_to_floatx80(fpa11->fpreg[Fd].fSingle, &fpa11->fp_status);
else
fpa11->fpreg[Fd].fExtended =
float64_to_floatx80(fpa11->fpreg[Fd].fDouble);
float64_to_floatx80(fpa11->fpreg[Fd].fDouble, &fpa11->fp_status);
}
break;
}

View File

@ -106,11 +106,11 @@ void storeSingle(const unsigned int Fn,unsigned int *pMem)
switch (fpa11->fType[Fn])
{
case typeDouble:
val = float64_to_float32(fpa11->fpreg[Fn].fDouble);
val = float64_to_float32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
break;
case typeExtended:
val = floatx80_to_float32(fpa11->fpreg[Fn].fExtended);
val = floatx80_to_float32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status);
break;
default: val = fpa11->fpreg[Fn].fSingle;
@ -129,11 +129,11 @@ void storeDouble(const unsigned int Fn,unsigned int *pMem)
switch (fpa11->fType[Fn])
{
case typeSingle:
val = float32_to_float64(fpa11->fpreg[Fn].fSingle);
val = float32_to_float64(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
break;
case typeExtended:
val = floatx80_to_float64(fpa11->fpreg[Fn].fExtended);
val = floatx80_to_float64(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status);
break;
default: val = fpa11->fpreg[Fn].fDouble;
@ -157,11 +157,11 @@ void storeExtended(const unsigned int Fn,unsigned int *pMem)
switch (fpa11->fType[Fn])
{
case typeSingle:
val = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
val = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
break;
case typeDouble:
val = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
val = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
break;
default: val = fpa11->fpreg[Fn].fExtended;

View File

@ -21,7 +21,6 @@
*/
#include "fpa11.h"
#include "milieu.h"
#include "softfloat.h"
#include "fpopcode.h"
#include "fpa11.inl"
@ -89,7 +88,7 @@ unsigned int PerformFLT(const unsigned int opcode)
{
fpa11->fType[getFn(opcode)] = typeSingle;
fpa11->fpreg[getFn(opcode)].fSingle =
int32_to_float32(readRegister(getRd(opcode)));
int32_to_float32(readRegister(getRd(opcode)), &fpa11->fp_status);
}
break;
@ -97,7 +96,7 @@ unsigned int PerformFLT(const unsigned int opcode)
{
fpa11->fType[getFn(opcode)] = typeDouble;
fpa11->fpreg[getFn(opcode)].fDouble =
int32_to_float64(readRegister(getRd(opcode)));
int32_to_float64(readRegister(getRd(opcode)), &fpa11->fp_status);
}
break;
@ -105,7 +104,7 @@ unsigned int PerformFLT(const unsigned int opcode)
{
fpa11->fType[getFn(opcode)] = typeExtended;
fpa11->fpreg[getFn(opcode)].fExtended =
int32_to_floatx80(readRegister(getRd(opcode)));
int32_to_floatx80(readRegister(getRd(opcode)), &fpa11->fp_status);
}
break;
@ -128,7 +127,7 @@ unsigned int PerformFIX(const unsigned int opcode)
case typeSingle:
{
writeRegister(getRd(opcode),
float32_to_int32(fpa11->fpreg[Fn].fSingle));
float32_to_int32(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status));
}
break;
@ -136,14 +135,14 @@ unsigned int PerformFIX(const unsigned int opcode)
{
//printf("F%d is 0x%llx\n",Fn,fpa11->fpreg[Fn].fDouble);
writeRegister(getRd(opcode),
float64_to_int32(fpa11->fpreg[Fn].fDouble));
float64_to_int32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status));
}
break;
case typeExtended:
{
writeRegister(getRd(opcode),
floatx80_to_int32(fpa11->fpreg[Fn].fExtended));
floatx80_to_int32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status));
}
break;
@ -157,22 +156,23 @@ unsigned int PerformFIX(const unsigned int opcode)
static unsigned int __inline__
PerformComparisonOperation(floatx80 Fn, floatx80 Fm)
{
FPA11 *fpa11 = GET_FPA11();
unsigned int flags = 0;
/* test for less than condition */
if (floatx80_lt(Fn,Fm))
if (floatx80_lt(Fn,Fm, &fpa11->fp_status))
{
flags |= CC_NEGATIVE;
}
/* test for equal condition */
if (floatx80_eq(Fn,Fm))
if (floatx80_eq(Fn,Fm, &fpa11->fp_status))
{
flags |= CC_ZERO;
}
/* test for greater than or equal condition */
if (floatx80_lt(Fm,Fn))
if (floatx80_lt(Fm,Fn, &fpa11->fp_status))
{
flags |= CC_CARRY;
}
@ -208,14 +208,14 @@ static unsigned int PerformComparison(const unsigned int opcode)
//printk("single.\n");
if (float32_is_nan(fpa11->fpreg[Fn].fSingle))
goto unordered;
rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
break;
case typeDouble:
//printk("double.\n");
if (float64_is_nan(fpa11->fpreg[Fn].fDouble))
goto unordered;
rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
break;
case typeExtended:
@ -244,14 +244,14 @@ static unsigned int PerformComparison(const unsigned int opcode)
//printk("single.\n");
if (float32_is_nan(fpa11->fpreg[Fm].fSingle))
goto unordered;
rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle);
rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status);
break;
case typeDouble:
//printk("double.\n");
if (float64_is_nan(fpa11->fpreg[Fm].fDouble))
goto unordered;
rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble);
rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status);
break;
case typeExtended:
@ -283,7 +283,7 @@ static unsigned int PerformComparison(const unsigned int opcode)
if (BIT_AC & readFPSR()) flags |= CC_CARRY;
if (e_flag) float_raise(float_flag_invalid);
if (e_flag) float_raise(float_flag_invalid, &fpa11->fp_status);
writeConditionCodes(flags);
return 1;

View File

@ -27,14 +27,14 @@
//#include "fpmodule.inl"
const floatx80 floatx80Constant[] = {
{ 0x0000, 0x0000000000000000ULL}, /* extended 0.0 */
{ 0x3fff, 0x8000000000000000ULL}, /* extended 1.0 */
{ 0x4000, 0x8000000000000000ULL}, /* extended 2.0 */
{ 0x4000, 0xc000000000000000ULL}, /* extended 3.0 */
{ 0x4001, 0x8000000000000000ULL}, /* extended 4.0 */
{ 0x4001, 0xa000000000000000ULL}, /* extended 5.0 */
{ 0x3ffe, 0x8000000000000000ULL}, /* extended 0.5 */
{ 0x4002, 0xa000000000000000ULL} /* extended 10.0 */
{ 0x0000000000000000ULL, 0x0000}, /* extended 0.0 */
{ 0x8000000000000000ULL, 0x3fff}, /* extended 1.0 */
{ 0x8000000000000000ULL, 0x4000}, /* extended 2.0 */
{ 0xc000000000000000ULL, 0x4000}, /* extended 3.0 */
{ 0x8000000000000000ULL, 0x4001}, /* extended 4.0 */
{ 0xa000000000000000ULL, 0x4001}, /* extended 5.0 */
{ 0x8000000000000000ULL, 0x3ffe}, /* extended 0.5 */
{ 0xa000000000000000ULL, 0x4002} /* extended 10.0 */
};
const float64 float64Constant[] = {

View File

@ -1,48 +0,0 @@
/*
===============================================================================
This C header file is part of the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
arithmetic/softfloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) they include prominent notice that the work is derivative, and (2) they
include prominent notice akin to these three paragraphs for those parts of
this code that are retained.
===============================================================================
*/
/*
-------------------------------------------------------------------------------
Include common integer types and flags.
-------------------------------------------------------------------------------
*/
#include "ARM-gcc.h"
/*
-------------------------------------------------------------------------------
Symbolic Boolean literals.
-------------------------------------------------------------------------------
*/
enum {
FALSE = 0,
TRUE = 1
};

View File

@ -76,30 +76,30 @@ unsigned int SingleCPDO(const unsigned int opcode)
{
/* dyadic opcodes */
case ADF_CODE:
fpa11->fpreg[Fd].fSingle = float32_add(rFn,rFm);
fpa11->fpreg[Fd].fSingle = float32_add(rFn,rFm, &fpa11->fp_status);
break;
case MUF_CODE:
case FML_CODE:
fpa11->fpreg[Fd].fSingle = float32_mul(rFn,rFm);
fpa11->fpreg[Fd].fSingle = float32_mul(rFn,rFm, &fpa11->fp_status);
break;
case SUF_CODE:
fpa11->fpreg[Fd].fSingle = float32_sub(rFn,rFm);
fpa11->fpreg[Fd].fSingle = float32_sub(rFn,rFm, &fpa11->fp_status);
break;
case RSF_CODE:
fpa11->fpreg[Fd].fSingle = float32_sub(rFm,rFn);
fpa11->fpreg[Fd].fSingle = float32_sub(rFm,rFn, &fpa11->fp_status);
break;
case DVF_CODE:
case FDV_CODE:
fpa11->fpreg[Fd].fSingle = float32_div(rFn,rFm);
fpa11->fpreg[Fd].fSingle = float32_div(rFn,rFm, &fpa11->fp_status);
break;
case RDF_CODE:
case FRD_CODE:
fpa11->fpreg[Fd].fSingle = float32_div(rFm,rFn);
fpa11->fpreg[Fd].fSingle = float32_div(rFm,rFn, &fpa11->fp_status);
break;
#if 0
@ -113,7 +113,7 @@ unsigned int SingleCPDO(const unsigned int opcode)
#endif
case RMF_CODE:
fpa11->fpreg[Fd].fSingle = float32_rem(rFn,rFm);
fpa11->fpreg[Fd].fSingle = float32_rem(rFn,rFm, &fpa11->fp_status);
break;
#if 0
@ -139,11 +139,11 @@ unsigned int SingleCPDO(const unsigned int opcode)
case RND_CODE:
case URD_CODE:
fpa11->fpreg[Fd].fSingle = float32_round_to_int(rFm);
fpa11->fpreg[Fd].fSingle = float32_round_to_int(rFm, &fpa11->fp_status);
break;
case SQT_CODE:
fpa11->fpreg[Fd].fSingle = float32_sqrt(rFm);
fpa11->fpreg[Fd].fSingle = float32_sqrt(rFm, &fpa11->fp_status);
break;
#if 0

View File

@ -1,740 +0,0 @@
/*
===============================================================================
This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
arithmetic/softfloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) they include prominent notice that the work is derivative, and (2) they
include prominent notice akin to these three paragraphs for those parts of
this code that are retained.
===============================================================================
*/
/*
-------------------------------------------------------------------------------
Shifts `a' right by the number of bits given in `count'. If any nonzero
bits are shifted off, they are ``jammed'' into the least significant bit of
the result by setting the least significant bit to 1. The value of `count'
can be arbitrarily large; in particular, if `count' is greater than 32, the
result will be either 0 or 1, depending on whether `a' is zero or nonzero.
The result is stored in the location pointed to by `zPtr'.
-------------------------------------------------------------------------------
*/
INLINE void shift32RightJamming( bits32 a, int16 count, bits32 *zPtr )
{
bits32 z;
if ( count == 0 ) {
z = a;
}
else if ( count < 32 ) {
z = ( a>>count ) | ( ( a<<( ( - count ) & 31 ) ) != 0 );
}
else {
z = ( a != 0 );
}
*zPtr = z;
}
/*
-------------------------------------------------------------------------------
Shifts `a' right by the number of bits given in `count'. If any nonzero
bits are shifted off, they are ``jammed'' into the least significant bit of
the result by setting the least significant bit to 1. The value of `count'
can be arbitrarily large; in particular, if `count' is greater than 64, the
result will be either 0 or 1, depending on whether `a' is zero or nonzero.
The result is stored in the location pointed to by `zPtr'.
-------------------------------------------------------------------------------
*/
INLINE void shift64RightJamming( bits64 a, int16 count, bits64 *zPtr )
{
bits64 z;
// __asm__("@shift64RightJamming -- start");
if ( count == 0 ) {
z = a;
}
else if ( count < 64 ) {
z = ( a>>count ) | ( ( a<<( ( - count ) & 63 ) ) != 0 );
}
else {
z = ( a != 0 );
}
// __asm__("@shift64RightJamming -- end");
*zPtr = z;
}
/*
-------------------------------------------------------------------------------
Shifts the 128-bit value formed by concatenating `a0' and `a1' right by 64
_plus_ the number of bits given in `count'. The shifted result is at most
64 nonzero bits; this is stored at the location pointed to by `z0Ptr'. The
bits shifted off form a second 64-bit result as follows: The _last_ bit
shifted off is the most-significant bit of the extra result, and the other
63 bits of the extra result are all zero if and only if _all_but_the_last_
bits shifted off were all zero. This extra result is stored in the location
pointed to by `z1Ptr'. The value of `count' can be arbitrarily large.
(This routine makes more sense if `a0' and `a1' are considered to form a
fixed-point value with binary point between `a0' and `a1'. This fixed-point
value is shifted right by the number of bits given in `count', and the
integer part of the result is returned at the location pointed to by
`z0Ptr'. The fractional part of the result may be slightly corrupted as
described above, and is returned at the location pointed to by `z1Ptr'.)
-------------------------------------------------------------------------------
*/
INLINE void
shift64ExtraRightJamming(
bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
{
bits64 z0, z1;
int8 negCount = ( - count ) & 63;
if ( count == 0 ) {
z1 = a1;
z0 = a0;
}
else if ( count < 64 ) {
z1 = ( a0<<negCount ) | ( a1 != 0 );
z0 = a0>>count;
}
else {
if ( count == 64 ) {
z1 = a0 | ( a1 != 0 );
}
else {
z1 = ( ( a0 | a1 ) != 0 );
}
z0 = 0;
}
*z1Ptr = z1;
*z0Ptr = z0;
}
/*
-------------------------------------------------------------------------------
Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the
number of bits given in `count'. Any bits shifted off are lost. The value
of `count' can be arbitrarily large; in particular, if `count' is greater
than 128, the result will be 0. The result is broken into two 64-bit pieces
which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
-------------------------------------------------------------------------------
*/
INLINE void
shift128Right(
bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
{
bits64 z0, z1;
int8 negCount = ( - count ) & 63;
if ( count == 0 ) {
z1 = a1;
z0 = a0;
}
else if ( count < 64 ) {
z1 = ( a0<<negCount ) | ( a1>>count );
z0 = a0>>count;
}
else {
z1 = ( count < 64 ) ? ( a0>>( count & 63 ) ) : 0;
z0 = 0;
}
*z1Ptr = z1;
*z0Ptr = z0;
}
/*
-------------------------------------------------------------------------------
Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the
number of bits given in `count'. If any nonzero bits are shifted off, they
are ``jammed'' into the least significant bit of the result by setting the
least significant bit to 1. The value of `count' can be arbitrarily large;
in particular, if `count' is greater than 128, the result will be either 0
or 1, depending on whether the concatenation of `a0' and `a1' is zero or
nonzero. The result is broken into two 64-bit pieces which are stored at
the locations pointed to by `z0Ptr' and `z1Ptr'.
-------------------------------------------------------------------------------
*/
INLINE void
shift128RightJamming(
bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
{
bits64 z0, z1;
int8 negCount = ( - count ) & 63;
if ( count == 0 ) {
z1 = a1;
z0 = a0;
}
else if ( count < 64 ) {
z1 = ( a0<<negCount ) | ( a1>>count ) | ( ( a1<<negCount ) != 0 );
z0 = a0>>count;
}
else {
if ( count == 64 ) {
z1 = a0 | ( a1 != 0 );
}
else if ( count < 128 ) {
z1 = ( a0>>( count & 63 ) ) | ( ( ( a0<<negCount ) | a1 ) != 0 );
}
else {
z1 = ( ( a0 | a1 ) != 0 );
}
z0 = 0;
}
*z1Ptr = z1;
*z0Ptr = z0;
}
/*
-------------------------------------------------------------------------------
Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' right
by 64 _plus_ the number of bits given in `count'. The shifted result is
at most 128 nonzero bits; these are broken into two 64-bit pieces which are
stored at the locations pointed to by `z0Ptr' and `z1Ptr'. The bits shifted
off form a third 64-bit result as follows: The _last_ bit shifted off is
the most-significant bit of the extra result, and the other 63 bits of the
extra result are all zero if and only if _all_but_the_last_ bits shifted off
were all zero. This extra result is stored in the location pointed to by
`z2Ptr'. The value of `count' can be arbitrarily large.
(This routine makes more sense if `a0', `a1', and `a2' are considered
to form a fixed-point value with binary point between `a1' and `a2'. This
fixed-point value is shifted right by the number of bits given in `count',
and the integer part of the result is returned at the locations pointed to
by `z0Ptr' and `z1Ptr'. The fractional part of the result may be slightly
corrupted as described above, and is returned at the location pointed to by
`z2Ptr'.)
-------------------------------------------------------------------------------
*/
INLINE void
shift128ExtraRightJamming(
bits64 a0,
bits64 a1,
bits64 a2,
int16 count,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr
)
{
bits64 z0, z1, z2;
int8 negCount = ( - count ) & 63;
if ( count == 0 ) {
z2 = a2;
z1 = a1;
z0 = a0;
}
else {
if ( count < 64 ) {
z2 = a1<<negCount;
z1 = ( a0<<negCount ) | ( a1>>count );
z0 = a0>>count;
}
else {
if ( count == 64 ) {
z2 = a1;
z1 = a0;
}
else {
a2 |= a1;
if ( count < 128 ) {
z2 = a0<<negCount;
z1 = a0>>( count & 63 );
}
else {
z2 = ( count == 128 ) ? a0 : ( a0 != 0 );
z1 = 0;
}
}
z0 = 0;
}
z2 |= ( a2 != 0 );
}
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*
-------------------------------------------------------------------------------
Shifts the 128-bit value formed by concatenating `a0' and `a1' left by the
number of bits given in `count'. Any bits shifted off are lost. The value
of `count' must be less than 64. The result is broken into two 64-bit
pieces which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
-------------------------------------------------------------------------------
*/
INLINE void
shortShift128Left(
bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr )
{
*z1Ptr = a1<<count;
*z0Ptr =
( count == 0 ) ? a0 : ( a0<<count ) | ( a1>>( ( - count ) & 63 ) );
}
/*
-------------------------------------------------------------------------------
Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' left
by the number of bits given in `count'. Any bits shifted off are lost.
The value of `count' must be less than 64. The result is broken into three
64-bit pieces which are stored at the locations pointed to by `z0Ptr',
`z1Ptr', and `z2Ptr'.
-------------------------------------------------------------------------------
*/
INLINE void
shortShift192Left(
bits64 a0,
bits64 a1,
bits64 a2,
int16 count,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr
)
{
bits64 z0, z1, z2;
int8 negCount;
z2 = a2<<count;
z1 = a1<<count;
z0 = a0<<count;
if ( 0 < count ) {
negCount = ( ( - count ) & 63 );
z1 |= a2>>negCount;
z0 |= a1>>negCount;
}
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*
-------------------------------------------------------------------------------
Adds the 128-bit value formed by concatenating `a0' and `a1' to the 128-bit
value formed by concatenating `b0' and `b1'. Addition is modulo 2^128, so
any carry out is lost. The result is broken into two 64-bit pieces which
are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
-------------------------------------------------------------------------------
*/
INLINE void
add128(
bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr )
{
bits64 z1;
z1 = a1 + b1;
*z1Ptr = z1;
*z0Ptr = a0 + b0 + ( z1 < a1 );
}
/*
-------------------------------------------------------------------------------
Adds the 192-bit value formed by concatenating `a0', `a1', and `a2' to the
192-bit value formed by concatenating `b0', `b1', and `b2'. Addition is
modulo 2^192, so any carry out is lost. The result is broken into three
64-bit pieces which are stored at the locations pointed to by `z0Ptr',
`z1Ptr', and `z2Ptr'.
-------------------------------------------------------------------------------
*/
INLINE void
add192(
bits64 a0,
bits64 a1,
bits64 a2,
bits64 b0,
bits64 b1,
bits64 b2,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr
)
{
bits64 z0, z1, z2;
int8 carry0, carry1;
z2 = a2 + b2;
carry1 = ( z2 < a2 );
z1 = a1 + b1;
carry0 = ( z1 < a1 );
z0 = a0 + b0;
z1 += carry1;
z0 += ( z1 < carry1 );
z0 += carry0;
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*
-------------------------------------------------------------------------------
Subtracts the 128-bit value formed by concatenating `b0' and `b1' from the
128-bit value formed by concatenating `a0' and `a1'. Subtraction is modulo
2^128, so any borrow out (carry out) is lost. The result is broken into two
64-bit pieces which are stored at the locations pointed to by `z0Ptr' and
`z1Ptr'.
-------------------------------------------------------------------------------
*/
INLINE void
sub128(
bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr )
{
*z1Ptr = a1 - b1;
*z0Ptr = a0 - b0 - ( a1 < b1 );
}
/*
-------------------------------------------------------------------------------
Subtracts the 192-bit value formed by concatenating `b0', `b1', and `b2'
from the 192-bit value formed by concatenating `a0', `a1', and `a2'.
Subtraction is modulo 2^192, so any borrow out (carry out) is lost. The
result is broken into three 64-bit pieces which are stored at the locations
pointed to by `z0Ptr', `z1Ptr', and `z2Ptr'.
-------------------------------------------------------------------------------
*/
INLINE void
sub192(
bits64 a0,
bits64 a1,
bits64 a2,
bits64 b0,
bits64 b1,
bits64 b2,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr
)
{
bits64 z0, z1, z2;
int8 borrow0, borrow1;
z2 = a2 - b2;
borrow1 = ( a2 < b2 );
z1 = a1 - b1;
borrow0 = ( a1 < b1 );
z0 = a0 - b0;
z0 -= ( z1 < borrow1 );
z1 -= borrow1;
z0 -= borrow0;
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*
-------------------------------------------------------------------------------
Multiplies `a' by `b' to obtain a 128-bit product. The product is broken
into two 64-bit pieces which are stored at the locations pointed to by
`z0Ptr' and `z1Ptr'.
-------------------------------------------------------------------------------
*/
INLINE void mul64To128( bits64 a, bits64 b, bits64 *z0Ptr, bits64 *z1Ptr )
{
bits32 aHigh, aLow, bHigh, bLow;
bits64 z0, zMiddleA, zMiddleB, z1;
aLow = a;
aHigh = a>>32;
bLow = b;
bHigh = b>>32;
z1 = ( (bits64) aLow ) * bLow;
zMiddleA = ( (bits64) aLow ) * bHigh;
zMiddleB = ( (bits64) aHigh ) * bLow;
z0 = ( (bits64) aHigh ) * bHigh;
zMiddleA += zMiddleB;
z0 += ( ( (bits64) ( zMiddleA < zMiddleB ) )<<32 ) + ( zMiddleA>>32 );
zMiddleA <<= 32;
z1 += zMiddleA;
z0 += ( z1 < zMiddleA );
*z1Ptr = z1;
*z0Ptr = z0;
}
/*
-------------------------------------------------------------------------------
Multiplies the 128-bit value formed by concatenating `a0' and `a1' by `b' to
obtain a 192-bit product. The product is broken into three 64-bit pieces
which are stored at the locations pointed to by `z0Ptr', `z1Ptr', and
`z2Ptr'.
-------------------------------------------------------------------------------
*/
INLINE void
mul128By64To192(
bits64 a0,
bits64 a1,
bits64 b,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr
)
{
bits64 z0, z1, z2, more1;
mul64To128( a1, b, &z1, &z2 );
mul64To128( a0, b, &z0, &more1 );
add128( z0, more1, 0, z1, &z0, &z1 );
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*
-------------------------------------------------------------------------------
Multiplies the 128-bit value formed by concatenating `a0' and `a1' to the
128-bit value formed by concatenating `b0' and `b1' to obtain a 256-bit
product. The product is broken into four 64-bit pieces which are stored at
the locations pointed to by `z0Ptr', `z1Ptr', `z2Ptr', and `z3Ptr'.
-------------------------------------------------------------------------------
*/
INLINE void
mul128To256(
bits64 a0,
bits64 a1,
bits64 b0,
bits64 b1,
bits64 *z0Ptr,
bits64 *z1Ptr,
bits64 *z2Ptr,
bits64 *z3Ptr
)
{
bits64 z0, z1, z2, z3;
bits64 more1, more2;
mul64To128( a1, b1, &z2, &z3 );
mul64To128( a1, b0, &z1, &more2 );
add128( z1, more2, 0, z2, &z1, &z2 );
mul64To128( a0, b0, &z0, &more1 );
add128( z0, more1, 0, z1, &z0, &z1 );
mul64To128( a0, b1, &more1, &more2 );
add128( more1, more2, 0, z2, &more1, &z2 );
add128( z0, z1, 0, more1, &z0, &z1 );
*z3Ptr = z3;
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*
-------------------------------------------------------------------------------
Returns an approximation to the 64-bit integer quotient obtained by dividing
`b' into the 128-bit value formed by concatenating `a0' and `a1'. The
divisor `b' must be at least 2^63. If q is the exact quotient truncated
toward zero, the approximation returned lies between q and q + 2 inclusive.
If the exact quotient q is larger than 64 bits, the maximum positive 64-bit
unsigned integer is returned.
-------------------------------------------------------------------------------
*/
static bits64 estimateDiv128To64( bits64 a0, bits64 a1, bits64 b )
{
bits64 b0, b1;
bits64 rem0, rem1, term0, term1;
bits64 z;
if ( b <= a0 ) return LIT64( 0xFFFFFFFFFFFFFFFF );
b0 = b>>32;
z = ( b0<<32 <= a0 ) ? LIT64( 0xFFFFFFFF00000000 ) : ( a0 / b0 )<<32;
mul64To128( b, z, &term0, &term1 );
sub128( a0, a1, term0, term1, &rem0, &rem1 );
while ( ( (sbits64) rem0 ) < 0 ) {
z -= LIT64( 0x100000000 );
b1 = b<<32;
add128( rem0, rem1, b0, b1, &rem0, &rem1 );
}
rem0 = ( rem0<<32 ) | ( rem1>>32 );
z |= ( b0<<32 <= rem0 ) ? 0xFFFFFFFF : rem0 / b0;
return z;
}
/*
-------------------------------------------------------------------------------
Returns an approximation to the square root of the 32-bit significand given
by `a'. Considered as an integer, `a' must be at least 2^31. If bit 0 of
`aExp' (the least significant bit) is 1, the integer returned approximates
2^31*sqrt(`a'/2^31), where `a' is considered an integer. If bit 0 of `aExp'
is 0, the integer returned approximates 2^31*sqrt(`a'/2^30). In either
case, the approximation returned lies strictly within +/-2 of the exact
value.
-------------------------------------------------------------------------------
*/
static bits32 estimateSqrt32( int16 aExp, bits32 a )
{
static const bits16 sqrtOddAdjustments[] = {
0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0,
0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67
};
static const bits16 sqrtEvenAdjustments[] = {
0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E,
0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002
};
int8 index;
bits32 z;
index = ( a>>27 ) & 15;
if ( aExp & 1 ) {
z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ index ];
z = ( ( a / z )<<14 ) + ( z<<15 );
a >>= 1;
}
else {
z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ index ];
z = a / z + z;
z = ( 0x20000 <= z ) ? 0xFFFF8000 : ( z<<15 );
if ( z <= a ) return (bits32) ( ( (sbits32) a )>>1 );
}
return ( (bits32) ( ( ( (bits64) a )<<31 ) / z ) ) + ( z>>1 );
}
/*
-------------------------------------------------------------------------------
Returns the number of leading 0 bits before the most-significant 1 bit
of `a'. If `a' is zero, 32 is returned.
-------------------------------------------------------------------------------
*/
static int8 countLeadingZeros32( bits32 a )
{
static const int8 countLeadingZerosHigh[] = {
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
int8 shiftCount;
shiftCount = 0;
if ( a < 0x10000 ) {
shiftCount += 16;
a <<= 16;
}
if ( a < 0x1000000 ) {
shiftCount += 8;
a <<= 8;
}
shiftCount += countLeadingZerosHigh[ a>>24 ];
return shiftCount;
}
/*
-------------------------------------------------------------------------------
Returns the number of leading 0 bits before the most-significant 1 bit
of `a'. If `a' is zero, 64 is returned.
-------------------------------------------------------------------------------
*/
static int8 countLeadingZeros64( bits64 a )
{
int8 shiftCount;
shiftCount = 0;
if ( a < ( (bits64) 1 )<<32 ) {
shiftCount += 32;
}
else {
a >>= 32;
}
shiftCount += countLeadingZeros32( a );
return shiftCount;
}
/*
-------------------------------------------------------------------------------
Returns 1 if the 128-bit value formed by concatenating `a0' and `a1'
is equal to the 128-bit value formed by concatenating `b0' and `b1'.
Otherwise, returns 0.
-------------------------------------------------------------------------------
*/
INLINE flag eq128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
{
return ( a0 == b0 ) && ( a1 == b1 );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less
than or equal to the 128-bit value formed by concatenating `b0' and `b1'.
Otherwise, returns 0.
-------------------------------------------------------------------------------
*/
INLINE flag le128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
{
return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 <= b1 ) );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less
than the 128-bit value formed by concatenating `b0' and `b1'. Otherwise,
returns 0.
-------------------------------------------------------------------------------
*/
INLINE flag lt128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
{
return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 < b1 ) );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is
not equal to the 128-bit value formed by concatenating `b0' and `b1'.
Otherwise, returns 0.
-------------------------------------------------------------------------------
*/
INLINE flag ne128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 )
{
return ( a0 != b0 ) || ( a1 != b1 );
}

View File

@ -1,366 +0,0 @@
/*
===============================================================================
This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
arithmetic/softfloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) they include prominent notice that the work is derivative, and (2) they
include prominent notice akin to these three paragraphs for those parts of
this code that are retained.
===============================================================================
*/
/*
-------------------------------------------------------------------------------
Underflow tininess-detection mode, statically initialized to default value.
(The declaration in `softfloat.h' must match the `int8' type here.)
-------------------------------------------------------------------------------
*/
int8 float_detect_tininess = float_tininess_after_rounding;
/*
-------------------------------------------------------------------------------
Raises the exceptions specified by `flags'. Floating-point traps can be
defined here if desired. It is currently not possible for such a trap to
substitute a result value. If traps are not implemented, this routine
should be simply `float_exception_flags |= flags;'.
ScottB: November 4, 1998
Moved this function out of softfloat-specialize into fpmodule.c.
This effectively isolates all the changes required for integrating with the
Linux kernel into fpmodule.c. Porting to NetBSD should only require modifying
fpmodule.c to integrate with the NetBSD kernel (I hope!).
-------------------------------------------------------------------------------
*/
void float_raise( int8 flags )
{
float_exception_flags |= flags;
}
/*
-------------------------------------------------------------------------------
Internal canonical NaN format.
-------------------------------------------------------------------------------
*/
typedef struct {
flag sign;
bits64 high, low;
} commonNaNT;
/*
-------------------------------------------------------------------------------
The pattern for a default generated single-precision NaN.
-------------------------------------------------------------------------------
*/
#define float32_default_nan 0xFFFFFFFF
/*
-------------------------------------------------------------------------------
Returns 1 if the single-precision floating-point value `a' is a NaN;
otherwise returns 0.
-------------------------------------------------------------------------------
*/
flag float32_is_nan( float32 a )
{
return ( 0xFF000000 < (bits32) ( a<<1 ) );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the single-precision floating-point value `a' is a signaling
NaN; otherwise returns 0.
-------------------------------------------------------------------------------
*/
flag float32_is_signaling_nan( float32 a )
{
return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
}
/*
-------------------------------------------------------------------------------
Returns the result of converting the single-precision floating-point NaN
`a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
exception is raised.
-------------------------------------------------------------------------------
*/
static commonNaNT float32ToCommonNaN( float32 a )
{
commonNaNT z;
if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
z.sign = a>>31;
z.low = 0;
z.high = ( (bits64) a )<<41;
return z;
}
/*
-------------------------------------------------------------------------------
Returns the result of converting the canonical NaN `a' to the single-
precision floating-point format.
-------------------------------------------------------------------------------
*/
static float32 commonNaNToFloat32( commonNaNT a )
{
return ( ( (bits32) a.sign )<<31 ) | 0x7FC00000 | ( a.high>>41 );
}
/*
-------------------------------------------------------------------------------
Takes two single-precision floating-point values `a' and `b', one of which
is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
signaling NaN, the invalid exception is raised.
-------------------------------------------------------------------------------
*/
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 ( aIsNaN ) {
return ( aIsSignalingNaN & bIsNaN ) ? b : a;
}
else {
return b;
}
}
/*
-------------------------------------------------------------------------------
The pattern for a default generated double-precision NaN.
-------------------------------------------------------------------------------
*/
#define float64_default_nan LIT64( 0xFFFFFFFFFFFFFFFF )
/*
-------------------------------------------------------------------------------
Returns 1 if the double-precision floating-point value `a' is a NaN;
otherwise returns 0.
-------------------------------------------------------------------------------
*/
flag float64_is_nan( float64 a )
{
return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the double-precision floating-point value `a' is a signaling
NaN; otherwise returns 0.
-------------------------------------------------------------------------------
*/
flag float64_is_signaling_nan( float64 a )
{
return
( ( ( a>>51 ) & 0xFFF ) == 0xFFE )
&& ( a & LIT64( 0x0007FFFFFFFFFFFF ) );
}
/*
-------------------------------------------------------------------------------
Returns the result of converting the double-precision floating-point NaN
`a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
exception is raised.
-------------------------------------------------------------------------------
*/
static commonNaNT float64ToCommonNaN( float64 a )
{
commonNaNT z;
if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
z.sign = a>>63;
z.low = 0;
z.high = a<<12;
return z;
}
/*
-------------------------------------------------------------------------------
Returns the result of converting the canonical NaN `a' to the double-
precision floating-point format.
-------------------------------------------------------------------------------
*/
static float64 commonNaNToFloat64( commonNaNT a )
{
return
( ( (bits64) a.sign )<<63 )
| LIT64( 0x7FF8000000000000 )
| ( a.high>>12 );
}
/*
-------------------------------------------------------------------------------
Takes two double-precision floating-point values `a' and `b', one of which
is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
signaling NaN, the invalid exception is raised.
-------------------------------------------------------------------------------
*/
static float64 propagateFloat64NaN( float64 a, float64 b )
{
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
aIsNaN = float64_is_nan( a );
aIsSignalingNaN = float64_is_signaling_nan( a );
bIsNaN = float64_is_nan( b );
bIsSignalingNaN = float64_is_signaling_nan( b );
a |= LIT64( 0x0008000000000000 );
b |= LIT64( 0x0008000000000000 );
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
if ( aIsNaN ) {
return ( aIsSignalingNaN & bIsNaN ) ? b : a;
}
else {
return b;
}
}
#ifdef FLOATX80
/*
-------------------------------------------------------------------------------
The pattern for a default generated extended double-precision NaN. The
`high' and `low' values hold the most- and least-significant bits,
respectively.
-------------------------------------------------------------------------------
*/
#define floatx80_default_nan_high 0xFFFF
#define floatx80_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF )
/*
-------------------------------------------------------------------------------
Returns 1 if the extended double-precision floating-point value `a' is a
NaN; otherwise returns 0.
-------------------------------------------------------------------------------
*/
flag floatx80_is_nan( floatx80 a )
{
return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the extended double-precision floating-point value `a' is a
signaling NaN; otherwise returns 0.
-------------------------------------------------------------------------------
*/
flag floatx80_is_signaling_nan( floatx80 a )
{
//register int lr;
bits64 aLow;
//__asm__("mov %0, lr" : : "g" (lr));
//fp_printk("floatx80_is_signalling_nan() called from 0x%08x\n",lr);
aLow = a.low & ~ LIT64( 0x4000000000000000 );
return
( ( a.high & 0x7FFF ) == 0x7FFF )
&& (bits64) ( aLow<<1 )
&& ( a.low == aLow );
}
/*
-------------------------------------------------------------------------------
Returns the result of converting the extended double-precision floating-
point NaN `a' to the canonical NaN format. If `a' is a signaling NaN, the
invalid exception is raised.
-------------------------------------------------------------------------------
*/
static commonNaNT floatx80ToCommonNaN( floatx80 a )
{
commonNaNT z;
if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid );
z.sign = a.high>>15;
z.low = 0;
z.high = a.low<<1;
return z;
}
/*
-------------------------------------------------------------------------------
Returns the result of converting the canonical NaN `a' to the extended
double-precision floating-point format.
-------------------------------------------------------------------------------
*/
static floatx80 commonNaNToFloatx80( commonNaNT a )
{
floatx80 z;
z.low = LIT64( 0xC000000000000000 ) | ( a.high>>1 );
z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF;
return z;
}
/*
-------------------------------------------------------------------------------
Takes two extended double-precision floating-point values `a' and `b', one
of which is a NaN, and returns the appropriate NaN result. If either `a' or
`b' is a signaling NaN, the invalid exception is raised.
-------------------------------------------------------------------------------
*/
static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b )
{
flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
aIsNaN = floatx80_is_nan( a );
aIsSignalingNaN = floatx80_is_signaling_nan( a );
bIsNaN = floatx80_is_nan( b );
bIsSignalingNaN = floatx80_is_signaling_nan( b );
a.low |= LIT64( 0xC000000000000000 );
b.low |= LIT64( 0xC000000000000000 );
if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid );
if ( aIsNaN ) {
return ( aIsSignalingNaN & bIsNaN ) ? b : a;
}
else {
return b;
}
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,232 +0,0 @@
/*
===============================================================================
This C header file is part of the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
arithmetic/softfloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) they include prominent notice that the work is derivative, and (2) they
include prominent notice akin to these three paragraphs for those parts of
this code that are retained.
===============================================================================
*/
#ifndef __SOFTFLOAT_H__
#define __SOFTFLOAT_H__
/*
-------------------------------------------------------------------------------
The macro `FLOATX80' must be defined to enable the extended double-precision
floating-point format `floatx80'. If this macro is not defined, the
`floatx80' type will not be defined, and none of the functions that either
input or output the `floatx80' type will be defined.
-------------------------------------------------------------------------------
*/
#define FLOATX80
/*
-------------------------------------------------------------------------------
Software IEC/IEEE floating-point types.
-------------------------------------------------------------------------------
*/
typedef unsigned long int float32;
typedef unsigned long long float64;
typedef struct {
unsigned short high;
unsigned long long low;
} floatx80;
/*
-------------------------------------------------------------------------------
Software IEC/IEEE floating-point underflow tininess-detection mode.
-------------------------------------------------------------------------------
*/
extern signed char float_detect_tininess;
enum {
float_tininess_after_rounding = 0,
float_tininess_before_rounding = 1
};
/*
-------------------------------------------------------------------------------
Software IEC/IEEE floating-point rounding mode.
-------------------------------------------------------------------------------
*/
extern signed char float_rounding_mode;
enum {
float_round_nearest_even = 0,
float_round_to_zero = 1,
float_round_down = 2,
float_round_up = 3
};
/*
-------------------------------------------------------------------------------
Software IEC/IEEE floating-point exception flags.
-------------------------------------------------------------------------------
extern signed char float_exception_flags;
enum {
float_flag_inexact = 1,
float_flag_underflow = 2,
float_flag_overflow = 4,
float_flag_divbyzero = 8,
float_flag_invalid = 16
};
ScottB: November 4, 1998
Changed the enumeration to match the bit order in the FPA11.
*/
extern signed char float_exception_flags;
enum {
float_flag_invalid = 1,
float_flag_divbyzero = 2,
float_flag_overflow = 4,
float_flag_underflow = 8,
float_flag_inexact = 16
};
/*
-------------------------------------------------------------------------------
Routine to raise any or all of the software IEC/IEEE floating-point
exception flags.
-------------------------------------------------------------------------------
*/
void float_raise( signed char );
/*
-------------------------------------------------------------------------------
Software IEC/IEEE integer-to-floating-point conversion routines.
-------------------------------------------------------------------------------
*/
float32 int32_to_float32( signed int );
float64 int32_to_float64( signed int );
#ifdef FLOATX80
floatx80 int32_to_floatx80( signed int );
#endif
/*
-------------------------------------------------------------------------------
Software IEC/IEEE single-precision conversion routines.
-------------------------------------------------------------------------------
*/
signed int float32_to_int32( float32 );
signed int float32_to_int32_round_to_zero( float32 );
float64 float32_to_float64( float32 );
#ifdef FLOATX80
floatx80 float32_to_floatx80( float32 );
#endif
/*
-------------------------------------------------------------------------------
Software IEC/IEEE single-precision operations.
-------------------------------------------------------------------------------
*/
float32 float32_round_to_int( float32 );
float32 float32_add( float32, float32 );
float32 float32_sub( float32, float32 );
float32 float32_mul( float32, float32 );
float32 float32_div( float32, float32 );
float32 float32_rem( float32, float32 );
float32 float32_sqrt( float32 );
char float32_eq( float32, float32 );
char float32_le( float32, float32 );
char float32_lt( float32, float32 );
char float32_eq_signaling( float32, float32 );
char float32_le_quiet( float32, float32 );
char float32_lt_quiet( float32, float32 );
char float32_is_signaling_nan( float32 );
/*
-------------------------------------------------------------------------------
Software IEC/IEEE double-precision conversion routines.
-------------------------------------------------------------------------------
*/
signed int float64_to_int32( float64 );
signed int float64_to_int32_round_to_zero( float64 );
float32 float64_to_float32( float64 );
#ifdef FLOATX80
floatx80 float64_to_floatx80( float64 );
#endif
/*
-------------------------------------------------------------------------------
Software IEC/IEEE double-precision operations.
-------------------------------------------------------------------------------
*/
float64 float64_round_to_int( float64 );
float64 float64_add( float64, float64 );
float64 float64_sub( float64, float64 );
float64 float64_mul( float64, float64 );
float64 float64_div( float64, float64 );
float64 float64_rem( float64, float64 );
float64 float64_sqrt( float64 );
char float64_eq( float64, float64 );
char float64_le( float64, float64 );
char float64_lt( float64, float64 );
char float64_eq_signaling( float64, float64 );
char float64_le_quiet( float64, float64 );
char float64_lt_quiet( float64, float64 );
char float64_is_signaling_nan( float64 );
#ifdef FLOATX80
/*
-------------------------------------------------------------------------------
Software IEC/IEEE extended double-precision conversion routines.
-------------------------------------------------------------------------------
*/
signed int floatx80_to_int32( floatx80 );
signed int floatx80_to_int32_round_to_zero( floatx80 );
float32 floatx80_to_float32( floatx80 );
float64 floatx80_to_float64( floatx80 );
/*
-------------------------------------------------------------------------------
Software IEC/IEEE extended double-precision rounding precision. Valid
values are 32, 64, and 80.
-------------------------------------------------------------------------------
*/
extern signed char floatx80_rounding_precision;
/*
-------------------------------------------------------------------------------
Software IEC/IEEE extended double-precision operations.
-------------------------------------------------------------------------------
*/
floatx80 floatx80_round_to_int( floatx80 );
floatx80 floatx80_add( floatx80, floatx80 );
floatx80 floatx80_sub( floatx80, floatx80 );
floatx80 floatx80_mul( floatx80, floatx80 );
floatx80 floatx80_div( floatx80, floatx80 );
floatx80 floatx80_rem( floatx80, floatx80 );
floatx80 floatx80_sqrt( floatx80 );
char floatx80_eq( floatx80, floatx80 );
char floatx80_le( floatx80, floatx80 );
char floatx80_lt( floatx80, floatx80 );
char floatx80_eq_signaling( floatx80, floatx80 );
char floatx80_le_quiet( floatx80, floatx80 );
char floatx80_lt_quiet( floatx80, floatx80 );
char floatx80_is_signaling_nan( floatx80 );
#endif
#endif