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", ]