summaryrefslogtreecommitdiff
path: root/Source
diff options
context:
space:
mode:
authorLioncash <mathew1800@gmail.com>2020-12-28 10:51:19 -0500
committerLioncash <mathew1800@gmail.com>2020-12-28 11:37:29 -0500
commit5756ece7cee89263b78ab8fe0ad0819d1e752ecd (patch)
tree2a5ac107c860b0c8e92366f5593675107c0999ae /Source
parent8f4c6ad7b102244e056875b30c2fb2243b70f74f (diff)
DSPAnalyzer: Implement DSP analyzer skeleton and use it
Attempts to simply make use of the interface. Cleanup will follow in subsequent commits to make for nicer review.
Diffstat (limited to 'Source')
-rw-r--r--Source/Core/Core/DSP/DSPAnalyzer.cpp67
-rw-r--r--Source/Core/Core/DSP/DSPAnalyzer.h12
-rw-r--r--Source/Core/Core/DSP/DSPCore.cpp4
-rw-r--r--Source/Core/Core/DSP/DSPCore.h6
-rw-r--r--Source/Core/Core/DSP/Interpreter/DSPInterpreter.cpp14
-rw-r--r--Source/Core/Core/DSP/Jit/x64/DSPEmitter.cpp15
-rw-r--r--Source/Core/Core/DSP/Jit/x64/DSPJitBranch.cpp3
-rw-r--r--Source/Core/Core/HW/DSPLLE/DSPHost.cpp3
8 files changed, 58 insertions, 66 deletions
diff --git a/Source/Core/Core/DSP/DSPAnalyzer.cpp b/Source/Core/Core/DSP/DSPAnalyzer.cpp
index 7a88b99773..107645d6c5 100644
--- a/Source/Core/Core/DSP/DSPAnalyzer.cpp
+++ b/Source/Core/Core/DSP/DSPAnalyzer.cpp
@@ -14,13 +14,6 @@
namespace DSP::Analyzer
{
-namespace
-{
-constexpr size_t ISPACE = 65536;
-
-// Holds data about all instructions in RAM.
-std::array<u8, ISPACE> code_flags;
-
// Good candidates for idle skipping is mail wait loops. If we're time slicing
// between the main CPU and the DSP, if the DSP runs into one of these, it might
// as well give up its time slice immediately, after executing once.
@@ -65,14 +58,28 @@ constexpr u16 idle_skip_sigs[NUM_IDLE_SIGS][MAX_IDLE_SIG_SIZE + 1] = {
{0x00da, 0x0352, // LR $AX0.H, @0x0352
0x8600, // TSTAXH $AX0.H
0x0295, 0xFFFF, // JZ 0x????
- 0, 0}};
+ 0, 0},
+};
+
+Analyzer::Analyzer(const SDSP& dsp) : m_dsp{dsp}
+{
+}
+
+Analyzer::~Analyzer() = default;
+
+void Analyzer::Analyze()
+{
+ Reset();
+ AnalyzeRange(0x0000, 0x1000); // IRAM
+ AnalyzeRange(0x8000, 0x9000); // IROM
+}
-void Reset()
+void Analyzer::Reset()
{
- code_flags.fill(0);
+ m_code_flags.fill(0);
}
-void AnalyzeRange(const SDSP& dsp, u16 start_addr, u16 end_addr)
+void Analyzer::AnalyzeRange(u16 start_addr, u16 end_addr)
{
// First we run an extremely simplified version of a disassembler to find
// where all instructions start.
@@ -82,27 +89,27 @@ void AnalyzeRange(const SDSP& dsp, u16 start_addr, u16 end_addr)
u16 last_arithmetic = 0;
for (u16 addr = start_addr; addr < end_addr;)
{
- const UDSPInstruction inst = dsp.ReadIMEM(addr);
+ const UDSPInstruction inst = m_dsp.ReadIMEM(addr);
const DSPOPCTemplate* opcode = GetOpTemplate(inst);
if (!opcode)
{
addr++;
continue;
}
- code_flags[addr] |= CODE_START_OF_INST;
+ m_code_flags[addr] |= CODE_START_OF_INST;
// Look for loops.
if ((inst & 0xffe0) == 0x0060 || (inst & 0xff00) == 0x1100)
{
// BLOOP, BLOOPI
- const u16 loop_end = dsp.ReadIMEM(addr + 1);
- code_flags[addr] |= CODE_LOOP_START;
- code_flags[loop_end] |= CODE_LOOP_END;
+ const u16 loop_end = m_dsp.ReadIMEM(addr + 1);
+ m_code_flags[addr] |= CODE_LOOP_START;
+ m_code_flags[loop_end] |= CODE_LOOP_END;
}
else if ((inst & 0xffe0) == 0x0040 || (inst & 0xff00) == 0x1000)
{
// LOOP, LOOPI
- code_flags[addr] |= CODE_LOOP_START;
- code_flags[static_cast<u16>(addr + 1u)] |= CODE_LOOP_END;
+ m_code_flags[addr] |= CODE_LOOP_START;
+ m_code_flags[static_cast<u16>(addr + 1u)] |= CODE_LOOP_END;
}
// Mark the last arithmetic/multiplier instruction before a branch.
@@ -114,7 +121,7 @@ void AnalyzeRange(const SDSP& dsp, u16 start_addr, u16 end_addr)
if (opcode->branch && !opcode->uncond_branch)
{
- code_flags[last_arithmetic] |= CODE_UPDATE_SR;
+ m_code_flags[last_arithmetic] |= CODE_UPDATE_SR;
}
// If an instruction potentially raises exceptions, mark the following
@@ -122,7 +129,9 @@ void AnalyzeRange(const SDSP& dsp, u16 start_addr, u16 end_addr)
if (opcode->opcode == 0x00c0 || opcode->opcode == 0x1800 || opcode->opcode == 0x1880 ||
opcode->opcode == 0x1900 || opcode->opcode == 0x1980 || opcode->opcode == 0x2000 ||
opcode->extended)
- code_flags[static_cast<u16>(addr + opcode->size)] |= CODE_CHECK_INT;
+ {
+ m_code_flags[static_cast<u16>(addr + opcode->size)] |= CODE_CHECK_INT;
+ }
addr += opcode->size;
}
@@ -139,30 +148,16 @@ void AnalyzeRange(const SDSP& dsp, u16 start_addr, u16 end_addr)
found = true;
if (idle_skip_sigs[s][i] == 0xFFFF)
continue;
- if (idle_skip_sigs[s][i] != dsp.ReadIMEM(static_cast<u16>(addr + i)))
+ if (idle_skip_sigs[s][i] != m_dsp.ReadIMEM(static_cast<u16>(addr + i)))
break;
}
if (found)
{
INFO_LOG_FMT(DSPLLE, "Idle skip location found at {:02x} (sigNum:{})", addr, s + 1);
- code_flags[addr] |= CODE_IDLE_SKIP;
+ m_code_flags[addr] |= CODE_IDLE_SKIP;
}
}
}
INFO_LOG_FMT(DSPLLE, "Finished analysis.");
}
-} // Anonymous namespace
-
-void Analyze(const SDSP& dsp)
-{
- Reset();
- AnalyzeRange(dsp, 0x0000, 0x1000); // IRAM
- AnalyzeRange(dsp, 0x8000, 0x9000); // IROM
-}
-
-u8 GetCodeFlags(u16 address)
-{
- return code_flags[address];
-}
-
} // namespace DSP::Analyzer
diff --git a/Source/Core/Core/DSP/DSPAnalyzer.h b/Source/Core/Core/DSP/DSPAnalyzer.h
index 5cf80b88fe..ce599cffc2 100644
--- a/Source/Core/Core/DSP/DSPAnalyzer.h
+++ b/Source/Core/Core/DSP/DSPAnalyzer.h
@@ -66,16 +66,4 @@ private:
// DSP context for analysis to be run under.
const SDSP& m_dsp;
};
-
-// 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,
-// we can do as much static analysis as we want - but we should always throw
-// 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
-// some pretty expensive analysis if necessary.
-void Analyze(const SDSP& dsp);
-
-// Retrieves the flags set during analysis for code in memory.
-u8 GetCodeFlags(u16 address);
-
} // namespace DSP::Analyzer
diff --git a/Source/Core/Core/DSP/DSPCore.cpp b/Source/Core/Core/DSP/DSPCore.cpp
index 39618d5621..7be3350ae6 100644
--- a/Source/Core/Core/DSP/DSPCore.cpp
+++ b/Source/Core/Core/DSP/DSPCore.cpp
@@ -115,7 +115,7 @@ private:
SDSP& m_dsp;
};
-SDSP::SDSP(DSPCore& core) : m_dsp_core{core}
+SDSP::SDSP(DSPCore& core) : m_dsp_core{core}, m_analyzer{*this}
{
}
@@ -487,7 +487,7 @@ void DSPCore::Step()
void DSPCore::Reset()
{
m_dsp.Reset();
- Analyzer::Analyze(m_dsp);
+ m_dsp.GetAnalyzer().Analyze();
}
void DSPCore::ClearIRAM()
diff --git a/Source/Core/Core/DSP/DSPCore.h b/Source/Core/Core/DSP/DSPCore.h
index 719e6a02c8..f25c302a70 100644
--- a/Source/Core/Core/DSP/DSPCore.h
+++ b/Source/Core/Core/DSP/DSPCore.h
@@ -12,6 +12,7 @@
#include <string>
#include "Common/Event.h"
+#include "Core/DSP/DSPAnalyzer.h"
#include "Core/DSP/DSPBreakpoints.h"
#include "Core/DSP/DSPCaptureLogger.h"
@@ -396,6 +397,10 @@ struct SDSP
// Saves and loads any necessary state.
void DoState(PointerWrap& p);
+ // DSP static analyzer.
+ Analyzer::Analyzer& GetAnalyzer() { return m_analyzer; }
+ const Analyzer::Analyzer& GetAnalyzer() const { return m_analyzer; }
+
DSP_Regs r{};
u16 pc = 0;
@@ -449,6 +454,7 @@ private:
u16 ReadIFXImpl(u16 address);
DSPCore& m_dsp_core;
+ Analyzer::Analyzer m_analyzer;
};
enum class State
diff --git a/Source/Core/Core/DSP/Interpreter/DSPInterpreter.cpp b/Source/Core/Core/DSP/Interpreter/DSPInterpreter.cpp
index 70ea39b8f2..57662e1fb3 100644
--- a/Source/Core/Core/DSP/Interpreter/DSPInterpreter.cpp
+++ b/Source/Core/Core/DSP/Interpreter/DSPInterpreter.cpp
@@ -42,14 +42,16 @@ void Interpreter::ExecuteInstruction(const UDSPInstruction inst)
void Interpreter::Step()
{
+ auto& state = m_dsp_core.DSPState();
+
m_dsp_core.CheckExceptions();
- m_dsp_core.DSPState().step_counter++;
+ state.step_counter++;
- const u16 opc = m_dsp_core.DSPState().FetchInstruction();
+ const u16 opc = state.FetchInstruction();
ExecuteInstruction(UDSPInstruction{opc});
- const auto pc = m_dsp_core.DSPState().pc;
- if ((Analyzer::GetCodeFlags(static_cast<u16>(pc - 1)) & Analyzer::CODE_LOOP_END) != 0)
+ const auto pc = state.pc;
+ if ((state.GetAnalyzer().GetCodeFlags(static_cast<u16>(pc - 1)) & Analyzer::CODE_LOOP_END) != 0)
HandleLoop();
}
@@ -114,7 +116,7 @@ int Interpreter::RunCyclesDebug(int cycles)
}
// Idle skipping.
- if ((Analyzer::GetCodeFlags(state.pc) & Analyzer::CODE_IDLE_SKIP) != 0)
+ if ((state.GetAnalyzer().GetCodeFlags(state.pc) & Analyzer::CODE_IDLE_SKIP) != 0)
return 0;
Step();
@@ -170,7 +172,7 @@ int Interpreter::RunCycles(int cycles)
return 0;
// Idle skipping.
- if ((Analyzer::GetCodeFlags(state.pc) & Analyzer::CODE_IDLE_SKIP) != 0)
+ if ((state.GetAnalyzer().GetCodeFlags(state.pc) & Analyzer::CODE_IDLE_SKIP) != 0)
return 0;
Step();
diff --git a/Source/Core/Core/DSP/Jit/x64/DSPEmitter.cpp b/Source/Core/Core/DSP/Jit/x64/DSPEmitter.cpp
index 25f26d0f34..dce1fb52ab 100644
--- a/Source/Core/Core/DSP/Jit/x64/DSPEmitter.cpp
+++ b/Source/Core/Core/DSP/Jit/x64/DSPEmitter.cpp
@@ -128,7 +128,7 @@ void DSPEmitter::checkExceptions(u32 retval)
bool DSPEmitter::FlagsNeeded() const
{
- const u8 flags = Analyzer::GetCodeFlags(m_compile_pc);
+ const u8 flags = m_dsp_core.DSPState().GetAnalyzer().GetCodeFlags(m_compile_pc);
return !(flags & Analyzer::CODE_START_OF_INST) || (flags & Analyzer::CODE_UPDATE_SR);
}
@@ -242,9 +242,10 @@ void DSPEmitter::Compile(u16 start_addr)
bool fixup_pc = false;
m_block_size[start_addr] = 0;
+ 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.GetCodeFlags(m_compile_pc) & Analyzer::CODE_CHECK_INT)
checkExceptions(m_block_size[start_addr]);
const UDSPInstruction inst = m_dsp_core.DSPState().ReadIMEM(m_compile_pc);
@@ -262,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)
+ if ((analyzer.GetCodeFlags(static_cast<u16>(m_compile_pc - 1u)) & Analyzer::CODE_LOOP_END) != 0)
{
MOVZX(32, 16, EAX, M_SDSP_r_st(2));
TEST(32, R(EAX), R(EAX));
@@ -283,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)
+ if (!Host::OnThread() && (analyzer.GetCodeFlags(start_addr) & Analyzer::CODE_IDLE_SKIP) != 0)
{
MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES));
}
@@ -319,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)
+ if (!Host::OnThread() && (analyzer.GetCodeFlags(start_addr) & Analyzer::CODE_IDLE_SKIP) != 0)
{
MOV(16, R(EAX), Imm16(DSP_IDLE_SKIP_CYCLES));
}
@@ -336,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)
+ if ((analyzer.GetCodeFlags(m_compile_pc) & Analyzer::CODE_IDLE_SKIP) != 0)
{
break;
}
@@ -382,7 +383,7 @@ void DSPEmitter::Compile(u16 start_addr)
}
m_gpr.SaveRegs();
- if (!Host::OnThread() && Analyzer::GetCodeFlags(start_addr) & Analyzer::CODE_IDLE_SKIP)
+ if (!Host::OnThread() && (analyzer.GetCodeFlags(start_addr) & Analyzer::CODE_IDLE_SKIP) != 0)
{
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 664ce367c6..ca864c9943 100644
--- a/Source/Core/Core/DSP/Jit/x64/DSPJitBranch.cpp
+++ b/Source/Core/Core/DSP/Jit/x64/DSPJitBranch.cpp
@@ -82,7 +82,8 @@ void DSPEmitter::WriteBranchExit()
{
DSPJitRegCache c(m_gpr);
m_gpr.SaveRegs();
- if (Analyzer::GetCodeFlags(m_start_address) & Analyzer::CODE_IDLE_SKIP)
+ if ((m_dsp_core.DSPState().GetAnalyzer().GetCodeFlags(m_start_address) &
+ Analyzer::CODE_IDLE_SKIP) != 0)
{
MOV(16, R(EAX), Imm16(0x1000));
}
diff --git a/Source/Core/Core/HW/DSPLLE/DSPHost.cpp b/Source/Core/Core/HW/DSPLLE/DSPHost.cpp
index f42510b874..b0e06edca5 100644
--- a/Source/Core/Core/HW/DSPLLE/DSPHost.cpp
+++ b/Source/Core/Core/HW/DSPLLE/DSPHost.cpp
@@ -93,8 +93,7 @@ void CodeLoaded(DSPCore& dsp, const u8* ptr, size_t size)
UpdateDebugger();
dsp.ClearIRAM();
-
- Analyzer::Analyze(state);
+ state.GetAnalyzer().Analyze();
}
void UpdateDebugger()