DSPAnalyzer: Break tight coupling to SDSP

Allows the analyzer to exist independently of the DSP structure. This
allows for unit-tests to be created in a nicer manner.

SDSP is only necessary during the analysis phase, so we only need to
keep a reference around to it then as opposed to the entire lifecycle of
the analyzer.

This also allows the copy/move assignment operators to be defaulted, as
a reference member variable prevents that.
This commit is contained in:
Lioncash 2020-12-28 11:51:25 -05:00
parent f9c488f0d9
commit cc512a7524
4 changed files with 16 additions and 22 deletions

View File

@ -61,17 +61,14 @@ constexpr u16 idle_skip_sigs[NUM_IDLE_SIGS][MAX_IDLE_SIG_SIZE + 1] = {
0, 0}, 0, 0},
}; };
Analyzer::Analyzer(const SDSP& dsp) : m_dsp{dsp} Analyzer::Analyzer() = default;
{
}
Analyzer::~Analyzer() = default; Analyzer::~Analyzer() = default;
void Analyzer::Analyze() void Analyzer::Analyze(const SDSP& dsp)
{ {
Reset(); Reset();
AnalyzeRange(0x0000, 0x1000); // IRAM AnalyzeRange(dsp, 0x0000, 0x1000); // IRAM
AnalyzeRange(0x8000, 0x9000); // IROM AnalyzeRange(dsp, 0x8000, 0x9000); // IROM
} }
void Analyzer::Reset() void Analyzer::Reset()
@ -79,7 +76,7 @@ void Analyzer::Reset()
m_code_flags.fill(0); m_code_flags.fill(0);
} }
void Analyzer::AnalyzeRange(u16 start_addr, u16 end_addr) void Analyzer::AnalyzeRange(const SDSP& dsp, u16 start_addr, u16 end_addr)
{ {
// First we run an extremely simplified version of a disassembler to find // First we run an extremely simplified version of a disassembler to find
// where all instructions start. // where all instructions start.
@ -89,7 +86,7 @@ void Analyzer::AnalyzeRange(u16 start_addr, u16 end_addr)
u16 last_arithmetic = 0; u16 last_arithmetic = 0;
for (u16 addr = start_addr; addr < end_addr;) for (u16 addr = start_addr; addr < end_addr;)
{ {
const UDSPInstruction inst = m_dsp.ReadIMEM(addr); const UDSPInstruction inst = dsp.ReadIMEM(addr);
const DSPOPCTemplate* opcode = GetOpTemplate(inst); const DSPOPCTemplate* opcode = GetOpTemplate(inst);
if (!opcode) if (!opcode)
{ {
@ -101,7 +98,7 @@ void Analyzer::AnalyzeRange(u16 start_addr, u16 end_addr)
if ((inst & 0xffe0) == 0x0060 || (inst & 0xff00) == 0x1100) if ((inst & 0xffe0) == 0x0060 || (inst & 0xff00) == 0x1100)
{ {
// BLOOP, BLOOPI // BLOOP, BLOOPI
const u16 loop_end = m_dsp.ReadIMEM(addr + 1); const u16 loop_end = dsp.ReadIMEM(addr + 1);
m_code_flags[addr] |= CODE_LOOP_START; m_code_flags[addr] |= CODE_LOOP_START;
m_code_flags[loop_end] |= CODE_LOOP_END; m_code_flags[loop_end] |= CODE_LOOP_END;
} }
@ -148,7 +145,7 @@ void Analyzer::AnalyzeRange(u16 start_addr, u16 end_addr)
found = true; found = true;
if (idle_skip_sigs[s][i] == 0xFFFF) if (idle_skip_sigs[s][i] == 0xFFFF)
continue; continue;
if (idle_skip_sigs[s][i] != m_dsp.ReadIMEM(static_cast<u16>(addr + i))) if (idle_skip_sigs[s][i] != dsp.ReadIMEM(static_cast<u16>(addr + i)))
break; break;
} }
if (found) if (found)

View File

@ -20,14 +20,14 @@ namespace DSP
class Analyzer class Analyzer
{ {
public: public:
explicit Analyzer(const SDSP& dsp); explicit Analyzer();
~Analyzer(); ~Analyzer();
Analyzer(const Analyzer&) = default; Analyzer(const Analyzer&) = default;
Analyzer& operator=(const Analyzer&) = delete; Analyzer& operator=(const Analyzer&) = default;
Analyzer(Analyzer&&) = default; Analyzer(Analyzer&&) = default;
Analyzer& operator=(Analyzer&&) = delete; Analyzer& operator=(Analyzer&&) = default;
// This one should be called every time IRAM changes - which is basically // This one should be called every time IRAM changes - which is basically
// every time that a new ucode gets uploaded, and never else. At that point, // every time that a new ucode gets uploaded, and never else. At that point,
@ -35,7 +35,7 @@ public:
// all old analysis away. Luckily the entire address space is only 64K code // all old analysis away. Luckily the entire address space is only 64K code
// words and the actual code space 8K instructions in total, so we can do // words and the actual code space 8K instructions in total, so we can do
// some pretty expensive analysis if necessary. // some pretty expensive analysis if necessary.
void Analyze(); void Analyze(const SDSP& dsp);
// Whether or not the given address indicates the start of an instruction. // Whether or not the given address indicates the start of an instruction.
[[nodiscard]] bool IsStartOfInstruction(u16 address) const [[nodiscard]] bool IsStartOfInstruction(u16 address) const
@ -90,15 +90,12 @@ private:
// Analyzes a region of DSP memory. // Analyzes a region of DSP memory.
// Note: start is inclusive, end is exclusive. // Note: start is inclusive, end is exclusive.
void AnalyzeRange(u16 start_addr, u16 end_addr); void AnalyzeRange(const SDSP& dsp, u16 start_addr, u16 end_addr);
// Retrieves the flags set during analysis for code in memory. // Retrieves the flags set during analysis for code in memory.
[[nodiscard]] u8 GetCodeFlags(u16 address) const { return m_code_flags[address]; } [[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{};
// DSP context for analysis to be run under.
const SDSP& m_dsp;
}; };
} // namespace DSP } // namespace DSP

View File

@ -115,7 +115,7 @@ private:
SDSP& m_dsp; SDSP& m_dsp;
}; };
SDSP::SDSP(DSPCore& core) : m_dsp_core{core}, m_analyzer{*this} SDSP::SDSP(DSPCore& core) : m_dsp_core{core}
{ {
} }
@ -487,7 +487,7 @@ void DSPCore::Step()
void DSPCore::Reset() void DSPCore::Reset()
{ {
m_dsp.Reset(); m_dsp.Reset();
m_dsp.GetAnalyzer().Analyze(); m_dsp.GetAnalyzer().Analyze(m_dsp);
} }
void DSPCore::ClearIRAM() void DSPCore::ClearIRAM()

View File

@ -93,7 +93,7 @@ void CodeLoaded(DSPCore& dsp, const u8* ptr, size_t size)
UpdateDebugger(); UpdateDebugger();
dsp.ClearIRAM(); dsp.ClearIRAM();
state.GetAnalyzer().Analyze(); state.GetAnalyzer().Analyze(state);
} }
void UpdateDebugger() void UpdateDebugger()