mirror of
https://github.com/izzy2lost/dolphin.git
synced 2026-06-19 01:16:48 -07:00
Core: Update page table mappings incrementally
Removing and readding every page table mapping every time something changes in the page table is very slow. Instead, let's generate a diff and ask Memmap to update only the diff.
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <span>
|
||||
#include <tuple>
|
||||
|
||||
@@ -243,11 +244,7 @@ void MemoryManager::UpdateDBATMappings(const PowerPC::BatTable& dbat_table)
|
||||
}
|
||||
m_dbat_mapped_entries.clear();
|
||||
|
||||
for (auto& entry : m_page_table_mapped_entries)
|
||||
{
|
||||
m_arena.UnmapFromMemoryRegion(entry.mapped_pointer, entry.mapped_size);
|
||||
}
|
||||
m_page_table_mapped_entries.clear();
|
||||
RemoveAllPageTableMappings();
|
||||
|
||||
m_logical_page_mappings.fill(nullptr);
|
||||
|
||||
@@ -301,7 +298,7 @@ void MemoryManager::UpdateDBATMappings(const PowerPC::BatTable& dbat_table)
|
||||
intersection_start, mapped_size, logical_address);
|
||||
continue;
|
||||
}
|
||||
m_dbat_mapped_entries.push_back({mapped_pointer, mapped_size});
|
||||
m_dbat_mapped_entries.push_back({mapped_pointer, mapped_size, logical_address});
|
||||
}
|
||||
|
||||
m_logical_page_mappings[i] =
|
||||
@@ -312,18 +309,12 @@ void MemoryManager::UpdateDBATMappings(const PowerPC::BatTable& dbat_table)
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryManager::UpdatePageTableMappings(const std::map<u32, u32>& page_mappings)
|
||||
void MemoryManager::AddPageTableMappings(const std::map<u32, u32>& mappings)
|
||||
{
|
||||
if (!m_is_fastmem_arena_initialized || m_page_size > PowerPC::HW_PAGE_SIZE)
|
||||
return;
|
||||
|
||||
for (auto& entry : m_page_table_mapped_entries)
|
||||
{
|
||||
m_arena.UnmapFromMemoryRegion(entry.mapped_pointer, entry.mapped_size);
|
||||
}
|
||||
m_page_table_mapped_entries.clear();
|
||||
|
||||
for (const auto [logical_address, translated_address] : page_mappings)
|
||||
for (const auto [logical_address, translated_address] : mappings)
|
||||
{
|
||||
constexpr u32 logical_size = PowerPC::HW_PAGE_SIZE;
|
||||
for (const auto& physical_region : m_physical_regions)
|
||||
@@ -351,11 +342,36 @@ void MemoryManager::UpdatePageTableMappings(const std::map<u32, u32>& page_mappi
|
||||
intersection_start, mapped_size, logical_address);
|
||||
continue;
|
||||
}
|
||||
m_page_table_mapped_entries.push_back({mapped_pointer, mapped_size});
|
||||
m_page_table_mapped_entries.push_back({mapped_pointer, mapped_size, logical_address});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MemoryManager::RemovePageTableMappings(const std::set<u32>& mappings)
|
||||
{
|
||||
if (m_page_size > PowerPC::HW_PAGE_SIZE)
|
||||
return;
|
||||
|
||||
if (mappings.empty())
|
||||
return;
|
||||
|
||||
std::erase_if(m_page_table_mapped_entries, [this, &mappings](const LogicalMemoryView& entry) {
|
||||
const bool remove = mappings.contains(entry.logical_address);
|
||||
if (remove)
|
||||
m_arena.UnmapFromMemoryRegion(entry.mapped_pointer, entry.mapped_size);
|
||||
return remove;
|
||||
});
|
||||
}
|
||||
|
||||
void MemoryManager::RemoveAllPageTableMappings()
|
||||
{
|
||||
for (auto& entry : m_page_table_mapped_entries)
|
||||
{
|
||||
m_arena.UnmapFromMemoryRegion(entry.mapped_pointer, entry.mapped_size);
|
||||
}
|
||||
m_page_table_mapped_entries.clear();
|
||||
}
|
||||
|
||||
void MemoryManager::DoState(PointerWrap& p)
|
||||
{
|
||||
const u32 current_ram_size = GetRamSize();
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -55,6 +56,7 @@ struct LogicalMemoryView
|
||||
{
|
||||
void* mapped_pointer;
|
||||
u32 mapped_size;
|
||||
u32 logical_address;
|
||||
};
|
||||
|
||||
class MemoryManager
|
||||
@@ -101,7 +103,9 @@ public:
|
||||
void DoState(PointerWrap& p);
|
||||
|
||||
void UpdateDBATMappings(const PowerPC::BatTable& dbat_table);
|
||||
void UpdatePageTableMappings(const std::map<u32, u32>& page_mappings);
|
||||
void AddPageTableMappings(const std::map<u32, u32>& mappings);
|
||||
void RemovePageTableMappings(const std::set<u32>& mappings);
|
||||
void RemoveAllPageTableMappings();
|
||||
|
||||
void Clear();
|
||||
|
||||
|
||||
@@ -33,19 +33,19 @@ constexpr Arm64Gen::ARM64Reg DISPATCHER_PC = Arm64Gen::ARM64Reg::W26;
|
||||
PowerPC::PowerPCState, elem); \
|
||||
_Pragma("GCC diagnostic pop") \
|
||||
}())
|
||||
#else
|
||||
#define PPCSTATE_OFF(elem) (offsetof(PowerPC::PowerPCState, elem))
|
||||
#endif
|
||||
|
||||
#define PPCSTATE_OFF_ARRAY(elem, i) \
|
||||
(PPCSTATE_OFF(elem[0]) + sizeof(PowerPC::PowerPCState::elem[0]) * (i))
|
||||
#else
|
||||
#define PPCSTATE_OFF(elem) (offsetof(PowerPC::PowerPCState, elem))
|
||||
|
||||
#define PPCSTATE_OFF_ARRAY(elem, i) \
|
||||
(offsetof(PowerPC::PowerPCState, elem[0]) + sizeof(PowerPC::PowerPCState::elem[0]) * (i))
|
||||
#endif
|
||||
#define PPCSTATE_OFF_STD_ARRAY(elem, i) \
|
||||
(PPCSTATE_OFF(elem) + sizeof(PowerPC::PowerPCState::elem[0]) * (i))
|
||||
|
||||
#define PPCSTATE_OFF_GPR(i) PPCSTATE_OFF_ARRAY(gpr, i)
|
||||
#define PPCSTATE_OFF_CR(i) PPCSTATE_OFF_ARRAY(cr.fields, i)
|
||||
#define PPCSTATE_OFF_SR(i) PPCSTATE_OFF_ARRAY(sr, i)
|
||||
#define PPCSTATE_OFF_SR(i) PPCSTATE_OFF_STD_ARRAY(sr, i)
|
||||
#define PPCSTATE_OFF_SPR(i) PPCSTATE_OFF_ARRAY(spr, i)
|
||||
|
||||
static_assert(std::is_same_v<decltype(PowerPC::PowerPCState::ps[0]), PowerPC::PairedSingle&>);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,10 @@
|
||||
#include <cstddef>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/BitField.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
@@ -123,7 +126,7 @@ public:
|
||||
~MMU();
|
||||
|
||||
void Reset();
|
||||
void DoState(PointerWrap& p);
|
||||
void DoState(PointerWrap& p, bool sr_changed);
|
||||
|
||||
// Routines for debugger UI, cheats, etc. to access emulated memory from the
|
||||
// perspective of the CPU. Not for use by core emulation routines.
|
||||
@@ -301,6 +304,26 @@ private:
|
||||
explicit EffectiveAddress(u32 address) : Hex{address} {}
|
||||
};
|
||||
|
||||
union PageMapping
|
||||
{
|
||||
// A small priority number wins over a larger priority number.
|
||||
BitField<0, 11, u32> priority;
|
||||
// Whether we're allowed to create a host mapping for this mapping.
|
||||
BitField<11, 1, u32> host_mapping;
|
||||
// The physical address of the page.
|
||||
BitField<12, 20, u32> RPN;
|
||||
|
||||
u32 Hex = 0;
|
||||
|
||||
PageMapping() = default;
|
||||
PageMapping(u32 RPN_, bool host_mapping_, u32 priority_)
|
||||
{
|
||||
RPN = RPN_;
|
||||
host_mapping = host_mapping_;
|
||||
priority = priority_;
|
||||
}
|
||||
};
|
||||
|
||||
template <const XCheckTLBFlag flag>
|
||||
TranslateAddressResult TranslateAddress(u32 address);
|
||||
|
||||
@@ -312,6 +335,10 @@ private:
|
||||
|
||||
void Memcheck(u32 address, u64 var, bool write, size_t size);
|
||||
|
||||
void ClearPageTable();
|
||||
void ReloadPageTable();
|
||||
void PageTableUpdated(std::span<u8> page_table);
|
||||
|
||||
void UpdateBATs(BatTable& bat_table, u32 base_spr);
|
||||
void UpdateFakeMMUBat(BatTable& bat_table, u32 start_addr);
|
||||
|
||||
@@ -329,9 +356,18 @@ private:
|
||||
PowerPC::PowerPCState& m_ppc_state;
|
||||
|
||||
// STATE_TO_SAVE
|
||||
std::map<u32, u32> m_page_mappings;
|
||||
std::vector<u8> m_page_table;
|
||||
// END STATE_TO_SAVE
|
||||
|
||||
// This keeps track of all valid page table mappings in m_page_table.
|
||||
// The key is the logical address.
|
||||
std::map<u32, PageMapping> m_page_mappings;
|
||||
|
||||
// These are kept around just for their memory allocations. They are always cleared before use.
|
||||
std::vector<u8> m_temp_page_table;
|
||||
std::set<u32> m_removed_mappings;
|
||||
std::map<u32, u32> m_added_mappings;
|
||||
|
||||
BatTable m_ibat_table;
|
||||
BatTable m_dbat_table;
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "Core/PowerPC/PowerPC.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <bit>
|
||||
#include <cstring>
|
||||
|
||||
@@ -78,6 +79,8 @@ void PowerPCManager::DoState(PointerWrap& p)
|
||||
// *((u64 *)&TL(m_ppc_state)) = SystemTimers::GetFakeTimeBase(); //works since we are little
|
||||
// endian and TL comes first :)
|
||||
|
||||
const std::array<u32, 16> old_sr = m_ppc_state.sr;
|
||||
|
||||
p.DoArray(m_ppc_state.gpr);
|
||||
p.Do(m_ppc_state.pc);
|
||||
p.Do(m_ppc_state.npc);
|
||||
@@ -105,10 +108,10 @@ void PowerPCManager::DoState(PointerWrap& p)
|
||||
m_ppc_state.dCache.DoState(memory, p);
|
||||
|
||||
auto& mmu = m_system.GetMMU();
|
||||
mmu.DoState(p);
|
||||
|
||||
if (p.IsReadMode())
|
||||
{
|
||||
mmu.DoState(p, old_sr != m_ppc_state.sr);
|
||||
|
||||
if (!m_ppc_state.m_enable_dcache)
|
||||
{
|
||||
INFO_LOG_FMT(POWERPC, "Flushing data cache");
|
||||
@@ -121,6 +124,10 @@ void PowerPCManager::DoState(PointerWrap& p)
|
||||
mmu.IBATUpdated();
|
||||
mmu.DBATUpdated();
|
||||
}
|
||||
else
|
||||
{
|
||||
mmu.DoState(p, false);
|
||||
}
|
||||
|
||||
// SystemTimers::DecrementerSet();
|
||||
// SystemTimers::TimeBaseSet();
|
||||
|
||||
@@ -175,7 +175,7 @@ struct PowerPCState
|
||||
alignas(16) PairedSingle ps[32];
|
||||
#endif
|
||||
|
||||
u32 sr[16]{}; // Segment registers.
|
||||
std::array<u32, 16> sr{}; // Segment registers.
|
||||
|
||||
// special purpose registers - controls quantizers, DMA, and lots of other misc extensions.
|
||||
// also for power management, but we don't care about that.
|
||||
|
||||
Reference in New Issue
Block a user