summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/memory/freezer.cpp40
-rw-r--r--src/core/memory/freezer.h39
2 files changed, 49 insertions, 30 deletions
diff --git a/src/core/memory/freezer.cpp b/src/core/memory/freezer.cpp
index 1d0ccf328..6b20e8388 100644
--- a/src/core/memory/freezer.cpp
+++ b/src/core/memory/freezer.cpp
@@ -3,18 +3,20 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/assert.h" 5#include "common/assert.h"
6#include "common/logging/log.h"
6#include "core/core.h" 7#include "core/core.h"
8#include "core/core_timing.h"
7#include "core/core_timing_util.h" 9#include "core/core_timing_util.h"
8#include "core/memory.h" 10#include "core/memory.h"
9#include "core/memory/freezer.h" 11#include "core/memory/freezer.h"
10 12
11namespace Memory { 13namespace Memory {
12 14
13constexpr s64 MEMORY_FREEZER_TICKS = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 60);
14
15namespace { 15namespace {
16 16
17u64 MemoryReadWidth(u8 width, VAddr addr) { 17constexpr s64 MEMORY_FREEZER_TICKS = static_cast<s64>(Core::Timing::BASE_CLOCK_RATE / 60);
18
19u64 MemoryReadWidth(u32 width, VAddr addr) {
18 switch (width) { 20 switch (width) {
19 case 1: 21 case 1:
20 return Read8(addr); 22 return Read8(addr);
@@ -30,7 +32,7 @@ u64 MemoryReadWidth(u8 width, VAddr addr) {
30 } 32 }
31} 33}
32 34
33void MemoryWriteWidth(u8 width, VAddr addr, u64 value) { 35void MemoryWriteWidth(u32 width, VAddr addr, u64 value) {
34 switch (width) { 36 switch (width) {
35 case 1: 37 case 1:
36 Write8(addr, static_cast<u8>(value)); 38 Write8(addr, static_cast<u8>(value));
@@ -73,19 +75,19 @@ void Freezer::SetActive(bool active) {
73} 75}
74 76
75bool Freezer::IsActive() const { 77bool Freezer::IsActive() const {
76 return active.load(); 78 return active.load(std::memory_order_relaxed);
77} 79}
78 80
79void Freezer::Clear() { 81void Freezer::Clear() {
80 std::lock_guard<std::recursive_mutex> lock(entries_mutex); 82 std::lock_guard lock{entries_mutex};
81 83
82 LOG_DEBUG(Common_Memory, "Clearing all frozen memory values."); 84 LOG_DEBUG(Common_Memory, "Clearing all frozen memory values.");
83 85
84 entries.clear(); 86 entries.clear();
85} 87}
86 88
87u64 Freezer::Freeze(VAddr address, u8 width) { 89u64 Freezer::Freeze(VAddr address, u32 width) {
88 std::lock_guard<std::recursive_mutex> lock(entries_mutex); 90 std::lock_guard lock{entries_mutex};
89 91
90 const auto current_value = MemoryReadWidth(width, address); 92 const auto current_value = MemoryReadWidth(width, address);
91 entries.push_back({address, width, current_value}); 93 entries.push_back({address, width, current_value});
@@ -98,7 +100,7 @@ u64 Freezer::Freeze(VAddr address, u8 width) {
98} 100}
99 101
100void Freezer::Unfreeze(VAddr address) { 102void Freezer::Unfreeze(VAddr address) {
101 std::lock_guard<std::recursive_mutex> lock(entries_mutex); 103 std::lock_guard lock{entries_mutex};
102 104
103 LOG_DEBUG(Common_Memory, "Unfreezing memory for address={:016X}", address); 105 LOG_DEBUG(Common_Memory, "Unfreezing memory for address={:016X}", address);
104 106
@@ -108,8 +110,8 @@ void Freezer::Unfreeze(VAddr address) {
108 entries.end()); 110 entries.end());
109} 111}
110 112
111bool Freezer::IsFrozen(VAddr address) { 113bool Freezer::IsFrozen(VAddr address) const {
112 std::lock_guard<std::recursive_mutex> lock(entries_mutex); 114 std::lock_guard lock{entries_mutex};
113 115
114 return std::find_if(entries.begin(), entries.end(), [&address](const Entry& entry) { 116 return std::find_if(entries.begin(), entries.end(), [&address](const Entry& entry) {
115 return entry.address == address; 117 return entry.address == address;
@@ -117,7 +119,7 @@ bool Freezer::IsFrozen(VAddr address) {
117} 119}
118 120
119void Freezer::SetFrozenValue(VAddr address, u64 value) { 121void Freezer::SetFrozenValue(VAddr address, u64 value) {
120 std::lock_guard<std::recursive_mutex> lock(entries_mutex); 122 std::lock_guard lock{entries_mutex};
121 123
122 const auto iter = std::find_if(entries.begin(), entries.end(), [&address](const Entry& entry) { 124 const auto iter = std::find_if(entries.begin(), entries.end(), [&address](const Entry& entry) {
123 return entry.address == address; 125 return entry.address == address;
@@ -135,8 +137,8 @@ void Freezer::SetFrozenValue(VAddr address, u64 value) {
135 iter->value = value; 137 iter->value = value;
136} 138}
137 139
138std::optional<Freezer::Entry> Freezer::GetEntry(VAddr address) { 140std::optional<Freezer::Entry> Freezer::GetEntry(VAddr address) const {
139 std::lock_guard<std::recursive_mutex> lock(entries_mutex); 141 std::lock_guard lock{entries_mutex};
140 142
141 const auto iter = std::find_if(entries.begin(), entries.end(), [&address](const Entry& entry) { 143 const auto iter = std::find_if(entries.begin(), entries.end(), [&address](const Entry& entry) {
142 return entry.address == address; 144 return entry.address == address;
@@ -149,19 +151,19 @@ std::optional<Freezer::Entry> Freezer::GetEntry(VAddr address) {
149 return *iter; 151 return *iter;
150} 152}
151 153
152std::vector<Freezer::Entry> Freezer::GetEntries() { 154std::vector<Freezer::Entry> Freezer::GetEntries() const {
153 std::lock_guard<std::recursive_mutex> lock(entries_mutex); 155 std::lock_guard lock{entries_mutex};
154 156
155 return entries; 157 return entries;
156} 158}
157 159
158void Freezer::FrameCallback(u64 userdata, s64 cycles_late) { 160void Freezer::FrameCallback(u64 userdata, s64 cycles_late) {
159 if (!active.load()) { 161 if (!IsActive()) {
160 LOG_DEBUG(Common_Memory, "Memory freezer has been deactivated, ending callback events."); 162 LOG_DEBUG(Common_Memory, "Memory freezer has been deactivated, ending callback events.");
161 return; 163 return;
162 } 164 }
163 165
164 std::lock_guard<std::recursive_mutex> lock(entries_mutex); 166 std::lock_guard lock{entries_mutex};
165 167
166 for (const auto& entry : entries) { 168 for (const auto& entry : entries) {
167 LOG_DEBUG(Common_Memory, 169 LOG_DEBUG(Common_Memory,
@@ -174,7 +176,7 @@ void Freezer::FrameCallback(u64 userdata, s64 cycles_late) {
174} 176}
175 177
176void Freezer::FillEntryReads() { 178void Freezer::FillEntryReads() {
177 std::lock_guard<std::recursive_mutex> lock(entries_mutex); 179 std::lock_guard lock{entries_mutex};
178 180
179 LOG_DEBUG(Common_Memory, "Updating memory freeze entries to current values."); 181 LOG_DEBUG(Common_Memory, "Updating memory freeze entries to current values.");
180 182
diff --git a/src/core/memory/freezer.h b/src/core/memory/freezer.h
index 3e271793e..b0c610039 100644
--- a/src/core/memory/freezer.h
+++ b/src/core/memory/freezer.h
@@ -4,14 +4,16 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <atomic>
8#include <mutex>
7#include <optional> 9#include <optional>
8#include <vector> 10#include <vector>
9#include "common/common_types.h" 11#include "common/common_types.h"
10#include "core/core_timing.h"
11 12
12namespace Core { 13namespace Core::Timing {
13class System; 14class CoreTiming;
14} // namespace Core 15struct EventType;
16} // namespace Core::Timing
15 17
16namespace Memory { 18namespace Memory {
17 19
@@ -20,27 +22,42 @@ class Freezer {
20public: 22public:
21 struct Entry { 23 struct Entry {
22 VAddr address; 24 VAddr address;
23 u8 width; 25 u32 width;
24 u64 value; 26 u64 value;
25 }; 27 };
26 28
27 Freezer(Core::Timing::CoreTiming& core_timing); 29 explicit Freezer(Core::Timing::CoreTiming& core_timing);
28 ~Freezer(); 30 ~Freezer();
29 31
32 // Enables or disables the entire memory freezer.
30 void SetActive(bool active); 33 void SetActive(bool active);
34
35 // Returns whether or not the freezer is active.
31 bool IsActive() const; 36 bool IsActive() const;
32 37
38 // Removes all entries from the freezer.
33 void Clear(); 39 void Clear();
34 40
35 u64 Freeze(VAddr address, u8 width); 41 // Freezes a value to its current memory address. The value the memory is kept at will be the
42 // value that is read during this function. Width can be 1, 2, 4, or 8 (in bytes).
43 u64 Freeze(VAddr address, u32 width);
44
45 // Unfreezes the memory value at address. If the address isn't frozen, this is a no-op.
36 void Unfreeze(VAddr address); 46 void Unfreeze(VAddr address);
37 47
38 bool IsFrozen(VAddr address); 48 // Returns whether or not the address is frozen.
49 bool IsFrozen(VAddr address) const;
50
51 // Sets the value that address should be frozen to. This doesn't change the width set by using
52 // Freeze(). If the value isn't frozen, this will not freeze it and is thus a no-op.
39 void SetFrozenValue(VAddr address, u64 value); 53 void SetFrozenValue(VAddr address, u64 value);
40 54
41 std::optional<Entry> GetEntry(VAddr address); 55 // Returns the entry corresponding to the address if the address is frozen, otherwise
56 // std::nullopt.
57 std::optional<Entry> GetEntry(VAddr address) const;
42 58
43 std::vector<Entry> GetEntries(); 59 // Returns all the entries in the freezer, an empty vector means nothing is frozen.
60 std::vector<Entry> GetEntries() const;
44 61
45private: 62private:
46 void FrameCallback(u64 userdata, s64 cycles_late); 63 void FrameCallback(u64 userdata, s64 cycles_late);
@@ -48,7 +65,7 @@ private:
48 65
49 std::atomic_bool active{false}; 66 std::atomic_bool active{false};
50 67
51 std::recursive_mutex entries_mutex; 68 mutable std::mutex entries_mutex;
52 std::vector<Entry> entries; 69 std::vector<Entry> entries;
53 70
54 Core::Timing::EventType* event; 71 Core::Timing::EventType* event;