From 3ee605d699bb970156b7f8e92a52d6293cf4da07 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Thu, 19 Aug 2021 17:12:23 -0700 Subject: [PATCH] DSPJit: Rework overflow and carry handling --- Source/Core/Core/DSP/Jit/x64/DSPEmitter.h | 12 +- .../Core/DSP/Jit/x64/DSPJitArithmetic.cpp | 690 +++++++++--------- Source/Core/Core/DSP/Jit/x64/DSPJitCCUtil.cpp | 55 +- .../Core/DSP/Jit/x64/DSPJitMultiplier.cpp | 5 +- Source/Core/Core/DSP/Jit/x64/DSPJitUtil.cpp | 10 +- 5 files changed, 390 insertions(+), 382 deletions(-) diff --git a/Source/Core/Core/DSP/Jit/x64/DSPEmitter.h b/Source/Core/Core/DSP/Jit/x64/DSPEmitter.h index ee74def463..05d52abe51 100644 --- a/Source/Core/Core/DSP/Jit/x64/DSPEmitter.h +++ b/Source/Core/Core/DSP/Jit/x64/DSPEmitter.h @@ -228,6 +228,7 @@ private: void get_long_prod(Gen::X64Reg long_prod = Gen::RAX); void get_long_prod_round_prodl(Gen::X64Reg long_prod = Gen::RAX); void set_long_prod(); + void dsp_convert_long_acc(Gen::X64Reg long_acc); // s64 -> s40 void round_long_acc(Gen::X64Reg long_acc = Gen::EAX); void set_long_acc(int _reg, Gen::X64Reg acc = Gen::EAX); void get_acc_h(int _reg, Gen::X64Reg acc = Gen::EAX, bool sign = true); @@ -246,7 +247,16 @@ private: // CC helpers void Update_SR_Register64(Gen::X64Reg val = Gen::EAX, Gen::X64Reg scratch = Gen::EDX); - void Update_SR_Register64_Carry(Gen::X64Reg val, Gen::X64Reg carry_ovfl, bool carry_eq = false); + void UpdateSR64AddSub(Gen::X64Reg val1, Gen::X64Reg val2, Gen::X64Reg result, Gen::X64Reg scratch, + bool subtract); + void UpdateSR64Add(Gen::X64Reg val1, Gen::X64Reg val2, Gen::X64Reg result, Gen::X64Reg scratch) + { + UpdateSR64AddSub(val1, val2, result, scratch, false); + } + void UpdateSR64Sub(Gen::X64Reg val1, Gen::X64Reg val2, Gen::X64Reg result, Gen::X64Reg scratch) + { + UpdateSR64AddSub(val1, val2, result, scratch, true); + } void Update_SR_Register16(Gen::X64Reg val = Gen::EAX); void Update_SR_Register16_OverS32(Gen::X64Reg val = Gen::EAX); diff --git a/Source/Core/Core/DSP/Jit/x64/DSPJitArithmetic.cpp b/Source/Core/Core/DSP/Jit/x64/DSPJitArithmetic.cpp index 633b714124..e651bfb84f 100644 --- a/Source/Core/Core/DSP/Jit/x64/DSPJitArithmetic.cpp +++ b/Source/Core/Core/DSP/Jit/x64/DSPJitArithmetic.cpp @@ -64,18 +64,19 @@ void DSPEmitter::andcf(const UDSPInstruction opc) if (FlagsNeeded()) { const u8 reg = (opc >> 8) & 0x1; - // u16 imm = dsp_fetch_code(); + // const u16 imm = m_dsp_core.DSPState().FetchInstruction(); const u16 imm = m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1); - // u16 val = dsp_get_acc_m(reg); - get_acc_m(reg); - // Update_SR_LZ(((val & imm) == imm) ? true : false); - // if ((val & imm) == imm) - // g_dsp.r.sr |= SR_LOGIC_ZERO; - // else - // g_dsp.r.sr &= ~SR_LOGIC_ZERO; + // const u16 val = GetAccMid(reg); + X64Reg val = RAX; + get_acc_m(reg, val); + // UpdateSRLogicZero((val & imm) == imm); + // if ((val & imm) == imm) + // g_dsp.r.sr |= SR_LOGIC_ZERO; + // else + // g_dsp.r.sr &= ~SR_LOGIC_ZERO; const OpArg sr_reg = m_gpr.GetReg(DSP_REG_SR); - AND(16, R(RAX), Imm16(imm)); - CMP(16, R(RAX), Imm16(imm)); + AND(16, R(val), Imm16(imm)); + CMP(16, R(val), Imm16(imm)); FixupBranch notLogicZero = J_CC(CC_NE); OR(16, sr_reg, Imm16(SR_LOGIC_ZERO)); FixupBranch exit = J(); @@ -99,17 +100,18 @@ void DSPEmitter::andf(const UDSPInstruction opc) if (FlagsNeeded()) { const u8 reg = (opc >> 8) & 0x1; - // u16 imm = dsp_fetch_code(); + // const u16 imm = m_dsp_core.DSPState().FetchInstruction(); const u16 imm = m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1); - // u16 val = dsp_get_acc_m(reg); - get_acc_m(reg); - // Update_SR_LZ(((val & imm) == 0) ? true : false); - // if ((val & imm) == 0) - // g_dsp.r.sr |= SR_LOGIC_ZERO; - // else - // g_dsp.r.sr &= ~SR_LOGIC_ZERO; + // const u16 val = GetAccMid(reg); + X64Reg val = RAX; + get_acc_m(reg, val); + // UpdateSRLogicZero((val & imm) == 0); + // if ((val & imm) == 0) + // g_dsp.r.sr |= SR_LOGIC_ZERO; + // else + // g_dsp.r.sr &= ~SR_LOGIC_ZERO; const OpArg sr_reg = m_gpr.GetReg(DSP_REG_SR); - TEST(16, R(RAX), Imm16(imm)); + TEST(16, R(val), Imm16(imm)); FixupBranch notLogicZero = J_CC(CC_NE); OR(16, sr_reg, Imm16(SR_LOGIC_ZERO)); FixupBranch exit = J(); @@ -167,18 +169,21 @@ void DSPEmitter::cmp(const UDSPInstruction opc) { if (FlagsNeeded()) { + // const s64 acc0 = GetLongAcc(0); + X64Reg acc0 = RAX; + get_long_acc(0, acc0); + // const s64 acc1 = GetLongAcc(1); + X64Reg acc1 = RDX; + get_long_acc(1, acc1); + // s64 res = dsp_convert_long_acc(acc0 - acc1); + X64Reg res = RCX; + MOV(64, R(res), R(acc0)); + SUB(64, R(res), R(acc1)); + dsp_convert_long_acc(RCX); + + // UpdateSR64Sub(acc0, acc1, res); X64Reg tmp1 = m_gpr.GetFreeXReg(); - // s64 acc0 = dsp_get_long_acc(0); - get_long_acc(0, tmp1); - MOV(64, R(RAX), R(tmp1)); - // s64 acc1 = dsp_get_long_acc(1); - get_long_acc(1, RDX); - // s64 res = dsp_convert_long_acc(acc0 - acc1); - SUB(64, R(RAX), R(RDX)); - // Update_SR_Register64(res, isCarry2(acc0, res), isOverflow(acc0, -acc1, res)); // CF -> - // influence on ABS/0xa100 - NEG(64, R(RDX)); - Update_SR_Register64_Carry(EAX, tmp1, true); + UpdateSR64Sub(acc0, acc1, res, tmp1); m_gpr.PutXReg(tmp1); } } @@ -195,19 +200,22 @@ void DSPEmitter::cmpar(const UDSPInstruction opc) u8 rreg = ((opc >> 12) & 0x1); u8 sreg = (opc >> 11) & 0x1; + // const s64 acc = GetLongAcc(sreg); + X64Reg acc = RAX; + get_long_acc(sreg, acc); + // s64 ax = GetAXHigh(rreg); + X64Reg ax = RDX; + get_ax_h(rreg, ax); + // ax <<= 16; + SHL(64, R(ax), Imm8(16)); + // const s64 res = dsp_convert_long_acc(acc - ax); + X64Reg res = RCX; + MOV(64, R(res), R(acc)); + SUB(64, R(res), R(ax)); + dsp_convert_long_acc(res); + // UpdateSR64Sub(acc, ax, res); X64Reg tmp1 = m_gpr.GetFreeXReg(); - // s64 sr = dsp_get_long_acc(sreg); - get_long_acc(sreg, tmp1); - MOV(64, R(RAX), R(tmp1)); - // s64 rr = (s16)g_dsp.r.axh[rreg]; - get_ax_h(rreg, RDX); - // rr <<= 16; - SHL(64, R(RDX), Imm8(16)); - // s64 res = dsp_convert_long_acc(sr - rr); - SUB(64, R(RAX), R(RDX)); - // Update_SR_Register64(res, isCarry2(sr, res), isOverflow(sr, -rr, res)); - NEG(64, R(RDX)); - Update_SR_Register64_Carry(EAX, tmp1, true); + UpdateSR64Sub(acc, ax, res, tmp1); m_gpr.PutXReg(tmp1); } } @@ -224,19 +232,24 @@ void DSPEmitter::cmpi(const UDSPInstruction opc) if (FlagsNeeded()) { const u8 reg = (opc >> 8) & 0x1; - const X64Reg tmp1 = m_gpr.GetFreeXReg(); - // s64 val = dsp_get_long_acc(reg); - get_long_acc(reg, tmp1); - MOV(64, R(RAX), R(tmp1)); - // s64 imm = (s64)(s16)dsp_fetch_code() << 16; // Immediate is considered to be at M level in - // the 40-bit accumulator. - const u16 imm = m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1); - MOV(64, R(RDX), Imm64((s64)(s16)imm << 16)); - // s64 res = dsp_convert_long_acc(val - imm); - SUB(64, R(RAX), R(RDX)); - // Update_SR_Register64(res, isCarry2(val, res), isOverflow(val, -imm, res)); - NEG(64, R(RDX)); - Update_SR_Register64_Carry(EAX, tmp1, true); + // const s64 val = GetLongAcc(reg); + X64Reg val = RAX; + get_long_acc(reg, val); + // Immediate is considered to be at M level in the 40-bit accumulator. + // s64 imm = static_cast(state.FetchInstruction()); + // imm <<= 16; + X64Reg imm_reg = RDX; + s64 imm = static_cast(m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1)); + imm <<= 16; + MOV(64, R(imm_reg), Imm64(imm)); + // const s64 res = dsp_convert_long_acc(val - imm); + X64Reg res = RCX; + MOV(64, R(res), R(val)); + SUB(64, R(res), R(imm_reg)); + dsp_convert_long_acc(res); + // UpdateSR64Sub(val, imm, res); + X64Reg tmp1 = m_gpr.GetFreeXReg(); + UpdateSR64Sub(val, imm_reg, res, tmp1); m_gpr.PutXReg(tmp1); } } @@ -253,18 +266,23 @@ void DSPEmitter::cmpis(const UDSPInstruction opc) if (FlagsNeeded()) { u8 areg = (opc >> 8) & 0x1; - // s64 acc = dsp_get_long_acc(areg); + // const s64 acc = GetLongAcc(areg); + X64Reg acc = RAX; + get_long_acc(areg, acc); + // s64 imm = static_cast(opc); + // imm <<= 16; + X64Reg imm_reg = RDX; + s64 imm = static_cast(opc); + imm <<= 16; + MOV(64, R(imm_reg), Imm64(imm)); + // const s64 res = dsp_convert_long_acc(acc - imm); + X64Reg res = RCX; + MOV(64, R(res), R(acc)); + SUB(64, R(res), R(imm_reg)); + dsp_convert_long_acc(res); + // UpdateSR64Sub(acc, imm, res); X64Reg tmp1 = m_gpr.GetFreeXReg(); - get_long_acc(areg, tmp1); - MOV(64, R(RAX), R(tmp1)); - // s64 val = (s8)opc; - // val <<= 16; - MOV(64, R(RDX), Imm64((s64)(s8)opc << 16)); - // s64 res = dsp_convert_long_acc(acc - val); - SUB(64, R(RAX), R(RDX)); - // Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -val, res)); - NEG(64, R(RDX)); - Update_SR_Register64_Carry(EAX, tmp1, true); + UpdateSR64Sub(acc, imm_reg, res, tmp1); m_gpr.PutXReg(tmp1); } } @@ -521,29 +539,27 @@ void DSPEmitter::addr(const UDSPInstruction opc) u8 dreg = (opc >> 8) & 0x1; u8 sreg = ((opc >> 9) & 0x3) + DSP_REG_AXL0; - // s64 acc = dsp_get_long_acc(dreg); - X64Reg tmp1 = m_gpr.GetFreeXReg(); - get_long_acc(dreg, tmp1); - MOV(64, R(RAX), R(tmp1)); - // s64 ax = (s16)g_dsp.r[sreg]; - dsp_op_read_reg(sreg, RDX, RegisterExtension::Sign); - // ax <<= 16; - SHL(64, R(RDX), Imm8(16)); - // s64 res = acc + ax; - ADD(64, R(RAX), R(RDX)); - // dsp_set_long_acc(dreg, res); - // Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, ax, res)); + // const s64 acc = GetLongAcc(dreg); + X64Reg acc = RAX; + get_long_acc(dreg, acc); + // s64 ax = ...; + X64Reg ax = RDX; + dsp_op_read_reg(sreg, ax, RegisterExtension::Sign); + // ax <<= 16; + SHL(64, R(ax), Imm8(16)); + // const s64 res = acc + ax; + X64Reg res = RCX; + LEA(64, res, MRegSum(acc, ax)); + // SetLongAcc(dreg, res); + set_long_acc(dreg, res); if (FlagsNeeded()) { - MOV(64, R(RCX), R(RAX)); - set_long_acc(dreg, RCX); - Update_SR_Register64_Carry(EAX, tmp1); + // UpdateSR64Add(acc, ax, GetLongAcc(dreg)); + get_long_acc(dreg, res); + X64Reg tmp1 = m_gpr.GetFreeXReg(); + UpdateSR64Add(acc, ax, res, tmp1); + m_gpr.PutXReg(tmp1); } - else - { - set_long_acc(dreg, RAX); - } - m_gpr.PutXReg(tmp1); } // ADDAX $acD, $axS @@ -556,28 +572,25 @@ void DSPEmitter::addax(const UDSPInstruction opc) u8 dreg = (opc >> 8) & 0x1; u8 sreg = (opc >> 9) & 0x1; - X64Reg tmp1 = m_gpr.GetFreeXReg(); - // s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, tmp1); - MOV(64, R(RAX), R(tmp1)); - // s64 ax = dsp_get_long_acx(sreg); - get_long_acx(sreg, RDX); - // s64 res = acc + ax; - ADD(64, R(RAX), R(RDX)); - // dsp_set_long_acc(dreg, res); - // res = dsp_get_long_acc(dreg); - // Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, ax, res)); + // const s64 acc = GetLongAcc(dreg); + X64Reg acc = RAX; + get_long_acc(dreg, acc); + // const s64 ax = GetLongACX(sreg); + X64Reg ax = RDX; + get_long_acx(sreg, ax); + // const s64 res = acc + ax; + X64Reg res = RCX; + LEA(64, res, MRegSum(acc, ax)); + // SetLongAcc(dreg, res); + set_long_acc(dreg, res); if (FlagsNeeded()) { - MOV(64, R(RCX), R(RAX)); - set_long_acc(dreg, RCX); - Update_SR_Register64_Carry(EAX, tmp1); + // UpdateSR64Add(acc, ax, GetLongAcc(dreg)); + get_long_acc(dreg, res); + X64Reg tmp1 = m_gpr.GetFreeXReg(); + UpdateSR64Add(acc, ax, res, tmp1); + m_gpr.PutXReg(tmp1); } - else - { - set_long_acc(dreg, RAX); - } - m_gpr.PutXReg(tmp1); } // ADD $acD, $ac(1-D) @@ -589,28 +602,25 @@ void DSPEmitter::add(const UDSPInstruction opc) { u8 dreg = (opc >> 8) & 0x1; - X64Reg tmp1 = m_gpr.GetFreeXReg(); - // s64 acc0 = dsp_get_long_acc(dreg); - get_long_acc(dreg, tmp1); - MOV(64, R(RAX), R(tmp1)); - // s64 acc1 = dsp_get_long_acc(1 - dreg); - get_long_acc(1 - dreg, RDX); - // s64 res = acc0 + acc1; - ADD(64, R(RAX), R(RDX)); - // dsp_set_long_acc(dreg, res); - // res = dsp_get_long_acc(dreg); - // Update_SR_Register64(res, isCarry(acc0, res), isOverflow(acc0, acc1, res)); + // const s64 acc0 = GetLongAcc(dreg); + X64Reg acc0 = RAX; + get_long_acc(dreg, acc0); + // const s64 acc1 = GetLongAcc(1 - dreg); + X64Reg acc1 = RDX; + get_long_acc(1 - dreg, acc1); + // const s64 res = acc0 + acc1; + X64Reg res = RCX; + LEA(64, res, MRegSum(acc0, acc1)); + // SetLongAcc(dreg, res); + set_long_acc(dreg, res); if (FlagsNeeded()) { - MOV(64, R(RCX), R(RAX)); - set_long_acc(dreg, RCX); - Update_SR_Register64_Carry(EAX, tmp1); + // UpdateSR64Add(acc0, acc1, GetLongAcc(dreg)); + get_long_acc(dreg, res); + X64Reg tmp1 = m_gpr.GetFreeXReg(); + UpdateSR64Add(acc0, acc1, res, tmp1); + m_gpr.PutXReg(tmp1); } - else - { - set_long_acc(dreg, RAX); - } - m_gpr.PutXReg(tmp1); } // ADDP $acD @@ -622,28 +632,25 @@ void DSPEmitter::addp(const UDSPInstruction opc) { u8 dreg = (opc >> 8) & 0x1; - X64Reg tmp1 = m_gpr.GetFreeXReg(); - // s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, tmp1); - MOV(64, R(RAX), R(tmp1)); - // s64 prod = dsp_get_long_prod(); - get_long_prod(RDX); - // s64 res = acc + prod; - ADD(64, R(RAX), R(RDX)); - // dsp_set_long_acc(dreg, res); - // res = dsp_get_long_acc(dreg); - // Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, prod, res)); + // const s64 acc = GetLongAcc(dreg); + X64Reg acc = RAX; + get_long_acc(dreg, acc); + // const s64 prod = GetLongProduct(); + X64Reg prod = RDX; + get_long_prod(prod); + // const s64 res = acc + prod; + X64Reg res = RCX; + LEA(64, res, MRegSum(acc, prod)); + // SetLongAcc(dreg, res); + set_long_acc(dreg, res); if (FlagsNeeded()) { - MOV(64, R(RCX), R(RAX)); - set_long_acc(dreg, RCX); - Update_SR_Register64_Carry(EAX, tmp1); + // UpdateSR64Add(acc, prod, GetLongAcc(dreg)); + get_long_acc(dreg, res); + X64Reg tmp1 = m_gpr.GetFreeXReg(); + UpdateSR64Add(acc, prod, res, tmp1); + m_gpr.PutXReg(tmp1); } - else - { - set_long_acc(dreg, RAX); - } - m_gpr.PutXReg(tmp1); } // ADDAXL $acD, $axS.l @@ -657,29 +664,26 @@ void DSPEmitter::addaxl(const UDSPInstruction opc) u8 sreg = (opc >> 9) & 0x1; u8 dreg = (opc >> 8) & 0x1; - X64Reg tmp1 = m_gpr.GetFreeXReg(); - // u64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, tmp1); - MOV(64, R(RAX), R(tmp1)); - // u16 acx = (u16)dsp_get_ax_l(sreg); - get_ax_l(sreg, RDX); - MOVZX(64, 16, RDX, R(RDX)); - // u64 res = acc + acx; - ADD(64, R(RAX), R(RDX)); - // dsp_set_long_acc(dreg, (s64)res); - // res = dsp_get_long_acc(dreg); - // Update_SR_Register64((s64)res, isCarry(acc, res), isOverflow((s64)acc, (s64)acx, (s64)res)); + // const u64 acc = GetLongAcc(dreg); + X64Reg acc = RAX; + get_long_acc(dreg, acc); + // const u16 acx = static_cast(GetAXLow(sreg)); + X64Reg acx = RDX; + get_ax_l(sreg, acx); + MOVZX(64, 16, acx, R(acx)); + // const u64 res = acc + acx; + X64Reg res = RCX; + LEA(64, res, MRegSum(acc, acx)); + // SetLongAcc(dreg, static_cast(res)); + set_long_acc(dreg, res); if (FlagsNeeded()) { - MOV(64, R(RCX), R(RAX)); - set_long_acc(dreg, RCX); - Update_SR_Register64_Carry(EAX, tmp1); + // UpdateSR64Add(acc, acx, GetLongAcc(dreg)); + get_long_acc(dreg, res); + X64Reg tmp1 = m_gpr.GetFreeXReg(); + UpdateSR64Add(acc, acx, res, tmp1); + m_gpr.PutXReg(tmp1); } - else - { - set_long_acc(dreg, RAX); - } - m_gpr.PutXReg(tmp1); } // ADDI $amR, #I @@ -691,30 +695,30 @@ void DSPEmitter::addaxl(const UDSPInstruction opc) void DSPEmitter::addi(const UDSPInstruction opc) { u8 areg = (opc >> 8) & 0x1; - X64Reg tmp1 = m_gpr.GetFreeXReg(); - // s64 acc = dsp_get_long_acc(areg); - get_long_acc(areg, tmp1); - MOV(64, R(RAX), R(tmp1)); - // s64 imm = (s16)dsp_fetch_code(); - const s16 imm = m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1); + // const s64 acc = GetLongAcc(areg); + X64Reg acc = RAX; + get_long_acc(areg, acc); + // s64 imm = static_cast(state.FetchInstruction()); // imm <<= 16; - MOV(64, R(RDX), Imm32(imm << 16)); - // s64 res = acc + imm; - ADD(64, R(RAX), R(RDX)); - // dsp_set_long_acc(areg, res); - // res = dsp_get_long_acc(areg); - // Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, imm, res)); + s64 imm = static_cast(m_dsp_core.DSPState().ReadIMEM(m_compile_pc + 1)); + imm <<= 16; + // const s64 res = acc + imm; + X64Reg res = RCX; + // Can safely use LEA as we are using a 16-bit sign-extended immediate shifted left by 16, which + // fits in a signed 32-bit immediate + LEA(64, res, MDisp(acc, static_cast(imm))); + // SetLongAcc(areg, res); + set_long_acc(areg, res); if (FlagsNeeded()) { - MOV(64, R(RCX), R(RAX)); - set_long_acc(areg, RCX); - Update_SR_Register64_Carry(EAX, tmp1); + // UpdateSR64Add(acc, imm, GetLongAcc(areg)); + get_long_acc(areg, res); + X64Reg imm_reg = RDX; + MOV(64, R(imm_reg), Imm64(imm)); + X64Reg tmp1 = m_gpr.GetFreeXReg(); + UpdateSR64Add(acc, imm_reg, res, tmp1); + m_gpr.PutXReg(tmp1); } - else - { - set_long_acc(areg, RAX); - } - m_gpr.PutXReg(tmp1); } // ADDIS $acD, #I @@ -726,30 +730,28 @@ void DSPEmitter::addis(const UDSPInstruction opc) { u8 dreg = (opc >> 8) & 0x1; - X64Reg tmp1 = m_gpr.GetFreeXReg(); - // s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, tmp1); - MOV(64, R(RAX), R(tmp1)); - // s64 imm = (s8)(u8)opc; - // imm <<= 16; - s32 imm = static_cast(opc) << 24 >> 8; - MOV(64, R(RDX), Imm32(imm)); - // s64 res = acc + imm; - ADD(64, R(RAX), R(RDX)); - // dsp_set_long_acc(dreg, res); - // res = dsp_get_long_acc(dreg); - // Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, imm, res)); + // const s64 acc = GetLongAcc(dreg); + X64Reg acc = RAX; + get_long_acc(dreg, acc); + // s64 imm = static_cast(opc); + // imm <<= 16; + s64 imm = static_cast(opc); + imm <<= 16; + // const s64 res = acc + imm; + X64Reg res = RCX; + LEA(64, res, MDisp(acc, static_cast(imm))); + // SetLongAcc(dreg, res); + set_long_acc(dreg, res); if (FlagsNeeded()) { - MOV(64, R(RCX), R(RAX)); - set_long_acc(dreg, RCX); - Update_SR_Register64_Carry(EAX, tmp1); + // UpdateSR64Add(acc, imm, GetLongAcc(dreg)); + get_long_acc(dreg, res); + X64Reg imm_reg = RDX; + MOV(64, R(imm_reg), Imm64(imm)); + X64Reg tmp1 = m_gpr.GetFreeXReg(); + UpdateSR64Add(acc, imm_reg, res, tmp1); + m_gpr.PutXReg(tmp1); } - else - { - set_long_acc(dreg, RAX); - } - m_gpr.PutXReg(tmp1); } // INCM $acsD @@ -761,26 +763,24 @@ void DSPEmitter::incm(const UDSPInstruction opc) { u8 dreg = (opc >> 8) & 0x1; s64 subtract = 0x10000; - X64Reg tmp1 = m_gpr.GetFreeXReg(); - // s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, tmp1); - // s64 res = acc + sub; - LEA(64, RAX, MDisp(tmp1, subtract)); - // dsp_set_long_acc(dreg, res); - // res = dsp_get_long_acc(dreg); - // Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, subtract, res)); + // const s64 acc = GetLongAcc(dreg); + X64Reg acc = RAX; + get_long_acc(dreg, acc); + // const s64 res = acc + sub; + X64Reg res = RCX; + LEA(64, res, MDisp(acc, static_cast(subtract))); + // SetLongAcc(dreg, res); + set_long_acc(dreg, res); if (FlagsNeeded()) { - MOV(64, R(RDX), Imm32((u32)subtract)); - MOV(64, R(RCX), R(RAX)); - set_long_acc(dreg, RCX); - Update_SR_Register64_Carry(EAX, tmp1); + // UpdateSR64Add(acc, sub, GetLongAcc(dreg)); + get_long_acc(dreg, res); + X64Reg imm_reg = RDX; + MOV(64, R(imm_reg), Imm64(subtract)); + X64Reg tmp1 = m_gpr.GetFreeXReg(); + UpdateSR64Add(acc, imm_reg, res, tmp1); + m_gpr.PutXReg(tmp1); } - else - { - set_long_acc(dreg); - } - m_gpr.PutXReg(tmp1); } // INC $acD @@ -791,26 +791,24 @@ void DSPEmitter::incm(const UDSPInstruction opc) void DSPEmitter::inc(const UDSPInstruction opc) { u8 dreg = (opc >> 8) & 0x1; - X64Reg tmp1 = m_gpr.GetFreeXReg(); - // s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, tmp1); - // s64 res = acc + 1; - LEA(64, RAX, MDisp(tmp1, 1)); - // dsp_set_long_acc(dreg, res); - // res = dsp_get_long_acc(dreg); - // Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, 1, res)); + // const s64 acc = GetLongAcc(dreg); + X64Reg acc = RAX; + get_long_acc(dreg, acc); + // const s64 res = acc + 1; + X64Reg res = RCX; + LEA(64, res, MDisp(acc, 1)); + // SetLongAcc(dreg, res); + set_long_acc(dreg, res); if (FlagsNeeded()) { - MOV(64, R(RDX), Imm64(1)); - MOV(64, R(RCX), R(RAX)); - set_long_acc(dreg, RCX); - Update_SR_Register64_Carry(EAX, tmp1); + // UpdateSR64Add(acc, 1, GetLongAcc(dreg)); + get_long_acc(dreg, res); + X64Reg imm_reg = RDX; + MOV(64, R(imm_reg), Imm64(1)); + X64Reg tmp1 = m_gpr.GetFreeXReg(); + UpdateSR64Add(acc, imm_reg, res, tmp1); + m_gpr.PutXReg(tmp1); } - else - { - set_long_acc(dreg); - } - m_gpr.PutXReg(tmp1); } //---- @@ -825,31 +823,28 @@ void DSPEmitter::subr(const UDSPInstruction opc) u8 dreg = (opc >> 8) & 0x1; u8 sreg = ((opc >> 9) & 0x3) + DSP_REG_AXL0; - X64Reg tmp1 = m_gpr.GetFreeXReg(); - // s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, tmp1); - MOV(64, R(RAX), R(tmp1)); - // s64 ax = (s16)g_dsp.r[sreg]; - dsp_op_read_reg(sreg, RDX, RegisterExtension::Sign); - // ax <<= 16; - SHL(64, R(RDX), Imm8(16)); - // s64 res = acc - ax; - SUB(64, R(RAX), R(RDX)); - // dsp_set_long_acc(dreg, res); - // res = dsp_get_long_acc(dreg); - // Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -ax, res)); + // const s64 acc = GetLongAcc(dreg); + X64Reg acc = RAX; + get_long_acc(dreg, acc); + // s64 ax = ...; + X64Reg ax = RDX; + dsp_op_read_reg(sreg, ax, RegisterExtension::Sign); + // ax <<= 16; + SHL(64, R(ax), Imm8(16)); + // const s64 res = acc - ax; + X64Reg res = RCX; + MOV(64, R(res), R(acc)); + SUB(64, R(res), R(ax)); + // SetLongAcc(dreg, res); + set_long_acc(dreg, res); if (FlagsNeeded()) { - NEG(64, R(RDX)); - MOV(64, R(RCX), R(RAX)); - set_long_acc(dreg, RCX); - Update_SR_Register64_Carry(EAX, tmp1, true); + // UpdateSR64Sub(acc, ax, GetLongAcc(dreg)); + get_long_acc(dreg, res); + X64Reg tmp1 = m_gpr.GetFreeXReg(); + UpdateSR64Sub(acc, ax, res, tmp1); + m_gpr.PutXReg(tmp1); } - else - { - set_long_acc(dreg, RAX); - } - m_gpr.PutXReg(tmp1); } // SUBAX $acD, $axS @@ -862,29 +857,26 @@ void DSPEmitter::subax(const UDSPInstruction opc) u8 dreg = (opc >> 8) & 0x1; u8 sreg = (opc >> 9) & 0x1; - X64Reg tmp1 = m_gpr.GetFreeXReg(); - // s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, tmp1); - MOV(64, R(RAX), R(tmp1)); - // s64 acx = dsp_get_long_acx(sreg); - get_long_acx(sreg, RDX); - // s64 res = acc - acx; - SUB(64, R(RAX), R(RDX)); - // dsp_set_long_acc(dreg, res); - // res = dsp_get_long_acc(dreg); - // Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -acx, res)); + // const s64 acc = GetLongAcc(dreg); + X64Reg acc = RAX; + get_long_acc(dreg, acc); + // const s64 acx = GetLongACX(sreg); + X64Reg acx = RDX; + get_long_acx(sreg, acx); + // const s64 res = acc - acx; + X64Reg res = RCX; + MOV(64, R(res), R(acc)); + SUB(64, R(res), R(acx)); + // SetLongAcc(dreg, res); + set_long_acc(dreg, res); if (FlagsNeeded()) { - NEG(64, R(RDX)); - MOV(64, R(RCX), R(RAX)); - set_long_acc(dreg, RCX); - Update_SR_Register64_Carry(EAX, tmp1, true); + // UpdateSR64Sub(acc, acx, GetLongAcc(dreg)); + get_long_acc(dreg, res); + X64Reg tmp1 = m_gpr.GetFreeXReg(); + UpdateSR64Sub(acc, acx, res, tmp1); + m_gpr.PutXReg(tmp1); } - else - { - set_long_acc(dreg, RAX); - } - m_gpr.PutXReg(tmp1); } // SUB $acD, $ac(1-D) @@ -895,29 +887,26 @@ void DSPEmitter::subax(const UDSPInstruction opc) void DSPEmitter::sub(const UDSPInstruction opc) { u8 dreg = (opc >> 8) & 0x1; - X64Reg tmp1 = m_gpr.GetFreeXReg(); - // s64 acc1 = dsp_get_long_acc(dreg); - get_long_acc(dreg, tmp1); - MOV(64, R(RAX), R(tmp1)); - // s64 acc2 = dsp_get_long_acc(1 - dreg); - get_long_acc(1 - dreg, RDX); - // s64 res = acc1 - acc2; - SUB(64, R(RAX), R(RDX)); - // dsp_set_long_acc(dreg, res); - // res = dsp_get_long_acc(dreg); - // Update_SR_Register64(res, isCarry2(acc1, res), isOverflow(acc1, -acc2, res)); + // const s64 acc1 = GetLongAcc(dreg); + X64Reg acc1 = RAX; + get_long_acc(dreg, acc1); + // const s64 acc2 = GetLongAcc(1 - dreg); + X64Reg acc2 = RDX; + get_long_acc(1 - dreg, acc2); + // const s64 res = acc1 - acc2; + X64Reg res = RCX; + MOV(64, R(res), R(acc1)); + SUB(64, R(res), R(acc2)); + // SetLongAcc(dreg, res); + set_long_acc(dreg, res); if (FlagsNeeded()) { - NEG(64, R(RDX)); - MOV(64, R(RCX), R(RAX)); - set_long_acc(dreg, RCX); - Update_SR_Register64_Carry(EAX, tmp1, true); + // UpdateSR64Sub(acc1, acc2, GetLongAcc(dreg)); + get_long_acc(dreg, res); + X64Reg tmp1 = m_gpr.GetFreeXReg(); + UpdateSR64Sub(acc1, acc2, res, tmp1); + m_gpr.PutXReg(tmp1); } - else - { - set_long_acc(dreg, RAX); - } - m_gpr.PutXReg(tmp1); } // SUBP $acD @@ -928,29 +917,26 @@ void DSPEmitter::sub(const UDSPInstruction opc) void DSPEmitter::subp(const UDSPInstruction opc) { u8 dreg = (opc >> 8) & 0x1; - X64Reg tmp1 = m_gpr.GetFreeXReg(); - // s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, tmp1); - MOV(64, R(RAX), R(tmp1)); - // s64 prod = dsp_get_long_prod(); - get_long_prod(RDX); - // s64 res = acc - prod; - SUB(64, R(RAX), R(RDX)); - // dsp_set_long_acc(dreg, res); - // res = dsp_get_long_acc(dreg); - // Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -prod, res)); + // const s64 acc = GetLongAcc(dreg); + X64Reg acc = RAX; + get_long_acc(dreg, acc); + // const s64 prod = GetLongProduct(); + X64Reg prod = RDX; + get_long_prod(prod); + // const s64 res = acc - prod; + X64Reg res = RCX; + MOV(64, R(res), R(acc)); + SUB(64, R(res), R(prod)); + // SetLongAcc(dreg, res); + set_long_acc(dreg, res); if (FlagsNeeded()) { - NEG(64, R(RDX)); - MOV(64, R(RCX), R(RAX)); - set_long_acc(dreg, RCX); - Update_SR_Register64_Carry(EAX, tmp1, true); + // UpdateSR64Sub(acc, prod, GetLongAcc(dreg)); + get_long_acc(dreg, res); + X64Reg tmp1 = m_gpr.GetFreeXReg(); + UpdateSR64Sub(acc, prod, res, tmp1); + m_gpr.PutXReg(tmp1); } - else - { - set_long_acc(dreg, RAX); - } - m_gpr.PutXReg(tmp1); } // DECM $acsD @@ -962,26 +948,24 @@ void DSPEmitter::decm(const UDSPInstruction opc) { u8 dreg = (opc >> 8) & 0x01; s64 subtract = 0x10000; - X64Reg tmp1 = m_gpr.GetFreeXReg(); - // s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, tmp1); - // s64 res = acc - sub; - LEA(64, RAX, MDisp(tmp1, -subtract)); - // dsp_set_long_acc(dreg, res); - // res = dsp_get_long_acc(dreg); - // Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -subtract, res)); + // const s64 acc = GetLongAcc(dreg); + X64Reg acc = RAX; + get_long_acc(dreg, acc); + // const s64 res = acc - sub; + X64Reg res = RCX; + LEA(64, res, MDisp(acc, -subtract)); + // SetLongAcc(dreg, res); + set_long_acc(dreg, res); if (FlagsNeeded()) { - MOV(64, R(RDX), Imm64(-subtract)); - MOV(64, R(RCX), R(RAX)); - set_long_acc(dreg, RCX); - Update_SR_Register64_Carry(EAX, tmp1, true); + // UpdateSR64Sub(acc, sub, GetLongAcc(dreg)); + get_long_acc(dreg, res); + X64Reg imm_reg = RDX; + MOV(64, R(imm_reg), Imm64(subtract)); + X64Reg tmp1 = m_gpr.GetFreeXReg(); + UpdateSR64Sub(acc, imm_reg, res, tmp1); + m_gpr.PutXReg(tmp1); } - else - { - set_long_acc(dreg, RAX); - } - m_gpr.PutXReg(tmp1); } // DEC $acD @@ -992,26 +976,24 @@ void DSPEmitter::decm(const UDSPInstruction opc) void DSPEmitter::dec(const UDSPInstruction opc) { u8 dreg = (opc >> 8) & 0x01; - X64Reg tmp1 = m_gpr.GetFreeXReg(); - // s64 acc = dsp_get_long_acc(dreg); - get_long_acc(dreg, tmp1); - // s64 res = acc - 1; - LEA(64, RAX, MDisp(tmp1, -1)); - // dsp_set_long_acc(dreg, res); - // res = dsp_get_long_acc(dreg); - // Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -1, res)); + // const s64 acc = GetLongAcc(dreg); + X64Reg acc = RAX; + get_long_acc(dreg, acc); + // const s64 res = acc - 1; + X64Reg res = RCX; + LEA(64, res, MDisp(acc, -1)); + // SetLongAcc(dreg, res); + set_long_acc(dreg, res); if (FlagsNeeded()) { - MOV(64, R(RDX), Imm64(-1)); - MOV(64, R(RCX), R(RAX)); - set_long_acc(dreg, RCX); - Update_SR_Register64_Carry(EAX, tmp1, true); + // UpdateSR64Sub(acc, 1, GetLongAcc(dreg)); + get_long_acc(dreg, res); + X64Reg imm_reg = RDX; + MOV(64, R(RDX), Imm64(1)); + X64Reg tmp1 = m_gpr.GetFreeXReg(); + UpdateSR64Sub(acc, imm_reg, res, tmp1); + m_gpr.PutXReg(tmp1); } - else - { - set_long_acc(dreg); - } - m_gpr.PutXReg(tmp1); } //---- diff --git a/Source/Core/Core/DSP/Jit/x64/DSPJitCCUtil.cpp b/Source/Core/Core/DSP/Jit/x64/DSPJitCCUtil.cpp index 58676e8ef2..a891d0c483 100644 --- a/Source/Core/Core/DSP/Jit/x64/DSPJitCCUtil.cpp +++ b/Source/Core/Core/DSP/Jit/x64/DSPJitCCUtil.cpp @@ -65,45 +65,52 @@ void DSPEmitter::Update_SR_Register64(Gen::X64Reg val, Gen::X64Reg scratch) Update_SR_Register(val, scratch); } -// In: (val): s64 _Value -// In: (carry_ovfl): 1 = carry, 2 = overflow -// Clobbers RDX -void DSPEmitter::Update_SR_Register64_Carry(X64Reg val, X64Reg carry_ovfl, bool carry_eq) +// Updates SR based on a 64-bit value computed by result = val1 + val2 or result = val1 - val2 +// Clobbers scratch +void DSPEmitter::UpdateSR64AddSub(Gen::X64Reg val1, Gen::X64Reg val2, Gen::X64Reg result, + Gen::X64Reg scratch, bool subtract) { const OpArg sr_reg = m_gpr.GetReg(DSP_REG_SR); - // g_dsp.r[DSP_REG_SR] &= ~SR_CMP_MASK; + // g_dsp.r[DSP_REG_SR] &= ~SR_CMP_MASK; AND(16, sr_reg, Imm16(~SR_CMP_MASK)); - CMP(64, R(carry_ovfl), R(val)); + CMP(64, R(val1), R(result)); + // x86 ZF set if val1 == result + // x86 CF set if val1 < result + // Note that x86 uses a different definition of carry than the DSP // 0x01 - // g_dsp.r[DSP_REG_SR] |= SR_CARRY; - // Carry = (acc>res) - // Carry2 = (acc>=res) - FixupBranch noCarry = J_CC(carry_eq ? CC_B : CC_BE); + // g_dsp.r[DSP_REG_SR] |= SR_CARRY; + // isCarryAdd = (val1 > result) => skip setting if (val <= result) => jump if ZF or CF => use JBE + // isCarrySubtract = (val1 >= result) => skip setting if (val < result) => jump if CF => use JB + FixupBranch noCarry = J_CC(subtract ? CC_B : CC_BE); OR(16, sr_reg, Imm16(SR_CARRY)); SetJumpTarget(noCarry); // 0x02 and 0x80 - // g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW; - // g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW_STICKY; - // Overflow = ((acc ^ res) & (ax ^ res)) < 0 - XOR(64, R(carry_ovfl), R(val)); - XOR(64, R(RDX), R(val)); - TEST(64, R(carry_ovfl), R(RDX)); + // g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW; + // g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW_STICKY; + // Overflow (add) = ((val1 ^ res) & (val2 ^ res)) < 0 + // Overflow (sub) = ((val1 ^ res) & (-val2 ^ res)) < 0 + MOV(64, R(scratch), R(val1)); + XOR(64, R(scratch), R(result)); + + if (subtract) + NEG(64, R(val2)); + XOR(64, R(result), R(val2)); + + TEST(64, R(scratch), R(result)); // Test scratch & value FixupBranch noOverflow = J_CC(CC_GE); OR(16, sr_reg, Imm16(SR_OVERFLOW | SR_OVERFLOW_STICKY)); SetJumpTarget(noOverflow); + // Restore result and val2 -- TODO: does this really matter? + XOR(64, R(result), R(val2)); + if (subtract) + NEG(64, R(val2)); + m_gpr.PutReg(DSP_REG_SR); - if (carry_eq) - { - Update_SR_Register(); - } - else - { - Update_SR_Register(val); - } + Update_SR_Register(result, scratch); } // In: RAX: s64 _Value diff --git a/Source/Core/Core/DSP/Jit/x64/DSPJitMultiplier.cpp b/Source/Core/Core/DSP/Jit/x64/DSPJitMultiplier.cpp index efbd59d164..7fba07f974 100644 --- a/Source/Core/Core/DSP/Jit/x64/DSPJitMultiplier.cpp +++ b/Source/Core/Core/DSP/Jit/x64/DSPJitMultiplier.cpp @@ -259,13 +259,14 @@ void DSPEmitter::addpaxz(const UDSPInstruction opc) // s64 oldprod = dsp_get_long_prod(); // dsp_set_long_acc(dreg, res); // res = dsp_get_long_acc(dreg); - // Update_SR_Register64(res, isCarry(oldprod, res), false); + // Update_SR_Register64(res, isCarryAdd(oldprod, res), false); if (FlagsNeeded()) { get_long_prod(RDX); MOV(64, R(RCX), R(RAX)); set_long_acc(dreg, RCX); - Update_SR_Register64_Carry(EAX, tmp1); + // TODO: Why does this not set the overflow bit? (And thus, why can't it use UpdateSR64Add?) + Update_SR_Register64(EAX, tmp1); } else { diff --git a/Source/Core/Core/DSP/Jit/x64/DSPJitUtil.cpp b/Source/Core/Core/DSP/Jit/x64/DSPJitUtil.cpp index 4957947b40..bbf97b98c7 100644 --- a/Source/Core/Core/DSP/Jit/x64/DSPJitUtil.cpp +++ b/Source/Core/Core/DSP/Jit/x64/DSPJitUtil.cpp @@ -690,7 +690,15 @@ void DSPEmitter::set_long_prod() m_gpr.PutReg(DSP_REG_PROD_64, true); } -// Returns s64 in RAX +// s64 -> s40 in long_acc +void DSPEmitter::dsp_convert_long_acc(Gen::X64Reg long_acc) +{ + // return ((long_acc << (64 - 40)) >> (64 - 40)) + SHL(64, R(long_acc), Imm8(64 - 40)); // sign extend + SAR(64, R(long_acc), Imm8(64 - 40)); +} + +// Returns s64 in long_acc void DSPEmitter::round_long_acc(X64Reg long_acc) { // if (prod & 0x10000) prod = (prod + 0x8000) & ~0xffff;