From 57a3c878158d56565e42164a2c23e01d07050dd3 Mon Sep 17 00:00:00 2001 From: "j4ck.fr0st" Date: Fri, 9 Apr 2010 19:18:50 +0000 Subject: [PATCH] DSPJit: disabled NR again until we fix DSPEmitter::increase_addr_reg. And to help test things like that: DSPJitTester (use with caution on x64, most likely fails there; r5250 might be why) git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5306 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/Common/Src/x64Emitter.cpp | 2 +- Source/Core/Common/Src/x64Emitter.h | 2 +- Source/Core/DSPCore/Src/DSPTables.cpp | 2 +- Source/Core/DSPCore/Src/Jit/DSPJitUtil.cpp | 54 ++++++++------ Source/Dolphin.sln | 1 + Source/UnitTests/AudioJitTests.cpp | 84 ++++++++++++++++++++++ Source/UnitTests/DSPJitTester.cpp | 71 ++++++++++++++++++ Source/UnitTests/DSPJitTester.h | 49 +++++++++++++ Source/UnitTests/UnitTests.cpp | 5 ++ Source/UnitTests/UnitTests.vcproj | 30 ++++++-- 10 files changed, 272 insertions(+), 28 deletions(-) create mode 100644 Source/UnitTests/AudioJitTests.cpp create mode 100644 Source/UnitTests/DSPJitTester.cpp create mode 100644 Source/UnitTests/DSPJitTester.h 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 @@ + + + + + + + +