// Copyright 2018 Dolphin Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "Common/Debug/MemoryPatches.h" #include #include #include namespace Common::Debug { MemoryPatch::MemoryPatch(u32 address_, std::vector value_) : address(address_), value(std::move(value_)) { } MemoryPatch::MemoryPatch(u32 address_, u32 value_) : MemoryPatch(address_, {static_cast(value_ >> 24), static_cast(value_ >> 16), static_cast(value_ >> 8), static_cast(value_)}) { } MemoryPatches::MemoryPatches() = default; MemoryPatches::~MemoryPatches() = default; void MemoryPatches::SetPatch(const Core::CPUThreadGuard& guard, u32 address, u32 value) { const std::size_t index = m_patches.size(); m_patches.emplace_back(address, value); Patch(guard, index); } void MemoryPatches::SetPatch(const Core::CPUThreadGuard& guard, u32 address, std::vector value) { UnsetPatch(guard, address); const std::size_t index = m_patches.size(); m_patches.emplace_back(address, std::move(value)); Patch(guard, index); } void MemoryPatches::SetFramePatch(const Core::CPUThreadGuard& guard, u32 address, u32 value) { const std::size_t index = m_patches.size(); m_patches.emplace_back(address, value); m_patches.back().type = MemoryPatch::ApplyType::EachFrame; Patch(guard, index); } void MemoryPatches::SetFramePatch(const Core::CPUThreadGuard& guard, u32 address, std::vector value) { UnsetPatch(guard, address); const std::size_t index = m_patches.size(); m_patches.emplace_back(address, std::move(value)); m_patches.back().type = MemoryPatch::ApplyType::EachFrame; Patch(guard, index); } const std::vector& MemoryPatches::GetPatches() const { return m_patches; } void MemoryPatches::UnsetPatch(const Core::CPUThreadGuard& guard, u32 address) { const auto it = std::find_if(m_patches.begin(), m_patches.end(), [address](const auto& patch) { return patch.address == address; }); if (it == m_patches.end()) return; const std::size_t index = std::distance(m_patches.begin(), it); RemovePatch(guard, index); } void MemoryPatches::EnablePatch(const Core::CPUThreadGuard& guard, std::size_t index) { if (m_patches[index].is_enabled == MemoryPatch::State::Enabled) return; m_patches[index].is_enabled = MemoryPatch::State::Enabled; Patch(guard, index); } void MemoryPatches::DisablePatch(const Core::CPUThreadGuard& guard, std::size_t index) { if (m_patches[index].is_enabled == MemoryPatch::State::Disabled) return; m_patches[index].is_enabled = MemoryPatch::State::Disabled; Patch(guard, index); } bool MemoryPatches::HasEnabledPatch(u32 address) const { return std::any_of(m_patches.begin(), m_patches.end(), [address](const MemoryPatch& patch) { return patch.address == address && patch.is_enabled == MemoryPatch::State::Enabled; }); } void MemoryPatches::RemovePatch(const Core::CPUThreadGuard& guard, std::size_t index) { DisablePatch(guard, index); UnPatch(index); m_patches.erase(m_patches.begin() + index); } void MemoryPatches::ClearPatches(const Core::CPUThreadGuard& guard) { const std::size_t size = m_patches.size(); for (std::size_t index = 0; index < size; ++index) { DisablePatch(guard, index); UnPatch(index); } m_patches.clear(); } } // namespace Common::Debug