From ea35eeb72871996121f1b6474ee9c6e3b25dfa63 Mon Sep 17 00:00:00 2001 From: Flyinghead Date: Fri, 13 Jul 2018 12:02:32 +0200 Subject: [PATCH] Fix FTRC op in both interpreter and dynarec with respect to Inf and NaN The -ffast-math gcc option implies the -ffinite-math-only option, which produces wrong results with Inf and NaN. Use integer math to detect the sign of float numbers in FTRC to avoid these issues. Also the upper cut off value for conversion was apparently wrong. Also fixed the x86 dynarec but not tested. Fixes wrong car color in Tokyo Xtreme Racer car selection screen. --- core/hw/sh4/dyna/shil_canonical.h | 10 +++++----- core/hw/sh4/interpr/sh4_fpu.cpp | 15 +++++++++------ core/rec-x86/rec_x86_il.cpp | 4 ++-- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/core/hw/sh4/dyna/shil_canonical.h b/core/hw/sh4/dyna/shil_canonical.h index 68a7755aa..0dd421be9 100644 --- a/core/hw/sh4/dyna/shil_canonical.h +++ b/core/hw/sh4/dyna/shil_canonical.h @@ -677,9 +677,10 @@ shil_opc(cvt_f2i_t) shil_canonical ( u32,f1,(f32 f1), - if (f1 > 0x7FFFFFBF) - f1 = 0x7FFFFFBF; - return (s32)f1; + if (f1 > 2147483520.0f) // IEEE 754: 0x4effffff + return 0x7fffffff; + else + return (s32)f1; ) shil_compile @@ -687,7 +688,6 @@ shil_compile shil_cf_arg_f32(rs1); shil_cf(f1); shil_cf_rv_u32(rd); - //die(); ) shil_opc_end() @@ -1044,4 +1044,4 @@ SHIL_END #undef UN_OP_I #undef UN_OP_F #undef BIN_OP_FU -#undef shil_recimp \ No newline at end of file +#undef shil_recimp diff --git a/core/hw/sh4/interpr/sh4_fpu.cpp b/core/hw/sh4/interpr/sh4_fpu.cpp index a64b030c5..2d28687e2 100644 --- a/core/hw/sh4/interpr/sh4_fpu.cpp +++ b/core/hw/sh4/interpr/sh4_fpu.cpp @@ -628,22 +628,25 @@ sh4op(i1111_nnnn_0011_1101) if (fpscr.PR == 0) { u32 n = GetN(op); - fpul = (u32)(s32)min(fr[n],(float)0x7FFFFFBF); + fpul = (u32)(s32)min(fr[n], 2147483520.0f); // IEEE 754: 0x4effffff - if (fpul==0x80000000) //this is actually a x86-specific fix. I think ARM saturates + // Intel CPUs convert out of range float numbers to 0x80000000. Manually set the correct sign + if (fpul == 0x80000000) { - if (fr[n]>0) + if (*(int *)&fr[n] > 0) // Using integer math to avoid issues with Inf and NaN fpul--; } } else { u32 n = (op >> 9) & 0x07; - fpul = (u32)(s32)GetDR(n); + f64 f = GetDR(n); + fpul = (u32)(s32)f; - if (fpul==0x80000000) //this is actually a x86-specific fix. I think ARM saturates + // Intel CPUs convert out of range float numbers to 0x80000000. Manually set the correct sign + if (fpul == 0x80000000) { - if (GetDR(n)>0) + if (*(s64 *)&f > 0) // Using integer math to avoid issues with Inf and NaN fpul--; } } diff --git a/core/rec-x86/rec_x86_il.cpp b/core/rec-x86/rec_x86_il.cpp index 38bb27976..80d43bdc6 100644 --- a/core/rec-x86/rec_x86_il.cpp +++ b/core/rec-x86/rec_x86_il.cpp @@ -1453,7 +1453,7 @@ void ngen_opcode(RuntimeBlockInfo* block, shil_opcode* op,x86_block* x86e, bool verify(op->rs1.is_r32f()); verify(reg.IsAllocg(op->rd)); verify(reg.IsAllocf(op->rs1)); - static f32 sse_ftrc_saturate = 0x7FFFFFBF;//1.11111111111111111111111 << 31 + static f32 sse_ftrc_saturate = 2147483520.0f; // IEEE 754: 0x4effffff x86e->Emit(op_movaps, XMM0, reg.mapf(op->rs1)); x86e->Emit(op_minss, XMM0, &sse_ftrc_saturate); x86e->Emit(op_cvttss2si, reg.mapg(op->rd), XMM0); @@ -1536,4 +1536,4 @@ defaulty: } } -#endif \ No newline at end of file +#endif