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->opcode == 0x1900 || opcode->opcode == 0x1980 || opcode->opcode == 0x2000 ||
|
||||||
opcode->extended)
|
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;
|
addr += opcode->size;
|
||||||
|
|
|
@ -26,7 +26,7 @@ enum CodeFlags : u8
|
||||||
CODE_LOOP_START = 4,
|
CODE_LOOP_START = 4,
|
||||||
CODE_LOOP_END = 8,
|
CODE_LOOP_END = 8,
|
||||||
CODE_UPDATE_SR = 16,
|
CODE_UPDATE_SR = 16,
|
||||||
CODE_CHECK_INT = 32,
|
CODE_CHECK_EXC = 32,
|
||||||
};
|
};
|
||||||
|
|
||||||
class Analyzer
|
class Analyzer
|
||||||
|
@ -49,8 +49,41 @@ public:
|
||||||
// some pretty expensive analysis if necessary.
|
// some pretty expensive analysis if necessary.
|
||||||
void Analyze();
|
void Analyze();
|
||||||
|
|
||||||
// Retrieves the flags set during analysis for code in memory.
|
// Whether or not the given address indicates the start of an instruction.
|
||||||
[[nodiscard]] u8 GetCodeFlags(u16 address) const { return m_code_flags[address]; }
|
[[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:
|
private:
|
||||||
// Flushes all analyzed state.
|
// Flushes all analyzed state.
|
||||||
|
@ -60,6 +93,9 @@ private:
|
||||||
// Note: start is inclusive, end is exclusive.
|
// Note: start is inclusive, end is exclusive.
|
||||||
void AnalyzeRange(u16 start_addr, u16 end_addr);
|
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.
|
// Holds data about all instructions in RAM.
|
||||||
std::array<u8, 65536> m_code_flags{};
|
std::array<u8, 65536> m_code_flags{};
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ void Interpreter::Step()
|
||||||
ExecuteInstruction(UDSPInstruction{opc});
|
ExecuteInstruction(UDSPInstruction{opc});
|
||||||
|
|
||||||
const auto pc = state.pc;
|
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();
|
HandleLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,8 +115,7 @@ int Interpreter::RunCyclesDebug(int cycles)
|
||||||
return cycles;
|
return cycles;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Idle skipping.
|
if (state.GetAnalyzer().IsIdleSkip(state.pc))
|
||||||
if ((state.GetAnalyzer().GetCodeFlags(state.pc) & Analyzer::CODE_IDLE_SKIP) != 0)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
Step();
|
Step();
|
||||||
|
@ -171,8 +170,7 @@ int Interpreter::RunCycles(int cycles)
|
||||||
if ((state.cr & CR_HALT) != 0)
|
if ((state.cr & CR_HALT) != 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// Idle skipping.
|
if (state.GetAnalyzer().IsIdleSkip(state.pc))
|
||||||
if ((state.GetAnalyzer().GetCodeFlags(state.pc) & Analyzer::CODE_IDLE_SKIP) != 0)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
Step();
|
Step();
|
||||||
|
|
|
@ -128,9 +128,9 @@ void DSPEmitter::checkExceptions(u32 retval)
|
||||||
|
|
||||||
bool DSPEmitter::FlagsNeeded() const
|
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)
|
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();
|
auto& analyzer = m_dsp_core.DSPState().GetAnalyzer();
|
||||||
while (m_compile_pc < start_addr + MAX_BLOCK_SIZE)
|
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]);
|
checkExceptions(m_block_size[start_addr]);
|
||||||
|
|
||||||
const UDSPInstruction inst = m_dsp_core.DSPState().ReadIMEM(m_compile_pc);
|
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
|
// Handle loop condition, only if current instruction was flagged as a loop destination
|
||||||
// by the analyzer.
|
// 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));
|
MOVZX(32, 16, EAX, M_SDSP_r_st(2));
|
||||||
TEST(32, R(EAX), R(EAX));
|
TEST(32, R(EAX), R(EAX));
|
||||||
|
@ -284,7 +284,7 @@ void DSPEmitter::Compile(u16 start_addr)
|
||||||
DSPJitRegCache c(m_gpr);
|
DSPJitRegCache c(m_gpr);
|
||||||
HandleLoop();
|
HandleLoop();
|
||||||
m_gpr.SaveRegs();
|
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));
|
MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES));
|
||||||
}
|
}
|
||||||
|
@ -320,7 +320,7 @@ void DSPEmitter::Compile(u16 start_addr)
|
||||||
DSPJitRegCache c(m_gpr);
|
DSPJitRegCache c(m_gpr);
|
||||||
// don't update g_dsp.pc -- the branch insn already did
|
// don't update g_dsp.pc -- the branch insn already did
|
||||||
m_gpr.SaveRegs();
|
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));
|
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
|
// 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;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -383,7 +383,7 @@ void DSPEmitter::Compile(u16 start_addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
m_gpr.SaveRegs();
|
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));
|
MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES));
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,8 +82,7 @@ void DSPEmitter::WriteBranchExit()
|
||||||
{
|
{
|
||||||
DSPJitRegCache c(m_gpr);
|
DSPJitRegCache c(m_gpr);
|
||||||
m_gpr.SaveRegs();
|
m_gpr.SaveRegs();
|
||||||
if ((m_dsp_core.DSPState().GetAnalyzer().GetCodeFlags(m_start_address) &
|
if (m_dsp_core.DSPState().GetAnalyzer().IsIdleSkip(m_start_address))
|
||||||
Analyzer::CODE_IDLE_SKIP) != 0)
|
|
||||||
{
|
{
|
||||||
MOV(16, R(EAX), Imm16(0x1000));
|
MOV(16, R(EAX), Imm16(0x1000));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue