From b7761beee9c8f5025b1835bdc8cf360fb7270d93 Mon Sep 17 00:00:00 2001 From: Andrew Church Date: Sun, 18 Jan 2015 07:02:50 +0900 Subject: [PATCH] Fix lfs/stfs with SNaNs. --- rpcs3/Emu/Cell/PPUInterpreter.h | 92 ++++++++++++++++++++++++++++++--- rpcs3/Emu/Cell/PPUThread.h | 4 ++ 2 files changed, 88 insertions(+), 8 deletions(-) diff --git a/rpcs3/Emu/Cell/PPUInterpreter.h b/rpcs3/Emu/Cell/PPUInterpreter.h index 868cb4252f..31bddf28e0 100644 --- a/rpcs3/Emu/Cell/PPUInterpreter.h +++ b/rpcs3/Emu/Cell/PPUInterpreter.h @@ -3059,7 +3059,16 @@ private: void LFSX(u32 frd, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - CPU.FPR[frd] = vm::get_ref>(vm::cast(addr)).value(); + float val = vm::get_ref>(vm::cast(addr)).value(); + if (!FPRdouble::IsNaN(val)) + { + CPU.FPR[frd] = val; + } + else + { + u64 bits = (u32&)val; + (u64&)CPU.FPR[frd] = (bits & 0x80000000) << 32 | 7ULL << 60 | (bits & 0x7fffffff) << 29; + } } void SRW(u32 ra, u32 rs, u32 rb, bool rc) { @@ -3120,7 +3129,16 @@ private: void LFSUX(u32 frd, u32 ra, u32 rb) { const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - CPU.FPR[frd] = vm::get_ref>(vm::cast(addr)).value(); + float val = vm::get_ref>(vm::cast(addr)).value(); + if (!FPRdouble::IsNaN(val)) + { + CPU.FPR[frd] = val; + } + else + { + u64 bits = (u32&)val; + (u64&)CPU.FPR[frd] = (bits & 0x80000000) << 32 | 7ULL << 60 | (bits & 0x7fffffff) << 29; + } CPU.GPR[ra] = addr; } void SYNC(u32 l) @@ -3176,7 +3194,17 @@ private: void STFSX(u32 frs, u32 ra, u32 rb) { const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; - vm::get_ref>(vm::cast(addr)) = (float)CPU.FPR[frs]; + double val = CPU.FPR[frs]; + if (!FPRdouble::IsNaN(val)) + { + vm::get_ref>(vm::cast(addr)) = (float)val; + } + else + { + u64 bits = (u64&)val; + u32 bits32 = (bits>>32 & 0x80000000) | (bits>>29 & 0x7fffffff); + vm::get_ref>(vm::cast(addr)) = (float)bits32; + } } void STVRX(u32 vs, u32 ra, u32 rb) { @@ -3188,7 +3216,17 @@ private: void STFSUX(u32 frs, u32 ra, u32 rb) { const u64 addr = CPU.GPR[ra] + CPU.GPR[rb]; - vm::get_ref>(vm::cast(addr)) = (float)CPU.FPR[frs]; + double val = CPU.FPR[frs]; + if (!FPRdouble::IsNaN(val)) + { + vm::get_ref>(vm::cast(addr)) = (float)val; + } + else + { + u64 bits = (u64&)val; + u32 bits32 = (bits>>32 & 0x80000000) | (bits>>29 & 0x7fffffff); + vm::get_ref>(vm::cast(addr)) = (float)bits32; + } CPU.GPR[ra] = addr; } void STSWI(u32 rd, u32 ra, u32 nb) @@ -3459,12 +3497,30 @@ private: void LFS(u32 frd, u32 ra, s32 d) { const u64 addr = ra ? CPU.GPR[ra] + d : d; - CPU.FPR[frd] = vm::get_ref>(vm::cast(addr)).value(); + float val = vm::get_ref>(vm::cast(addr)).value(); + if (!FPRdouble::IsNaN(val)) + { + CPU.FPR[frd] = val; + } + else + { + u64 bits = (u32&)val; + (u64&)CPU.FPR[frd] = (bits & 0x80000000) << 32 | 7ULL << 60 | (bits & 0x7fffffff) << 29; + } } void LFSU(u32 frd, u32 ra, s32 ds) { const u64 addr = CPU.GPR[ra] + ds; - CPU.FPR[frd] = vm::get_ref>(vm::cast(addr)).value(); + float val = vm::get_ref>(vm::cast(addr)).value(); + if (!FPRdouble::IsNaN(val)) + { + CPU.FPR[frd] = val; + } + else + { + u64 bits = (u32&)val; + (u64&)CPU.FPR[frd] = (bits & 0x80000000) << 32 | 7ULL << 60 | (bits & 0x7fffffff) << 29; + } CPU.GPR[ra] = addr; } void LFD(u32 frd, u32 ra, s32 d) @@ -3481,12 +3537,32 @@ private: void STFS(u32 frs, u32 ra, s32 d) { const u64 addr = ra ? CPU.GPR[ra] + d : d; - vm::get_ref>(vm::cast(addr)) = (float)CPU.FPR[frs]; + double val = CPU.FPR[frs]; + if (!FPRdouble::IsNaN(val)) + { + vm::get_ref>(vm::cast(addr)) = (float)val; + } + else + { + u64 bits = (u64&)val; + u32 bits32 = (bits>>32 & 0x80000000) | (bits>>29 & 0x7fffffff); + vm::get_ref>(vm::cast(addr)) = (float)bits32; + } } void STFSU(u32 frs, u32 ra, s32 d) { const u64 addr = CPU.GPR[ra] + d; - vm::get_ref>(vm::cast(addr)) = (float)CPU.FPR[frs]; + double val = CPU.FPR[frs]; + if (!FPRdouble::IsNaN(val)) + { + vm::get_ref>(vm::cast(addr)) = (float)val; + } + else + { + u64 bits = (u64&)val; + u32 bits32 = (bits>>32 & 0x80000000) | (bits>>29 & 0x7fffffff); + vm::get_ref>(vm::cast(addr)) = (float)bits32; + } CPU.GPR[ra] = addr; } void STFD(u32 frs, u32 ra, s32 d) diff --git a/rpcs3/Emu/Cell/PPUThread.h b/rpcs3/Emu/Cell/PPUThread.h index ebd8d4f7a1..8a503151e9 100644 --- a/rpcs3/Emu/Cell/PPUThread.h +++ b/rpcs3/Emu/Cell/PPUThread.h @@ -443,18 +443,22 @@ struct PPCdouble PPCdouble() : _u64(0) { + type = UpdateType(); } PPCdouble(double val) : _double(val) { + type = UpdateType(); } PPCdouble(u64 val) : _u64(val) { + type = UpdateType(); } PPCdouble(u32 val) : _u64(val) { + type = UpdateType(); } };