Cached TLB entries
This commit is contained in:
@@ -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 = ®s.cop0.tlb[i]; entry->initialized) {
|
if (TLBEntry *entry = ®s.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:
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user