DSPAnalyzer: Add convenience functions over bit tests

Makes it harder to accidentally misuse and increases readability.
This commit is contained in:
Lioncash 2020-12-28 11:15:55 -05:00
parent 5756ece7ce
commit 2ff4d04785
5 changed files with 52 additions and 19 deletions

View File

@ -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;

View File

@ -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{};

View File

@ -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();

View File

@ -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));
}

View File

@ -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));
}