diff --git a/src/core/arm/cache/cache.cpp b/src/core/arm/cache/cache.cpp index 25af75289..678b16784 100644 --- a/src/core/arm/cache/cache.cpp +++ b/src/core/arm/cache/cache.cpp @@ -7,21 +7,53 @@ namespace Cache { +static std::list caches; + +void RegisterCode(u32 address, u32 size) { + for (auto const& cache : caches) { + cache->OnCodeLoad(address, size); + } +} + +void UnregisterCode(u32 address, u32 size) { + for (auto const& cache : caches) { + cache->OnCodeUnload(address, size); + } +} + +void ClearCache() { + for (auto const& cache : caches) { + cache->Clear(); + } +} + +static void RegisterCache(CacheBase* cache) { + caches.push_back(cache); +} + +static void UnregisterCache(CacheBase* cache) { + caches.erase(std::remove(caches.begin(), caches.end(), cache), caches.end()); +} + CacheBase::CacheBase(bool index_mode, OnClearCb clearcb) : index_mode(index_mode) { page_pointers.fill(nullptr); Clear(); SetClearCallback(clearcb); - g_cachemanager.RegisterCache(this); + RegisterCache(this); } CacheBase::~CacheBase() { - g_cachemanager.UnregisterCache(this); + UnregisterCache(this); } void CacheBase::Clear() { - if (OnClearCallback != nullptr) OnClearCallback(); + if (OnClearCallback != nullptr) { + OnClearCallback(); + } - for (auto& cache : ptr_caches) cache.data.assign(cache.data.size(), nullptr); + for (auto& cache : ptr_caches) { + cache.data.assign(cache.data.size(), nullptr); + } if (index_mode) { blocks_pc.assign(MAX_BLOCKS, INVALID_BLOCK); @@ -30,18 +62,25 @@ void CacheBase::Clear() { } bool CacheBase::RemoveBlock(u32 pc) { - u8** ptr = page_pointers[pc >> Memory::PAGE_BITS]; + void** ptr = page_pointers[pc >> Memory::PAGE_BITS]; if (ptr != nullptr) { ptr = &ptr[pc & Memory::PAGE_MASK]; - if (*ptr == nullptr) return false; + + if (*ptr == nullptr) { + return false; + } if (index_mode) { const u32 id = pointer_to_id(*ptr); ASSERT(blocks_pc[id] == pc); blocks_pc[id] = INVALID_BLOCK; - if (id < next_block) next_block = id; - while (num_blocks > 0 && blocks_pc[num_blocks - 1] == INVALID_BLOCK) --num_blocks; + if (id < next_block) { + next_block = id; + } + while (num_blocks > 0 && blocks_pc[num_blocks - 1] == INVALID_BLOCK) { + --num_blocks; + } } *ptr = nullptr; return true; @@ -52,17 +91,24 @@ bool CacheBase::RemoveBlock(u32 pc) { bool CacheBase::RemoveRange(u32 start, u32 end) { bool result = false; for (auto& cache : ptr_caches) { - for (int i = std::max(start, cache.addr); i < std::min(end, cache.addr_end); ++i) { - u8** ptr = &cache.data[i - cache.addr]; - if (*ptr == nullptr) continue; + for (u32 i = std::max(start, cache.addr); i < std::min(end, cache.addr_end); ++i) { + void** ptr = &cache.data[i - cache.addr]; + + if (*ptr == nullptr) { + continue; + } if (index_mode) { const u32 id = pointer_to_id(*ptr); ASSERT(blocks_pc[id] == i); blocks_pc[id] = INVALID_BLOCK; - if (id < next_block) next_block = id; - while (num_blocks > 0 && blocks_pc[num_blocks - 1] == INVALID_BLOCK) --num_blocks; + if (id < next_block) { + next_block = id; + } + while (num_blocks > 0 && blocks_pc[num_blocks - 1] == INVALID_BLOCK) { + --num_blocks; + } } *ptr = nullptr; result = true; @@ -75,23 +121,29 @@ void CacheBase::OnCodeLoad(u32 address, u32 size) { const u32 end = address + size; // Check there is no overlapping - for (auto const& cache : ptr_caches) ASSERT((address >= cache.addr_end) || (end <= cache.addr)); + for (auto const& cache : ptr_caches) { + ASSERT((address >= cache.addr_end) || (end <= cache.addr)); + } ASSERT((address & Memory::PAGE_MASK) == 0 && (size & Memory::PAGE_MASK) == 0); BlockPtrCache cache{ address, address + size }; cache.data.assign(size, nullptr); - for (u32 i = address; i < end; i += Memory::PAGE_SIZE) { page_pointers[i >> Memory::PAGE_BITS] = &cache.data[i - address]; } + for (u32 i = address; i < end; i += Memory::PAGE_SIZE) { + page_pointers[i >> Memory::PAGE_BITS] = &cache.data[i - address]; + } ptr_caches.emplace_back(std::move(cache)); } void CacheBase::OnCodeUnload(u32 address, u32 size) { ptr_caches.erase(std::remove_if(ptr_caches.begin(), ptr_caches.end(), - [&](auto const& cache) { + [&, this](auto const& cache) { if ((address < cache.addr_end) && (address + size > cache.addr)) { - RemoveRange(cache.addr, cache.addr_end); - for (u32 i = cache.addr; i < cache.addr_end; i += Memory::PAGE_SIZE) { page_pointers[i >> Memory::PAGE_BITS] = nullptr; } + this->RemoveRange(cache.addr, cache.addr_end); + for (u32 i = cache.addr; i < cache.addr_end; i += Memory::PAGE_SIZE) { + page_pointers[i >> Memory::PAGE_BITS] = nullptr; + } return true; } return false; @@ -99,55 +151,39 @@ void CacheBase::OnCodeUnload(u32 address, u32 size) { ptr_caches.cend()); } -u8*& CacheBase::GetNewPtr(u32 pc) { +void*& CacheBase::GetNewPtr(u32 pc) { DEBUG_ASSERT(!index_mode || next_block == MAX_BLOCKS || ((next_block < MAX_BLOCKS) && blocks_pc[next_block] == INVALID_BLOCK)); DEBUG_ASSERT(GetPtr(pc) == nullptr); - u8** page_ptr = page_pointers[pc >> Memory::PAGE_BITS]; + void** page_ptr = page_pointers[pc >> Memory::PAGE_BITS]; if (page_ptr == nullptr) { // pc isnt within mapped code OnCodeLoad(pc & ~Memory::PAGE_MASK, Memory::PAGE_SIZE); page_ptr = page_pointers[pc >> Memory::PAGE_BITS]; } - u8** block_ptr = &page_ptr[pc & Memory::PAGE_MASK]; + void** block_ptr = &page_ptr[pc & Memory::PAGE_MASK]; DEBUG_ASSERT(*block_ptr == nullptr); if (index_mode) { - if (next_block == MAX_BLOCKS) Clear(); + if (next_block == MAX_BLOCKS) { + Clear(); + } blocks_pc[next_block] = pc; *block_ptr = id_to_pointer(next_block); - do ++next_block; while (next_block <= num_blocks && blocks_pc[next_block] != INVALID_BLOCK); - if (next_block > num_blocks) num_blocks++; + do { + ++next_block; + } while (next_block <= num_blocks && blocks_pc[next_block] != INVALID_BLOCK); + + if (next_block > num_blocks) { + num_blocks++; + } } return *block_ptr; } - -void CacheManager::RegisterCode(u32 address, u32 size) const { - for (auto const& cache : caches) cache->OnCodeLoad(address, size); -} - -void CacheManager::UnregisterCode(u32 address, u32 size) const { - for (auto const& cache : caches) cache->OnCodeUnload(address, size); -} - -void CacheManager::ClearCache() const { - for (auto const& cache : caches) cache->Clear(); -} - -void CacheManager::RegisterCache(CacheBase* cache) { - caches.push_back(cache); -} - -void CacheManager::UnregisterCache(CacheBase* cache) { - caches.erase(std::remove(caches.begin(), caches.end(), cache), caches.end()); -} - -CacheManager g_cachemanager; - } diff --git a/src/core/arm/cache/cache.h b/src/core/arm/cache/cache.h index 924396a70..e6578a6bc 100644 --- a/src/core/arm/cache/cache.h +++ b/src/core/arm/cache/cache.h @@ -17,6 +17,14 @@ namespace Cache { +/// Loaders call these when mapping/unmapping code +void RegisterCode(u32 address, u32 size); +void UnregisterCode(u32 address, u32 size = 1); + +/// Clear every cache +void ClearCache(); + + using OnClearCb = std::function; const u32 MAX_BLOCKS = 0x40000; @@ -25,7 +33,7 @@ const u32 INVALID_BLOCK = 0xFFFFFFFF; struct BlockPtrCache { u32 addr; u32 addr_end; - std::vector data; + std::vector data; }; class CacheBase { @@ -35,7 +43,9 @@ protected: public: /// Called when the cache needs to reset or Clear() is called - void SetClearCallback(OnClearCb cb) { OnClearCallback = cb; } + void SetClearCallback(OnClearCb cb) { + OnClearCallback = cb; + } /// Clear and call clear callback void Clear(); @@ -47,25 +57,25 @@ public: void OnCodeUnload(u32 address, u32 size); protected: - u8* GetPtr(u32 pc) const { - u8** ptr = page_pointers[pc >> Memory::PAGE_BITS]; + void* GetPtr(u32 pc) const { + void** ptr = page_pointers[pc >> Memory::PAGE_BITS]; if (ptr != nullptr) { DEBUG_ASSERT(!index_mode || blocks_pc[pointer_to_id(ptr[pc & Memory::PAGE_MASK])] == pc); return ptr[pc & Memory::PAGE_MASK]; } return nullptr; } - u8*& GetNewPtr(u32 pc); + void*& GetNewPtr(u32 pc); - std::function id_to_pointer; - std::function pointer_to_id; + std::function id_to_pointer; + std::function pointer_to_id; private: bool index_mode; OnClearCb OnClearCallback = nullptr; std::vector ptr_caches; - std::array page_pointers; + std::array page_pointers; std::vector blocks_pc; u32 next_block = 0; @@ -82,10 +92,14 @@ public: ~PtrCache() {} /// Get cached pointer for PC - T FindPtr(u32 pc) { return reinterpret_cast(GetPtr(pc)); } + T GetPtr(u32 pc) { + return reinterpret_cast(CacheBase::GetPtr(pc)); + } /// Get reference of pointer for PC - T& GetNewPtr(u32 pc) { return reinterpret_cast(CacheBase::GetNewPtr(pc)); } + T& GetNewPtr(u32 pc) { + return reinterpret_cast(CacheBase::GetNewPtr(pc)); + } }; /// Index based cache @@ -93,45 +107,30 @@ template class Cache final : public CacheBase { public: explicit Cache(OnClearCb clearcb = nullptr) : CacheBase(true, clearcb) { - id_to_pointer = [this](u32 id) -> u8* { - return reinterpret_cast(&blocks[id]); + id_to_pointer = [this](u32 id) -> void* { + return &blocks[id]; }; - pointer_to_id = [this](u8* ptr) -> u32 { - return static_cast(reinterpret_cast(ptr) - &blocks[0]); + pointer_to_id = [this](void* ptr) -> u32 { + return static_cast(std::distance(blocks.begin(), + std::find_if(blocks.begin(), blocks.end(), [&](auto const& block) { + return (reinterpret_cast(ptr) == &block) ? true : false; + }))); }; } ~Cache() {} /// Get block cached for PC - T* FindBlock(u32 pc) { return reinterpret_cast(GetPtr(pc)); } + T* GetBlock(u32 pc) { + return reinterpret_cast(GetPtr(pc)); + } /// Allocate block for PC - T& GetNewBlock(u32 pc) { return *reinterpret_cast(GetNewPtr(pc)); } + T& GetNewBlock(u32 pc) { + return *reinterpret_cast(GetNewPtr(pc)); + } private: std::array blocks; }; -class CacheManager { -public: - CacheManager() {} - ~CacheManager() {} - - /// Loaders call these when mapping/unmapping code - void RegisterCode(u32 address, u32 size) const; - void UnregisterCode(u32 address, u32 size = 1) const; - - /// Clear every cache - void ClearCache() const; - -private: - std::list caches; - -public: - void RegisterCache(CacheBase* cache); - void UnregisterCache(CacheBase* cache); -}; - -extern CacheManager g_cachemanager; - } diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index 99cf5dfee..1aea759de 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp @@ -3893,10 +3893,12 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { cpu->Reg[15] &= 0xfffffffc; //clear cache if we dont have more than 10kb of buffer remaining - if ((top + (10 * 1024)) >= CACHE_BUFFER_SIZE) instr_cache.Clear(); + if ((top + (10 * 1024)) >= CACHE_BUFFER_SIZE) { + instr_cache.Clear(); + } // Find the cached instruction cream, otherwise translate it... - ptr = instr_cache.FindPtr(cpu->Reg[15]); + ptr = instr_cache.GetPtr(cpu->Reg[15]); if (ptr == nullptr) { ptr = instr_cache.GetNewPtr(cpu->Reg[15]) = reinterpret_cast(&inst_buf[top]); if (cpu->NumInstrsToExecute != 1) { diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 1e1e459d9..4ce6f9891 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -122,8 +122,8 @@ void Process::Run(s32 main_thread_priority, u32 stack_size) { MapSegment(codeset->data, VMAPermission::ReadWrite, MemoryState::Private); // Map cache - Cache::g_cachemanager.UnregisterCode(0, 0xFFFFFFFF); - Cache::g_cachemanager.RegisterCode(codeset->code.addr, codeset->code.size); + Cache::UnregisterCode(0, 0xFFFFFFFF); + Cache::RegisterCode(codeset->code.addr, codeset->code.size); // Allocate and map stack vm_manager.MapMemoryBlock(Memory::HEAP_VADDR_END - stack_size,