From a0d46ca24e6afdbe03247e5f9b5bbb3450734d3e Mon Sep 17 00:00:00 2001 From: SimoneN64 Date: Tue, 15 Oct 2024 10:56:47 +0200 Subject: [PATCH] Cached TLB entries --- src/backend/core/registers/Cop0.cpp | 39 +++++++++++-------- src/backend/core/registers/Cop0.hpp | 27 +++++++++---- .../core/registers/cop/cop0instructions.cpp | 11 ++++++ 3 files changed, 54 insertions(+), 23 deletions(-) diff --git a/src/backend/core/registers/Cop0.cpp b/src/backend/core/registers/Cop0.cpp index 1b12f07e..ba0d4921 100644 --- a/src/backend/core/registers/Cop0.cpp +++ b/src/backend/core/registers/Cop0.cpp @@ -293,7 +293,13 @@ static FORCE_INLINE u64 getVPN(const u64 addr, const u64 pageMask) { return vpn & ~mask; } -TLBEntry *Cop0::TLBTryMatch(const u64 vaddr, int *match) const { +TLBEntry *Cop0::TLBTryMatch(const u64 vaddr, int* index) { + if (tlbCache.contains(vaddr)) { + if (index) + *index = tlbCache[vaddr].index; + return tlbCache[vaddr].entry; + } + for (int i = 0; i < 32; i++) { if (TLBEntry *entry = ®s.cop0.tlb[i]; entry->initialized) { const u64 entry_vpn = getVPN(entry->entryHi.raw, entry->pageMask.raw); @@ -303,9 +309,10 @@ TLBEntry *Cop0::TLBTryMatch(const u64 vaddr, int *match) const { if (const bool asid_match = entry->global || regs.cop0.entryHi.asid == entry->entryHi.asid; vpn_match && asid_match) { - if (match) { - *match = i; - } + tlbCache[vaddr].entry = entry; + tlbCache[vaddr].index = i; + if (index) + *index = i; return entry; } } @@ -314,8 +321,8 @@ TLBEntry *Cop0::TLBTryMatch(const u64 vaddr, int *match) const { return nullptr; } -bool Cop0::ProbeTLB(const TLBAccessType accessType, const u64 vaddr, u32 &paddr, int *match) const { - const TLBEntry *entry = TLBTryMatch(vaddr, match); +bool Cop0::ProbeTLB(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) { + const TLBEntry *entry = TLBTryMatch(vaddr, nullptr); if (!entry) { regs.cop0.tlbError = MISS; return false; @@ -541,21 +548,21 @@ bool Cop0::MapVAddr(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) } } -bool Cop0::UserMapVAddr32(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) const { +bool Cop0::UserMapVAddr32(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) { switch (vaddr) { case VREGION_KUSEG: - return ProbeTLB(accessType, s64(s32(vaddr)), paddr, nullptr); + return ProbeTLB(accessType, s64(s32(vaddr)), paddr); default: regs.cop0.tlbError = DISALLOWED_ADDRESS; return false; } } -bool Cop0::MapVAddr32(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) const { +bool Cop0::MapVAddr32(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) { switch (u32(vaddr) >> 29 & 7) { case 0 ... 3: case 7: - return ProbeTLB(accessType, s64(s32(vaddr)), paddr, nullptr); + return ProbeTLB(accessType, s64(s32(vaddr)), paddr); case 4 ... 5: paddr = vaddr & 0x1FFFFFFF; return true; @@ -568,21 +575,21 @@ bool Cop0::MapVAddr32(const TLBAccessType accessType, const u64 vaddr, u32 &padd return false; } -bool Cop0::UserMapVAddr64(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) const { +bool Cop0::UserMapVAddr64(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) { switch (vaddr) { case VREGION_XKUSEG: - return ProbeTLB(accessType, vaddr, paddr, nullptr); + return ProbeTLB(accessType, vaddr, paddr); default: regs.cop0.tlbError = DISALLOWED_ADDRESS; return false; } } -bool Cop0::MapVAddr64(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) const { +bool Cop0::MapVAddr64(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) { switch (vaddr) { case VREGION_XKUSEG: case VREGION_XKSSEG: - return ProbeTLB(accessType, vaddr, paddr, nullptr); + return ProbeTLB(accessType, vaddr, paddr); case VREGION_XKPHYS: { if (!regs.cop0.kernelMode) { @@ -602,7 +609,7 @@ bool Cop0::MapVAddr64(const TLBAccessType accessType, const u64 vaddr, u32 &padd return true; } case VREGION_XKSEG: - return ProbeTLB(accessType, vaddr, paddr, nullptr); + return ProbeTLB(accessType, vaddr, paddr); case VREGION_CKSEG0: // Identical to kseg0 in 32 bit mode. // Unmapped translation. Subtract the base address of the space to get the physical address. @@ -618,7 +625,7 @@ bool Cop0::MapVAddr64(const TLBAccessType accessType, const u64 vaddr, u32 &padd case VREGION_CKSSEG: Util::panic("Resolving virtual address 0x{:016X} (VREGION_CKSSEG) in 64 bit mode", vaddr); case VREGION_CKSEG3: - return ProbeTLB(accessType, vaddr, paddr, nullptr); + return ProbeTLB(accessType, vaddr, paddr); case VREGION_XBAD1: case VREGION_XBAD2: case VREGION_XBAD3: diff --git a/src/backend/core/registers/Cop0.hpp b/src/backend/core/registers/Cop0.hpp index 466ce548..b54d90c4 100644 --- a/src/backend/core/registers/Cop0.hpp +++ b/src/backend/core/registers/Cop0.hpp @@ -1,6 +1,7 @@ #pragma once #include -#include "log.hpp" +#include +#include namespace n64 { #define STATUS_MASK 0xFF57FFFF @@ -160,6 +161,12 @@ struct TLBEntry { PageMask pageMask; bool global; + + auto operator==(const TLBEntry& other) { + return initialized == other.initialized && entryLo0.raw == other.entryLo0.raw && + entryLo1.raw == other.entryLo1.raw && entryHi.raw == other.entryHi.raw && pageMask.raw == other.pageMask.raw && + global == other.global; + } }; enum TLBError : u8 { NONE, MISS, INVALID, MODIFICATION, DISALLOWED_ADDRESS }; @@ -236,6 +243,12 @@ struct Cop0 { s64 ErrorEPC{}; u32 r31{}; TLBEntry tlb[32]{}; + struct TLBCachedEntry { + int index = -1; + TLBEntry *entry = nullptr; + }; + + std::unordered_map tlbCache; TLBError tlbError = NONE; s64 openbus{}; template @@ -267,15 +280,15 @@ struct Cop0 { enum TLBAccessType { LOAD, STORE }; - bool ProbeTLB(TLBAccessType accessType, u64 vaddr, u32 &paddr, int *match) const; + bool ProbeTLB(TLBAccessType accessType, u64 vaddr, u32 &paddr); void FireException(ExceptionCode code, int cop, s64 pc) const; bool MapVAddr(TLBAccessType accessType, u64 vaddr, u32 &paddr); - bool UserMapVAddr32(TLBAccessType accessType, u64 vaddr, u32 &paddr) const; - bool MapVAddr32(TLBAccessType accessType, u64 vaddr, u32 &paddr) const; - bool UserMapVAddr64(TLBAccessType accessType, u64 vaddr, u32 &paddr) const; - bool MapVAddr64(TLBAccessType accessType, u64 vaddr, u32 &paddr) const; + bool UserMapVAddr32(TLBAccessType accessType, u64 vaddr, u32 &paddr); + bool MapVAddr32(TLBAccessType accessType, u64 vaddr, u32 &paddr); + bool UserMapVAddr64(TLBAccessType accessType, u64 vaddr, u32 &paddr); + bool MapVAddr64(TLBAccessType accessType, u64 vaddr, u32 &paddr); - TLBEntry *TLBTryMatch(u64 vaddr, int *match) const; + TLBEntry *TLBTryMatch(u64 vaddr, int* index); void HandleTLBException(u64 vaddr) const; static ExceptionCode GetTLBExceptionCode(TLBError error, TLBAccessType accessType); diff --git a/src/backend/core/registers/cop/cop0instructions.cpp b/src/backend/core/registers/cop/cop0instructions.cpp index 36233dbc..e447103d 100644 --- a/src/backend/core/registers/cop/cop0instructions.cpp +++ b/src/backend/core/registers/cop/cop0instructions.cpp @@ -50,6 +50,17 @@ void Cop0::tlbw(const int index_) { Util::panic("TLBWI with TLB index {}", index_); } + for (auto &[key, cachedTlb] : tlbCache) { + auto &[cachedIndex, cachedEntry] = cachedTlb; + if (cachedEntry) { + if (*cachedEntry == tlb[index_]) { + cachedIndex = -1; + cachedEntry = nullptr; + break; + } + } + } + tlb[index_].entryHi.raw = entryHi.raw; tlb[index_].entryHi.vpn2 &= ~page_mask.mask;