|
|
|
@ -4,6 +4,7 @@ |
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
#include <cstring>
|
|
|
|
#include <mutex>
|
|
|
|
#include <optional>
|
|
|
|
#include <utility>
|
|
|
|
|
|
|
|
@ -497,7 +498,21 @@ struct Memory::Impl { |
|
|
|
return CopyBlock(*system.CurrentProcess(), dest_addr, src_addr, size); |
|
|
|
} |
|
|
|
|
|
|
|
struct PageEntry { |
|
|
|
u8* const pointer; |
|
|
|
const Common::PageType attribute; |
|
|
|
}; |
|
|
|
|
|
|
|
PageEntry SafePageEntry(std::size_t base) const { |
|
|
|
std::lock_guard lock{rasterizer_cache_guard}; |
|
|
|
return { |
|
|
|
.pointer = current_page_table->pointers[base], |
|
|
|
.attribute = current_page_table->attributes[base], |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) { |
|
|
|
std::lock_guard lock{rasterizer_cache_guard}; |
|
|
|
if (vaddr == 0) { |
|
|
|
return; |
|
|
|
} |
|
|
|
@ -630,16 +645,22 @@ struct Memory::Impl { |
|
|
|
*/ |
|
|
|
template <typename T> |
|
|
|
T Read(const VAddr vaddr) { |
|
|
|
const u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; |
|
|
|
if (page_pointer != nullptr) { |
|
|
|
// NOTE: Avoid adding any extra logic to this fast-path block
|
|
|
|
// Avoid adding any extra logic to this fast-path block
|
|
|
|
if (const u8* const pointer = current_page_table->pointers[vaddr >> PAGE_BITS]) { |
|
|
|
T value; |
|
|
|
std::memcpy(&value, &page_pointer[vaddr], sizeof(T)); |
|
|
|
std::memcpy(&value, &pointer[vaddr], sizeof(T)); |
|
|
|
return value; |
|
|
|
} |
|
|
|
|
|
|
|
const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; |
|
|
|
switch (type) { |
|
|
|
// Otherwise, we need to grab the page with a lock, in case it is currently being modified
|
|
|
|
const auto entry = SafePageEntry(vaddr >> PAGE_BITS); |
|
|
|
if (entry.pointer) { |
|
|
|
T value; |
|
|
|
std::memcpy(&value, &entry.pointer[vaddr], sizeof(T)); |
|
|
|
return value; |
|
|
|
} |
|
|
|
|
|
|
|
switch (entry.attribute) { |
|
|
|
case Common::PageType::Unmapped: |
|
|
|
LOG_ERROR(HW_Memory, "Unmapped Read{} @ 0x{:08X}", sizeof(T) * 8, vaddr); |
|
|
|
return 0; |
|
|
|
@ -670,15 +691,21 @@ struct Memory::Impl { |
|
|
|
*/ |
|
|
|
template <typename T> |
|
|
|
void Write(const VAddr vaddr, const T data) { |
|
|
|
u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; |
|
|
|
if (page_pointer != nullptr) { |
|
|
|
// NOTE: Avoid adding any extra logic to this fast-path block
|
|
|
|
std::memcpy(&page_pointer[vaddr], &data, sizeof(T)); |
|
|
|
// Avoid adding any extra logic to this fast-path block
|
|
|
|
if (u8* const pointer = current_page_table->pointers[vaddr >> PAGE_BITS]) { |
|
|
|
std::memcpy(&pointer[vaddr], &data, sizeof(T)); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
const Common::PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; |
|
|
|
switch (type) { |
|
|
|
// Otherwise, we need to grab the page with a lock, in case it is currently being modified
|
|
|
|
const auto entry = SafePageEntry(vaddr >> PAGE_BITS); |
|
|
|
if (entry.pointer) { |
|
|
|
// Memory was mapped, we are done
|
|
|
|
std::memcpy(&entry.pointer[vaddr], &data, sizeof(T)); |
|
|
|
return; |
|
|
|
} |
|
|
|
|
|
|
|
switch (entry.attribute) { |
|
|
|
case Common::PageType::Unmapped: |
|
|
|
LOG_ERROR(HW_Memory, "Unmapped Write{} 0x{:08X} @ 0x{:016X}", sizeof(data) * 8, |
|
|
|
static_cast<u32>(data), vaddr); |
|
|
|
@ -756,6 +783,7 @@ struct Memory::Impl { |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
mutable std::mutex rasterizer_cache_guard; |
|
|
|
Common::PageTable* current_page_table = nullptr; |
|
|
|
Core::System& system; |
|
|
|
}; |
|
|
|
|