diff --git a/qemu/fpu/softfloat.c b/qemu/fpu/softfloat.c index f303511e..e8fa08e0 100644 --- a/qemu/fpu/softfloat.c +++ b/qemu/fpu/softfloat.c @@ -611,6 +611,9 @@ static float64 roundAndPackFloat64(flag zSign, int zExp, uint64_t zSig, float_st case float_round_down: roundIncrement = zSign ? 0x3ff : 0; break; + case float_round_to_odd: + roundIncrement = (zSig & 0x400) ? 0 : 0x3ff; + break; default: abort(); } @@ -620,8 +623,10 @@ static float64 roundAndPackFloat64(flag zSign, int zExp, uint64_t zSig, float_st || ( ( zExp == 0x7FD ) && ( (int64_t) ( zSig + roundIncrement ) < 0 ) ) ) { + bool overflow_to_inf = roundingMode != float_round_to_odd && + roundIncrement != 0; float_raise(float_flag_overflow | float_flag_inexact, status); - return packFloat64( zSign, 0x7FF, - ( roundIncrement == 0 )); + return packFloat64(zSign, 0x7FF, -(!overflow_to_inf)); } if ( zExp < 0 ) { if (status->flush_to_zero) { @@ -638,6 +643,13 @@ static float64 roundAndPackFloat64(flag zSign, int zExp, uint64_t zSig, float_st if (isTiny && roundBits) { float_raise(float_flag_underflow, status); } + if (roundingMode == float_round_to_odd) { + /* + * For round-to-odd case, the roundIncrement depends on + * zSig which just changed. + */ + roundIncrement = (zSig & 0x400) ? 0 : 0x3ff; + } } } if ( roundBits ) status->float_exception_flags |= float_flag_inexact; @@ -1123,6 +1135,9 @@ static float128 case float_round_down: increment = zSign && zSig2; break; + case float_round_to_odd: + increment = !(zSig1 & 0x1) && zSig2; + break; default: abort(); } @@ -1142,6 +1157,7 @@ static float128 if ( ( roundingMode == float_round_to_zero ) || ( zSign && ( roundingMode == float_round_up ) ) || ( ! zSign && ( roundingMode == float_round_down ) ) + || (roundingMode == float_round_to_odd) ) { return packFloat128( @@ -1188,6 +1204,9 @@ static float128 case float_round_down: increment = zSign && zSig2; break; + case float_round_to_odd: + increment = !(zSig1 & 0x1) && zSig2; + break; default: abort(); } diff --git a/qemu/include/fpu/softfloat.h b/qemu/include/fpu/softfloat.h index f17daaa8..d121bcfe 100644 --- a/qemu/include/fpu/softfloat.h +++ b/qemu/include/fpu/softfloat.h @@ -188,6 +188,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, }; /*----------------------------------------------------------------------------