summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorPokechu22 <Pokechu022@gmail.com>2021-08-18 16:28:08 -0700
committerPokechu22 <Pokechu022@gmail.com>2021-08-22 17:07:44 -0700
commit779cd479bc7ddcaaa3826f54146ee6aef22310ee (patch)
tree6b2254df0bfab705e3514bdec433bbdee06848ad /Source/Core
parent3ee605d699bb970156b7f8e92a52d6293cf4da07 (diff)
DSPLLE: NEG can set the carry and overflow flags
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Core/DSP/Interpreter/DSPIntArithmetic.cpp15
-rw-r--r--Source/Core/Core/DSP/Jit/x64/DSPJitArithmetic.cpp31
2 files changed, 32 insertions, 14 deletions
diff --git a/Source/Core/Core/DSP/Interpreter/DSPIntArithmetic.cpp b/Source/Core/Core/DSP/Interpreter/DSPIntArithmetic.cpp
index 4cfa8d446e..c4319db554 100644
--- a/Source/Core/Core/DSP/Interpreter/DSPIntArithmetic.cpp
+++ b/Source/Core/Core/DSP/Interpreter/DSPIntArithmetic.cpp
@@ -704,18 +704,23 @@ void Interpreter::dec(const UDSPInstruction opc)
// 0111 110d xxxx xxxx
// Negate accumulator $acD.
//
-// flags out: --xx xx00
+// flags out: x-xx xxxx
+//
+// The carry flag is set only if $acD was zero.
+// The overflow flag is set only if $acD was 0x8000000000 (the minimum value),
+// as -INT_MIN is INT_MIN in two's complement. In both of these cases,
+// the value of $acD after the operation is the same as it was before.
void Interpreter::neg(const UDSPInstruction opc)
{
const u8 dreg = (opc >> 8) & 0x1;
- s64 acc = GetLongAcc(dreg);
- acc = 0 - acc;
+ const s64 acc = GetLongAcc(dreg);
+ const s64 res = 0 - acc;
ZeroWriteBackLog();
- SetLongAcc(dreg, acc);
- UpdateSR64(GetLongAcc(dreg));
+ SetLongAcc(dreg, res);
+ UpdateSR64Sub(0, acc, GetLongAcc(dreg));
}
// ABS $acD
diff --git a/Source/Core/Core/DSP/Jit/x64/DSPJitArithmetic.cpp b/Source/Core/Core/DSP/Jit/x64/DSPJitArithmetic.cpp
index e651bfb84f..1a9270cab1 100644
--- a/Source/Core/Core/DSP/Jit/x64/DSPJitArithmetic.cpp
+++ b/Source/Core/Core/DSP/Jit/x64/DSPJitArithmetic.cpp
@@ -1002,20 +1002,33 @@ void DSPEmitter::dec(const UDSPInstruction opc)
// 0111 110d xxxx xxxx
// Negate accumulator $acD.
//
-// flags out: --xx xx00
+// flags out: x-xx xxxx
+//
+// The carry flag is set only if $acD was zero.
+// The overflow flag is set only if $acD was 0x8000000000 (the minimum value),
+// as -INT_MIN is INT_MIN in two's complement. In both of these cases,
+// the value of $acD after the operation is the same as it was before.
void DSPEmitter::neg(const UDSPInstruction opc)
{
u8 dreg = (opc >> 8) & 0x1;
- // s64 acc = dsp_get_long_acc(dreg);
- get_long_acc(dreg);
- // acc = 0 - acc;
- NEG(64, R(RAX));
- // dsp_set_long_acc(dreg, acc);
- set_long_acc(dreg);
- // Update_SR_Register64(dsp_get_long_acc(dreg));
+ // const s64 acc = GetLongAcc(dreg);
+ X64Reg acc = RAX;
+ get_long_acc(dreg, acc);
+ // const s64 res = 0 - acc;
+ X64Reg res = RCX;
+ MOV(64, R(res), R(acc));
+ NEG(64, R(res));
+ // SetLongAcc(dreg, res);
+ set_long_acc(dreg, res);
if (FlagsNeeded())
{
- Update_SR_Register64();
+ // UpdateSR64Sub(0, acc, GetLongAcc(dreg));
+ get_long_acc(dreg, res);
+ X64Reg imm_reg = RDX;
+ XOR(64, R(imm_reg), R(imm_reg));
+ X64Reg tmp1 = m_gpr.GetFreeXReg();
+ UpdateSR64Sub(imm_reg, acc, res, tmp1);
+ m_gpr.PutXReg(tmp1);
}
}