From f581bf5474d2319ca37484eb63208017ac96ce0a Mon Sep 17 00:00:00 2001 From: Will Newton Date: Tue, 7 Jan 2014 17:17:48 +0000 Subject: softfloat: Add float to 16bit integer conversions. ARMv8 requires support for converting 32 and 64bit floating point values to signed and unsigned 16bit integers. Signed-off-by: Will Newton [PMM: updated not to incorrectly set Inexact for Invalid inputs] Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- include/fpu/softfloat.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include/fpu/softfloat.h') diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index 2365274daa..a9b8cd9950 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -265,6 +265,8 @@ extern const float16 float16_default_nan; /*---------------------------------------------------------------------------- | Software IEC/IEEE single-precision conversion routines. *----------------------------------------------------------------------------*/ +int_fast16_t float32_to_int16(float32 STATUS_PARAM); +uint_fast16_t float32_to_uint16(float32 STATUS_PARAM); int_fast16_t float32_to_int16_round_to_zero(float32 STATUS_PARAM); uint_fast16_t float32_to_uint16_round_to_zero(float32 STATUS_PARAM); int32 float32_to_int32( float32 STATUS_PARAM ); @@ -371,6 +373,8 @@ extern const float32 float32_default_nan; /*---------------------------------------------------------------------------- | Software IEC/IEEE double-precision conversion routines. *----------------------------------------------------------------------------*/ +int_fast16_t float64_to_int16(float64 STATUS_PARAM); +uint_fast16_t float64_to_uint16(float64 STATUS_PARAM); int_fast16_t float64_to_int16_round_to_zero(float64 STATUS_PARAM); uint_fast16_t float64_to_uint16_round_to_zero(float64 STATUS_PARAM); int32 float64_to_int32( float64 STATUS_PARAM ); -- cgit v1.2.3-55-g7522 From 8afbdabac2a1bdc137691c46965ef8c490cb5e44 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 7 Jan 2014 17:17:49 +0000 Subject: softfloat: Add 16 bit integer to float conversions Add the float to 16 bit integer conversion routines. These can be trivially implemented in terms of the int32_to_float* routines, but providing them makes our API more symmetrical and can simplify callers. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- include/fpu/softfloat.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'include/fpu/softfloat.h') diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index a9b8cd9950..926d849252 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -239,6 +239,27 @@ floatx80 int64_to_floatx80( int64 STATUS_PARAM ); float128 int64_to_float128( int64 STATUS_PARAM ); float128 uint64_to_float128( uint64 STATUS_PARAM ); +/* We provide the int16 versions for symmetry of API with float-to-int */ +INLINE float32 int16_to_float32(int16_t v STATUS_PARAM) +{ + return int32_to_float32(v STATUS_VAR); +} + +INLINE float32 uint16_to_float32(uint16_t v STATUS_PARAM) +{ + return uint32_to_float32(v STATUS_VAR); +} + +INLINE float64 int16_to_float64(int16_t v STATUS_PARAM) +{ + return int32_to_float64(v STATUS_VAR); +} + +INLINE float64 uint16_to_float64(uint16_t v STATUS_PARAM) +{ + return uint32_to_float64(v STATUS_VAR); +} + /*---------------------------------------------------------------------------- | Software half-precision conversion routines. *----------------------------------------------------------------------------*/ -- cgit v1.2.3-55-g7522 From c4850f9e1b9cef2ac35cd6e6f3d8d2147787740c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 7 Jan 2014 17:17:49 +0000 Subject: softfloat: Make the int-to-float functions take exact-width types Currently the int-to-float functions take types which are specified as "at least X bits wide", rather than "exactly X bits wide". This is confusing and unhelpful since it means that the callers have to include an explicit cast to [u]intXX_t to ensure the correct behaviour. Fix them all to take the exactly-X-bits-wide types instead. Note that this doesn't change behaviour at all since at the moment we happen to define the 'int32' and 'uint32' types as exactly 32 bits wide, and the 'int64' and 'uint64' types as exactly 64 bits wide. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- fpu/softfloat.c | 26 +++++++++++++------------- include/fpu/softfloat.h | 26 +++++++++++++------------- 2 files changed, 26 insertions(+), 26 deletions(-) (limited to 'include/fpu/softfloat.h') diff --git a/fpu/softfloat.c b/fpu/softfloat.c index dbaa32c7e3..3170b882b9 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -1121,7 +1121,7 @@ static float128 | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -float32 int32_to_float32( int32 a STATUS_PARAM ) +float32 int32_to_float32(int32_t a STATUS_PARAM) { flag zSign; @@ -1138,7 +1138,7 @@ float32 int32_to_float32( int32 a STATUS_PARAM ) | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -float64 int32_to_float64( int32 a STATUS_PARAM ) +float64 int32_to_float64(int32_t a STATUS_PARAM) { flag zSign; uint32 absA; @@ -1161,7 +1161,7 @@ float64 int32_to_float64( int32 a STATUS_PARAM ) | Arithmetic. *----------------------------------------------------------------------------*/ -floatx80 int32_to_floatx80( int32 a STATUS_PARAM ) +floatx80 int32_to_floatx80(int32_t a STATUS_PARAM) { flag zSign; uint32 absA; @@ -1183,7 +1183,7 @@ floatx80 int32_to_floatx80( int32 a STATUS_PARAM ) | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -float128 int32_to_float128( int32 a STATUS_PARAM ) +float128 int32_to_float128(int32_t a STATUS_PARAM) { flag zSign; uint32 absA; @@ -1205,7 +1205,7 @@ float128 int32_to_float128( int32 a STATUS_PARAM ) | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -float32 int64_to_float32( int64 a STATUS_PARAM ) +float32 int64_to_float32(int64_t a STATUS_PARAM) { flag zSign; uint64 absA; @@ -1231,7 +1231,7 @@ float32 int64_to_float32( int64 a STATUS_PARAM ) } -float32 uint64_to_float32( uint64 a STATUS_PARAM ) +float32 uint64_to_float32(uint64_t a STATUS_PARAM) { int8 shiftCount; @@ -1258,7 +1258,7 @@ float32 uint64_to_float32( uint64 a STATUS_PARAM ) | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -float64 int64_to_float64( int64 a STATUS_PARAM ) +float64 int64_to_float64(int64_t a STATUS_PARAM) { flag zSign; @@ -1271,7 +1271,7 @@ float64 int64_to_float64( int64 a STATUS_PARAM ) } -float64 uint64_to_float64(uint64 a STATUS_PARAM) +float64 uint64_to_float64(uint64_t a STATUS_PARAM) { int exp = 0x43C; @@ -1292,7 +1292,7 @@ float64 uint64_to_float64(uint64 a STATUS_PARAM) | Arithmetic. *----------------------------------------------------------------------------*/ -floatx80 int64_to_floatx80( int64 a STATUS_PARAM ) +floatx80 int64_to_floatx80(int64_t a STATUS_PARAM) { flag zSign; uint64 absA; @@ -1312,7 +1312,7 @@ floatx80 int64_to_floatx80( int64 a STATUS_PARAM ) | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -float128 int64_to_float128( int64 a STATUS_PARAM ) +float128 int64_to_float128(int64_t a STATUS_PARAM) { flag zSign; uint64 absA; @@ -1339,7 +1339,7 @@ float128 int64_to_float128( int64 a STATUS_PARAM ) } -float128 uint64_to_float128(uint64 a STATUS_PARAM) +float128 uint64_to_float128(uint64_t a STATUS_PARAM) { if (a == 0) { return float128_zero; @@ -6445,12 +6445,12 @@ int float128_unordered_quiet( float128 a, float128 b STATUS_PARAM ) } /* misc functions */ -float32 uint32_to_float32( uint32 a STATUS_PARAM ) +float32 uint32_to_float32(uint32_t a STATUS_PARAM) { return int64_to_float32(a STATUS_VAR); } -float64 uint32_to_float64( uint32 a STATUS_PARAM ) +float64 uint32_to_float64(uint32_t a STATUS_PARAM) { return int64_to_float64(a STATUS_VAR); } diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index 926d849252..78b165670d 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -225,19 +225,19 @@ enum { /*---------------------------------------------------------------------------- | Software IEC/IEEE integer-to-floating-point conversion routines. *----------------------------------------------------------------------------*/ -float32 int32_to_float32( int32 STATUS_PARAM ); -float64 int32_to_float64( int32 STATUS_PARAM ); -float32 uint32_to_float32( uint32 STATUS_PARAM ); -float64 uint32_to_float64( uint32 STATUS_PARAM ); -floatx80 int32_to_floatx80( int32 STATUS_PARAM ); -float128 int32_to_float128( int32 STATUS_PARAM ); -float32 int64_to_float32( int64 STATUS_PARAM ); -float32 uint64_to_float32( uint64 STATUS_PARAM ); -float64 int64_to_float64( int64 STATUS_PARAM ); -float64 uint64_to_float64( uint64 STATUS_PARAM ); -floatx80 int64_to_floatx80( int64 STATUS_PARAM ); -float128 int64_to_float128( int64 STATUS_PARAM ); -float128 uint64_to_float128( uint64 STATUS_PARAM ); +float32 int32_to_float32(int32_t STATUS_PARAM); +float64 int32_to_float64(int32_t STATUS_PARAM); +float32 uint32_to_float32(uint32_t STATUS_PARAM); +float64 uint32_to_float64(uint32_t STATUS_PARAM); +floatx80 int32_to_floatx80(int32_t STATUS_PARAM); +float128 int32_to_float128(int32_t STATUS_PARAM); +float32 int64_to_float32(int64_t STATUS_PARAM); +float32 uint64_to_float32(uint64_t STATUS_PARAM); +float64 int64_to_float64(int64_t STATUS_PARAM); +float64 uint64_to_float64(uint64_t STATUS_PARAM); +floatx80 int64_to_floatx80(int64_t STATUS_PARAM); +float128 int64_to_float128(int64_t STATUS_PARAM); +float128 uint64_to_float128(uint64_t STATUS_PARAM); /* We provide the int16 versions for symmetry of API with float-to-int */ INLINE float32 int16_to_float32(int16_t v STATUS_PARAM) -- cgit v1.2.3-55-g7522 From 2f18bbf9844ad110e0e69ad22708f37cab1557f6 Mon Sep 17 00:00:00 2001 From: Tom Musta Date: Tue, 7 Jan 2014 17:17:50 +0000 Subject: softfloat: Add float32_to_uint64() This patch adds the float32_to_uint64() routine, which converts a 32-bit floating point number to an unsigned 64 bit number. This contribution can be licensed under either the softfloat-2a or -2b license. Signed-off-by: Tom Musta Reviewed-by: Peter Maydell [PMM: removed harmless but silly int64_t casts] Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- fpu/softfloat.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ include/fpu/softfloat.h | 1 + 2 files changed, 47 insertions(+) (limited to 'include/fpu/softfloat.h') diff --git a/fpu/softfloat.c b/fpu/softfloat.c index d2e909593f..c2c1a5650b 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -1557,6 +1557,52 @@ int64 float32_to_int64( float32 a STATUS_PARAM ) } +/*---------------------------------------------------------------------------- +| Returns the result of converting the single-precision floating-point value +| `a' to the 64-bit unsigned integer format. The conversion is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic---which means in particular that the conversion is rounded +| according to the current rounding mode. If `a' is a NaN, the largest +| unsigned integer is returned. Otherwise, if the conversion overflows, the +| largest unsigned integer is returned. If the 'a' is negative, the result +| is rounded and zero is returned; values that do not round to zero will +| raise the inexact exception flag. +*----------------------------------------------------------------------------*/ + +uint64 float32_to_uint64(float32 a STATUS_PARAM) +{ + flag aSign; + int_fast16_t aExp, shiftCount; + uint32_t aSig; + uint64_t aSig64, aSigExtra; + a = float32_squash_input_denormal(a STATUS_VAR); + + aSig = extractFloat32Frac(a); + aExp = extractFloat32Exp(a); + aSign = extractFloat32Sign(a); + if ((aSign) && (aExp > 126)) { + float_raise(float_flag_invalid STATUS_VAR); + if (float32_is_any_nan(a)) { + return LIT64(0xFFFFFFFFFFFFFFFF); + } else { + return 0; + } + } + shiftCount = 0xBE - aExp; + if (aExp) { + aSig |= 0x00800000; + } + if (shiftCount < 0) { + float_raise(float_flag_invalid STATUS_VAR); + return LIT64(0xFFFFFFFFFFFFFFFF); + } + + aSig64 = aSig; + aSig64 <<= 40; + shift64ExtraRightJamming(aSig64, 0, shiftCount, &aSig64, &aSigExtra); + return roundAndPackUint64(aSign, aSig64, aSigExtra STATUS_VAR); +} + /*---------------------------------------------------------------------------- | Returns the result of converting the single-precision floating-point value | `a' to the 64-bit two's complement integer format. The conversion is diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index 78b165670d..eb81c3b0cc 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -295,6 +295,7 @@ int32 float32_to_int32_round_to_zero( float32 STATUS_PARAM ); uint32 float32_to_uint32( float32 STATUS_PARAM ); uint32 float32_to_uint32_round_to_zero( float32 STATUS_PARAM ); int64 float32_to_int64( float32 STATUS_PARAM ); +uint64 float32_to_uint64(float32 STATUS_PARAM); int64 float32_to_int64_round_to_zero( float32 STATUS_PARAM ); float64 float32_to_float64( float32 STATUS_PARAM ); floatx80 float32_to_floatx80( float32 STATUS_PARAM ); -- cgit v1.2.3-55-g7522 From 879d096b37b1233fec334bc2c2f569ac3b8fec9a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 7 Jan 2014 17:19:11 +0000 Subject: softfloat: Provide complete set of accessors for fp state Tidy up the get/set accessors for the fp state to add missing ones and make them all inline in softfloat.h rather than some inline and some not. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- fpu/softfloat.c | 15 --------------- include/fpu/softfloat.h | 39 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 36 insertions(+), 18 deletions(-) (limited to 'include/fpu/softfloat.h') diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 3232ce2547..4abcd36b15 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -59,21 +59,6 @@ these four paragraphs for those parts of this code that are retained. *----------------------------------------------------------------------------*/ #include "softfloat-specialize.h" -void set_float_rounding_mode(int val STATUS_PARAM) -{ - STATUS(float_rounding_mode) = val; -} - -void set_float_exception_flags(int val STATUS_PARAM) -{ - STATUS(float_exception_flags) = val; -} - -void set_floatx80_rounding_precision(int val STATUS_PARAM) -{ - STATUS(floatx80_rounding_precision) = val; -} - /*---------------------------------------------------------------------------- | Returns the fraction bits of the half-precision floating-point value `a'. *----------------------------------------------------------------------------*/ diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index eb81c3b0cc..a634a4ebff 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -180,12 +180,22 @@ typedef struct float_status { flag default_nan_mode; } float_status; -void set_float_rounding_mode(int val STATUS_PARAM); -void set_float_exception_flags(int val STATUS_PARAM); INLINE void set_float_detect_tininess(int val STATUS_PARAM) { STATUS(float_detect_tininess) = val; } +INLINE void set_float_rounding_mode(int val STATUS_PARAM) +{ + STATUS(float_rounding_mode) = val; +} +INLINE void set_float_exception_flags(int val STATUS_PARAM) +{ + STATUS(float_exception_flags) = val; +} +INLINE void set_floatx80_rounding_precision(int val STATUS_PARAM) +{ + STATUS(floatx80_rounding_precision) = val; +} INLINE void set_flush_to_zero(flag val STATUS_PARAM) { STATUS(flush_to_zero) = val; @@ -198,11 +208,34 @@ INLINE void set_default_nan_mode(flag val STATUS_PARAM) { STATUS(default_nan_mode) = val; } +INLINE int get_float_detect_tininess(float_status *status) +{ + return STATUS(float_detect_tininess); +} +INLINE int get_float_rounding_mode(float_status *status) +{ + return STATUS(float_rounding_mode); +} INLINE int get_float_exception_flags(float_status *status) { return STATUS(float_exception_flags); } -void set_floatx80_rounding_precision(int val STATUS_PARAM); +INLINE int get_floatx80_rounding_precision(float_status *status) +{ + return STATUS(floatx80_rounding_precision); +} +INLINE flag get_flush_to_zero(float_status *status) +{ + return STATUS(flush_to_zero); +} +INLINE flag get_flush_inputs_to_zero(float_status *status) +{ + return STATUS(flush_inputs_to_zero); +} +INLINE flag get_default_nan_mode(float_status *status) +{ + return STATUS(default_nan_mode); +} /*---------------------------------------------------------------------------- | Routine to raise any or all of the software IEC/IEEE floating-point -- cgit v1.2.3-55-g7522 From 14c9a07eb9cae3d3bc1d39cc8815dd88337ce07a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 7 Jan 2014 17:19:12 +0000 Subject: softfloat: Add float16 <=> float64 conversion functions Add the conversion functions float16_to_float64() and float64_to_float16(), which will be needed for the ARM A64 instruction set. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- fpu/softfloat.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++ include/fpu/softfloat.h | 2 ++ 2 files changed, 77 insertions(+) (limited to 'include/fpu/softfloat.h') diff --git a/fpu/softfloat.c b/fpu/softfloat.c index c63e011ae8..d4ca7cf7f1 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -3281,6 +3281,81 @@ float16 float32_to_float16(float32 a, flag ieee STATUS_PARAM) return roundAndPackFloat16(aSign, aExp, aSig, ieee STATUS_VAR); } +float64 float16_to_float64(float16 a, flag ieee STATUS_PARAM) +{ + flag aSign; + int_fast16_t aExp; + uint32_t aSig; + + aSign = extractFloat16Sign(a); + aExp = extractFloat16Exp(a); + aSig = extractFloat16Frac(a); + + if (aExp == 0x1f && ieee) { + if (aSig) { + return commonNaNToFloat64( + float16ToCommonNaN(a STATUS_VAR) STATUS_VAR); + } + return packFloat64(aSign, 0x7ff, 0); + } + if (aExp == 0) { + if (aSig == 0) { + return packFloat64(aSign, 0, 0); + } + + normalizeFloat16Subnormal(aSig, &aExp, &aSig); + aExp--; + } + return packFloat64(aSign, aExp + 0x3f0, ((uint64_t)aSig) << 42); +} + +float16 float64_to_float16(float64 a, flag ieee STATUS_PARAM) +{ + flag aSign; + int_fast16_t aExp; + uint64_t aSig; + uint32_t zSig; + + a = float64_squash_input_denormal(a STATUS_VAR); + + aSig = extractFloat64Frac(a); + aExp = extractFloat64Exp(a); + aSign = extractFloat64Sign(a); + if (aExp == 0x7FF) { + if (aSig) { + /* Input is a NaN */ + if (!ieee) { + float_raise(float_flag_invalid STATUS_VAR); + return packFloat16(aSign, 0, 0); + } + return commonNaNToFloat16( + float64ToCommonNaN(a STATUS_VAR) STATUS_VAR); + } + /* Infinity */ + if (!ieee) { + float_raise(float_flag_invalid STATUS_VAR); + return packFloat16(aSign, 0x1f, 0x3ff); + } + return packFloat16(aSign, 0x1f, 0); + } + shift64RightJamming(aSig, 29, &aSig); + zSig = aSig; + if (aExp == 0 && zSig == 0) { + return packFloat16(aSign, 0, 0); + } + /* Decimal point between bits 22 and 23. Note that we add the 1 bit + * even if the input is denormal; however this is harmless because + * the largest possible single-precision denormal is still smaller + * than the smallest representable half-precision denormal, and so we + * will end up ignoring aSig and returning via the "always return zero" + * codepath. + */ + zSig |= 0x00800000; + aExp -= 0x3F1; + + return roundAndPackFloat16(aSign, aExp, zSig, ieee STATUS_VAR); +} + /*---------------------------------------------------------------------------- | Returns the result of converting the double-precision floating-point value | `a' to the extended double-precision floating-point format. The conversion diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index a634a4ebff..83d324aca8 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -298,6 +298,8 @@ INLINE float64 uint16_to_float64(uint16_t v STATUS_PARAM) *----------------------------------------------------------------------------*/ float16 float32_to_float16( float32, flag STATUS_PARAM ); float32 float16_to_float32( float16, flag STATUS_PARAM ); +float16 float64_to_float16(float64 a, flag ieee STATUS_PARAM); +float64 float16_to_float64(float16 a, flag ieee STATUS_PARAM); /*---------------------------------------------------------------------------- | Software half-precision operations. -- cgit v1.2.3-55-g7522 From f9288a76f1819c2dbf8d2873aebab6aec0f461f5 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 7 Jan 2014 17:19:12 +0000 Subject: softfloat: Add support for ties-away rounding IEEE754-2008 specifies a new rounding mode: "roundTiesToAway: the floating-point number nearest to the infinitely precise result shall be delivered; if the two nearest floating-point numbers bracketing an unrepresentable infinitely precise result are equally near, the one with larger magnitude shall be delivered." Implement this new mode (it is needed for ARM). The general principle is that the required code is exactly like the ties-to-even code, except that we do not need to do the "in case of exact tie clear LSB to round-to-even", because the rounding operation naturally causes the exact tie to round up in magnitude. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson --- fpu/softfloat.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ include/fpu/softfloat.h | 3 ++- 2 files changed, 56 insertions(+), 1 deletion(-) (limited to 'include/fpu/softfloat.h') diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 6c7a90a054..e0ea599769 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -111,6 +111,7 @@ static int32 roundAndPackInt32( flag zSign, uint64_t absZ STATUS_PARAM) roundNearestEven = ( roundingMode == float_round_nearest_even ); switch (roundingMode) { case float_round_nearest_even: + case float_round_ties_away: roundIncrement = 0x40; break; case float_round_to_zero: @@ -161,6 +162,7 @@ static int64 roundAndPackInt64( flag zSign, uint64_t absZ0, uint64_t absZ1 STATU roundNearestEven = ( roundingMode == float_round_nearest_even ); switch (roundingMode) { case float_round_nearest_even: + case float_round_ties_away: increment = ((int64_t) absZ1 < 0); break; case float_round_to_zero: @@ -214,6 +216,7 @@ static int64 roundAndPackUint64(flag zSign, uint64_t absZ0, roundNearestEven = (roundingMode == float_round_nearest_even); switch (roundingMode) { case float_round_nearest_even: + case float_round_ties_away: increment = ((int64_t)absZ1 < 0); break; case float_round_to_zero: @@ -366,6 +369,7 @@ static float32 roundAndPackFloat32(flag zSign, int_fast16_t zExp, uint32_t zSig roundNearestEven = ( roundingMode == float_round_nearest_even ); switch (roundingMode) { case float_round_nearest_even: + case float_round_ties_away: roundIncrement = 0x40; break; case float_round_to_zero: @@ -550,6 +554,7 @@ static float64 roundAndPackFloat64(flag zSign, int_fast16_t zExp, uint64_t zSig roundNearestEven = ( roundingMode == float_round_nearest_even ); switch (roundingMode) { case float_round_nearest_even: + case float_round_ties_away: roundIncrement = 0x200; break; case float_round_to_zero: @@ -734,6 +739,7 @@ static floatx80 zSig0 |= ( zSig1 != 0 ); switch (roundingMode) { case float_round_nearest_even: + case float_round_ties_away: break; case float_round_to_zero: roundIncrement = 0; @@ -794,6 +800,7 @@ static floatx80 precision80: switch (roundingMode) { case float_round_nearest_even: + case float_round_ties_away: increment = ((int64_t)zSig1 < 0); break; case float_round_to_zero: @@ -838,6 +845,7 @@ static floatx80 if ( zSig1 ) STATUS(float_exception_flags) |= float_flag_inexact; switch (roundingMode) { case float_round_nearest_even: + case float_round_ties_away: increment = ((int64_t)zSig1 < 0); break; case float_round_to_zero: @@ -1052,6 +1060,7 @@ static float128 roundNearestEven = ( roundingMode == float_round_nearest_even ); switch (roundingMode) { case float_round_nearest_even: + case float_round_ties_away: increment = ((int64_t)zSig2 < 0); break; case float_round_to_zero: @@ -1114,6 +1123,7 @@ static float128 if ( isTiny && zSig2 ) float_raise( float_flag_underflow STATUS_VAR); switch (roundingMode) { case float_round_nearest_even: + case float_round_ties_away: increment = ((int64_t)zSig2 < 0); break; case float_round_to_zero: @@ -1785,6 +1795,11 @@ float32 float32_round_to_int( float32 a STATUS_PARAM) return packFloat32( aSign, 0x7F, 0 ); } break; + case float_round_ties_away: + if (aExp == 0x7E) { + return packFloat32(aSign, 0x7F, 0); + } + break; case float_round_down: return make_float32(aSign ? 0xBF800000 : 0); case float_round_up: @@ -1803,6 +1818,9 @@ float32 float32_round_to_int( float32 a STATUS_PARAM) z &= ~lastBitMask; } break; + case float_round_ties_away: + z += lastBitMask >> 1; + break; case float_round_to_zero: break; case float_round_up: @@ -3183,6 +3201,9 @@ static float32 roundAndPackFloat16(flag zSign, int_fast16_t zExp, increment = zSig & (increment << 1); } break; + case float_round_ties_away: + increment = (mask + 1) >> 1; + break; case float_round_up: increment = zSign ? 0 : mask; break; @@ -3487,6 +3508,11 @@ float64 float64_round_to_int( float64 a STATUS_PARAM ) return packFloat64( aSign, 0x3FF, 0 ); } break; + case float_round_ties_away: + if (aExp == 0x3FE) { + return packFloat64(aSign, 0x3ff, 0); + } + break; case float_round_down: return make_float64(aSign ? LIT64( 0xBFF0000000000000 ) : 0); case float_round_up: @@ -3506,6 +3532,9 @@ float64 float64_round_to_int( float64 a STATUS_PARAM ) z &= ~lastBitMask; } break; + case float_round_ties_away: + z += lastBitMask >> 1; + break; case float_round_to_zero: break; case float_round_up: @@ -4771,6 +4800,11 @@ floatx80 floatx80_round_to_int( floatx80 a STATUS_PARAM ) packFloatx80( aSign, 0x3FFF, LIT64( 0x8000000000000000 ) ); } break; + case float_round_ties_away: + if (aExp == 0x3FFE) { + return packFloatx80(aSign, 0x3FFF, LIT64(0x8000000000000000)); + } + break; case float_round_down: return aSign ? @@ -4794,6 +4828,9 @@ floatx80 floatx80_round_to_int( floatx80 a STATUS_PARAM ) z.low &= ~lastBitMask; } break; + case float_round_ties_away: + z.low += lastBitMask >> 1; + break; case float_round_to_zero: break; case float_round_up: @@ -5862,6 +5899,15 @@ float128 float128_round_to_int( float128 a STATUS_PARAM ) } } break; + case float_round_ties_away: + if (lastBitMask) { + add128(z.high, z.low, 0, lastBitMask >> 1, &z.high, &z.low); + } else { + if ((int64_t) z.low < 0) { + ++z.high; + } + } + break; case float_round_to_zero: break; case float_round_up: @@ -5893,6 +5939,11 @@ float128 float128_round_to_int( float128 a STATUS_PARAM ) return packFloat128( aSign, 0x3FFF, 0, 0 ); } break; + case float_round_ties_away: + if (aExp == 0x3FFE) { + return packFloat128(aSign, 0x3FFF, 0, 0); + } + break; case float_round_down: return aSign ? packFloat128( 1, 0x3FFF, 0, 0 ) @@ -5916,6 +5967,9 @@ float128 float128_round_to_int( float128 a STATUS_PARAM ) z.high &= ~ lastBitMask; } break; + case float_round_ties_away: + z.high += lastBitMask>>1; + break; case float_round_to_zero: break; case float_round_up: diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index 83d324aca8..806ae13780 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -152,7 +152,8 @@ enum { float_round_nearest_even = 0, float_round_down = 1, float_round_up = 2, - float_round_to_zero = 3 + float_round_to_zero = 3, + float_round_ties_away = 4, }; /*---------------------------------------------------------------------------- -- cgit v1.2.3-55-g7522