64 bit tlb
This commit is contained in:
@@ -58,6 +58,38 @@
|
||||
#define PIF_ROM_REGION PIF_ROM_REGION_START ... PIF_ROM_REGION_END
|
||||
#define PIF_RAM_REGION PIF_RAM_REGION_START ... PIF_RAM_REGION_END
|
||||
|
||||
#define START_VREGION_KUSEG 0x00000000
|
||||
#define START_VREGION_KSEG0 0x80000000
|
||||
#define START_VREGION_KSEG1 0xA0000000
|
||||
#define START_VREGION_KSSEG 0xC0000000
|
||||
#define START_VREGION_KSEG3 0xE0000000
|
||||
|
||||
#define END_VREGION_KUSEG 0x7FFFFFFF
|
||||
#define END_VREGION_KSEG0 0x9FFFFFFF
|
||||
#define END_VREGION_KSEG1 0xBFFFFFFF
|
||||
#define END_VREGION_KSSEG 0xDFFFFFFF
|
||||
#define END_VREGION_KSEG3 0xFFFFFFFF
|
||||
|
||||
#define VREGION_KUSEG START_VREGION_KUSEG ... END_VREGION_KUSEG
|
||||
#define VREGION_KSEG0 START_VREGION_KSEG0 ... END_VREGION_KSEG0
|
||||
#define VREGION_KSEG1 START_VREGION_KSEG1 ... END_VREGION_KSEG1
|
||||
#define VREGION_KSSEG START_VREGION_KSSEG ... END_VREGION_KSSEG
|
||||
#define VREGION_KSEG3 START_VREGION_KSEG3 ... END_VREGION_KSEG3
|
||||
|
||||
#define DIRECT_MAP_MASK 0x1FFFFFFF
|
||||
|
||||
#define VREGION_XKUSEG 0x0000000000000000 ... 0x000000FFFFFFFFFF
|
||||
#define VREGION_XBAD1 0x0000010000000000 ... 0x3FFFFFFFFFFFFFFF
|
||||
#define VREGION_XKSSEG 0x4000000000000000 ... 0x400000FFFFFFFFFF
|
||||
#define VREGION_XBAD2 0x4000010000000000 ... 0x7FFFFFFFFFFFFFFF
|
||||
#define VREGION_XKPHYS 0x8000000000000000 ... 0xBFFFFFFFFFFFFFFF
|
||||
#define VREGION_XKSEG 0xC000000000000000 ... 0xC00000FF7FFFFFFF
|
||||
#define VREGION_XBAD3 0xC00000FF80000000 ... 0xFFFFFFFF7FFFFFFF
|
||||
#define VREGION_CKSEG0 0xFFFFFFFF80000000 ... 0xFFFFFFFF9FFFFFFF
|
||||
#define VREGION_CKSEG1 0xFFFFFFFFA0000000 ... 0xFFFFFFFFBFFFFFFF
|
||||
#define VREGION_CKSSEG 0xFFFFFFFFC0000000 ... 0xFFFFFFFFDFFFFFFF
|
||||
#define VREGION_CKSEG3 0xFFFFFFFFE0000000 ... 0xFFFFFFFFFFFFFFFF
|
||||
|
||||
constexpr u64 operator""_kb(unsigned long long int x) {
|
||||
return 1024ULL * x;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#include <core/registers/Cop0.hpp>
|
||||
#include <log.hpp>
|
||||
#include <core/registers/Registers.hpp>
|
||||
#include <core/Interpreter.hpp>
|
||||
@@ -107,6 +106,7 @@ void Cop0::SetReg32(u8 addr, u32 value) {
|
||||
case COP0_REG_STATUS:
|
||||
status.raw &= ~STATUS_MASK;
|
||||
status.raw |= (value & STATUS_MASK);
|
||||
Update();
|
||||
break;
|
||||
case COP0_REG_CAUSE: {
|
||||
Cop0Cause tmp{};
|
||||
@@ -294,6 +294,8 @@ void FireException(Registers& regs, ExceptionCode code, int cop, bool useOldPC)
|
||||
default: Util::panic("Unhandled exception! {}", static_cast<u8>(code));
|
||||
}
|
||||
}
|
||||
|
||||
regs.cop0.Update();
|
||||
}
|
||||
|
||||
void HandleTLBException(Registers& regs, u64 vaddr) {
|
||||
@@ -362,4 +364,116 @@ void Cop0::decodeInterp(Registers& regs, u32 instr) {
|
||||
default: Util::panic("Unimplemented COP0 instruction {} {}", mask_cop >> 4, mask_cop & 7);
|
||||
}
|
||||
}
|
||||
|
||||
bool MapVAddr(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr) {
|
||||
if(regs.cop0.is_64bit_addressing) [[unlikely]] {
|
||||
if (regs.cop0.kernel_mode) [[likely]] {
|
||||
return MapVAddr64(regs, accessType, vaddr, paddr);
|
||||
} else if (regs.cop0.user_mode) {
|
||||
return UserMapVAddr64(regs, accessType, vaddr, paddr);
|
||||
} else if (regs.cop0.supervisor_mode) {
|
||||
Util::panic("Supervisor mode memory access, 64 bit mode");
|
||||
} else {
|
||||
Util::panic("Unknown mode! This should never happen!");
|
||||
}
|
||||
} else {
|
||||
if (regs.cop0.kernel_mode) [[likely]] {
|
||||
return MapVAddr32(regs, accessType, vaddr, paddr);
|
||||
} else if (regs.cop0.user_mode) {
|
||||
return UserMapVAddr32(regs, accessType, vaddr, paddr);
|
||||
} else if (regs.cop0.supervisor_mode) {
|
||||
Util::panic("Supervisor mode memory access, 32 bit mode");
|
||||
} else {
|
||||
Util::panic("Unknown mode! This should never happen!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool UserMapVAddr32(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr) {
|
||||
switch (vaddr) {
|
||||
case VREGION_KUSEG:
|
||||
return ProbeTLB(regs, accessType, s64(s32(vaddr)), paddr, nullptr);
|
||||
default:
|
||||
regs.cop0.tlbError = DISALLOWED_ADDRESS;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool MapVAddr32(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr) {
|
||||
switch((u32(vaddr) >> 29) & 7) {
|
||||
case 0 ... 3: case 7:
|
||||
return ProbeTLB(regs, accessType, s64(s32(vaddr)), paddr, nullptr);
|
||||
case 4 ... 5:
|
||||
paddr = vaddr & 0x1FFFFFFF;
|
||||
return true;
|
||||
case 6: Util::panic("Unimplemented virtual mapping in KSSEG! ({:08X})", vaddr);
|
||||
default:
|
||||
Util::panic("Should never end up in default case in map_vaddr! ({:08X})", vaddr);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UserMapVAddr64(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr) {
|
||||
switch (vaddr) {
|
||||
case VREGION_XKUSEG:
|
||||
return ProbeTLB(regs, accessType, vaddr, paddr, nullptr);
|
||||
default:
|
||||
regs.cop0.tlbError = DISALLOWED_ADDRESS;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool MapVAddr64(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr) {
|
||||
switch (vaddr) {
|
||||
case VREGION_XKUSEG: case VREGION_XKSSEG:
|
||||
return ProbeTLB(regs, accessType, vaddr, paddr, nullptr);
|
||||
case VREGION_XKPHYS: {
|
||||
if (!regs.cop0.kernel_mode) {
|
||||
Util::panic("Access to XKPHYS address 0x{:016X} when outside kernel mode!", vaddr);
|
||||
}
|
||||
u8 high_two_bits = (vaddr >> 62) & 0b11;
|
||||
if (high_two_bits != 0b10) {
|
||||
Util::panic("Access to XKPHYS address 0x{:016X} with high two bits != 0b10!", vaddr);
|
||||
}
|
||||
u8 subsegment = (vaddr >> 59) & 0b11;
|
||||
bool cached = subsegment != 2; // do something with this eventually
|
||||
// If any bits in the range of 58:32 are set, the address is invalid.
|
||||
bool valid = (vaddr & 0x07FFFFFF00000000) == 0;
|
||||
if (!valid) {
|
||||
regs.cop0.tlbError = DISALLOWED_ADDRESS;
|
||||
return false;
|
||||
}
|
||||
paddr = vaddr & 0xFFFFFFFF;
|
||||
return true;
|
||||
}
|
||||
case VREGION_XKSEG:
|
||||
return ProbeTLB(regs, accessType, vaddr, paddr, nullptr);
|
||||
case VREGION_CKSEG0:
|
||||
// Identical to kseg0 in 32 bit mode.
|
||||
// Unmapped translation. Subtract the base address of the space to get the physical address.
|
||||
paddr = vaddr - START_VREGION_KSEG0; // Implies cutting off the high 32 bits
|
||||
Util::trace("CKSEG0: Translated 0x{:016X} to 0x{:08X}", vaddr, paddr);
|
||||
return true;
|
||||
case VREGION_CKSEG1:
|
||||
// Identical to kseg1 in 32 bit mode.
|
||||
// Unmapped translation. Subtract the base address of the space to get the physical address.
|
||||
paddr = vaddr - START_VREGION_KSEG1; // Implies cutting off the high 32 bits
|
||||
Util::trace("KSEG1: Translated 0x{:016X} to 0x{:08X}", vaddr, paddr);
|
||||
return true;
|
||||
case VREGION_CKSSEG:
|
||||
Util::panic("Resolving virtual address 0x{:016X} (VREGION_CKSSEG) in 64 bit mode", vaddr);
|
||||
case VREGION_CKSEG3:
|
||||
return ProbeTLB(regs, accessType, vaddr, paddr, nullptr);
|
||||
case VREGION_XBAD1:
|
||||
case VREGION_XBAD2:
|
||||
case VREGION_XBAD3:
|
||||
regs.cop0.tlbError = DISALLOWED_ADDRESS;
|
||||
return false;
|
||||
default:
|
||||
Util::panic("Resolving virtual address 0x{:016X} in 64 bit mode", vaddr);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -221,10 +221,10 @@ struct Cop0 {
|
||||
|
||||
void Reset();
|
||||
|
||||
bool kernel_mode{};
|
||||
bool supervisor_mode{};
|
||||
bool user_mode{};
|
||||
bool is_64bit_addressing{};
|
||||
bool kernel_mode{true};
|
||||
bool supervisor_mode{false};
|
||||
bool user_mode{false};
|
||||
bool is_64bit_addressing{false};
|
||||
bool llbit{};
|
||||
|
||||
PageMask pageMask{};
|
||||
@@ -263,6 +263,18 @@ struct Cop0 {
|
||||
val = (val % upper) + lower;
|
||||
return val;
|
||||
}
|
||||
|
||||
FORCE_INLINE void Update() {
|
||||
bool exception = status.exl || status.erl;
|
||||
|
||||
kernel_mode = exception || status.ksu == 0;
|
||||
supervisor_mode = !exception && status.ksu == 1;
|
||||
user_mode = !exception && status.ksu == 2;
|
||||
is_64bit_addressing =
|
||||
(kernel_mode && status.kx)
|
||||
|| (supervisor_mode && status.sx)
|
||||
|| (user_mode && status.ux);
|
||||
}
|
||||
private:
|
||||
FORCE_INLINE u32 GetWired() { return wired & 0x3F; }
|
||||
FORCE_INLINE u32 GetCount() { return u32(u64(count >> 1)); }
|
||||
@@ -289,20 +301,11 @@ enum TLBAccessType {
|
||||
|
||||
bool ProbeTLB(Registers& regs, TLBAccessType access_type, u64 vaddr, u32& paddr, int* match);
|
||||
|
||||
static FORCE_INLINE bool MapVAddr(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr) {
|
||||
switch(u32(vaddr) >> 29) {
|
||||
case 0 ... 3: case 7:
|
||||
return ProbeTLB(regs, accessType, vaddr, paddr, nullptr);
|
||||
case 4 ... 5:
|
||||
paddr = vaddr & 0x1FFFFFFF;
|
||||
return true;
|
||||
case 6: Util::panic("Unimplemented virtual mapping in KSSEG! ({:08X})", vaddr);
|
||||
default:
|
||||
Util::panic("Should never end up in default case in map_vaddr! ({:08X})", vaddr);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
bool MapVAddr(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr);
|
||||
bool UserMapVAddr32(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr);
|
||||
bool MapVAddr32(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr);
|
||||
bool UserMapVAddr64(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr);
|
||||
bool MapVAddr64(Registers& regs, TLBAccessType accessType, u64 vaddr, u32& paddr);
|
||||
|
||||
TLBEntry* TLBTryMatch(Registers& regs, u64 vaddr, int* match);
|
||||
void HandleTLBException(Registers& regs, u64 vaddr);
|
||||
|
||||
Reference in New Issue
Block a user