diff --git a/Source/Core/Common/Src/x64Emitter.cpp b/Source/Core/Common/Src/x64Emitter.cpp
index 116b892c3a..575247d840 100644
--- a/Source/Core/Common/Src/x64Emitter.cpp
+++ b/Source/Core/Common/Src/x64Emitter.cpp
@@ -985,7 +985,7 @@ void XEmitter::IMUL(int bits, X64Reg regOp, OpArg a)
if (a.IsImm())
{
IMUL(bits, regOp, R(regOp), a) ;
- return ;
+ return;
}
if (bits == 16)
diff --git a/Source/Core/Common/Src/x64Emitter.h b/Source/Core/Common/Src/x64Emitter.h
index e4d7013f87..36f5ea0b61 100644
--- a/Source/Core/Common/Src/x64Emitter.h
+++ b/Source/Core/Common/Src/x64Emitter.h
@@ -296,7 +296,7 @@ public:
void CALLptr(OpArg arg);
FixupBranch J_CC(CCFlags conditionCode, bool force5bytes = false);
- void J_CC(CCFlags conditionCode, JumpTarget target);
+ //void J_CC(CCFlags conditionCode, JumpTarget target);
void J_CC(CCFlags conditionCode, const u8 * addr, bool force5Bytes = false);
void SetJumpTarget(const FixupBranch &branch);
diff --git a/Source/Core/DSPCore/Src/DSPTables.cpp b/Source/Core/DSPCore/Src/DSPTables.cpp
index 681ebf640d..a684302992 100644
--- a/Source/Core/DSPCore/Src/DSPTables.cpp
+++ b/Source/Core/DSPCore/Src/DSPTables.cpp
@@ -310,7 +310,7 @@ const DSPOPCTemplate opcodes_ext[] =
{"DR", 0x0004, 0x00fc, DSPInterpreter::Ext::dr, &DSPEmitter::dr, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, false, false},
{"IR", 0x0008, 0x00fc, DSPInterpreter::Ext::ir, &DSPEmitter::ir, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, false, false},
- {"NR", 0x000c, 0x00fc, DSPInterpreter::Ext::nr, &DSPEmitter::nr, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, false, false},
+ {"NR", 0x000c, 0x00fc, DSPInterpreter::Ext::nr, NULL /*&DSPEmitter::nr*/, 1, 1, {{P_REG, 1, 0, 0, 0x0003}}, false, false},
{"MV", 0x0010, 0x00f0, DSPInterpreter::Ext::mv, NULL /*&DSPEmitter::mv*/, 1, +2, {{P_REG18, 1, 0, 2, 0x000c}, {P_REG1C, 1, 0, 0, 0x0003}}, false, false},
{"S", 0x0020, 0x00e4, DSPInterpreter::Ext::s, NULL /*&DSPEmitter::s*/, 1, 2, {{P_PRG, 1, 0, 0, 0x0003}, {P_REG1C, 1, 0, 3, 0x0018}}, false, false},
diff --git a/Source/Core/DSPCore/Src/Jit/DSPJitUtil.cpp b/Source/Core/DSPCore/Src/Jit/DSPJitUtil.cpp
index 83b903bb3b..69904d5e7a 100644
--- a/Source/Core/DSPCore/Src/Jit/DSPJitUtil.cpp
+++ b/Source/Core/DSPCore/Src/Jit/DSPJitUtil.cpp
@@ -31,6 +31,9 @@ using namespace Gen;
// See http://code.google.com/p/dolphin-emu/source/detail?r=3125
void DSPEmitter::increment_addr_reg(int reg)
{
+ PUSH(EAX);
+ PUSH(ECX);
+
// u16 tmb = g_dsp.r[DSP_REG_WR0 + reg];
MOVZX(32, 16, EAX, M(&g_dsp.r[DSP_REG_WR0 + reg]));
@@ -77,11 +80,17 @@ void DSPEmitter::increment_addr_reg(int reg)
// g_dsp.r[reg] = tmp;
MOV(16, M(&g_dsp.r[reg]), R(ECX));
+
+ POP(ECX);
+ POP(EAX);
}
// See http://code.google.com/p/dolphin-emu/source/detail?r=3125
void DSPEmitter::decrement_addr_reg(int reg)
{
+ PUSH(EAX);
+ PUSH(ECX);
+
// s16 tmp = g_dsp.r[reg];
MOVZX(32, 16, EAX, M(&g_dsp.r[reg]));
@@ -104,49 +113,54 @@ void DSPEmitter::decrement_addr_reg(int reg)
// g_dsp.r[reg] = tmp;
MOV(16, M(&g_dsp.r[reg]), R(EAX));
+ POP(ECX);
+ POP(EAX);
}
// Increase addr register according to the correspond ix register
void DSPEmitter::increase_addr_reg(int reg)
{
// s16 value = (s16)g_dsp.r[DSP_REG_IX0 + reg];
- MOVSX(32, 16, EDX, M(&g_dsp.r[DSP_REG_IX0 + reg]));
+ //FIXME: interpreter uses reg, not IX0+reg?
+ MOVSX(32, 16, EDX, M(&g_dsp.r[reg]));
+ XOR(32, R(ECX), R(ECX)); // i = 0
// if (value > 0)
CMP(16, R(EDX), Imm16(0));
+ //FIXME: those jumps are too far for one byte,
+ // and force5bytes = true causes an illegal
+ // instruction for me.
+ // calling (de|in)crement_addr_reg causes that.
FixupBranch end = J_CC(CC_Z);
FixupBranch negValue = J_CC(CC_L);
// for (int i = 0; i < value; i++)
- XOR(32, R(ESI), R(ESI)); // i = 0
-
- FixupBranch posloop;
- SetJumpTarget(posloop);
-
- increment_addr_reg(reg);
-
- ADD(32, R(ESI), Imm32(1)); // i++
- CMP(32, R(ESI), R(EDX)); // i < value
+ JumpTarget loop_pos = GetCodePtr();
+ increment_addr_reg(reg);
+ ADD(32, R(ECX), Imm32(1)); // i++
+ CMP(32, R(ECX), R(EDX)); // i < value
+ J_CC(CC_NE, loop_pos);
FixupBranch posValue = J();
- // FIXME: get normal abs with cdq
- IMUL(32, EDX, Imm16(-1));
+
+ SetJumpTarget(negValue);
+ //abs == cdq; xor eax, edx; sub eax, edx
+ //we know its negative, and in that case edx is -1
+ XOR(32, R(EDX), Imm32(-1));
+ SUB(32, R(EDX), Imm32(-1));
// for (int i = 0; i < (int)(-value); i++)
- XOR(32, R(ESI), R(ESI)); // i = 0
-
- FixupBranch negloop;
- SetJumpTarget(negloop);
-
+ JumpTarget loop_neg = GetCodePtr();
decrement_addr_reg(reg);
- ADD(32, R(ESI), Imm32(1)); // i++
- CMP(32, R(ESI), R(EDX)); // i < -value
- negloop = J_CC(CC_L);
+ ADD(32, R(ECX), Imm32(1)); // i++
+ CMP(32, R(ECX), R(EDX)); // i < -value
+ J_CC(CC_NE, loop_neg);
SetJumpTarget(posValue);
SetJumpTarget(end);
+ MOV(16, M(&g_dsp.r[reg]), R(EDX));
}
// Decrease addr register according to the correspond ix register
diff --git a/Source/Dolphin.sln b/Source/Dolphin.sln
index 0fc16f53a7..d256c799f5 100644
--- a/Source/Dolphin.sln
+++ b/Source/Dolphin.sln
@@ -142,6 +142,7 @@ EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTests", "UnitTests\UnitTests.vcproj", "{40C636FA-B5BF-4D67-ABC8-376B524A7551}"
ProjectSection(ProjectDependencies) = postProject
{11F55366-12EC-4C44-A8CB-1D4E315D61ED} = {11F55366-12EC-4C44-A8CB-1D4E315D61ED}
+ {838A89A3-3AA0-4A45-ACBE-3D1E0980C2ED} = {838A89A3-3AA0-4A45-ACBE-3D1E0980C2ED}
{1C8436C9-DBAF-42BE-83BC-CF3EC9175ABE} = {1C8436C9-DBAF-42BE-83BC-CF3EC9175ABE}
{F0B874CB-4476-4199-9315-8343D05AE684} = {F0B874CB-4476-4199-9315-8343D05AE684}
{C573CAF7-EE6A-458E-8049-16C0BF34C2E9} = {C573CAF7-EE6A-458E-8049-16C0BF34C2E9}
diff --git a/Source/UnitTests/AudioJitTests.cpp b/Source/UnitTests/AudioJitTests.cpp
new file mode 100644
index 0000000000..2247f529b5
--- /dev/null
+++ b/Source/UnitTests/AudioJitTests.cpp
@@ -0,0 +1,84 @@
+#include "DSPJitTester.h"
+
+void nx_dr()
+{
+ SDSP test_dsp;
+ DSPJitTester tester(0x40, 0x04);
+
+ for (u16 input_reg = 0; input_reg < 50; input_reg++)
+ for (u16 input_wr0 = 0; input_wr0 < 10; input_wr0++)
+ {
+ memset(&test_dsp, 0, sizeof(SDSP));
+ test_dsp.r[DSP_REG_WR0] = input_wr0;
+ test_dsp.r[0] = input_reg;
+ if (!tester.Test(test_dsp))
+ {
+ printf("%s Test failed: in = 0x%04x, wr0 = 0x%04x > int = 0x%04x, jit = 0x%04x\n",
+ tester.GetInstructionName(),
+ input_reg, input_wr0,
+ tester.GetLastInterpreterDSP().r[0], tester.GetLastJitDSP().r[0]);
+ }
+ }
+ tester.Report();
+}
+
+void nx_ir()
+{
+ SDSP test_dsp;
+ DSPJitTester tester(0x40, 0x08);
+
+ for (u16 input_reg = 0; input_reg < 50; input_reg++)
+ for (u16 input_wr0 = 0; input_wr0 < 10; input_wr0++)
+ {
+ memset(&test_dsp, 0, sizeof(SDSP));
+ test_dsp.r[DSP_REG_WR0] = input_wr0;
+ test_dsp.r[0] = input_reg;
+ if (!tester.Test(test_dsp))
+ {
+ printf("%s Test failed: in = 0x%04x, wr0 = 0x%04x > int = 0x%04x, jit = 0x%04x\n",
+ tester.GetInstructionName(),
+ input_reg, input_wr0,
+ tester.GetLastInterpreterDSP().r[0], tester.GetLastJitDSP().r[0]);
+ }
+ }
+ tester.Report();
+}
+
+void nx_nr()
+{
+ SDSP test_dsp;
+ DSPJitTester tester(0x40, 0x0c);
+
+ for (u16 input_reg = 0; input_reg < 50; input_reg++)
+ for (u16 input_wr0 = 0; input_wr0 < 10; input_wr0++)
+ {
+ memset(&test_dsp, 0, sizeof(SDSP));
+ test_dsp.r[DSP_REG_WR0] = input_wr0;
+ test_dsp.r[0] = input_reg;
+ if (!tester.Test(test_dsp))
+ {
+ printf("%s Test failed: in = 0x%04x, wr0 = 0x%04x > int = 0x%04x, jit = 0x%04x\n",
+ tester.GetInstructionName(),
+ input_reg, input_wr0,
+ tester.GetLastInterpreterDSP().r[0], tester.GetLastJitDSP().r[0]);
+ }
+ }
+ tester.Report();
+}
+
+void AudioJitTests()
+{
+ DSPJitTester::Initialize();
+
+ nx_ir();
+ nx_dr();
+ //nx_nr();
+}
+
+//required to be able to link against DSPCore
+void DSPHost_UpdateDebugger() { }
+unsigned int DSPHost_CodeLoaded(unsigned const char*, int) { return 0; }
+void DSPHost_InterruptRequest() { }
+bool DSPHost_OnThread() { return false; }
+void DSPHost_WriteHostMemory(unsigned char, unsigned int) { }
+unsigned char DSPHost_ReadHostMemory(unsigned int) { return 0; }
\ No newline at end of file
diff --git a/Source/UnitTests/DSPJitTester.cpp b/Source/UnitTests/DSPJitTester.cpp
new file mode 100644
index 0000000000..aa13aa6d6d
--- /dev/null
+++ b/Source/UnitTests/DSPJitTester.cpp
@@ -0,0 +1,71 @@
+#include "DSPJitTester.h"
+
+bool DSPJitTester::Test(SDSP dsp_settings)
+{
+ if (be_verbose)
+ printf("Running %s: ", instruction_name);
+
+ last_int_dsp = RunInterpreter(dsp_settings);
+ last_jit_dsp = RunJit(dsp_settings);
+
+ run_count++;
+ bool success = AreEqual(last_int_dsp, last_jit_dsp);
+ if (!success)
+ fail_count++;
+ return success;
+}
+SDSP DSPJitTester::RunInterpreter(SDSP dsp_settings)
+{
+ ResetInterpreter();
+ memcpy(&g_dsp, &dsp_settings, sizeof(SDSP));
+ ExecuteInstruction(instruction);
+
+ return g_dsp;
+}
+SDSP DSPJitTester::RunJit(SDSP dsp_settings)
+{
+ ResetJit();
+ memcpy(&g_dsp, &dsp_settings, sizeof(SDSP));
+ const u8* code = jit.GetCodePtr();
+ jit.WriteCallInterpreter(instruction);
+ jit.RET();
+ ((void(*)())code)();
+
+ return g_dsp;
+}
+void DSPJitTester::ResetInterpreter()
+{
+ for (int i=0; i < WRITEBACKLOGSIZE; i++)
+ writeBackLogIdx[i] = -1;
+}
+void DSPJitTester::ResetJit()
+{
+ jit.ClearCodeSpace();
+}
+bool DSPJitTester::AreEqual(SDSP& int_dsp, SDSP& jit_dsp)
+{
+ bool equal = true;
+ for (int i = 0; i < 32; i++)
+ {
+ if (int_dsp.r[i] != jit_dsp.r[i])
+ {
+ if (equal && be_verbose)
+ printf("failed\n");
+ equal = false;
+ if (be_verbose)
+ printf("\t%s: int = 0x%04x, jit = 0x%04x\n", regnames[i].name, int_dsp.r[i], jit_dsp.r[i]);
+ }
+ }
+ if (equal && be_verbose)
+ printf("passed\n");
+ return equal;
+}
+void DSPJitTester::Report()
+{
+ printf("%s (0x%04x): Ran %d times, Failed %d times.\n", instruction_name, instruction, run_count, fail_count);
+}
+void DSPJitTester::Initialize()
+{
+ //init int
+ InitInstructionTable();
+}
\ No newline at end of file
diff --git a/Source/UnitTests/DSPJitTester.h b/Source/UnitTests/DSPJitTester.h
new file mode 100644
index 0000000000..98de3a7868
--- /dev/null
+++ b/Source/UnitTests/DSPJitTester.h
@@ -0,0 +1,49 @@
+#ifndef __DSP_JIT_TESTER_
+#define __DSP_JIT_TESTER_
+
+#include "DSPCore.h"
+#include "DSPInterpreter.h"
+//#include "DSPIntExtOps.h"
+//
+//#include "x64Emitter.h"
+
+class DSPJitTester
+{
+ UDSPInstruction instruction;
+ const DSPOPCTemplate *opcode_template;
+ DSPEmitter jit;
+ SDSP last_int_dsp;
+ SDSP last_jit_dsp;
+ bool be_verbose;
+ int run_count;
+ int fail_count;
+ char instruction_name[16];
+
+ bool AreEqual(SDSP&, SDSP&);
+public:
+ DSPJitTester(u16 opcode, u16 opcode_ext, bool verbose = false)
+ : be_verbose(verbose), run_count(0), fail_count(0)
+ {
+ instruction = opcode << 9 | opcode_ext;
+ opcode_template = GetOpTemplate(instruction);
+ sprintf(instruction_name, "%s", opcode_template->name);
+ if (opcode_template->extended)
+ sprintf(&instruction_name[strlen(instruction_name)], "'%s",
+ extOpTable[instruction & (((instruction >> 12) == 0x3) ? 0x7F : 0xFF)]->name);
+ }
+ bool Test(SDSP);
+ SDSP RunInterpreter(SDSP);
+ SDSP RunJit(SDSP);
+ void ResetInterpreter();
+ void ResetJit();
+ inline SDSP GetLastInterpreterDSP() { return last_int_dsp; }
+ inline SDSP GetLastJitDSP() { return last_jit_dsp; }
+ inline int GetRunCount() { return run_count; }
+ inline int GetFailCount() { return fail_count; }
+ inline const char* GetInstructionName() { return instruction_name; }
+ void Report();
+
+ static void Initialize();
+};
+
+#endif
\ No newline at end of file
diff --git a/Source/UnitTests/UnitTests.cpp b/Source/UnitTests/UnitTests.cpp
index e7de4a1545..27eb352ea5 100644
--- a/Source/UnitTests/UnitTests.cpp
+++ b/Source/UnitTests/UnitTests.cpp
@@ -23,6 +23,8 @@
#include "PowerPC/PowerPC.h"
#include "HW/SI_DeviceGCController.h"
+void AudioJitTests();
+
using namespace std;
int fail_count = 0;
@@ -101,6 +103,8 @@ void StringTests()
int main(int argc, _TCHAR* argv[])
{
+ AudioJitTests();
+
CoreTests();
MathTests();
StringTests();
@@ -133,6 +137,7 @@ void Host_SetWiiMoteConnectionState(int _State){}
void Host_UpdateLeds(int bits){}
void Host_UpdateSpeakerStatus(int index, int bits){}
void Host_UpdateStatus(){}
+void Host_Message(int){}
int CSIDevice_GCController::GetNetInput(u8 numPAD, SPADStatus PadStatus, u32 *PADStatus)
{
diff --git a/Source/UnitTests/UnitTests.vcproj b/Source/UnitTests/UnitTests.vcproj
index 86a71847e8..f15b4ac7b7 100644
--- a/Source/UnitTests/UnitTests.vcproj
+++ b/Source/UnitTests/UnitTests.vcproj
@@ -1,7 +1,7 @@
+
+
+
+
+
+
+
+