From 6bdcae816630f8ee79593a4b3fda7904bca620c9 Mon Sep 17 00:00:00 2001 From: ferris Date: Sun, 29 Jan 2017 15:53:35 +0100 Subject: [PATCH] Attempted to fix minor FP inaccuracies I'm still somewhat convinced that the bugs in space invaders, vertical force, and virtual bowling all might be related to the FP implementation, as those games all started working when FP was introduced, and exhibit kinds of bugs that don't seem to appear in other games. I went through the CPU manual a bit to try and find some more details and noticed that when the results of addf.s and subf.s would be -0, the result would be rounded to 0. I also assumed this would apply to cmpf.s, but I could be wrong about that. This fix is implemented here, however, it didn't seem to affect the behavior of any of these games, so I'm not sure I want to merge to master, but I'd like to document this in a commit at least. I've also dug through the code a bit for the v810 emulation in both mame and mednafen. Mame appears to be even more sloppy about FP than we are; I have yet to actually test these games in that emulator, but I should to so to try and eliminate this as the possible cause for those bugs. Mednafen even goes so far as to emulate the FP operations in software. This seems a bit extreme, especially since the floats in the v810 are IEEE single conformant, but might not be the worst choice as far as generating exceptions is concerned (which we don't handle currently). Need to investigate further. --- src/nvc.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/nvc.rs b/src/nvc.rs index afdbc14..9b6b17b 100644 --- a/src/nvc.rs +++ b/src/nvc.rs @@ -619,7 +619,7 @@ impl Nvc { OPCODE_BITS_SUB_OP_CMPF_S => { let lhs = self.reg_gpr_float(reg2); let rhs = self.reg_gpr_float(reg1); - let value = lhs - rhs; + let value = self.fix_fp_sign(lhs - rhs); self.set_fp_flags(value); @@ -645,7 +645,7 @@ impl Nvc { OPCODE_BITS_SUB_OP_ADDF_S => { let lhs = self.reg_gpr_float(reg2); let rhs = self.reg_gpr_float(reg1); - let value = lhs + rhs; + let value = self.fix_fp_sign(lhs + rhs); self.set_reg_gpr_float(reg2, value); self.set_fp_flags(value); @@ -655,7 +655,7 @@ impl Nvc { OPCODE_BITS_SUB_OP_SUBF_S => { let lhs = self.reg_gpr_float(reg2); let rhs = self.reg_gpr_float(reg1); - let value = lhs - rhs; + let value = self.fix_fp_sign(lhs - rhs); self.set_reg_gpr_float(reg2, value); self.set_fp_flags(value); @@ -791,6 +791,14 @@ impl Nvc { self.psw_sign = (value & 0x80000000) != 0; } + fn fix_fp_sign(&mut self, value: f32) -> f32 { + if value.abs() == 0.0 { + return 0.0; + } + + return value; + } + fn set_fp_flags(&mut self, value: f32) { self.psw_carry = value.is_sign_negative(); self.psw_overflow = false;