diff --git a/Source/Core/DSPCore/CMakeLists.txt b/Source/Core/DSPCore/CMakeLists.txt index d428997e25..86623856d5 100644 --- a/Source/Core/DSPCore/CMakeLists.txt +++ b/Source/Core/DSPCore/CMakeLists.txt @@ -20,6 +20,7 @@ set(SRCS Src/assemble.cpp Src/DSPTables.cpp Src/Jit/DSPJitExtOps.cpp Src/Jit/DSPJitCCUtil.cpp + Src/Jit/DSPJitArithmetic.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 f28f061537..d40bf17399 100644 --- a/Source/Core/DSPCore/DSPCore.vcproj +++ b/Source/Core/DSPCore/DSPCore.vcproj @@ -458,6 +458,10 @@ RelativePath=".\Src\DSPEmitter.h" > + + diff --git a/Source/Core/DSPCore/Src/DSPEmitter.h b/Source/Core/DSPCore/Src/DSPEmitter.h index bbb8c97ebd..85979f214d 100644 --- a/Source/Core/DSPCore/Src/DSPEmitter.h +++ b/Source/Core/DSPCore/Src/DSPEmitter.h @@ -116,6 +116,11 @@ public: void mrr(const UDSPInstruction opc); void nx(const UDSPInstruction opc); + // Arithmetic + void addr(const UDSPInstruction opc); + void lsl16(const UDSPInstruction opc); + void lsl(const UDSPInstruction opc); + // Multipliers void get_multiply_prod(); void multiply(); diff --git a/Source/Core/DSPCore/Src/DSPTables.cpp b/Source/Core/DSPCore/Src/DSPTables.cpp index e9a5e0f7d8..8664eab5c0 100644 --- a/Source/Core/DSPCore/Src/DSPTables.cpp +++ b/Source/Core/DSPCore/Src/DSPTables.cpp @@ -149,7 +149,7 @@ const DSPOPCTemplate opcodes[] = {"SBCLR", 0x1200, 0xff00, DSPInterpreter::sbclr, &DSPEmitter::sbclr, 1, 1, {{P_IMM, 1, 0, 0, 0x0007}}, false, false, false}, {"SBSET", 0x1300, 0xff00, DSPInterpreter::sbset, &DSPEmitter::sbset, 1, 1, {{P_IMM, 1, 0, 0, 0x0007}}, false, false, false}, - {"LSL", 0x1400, 0xfec0, DSPInterpreter::lsl, NULL, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, false, false, false}, + {"LSL", 0x1400, 0xfec0, DSPInterpreter::lsl, &DSPEmitter::lsl, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, false, false, false}, {"LSR", 0x1440, 0xfec0, DSPInterpreter::lsr, NULL, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, false, false, false}, {"ASL", 0x1480, 0xfec0, DSPInterpreter::asl, NULL, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, false, false, false}, {"ASR", 0x14c0, 0xfec0, DSPInterpreter::asr, NULL, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_IMM, 1, 0, 0, 0x003f}}, false, false, false}, @@ -220,7 +220,7 @@ const DSPOPCTemplate opcodes[] = {"ASRNR", 0x3e80, 0xfe80, DSPInterpreter::asrnr, NULL, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACCM_D, 1, 0, 8, 0x0100}}, true, false, false}, //4 - {"ADDR", 0x4000, 0xf800, DSPInterpreter::addr, NULL, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0600}}, true, false, false}, + {"ADDR", 0x4000, 0xf800, DSPInterpreter::addr, &DSPEmitter::addr, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_REG18, 1, 0, 9, 0x0600}}, true, false, false}, {"ADDAX", 0x4800, 0xfc00, DSPInterpreter::addax, NULL, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_AX, 1, 0, 9, 0x0200}}, true, false, false}, {"ADD", 0x4c00, 0xfe00, DSPInterpreter::add, NULL, 1, 2, {{P_ACC, 1, 0, 8, 0x0100}, {P_ACC_D, 1, 0, 8, 0x0100}}, true, false, false}, {"ADDP", 0x4e00, 0xfe00, DSPInterpreter::addp, NULL, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false}, @@ -290,7 +290,7 @@ const DSPOPCTemplate opcodes[] = {"MSUBC", 0xec00, 0xfc00, DSPInterpreter::msubc, &DSPEmitter::msubc, 1, 2, {{P_ACCM, 1, 0, 9, 0x0200}, {P_REG19, 1, 0, 7, 0x0100}}, true, false, false}, //f - {"LSL16", 0xf000, 0xfe00, DSPInterpreter::lsl16, NULL, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false}, + {"LSL16", 0xf000, 0xfe00, DSPInterpreter::lsl16, &DSPEmitter::lsl16, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false}, {"MADD", 0xf200, 0xfe00, DSPInterpreter::madd, &DSPEmitter::madd, 1, 2, {{P_REG18, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 8, 0x0100}}, true, false, false}, {"LSR16", 0xf400, 0xfe00, DSPInterpreter::lsr16, NULL, 1, 1, {{P_ACC, 1, 0, 8, 0x0100}}, true, false, false}, {"MSUB", 0xf600, 0xfe00, DSPInterpreter::msub, &DSPEmitter::msub, 1, 2, {{P_REG18, 1, 0, 8, 0x0100}, {P_REG1A, 1, 0, 8, 0x0100}}, true, false, false}, diff --git a/Source/Core/DSPCore/Src/Jit/DSPJitArithmetic.cpp b/Source/Core/DSPCore/Src/Jit/DSPJitArithmetic.cpp new file mode 100644 index 0000000000..aa6d64f17e --- /dev/null +++ b/Source/Core/DSPCore/Src/Jit/DSPJitArithmetic.cpp @@ -0,0 +1,1151 @@ +// 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 + +#include "../DSPIntCCUtil.h" +#include "../DSPIntUtil.h" +#include "../DSPEmitter.h" +#include "x64Emitter.h" +#include "ABI.h" +using namespace Gen; + +// CLR $acR +// 1000 r001 xxxx xxxx +// Clears accumulator $acR +// +// flags out: --10 0100 +//void DSPEmitter::clr(const UDSPInstruction opc) +//{ +// u8 reg = (opc >> 11) & 0x1; + +// dsp_set_long_acc(reg, 0); +// Update_SR_Register64(0); +// zeroWriteBackLog(); +//} + +// CLRL $acR.l +// 1111 110r xxxx xxxx +// Clears (and rounds!) $acR.l - low 16 bits of accumulator $acR. +// +// flags out: --xx xx00 +//void DSPEmitter::clrl(const UDSPInstruction opc) +//{ +// u8 reg = (opc >> 8) & 0x1; +// s64 acc = dsp_round_long_acc(dsp_get_long_acc(reg)); + +// zeroWriteBackLog(); + +// dsp_set_long_acc(reg, acc); +// Update_SR_Register64(acc); +//} + +//---- + +// ANDCF $acD.m, #I +// 0000 001r 1100 0000 +// iiii iiii iiii iiii +// Set logic zero (LZ) flag in status register $sr if result of logic AND of +// accumulator mid part $acD.m with immediate value I is equal I. +// +// flags out: -x-- ---- +//void DSPEmitter::andcf(const UDSPInstruction opc) +//{ +// u8 reg = (opc >> 8) & 0x1; + +// u16 imm = dsp_fetch_code(); +// u16 val = dsp_get_acc_m(reg); +// Update_SR_LZ(((val & imm) == imm) ? true : false); +//} + +// ANDF $acD.m, #I +// 0000 001r 1010 0000 +// iiii iiii iiii iiii +// Set logic zero (LZ) flag in status register $sr if result of logical AND +// operation of accumulator mid part $acD.m with immediate value I is equal +// immediate value 0. +// +// flags out: -x-- ---- +//void DSPEmitter::andf(const UDSPInstruction opc) +//{ +// u8 reg = (opc >> 8) & 0x1; + +// u16 imm = dsp_fetch_code(); +// u16 val = dsp_get_acc_m(reg); +// Update_SR_LZ(((val & imm) == 0) ? true : false); +//} + +//---- + +// TST +// 1011 r001 xxxx xxxx +// Test accumulator %acR. +// +// flags out: --xx xx00 +//void DSPEmitter::tst(const UDSPInstruction opc) +//{ +// u8 reg = (opc >> 11) & 0x1; + +// s64 acc = dsp_get_long_acc(reg); +// Update_SR_Register64(acc); +// zeroWriteBackLog(); +//} + +// TSTAXH $axR.h +// 1000 011r xxxx xxxx +// Test high part of secondary accumulator $axR.h. +// +// flags out: --x0 xx00 +//void DSPEmitter::tstaxh(const UDSPInstruction opc) +//{ +// u8 reg = (opc >> 8) & 0x1; + +// s16 val = dsp_get_ax_h(reg); +// Update_SR_Register16(val); +// zeroWriteBackLog(); +//} + +//---- + +// CMP +// 1000 0010 xxxx xxxx +// Compares accumulator $ac0 with accumulator $ac1. +// +// flags out: x-xx xxxx +//void DSPEmitter::cmp(const UDSPInstruction opc) +//{ +// s64 acc0 = dsp_get_long_acc(0); +// s64 acc1 = dsp_get_long_acc(1); +// s64 res = dsp_convert_long_acc(acc0 - acc1); +// +// Update_SR_Register64(res, isCarry2(acc0, res), isOverflow(acc0, -acc1, res)); // CF -> influence on ABS/0xa100 +// zeroWriteBackLog(); +//} + +// CMPAR $acS axR.h +// 1100 0001 xxxx xxxx +// Compares accumulator $acS with accumulator axR.h. +// Not described by Duddie's doc - at least not as a separate instruction. +// +// flags out: x-xx xxxx +//void DSPEmitter::cmpar(const UDSPInstruction opc) +//{ +// u8 rreg = ((opc >> 12) & 0x1) + DSP_REG_AXH0; +// u8 sreg = (opc >> 11) & 0x1; + +// s64 sr = dsp_get_long_acc(sreg); +// s64 rr = (s16)g_dsp.r[rreg]; +// rr <<= 16; +// s64 res = dsp_convert_long_acc(sr - rr); +// +// Update_SR_Register64(res, isCarry2(sr, res), isOverflow(sr, -rr, res)); +// zeroWriteBackLog(); +//} + +// CMPI $amD, #I +// 0000 001r 1000 0000 +// iiii iiii iiii iiii +// Compares mid accumulator $acD.hm ($amD) with sign extended immediate value I. +// Although flags are being set regarding whole accumulator register. +// +// flags out: x-xx xxxx +//void DSPEmitter::cmpi(const UDSPInstruction opc) +//{ +// u8 reg = (opc >> 8) & 0x1; + +// s64 val = dsp_get_long_acc(reg); +// s64 imm = (s64)(s16)dsp_fetch_code() << 16; // Immediate is considered to be at M level in the 40-bit accumulator. +// s64 res = dsp_convert_long_acc(val - imm); + +// Update_SR_Register64(res, isCarry2(val, res), isOverflow(val, -imm, res)); +//} + +// CMPIS $acD, #I +// 0000 011d iiii iiii +// Compares accumulator with short immediate. Comaprison is executed +// by subtracting short immediate (8bit sign extended) from mid accumulator +// $acD.hm and computing flags based on whole accumulator $acD. +// +// flags out: x-xx xxxx +//void DSPEmitter::cmpis(const UDSPInstruction opc) +//{ +// u8 areg = (opc >> 8) & 0x1; + +// s64 acc = dsp_get_long_acc(areg); +// s64 val = (s8)opc; +// val <<= 16; +// s64 res = dsp_convert_long_acc(acc - val); + +// Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -val, res)); +//} + +//---- + +// XORR $acD.m, $axS.h +// 0011 00sd 0xxx xxxx +// Logic XOR (exclusive or) middle part of accumulator $acD.m with +// high part of secondary accumulator $axS.h. +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +//void DSPEmitter::xorr(const UDSPInstruction opc) +//{ +// u8 dreg = (opc >> 8) & 0x1; +// u8 sreg = (opc >> 9) & 0x1; +// u16 accm = g_dsp.r[DSP_REG_ACM0 + dreg] ^ g_dsp.r[DSP_REG_AXH0 + sreg]; +// +// zeroWriteBackLogPreserveAcc(dreg); + +// g_dsp.r[DSP_REG_ACM0 + dreg] = accm; +// Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); +//} + +// ANDR $acD.m, $axS.h +// 0011 01sd 0xxx xxxx +// Logic AND middle part of accumulator $acD.m with high part of +// secondary accumulator $axS.h. +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +//void DSPEmitter::andr(const UDSPInstruction opc) +//{ +// u8 dreg = (opc >> 8) & 0x1; +// u8 sreg = (opc >> 9) & 0x1; +// u16 accm = g_dsp.r[DSP_REG_ACM0 + dreg] & g_dsp.r[DSP_REG_AXH0 + sreg]; +// +// zeroWriteBackLogPreserveAcc(dreg); + +// g_dsp.r[DSP_REG_ACM0 + dreg] = accm; +// Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); +//} + +// ORR $acD.m, $axS.h +// 0011 10sd 0xxx xxxx +// Logic OR middle part of accumulator $acD.m with high part of +// secondary accumulator $axS.h. +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +//void DSPEmitter::orr(const UDSPInstruction opc) +//{ +// u8 dreg = (opc >> 8) & 0x1; +// u8 sreg = (opc >> 9) & 0x1; +// u16 accm = g_dsp.r[DSP_REG_ACM0 + dreg] | g_dsp.r[DSP_REG_AXH0 + sreg]; +// +// zeroWriteBackLogPreserveAcc(dreg); + +// g_dsp.r[DSP_REG_ACM0 + dreg] = accm; +// Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); +//} + +// ANDC $acD.m, $ac(1-D).m +// 0011 110d 0xxx xxxx +// Logic AND middle part of accumulator $acD.m with middle part of +// accumulator $ac(1-D).m +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +//void DSPEmitter::andc(const UDSPInstruction opc) +//{ +// u8 dreg = (opc >> 8) & 0x1; +// u16 accm = g_dsp.r[DSP_REG_ACM0 + dreg] & g_dsp.r[DSP_REG_ACM0 + (1 - dreg)]; +// +// zeroWriteBackLogPreserveAcc(dreg); + +// g_dsp.r[DSP_REG_ACM0 + dreg] = accm; +// Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); +//} + +// ORC $acD.m, $ac(1-D).m +// 0011 111d 0xxx xxxx +// Logic OR middle part of accumulator $acD.m with middle part of +// accumulator $ac(1-D).m. +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +//void DSPEmitter::orc(const UDSPInstruction opc) +//{ +// u8 dreg = (opc >> 8) & 0x1; +// u16 accm = g_dsp.r[DSP_REG_ACM0 + dreg] | g_dsp.r[DSP_REG_ACM0 + (1 - dreg)]; +// +// zeroWriteBackLogPreserveAcc(dreg); + +// g_dsp.r[DSP_REG_ACM0 + dreg] = accm; +// Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); +//} + +// XORC $acD.m +// 0011 000d 1xxx xxxx +// Logic XOR (exclusive or) middle part of accumulator $acD.m with $ac(1-D).m +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +//void DSPEmitter::xorc(const UDSPInstruction opc) +//{ +// u8 dreg = (opc >> 8) & 0x1; +// u16 accm = g_dsp.r[DSP_REG_ACM0 + dreg] ^ g_dsp.r[DSP_REG_ACM0 + (1 - dreg)]; + +// zeroWriteBackLogPreserveAcc(dreg); + +// g_dsp.r[DSP_REG_ACM0 + dreg] = accm; +// Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); +//} + +// NOT $acD.m +// 0011 001d 1xxx xxxx +// Invert all bits in dest reg, aka xor with 0xffff +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +//void DSPEmitter::notc(const UDSPInstruction opc) +//{ +// u8 dreg = (opc >> 8) & 0x1; +// u16 accm = g_dsp.r[DSP_REG_ACM0 + dreg] ^ 0xffff; + +// zeroWriteBackLogPreserveAcc(dreg); + +// g_dsp.r[DSP_REG_ACM0 + dreg] = accm; +// Update_SR_Register16((s16)accm, false, false, isOverS32(dsp_get_long_acc(dreg))); +//} + +// XORI $acD.m, #I +// 0000 001r 0010 0000 +// iiii iiii iiii iiii +// Logic exclusive or (XOR) of accumulator mid part $acD.m with +// immediate value I. +// +// flags out: --xx xx00 +//void DSPEmitter::xori(const UDSPInstruction opc) +//{ +// u8 reg = (opc >> 8) & 0x1; +// u16 imm = dsp_fetch_code(); +// g_dsp.r[DSP_REG_ACM0 + reg] ^= imm; + +// Update_SR_Register16((s16)g_dsp.r[DSP_REG_ACM0 + reg], false, false, isOverS32(dsp_get_long_acc(reg))); +//} + +// ANDI $acD.m, #I +// 0000 001r 0100 0000 +// iiii iiii iiii iiii +// Logic AND of accumulator mid part $acD.m with immediate value I. +// +// flags out: --xx xx00 +//void DSPEmitter::andi(const UDSPInstruction opc) +//{ +// u8 reg = (opc >> 8) & 0x1; +// u16 imm = dsp_fetch_code(); +// g_dsp.r[DSP_REG_ACM0 + reg] &= imm; + +// Update_SR_Register16((s16)g_dsp.r[DSP_REG_ACM0 + reg], false, false, isOverS32(dsp_get_long_acc(reg))); +//} + +// ORI $acD.m, #I +// 0000 001r 0110 0000 +// iiii iiii iiii iiii +// Logic OR of accumulator mid part $acD.m with immediate value I. +// +// flags out: --xx xx00 +//void DSPEmitter::ori(const UDSPInstruction opc) +//{ +// u8 reg = (opc >> 8) & 0x1; +// u16 imm = dsp_fetch_code(); +// g_dsp.r[DSP_REG_ACM0 + reg] |= imm; + +// Update_SR_Register16((s16)g_dsp.r[DSP_REG_ACM0 + reg], false, false, isOverS32(dsp_get_long_acc(reg))); +//} + +//---- + +// ADDR $acD.M, $axS.L +// 0100 0ssd xxxx xxxx +// Adds register $axS.L to accumulator $acD.M register. +// +// flags out: x-xx xxxx +void DSPEmitter::addr(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 dreg = (opc >> 8) & 0x1; + u8 sreg = ((opc >> 9) & 0x3) + DSP_REG_AXL0; + + MOV(64, R(R11), ImmPtr(&g_dsp.r)); +// s64 acc = dsp_get_long_acc(dreg); + get_long_acc(dreg); + PUSH(64, R(RAX)); +// s64 ax = (s16)g_dsp.r[sreg]; + MOV(16, R(RDX), MDisp(R11, sreg * 2)); +// ax <<= 16; + SHL(64, R(RDX), Imm8(16)); +// s64 res = acc + ax; + ADD(64, R(RAX), R(RDX)); +// dsp_set_long_acc(dreg, res); + set_long_acc(dreg); +// Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, ax, res)); + XOR(8, R(RSI), R(RSI)); + POP(64, R(RCX)); + CMP(64, R(RCX), R(RAX)); + + // Carry = (acc>res) + FixupBranch noCarry = J_CC(CC_G); + OR(8, R(RSI), Imm8(1)); + SetJumpTarget(noCarry); + + // Overflow = ((acc ^ res) & (ax ^ res)) < 0 + XOR(64, R(RCX), R(RAX)); + XOR(64, R(RDX), R(RAX)); + AND(64, R(RCX), R(RDX)); + CMP(64, R(RCX), Imm8(0)); + FixupBranch noOverflow = J_CC(CC_L); + OR(8, R(RSI), Imm8(2)); + SetJumpTarget(noOverflow); + + Update_SR_Register64(); +#else + ABI_CallFunctionC((void *)&DSPInterpreter::addr, opc); +#endif +} + +// ADDAX $acD, $axS +// 0100 10sd xxxx xxxx +// Adds secondary accumulator $axS to accumulator register $acD. +// +// flags out: x-xx xxxx +//void DSPEmitter::addax(const UDSPInstruction opc) +//{ +// u8 dreg = (opc >> 8) & 0x1; +// u8 sreg = (opc >> 9) & 0x1; + +// s64 acc = dsp_get_long_acc(dreg); +// s64 ax = dsp_get_long_acx(sreg); +// s64 res = acc + ax; + +// zeroWriteBackLog(); + +// dsp_set_long_acc(dreg, res); +// res = dsp_get_long_acc(dreg); +// Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, ax, res)); +//} + +// ADD $acD, $ac(1-D) +// 0100 110d xxxx xxxx +// Adds accumulator $ac(1-D) to accumulator register $acD. +// +// flags out: x-xx xxxx +//void DSPEmitter::add(const UDSPInstruction opc) +//{ +// u8 dreg = (opc >> 8) & 0x1; + +// s64 acc0 = dsp_get_long_acc(dreg); +// s64 acc1 = dsp_get_long_acc(1 - dreg); +// s64 res = acc0 + acc1; + +// zeroWriteBackLog(); + +// dsp_set_long_acc(dreg, res); +// res = dsp_get_long_acc(dreg); +// Update_SR_Register64(res, isCarry(acc0, res), isOverflow(acc0, acc1, res)); +//} + +// ADDP $acD +// 0100 111d xxxx xxxx +// Adds product register to accumulator register. +// +// flags out: x-xx xxxx +//void DSPEmitter::addp(const UDSPInstruction opc) +//{ +// u8 dreg = (opc >> 8) & 0x1; + +// s64 acc = dsp_get_long_acc(dreg); +// s64 prod = dsp_get_long_prod(); +// s64 res = acc + prod; + +// zeroWriteBackLog(); + +// dsp_set_long_acc(dreg, res); +// res = dsp_get_long_acc(dreg); +// Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, prod, res)); +//} + +// ADDAXL $acD, $axS.l +// 0111 00sd xxxx xxxx +// Adds secondary accumulator $axS.l to accumulator register $acD. +// should be unsigned values!! +// +// flags out: x-xx xxxx +//void DSPEmitter::addaxl(const UDSPInstruction opc) +//{ +// u8 sreg = (opc >> 9) & 0x1; +// u8 dreg = (opc >> 8) & 0x1; + +// u64 acc = dsp_get_long_acc(dreg); +// u16 acx = (u16)dsp_get_ax_l(sreg); + +// u64 res = acc + acx; + +// zeroWriteBackLog(); + +// 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)); +//} + +// ADDI $amR, #I +// 0000 001r 0000 0000 +// iiii iiii iiii iiii +// Adds immediate (16-bit sign extended) to mid accumulator $acD.hm. +// +// flags out: x-xx xxxx +//void DSPEmitter::addi(const UDSPInstruction opc) +//{ +// u8 areg = (opc >> 8) & 0x1; + +// s64 acc = dsp_get_long_acc(areg); +// s64 imm = (s16)dsp_fetch_code(); +// imm <<= 16; +// s64 res = acc + imm; + +// dsp_set_long_acc(areg, res); +// res = dsp_get_long_acc(areg); +// Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, imm, res)); +//} + +// ADDIS $acD, #I +// 0000 010d iiii iiii +// Adds short immediate (8-bit sign extended) to mid accumulator $acD.hm. +// +// flags out: x-xx xxxx +//void DSPEmitter::addis(const UDSPInstruction opc) +//{ +// u8 dreg = (opc >> 8) & 0x1; + +// s64 acc = dsp_get_long_acc(dreg); +// s64 imm = (s8)(u8)opc; +// imm <<= 16; +// s64 res = acc + imm; + +// dsp_set_long_acc(dreg, res); +// res = dsp_get_long_acc(dreg); +// Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, imm, res)); +//} + +// INCM $acsD +// 0111 010d xxxx xxxx +// Increment 24-bit mid-accumulator $acsD. +// +// flags out: x-xx xxxx +//void DSPEmitter::incm(const UDSPInstruction opc) +//{ +// u8 dreg = (opc >> 8) & 0x1; + +// s64 sub = 0x10000; +// s64 acc = dsp_get_long_acc(dreg); +// s64 res = acc + sub; + +// zeroWriteBackLog(); +// +// dsp_set_long_acc(dreg, res); +// res = dsp_get_long_acc(dreg); +// Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, sub, res)); +//} + +// INC $acD +// 0111 011d xxxx xxxx +// Increment accumulator $acD. +// +// flags out: x-xx xxxx +//void DSPEmitter::inc(const UDSPInstruction opc) +//{ +// u8 dreg = (opc >> 8) & 0x1; + +// s64 acc = dsp_get_long_acc(dreg); +// s64 res = acc + 1; + +// zeroWriteBackLog(); + +// dsp_set_long_acc(dreg, res); +// res = dsp_get_long_acc(dreg); +// Update_SR_Register64(res, isCarry(acc, res), isOverflow(acc, 1, res)); +//} + +//---- + +// SUBR $acD.M, $axS.L +// 0101 0ssd xxxx xxxx +// Subtracts register $axS.L from accumulator $acD.M register. +// +// flags out: x-xx xxxx +//void DSPEmitter::subr(const UDSPInstruction opc) +//{ +// u8 dreg = (opc >> 8) & 0x1; +// u8 sreg = ((opc >> 9) & 0x3) + DSP_REG_AXL0; + +// s64 acc = dsp_get_long_acc(dreg); +// s64 ax = (s16)g_dsp.r[sreg]; +// ax <<= 16; +// s64 res = acc - ax; + +// zeroWriteBackLog(); + +// dsp_set_long_acc(dreg, res); +// res = dsp_get_long_acc(dreg); +// Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -ax, res)); +//} + +// SUBAX $acD, $axS +// 0101 10sd xxxx xxxx +// Subtracts secondary accumulator $axS from accumulator register $acD. +// +// flags out: x-xx xxxx +//void DSPEmitter::subax(const UDSPInstruction opc) +//{ +// u8 dreg = (opc >> 8) & 0x1; +// u8 sreg = (opc >> 9) & 0x1; + +// s64 acc = dsp_get_long_acc(dreg); +// s64 acx = dsp_get_long_acx(sreg); +// s64 res = acc - acx; + +// zeroWriteBackLog(); + +// dsp_set_long_acc(dreg, res); +// res = dsp_get_long_acc(dreg); +// Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -acx, res)); +//} + +// SUB $acD, $ac(1-D) +// 0101 110d xxxx xxxx +// Subtracts accumulator $ac(1-D) from accumulator register $acD. +// +// flags out: x-xx xxxx +//void DSPEmitter::sub(const UDSPInstruction opc) +//{ +// u8 dreg = (opc >> 8) & 0x1; + +// s64 acc1 = dsp_get_long_acc(dreg); +// s64 acc2 = dsp_get_long_acc(1 - dreg); +// s64 res = acc1 - acc2; + +// zeroWriteBackLog(); + +// dsp_set_long_acc(dreg, res); +// res = dsp_get_long_acc(dreg); +// Update_SR_Register64(res, isCarry2(acc1, res), isOverflow(acc1, -acc2, res)); +//} + +// SUBP $acD +// 0101 111d xxxx xxxx +// Subtracts product register from accumulator register. +// +// flags out: x-xx xxxx +//void DSPEmitter::subp(const UDSPInstruction opc) +//{ +// u8 dreg = (opc >> 8) & 0x1; + +// s64 acc = dsp_get_long_acc(dreg); +// s64 prod = dsp_get_long_prod(); +// s64 res = acc - prod; + +// zeroWriteBackLog(); + +// dsp_set_long_acc(dreg, res); +// res = dsp_get_long_acc(dreg); +// Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -prod, res)); +//} + +// DECM $acsD +// 0111 100d xxxx xxxx +// Decrement 24-bit mid-accumulator $acsD. +// +// flags out: x-xx xxxx +//void DSPEmitter::decm(const UDSPInstruction opc) +//{ +// u8 dreg = (opc >> 8) & 0x01; + +// s64 sub = 0x10000; +// s64 acc = dsp_get_long_acc(dreg); +// s64 res = acc - sub; + +// zeroWriteBackLog(); +// +// dsp_set_long_acc(dreg, res); +// res = dsp_get_long_acc(dreg); +// Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -sub, res)); +//} + +// DEC $acD +// 0111 101d xxxx xxxx +// Decrement accumulator $acD. +// +// flags out: x-xx xxxx +//void DSPEmitter::dec(const UDSPInstruction opc) +//{ +// u8 dreg = (opc >> 8) & 0x01; + +// s64 acc = dsp_get_long_acc(dreg); +// s64 res = acc - 1; + +// zeroWriteBackLog(); + +// dsp_set_long_acc(dreg, res); +// res = dsp_get_long_acc(dreg); +// Update_SR_Register64(res, isCarry2(acc, res), isOverflow(acc, -1, res)); +//} + +//---- + +// NEG $acD +// 0111 110d xxxx xxxx +// Negate accumulator $acD. +// +// flags out: --xx xx00 +//void DSPEmitter::neg(const UDSPInstruction opc) +//{ +// u8 dreg = (opc >> 8) & 0x1; +// +// s64 acc = dsp_get_long_acc(dreg); +// acc = 0 - acc; + +// zeroWriteBackLog(); + +// dsp_set_long_acc(dreg, acc); +// Update_SR_Register64(dsp_get_long_acc(dreg)); +//} + +// ABS $acD +// 1010 d001 xxxx xxxx +// absolute value of $acD +// +// flags out: --xx xx00 +//void DSPEmitter::abs(const UDSPInstruction opc) +//{ +// u8 dreg = (opc >> 11) & 0x1; + +// s64 acc = dsp_get_long_acc(dreg); + +// if (acc < 0) +// acc = 0 - acc; +// +// zeroWriteBackLog(); + +// dsp_set_long_acc(dreg, acc); +// Update_SR_Register64(dsp_get_long_acc(dreg)); +//} +//---- + +// MOVR $acD, $axS.R +// 0110 0srd xxxx xxxx +// Moves register $axS.R (sign extended) to middle accumulator $acD.hm. +// Sets $acD.l to 0. +// TODO: Check what happens to acD.h. +// +// flags out: --xx xx00 +//void DSPEmitter::movr(const UDSPInstruction opc) +//{ +// u8 areg = (opc >> 8) & 0x1; +// u8 sreg = ((opc >> 9) & 0x3) + DSP_REG_AXL0; +// +// s64 acc = (s16)g_dsp.r[sreg]; +// acc <<= 16; +// acc &= ~0xffff; + +// zeroWriteBackLog(); + +// dsp_set_long_acc(areg, acc); +// Update_SR_Register64(acc); +//} + +// MOVAX $acD, $axS +// 0110 10sd xxxx xxxx +// Moves secondary accumulator $axS to accumulator $axD. +// +// flags out: --xx xx00 +//void DSPEmitter::movax(const UDSPInstruction opc) +//{ +// u8 dreg = (opc >> 8) & 0x1; +// u8 sreg = (opc >> 9) & 0x1; + +// s64 acx = dsp_get_long_acx(sreg); + +// zeroWriteBackLog(); + +// dsp_set_long_acc(dreg, acx); +// Update_SR_Register64(acx); +//} + +// MOV $acD, $ac(1-D) +// 0110 110d xxxx xxxx +// Moves accumulator $ax(1-D) to accumulator $axD. +// +// flags out: --x0 xx00 +//void DSPEmitter::mov(const UDSPInstruction opc) +//{ +// u8 dreg = (opc >> 8) & 0x1; +// u64 acc = dsp_get_long_acc(1 - dreg); + +// zeroWriteBackLog(); + +// dsp_set_long_acc(dreg, acc); +// Update_SR_Register64(acc); +//} + +//---- + +// LSL16 $acR +// 1111 000r xxxx xxxx +// Logically shifts left accumulator $acR by 16. +// +// flags out: --xx xx00 +void DSPEmitter::lsl16(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 areg = (opc >> 8) & 0x1; +// s64 acc = dsp_get_long_acc(areg); + get_long_acc(areg); +// acc <<= 16; + SHL(64, R(RAX), Imm8(16)); +// dsp_set_long_acc(areg, acc); + set_long_acc(areg); +// Update_SR_Register64(dsp_get_long_acc(areg)); + Update_SR_Register64(); +#else + ABI_CallFunctionC((void *)&DSPInterpreter::lsl16, opc); +#endif +} + +// LSR16 $acR +// 1111 010r xxxx xxxx +// Logically shifts right accumulator $acR by 16. +// +// flags out: --xx xx00 +//void DSPEmitter::lsr16(const UDSPInstruction opc) +//{ +// u8 areg = (opc >> 8) & 0x1; + +// u64 acc = dsp_get_long_acc(areg); +// acc &= 0x000000FFFFFFFFFFULL; // Lop off the extraneous sign extension our 64-bit fake accum causes +// acc >>= 16; + +// zeroWriteBackLog(); + +// dsp_set_long_acc(areg, (s64)acc); +// Update_SR_Register64(dsp_get_long_acc(areg)); +//} + +// ASR16 $acR +// 1001 r001 xxxx xxxx +// Arithmetically shifts right accumulator $acR by 16. +// +// flags out: --xx xx00 +//void DSPEmitter::asr16(const UDSPInstruction opc) +//{ +// u8 areg = (opc >> 11) & 0x1; + +// s64 acc = dsp_get_long_acc(areg); +// acc >>= 16; + +// zeroWriteBackLog(); + +// dsp_set_long_acc(areg, acc); +// Update_SR_Register64(dsp_get_long_acc(areg)); +//} + +// LSL $acR, #I +// 0001 010r 00ii iiii +// Logically shifts left accumulator $acR by number specified by value I. +// +// flags out: --xx xx00 +void DSPEmitter::lsl(const UDSPInstruction opc) +{ +#ifdef _M_X64 + u8 rreg = (opc >> 8) & 0x01; + u16 shift = opc & 0x3f; +// u64 acc = dsp_get_long_acc(rreg); + get_long_acc(rreg); + +// acc <<= shift; + SHL(64, R(RAX), Imm8(shift)); + +// dsp_set_long_acc(rreg, acc); + set_long_acc(rreg); +// Update_SR_Register64(dsp_get_long_acc(rreg)); + Update_SR_Register64(); +#else + ABI_CallFunctionC((void *)&DSPInterpreter::lsl, opc); +#endif +} + +// LSR $acR, #I +// 0001 010r 01ii iiii +// Logically shifts right accumulator $acR by number specified by value +// calculated by negating sign extended bits 0-6. +// +// flags out: --xx xx00 +//void DSPEmitter::lsr(const UDSPInstruction opc) +//{ +// u8 rreg = (opc >> 8) & 0x01; +// u16 shift; +// u64 acc = dsp_get_long_acc(rreg); +// acc &= 0x000000FFFFFFFFFFULL; // Lop off the extraneous sign extension our 64-bit fake accum causes + +// if ((opc & 0x3f) == 0) +// shift = 0; +// else +// shift = 0x40 - (opc & 0x3f); + +// acc >>= shift; +// +// dsp_set_long_acc(rreg, (s64)acc); +// Update_SR_Register64(dsp_get_long_acc(rreg)); +//} + +// ASL $acR, #I +// 0001 010r 10ii iiii +// Logically shifts left accumulator $acR by number specified by value I. +// +// flags out: --xx xx00 +//void DSPEmitter::asl(const UDSPInstruction opc) +//{ +// u8 rreg = (opc >> 8) & 0x01; +// u16 shift = opc & 0x3f; +// u64 acc = dsp_get_long_acc(rreg); + +// acc <<= shift; +// +// dsp_set_long_acc(rreg, acc); +// Update_SR_Register64(dsp_get_long_acc(rreg)); +//} + +// ASR $acR, #I +// 0001 010r 11ii iiii +// Arithmetically shifts right accumulator $acR by number specified by +// value calculated by negating sign extended bits 0-6. +// +// flags out: --xx xx00 +//void DSPEmitter::asr(const UDSPInstruction opc) +//{ +// u8 dreg = (opc >> 8) & 0x01; +// u16 shift; + +// if ((opc & 0x3f) == 0) +// shift = 0; +// else +// shift = 0x40 - (opc & 0x3f); + +// // arithmetic shift +// s64 acc = dsp_get_long_acc(dreg); +// acc >>= shift; + +// dsp_set_long_acc(dreg, acc); +// Update_SR_Register64(dsp_get_long_acc(dreg)); +//} + +// LSRN (fixed parameters) +// 0000 0010 1100 1010 +// Logically shifts right accumulator $ACC0 by lower 7-bit (signed) value in $AC1.M +// (if value negative, becomes left shift). +// +// flags out: --xx xx00 +//void DSPEmitter::lsrn(const UDSPInstruction opc) +//{ +// s16 shift; +// u16 accm = (u16)dsp_get_acc_m(1); +// u64 acc = dsp_get_long_acc(0); +// acc &= 0x000000FFFFFFFFFFULL; + +// if ((accm & 0x3f) == 0) +// shift = 0; +// else if (accm & 0x40) +// shift = -0x40 + (accm & 0x3f); +// else +// shift = accm & 0x3f; + +// if (shift > 0) { +// acc >>= shift; +// } else if (shift < 0) { +// acc <<= -shift; +// } + +// dsp_set_long_acc(0, (s64)acc); +// Update_SR_Register64(dsp_get_long_acc(0)); +//} + +// ASRN (fixed parameters) +// 0000 0010 1100 1011 +// Arithmetically shifts right accumulator $ACC0 by lower 7-bit (signed) value in $AC1.M +// (if value negative, becomes left shift). +// +// flags out: --xx xx00 +//void DSPEmitter::asrn(const UDSPInstruction opc) +//{ +// s16 shift; +// u16 accm = (u16)dsp_get_acc_m(1); +// s64 acc = dsp_get_long_acc(0); + +// if ((accm & 0x3f) == 0) +// shift = 0; +// else if (accm & 0x40) +// shift = -0x40 + (accm & 0x3f); +// else +// shift = accm & 0x3f; + +// if (shift > 0) { +// acc >>= shift; +// } else if (shift < 0) { +// acc <<= -shift; +// } + +// dsp_set_long_acc(0, acc); +// Update_SR_Register64(dsp_get_long_acc(0)); +//} + +// LSRNRX $acD, $axS.h +// 0011 01sd 1xxx xxxx +// Logically shifts left/right accumulator $ACC[D] by lower 7-bit (signed) value in $AX[S].H +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +//void DSPEmitter::lsrnrx(const UDSPInstruction opc) +//{ +// u8 dreg = (opc >> 8) & 0x1; +// u8 sreg = (opc >> 9) & 0x1; + +// s16 shift; +// u16 axh = g_dsp.r[DSP_REG_AXH0 + sreg]; +// u64 acc = dsp_get_long_acc(dreg); +// acc &= 0x000000FFFFFFFFFFULL; + +// if ((axh & 0x3f) == 0) +// shift = 0; +// else if (axh & 0x40) +// shift = -0x40 + (axh & 0x3f); +// else +// shift = axh & 0x3f; + +// if (shift > 0) { +// acc <<= shift; +// } else if (shift < 0) { +// acc >>= -shift; +// } + +// zeroWriteBackLog(); + +// dsp_set_long_acc(dreg, (s64)acc); +// Update_SR_Register64(dsp_get_long_acc(dreg)); +//} + +// ASRNRX $acD, $axS.h +// 0011 10sd 1xxx xxxx +// Arithmetically shifts left/right accumulator $ACC[D] by lower 7-bit (signed) value in $AX[S].H +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +//void DSPEmitter::asrnrx(const UDSPInstruction opc) +//{ +// u8 dreg = (opc >> 8) & 0x1; +// u8 sreg = (opc >> 9) & 0x1; + +// s16 shift; +// u16 axh = g_dsp.r[DSP_REG_AXH0 + sreg]; +// s64 acc = dsp_get_long_acc(dreg); + +// if ((axh & 0x3f) == 0) +// shift = 0; +// else if (axh & 0x40) +// shift = -0x40 + (axh & 0x3f); +// else +// shift = axh & 0x3f; + +// if (shift > 0) { +// acc <<= shift; +// } else if (shift < 0) { +// acc >>= -shift; +// } + +// zeroWriteBackLog(); + +// dsp_set_long_acc(dreg, acc); +// Update_SR_Register64(dsp_get_long_acc(dreg)); +//} + +// LSRNR $acD +// 0011 110d 1xxx xxxx +// Logically shifts left/right accumulator $ACC[D] by lower 7-bit (signed) value in $AC[1-D].M +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +//void DSPEmitter::lsrnr(const UDSPInstruction opc) +//{ +// u8 dreg = (opc >> 8) & 0x1; + +// s16 shift; +// u16 accm = (u16)dsp_get_acc_m(1 - dreg); +// u64 acc = dsp_get_long_acc(dreg); +// acc &= 0x000000FFFFFFFFFFULL; + +// if ((accm & 0x3f) == 0) +// shift = 0; +// else if (accm & 0x40) +// shift = -0x40 + (accm & 0x3f); +// else +// shift = accm & 0x3f; + +// if (shift > 0) +// acc <<= shift; +// else if (shift < 0) +// acc >>= -shift; + +// zeroWriteBackLog(); + +// dsp_set_long_acc(dreg, (s64)acc); +// Update_SR_Register64(dsp_get_long_acc(dreg)); +//} + +// ASRNR $acD +// 0011 111d 1xxx xxxx +// Arithmeticaly shift left/right accumulator $ACC[D] by lower 7-bit (signed) value in $AC[1-D].M +// x = extension (7 bits!!) +// +// flags out: --xx xx00 +//void DSPEmitter::asrnr(const UDSPInstruction opc) +//{ +// u8 dreg = (opc >> 8) & 0x1; + +// s16 shift; +// u16 accm = (u16)dsp_get_acc_m(1 - dreg); +// s64 acc = dsp_get_long_acc(dreg); + +// if ((accm & 0x3f) == 0) +// shift = 0; +// else if (accm & 0x40) +// shift = -0x40 + (accm & 0x3f); +// else +// shift = accm & 0x3f; + +// if (shift > 0) +// acc <<= shift; +// else if (shift < 0) +// acc >>= -shift; + +// zeroWriteBackLog(); + +// dsp_set_long_acc(dreg, acc); +// Update_SR_Register64(dsp_get_long_acc(dreg)); +//} + + +//} // namespace + +// diff --git a/Source/Core/DSPCore/Src/Jit/DSPJitCCUtil.cpp b/Source/Core/DSPCore/Src/Jit/DSPJitCCUtil.cpp index 0fb91a84fb..d0e0e9b7d8 100644 --- a/Source/Core/DSPCore/Src/Jit/DSPJitCCUtil.cpp +++ b/Source/Core/DSPCore/Src/Jit/DSPJitCCUtil.cpp @@ -26,7 +26,8 @@ #include "ABI.h" using namespace Gen; -// In: RAX: s64 _Value, +// In: RAX: s64 _Value +// In: RCX: 1 = carry, 2 = overflow // Clobbers RDX void DSPEmitter::Update_SR_Register64(bool carry, bool overflow) { @@ -36,18 +37,18 @@ void DSPEmitter::Update_SR_Register64(bool carry, bool overflow) // 0x01 // g_dsp.r[DSP_REG_SR] |= SR_CARRY; - if (carry) - { - OR(16, MDisp(R11, DSP_REG_SR * 2), Imm16(SR_CARRY)); - } + TEST(8, R(RSI), Imm8(1)); + FixupBranch noCarry = J_CC(CC_NZ); + OR(16, MDisp(R11, DSP_REG_SR * 2), 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; - if (overflow) - { - OR(16, MDisp(R11, DSP_REG_SR * 2), Imm16(SR_OVERFLOW | SR_OVERFLOW_STICKY)); - } + TEST(8, R(RSI), Imm8(2)); + FixupBranch noOverflow = J_CC(CC_NZ); + OR(16, MDisp(R11, DSP_REG_SR * 2), Imm16(SR_OVERFLOW | SR_OVERFLOW_STICKY)); + SetJumpTarget(noOverflow); // // 0x04 // if (_Value == 0) g_dsp.r[DSP_REG_SR] |= SR_ARITH_ZERO; diff --git a/Source/Core/DSPCore/Src/SConscript b/Source/Core/DSPCore/Src/SConscript index 8628d4ed22..95e2d8d897 100644 --- a/Source/Core/DSPCore/Src/SConscript +++ b/Source/Core/DSPCore/Src/SConscript @@ -26,6 +26,7 @@ files = [ "Jit/DSPJitExtOps.cpp", "Jit/DSPJitUtil.cpp", "Jit/DSPJitCCUtil.cpp", + "Jit/DSPJitArithmetic.cpp", "Jit/DSPJitMultiplier.cpp", "Jit/DSPJitMisc.cpp", ]