dolphin/Source/Core/Core/DSP/DSPAnalyzer.h

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

109 lines
3.2 KiB
C
Raw Normal View History

// Copyright 2009 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
#include "Common/CommonTypes.h"
DSP: Eliminate most global state An unfortunately large single commit that deglobalizes the DSP code. (which I'm very sorry about). This would have otherwise been extremely difficult to separate due to extensive use of the globals in very coupling ways that would result in more scaffolding to work around than is worth it. Aside from the video code, I believe only the DSP code is the hairiest to deal with in terms of globals, so I guess it's best to get this dealt with right off the bat. A summary of what this commit does: - Turns the DSPInterpreter into its own class This is the most involved portion of this change. The bulk of the changes are turning non-member functions into member functions that would be situated into the Interpreter class. - Eliminates all usages to globals within DSPCore. This generally involves turning a lot of non-member functions into member functions that are either situated within SDSP or DSPCore. - Discards DSPDebugInterface (it wasn't hooked up to anything, and for the sake of eliminating global state, I'd rather get rid of it than think up ways for this class to be integrated with everything else. - Readjusts the DSP JIT to handle calling out to member functions. In most cases, this just means wrapping respective member function calles into thunk functions. Surprisingly, this doesn't even make use of the introduced System class. It was possible all along to do this without it. We can house everything within the DSPLLE class, which is quite nice =)
2020-12-21 09:22:06 -05:00
namespace DSP
{
struct SDSP;
}
namespace DSP
{
// Useful things to detect:
// * Loop endpoints - so that we can avoid checking for loops every cycle.
class Analyzer
{
public:
explicit Analyzer();
~Analyzer();
Analyzer(const Analyzer&) = default;
Analyzer& operator=(const Analyzer&) = default;
Analyzer(Analyzer&&) = default;
Analyzer& operator=(Analyzer&&) = default;
// 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);
// 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:
enum CodeFlags : u8
{
CODE_NONE = 0,
CODE_START_OF_INST = 1,
CODE_IDLE_SKIP = 2,
CODE_LOOP_START = 4,
CODE_LOOP_END = 8,
CODE_UPDATE_SR = 16,
CODE_CHECK_EXC = 32,
};
// Flushes all analyzed state.
void Reset();
// Analyzes a region of DSP memory.
// Note: start is inclusive, end is exclusive.
void AnalyzeRange(const SDSP& dsp, u16 start_addr, u16 end_addr);
// Finds addresses in the range [start_addr, end_addr) that are the start of an
// instruction. During this process other attributes may be detected as well
// for relevant instructions (loop start/end, etc).
void FindInstructionStarts(const SDSP& dsp, u16 start_addr, u16 end_addr);
// Finds locations within the range [start_addr, end_addr) that may contain idle skips.
void FindIdleSkips(const SDSP& dsp, 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{};
};
} // namespace DSP