| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  | // Copyright 2019 yuzu Emulator Project
 | 
					
						
							|  |  |  | // Licensed under GPLv2 or any later version
 | 
					
						
							|  |  |  | // Refer to the license.txt file included.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "common/assert.h"
 | 
					
						
							| 
									
										
										
										
											2019-05-30 16:57:23 -04:00
										 |  |  | #include "common/logging/log.h"
 | 
					
						
							| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  | #include "core/core.h"
 | 
					
						
							| 
									
										
										
										
											2019-05-30 16:57:23 -04:00
										 |  |  | #include "core/core_timing.h"
 | 
					
						
							| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  | #include "core/core_timing_util.h"
 | 
					
						
							| 
									
										
										
										
											2020-02-11 19:56:24 -04:00
										 |  |  | #include "core/hardware_properties.h"
 | 
					
						
							| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  | #include "core/memory.h"
 | 
					
						
							| 
									
										
										
										
											2019-06-07 11:11:11 -04:00
										 |  |  | #include "core/tools/freezer.h"
 | 
					
						
							| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-07 11:11:11 -04:00
										 |  |  | namespace Tools { | 
					
						
							| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  | namespace { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-15 18:30:06 -04:00
										 |  |  | constexpr auto memory_freezer_ns = std::chrono::nanoseconds{1000000000 / 60}; | 
					
						
							| 
									
										
										
										
											2019-05-30 16:57:23 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-31 15:10:44 -04:00
										 |  |  | u64 MemoryReadWidth(Core::Memory::Memory& memory, u32 width, VAddr addr) { | 
					
						
							| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  |     switch (width) { | 
					
						
							|  |  |  |     case 1: | 
					
						
							| 
									
										
										
										
											2019-11-26 16:29:34 -05:00
										 |  |  |         return memory.Read8(addr); | 
					
						
							| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  |     case 2: | 
					
						
							| 
									
										
										
										
											2019-11-26 16:29:34 -05:00
										 |  |  |         return memory.Read16(addr); | 
					
						
							| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  |     case 4: | 
					
						
							| 
									
										
										
										
											2019-11-26 16:29:34 -05:00
										 |  |  |         return memory.Read32(addr); | 
					
						
							| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  |     case 8: | 
					
						
							| 
									
										
										
										
											2019-11-26 16:29:34 -05:00
										 |  |  |         return memory.Read64(addr); | 
					
						
							| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  |     default: | 
					
						
							|  |  |  |         UNREACHABLE(); | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-31 15:10:44 -04:00
										 |  |  | void MemoryWriteWidth(Core::Memory::Memory& memory, u32 width, VAddr addr, u64 value) { | 
					
						
							| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  |     switch (width) { | 
					
						
							|  |  |  |     case 1: | 
					
						
							| 
									
										
										
										
											2019-11-26 17:39:57 -05:00
										 |  |  |         memory.Write8(addr, static_cast<u8>(value)); | 
					
						
							| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  |         break; | 
					
						
							|  |  |  |     case 2: | 
					
						
							| 
									
										
										
										
											2019-11-26 17:39:57 -05:00
										 |  |  |         memory.Write16(addr, static_cast<u16>(value)); | 
					
						
							| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  |         break; | 
					
						
							|  |  |  |     case 4: | 
					
						
							| 
									
										
										
										
											2019-11-26 17:39:57 -05:00
										 |  |  |         memory.Write32(addr, static_cast<u32>(value)); | 
					
						
							| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  |         break; | 
					
						
							|  |  |  |     case 8: | 
					
						
							| 
									
										
										
										
											2019-11-26 17:39:57 -05:00
										 |  |  |         memory.Write64(addr, value); | 
					
						
							| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  |         break; | 
					
						
							|  |  |  |     default: | 
					
						
							|  |  |  |         UNREACHABLE(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } // Anonymous namespace
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-31 15:10:44 -04:00
										 |  |  | Freezer::Freezer(Core::Timing::CoreTiming& core_timing_, Core::Memory::Memory& memory_) | 
					
						
							| 
									
										
										
										
											2019-11-26 14:10:49 -05:00
										 |  |  |     : core_timing{core_timing_}, memory{memory_} { | 
					
						
							| 
									
										
										
										
											2020-07-27 19:00:41 -04:00
										 |  |  |     event = Core::Timing::CreateEvent( | 
					
						
							|  |  |  |         "MemoryFreezer::FrameCallback", | 
					
						
							|  |  |  |         [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { | 
					
						
							|  |  |  |             FrameCallback(user_data, ns_late); | 
					
						
							|  |  |  |         }); | 
					
						
							| 
									
										
										
										
											2020-07-15 18:30:06 -04:00
										 |  |  |     core_timing.ScheduleEvent(memory_freezer_ns, event); | 
					
						
							| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Freezer::~Freezer() { | 
					
						
							|  |  |  |     core_timing.UnscheduleEvent(event, 0); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Freezer::SetActive(bool active) { | 
					
						
							|  |  |  |     if (!this->active.exchange(active)) { | 
					
						
							|  |  |  |         FillEntryReads(); | 
					
						
							| 
									
										
										
										
											2020-07-15 18:30:06 -04:00
										 |  |  |         core_timing.ScheduleEvent(memory_freezer_ns, event); | 
					
						
							| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  |         LOG_DEBUG(Common_Memory, "Memory freezer activated!"); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         LOG_DEBUG(Common_Memory, "Memory freezer deactivated!"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool Freezer::IsActive() const { | 
					
						
							| 
									
										
										
										
											2019-05-30 16:57:23 -04:00
										 |  |  |     return active.load(std::memory_order_relaxed); | 
					
						
							| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Freezer::Clear() { | 
					
						
							| 
									
										
										
										
											2019-05-30 16:57:23 -04:00
										 |  |  |     std::lock_guard lock{entries_mutex}; | 
					
						
							| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     LOG_DEBUG(Common_Memory, "Clearing all frozen memory values."); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     entries.clear(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-30 16:57:23 -04:00
										 |  |  | u64 Freezer::Freeze(VAddr address, u32 width) { | 
					
						
							|  |  |  |     std::lock_guard lock{entries_mutex}; | 
					
						
							| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-26 14:10:49 -05:00
										 |  |  |     const auto current_value = MemoryReadWidth(memory, width, address); | 
					
						
							| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  |     entries.push_back({address, width, current_value}); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     LOG_DEBUG(Common_Memory, | 
					
						
							|  |  |  |               "Freezing memory for address={:016X}, width={:02X}, current_value={:016X}", address, | 
					
						
							|  |  |  |               width, current_value); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return current_value; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Freezer::Unfreeze(VAddr address) { | 
					
						
							| 
									
										
										
										
											2019-05-30 16:57:23 -04:00
										 |  |  |     std::lock_guard lock{entries_mutex}; | 
					
						
							| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     LOG_DEBUG(Common_Memory, "Unfreezing memory for address={:016X}", address); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     entries.erase( | 
					
						
							|  |  |  |         std::remove_if(entries.begin(), entries.end(), | 
					
						
							|  |  |  |                        [&address](const Entry& entry) { return entry.address == address; }), | 
					
						
							|  |  |  |         entries.end()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-30 16:57:23 -04:00
										 |  |  | bool Freezer::IsFrozen(VAddr address) const { | 
					
						
							|  |  |  |     std::lock_guard lock{entries_mutex}; | 
					
						
							| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return std::find_if(entries.begin(), entries.end(), [&address](const Entry& entry) { | 
					
						
							|  |  |  |                return entry.address == address; | 
					
						
							|  |  |  |            }) != entries.end(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Freezer::SetFrozenValue(VAddr address, u64 value) { | 
					
						
							| 
									
										
										
										
											2019-05-30 16:57:23 -04:00
										 |  |  |     std::lock_guard lock{entries_mutex}; | 
					
						
							| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const auto iter = std::find_if(entries.begin(), entries.end(), [&address](const Entry& entry) { | 
					
						
							|  |  |  |         return entry.address == address; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (iter == entries.end()) { | 
					
						
							|  |  |  |         LOG_ERROR(Common_Memory, | 
					
						
							|  |  |  |                   "Tried to set freeze value for address={:016X} that is not frozen!", address); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     LOG_DEBUG(Common_Memory, | 
					
						
							|  |  |  |               "Manually overridden freeze value for address={:016X}, width={:02X} to value={:016X}", | 
					
						
							|  |  |  |               iter->address, iter->width, value); | 
					
						
							|  |  |  |     iter->value = value; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-30 16:57:23 -04:00
										 |  |  | std::optional<Freezer::Entry> Freezer::GetEntry(VAddr address) const { | 
					
						
							|  |  |  |     std::lock_guard lock{entries_mutex}; | 
					
						
							| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const auto iter = std::find_if(entries.begin(), entries.end(), [&address](const Entry& entry) { | 
					
						
							|  |  |  |         return entry.address == address; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (iter == entries.end()) { | 
					
						
							|  |  |  |         return std::nullopt; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return *iter; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-30 16:57:23 -04:00
										 |  |  | std::vector<Freezer::Entry> Freezer::GetEntries() const { | 
					
						
							|  |  |  |     std::lock_guard lock{entries_mutex}; | 
					
						
							| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return entries; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-27 19:00:41 -04:00
										 |  |  | void Freezer::FrameCallback(std::uintptr_t, std::chrono::nanoseconds ns_late) { | 
					
						
							| 
									
										
										
										
											2019-05-30 16:57:23 -04:00
										 |  |  |     if (!IsActive()) { | 
					
						
							| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  |         LOG_DEBUG(Common_Memory, "Memory freezer has been deactivated, ending callback events."); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-30 16:57:23 -04:00
										 |  |  |     std::lock_guard lock{entries_mutex}; | 
					
						
							| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for (const auto& entry : entries) { | 
					
						
							|  |  |  |         LOG_DEBUG(Common_Memory, | 
					
						
							|  |  |  |                   "Enforcing memory freeze at address={:016X}, value={:016X}, width={:02X}", | 
					
						
							|  |  |  |                   entry.address, entry.value, entry.width); | 
					
						
							| 
									
										
										
										
											2019-11-26 14:10:49 -05:00
										 |  |  |         MemoryWriteWidth(memory, entry.width, entry.address, entry.value); | 
					
						
							| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-15 19:14:21 -04:00
										 |  |  |     core_timing.ScheduleEvent(memory_freezer_ns - ns_late, event); | 
					
						
							| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void Freezer::FillEntryReads() { | 
					
						
							| 
									
										
										
										
											2019-05-30 16:57:23 -04:00
										 |  |  |     std::lock_guard lock{entries_mutex}; | 
					
						
							| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     LOG_DEBUG(Common_Memory, "Updating memory freeze entries to current values."); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (auto& entry : entries) { | 
					
						
							| 
									
										
										
										
											2019-11-26 14:10:49 -05:00
										 |  |  |         entry.value = MemoryReadWidth(memory, entry.width, entry.address); | 
					
						
							| 
									
										
										
										
											2019-05-30 08:52:20 -04:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-07 11:11:11 -04:00
										 |  |  | } // namespace Tools
 |