mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-08-03 14:49:22 +00:00
PowerPC: Track registers used in memory break point conditions
This commit is contained in:
parent
edb1db7400
commit
96e43164d0
4 changed files with 75 additions and 2 deletions
|
@ -346,8 +346,12 @@ void MemChecks::Update()
|
||||||
{
|
{
|
||||||
const Core::CPUThreadGuard guard(m_system);
|
const Core::CPUThreadGuard guard(m_system);
|
||||||
|
|
||||||
// Clear the JIT cache so it can switch the watchpoint-compatible mode.
|
const bool registers_changed = UpdateRegistersUsedInConditions();
|
||||||
if (m_mem_breakpoints_set != HasAny())
|
|
||||||
|
// If we've added a first memcheck, clear the JIT cache so it can switch to watchpoint-compatible
|
||||||
|
// code. Or, if we've added a memcheck whose condition wants to read from a new register,
|
||||||
|
// clear the JIT cache to make the slow memory access code flush that register.
|
||||||
|
if (registers_changed || m_mem_breakpoints_set != HasAny())
|
||||||
{
|
{
|
||||||
m_system.GetJitInterface().ClearCache(guard);
|
m_system.GetJitInterface().ClearCache(guard);
|
||||||
m_mem_breakpoints_set = HasAny();
|
m_mem_breakpoints_set = HasAny();
|
||||||
|
@ -356,6 +360,27 @@ void MemChecks::Update()
|
||||||
m_system.GetMMU().DBATUpdated();
|
m_system.GetMMU().DBATUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MemChecks::UpdateRegistersUsedInConditions()
|
||||||
|
{
|
||||||
|
BitSet32 gprs_used, fprs_used;
|
||||||
|
for (TMemCheck& mem_check : m_mem_checks)
|
||||||
|
{
|
||||||
|
if (mem_check.condition)
|
||||||
|
{
|
||||||
|
gprs_used |= mem_check.condition->GetGPRsUsed();
|
||||||
|
fprs_used |= mem_check.condition->GetFPRsUsed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool registers_changed =
|
||||||
|
gprs_used != m_gprs_used_in_conditions || fprs_used != m_fprs_used_in_conditions;
|
||||||
|
|
||||||
|
m_gprs_used_in_conditions = gprs_used;
|
||||||
|
m_fprs_used_in_conditions = fprs_used;
|
||||||
|
|
||||||
|
return registers_changed;
|
||||||
|
}
|
||||||
|
|
||||||
TMemCheck* MemChecks::GetMemCheck(u32 address, size_t size)
|
TMemCheck* MemChecks::GetMemCheck(u32 address, size_t size)
|
||||||
{
|
{
|
||||||
const auto iter = std::ranges::find_if(m_mem_checks, [address, size](const auto& mc) {
|
const auto iter = std::ranges::find_if(m_mem_checks, [address, size](const auto& mc) {
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Common/BitSet.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Core/PowerPC/Expression.h"
|
#include "Core/PowerPC/Expression.h"
|
||||||
|
|
||||||
|
@ -127,8 +128,16 @@ public:
|
||||||
void Clear();
|
void Clear();
|
||||||
bool HasAny() const { return !m_mem_checks.empty(); }
|
bool HasAny() const { return !m_mem_checks.empty(); }
|
||||||
|
|
||||||
|
BitSet32 GetGPRsUsedInConditions() { return m_gprs_used_in_conditions; }
|
||||||
|
BitSet32 GetFPRsUsedInConditions() { return m_fprs_used_in_conditions; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Returns whether any change was made
|
||||||
|
bool UpdateRegistersUsedInConditions();
|
||||||
|
|
||||||
TMemChecks m_mem_checks;
|
TMemChecks m_mem_checks;
|
||||||
Core::System& m_system;
|
Core::System& m_system;
|
||||||
|
BitSet32 m_gprs_used_in_conditions;
|
||||||
|
BitSet32 m_fprs_used_in_conditions;
|
||||||
bool m_mem_breakpoints_set = false;
|
bool m_mem_breakpoints_set = false;
|
||||||
};
|
};
|
||||||
|
|
|
@ -494,3 +494,22 @@ std::string Expression::GetText() const
|
||||||
{
|
{
|
||||||
return m_text;
|
return m_text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Expression::ComputeRegistersUsed()
|
||||||
|
{
|
||||||
|
if (m_has_computed_registers_used)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (const VarBinding& bind : m_binds)
|
||||||
|
{
|
||||||
|
switch (bind.type)
|
||||||
|
{
|
||||||
|
case VarBindingType::GPR:
|
||||||
|
m_gprs_used[bind.index] = true;
|
||||||
|
break;
|
||||||
|
case VarBindingType::FPR:
|
||||||
|
m_fprs_used[bind.index] = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "Common/BitSet.h"
|
||||||
|
|
||||||
struct expr;
|
struct expr;
|
||||||
struct expr_var_list;
|
struct expr_var_list;
|
||||||
|
|
||||||
|
@ -41,6 +43,18 @@ public:
|
||||||
|
|
||||||
std::string GetText() const;
|
std::string GetText() const;
|
||||||
|
|
||||||
|
BitSet32 GetGPRsUsed()
|
||||||
|
{
|
||||||
|
ComputeRegistersUsed();
|
||||||
|
return m_gprs_used;
|
||||||
|
}
|
||||||
|
|
||||||
|
BitSet32 GetFPRsUsed()
|
||||||
|
{
|
||||||
|
ComputeRegistersUsed();
|
||||||
|
return m_fprs_used;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class SynchronizeDirection
|
enum class SynchronizeDirection
|
||||||
{
|
{
|
||||||
|
@ -69,10 +83,16 @@ private:
|
||||||
void SynchronizeBindings(Core::System& system, SynchronizeDirection dir) const;
|
void SynchronizeBindings(Core::System& system, SynchronizeDirection dir) const;
|
||||||
void Reporting(const double result) const;
|
void Reporting(const double result) const;
|
||||||
|
|
||||||
|
void ComputeRegistersUsed();
|
||||||
|
|
||||||
std::string m_text;
|
std::string m_text;
|
||||||
ExprPointer m_expr;
|
ExprPointer m_expr;
|
||||||
ExprVarListPointer m_vars;
|
ExprVarListPointer m_vars;
|
||||||
std::vector<VarBinding> m_binds;
|
std::vector<VarBinding> m_binds;
|
||||||
|
|
||||||
|
BitSet32 m_gprs_used;
|
||||||
|
BitSet32 m_fprs_used;
|
||||||
|
bool m_has_computed_registers_used = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool EvaluateCondition(Core::System& system, const std::optional<Expression>& condition)
|
inline bool EvaluateCondition(Core::System& system, const std::optional<Expression>& condition)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue