diff --git a/Source/Core/Core/DSP/DSPAnalyzer.cpp b/Source/Core/Core/DSP/DSPAnalyzer.cpp index 107645d6c5..a86b9c2c3e 100644 --- a/Source/Core/Core/DSP/DSPAnalyzer.cpp +++ b/Source/Core/Core/DSP/DSPAnalyzer.cpp @@ -130,7 +130,7 @@ void Analyzer::AnalyzeRange(u16 start_addr, u16 end_addr) opcode->opcode == 0x1900 || opcode->opcode == 0x1980 || opcode->opcode == 0x2000 || opcode->extended) { - m_code_flags[static_cast(addr + opcode->size)] |= CODE_CHECK_INT; + m_code_flags[static_cast(addr + opcode->size)] |= CODE_CHECK_EXC; } addr += opcode->size; diff --git a/Source/Core/Core/DSP/DSPAnalyzer.h b/Source/Core/Core/DSP/DSPAnalyzer.h index ce599cffc2..e2663adfd5 100644 --- a/Source/Core/Core/DSP/DSPAnalyzer.h +++ b/Source/Core/Core/DSP/DSPAnalyzer.h @@ -26,7 +26,7 @@ enum CodeFlags : u8 CODE_LOOP_START = 4, CODE_LOOP_END = 8, CODE_UPDATE_SR = 16, - CODE_CHECK_INT = 32, + CODE_CHECK_EXC = 32, }; class Analyzer @@ -49,8 +49,41 @@ public: // some pretty expensive analysis if necessary. void Analyze(); - // Retrieves the flags set during analysis for code in memory. - [[nodiscard]] u8 GetCodeFlags(u16 address) const { return m_code_flags[address]; } + // Whether or not the given address indicates the start of an instruction. + [[nodiscard]] bool IsStartOfInstruction(u16 address) const + { + return (GetCodeFlags(address) & CODE_START_OF_INST) != 0; + } + + // Whether or not the address indicates an idle skip location. + [[nodiscard]] bool IsIdleSkip(u16 address) const + { + return (GetCodeFlags(address) & CODE_IDLE_SKIP) != 0; + } + + // Whether or not the address indicates the start of a loop. + [[nodiscard]] bool IsLoopStart(u16 address) const + { + return (GetCodeFlags(address) & CODE_LOOP_START) != 0; + } + + // Whether or not the address indicates the end of a loop. + [[nodiscard]] bool IsLoopEnd(u16 address) const + { + return (GetCodeFlags(address) & CODE_LOOP_END) != 0; + } + + // Whether or not the address describes an instruction that requires updating the SR register. + [[nodiscard]] bool IsUpdateSR(u16 address) const + { + return (GetCodeFlags(address) & CODE_UPDATE_SR) != 0; + } + + // Whether or not the address describes instructions that potentially raise exceptions. + [[nodiscard]] bool IsCheckExceptions(u16 address) const + { + return (GetCodeFlags(address) & CODE_CHECK_EXC) != 0; + } private: // Flushes all analyzed state. @@ -60,6 +93,9 @@ private: // Note: start is inclusive, end is exclusive. void AnalyzeRange(u16 start_addr, u16 end_addr); + // Retrieves the flags set during analysis for code in memory. + [[nodiscard]] u8 GetCodeFlags(u16 address) const { return m_code_flags[address]; } + // Holds data about all instructions in RAM. std::array m_code_flags{}; diff --git a/Source/Core/Core/DSP/Interpreter/DSPInterpreter.cpp b/Source/Core/Core/DSP/Interpreter/DSPInterpreter.cpp index 57662e1fb3..acde5bc721 100644 --- a/Source/Core/Core/DSP/Interpreter/DSPInterpreter.cpp +++ b/Source/Core/Core/DSP/Interpreter/DSPInterpreter.cpp @@ -51,7 +51,7 @@ void Interpreter::Step() ExecuteInstruction(UDSPInstruction{opc}); const auto pc = state.pc; - if ((state.GetAnalyzer().GetCodeFlags(static_cast(pc - 1)) & Analyzer::CODE_LOOP_END) != 0) + if (state.GetAnalyzer().IsLoopEnd(static_cast(pc - 1))) HandleLoop(); } @@ -115,8 +115,7 @@ int Interpreter::RunCyclesDebug(int cycles) return cycles; } - // Idle skipping. - if ((state.GetAnalyzer().GetCodeFlags(state.pc) & Analyzer::CODE_IDLE_SKIP) != 0) + if (state.GetAnalyzer().IsIdleSkip(state.pc)) return 0; Step(); @@ -171,8 +170,7 @@ int Interpreter::RunCycles(int cycles) if ((state.cr & CR_HALT) != 0) return 0; - // Idle skipping. - if ((state.GetAnalyzer().GetCodeFlags(state.pc) & Analyzer::CODE_IDLE_SKIP) != 0) + if (state.GetAnalyzer().IsIdleSkip(state.pc)) return 0; Step(); diff --git a/Source/Core/Core/DSP/Jit/x64/DSPEmitter.cpp b/Source/Core/Core/DSP/Jit/x64/DSPEmitter.cpp index dce1fb52ab..5bb2326019 100644 --- a/Source/Core/Core/DSP/Jit/x64/DSPEmitter.cpp +++ b/Source/Core/Core/DSP/Jit/x64/DSPEmitter.cpp @@ -128,9 +128,9 @@ void DSPEmitter::checkExceptions(u32 retval) bool DSPEmitter::FlagsNeeded() const { - const u8 flags = m_dsp_core.DSPState().GetAnalyzer().GetCodeFlags(m_compile_pc); + const auto& analyzer = m_dsp_core.DSPState().GetAnalyzer(); - return !(flags & Analyzer::CODE_START_OF_INST) || (flags & Analyzer::CODE_UPDATE_SR); + return !analyzer.IsStartOfInstruction(m_compile_pc) || analyzer.IsUpdateSR(m_compile_pc); } static void FallbackThunk(Interpreter::Interpreter& interpreter, UDSPInstruction inst) @@ -245,7 +245,7 @@ void DSPEmitter::Compile(u16 start_addr) auto& analyzer = m_dsp_core.DSPState().GetAnalyzer(); while (m_compile_pc < start_addr + MAX_BLOCK_SIZE) { - if (analyzer.GetCodeFlags(m_compile_pc) & Analyzer::CODE_CHECK_INT) + if (analyzer.IsCheckExceptions(m_compile_pc)) checkExceptions(m_block_size[start_addr]); const UDSPInstruction inst = m_dsp_core.DSPState().ReadIMEM(m_compile_pc); @@ -263,7 +263,7 @@ void DSPEmitter::Compile(u16 start_addr) // Handle loop condition, only if current instruction was flagged as a loop destination // by the analyzer. - if ((analyzer.GetCodeFlags(static_cast(m_compile_pc - 1u)) & Analyzer::CODE_LOOP_END) != 0) + if (analyzer.IsLoopEnd(static_cast(m_compile_pc - 1u))) { MOVZX(32, 16, EAX, M_SDSP_r_st(2)); TEST(32, R(EAX), R(EAX)); @@ -284,7 +284,7 @@ void DSPEmitter::Compile(u16 start_addr) DSPJitRegCache c(m_gpr); HandleLoop(); m_gpr.SaveRegs(); - if (!Host::OnThread() && (analyzer.GetCodeFlags(start_addr) & Analyzer::CODE_IDLE_SKIP) != 0) + if (!Host::OnThread() && analyzer.IsIdleSkip(start_addr)) { MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES)); } @@ -320,7 +320,7 @@ void DSPEmitter::Compile(u16 start_addr) DSPJitRegCache c(m_gpr); // don't update g_dsp.pc -- the branch insn already did m_gpr.SaveRegs(); - if (!Host::OnThread() && (analyzer.GetCodeFlags(start_addr) & Analyzer::CODE_IDLE_SKIP) != 0) + if (!Host::OnThread() && analyzer.IsIdleSkip(start_addr)) { MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES)); } @@ -337,7 +337,7 @@ void DSPEmitter::Compile(u16 start_addr) } // End the block if we're before an idle skip address - if ((analyzer.GetCodeFlags(m_compile_pc) & Analyzer::CODE_IDLE_SKIP) != 0) + if (analyzer.IsIdleSkip(m_compile_pc)) { break; } @@ -383,7 +383,7 @@ void DSPEmitter::Compile(u16 start_addr) } m_gpr.SaveRegs(); - if (!Host::OnThread() && (analyzer.GetCodeFlags(start_addr) & Analyzer::CODE_IDLE_SKIP) != 0) + if (!Host::OnThread() && analyzer.IsIdleSkip(start_addr)) { MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES)); } diff --git a/Source/Core/Core/DSP/Jit/x64/DSPJitBranch.cpp b/Source/Core/Core/DSP/Jit/x64/DSPJitBranch.cpp index ca864c9943..34204d4c07 100644 --- a/Source/Core/Core/DSP/Jit/x64/DSPJitBranch.cpp +++ b/Source/Core/Core/DSP/Jit/x64/DSPJitBranch.cpp @@ -82,8 +82,7 @@ void DSPEmitter::WriteBranchExit() { DSPJitRegCache c(m_gpr); m_gpr.SaveRegs(); - if ((m_dsp_core.DSPState().GetAnalyzer().GetCodeFlags(m_start_address) & - Analyzer::CODE_IDLE_SKIP) != 0) + if (m_dsp_core.DSPState().GetAnalyzer().IsIdleSkip(m_start_address)) { MOV(16, R(EAX), Imm16(0x1000)); }