diff --git a/include/gcc_vr4300/soft_float.h b/include/gcc_vr4300/soft_float.h new file mode 100644 index 0000000..37f67ec --- /dev/null +++ b/include/gcc_vr4300/soft_float.h @@ -0,0 +1,30 @@ +#ifndef GCC_VR4300_SOFT_FLOAT_H +#define GCC_VR4300_SOFT_FLOAT_H + +#include "types.h" + +static inline bool Fpcsr_IsEnabled_InvalidOperation(void) { + uint32_t fpcsr; + + __asm__("cfc1 %0, $31" : "=r"(fpcsr)); + + return (fpcsr & (1 << 11)) ? 1 : 0; +} + +/** + * Set the "Invalid operation" exception. + * + * If the "Enable bit" for this exception is turned on then the hardware will + * trigger the exception by itself. + */ +static inline void Fpcsr_SetCause_InvalidOperation(void) { + uint32_t fpcsr; + + __asm__("cfc1 %0, $31" : "=r"(fpcsr)); + + fpcsr |= (1 << 11); + + __asm__("ctc1 %0, $31" : : "r"(fpcsr)); +} + +#endif diff --git a/src/soft_float/int_from_float/__fixtfsi.c b/src/soft_float/int_from_float/__fixtfsi.c index 616b787..d0217af 100644 --- a/src/soft_float/int_from_float/__fixtfsi.c +++ b/src/soft_float/int_from_float/__fixtfsi.c @@ -3,6 +3,7 @@ #include "gcc_vr4300/types.h" #include "gcc_vr4300/export.h" +#include "gcc_vr4300/soft_float.h" #if ABI_N32 || ABI_N64 EXPORT(__fixtfsi); @@ -24,7 +25,6 @@ int32_t __fixtfsi(float128 a) { int32_t realExponent; bool mantissaIsZero; int32_t computedValue; - uint32_t truncantedMantissa; flt.ld = a; @@ -55,42 +55,26 @@ int32_t __fixtfsi(float128 a) { return 0; } + // If value if infinity, NaN or outside of `int32_t` range then trigger the "Invalid operation" exception + // If said exception is disabled then return `2^31 - 1` + if (encodedExponent == 0x7FFF) { // Infinity and NaN - if (mantissaIsZero) { - // Infinity, return max int - - // TODO: should this be handled in any other way? - - if (sign) { - return INT32_MIN; - } else { - return INT32_MAX; - } - } - - // NaN - return 0; // ? + Fpcsr_SetCause_InvalidOperation(); + return 0xFFFFFFFF; } - // TODO: Figure out proper way to handle values outside of the int32_t range - if (realExponent < 0) { // Value smaller than 1, truncate to zero (?) return 0; } if (realExponent > 31) { - // Value is larger than int32_t, return int max - - // TODO: should this be handled in any other way? + // Value is larger than int32_t - if (sign) { - return INT32_MIN; - } else { - return INT32_MAX; - } + Fpcsr_SetCause_InvalidOperation(); + return 0xFFFFFFFF; } if (mantissaIsZero) {