diff --git a/Source/Core/DSPCore/CMakeLists.txt b/Source/Core/DSPCore/CMakeLists.txt
index 8ea572c808..d428997e25 100644
--- a/Source/Core/DSPCore/CMakeLists.txt
+++ b/Source/Core/DSPCore/CMakeLists.txt
@@ -19,6 +19,8 @@ set(SRCS Src/assemble.cpp
Src/DSPCore.cpp
Src/DSPTables.cpp
Src/Jit/DSPJitExtOps.cpp
+ Src/Jit/DSPJitCCUtil.cpp
+ Src/Jit/DSPJitMultiplier.cpp
Src/Jit/DSPJitUtil.cpp
Src/Jit/DSPJitMisc.cpp)
diff --git a/Source/Core/DSPCore/DSPCore.vcproj b/Source/Core/DSPCore/DSPCore.vcproj
index e00ebbbbaa..f28f061537 100644
--- a/Source/Core/DSPCore/DSPCore.vcproj
+++ b/Source/Core/DSPCore/DSPCore.vcproj
@@ -458,6 +458,10 @@
RelativePath=".\Src\DSPEmitter.h"
>
+
+
@@ -466,6 +470,10 @@
RelativePath=".\Src\Jit\DSPJitMisc.cpp"
>
+
+
diff --git a/Source/Core/DSPCore/Src/DSPEmitter.h b/Source/Core/DSPCore/Src/DSPEmitter.h
index 7020a5fd26..9865fca6e1 100644
--- a/Source/Core/DSPCore/Src/DSPEmitter.h
+++ b/Source/Core/DSPCore/Src/DSPEmitter.h
@@ -46,6 +46,9 @@ public:
int STACKALIGN RunForCycles(int cycles);
+ // CC Util
+ void Update_SR_Register64(bool carry = false, bool overflow = false);
+
// Register helpers
void setCompileSR(u16 bit);
void clrCompileSR(u16 bit);
@@ -113,6 +116,20 @@ public:
void mrr(const UDSPInstruction opc);
void nx(const UDSPInstruction opc);
+ // Multipliers
+ void get_multiply_prod();
+ void multiply();
+ void clrp(const UDSPInstruction opc);
+ void tstprod(const UDSPInstruction opc);
+ void movp(const UDSPInstruction opc);
+ void movnp(const UDSPInstruction opc);
+ void movpz(const UDSPInstruction opc);
+ void mulaxh(const UDSPInstruction opc);
+ void mul(const UDSPInstruction opc);
+ void mulmv(const UDSPInstruction opc);
+ void mulmvz(const UDSPInstruction opc);
+ void mulc(const UDSPInstruction opc);
+
// CALL this to start the dispatcher
const u8 *enterDispatcher;
@@ -131,7 +148,15 @@ private:
void ToMask(Gen::X64Reg value_reg = Gen::EDI, Gen::X64Reg temp_reg = Gen::ESI);
void dsp_increment_one(Gen::X64Reg ar = Gen::EAX, Gen::X64Reg wr = Gen::EDX, Gen::X64Reg wr_pow = Gen::EDI, Gen::X64Reg temp_reg = Gen::ESI);
void dsp_decrement_one(Gen::X64Reg ar = Gen::EAX, Gen::X64Reg wr = Gen::EDX, Gen::X64Reg wr_pow = Gen::EDI, Gen::X64Reg temp_reg = Gen::ESI);
-};
+ void get_long_prod();
+ void get_long_prod_round_prodl();
+ void set_long_prod();
+ void set_long_acc(int _reg);
+ void get_acc_m(int _reg);
+ void get_ax_l(int _reg);
+ void get_ax_h(int _reg);
+ void get_long_acc(int _reg);
+};
#endif // _DSPEMITTER_H
diff --git a/Source/Core/DSPCore/Src/DSPTables.cpp b/Source/Core/DSPCore/Src/DSPTables.cpp
index b08a522e46..2edcf03ef1 100644
--- a/Source/Core/DSPCore/Src/DSPTables.cpp
+++ b/Source/Core/DSPCore/Src/DSPTables.cpp
@@ -235,7 +235,7 @@ const DSPOPCTemplate opcodes[] =
{"MOVR", 0x6000, 0xf800, DSPInterpreter::movr, NULL, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0600}}, true, false, false},
{"MOVAX", 0x6800, 0xfc00, DSPInterpreter::movax, NULL, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_AX, 1, 0, 9, 0x0200}}, true, false, false},
{"MOV", 0x6c00, 0xfe00, DSPInterpreter::mov, NULL, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACC_D, 1, 0, 8, 0x0100}}, true, false, false},
- {"MOVP", 0x6e00, 0xfe00, DSPInterpreter::movp, NULL, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false},
+ {"MOVP", 0x6e00, 0xfe00, DSPInterpreter::movp, &DSPEmitter::movp, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false},
//7
{"ADDAXL", 0x7000, 0xfc00, DSPInterpreter::addaxl, NULL, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0200}}, true, false, false},
@@ -244,15 +244,15 @@ const DSPOPCTemplate opcodes[] =
{"DECM", 0x7800, 0xfe00, DSPInterpreter::decm, NULL, 1, 1, {{P_ACCM, 1, 0, 8, 0x0100}}, true, false, false},
{"DEC", 0x7a00, 0xfe00, DSPInterpreter::dec, NULL, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false},
{"NEG", 0x7c00, 0xfe00, DSPInterpreter::neg, NULL, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false},
- {"MOVNP", 0x7e00, 0xfe00, DSPInterpreter::movnp, NULL, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false},
+ {"MOVNP", 0x7e00, 0xfe00, DSPInterpreter::movnp, &DSPEmitter::movnp, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false},
//8
{"NX", 0x8000, 0xf700, DSPInterpreter::nx, &DSPEmitter::nx, 1, 0, {}, true, false, false},
{"CLR", 0x8100, 0xf700, DSPInterpreter::clr, NULL, 1, 1, {{P_ACC, 1, 0, 11, 0x0800}}, true, false, false},
{"CMP", 0x8200, 0xff00, DSPInterpreter::cmp, NULL, 1, 0, {}, true, false, false},
- {"MULAXH", 0x8300, 0xff00, DSPInterpreter::mulaxh, NULL, 1, 0, {}, true, false, false},
- {"CLRP", 0x8400, 0xff00, DSPInterpreter::clrp, NULL, 1, 0, {}, true, false, false},
- {"TSTPROD", 0x8500, 0xff00, DSPInterpreter::tstprod, NULL, 1, 0, {}, true, false, false},
+ {"MULAXH", 0x8300, 0xff00, DSPInterpreter::mulaxh, &DSPEmitter::mulaxh, 1, 0, {}, true, false, false},
+ {"CLRP", 0x8400, 0xff00, DSPInterpreter::clrp, &DSPEmitter::clrp, 1, 0, {}, true, false, false},
+ {"TSTPROD", 0x8500, 0xff00, DSPInterpreter::tstprod, &DSPEmitter::tstprod,1, 0, {}, true, false, false},
{"TSTAXH", 0x8600, 0xfe00, DSPInterpreter::tstaxh, NULL, 1, 1, {{P_REG1A, 1, 0, 8, 0x0100}}, true, false, false},
{"M2", 0x8a00, 0xff00, DSPInterpreter::srbith, &DSPEmitter::srbith, 1, 0, {}, true, false, false},
{"M0", 0x8b00, 0xff00, DSPInterpreter::srbith, &DSPEmitter::srbith, 1, 0, {}, true, false, false},
@@ -262,11 +262,11 @@ const DSPOPCTemplate opcodes[] =
{"SET40", 0x8f00, 0xff00, DSPInterpreter::srbith, &DSPEmitter::srbith, 1, 0, {}, true, false, false},
//9
- {"MUL", 0x9000, 0xf700, DSPInterpreter::mul, NULL, 1, 2, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}}, true, false, false},
+ {"MUL", 0x9000, 0xf700, DSPInterpreter::mul, &DSPEmitter::mul, 1, 2, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}}, true, false, false},
{"ASR16", 0x9100, 0xf700, DSPInterpreter::asr16, NULL, 1, 1, {{P_ACC, 1, 0, 11, 0x0800}}, true, false, false},
- {"MULMVZ", 0x9200, 0xf600, DSPInterpreter::mulmvz, NULL, 1, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false},
+ {"MULMVZ", 0x9200, 0xf600, DSPInterpreter::mulmvz, &DSPEmitter::mulmvz, 1, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false},
{"MULAC", 0x9400, 0xf600, DSPInterpreter::mulac, NULL, 1, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false},
- {"MULMV", 0x9600, 0xf600, DSPInterpreter::mulmv, NULL, 1, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false},
+ {"MULMV", 0x9600, 0xf600, DSPInterpreter::mulmv, &DSPEmitter::mulmv, 1, 3, {{P_REG18, 1, 0, 11, 0x0800}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false},
//a-b
{"MULX", 0xa000, 0xe700, DSPInterpreter::mulx, NULL, 1, 2, {{P_REGM18, 1, 0, 11, 0x1000}, {P_REGM19, 1, 0, 10, 0x0800}}, true, false, false},
@@ -277,7 +277,7 @@ const DSPOPCTemplate opcodes[] =
{"TST", 0xb100, 0xf700, DSPInterpreter::tst, NULL, 1, 1, {{P_ACC, 1, 0, 11, 0x0800}}, true, false, false},
//c-d
- {"MULC", 0xc000, 0xe700, DSPInterpreter::mulc, NULL, 1, 2, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}}, true, false, false},
+ {"MULC", 0xc000, 0xe700, DSPInterpreter::mulc, &DSPEmitter::mulc, 1, 2, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}}, true, false, false},
{"CMPAR" , 0xc100, 0xe700, DSPInterpreter::cmpar, NULL, 1, 2, {{P_ACC, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}}, true, false, false},
{"MULCMVZ", 0xc200, 0xe600, DSPInterpreter::mulcmvz, NULL, 1, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false},
{"MULCAC", 0xc400, 0xe600, DSPInterpreter::mulcac, NULL, 1, 3, {{P_ACCM, 1, 0, 12, 0x1000}, {P_REG1A, 1, 0, 11, 0x0800}, {P_ACC, 1, 0, 8, 0x0100}}, true, false, false},
@@ -296,7 +296,7 @@ const DSPOPCTemplate opcodes[] =
{"MSUB", 0xf600, 0xfe00, DSPInterpreter::msub, NULL, 1, 2, {{P_REG18, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 8, 0x0100}}, true, false, false},
{"ADDPAXZ", 0xf800, 0xfc00, DSPInterpreter::addpaxz, NULL, 1, 2, {{P_ACC, 1, 0, 9, 0x0200}, {P_AX, 1, 0, 8, 0x0100}}, true, false, false},
{"CLRL", 0xfc00, 0xfe00, DSPInterpreter::clrl, NULL, 1, 1, {{P_ACCL, 1, 0, 11, 0x0800}}, true, false, false},
- {"MOVPZ", 0xfe00, 0xfe00, DSPInterpreter::movpz, NULL, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false},
+ {"MOVPZ", 0xfe00, 0xfe00, DSPInterpreter::movpz, &DSPEmitter::movpz, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false},
};
const DSPOPCTemplate cw =
diff --git a/Source/Core/DSPCore/Src/Jit/DSPJitCCUtil.cpp b/Source/Core/DSPCore/Src/Jit/DSPJitCCUtil.cpp
new file mode 100644
index 0000000000..f4abd88a15
--- /dev/null
+++ b/Source/Core/DSPCore/Src/Jit/DSPJitCCUtil.cpp
@@ -0,0 +1,211 @@
+// Copyright (C) 2003 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+// Additional copyrights go to Duddie and Tratax (c) 2004
+
+
+// HELPER FUNCTIONS
+
+#include "../DSPIntUtil.h"
+#include "../DSPEmitter.h"
+#include "x64Emitter.h"
+#include "ABI.h"
+using namespace Gen;
+
+// In: RAX: s64 _Value,
+// Clobbers RDX
+void DSPEmitter::Update_SR_Register64(bool carry, bool overflow)
+{
+#ifdef _M_X64
+// g_dsp.r[DSP_REG_SR] &= ~SR_CMP_MASK;
+ AND(16, MDisp(R11, DSP_REG_SR * 2), Imm16(~SR_CMP_MASK));
+
+ // 0x01
+ // g_dsp.r[DSP_REG_SR] |= SR_CARRY;
+ if (carry)
+ {
+ OR(16, MDisp(R11, DSP_REG_SR * 2), Imm16(SR_CARRY));
+ }
+
+ // 0x02 and 0x80
+ // g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW;
+ // g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW_STICKY;
+ if (overflow)
+ {
+ OR(16, MDisp(R11, DSP_REG_SR * 2), Imm16(SR_OVERFLOW | SR_OVERFLOW_STICKY));
+ }
+
+// // 0x04
+// if (_Value == 0) g_dsp.r[DSP_REG_SR] |= SR_ARITH_ZERO;
+ TEST(64, R(RAX), R(RAX));
+ FixupBranch notZero = J_CC(CC_NZ);
+ OR(16, MDisp(R11, DSP_REG_SR * 2), Imm16(SR_ARITH_ZERO));
+ SetJumpTarget(notZero);
+
+// // 0x08
+// if (_Value < 0) g_dsp.r[DSP_REG_SR] |= SR_SIGN;
+ FixupBranch greaterThanEqual = J_CC(CC_NS);
+ OR(16, MDisp(R11, DSP_REG_SR * 2), Imm16(SR_SIGN));
+ SetJumpTarget(greaterThanEqual);
+
+// // 0x10
+// if (_Value != (s32)_Value) g_dsp.r[DSP_REG_SR] |= SR_OVER_S32;
+ MOVSX(64, 32, RDX, R(RAX));
+ CMP(64, R(RDX), R(RAX));
+ FixupBranch noOverS32 = J_CC(CC_E);
+ OR(16, MDisp(R11, DSP_REG_SR * 2), Imm16(SR_OVER_S32));
+ SetJumpTarget(noOverS32);
+
+// // 0x20 - Checks if top bits of m are equal
+// if (((_Value & 0xc0000000) == 0) || ((_Value & 0xc0000000) == 0xc0000000))
+ AND(32, R(EAX), Imm32(0xc0000000));
+ CMP(32, R(EAX), Imm32(0));
+ FixupBranch zeroC = J_CC(CC_E);
+ CMP(32, R(EAX), Imm32(0xc0000000));
+ FixupBranch cC = J_CC(CC_NE);
+ SetJumpTarget(zeroC);
+// g_dsp.r[DSP_REG_SR] |= SR_TOP2BITS;
+ OR(16, MDisp(R11, DSP_REG_SR * 2), Imm16(SR_TOP2BITS));
+ SetJumpTarget(cC);
+#endif
+}
+
+
+//void DSPEmitter::Update_SR_Register16(s16 _Value, bool carry, bool overflow, bool overS32)
+//{
+// g_dsp.r[DSP_REG_SR] &= ~SR_CMP_MASK;
+
+// // 0x01
+// if (carry)
+// {
+// g_dsp.r[DSP_REG_SR] |= SR_CARRY;
+// }
+
+// // 0x02 and 0x80
+// if (overflow)
+// {
+// g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW;
+// g_dsp.r[DSP_REG_SR] |= SR_OVERFLOW_STICKY;
+// }
+
+// // 0x04
+// if (_Value == 0)
+// {
+// g_dsp.r[DSP_REG_SR] |= SR_ARITH_ZERO;
+// }
+
+// // 0x08
+// if (_Value < 0)
+// {
+// g_dsp.r[DSP_REG_SR] |= SR_SIGN;
+// }
+
+// // 0x10
+// if (overS32)
+// {
+// g_dsp.r[DSP_REG_SR] |= SR_OVER_S32;
+// }
+
+// // 0x20 - Checks if top bits of m are equal
+// if ((((u16)_Value >> 14) == 0) || (((u16)_Value >> 14) == 3))
+// {
+// g_dsp.r[DSP_REG_SR] |= SR_TOP2BITS;
+// }
+//}
+
+//void DSPEmitter::Update_SR_LZ(bool value) {
+
+// if (value == true)
+// g_dsp.r[DSP_REG_SR] |= SR_LOGIC_ZERO;
+// else
+// g_dsp.r[DSP_REG_SR] &= ~SR_LOGIC_ZERO;
+//}
+
+//inline int GetMultiplyModifier()
+//{
+// return (g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY)?1:2;
+//}
+
+//inline bool isCarry() {
+// return (g_dsp.r[DSP_REG_SR] & SR_CARRY) ? true : false;
+//}
+
+//inline bool isOverflow() {
+// return (g_dsp.r[DSP_REG_SR] & SR_OVERFLOW) ? true : false;
+//}
+
+//inline bool isOverS32() {
+// return (g_dsp.r[DSP_REG_SR] & SR_OVER_S32) ? true : false;
+//}
+
+//inline bool isLess() {
+// return (!(g_dsp.r[DSP_REG_SR] & SR_OVERFLOW) != !(g_dsp.r[DSP_REG_SR] & SR_SIGN));
+//}
+
+//inline bool isZero() {
+// return (g_dsp.r[DSP_REG_SR] & SR_ARITH_ZERO) ? true : false;
+//}
+
+//inline bool isLogicZero() {
+// return (g_dsp.r[DSP_REG_SR] & SR_LOGIC_ZERO) ? true : false;
+//}
+
+//inline bool isConditionA() {
+// return (((g_dsp.r[DSP_REG_SR] & SR_OVER_S32) || (g_dsp.r[DSP_REG_SR] & SR_TOP2BITS)) && !(g_dsp.r[DSP_REG_SR] & SR_ARITH_ZERO)) ? true : false;
+//}
+
+//see DSPCore.h for flags
+//bool CheckCondition(u8 _Condition)
+//{
+// switch (_Condition & 0xf)
+// {
+// case 0xf: // Always true.
+// return true;
+// case 0x0: // GE - Greater Equal
+// return !isLess();
+// case 0x1: // L - Less
+// return isLess();
+// case 0x2: // G - Greater
+// return !isLess() && !isZero();
+// case 0x3: // LE - Less Equal
+// return isLess() || isZero();
+// case 0x4: // NZ - Not Zero
+// return !isZero();
+// case 0x5: // Z - Zero
+// return isZero();
+// case 0x6: // NC - Not carry
+// return !isCarry();
+// case 0x7: // C - Carry
+// return isCarry();
+// case 0x8: // ? - Not over s32
+// return !isOverS32();
+// case 0x9: // ? - Over s32
+// return isOverS32();
+// case 0xa: // ?
+// return isConditionA();
+// case 0xb: // ?
+// return !isConditionA();
+// case 0xc: // LNZ - Logic Not Zero
+// return !isLogicZero();
+// case 0xd: // LZ - Logic Zero
+// return isLogicZero();
+// case 0xe: // 0 - Overflow
+// return isOverflow();
+// default:
+// return true;
+// }
+//}
diff --git a/Source/Core/DSPCore/Src/Jit/DSPJitMultiplier.cpp b/Source/Core/DSPCore/Src/Jit/DSPJitMultiplier.cpp
new file mode 100644
index 0000000000..c48c090ecc
--- /dev/null
+++ b/Source/Core/DSPCore/Src/Jit/DSPJitMultiplier.cpp
@@ -0,0 +1,697 @@
+// Copyright (C) 2003 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+// Additional copyrights go to Duddie and Tratax (c) 2004
+
+
+// Multiplier and product register control
+
+#include "../DSPIntUtil.h"
+#include "../DSPEmitter.h"
+#include "x64Emitter.h"
+#include "ABI.h"
+using namespace Gen;
+
+// Only MULX family instructions have unsigned/mixed support.
+// Returns s64 in EAX
+// In: RSI = u16 a, RDI = u16 b, RCX = u8 sign
+void DSPEmitter::get_multiply_prod()
+{
+#ifdef _M_X64
+// if ((sign == 1) && (g_dsp.r[DSP_REG_SR] & SR_MUL_UNSIGNED)) //unsigned
+ MOV(16, R(RDX), MDisp(R11, DSP_REG_SR * 2)); // TODO check 16bit
+ AND(16, R(RDX), Imm16(SR_MUL_UNSIGNED));
+ TEST(16, R(RDX), R(RDX));
+ FixupBranch sign3 = J_CC(CC_Z);
+ TEST(32, R(ECX), Imm32(1));
+ FixupBranch sign1 = J_CC(CC_Z);
+// prod = (u32)(a * b);
+ MOV(64, R(EAX), R(RDI));
+ MUL(16, R(ESI));
+ FixupBranch mult2 = J();
+ SetJumpTarget(sign1);
+ TEST(32, R(ECX), Imm32(2));
+ FixupBranch sign2 = J_CC(CC_Z);
+// else if ((sign == 2) && (g_dsp.r[DSP_REG_SR] & SR_MUL_UNSIGNED)) //mixed
+// prod = a * (s16)b;
+ MOVSX(64, 16, RDI, R(RDI));
+ MOV(64, R(EAX), R(RDI));
+ MUL(16, R(ESI));
+// else
+ SetJumpTarget(sign2);
+ SetJumpTarget(sign3);
+// prod = (s16)a * (s16)b; //signed
+ MOVSX(64, 16, RSI, R(RSI));
+ MOVSX(64, 16, RDI, R(RDI));
+ MOV(64, R(EAX), R(RDI));
+ IMUL(16, R(ESI));
+
+// Conditionally multiply by 2.
+ SetJumpTarget(mult2);
+// if ((g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY) == 0)
+ MOV(16, R(RDX), MDisp(R11, DSP_REG_SR * 2)); // TODO check 16bit
+ AND(16, R(RDX), Imm16(SR_MUL_MODIFY));
+ TEST(16, R(RDX), R(RDX));
+ FixupBranch noMult2 = J_CC(CC_NZ);
+// prod <<= 1;
+ SHL(64, R(EAX), Imm8(1));
+ SetJumpTarget(noMult2);
+// return prod;
+#endif
+}
+
+// Returns s64 in EAX
+// In: RSI = u16 a, RDI = u16 b
+void DSPEmitter::multiply()
+{
+#ifdef _M_X64
+ // prod = (s16)a * (s16)b; //signed
+ MOVSX(64, 16, RSI, R(RSI));
+ MOVSX(64, 16, RDI, R(RDI));
+ MOV(64, R(EAX), R(RDI));
+ IMUL(64, R(ESI));
+
+ // Conditionally multiply by 2.
+ // if ((g_dsp.r[DSP_REG_SR] & SR_MUL_MODIFY) == 0)
+ TEST(16, MDisp(R11, DSP_REG_SR * 2), Imm16(SR_MUL_MODIFY));
+ FixupBranch noMult2 = J_CC(CC_NZ);
+ // prod <<= 1;
+ SHL(64, R(EAX), Imm8(1));
+ SetJumpTarget(noMult2);
+ // return prod;
+#endif
+}
+
+//inline s64 dsp_multiply_add(u16 a, u16 b, u8 sign = 0)
+//{
+// s64 prod = dsp_get_long_prod() + dsp_get_multiply_prod(a, b, sign);
+// return prod;
+//}
+
+//inline s64 dsp_multiply_sub(u16 a, u16 b, u8 sign = 0)
+//{
+// s64 prod = dsp_get_long_prod() - dsp_get_multiply_prod(a, b, sign);
+// return prod;
+//}
+
+//inline s64 dsp_multiply_mulx(u8 axh0, u8 axh1, u16 val1, u16 val2)
+//{
+// s64 result;
+
+// if ((axh0==0) && (axh1==0))
+// result = dsp_multiply(val1, val2, 1); // unsigned support ON if both ax?.l regs are used
+// else if ((axh0==0) && (axh1==1))
+// result = dsp_multiply(val1, val2, 2); // mixed support ON (u16)axl.0 * (s16)axh.1
+// else if ((axh0==1) && (axh1==0))
+// result = dsp_multiply(val2, val1, 2); // mixed support ON (u16)axl.1 * (s16)axh.0
+// else
+// result = dsp_multiply(val1, val2, 0); // unsigned support OFF if both ax?.h regs are used
+
+// return result;
+//}
+
+//----
+
+// CLRP
+// 1000 0100 xxxx xxxx
+// Clears product register $prod.
+// Magic numbers taken from duddie's doc
+
+// 00ff_(fff0 + 0010)_0000 = 0100_0000_0000, conveniently, lower 40bits = 0
+
+// It's not ok, to just zero all of them, correct values should be set because of
+// direct use of prod regs by AX/AXWII (look @that part of ucode).
+void DSPEmitter::clrp(const UDSPInstruction opc)
+{
+#ifdef _M_X64
+// g_dsp.r[DSP_REG_PRODL] = 0x0000;
+ MOV(64, R(R11), ImmPtr(&g_dsp.r));
+ MOV(16, MDisp(R11, DSP_REG_PRODL * 2), Imm16(0x0000));
+// g_dsp.r[DSP_REG_PRODM] = 0xfff0;
+ MOV(16, MDisp(R11, DSP_REG_PRODM * 2), Imm16(0xfff0));
+// g_dsp.r[DSP_REG_PRODH] = 0x00ff;
+ MOV(16, MDisp(R11, DSP_REG_PRODH * 2), Imm16(0x00ff));
+// g_dsp.r[DSP_REG_PRODM2] = 0x0010;
+ MOV(16, MDisp(R11, DSP_REG_PRODM2 * 2), Imm16(0x0010));
+#else
+ ABI_CallFunctionC((void *)&DSPInterpreter::clrp, opc);
+#endif
+}
+
+// TSTPROD
+// 1000 0101 xxxx xxxx
+// Test prod regs value.
+
+// flags out: --xx xx0x
+void DSPEmitter::tstprod(const UDSPInstruction opc)
+{
+#ifdef _M_X64
+// s64 prod = dsp_get_long_prod();
+ get_long_prod();
+// Update_SR_Register64(prod);
+ Update_SR_Register64();
+#else
+ ABI_CallFunctionC((void *)&DSPInterpreter::tstprod, opc);
+#endif
+}
+
+//----
+
+// MOVP $acD
+// 0110 111d xxxx xxxx
+// Moves multiply product from $prod register to accumulator $acD register.
+
+// flags out: --xx xx0x
+void DSPEmitter::movp(const UDSPInstruction opc)
+{
+#ifdef _M_X64
+ u8 dreg = (opc >> 8) & 0x1;
+
+// s64 acc = dsp_get_long_prod();
+ get_long_prod();
+// dsp_set_long_acc(dreg, acc);
+ set_long_acc(dreg);
+// Update_SR_Register64(acc);
+ Update_SR_Register64();
+#else
+ ABI_CallFunctionC((void *)&DSPInterpreter::movp, opc);
+#endif
+}
+
+// MOVNP $acD
+// 0111 111d xxxx xxxx
+// Moves negative of multiply product from $prod register to accumulator
+// $acD register.
+
+// flags out: --xx xx0x
+void DSPEmitter::movnp(const UDSPInstruction opc)
+{
+#ifdef _M_X64
+ u8 dreg = (opc >> 8) & 0x1;
+
+// s64 acc = -dsp_get_long_prod();
+ get_long_prod();
+ NEG(64, R(EAX));
+// dsp_set_long_acc(dreg, acc);
+ set_long_acc(dreg);
+// Update_SR_Register64(acc);
+ Update_SR_Register64();
+#else
+ ABI_CallFunctionC((void *)&DSPInterpreter::movnp, opc);
+#endif
+}
+
+// MOVPZ $acD
+// 1111 111d xxxx xxxx
+// Moves multiply product from $prod register to accumulator $acD
+// register and sets (rounds) $acD.l to 0
+
+// flags out: --xx xx0x
+void DSPEmitter::movpz(const UDSPInstruction opc)
+{
+#ifdef _M_X64
+ u8 dreg = (opc >> 8) & 0x01;
+
+// s64 acc = dsp_get_long_prod_round_prodl();
+ get_long_prod_round_prodl();
+// dsp_set_long_acc(dreg, acc);
+ set_long_acc(dreg);
+// Update_SR_Register64(acc);
+ Update_SR_Register64();
+#else
+ ABI_CallFunctionC((void *)&DSPInterpreter::movpz, opc);
+#endif
+}
+
+// ADDPAXZ $acD, $axS
+// 1111 10sd xxxx xxxx
+// Adds secondary accumulator $axS to product register and stores result
+// in accumulator register. Low 16-bits of $acD ($acD.l) are set (round) to 0.
+
+// flags out: --xx xx0x
+//void DSPEmitter::addpaxz(const UDSPInstruction opc)
+//{
+// u8 dreg = (opc >> 8) & 0x1;
+// u8 sreg = (opc >> 9) & 0x1;
+
+// s64 oldprod = dsp_get_long_prod();
+// s64 prod = dsp_get_long_prod_round_prodl();
+// s64 ax = dsp_get_long_acx(sreg);
+// s64 res = prod + (ax & ~0xffff);
+
+// zeroWriteBackLog();
+
+// dsp_set_long_acc(dreg, res);
+// res = dsp_get_long_acc(dreg);
+// Update_SR_Register64(res, isCarry(oldprod, res), false);
+//}
+
+//----
+
+// MULAXH
+// 1000 0011 xxxx xxxx
+// Multiply $ax0.h by $ax0.h
+void DSPEmitter::mulaxh(const UDSPInstruction opc)
+{
+#ifdef _M_X64
+// s64 prod = dsp_multiply(dsp_get_ax_h(0), dsp_get_ax_h(0));
+ MOV(64, R(R11), ImmPtr(&g_dsp.r));
+ MOVZX(64, 16, RSI, MDisp(R11, DSP_REG_AXH0 * 2));
+ MOV(64, R(RDI), R(RSI));
+ multiply();
+// dsp_set_long_prod(prod);
+ set_long_prod();
+#else
+ ABI_CallFunctionC((void *)&DSPInterpreter::mulaxh, opc);
+#endif
+}
+
+//----
+
+// MUL $axS.l, $axS.h
+// 1001 s000 xxxx xxxx
+// Multiply low part $axS.l of secondary accumulator $axS by high part
+// $axS.h of secondary accumulator $axS (treat them both as signed).
+void DSPEmitter::mul(const UDSPInstruction opc)
+{
+#ifdef _M_X64
+ u8 sreg = (opc >> 11) & 0x1;
+
+// u16 axl = dsp_get_ax_l(sreg);
+ MOV(64, R(R11), ImmPtr(&g_dsp.r));
+ MOVZX(64, 16, RSI, MDisp(R11, (DSP_REG_AXL0 + sreg) * 2));
+// u16 axh = dsp_get_ax_h(sreg);
+ MOVZX(64, 16, RDI, MDisp(R11, (DSP_REG_AXH0 + sreg) * 2));
+// s64 prod = dsp_multiply(axh, axl);
+ multiply();
+// dsp_set_long_prod(prod);
+ set_long_prod();
+#else
+ ABI_CallFunctionC((void *)&DSPInterpreter::mul, opc);
+#endif
+}
+
+// MULAC $axS.l, $axS.h, $acR
+// 1001 s10r xxxx xxxx
+// Add product register to accumulator register $acR. Multiply low part
+// $axS.l of secondary accumulator $axS by high part $axS.h of secondary
+// accumulator $axS (treat them both as signed).
+
+// flags out: --xx xx0x
+//void DSPEmitter::mulac(const UDSPInstruction opc)
+//{
+// u8 rreg = (opc >> 8) & 0x1;
+// u8 sreg = (opc >> 11) & 0x1;
+
+// s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod();
+// u16 axl = dsp_get_ax_l(sreg);
+// u16 axh = dsp_get_ax_h(sreg);
+// s64 prod = dsp_multiply(axl, axh);
+//
+// zeroWriteBackLog();
+
+// dsp_set_long_prod(prod);
+// dsp_set_long_acc(rreg, acc);
+// Update_SR_Register64(dsp_get_long_acc(rreg));
+//}
+
+// MULMV $axS.l, $axS.h, $acR
+// 1001 s11r xxxx xxxx
+// Move product register to accumulator register $acR. Multiply low part
+// $axS.l of secondary accumulator $axS by high part $axS.h of secondary
+// accumulator $axS (treat them both as signed).
+
+// flags out: --xx xx0x
+void DSPEmitter::mulmv(const UDSPInstruction opc)
+{
+#ifdef _M_X64
+ u8 rreg = (opc >> 8) & 0x1;
+
+// s64 acc = dsp_get_long_prod();
+ get_long_prod();
+ PUSH(64, R(RAX));
+ mul(opc);
+// dsp_set_long_acc(rreg, acc);
+ POP(64, R(RAX));
+ set_long_acc(rreg);
+// Update_SR_Register64(dsp_get_long_acc(rreg));
+ Update_SR_Register64();
+#else
+ ABI_CallFunctionC((void *)&DSPInterpreter::mulmv, opc);
+#endif
+}
+
+// MULMVZ $axS.l, $axS.h, $acR
+// 1001 s01r xxxx xxxx
+// Move product register to accumulator register $acR and clear (round) low part
+// of accumulator register $acR.l. Multiply low part $axS.l of secondary
+// accumulator $axS by high part $axS.h of secondary accumulator $axS (treat
+// them both as signed).
+
+// flags out: --xx xx0x
+void DSPEmitter::mulmvz(const UDSPInstruction opc)
+{
+#ifdef _M_X64
+ u8 rreg = (opc >> 8) & 0x1;
+
+// s64 acc = dsp_get_long_prod_round_prodl();
+ get_long_prod_round_prodl();
+ PUSH(64, R(RAX));
+ mul(opc);
+// dsp_set_long_acc(rreg, acc);
+ POP(64, R(RAX));
+ set_long_acc(rreg);
+// Update_SR_Register64(dsp_get_long_acc(rreg));
+ Update_SR_Register64();
+#else
+ ABI_CallFunctionC((void *)&DSPInterpreter::mulmvz, opc);
+#endif
+}
+
+//----
+
+// MULX $ax0.S, $ax1.T
+// 101s t000 xxxx xxxx
+// Multiply one part $ax0 by one part $ax1.
+// Part is selected by S and T bits. Zero selects low part, one selects high part.
+//void DSPEmitter::mulx(const UDSPInstruction opc)
+//{
+// u8 treg = ((opc >> 11) & 0x1);
+// u8 sreg = ((opc >> 12) & 0x1);
+
+// u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
+// u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
+// s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2);
+
+// zeroWriteBackLog();
+
+// dsp_set_long_prod(prod);
+//}
+
+// MULXAC $ax0.S, $ax1.T, $acR
+// 101s t01r xxxx xxxx
+// Add product register to accumulator register $acR. Multiply one part
+// $ax0 by one part $ax1. Part is selected by S and
+// T bits. Zero selects low part, one selects high part.
+
+// flags out: --xx xx0x
+//void DSPEmitter::mulxac(const UDSPInstruction opc)
+//{
+// u8 rreg = (opc >> 8) & 0x1;
+// u8 treg = (opc >> 11) & 0x1;
+// u8 sreg = (opc >> 12) & 0x1;
+
+// s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod();
+// u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
+// u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
+// s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2);
+//
+// zeroWriteBackLog();
+
+// dsp_set_long_prod(prod);
+// dsp_set_long_acc(rreg, acc);
+// Update_SR_Register64(dsp_get_long_acc(rreg));
+//}
+
+// MULXMV $ax0.S, $ax1.T, $acR
+// 101s t11r xxxx xxxx
+// Move product register to accumulator register $acR. Multiply one part
+// $ax0 by one part $ax1. Part is selected by S and
+// T bits. Zero selects low part, one selects high part.
+
+// flags out: --xx xx0x
+//void DSPEmitter::mulxmv(const UDSPInstruction opc)
+//{
+// u8 rreg = ((opc >> 8) & 0x1);
+// u8 treg = (opc >> 11) & 0x1;
+// u8 sreg = (opc >> 12) & 0x1;
+
+// s64 acc = dsp_get_long_prod();
+// u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
+// u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
+// s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2);
+
+// zeroWriteBackLog();
+
+// dsp_set_long_prod(prod);
+// dsp_set_long_acc(rreg, acc);
+// Update_SR_Register64(dsp_get_long_acc(rreg));
+//}
+
+// MULXMV $ax0.S, $ax1.T, $acR
+// 101s t01r xxxx xxxx
+// Move product register to accumulator register $acR and clear (round) low part
+// of accumulator register $acR.l. Multiply one part $ax0 by one part $ax1
+// Part is selected by S and T bits. Zero selects low part,
+// one selects high part.
+
+// flags out: --xx xx0x
+//void DSPEmitter::mulxmvz(const UDSPInstruction opc)
+//{
+// u8 rreg = (opc >> 8) & 0x1;
+// u8 treg = (opc >> 11) & 0x1;
+// u8 sreg = (opc >> 12) & 0x1;
+
+// s64 acc = dsp_get_long_prod_round_prodl();
+// u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
+// u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
+// s64 prod = dsp_multiply_mulx(sreg, treg, val1, val2);
+
+// zeroWriteBackLog();
+
+// dsp_set_long_prod(prod);
+// dsp_set_long_acc(rreg, acc);
+// Update_SR_Register64(dsp_get_long_acc(rreg));
+//}
+
+//----
+
+// MULC $acS.m, $axT.h
+// 110s t000 xxxx xxxx
+// Multiply mid part of accumulator register $acS.m by high part $axS.h of
+// secondary accumulator $axS (treat them both as signed).
+void DSPEmitter::mulc(const UDSPInstruction opc)
+{
+#ifdef _M_X64
+ u8 treg = (opc >> 11) & 0x1;
+ u8 sreg = (opc >> 12) & 0x1;
+
+// u16 accm = dsp_get_acc_m(sreg);
+ MOV(64, R(R11), ImmPtr(&g_dsp.r));
+ MOVZX(64, 16, ESI, MDisp(R11, (DSP_REG_ACM0 + sreg) * 2));
+// u16 axh = dsp_get_ax_h(treg);
+ MOVZX(64, 16, EDI, MDisp(R11, (DSP_REG_AXH0 + treg) * 2));
+// s64 prod = dsp_multiply(accm, axh);
+ multiply();
+// dsp_set_long_prod(prod);
+ set_long_prod();
+#else
+ ABI_CallFunctionC((void *)&DSPInterpreter::mulc, opc);
+#endif
+}
+
+// MULCAC $acS.m, $axT.h, $acR
+// 110s t10r xxxx xxxx
+// Multiply mid part of accumulator register $acS.m by high part $axS.h of
+// secondary accumulator $axS (treat them both as signed). Add product
+// register before multiplication to accumulator $acR.
+
+// flags out: --xx xx0x
+//void DSPEmitter::mulcac(const UDSPInstruction opc)
+//{
+// u8 rreg = (opc >> 8) & 0x1;
+// u8 treg = (opc >> 11) & 0x1;
+// u8 sreg = (opc >> 12) & 0x1;
+
+// s64 acc = dsp_get_long_acc(rreg) + dsp_get_long_prod();
+// u16 accm = dsp_get_acc_m(sreg);
+// u16 axh = dsp_get_ax_h(treg);
+// s64 prod = dsp_multiply(accm, axh);
+//
+// zeroWriteBackLog();
+
+// dsp_set_long_prod(prod);
+// dsp_set_long_acc(rreg, acc);
+// Update_SR_Register64(dsp_get_long_acc(rreg));
+//}
+
+// MULCMV $acS.m, $axT.h, $acR
+// 110s t11r xxxx xxxx
+// Multiply mid part of accumulator register $acS.m by high part $axT.h of
+// secondary accumulator $axT (treat them both as signed). Move product
+// register before multiplication to accumulator $acR.
+// possible mistake in duddie's doc axT.h rather than axS.h
+
+// flags out: --xx xx0x
+//void DSPEmitter::mulcmv(const UDSPInstruction opc)
+//{
+// u8 rreg = (opc >> 8) & 0x1;
+// u8 treg = (opc >> 11) & 0x1;
+// u8 sreg = (opc >> 12) & 0x1;
+
+// s64 acc = dsp_get_long_prod();
+// u16 accm = dsp_get_acc_m(sreg);
+// u16 axh = dsp_get_ax_h(treg);
+// s64 prod = dsp_multiply(accm, axh);
+//
+// zeroWriteBackLog();
+
+// dsp_set_long_prod(prod);
+// dsp_set_long_acc(rreg, acc);
+// Update_SR_Register64(dsp_get_long_acc(rreg));
+//}
+
+// MULCMVZ $acS.m, $axT.h, $acR
+// 110s t01r xxxx xxxx
+// (fixed possible bug in duddie's description, s->t)
+// Multiply mid part of accumulator register $acS.m by high part $axT.h of
+// secondary accumulator $axT (treat them both as signed). Move product
+// register before multiplication to accumulator $acR, set (round) low part of
+// accumulator $acR.l to zero.
+
+// flags out: --xx xx0x
+//void DSPEmitter::mulcmvz(const UDSPInstruction opc)
+//{
+// u8 rreg = (opc >> 8) & 0x1;
+// u8 treg = (opc >> 11) & 0x1;
+// u8 sreg = (opc >> 12) & 0x1;
+
+// s64 acc = dsp_get_long_prod_round_prodl();
+// u16 accm = dsp_get_acc_m(sreg);
+// u16 axh = dsp_get_ax_h(treg);
+// s64 prod = dsp_multiply(accm, axh);
+//
+// zeroWriteBackLog();
+
+// dsp_set_long_prod(prod);
+// dsp_set_long_acc(rreg, acc);
+// Update_SR_Register64(dsp_get_long_acc(rreg));
+//}
+
+//----
+
+// MADDX ax0.S ax1.T
+// 1110 00st xxxx xxxx
+// Multiply one part of secondary accumulator $ax0 (selected by S) by
+// one part of secondary accumulator $ax1 (selected by T) (treat them both as
+// signed) and add result to product register.
+//void DSPEmitter::maddx(const UDSPInstruction opc)
+//{
+// u8 treg = (opc >> 8) & 0x1;
+// u8 sreg = (opc >> 9) & 0x1;
+
+// u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
+// u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
+// s64 prod = dsp_multiply_add(val1, val2);
+//
+// zeroWriteBackLog();
+
+// dsp_set_long_prod(prod);
+//}
+
+// MSUBX $(0x18+S*2), $(0x19+T*2)
+// 1110 01st xxxx xxxx
+// Multiply one part of secondary accumulator $ax0 (selected by S) by
+// one part of secondary accumulator $ax1 (selected by T) (treat them both as
+// signed) and subtract result from product register.
+//void DSPEmitter::msubx(const UDSPInstruction opc)
+//{
+// u8 treg = (opc >> 8) & 0x1;
+// u8 sreg = (opc >> 9) & 0x1;
+
+// u16 val1 = (sreg == 0) ? dsp_get_ax_l(0) : dsp_get_ax_h(0);
+// u16 val2 = (treg == 0) ? dsp_get_ax_l(1) : dsp_get_ax_h(1);
+// s64 prod = dsp_multiply_sub(val1, val2);
+
+// zeroWriteBackLog();
+
+// dsp_set_long_prod(prod);
+//}
+
+// MADDC $acS.m, $axT.h
+// 1110 10st xxxx xxxx
+// Multiply middle part of accumulator $acS.m by high part of secondary
+// accumulator $axT.h (treat them both as signed) and add result to product
+// register.
+//void DSPEmitter::maddc(const UDSPInstruction opc)
+//{
+// u8 treg = (opc >> 8) & 0x1;
+// u8 sreg = (opc >> 9) & 0x1;
+
+// u16 accm = dsp_get_acc_m(sreg);
+// u16 axh = dsp_get_ax_h(treg);
+// s64 prod = dsp_multiply_add(accm, axh);
+
+// zeroWriteBackLog();
+
+// dsp_set_long_prod(prod);
+//}
+
+// MSUBC $acS.m, $axT.h
+// 1110 11st xxxx xxxx
+// Multiply middle part of accumulator $acS.m by high part of secondary
+// accumulator $axT.h (treat them both as signed) and subtract result from
+// product register.
+//void DSPEmitter::msubc(const UDSPInstruction opc)
+//{
+// u8 treg = (opc >> 8) & 0x1;
+// u8 sreg = (opc >> 9) & 0x1;
+//
+// u16 accm = dsp_get_acc_m(sreg);
+// u16 axh = dsp_get_ax_h(treg);
+// s64 prod = dsp_multiply_sub(accm, axh);
+
+// zeroWriteBackLog();
+
+// dsp_set_long_prod(prod);
+//}
+
+// MADD $axS.l, $axS.h
+// 1111 001s xxxx xxxx
+// Multiply low part $axS.l of secondary accumulator $axS by high part
+// $axS.h of secondary accumulator $axS (treat them both as signed) and add
+// result to product register.
+//void DSPEmitter::madd(const UDSPInstruction opc)
+//{
+// u8 sreg = (opc >> 8) & 0x1;
+//
+// u16 axl = dsp_get_ax_l(sreg);
+// u16 axh = dsp_get_ax_h(sreg);
+// s64 prod = dsp_multiply_add(axl, axh);
+//
+// zeroWriteBackLog();
+
+// dsp_set_long_prod(prod);
+//}
+
+// MSUB $axS.l, $axS.h
+// 1111 011s xxxx xxxx
+// Multiply low part $axS.l of secondary accumulator $axS by high part
+// $axS.h of secondary accumulator $axS (treat them both as signed) and
+// subtract result from product register.
+//void DSPEmitter::msub(const UDSPInstruction opc)
+//{
+// u8 sreg = (opc >> 8) & 0x1;
+//
+// u16 axl = dsp_get_ax_l(sreg);
+// u16 axh = dsp_get_ax_h(sreg);
+// s64 prod = dsp_multiply_sub(axl, axh);
+//
+// zeroWriteBackLog();
+
+// dsp_set_long_prod(prod);
+//}
diff --git a/Source/Core/DSPCore/Src/Jit/DSPJitUtil.cpp b/Source/Core/DSPCore/Src/Jit/DSPJitUtil.cpp
index 950b3aa84b..fe24dc875d 100644
--- a/Source/Core/DSPCore/Src/Jit/DSPJitUtil.cpp
+++ b/Source/Core/DSPCore/Src/Jit/DSPJitUtil.cpp
@@ -402,4 +402,144 @@ void DSPEmitter::ext_dmem_read(u16 addr)
SetJumpTarget(end2);
}
+// Returns s64 in RAX
+// Clobbers RSI
+void DSPEmitter::get_long_prod()
+{
+#ifdef _M_X64
+ MOV(64, R(R11), ImmPtr(&g_dsp.r));
+ //s64 val = (s8)(u8)g_dsp.r[DSP_REG_PRODH];
+ MOVSX(64, 8, RAX, MDisp(R11,DSP_REG_PRODH*2));
+ //val <<= 32;
+ SHL(64, R(RAX), Imm8(32));
+ //s64 low_prod = g_dsp.r[DSP_REG_PRODM];
+ MOVSX(64, 16, RSI, MDisp(R11,DSP_REG_PRODM*2));
+ //low_prod += g_dsp.r[DSP_REG_PRODM2];
+ MOVSX(64, 16, EDI, MDisp(R11,DSP_REG_PRODM2*2));
+ ADD(16, R(RSI), R(EDI));
+ //low_prod <<= 16;
+ SHL(64, R(RSI), Imm8(16));
+ OR(64, R(RAX), R(RSI));
+ //low_prod |= g_dsp.r[DSP_REG_PRODL];
+ MOV(16, R(RAX), MDisp(R11,DSP_REG_PRODL*2));
+ //return val;
+#endif
+}
+
+// Returns s64 in RAX
+// Clobbers RSI
+void DSPEmitter::get_long_prod_round_prodl()
+{
+#ifdef _M_X64
+ //s64 prod = dsp_get_long_prod();
+ get_long_prod();
+
+ //if (prod & 0x10000) prod = (prod + 0x8000) & ~0xffff;
+ TEST(32, R(EAX), Imm32(0x10000));
+ FixupBranch jump = J_CC(CC_Z);
+ ADD(64, R(RAX), Imm32(0x8000));
+ MOV(64, R(ESI), Imm64(~0xffff));
+ AND(64, R(RAX), R(RSI));
+ FixupBranch ret = J();
+ //else prod = (prod + 0x7fff) & ~0xffff;
+ SetJumpTarget(jump);
+ ADD(64, R(RAX), Imm32(0x7fff));
+ MOV(64, R(RSI), Imm64(~0xffff));
+ AND(64, R(RAX), R(RSI));
+ SetJumpTarget(ret);
+ //return prod;
+#endif
+}
+
+// For accurate emulation, this is wrong - but the real prod registers behave
+// in completely bizarre ways. Probably not meaningful to emulate them accurately.
+// In: RAX = s64 val
+void DSPEmitter::set_long_prod()
+{
+#ifdef _M_X64
+ // g_dsp.r[DSP_REG_PRODL] = (u16)val;
+ MOV(64, R(R11), ImmPtr(&g_dsp.r));
+ MOV(16, MDisp(R11, DSP_REG_PRODL * 2), R(AX));
+ // val >>= 16;
+ SHR(64, R(RAX), Imm8(16));
+ // g_dsp.r[DSP_REG_PRODM] = (u16)val;
+ MOV(16, MDisp(R11, DSP_REG_PRODM * 2), R(AX));
+ // val >>= 16;
+ SHR(64, R(RAX), Imm8(16));
+ // g_dsp.r[DSP_REG_PRODH] = (u8)val;
+ MOVZX(64, 8, RAX, R(AL));
+ MOV(8, MDisp(R11, DSP_REG_PRODH * 2), R(AL));
+ // g_dsp.r[DSP_REG_PRODM2] = 0;
+ MOV(16, MDisp(R11, DSP_REG_PRODM2 * 2), Imm16(0));
+#endif
+}
+
+// Returns s64 in RAX
+// Clobbers ESI
+void DSPEmitter::get_long_acc(int _reg)
+{
+#ifdef _M_X64
+// s64 high = (s64)(s8)g_dsp.r[DSP_REG_ACH0 + reg] << 32;
+ MOV(64, R(R11), ImmPtr(&g_dsp.r));
+ MOVSX(64, 8, EAX, MDisp(R11, (DSP_REG_ACH0 + _reg) * 2));
+ SHL(64, R(EAX), Imm8(32));
+// u32 mid_low = ((u32)g_dsp.r[DSP_REG_ACM0 + reg] << 16) | g_dsp.r[DSP_REG_ACL0 + reg];
+ MOVZX(64, 16, RSI, MDisp(R11, (DSP_REG_ACM0 + _reg) * 2));
+ SHL(32, R(RSI), Imm8(16));
+ OR(64, R(EAX), R(RSI));
+ MOVZX(64, 16, RSI, MDisp(R11, (DSP_REG_ACL0 + _reg) * 2));
+ OR(64, R(EAX), R(RSI));
+// return high | mid_low;
+#endif
+}
+
+// In: RAX = s64 val
+void DSPEmitter::set_long_acc(int _reg)
+{
+#ifdef _M_X64
+// g_dsp.r[DSP_REG_ACL0 + _reg] = (u16)val;
+ MOV(64, R(R11), ImmPtr(&g_dsp.r));
+ MOV(16, MDisp(R11, (DSP_REG_ACL0 + _reg) * 2), R(AX));
+// val >>= 16;
+ SHR(64, R(RAX), Imm8(16));
+// g_dsp.r[DSP_REG_ACM0 + _reg] = (u16)val;
+ MOV(16, MDisp(R11, (DSP_REG_ACM0 + _reg) * 2), R(AX));
+// val >>= 16;
+ SHR(64, R(RAX), Imm8(16));
+// g_dsp.r[DSP_REG_ACH0 + _reg] = (u16)(s16)(s8)(u8)val;
+ MOVSX(16, 8, AX, R(AX));
+ MOV(16, MDisp(R11, (DSP_REG_ACH0 + _reg) * 2), R(AX));
+#endif
+}
+
+// Returns s16 in AX
+void DSPEmitter::get_acc_m(int _reg)
+{
+// return g_dsp.r[DSP_REG_ACM0 + _reg];
+#ifdef _M_X64
+ MOV(64, R(R11), ImmPtr(&g_dsp.r));
+ MOV(16, R(EAX), MDisp(R11, (DSP_REG_ACM0 + _reg) * 2));
+#endif
+}
+
+// Returns s16 in EAX
+void DSPEmitter::get_ax_l(int _reg)
+{
+// return (s16)g_dsp.r[DSP_REG_AXL0 + _reg];
+#ifdef _M_X64
+ MOV(64, R(R11), ImmPtr(&g_dsp.r));
+ MOV(16, R(EAX), MDisp(R11, (DSP_REG_AXL0 + _reg) * 2));
+#endif
+}
+
+// Returns s16 in EAX
+void DSPEmitter::get_ax_h(int _reg)
+{
+// return (s16)g_dsp.r[DSP_REG_AXH0 + _reg];
+#ifdef _M_X64
+ MOV(64, R(R11), ImmPtr(&g_dsp.r));
+ MOV(16, R(EAX), MDisp(R11, (DSP_REG_AXH0 + _reg) * 2));
+#endif
+}
+
#endif
diff --git a/Source/Core/DSPCore/Src/SConscript b/Source/Core/DSPCore/Src/SConscript
index d678e22e73..8628d4ed22 100644
--- a/Source/Core/DSPCore/Src/SConscript
+++ b/Source/Core/DSPCore/Src/SConscript
@@ -25,6 +25,8 @@ files = [
"DSPTables.cpp",
"Jit/DSPJitExtOps.cpp",
"Jit/DSPJitUtil.cpp",
+ "Jit/DSPJitCCUtil.cpp",
+ "Jit/DSPJitMultiplier.cpp",
"Jit/DSPJitMisc.cpp",
]