Cached TLB entries

This commit is contained in:
SimoneN64
2024-10-15 10:56:47 +02:00
parent 57fd6a9af8
commit a0d46ca24e
3 changed files with 54 additions and 23 deletions

View File

@@ -293,7 +293,13 @@ static FORCE_INLINE u64 getVPN(const u64 addr, const u64 pageMask) {
return vpn & ~mask; 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++) { for (int i = 0; i < 32; i++) {
if (TLBEntry *entry = &regs.cop0.tlb[i]; entry->initialized) { if (TLBEntry *entry = &regs.cop0.tlb[i]; entry->initialized) {
const u64 entry_vpn = getVPN(entry->entryHi.raw, entry->pageMask.raw); 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; if (const bool asid_match = entry->global || regs.cop0.entryHi.asid == entry->entryHi.asid;
vpn_match && asid_match) { vpn_match && asid_match) {
if (match) { tlbCache[vaddr].entry = entry;
*match = i; tlbCache[vaddr].index = i;
} if (index)
*index = i;
return entry; return entry;
} }
} }
@@ -314,8 +321,8 @@ TLBEntry *Cop0::TLBTryMatch(const u64 vaddr, int *match) const {
return nullptr; return nullptr;
} }
bool Cop0::ProbeTLB(const TLBAccessType accessType, const u64 vaddr, u32 &paddr, int *match) const { bool Cop0::ProbeTLB(const TLBAccessType accessType, const u64 vaddr, u32 &paddr) {
const TLBEntry *entry = TLBTryMatch(vaddr, match); const TLBEntry *entry = TLBTryMatch(vaddr, nullptr);
if (!entry) { if (!entry) {
regs.cop0.tlbError = MISS; regs.cop0.tlbError = MISS;
return false; 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) { switch (vaddr) {
case VREGION_KUSEG: case VREGION_KUSEG:
return ProbeTLB(accessType, s64(s32(vaddr)), paddr, nullptr); return ProbeTLB(accessType, s64(s32(vaddr)), paddr);
default: default:
regs.cop0.tlbError = DISALLOWED_ADDRESS; regs.cop0.tlbError = DISALLOWED_ADDRESS;
return false; 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) { switch (u32(vaddr) >> 29 & 7) {
case 0 ... 3: case 0 ... 3:
case 7: case 7:
return ProbeTLB(accessType, s64(s32(vaddr)), paddr, nullptr); return ProbeTLB(accessType, s64(s32(vaddr)), paddr);
case 4 ... 5: case 4 ... 5:
paddr = vaddr & 0x1FFFFFFF; paddr = vaddr & 0x1FFFFFFF;
return true; return true;
@@ -568,21 +575,21 @@ bool Cop0::MapVAddr32(const TLBAccessType accessType, const u64 vaddr, u32 &padd
return false; 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) { switch (vaddr) {
case VREGION_XKUSEG: case VREGION_XKUSEG:
return ProbeTLB(accessType, vaddr, paddr, nullptr); return ProbeTLB(accessType, vaddr, paddr);
default: default:
regs.cop0.tlbError = DISALLOWED_ADDRESS; regs.cop0.tlbError = DISALLOWED_ADDRESS;
return false; 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) { switch (vaddr) {
case VREGION_XKUSEG: case VREGION_XKUSEG:
case VREGION_XKSSEG: case VREGION_XKSSEG:
return ProbeTLB(accessType, vaddr, paddr, nullptr); return ProbeTLB(accessType, vaddr, paddr);
case VREGION_XKPHYS: case VREGION_XKPHYS:
{ {
if (!regs.cop0.kernelMode) { if (!regs.cop0.kernelMode) {
@@ -602,7 +609,7 @@ bool Cop0::MapVAddr64(const TLBAccessType accessType, const u64 vaddr, u32 &padd
return true; return true;
} }
case VREGION_XKSEG: case VREGION_XKSEG:
return ProbeTLB(accessType, vaddr, paddr, nullptr); return ProbeTLB(accessType, vaddr, paddr);
case VREGION_CKSEG0: case VREGION_CKSEG0:
// Identical to kseg0 in 32 bit mode. // Identical to kseg0 in 32 bit mode.
// Unmapped translation. Subtract the base address of the space to get the physical address. // 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: case VREGION_CKSSEG:
Util::panic("Resolving virtual address 0x{:016X} (VREGION_CKSSEG) in 64 bit mode", vaddr); Util::panic("Resolving virtual address 0x{:016X} (VREGION_CKSSEG) in 64 bit mode", vaddr);
case VREGION_CKSEG3: case VREGION_CKSEG3:
return ProbeTLB(accessType, vaddr, paddr, nullptr); return ProbeTLB(accessType, vaddr, paddr);
case VREGION_XBAD1: case VREGION_XBAD1:
case VREGION_XBAD2: case VREGION_XBAD2:
case VREGION_XBAD3: case VREGION_XBAD3:

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include <common.hpp> #include <common.hpp>
#include "log.hpp" #include <log.hpp>
#include <unordered_map>
namespace n64 { namespace n64 {
#define STATUS_MASK 0xFF57FFFF #define STATUS_MASK 0xFF57FFFF
@@ -160,6 +161,12 @@ struct TLBEntry {
PageMask pageMask; PageMask pageMask;
bool global; 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 }; enum TLBError : u8 { NONE, MISS, INVALID, MODIFICATION, DISALLOWED_ADDRESS };
@@ -236,6 +243,12 @@ struct Cop0 {
s64 ErrorEPC{}; s64 ErrorEPC{};
u32 r31{}; u32 r31{};
TLBEntry tlb[32]{}; TLBEntry tlb[32]{};
struct TLBCachedEntry {
int index = -1;
TLBEntry *entry = nullptr;
};
std::unordered_map<u64, TLBCachedEntry> tlbCache;
TLBError tlbError = NONE; TLBError tlbError = NONE;
s64 openbus{}; s64 openbus{};
template <class T> template <class T>
@@ -267,15 +280,15 @@ struct Cop0 {
enum TLBAccessType { LOAD, STORE }; 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; void FireException(ExceptionCode code, int cop, s64 pc) const;
bool MapVAddr(TLBAccessType accessType, u64 vaddr, u32 &paddr); bool MapVAddr(TLBAccessType accessType, u64 vaddr, u32 &paddr);
bool UserMapVAddr32(TLBAccessType accessType, u64 vaddr, u32 &paddr) const; bool UserMapVAddr32(TLBAccessType accessType, u64 vaddr, u32 &paddr);
bool MapVAddr32(TLBAccessType accessType, u64 vaddr, u32 &paddr) const; bool MapVAddr32(TLBAccessType accessType, u64 vaddr, u32 &paddr);
bool UserMapVAddr64(TLBAccessType accessType, u64 vaddr, u32 &paddr) const; bool UserMapVAddr64(TLBAccessType accessType, u64 vaddr, u32 &paddr);
bool MapVAddr64(TLBAccessType accessType, u64 vaddr, u32 &paddr) const; 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; void HandleTLBException(u64 vaddr) const;
static ExceptionCode GetTLBExceptionCode(TLBError error, TLBAccessType accessType); static ExceptionCode GetTLBExceptionCode(TLBError error, TLBAccessType accessType);

View File

@@ -50,6 +50,17 @@ void Cop0::tlbw(const int index_) {
Util::panic("TLBWI with TLB index {}", 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.raw = entryHi.raw;
tlb[index_].entryHi.vpn2 &= ~page_mask.mask; tlb[index_].entryHi.vpn2 &= ~page_mask.mask;