From 95b0abb73709b23cf7fde37169420e4c22bd7f55 Mon Sep 17 00:00:00 2001 From: Marko Pusljar Date: Sun, 8 Aug 2010 16:35:10 +0000 Subject: [PATCH] dsplle - another small fix git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6075 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/DSPCore/Src/DSPCore.h | 2 +- Source/Core/DSPCore/Src/DSPIntUtil.h | 34 ++++++++++++++++---- Source/Core/DSPCore/Src/DspIntArithmetic.cpp | 3 +- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/Source/Core/DSPCore/Src/DSPCore.h b/Source/Core/DSPCore/Src/DSPCore.h index 92cb8516bf..aa14272447 100644 --- a/Source/Core/DSPCore/Src/DSPCore.h +++ b/Source/Core/DSPCore/Src/DSPCore.h @@ -163,7 +163,7 @@ #define SR_INT_ENABLE 0x0200 // Not 100% sure but duddie says so. This should replace the hack, if so. #define SR_400 0x0400 // unknown #define SR_EXT_INT_ENABLE 0x0800 // Appears in zelda - seems to disable external interupts -#define SR_1000 0x1000 // unknown +#define SR_ROUNDING_MODE 0x1000 // 0 - convergent rounding, 1 - twos complement rounding (source: motorola DSP56?00FM.pdf-s) #define SR_MUL_MODIFY 0x2000 // 1 = normal. 0 = x2 (M0, M2) #define SR_40_MODE_BIT 0x4000 // 0 = "16", 1 = "40" (SET16, SET40) Controls sign extension when loading mid accums. #define SR_MUL_UNSIGNED 0x8000 // 0 = normal. 1 = unsigned (CLR15, SET15) If set, treats operands as unsigned. Tested with mulx only so far. diff --git a/Source/Core/DSPCore/Src/DSPIntUtil.h b/Source/Core/DSPCore/Src/DSPIntUtil.h index 4c19b5955a..fa0c0e3ebe 100644 --- a/Source/Core/DSPCore/Src/DSPIntUtil.h +++ b/Source/Core/DSPCore/Src/DSPIntUtil.h @@ -160,11 +160,6 @@ inline void dsp_op_write_reg(int reg, u16 val) g_dsp.r[reg] = (u16)(s16)(s8)(u8)val; break; - case DSP_REG_ACM0: - case DSP_REG_ACM1: - g_dsp.r[reg] = val; - break; - // Stack registers. case DSP_REG_ST0: case DSP_REG_ST1: @@ -217,7 +212,19 @@ inline s64 dsp_get_long_prod() inline s64 dsp_get_long_prod_round_prodl() { - return (dsp_get_long_prod() + 0x7fff) & ~0xffff; + s64 prod = dsp_get_long_prod(); + + if (g_dsp.r[DSP_REG_SR] & SR_ROUNDING_MODE) + prod = (prod + 0x8000) & ~0xffff; + else + { + if (prod & 0x10000) + prod = (prod + 0x8000) & ~0xffff; + else + prod = (prod + 0x7fff) & ~0xffff; + } + + return prod; } // For accurate emulation, this is wrong - but the real prod registers behave @@ -271,6 +278,21 @@ inline s64 dsp_convert_long_acc(s64 val) // s64 -> s40 return ((s64)(s8)(val >> 32))<<32 | (u32)val; } +inline s64 dsp_round_long_acc(s64 val) +{ + if (g_dsp.r[DSP_REG_SR] & SR_ROUNDING_MODE) + val = (val + 0x8000) & ~0xffff; + else + { + if (val & 0x10000) + val = (val + 0x8000) & ~0xffff; + else + val = (val + 0x7fff) & ~0xffff; + } + + return val; +} + inline s16 dsp_get_acc_l(int _reg) { _assert_(_reg < 2); diff --git a/Source/Core/DSPCore/Src/DspIntArithmetic.cpp b/Source/Core/DSPCore/Src/DspIntArithmetic.cpp index 480317e8c5..7bc5e4b4ed 100644 --- a/Source/Core/DSPCore/Src/DspIntArithmetic.cpp +++ b/Source/Core/DSPCore/Src/DspIntArithmetic.cpp @@ -47,8 +47,7 @@ void clr(const UDSPInstruction opc) void clrl(const UDSPInstruction opc) { u8 reg = (opc >> 8) & 0x1; - - s64 acc = (dsp_get_long_acc(reg) + 0x7fff) & ~0xffff; + s64 acc = dsp_round_long_acc(dsp_get_long_acc(reg)); zeroWriteBackLog();