From 9b1d3704784fc3ca3c12d0c0371d3e3bb72ee945 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Mon, 16 Aug 2021 00:10:21 -0700 Subject: [PATCH] DSPLLE: Implement conditional variants of RTI --- Source/Core/Core/DSP/DSPTables.cpp | 19 ++++++- .../Core/DSP/Interpreter/DSPIntBranch.cpp | 8 ++- .../Core/DSP/Interpreter/DSPIntTables.cpp | 2 +- Source/Core/Core/DSP/Jit/x64/DSPEmitter.h | 1 + Source/Core/Core/DSP/Jit/x64/DSPJitBranch.cpp | 21 +++++-- Source/Core/Core/DSP/Jit/x64/DSPJitTables.cpp | 2 +- Source/DSPSpy/tests/rti_test.ds | 55 +++++++++++++++++++ 7 files changed, 96 insertions(+), 12 deletions(-) create mode 100644 Source/DSPSpy/tests/rti_test.ds diff --git a/Source/Core/Core/DSP/DSPTables.cpp b/Source/Core/Core/DSP/DSPTables.cpp index 05baa7a89a..7f1ab00a6b 100644 --- a/Source/Core/Core/DSP/DSPTables.cpp +++ b/Source/Core/Core/DSP/DSPTables.cpp @@ -18,7 +18,7 @@ namespace DSP { // clang-format off -const std::array s_opcodes = +const std::array s_opcodes = {{ // # of parameters----+ {type, size, loc, lshift, mask} branch reads PC // instruction approximation // name opcode mask size-V V param 1 param 2 param 3 extendable uncond. updates SR @@ -48,7 +48,22 @@ const std::array s_opcodes = {"RETO", 0x02de, 0xffff, 1, 0, {}, false, true, false, true, false}, // return if overflow {"RET", 0x02df, 0xffff, 1, 0, {}, false, true, true, false, false}, // unconditional return - {"RTI", 0x02ff, 0xffff, 1, 0, {}, false, true, true, false, false}, // return from interrupt + {"RTIGE", 0x02f0, 0xffff, 1, 0, {}, false, true, false, true, false}, // return from interrupt if greater or equal + {"RTIL", 0x02f1, 0xffff, 1, 0, {}, false, true, false, true, false}, // return from interrupt if less + {"RTIG", 0x02f2, 0xffff, 1, 0, {}, false, true, false, true, false}, // return from interrupt if greater + {"RTILE", 0x02f3, 0xffff, 1, 0, {}, false, true, false, true, false}, // return from interrupt if less or equal + {"RTINZ", 0x02f4, 0xffff, 1, 0, {}, false, true, false, true, false}, // return from interrupt if not zero + {"RTIZ", 0x02f5, 0xffff, 1, 0, {}, false, true, false, true, false}, // return from interrupt if zero + {"RTINC", 0x02f6, 0xffff, 1, 0, {}, false, true, false, true, false}, // return from interrupt if not carry + {"RTIC", 0x02f7, 0xffff, 1, 0, {}, false, true, false, true, false}, // return from interrupt if carry + {"RTIx8", 0x02f8, 0xffff, 1, 0, {}, false, true, false, true, false}, // return from interrupt if TODO + {"RTIx9", 0x02f9, 0xffff, 1, 0, {}, false, true, false, true, false}, // return from interrupt if TODO + {"RTIxA", 0x02fa, 0xffff, 1, 0, {}, false, true, false, true, false}, // return from interrupt if TODO + {"RTIxB", 0x02fb, 0xffff, 1, 0, {}, false, true, false, true, false}, // return from interrupt if TODO + {"RTILNZ", 0x02fc, 0xffff, 1, 0, {}, false, true, false, true, false}, // return from interrupt if logic not zero + {"RTILZ", 0x02fd, 0xffff, 1, 0, {}, false, true, false, true, false}, // return from interrupt if logic zero + {"RTIO", 0x02fe, 0xffff, 1, 0, {}, false, true, false, true, false}, // return from interrupt if overflow + {"RTI", 0x02ff, 0xffff, 1, 0, {}, false, true, true, false, false}, // return from interrupt unconditionally {"CALLGE", 0x02b0, 0xffff, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, // call if greater or equal {"CALLL", 0x02b1, 0xffff, 2, 1, {{P_ADDR_I, 2, 1, 0, 0xffff}}, false, true, false, true, false}, // call if less diff --git a/Source/Core/Core/DSP/Interpreter/DSPIntBranch.cpp b/Source/Core/Core/DSP/Interpreter/DSPIntBranch.cpp index 7dafeaf3d8..5f67d953c9 100644 --- a/Source/Core/Core/DSP/Interpreter/DSPIntBranch.cpp +++ b/Source/Core/Core/DSP/Interpreter/DSPIntBranch.cpp @@ -104,13 +104,17 @@ void Interpreter::ret(const UDSPInstruction opc) state.pc = state.PopStack(StackRegister::Call); } -// RTI +// RTIcc // 0000 0010 1111 1111 // Return from exception. Pops stored status register $sr from data stack // $st1 and program counter PC from call stack $st0 and sets $pc to this // location. -void Interpreter::rti(const UDSPInstruction) +// This instruction has a conditional form, but it is not used by any official ucode. +void Interpreter::rti(const UDSPInstruction opc) { + if (!CheckCondition(opc & 0xf)) + return; + auto& state = m_dsp_core.DSPState(); state.r.sr = state.PopStack(StackRegister::Data); state.pc = state.PopStack(StackRegister::Call); diff --git a/Source/Core/Core/DSP/Interpreter/DSPIntTables.cpp b/Source/Core/Core/DSP/Interpreter/DSPIntTables.cpp index c51dc74ab7..eefe8d2fd7 100644 --- a/Source/Core/Core/DSP/Interpreter/DSPIntTables.cpp +++ b/Source/Core/Core/DSP/Interpreter/DSPIntTables.cpp @@ -32,7 +32,7 @@ constexpr std::array s_opcodes {0x02d0, 0xfff0, &Interpreter::ret}, - {0x02ff, 0xffff, &Interpreter::rti}, + {0x02f0, 0xfff0, &Interpreter::rti}, {0x02b0, 0xfff0, &Interpreter::call}, diff --git a/Source/Core/Core/DSP/Jit/x64/DSPEmitter.h b/Source/Core/Core/DSP/Jit/x64/DSPEmitter.h index 12dcfba29d..ee74def463 100644 --- a/Source/Core/Core/DSP/Jit/x64/DSPEmitter.h +++ b/Source/Core/Core/DSP/Jit/x64/DSPEmitter.h @@ -221,6 +221,7 @@ private: void r_callr(UDSPInstruction opc); void r_ifcc(UDSPInstruction opc); void r_ret(UDSPInstruction opc); + void r_rti(UDSPInstruction opc); void Update_SR_Register(Gen::X64Reg val = Gen::EAX, Gen::X64Reg scratch = Gen::EDX); diff --git a/Source/Core/Core/DSP/Jit/x64/DSPJitBranch.cpp b/Source/Core/Core/DSP/Jit/x64/DSPJitBranch.cpp index ea4df2a6fd..043e5f2043 100644 --- a/Source/Core/Core/DSP/Jit/x64/DSPJitBranch.cpp +++ b/Source/Core/Core/DSP/Jit/x64/DSPJitBranch.cpp @@ -255,12 +255,7 @@ void DSPEmitter::ret(const UDSPInstruction opc) ReJitConditional(opc, &DSPEmitter::r_ret); } -// RTI -// 0000 0010 1111 1111 -// Return from exception. Pops stored status register $sr from data stack -// $st1 and program counter PC from call stack $st0 and sets $pc to this -// location. -void DSPEmitter::rti(const UDSPInstruction opc) +void DSPEmitter::r_rti(const UDSPInstruction opc) { // g_dsp.r[DSP_REG_SR] = dsp_reg_load_stack(StackRegister::Data); dsp_reg_load_stack(StackRegister::Data); @@ -268,6 +263,20 @@ void DSPEmitter::rti(const UDSPInstruction opc) // g_dsp.pc = dsp_reg_load_stack(StackRegister::Call); dsp_reg_load_stack(StackRegister::Call); MOV(16, M_SDSP_pc(), R(DX)); + WriteBranchExit(); +} + +// RTIcc +// 0000 0010 1111 1111 +// Return from exception. Pops stored status register $sr from data stack +// $st1 and program counter PC from call stack $st0 and sets $pc to this +// location. +// This instruction has a conditional form, but it is not used by any official ucode. +// NOTE: Cannot use FallBackToInterpreter(opc) here because of the need to write branch exit +void DSPEmitter::rti(const UDSPInstruction opc) +{ + MOV(16, M_SDSP_pc(), Imm16(m_compile_pc + 1)); + ReJitConditional(opc, &DSPEmitter::r_rti); } // HALT diff --git a/Source/Core/Core/DSP/Jit/x64/DSPJitTables.cpp b/Source/Core/Core/DSP/Jit/x64/DSPJitTables.cpp index 664cbd95d8..87f446f82d 100644 --- a/Source/Core/Core/DSP/Jit/x64/DSPJitTables.cpp +++ b/Source/Core/Core/DSP/Jit/x64/DSPJitTables.cpp @@ -32,7 +32,7 @@ const std::array s_opcodes = {0x02d0, 0xfff0, &DSPEmitter::ret}, - {0x02ff, 0xffff, &DSPEmitter::rti}, + {0x02f0, 0xfff0, &DSPEmitter::rti}, {0x02b0, 0xfff0, &DSPEmitter::call}, diff --git a/Source/DSPSpy/tests/rti_test.ds b/Source/DSPSpy/tests/rti_test.ds new file mode 100644 index 0000000000..81acd6af47 --- /dev/null +++ b/Source/DSPSpy/tests/rti_test.ds @@ -0,0 +1,55 @@ +; This test needs to manually specify IRQs + jmp irq0 + jmp irq1 + jmp irq2 + jmp irq3 + jmp irq4 + jmp accov_irq + jmp irq6 + jmp irq7 + +incdir "tests" +include "dsp_base_noirq.inc" + +test_main: + ; Use the accelerator to generate an IRQ by setting the start and end address to 0 + ; This will result in an interrupt on every read + SI @0xffda, #0 ; pred_scale + SI @0xffdb, #0 ; yn1 + SI @0xffdc, #0 ; yn2 + SI @0xffd1, #0 ; SampleFormat + SI @ACSAH, #0 + SI @ACCAH, #0 + SI @ACSAL, #0 + SI @ACCAL, #0 + SI @ACEAH, #0 + SI @ACEAL, #0 + + + LRI $AX1.H, #0x0000 + LRS $AX0.L, @ARAM ; Trigger interrupt + CALL send_back + + LRI $AX1.H, #0x0001 + LRS $AX0.L, @ARAM ; Trigger interrupt + CALL send_back + + LRI $AX1.H, #0x0000 + LRS $AX0.L, @ARAM ; Trigger interrupt + CALL send_back + + jmp end_of_test + +accov_irq: + ; Restore registers, otherwise no new interrupt will be generated + SI @0xffda, #0 ; pred_scale + SI @0xffdb, #0 ; yn1 + SI @0xffdc, #0 ; yn2 + + TSTAXH $AX1.H + LRI $AX1.L, #0x1111 + cw 0x02f4 ; RTINZ if it exists + LRI $AX1.L, #0x2222 + cw 0x02f5 ; RTIZ if it exists + LRI $AX1.L, #0x3333 + RTI