DSPAnalyzer: Add convenience functions over bit tests
Makes it harder to accidentally misuse and increases readability.
This commit is contained in:
parent
5756ece7ce
commit
2ff4d04785
|
@ -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<u16>(addr + opcode->size)] |= CODE_CHECK_INT;
|
||||
m_code_flags[static_cast<u16>(addr + opcode->size)] |= CODE_CHECK_EXC;
|
||||
}
|
||||
|
||||
addr += opcode->size;
|
||||
|
|
|
@ -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<u8, 65536> m_code_flags{};
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ void Interpreter::Step()
|
|||
ExecuteInstruction(UDSPInstruction{opc});
|
||||
|
||||
const auto pc = state.pc;
|
||||
if ((state.GetAnalyzer().GetCodeFlags(static_cast<u16>(pc - 1)) & Analyzer::CODE_LOOP_END) != 0)
|
||||
if (state.GetAnalyzer().IsLoopEnd(static_cast<u16>(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();
|
||||
|
|
|
@ -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<u16>(m_compile_pc - 1u)) & Analyzer::CODE_LOOP_END) != 0)
|
||||
if (analyzer.IsLoopEnd(static_cast<u16>(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));
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue