From 9ee6f678f473007e252934d6acd09c24490d9d42 Mon Sep 17 00:00:00 2001 From: Bharata B Rao Date: Fri, 10 Feb 2017 12:53:05 +0530 Subject: softfloat: Add round-to-odd rounding mode Power ISA 3.0 introduces a few quadruple precision floating point instructions that support round-to-odd rounding mode. The round-to-odd mode is explained as under: Let Z be the intermediate arithmetic result or the operand of a convert operation. If Z can be represented exactly in the target format, the result is Z. Otherwise the result is either Z1 or Z2 whichever is odd. Here Z1 and Z2 are the next larger and smaller numbers representable in the target format respectively. Signed-off-by: Bharata B Rao Reviewed-by: Peter Maydell Reviewed-by: Richard Henderson Signed-off-by: David Gibson --- include/fpu/softfloat.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/fpu/softfloat.h') diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index 842ec6b22a..8a39028664 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -180,6 +180,8 @@ enum { float_round_up = 2, float_round_to_zero = 3, float_round_ties_away = 4, + /* Not an IEEE rounding mode: round to the closest odd mantissa value */ + float_round_to_odd = 5, }; /*---------------------------------------------------------------------------- -- cgit v1.2.3-55-g7522 From 2e6d85683576c970c714c1cc071dca742835b9d4 Mon Sep 17 00:00:00 2001 From: Bharata B Rao Date: Fri, 10 Feb 2017 12:53:06 +0530 Subject: softfloat: Add float128_to_uint64_round_to_zero() Implement float128_to_uint64() and use that to implement float128_to_uint64_round_to_zero() This is required by xscvqpudz instruction of PowerPC ISA 3.0. Signed-off-by: Bharata B Rao Reviewed-by: Peter Maydell Signed-off-by: David Gibson --- fpu/softfloat.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++ include/fpu/softfloat.h | 2 ++ 2 files changed, 61 insertions(+) (limited to 'include/fpu/softfloat.h') diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 5ccba76481..47e4646570 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -6127,6 +6127,65 @@ int64_t float128_to_int64_round_to_zero(float128 a, float_status *status) } +/*---------------------------------------------------------------------------- +| Returns the result of converting the quadruple-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 +| positive integer is returned. If the conversion overflows, the +| largest unsigned integer is returned. If 'a' is negative, the value is +| rounded and zero is returned; negative values that do not round to zero +| will raise the inexact exception. +*----------------------------------------------------------------------------*/ + +uint64_t float128_to_uint64(float128 a, float_status *status) +{ + flag aSign; + int aExp; + int shiftCount; + uint64_t aSig0, aSig1; + + aSig0 = extractFloat128Frac0(a); + aSig1 = extractFloat128Frac1(a); + aExp = extractFloat128Exp(a); + aSign = extractFloat128Sign(a); + if (aSign && (aExp > 0x3FFE)) { + float_raise(float_flag_invalid, status); + if (float128_is_any_nan(a)) { + return LIT64(0xFFFFFFFFFFFFFFFF); + } else { + return 0; + } + } + if (aExp) { + aSig0 |= LIT64(0x0001000000000000); + } + shiftCount = 0x402F - aExp; + if (shiftCount <= 0) { + if (0x403E < aExp) { + float_raise(float_flag_invalid, status); + return LIT64(0xFFFFFFFFFFFFFFFF); + } + shortShift128Left(aSig0, aSig1, -shiftCount, &aSig0, &aSig1); + } else { + shift64ExtraRightJamming(aSig0, aSig1, shiftCount, &aSig0, &aSig1); + } + return roundAndPackUint64(aSign, aSig0, aSig1, status); +} + +uint64_t float128_to_uint64_round_to_zero(float128 a, float_status *status) +{ + uint64_t v; + signed char current_rounding_mode = status->float_rounding_mode; + + set_float_rounding_mode(float_round_to_zero, status); + v = float128_to_uint64(a, status); + set_float_rounding_mode(current_rounding_mode, status); + + return v; +} + /*---------------------------------------------------------------------------- | Returns the result of converting the quadruple-precision floating-point | value `a' to the single-precision floating-point format. The conversion diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index 8a39028664..a09ad0ea14 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -714,6 +714,8 @@ int32_t float128_to_int32(float128, float_status *status); int32_t float128_to_int32_round_to_zero(float128, float_status *status); int64_t float128_to_int64(float128, float_status *status); int64_t float128_to_int64_round_to_zero(float128, float_status *status); +uint64_t float128_to_uint64(float128, float_status *status); +uint64_t float128_to_uint64_round_to_zero(float128, float_status *status); float32 float128_to_float32(float128, float_status *status); float64 float128_to_float64(float128, float_status *status); floatx80 float128_to_floatx80(float128, float_status *status); -- cgit v1.2.3-55-g7522 From fd425037d25cecaaffdb3831697e0adc10ca2ba3 Mon Sep 17 00:00:00 2001 From: Bharata B Rao Date: Fri, 10 Feb 2017 12:53:07 +0530 Subject: softfloat: Add float128_to_uint32_round_to_zero() float128_to_uint32_round_to_zero() is needed by xscvqpuwz instruction of PowerPC ISA 3.0. Signed-off-by: Bharata B Rao Reviewed-by: Peter Maydell Signed-off-by: David Gibson --- fpu/softfloat.c | 28 ++++++++++++++++++++++++++++ include/fpu/softfloat.h | 1 + 2 files changed, 29 insertions(+) (limited to 'include/fpu/softfloat.h') diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 47e4646570..485a006aa7 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -6186,6 +6186,34 @@ uint64_t float128_to_uint64_round_to_zero(float128 a, float_status *status) return v; } +/*---------------------------------------------------------------------------- +| Returns the result of converting the quadruple-precision floating-point +| value `a' to the 32-bit unsigned integer format. The conversion +| is performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic except that the conversion is always rounded toward zero. +| If `a' is a NaN, the largest positive integer is returned. Otherwise, +| if the conversion overflows, the largest unsigned integer is returned. +| If 'a' is negative, the value is rounded and zero is returned; negative +| values that do not round to zero will raise the inexact exception. +*----------------------------------------------------------------------------*/ + +uint32_t float128_to_uint32_round_to_zero(float128 a, float_status *status) +{ + uint64_t v; + uint32_t res; + int old_exc_flags = get_float_exception_flags(status); + + v = float128_to_uint64_round_to_zero(a, status); + if (v > 0xffffffff) { + res = 0xffffffff; + } else { + return v; + } + set_float_exception_flags(old_exc_flags, status); + float_raise(float_flag_invalid, status); + return res; +} + /*---------------------------------------------------------------------------- | Returns the result of converting the quadruple-precision floating-point | value `a' to the single-precision floating-point format. The conversion diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index a09ad0ea14..f1288efa87 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -716,6 +716,7 @@ int64_t float128_to_int64(float128, float_status *status); int64_t float128_to_int64_round_to_zero(float128, float_status *status); uint64_t float128_to_uint64(float128, float_status *status); uint64_t float128_to_uint64_round_to_zero(float128, float_status *status); +uint32_t float128_to_uint32_round_to_zero(float128, float_status *status); float32 float128_to_float32(float128, float_status *status); float64 float128_to_float64(float128, float_status *status); floatx80 float128_to_floatx80(float128, float_status *status); -- cgit v1.2.3-55-g7522