diff --git a/Source/Core/DSPCore/Src/DSPEmitter.cpp b/Source/Core/DSPCore/Src/DSPEmitter.cpp index 7b0a27c362..0976d88d5a 100644 --- a/Source/Core/DSPCore/Src/DSPEmitter.cpp +++ b/Source/Core/DSPCore/Src/DSPEmitter.cpp @@ -93,6 +93,7 @@ void DSPEmitter::checkExceptions(u32 retval) { void DSPEmitter::EmitInstruction(UDSPInstruction inst) { const DSPOPCTemplate *tinst = GetOpTemplate(inst); + bool ext_is_jit = false; // Call extended if (tinst->extended) { @@ -100,15 +101,19 @@ void DSPEmitter::EmitInstruction(UDSPInstruction inst) if (! extOpTable[inst & 0x7F]->jitFunc) { // Fall back to interpreter ABI_CallFunctionC16((void*)extOpTable[inst & 0x7F]->intFunc, inst); + ext_is_jit = false; } else { (this->*extOpTable[inst & 0x7F]->jitFunc)(inst); + ext_is_jit = true; } } else { if (!extOpTable[inst & 0xFF]->jitFunc) { // Fall back to interpreter ABI_CallFunctionC16((void*)extOpTable[inst & 0xFF]->intFunc, inst); + ext_is_jit = false; } else { (this->*extOpTable[inst & 0xFF]->jitFunc)(inst); + ext_is_jit = true; } } } @@ -125,8 +130,10 @@ void DSPEmitter::EmitInstruction(UDSPInstruction inst) // Backlog if (tinst->extended) { - if (! extOpTable[inst & 0x7F]->jitFunc) { - ABI_CallFunction((void*)applyWriteBackLog); + if (!ext_is_jit) { + //need to call the online cleanup function because + //the writeBackLog gets populated at runtime + ABI_CallFunction((void*)::applyWriteBackLog); } else { popExtValueToReg(); } diff --git a/Source/Core/DSPCore/Src/DSPEmitter.h b/Source/Core/DSPCore/Src/DSPEmitter.h index 8ddd9aa368..95836de01c 100644 --- a/Source/Core/DSPCore/Src/DSPEmitter.h +++ b/Source/Core/DSPCore/Src/DSPEmitter.h @@ -64,6 +64,7 @@ public: void popExtValueToReg(); void pushExtValueFromMem(u16 dreg, u16 sreg); + void zeroWriteBackLog(const UDSPInstruction opc); // Ext commands void l(const UDSPInstruction opc); void ln(const UDSPInstruction opc); diff --git a/Source/Core/DSPCore/Src/DSPIntExtOps.cpp b/Source/Core/DSPCore/Src/DSPIntExtOps.cpp index 0486d2a238..ce4f29585e 100644 --- a/Source/Core/DSPCore/Src/DSPIntExtOps.cpp +++ b/Source/Core/DSPCore/Src/DSPIntExtOps.cpp @@ -28,6 +28,13 @@ // registers will wrap in odd ways, dictated by the corresponding wrapping // register, WR0-3. +// Needs comments. +inline static void writeToBackLog(int i, int idx, u16 value) +{ + writeBackLog[i] = value; + writeBackLogIdx[i] = idx; +} + namespace DSPInterpreter { diff --git a/Source/Core/DSPCore/Src/DSPIntExtOps.h b/Source/Core/DSPCore/Src/DSPIntExtOps.h index c154af24ee..46b809ca14 100644 --- a/Source/Core/DSPCore/Src/DSPIntExtOps.h +++ b/Source/Core/DSPCore/Src/DSPIntExtOps.h @@ -61,11 +61,4 @@ void nop(const UDSPInstruction opc); } // end namespace Ext } // end namespace DSPinterpeter -// Needs comments. -inline void writeToBackLog(int i, int idx, u16 value) -{ - writeBackLog[i] = value; - writeBackLogIdx[i] = idx; -} - #endif diff --git a/Source/Core/DSPCore/Src/Jit/DSPJitExtOps.cpp b/Source/Core/DSPCore/Src/Jit/DSPJitExtOps.cpp index fa5e1743cd..d151bf1194 100644 --- a/Source/Core/DSPCore/Src/Jit/DSPJitExtOps.cpp +++ b/Source/Core/DSPCore/Src/Jit/DSPJitExtOps.cpp @@ -19,8 +19,6 @@ #include "x64Emitter.h" #include "ABI.h" -#include "../DSPIntExtOps.h" // remove when getting rid of writebacklog -// See docs in the interpeter using namespace Gen; // DR $arR @@ -94,6 +92,7 @@ void DSPEmitter::l(const UDSPInstruction opc) if ((dreg >= DSP_REG_ACM0) && (g_dsp.r[DSP_REG_SR] & SR_40_MODE_BIT)) { +/* u16 val; ext_dmem_read(sreg); MOV(16, M(&val), R(EAX)); @@ -102,6 +101,7 @@ void DSPEmitter::l(const UDSPInstruction opc) writeToBackLog(1, dreg, val); writeToBackLog(2, dreg - DSP_REG_ACM0 + DSP_REG_ACL0, 0); increment_addr_reg(sreg); +*/ } else { @@ -127,6 +127,7 @@ void DSPEmitter::ln(const UDSPInstruction opc) if ((dreg >= DSP_REG_ACM0) && (g_dsp.r[DSP_REG_SR] & SR_40_MODE_BIT)) { +/* u16 val; ext_dmem_read(sreg); MOV(16, M(&val), R(EAX)); @@ -134,6 +135,7 @@ void DSPEmitter::ln(const UDSPInstruction opc) writeToBackLog(1, dreg, val); writeToBackLog(2, dreg - DSP_REG_ACM0 + DSP_REG_ACL0, 0); increase_addr_reg(sreg); +*/ } else { @@ -700,8 +702,8 @@ void DSPEmitter::pushExtValueFromReg(u16 dreg, u16 sreg) { void DSPEmitter::pushExtValueFromMem(u16 dreg, u16 sreg) { ext_dmem_read(sreg); - MOV(16, R(EBX), R(EAX)); - + MOVZX(32, 16, EBX, R(EAX)); + storeIndex = dreg; } @@ -726,3 +728,26 @@ void DSPEmitter::popExtValueToReg() { // TODO handle commands such as 'l } +// This function is being called in the main op after all input regs were read +// and before it writes into any regs. This way we can always use bitwise or to +// apply the ext command output, because if the main op didn't change the value +// then 0 | ext output = ext output and if it did then bitwise or is still the +// right thing to do +//this is only needed as long as we do fallback for ext ops +void DSPEmitter::zeroWriteBackLog(const UDSPInstruction opc) +{ + const DSPOPCTemplate *tinst = GetOpTemplate(opc); + + // Call extended + if (!tinst->extended) + return; + + if ((opc >> 12) == 0x3) { + if (! extOpTable[opc & 0x7F]->jitFunc) + ABI_CallFunction((void*)::zeroWriteBackLog); + } else { + if (! extOpTable[opc & 0xFF]->jitFunc) + ABI_CallFunction((void*)::zeroWriteBackLog); + } + return; +} diff --git a/Source/Core/DSPCore/Src/Jit/DSPJitMisc.cpp b/Source/Core/DSPCore/Src/Jit/DSPJitMisc.cpp index dafa3bea8f..4a2e3c6540 100644 --- a/Source/Core/DSPCore/Src/Jit/DSPJitMisc.cpp +++ b/Source/Core/DSPCore/Src/Jit/DSPJitMisc.cpp @@ -88,6 +88,7 @@ void DSPEmitter::nx(const UDSPInstruction opc) void DSPEmitter::dar(const UDSPInstruction opc) { // g_dsp.r[opc & 0x3] = dsp_decrement_addr_reg(opc & 0x3); + zeroWriteBackLog(opc); decrement_addr_reg(opc & 0x3); } @@ -98,6 +99,7 @@ void DSPEmitter::dar(const UDSPInstruction opc) void DSPEmitter::iar(const UDSPInstruction opc) { // g_dsp.r[opc & 0x3] = dsp_increment_addr_reg(opc & 0x3); + zeroWriteBackLog(opc); increment_addr_reg(opc & 0x3); } @@ -109,6 +111,7 @@ void DSPEmitter::subarn(const UDSPInstruction opc) { // u8 dreg = opc & 0x3; // g_dsp.r[dreg] = dsp_decrease_addr_reg(dreg, (s16)g_dsp.r[DSP_REG_IX0 + dreg]); + zeroWriteBackLog(opc); decrease_addr_reg(opc & 0x3); } @@ -123,6 +126,7 @@ void DSPEmitter::addarn(const UDSPInstruction opc) // g_dsp.r[dreg] = dsp_increase_addr_reg(dreg, (s16)g_dsp.r[DSP_REG_IX0 + sreg]); // From looking around it is always called with the matching index register + zeroWriteBackLog(opc); increase_addr_reg(opc & 0x3); } @@ -180,7 +184,7 @@ void DSPEmitter::sbset(const UDSPInstruction opc) // but it's harder to know exactly what effect they have. void DSPEmitter::srbith(const UDSPInstruction opc) { - ABI_CallFunction((void *)zeroWriteBackLog); + zeroWriteBackLog(opc); switch ((opc >> 8) & 0xf) { // M0/M2 change the multiplier mode (it can multiply by 2 for free). diff --git a/Source/UnitTests/AudioJitTests.cpp b/Source/UnitTests/AudioJitTests.cpp index cfabaeeb6c..4cef5931fa 100644 --- a/Source/UnitTests/AudioJitTests.cpp +++ b/Source/UnitTests/AudioJitTests.cpp @@ -28,6 +28,15 @@ void nx_nr() tester.Report(); } +void nx_mv() +{ + DSPJitTester tester(0x8000, 0x0010); + tester.AddTestData(DSP_REG_ACL0); + tester.AddTestData(DSP_REG_AXL0); + tester.TestAll(true); + tester.Report(); +} + void dar() { DSPJitTester tester(0x0004); @@ -81,14 +90,205 @@ void nx_s() { DSPJitTester tester(0x8000, 0x0020); tester.AddTestData(DSP_REG_AR0); + tester.AddTestData(DSP_REG_WR0); tester.AddTestData(DSP_REG_ACL0); tester.TestAll(true); tester.Report(); } + +void nx_sn() +{ + DSPJitTester tester(0x8000, 0x0024); + tester.AddTestData(DSP_REG_AR0); + tester.AddTestData(DSP_REG_WR0); + tester.AddTestData(DSP_REG_IX0); + tester.AddTestData(DSP_REG_ACL0); + tester.TestAll(true); + tester.Report(); +} + +void nx_l() +{ + + DSPJitTester tester(0x8000, 0x0040); + tester.AddTestData(DSP_REG_AR0); + tester.AddTestData(DSP_REG_WR0); + tester.AddTestData(DSP_REG_AXL0); + tester.TestAll(true); + tester.Report(); +} + +void set16_l() +{ + + DSPJitTester tester(0x8e00, 0x0070); + tester.AddTestData(DSP_REG_SR, 0); + tester.AddTestData(DSP_REG_SR, SR_40_MODE_BIT); + tester.AddTestData(DSP_REG_AR0); + tester.AddTestData(DSP_REG_WR0); + tester.AddTestData(DSP_REG_ACM0); + tester.TestAll(true); + tester.Report(); +} + +void nx_ln() +{ + DSPJitTester tester(0x8000, 0x0044); + tester.AddTestData(DSP_REG_AR0); + tester.AddTestData(DSP_REG_WR0); + tester.AddTestData(DSP_REG_IX0); + tester.AddTestData(DSP_REG_AXL0); + tester.TestAll(true); + tester.Report(); +} + +void nx_ls() +{ + DSPJitTester tester1(0x8000, 0x0080); + tester1.AddTestData(DSP_REG_ACM0); + tester1.AddTestData(DSP_REG_AR0); + tester1.AddTestData(DSP_REG_WR0); + tester1.TestAll(true); + tester1.Report(); + + DSPJitTester tester2(0x8000, 0x0080); + tester2.AddTestData(DSP_REG_ACM0); + tester2.AddTestData(DSP_REG_AR3); + tester2.AddTestData(DSP_REG_WR3); + tester2.TestAll(true); + tester2.Report(); +} + +void nx_lsn() +{ + DSPJitTester tester1(0x8000, 0x0084); + tester1.AddTestData(DSP_REG_ACM0); + tester1.AddTestData(DSP_REG_AR0); + tester1.AddTestData(DSP_REG_WR0); + tester1.AddTestData(DSP_REG_IX0); + tester1.TestAll(true); + tester1.Report(); + + DSPJitTester tester2(0x8000, 0x0084); + tester2.AddTestData(DSP_REG_ACM0); + tester2.AddTestData(DSP_REG_AR3); + tester2.AddTestData(DSP_REG_WR3); + tester2.TestAll(true); + tester2.Report(); +} + +void nx_lsm() +{ + DSPJitTester tester1(0x8000, 0x0088); + tester1.AddTestData(DSP_REG_ACM0); + tester1.AddTestData(DSP_REG_AR0); + tester1.AddTestData(DSP_REG_WR0); + tester1.TestAll(true); + tester1.Report(); + + DSPJitTester tester2(0x8000, 0x0088); + tester2.AddTestData(DSP_REG_ACM0); + tester2.AddTestData(DSP_REG_AR3); + tester2.AddTestData(DSP_REG_WR3); + tester2.AddTestData(DSP_REG_IX3); + tester2.TestAll(true); + tester2.Report(); +} + +void nx_lsnm() +{ + DSPJitTester tester1(0x8000, 0x008c); + tester1.AddTestData(DSP_REG_ACM0); + tester1.AddTestData(DSP_REG_AR0); + tester1.AddTestData(DSP_REG_WR0); + tester1.AddTestData(DSP_REG_IX0); + tester1.TestAll(true); + tester1.Report(); + + DSPJitTester tester2(0x8000, 0x008c); + tester2.AddTestData(DSP_REG_ACM0); + tester2.AddTestData(DSP_REG_AR3); + tester2.AddTestData(DSP_REG_WR3); + tester2.AddTestData(DSP_REG_IX3); + tester2.TestAll(true); + tester2.Report(); +} + +void nx_sl() +{ + DSPJitTester tester1(0x8000, 0x0082); + tester1.AddTestData(DSP_REG_ACM0); + tester1.AddTestData(DSP_REG_AR0); + tester1.AddTestData(DSP_REG_WR0); + tester1.TestAll(true); + tester1.Report(); + + DSPJitTester tester2(0x8000, 0x0082); + tester2.AddTestData(DSP_REG_ACM0); + tester2.AddTestData(DSP_REG_AR3); + tester2.AddTestData(DSP_REG_WR3); + tester2.TestAll(true); + tester2.Report(); +} + +void nx_sln() +{ + DSPJitTester tester1(0x8000, 0x0086); + tester1.AddTestData(DSP_REG_ACM0); + tester1.AddTestData(DSP_REG_AR0); + tester1.AddTestData(DSP_REG_WR0); + tester1.AddTestData(DSP_REG_IX0); + tester1.TestAll(true); + tester1.Report(); + + DSPJitTester tester2(0x8000, 0x0086); + tester2.AddTestData(DSP_REG_ACM0); + tester2.AddTestData(DSP_REG_AR3); + tester2.AddTestData(DSP_REG_WR3); + tester2.TestAll(true); + tester2.Report(); +} + +void nx_slm() +{ + DSPJitTester tester1(0x8000, 0x008a); + tester1.AddTestData(DSP_REG_ACM0); + tester1.AddTestData(DSP_REG_AR0); + tester1.AddTestData(DSP_REG_WR0); + tester1.TestAll(true); + tester1.Report(); + + DSPJitTester tester2(0x8000, 0x008a); + tester2.AddTestData(DSP_REG_ACM0); + tester2.AddTestData(DSP_REG_AR3); + tester2.AddTestData(DSP_REG_WR3); + tester2.AddTestData(DSP_REG_IX3); + tester2.TestAll(true); + tester2.Report(); +} + +void nx_slnm() +{ + DSPJitTester tester1(0x8000, 0x008e); + tester1.AddTestData(DSP_REG_ACM0); + tester1.AddTestData(DSP_REG_AR0); + tester1.AddTestData(DSP_REG_WR0); + tester1.AddTestData(DSP_REG_IX0); + tester1.TestAll(true); + tester1.Report(); + + DSPJitTester tester2(0x8000, 0x008e); + tester2.AddTestData(DSP_REG_ACM0); + tester2.AddTestData(DSP_REG_AR3); + tester2.AddTestData(DSP_REG_WR3); + tester2.AddTestData(DSP_REG_IX3); + tester2.TestAll(true); + tester2.Report(); +} + void AudioJitTests() { DSPJitTester::Initialize(); - dar(); iar(); subarn(); @@ -99,7 +299,22 @@ void AudioJitTests() nx_ir(); nx_dr(); nx_nr(); + nx_mv(); + + set16_l(); + nx_s(); + nx_sn(); + nx_l(); + nx_ln(); + nx_ls(); + nx_lsn(); + nx_lsm(); + nx_lsnm(); + nx_sl(); + nx_sln(); + nx_slm(); + nx_slnm(); } //required to be able to link against DSPCore diff --git a/Source/UnitTests/DSPJitTester.cpp b/Source/UnitTests/DSPJitTester.cpp index 2012ee09b8..c0b95ca35e 100644 --- a/Source/UnitTests/DSPJitTester.cpp +++ b/Source/UnitTests/DSPJitTester.cpp @@ -41,7 +41,9 @@ SDSP DSPJitTester::RunJit(SDSP dsp_settings) ResetJit(); memcpy(&g_dsp, &dsp_settings, sizeof(SDSP)); const u8* code = jit.GetCodePtr(); + jit.ABI_PushAllCalleeSavedRegsAndAdjustStack(); jit.EmitInstruction(instruction); + jit.ABI_PopAllCalleeSavedRegsAndAdjustStack(); jit.RET(); ((void(*)())code)();